Commit Graph

95 Commits

Author SHA1 Message Date
Alex Newman 50c9d977eb chore: bump version to 13.24.17 (#4028)
Package-facing patch bump so 13.24.17 ships #4026/#3575 (health probe deadline cap), #3445 (desktop-bundled Codex CLI on macOS), and #4027 (register memory_session_id, do not re-register). Rebuilds plugin bundles so the injected version matches.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-11 01:41:03 -07:00
Alex Newman 033667ed9a chore: bump version to 13.24.16 (#4023)
Package-facing patch bump so 13.24.16 ships #3629 (NULL memory_session_id), #3640 (runtime-only marketplace package.json), and #3631 (dead-transport Chroma handshake). Rebuilds plugin bundles so the injected version matches.
2026-09-11 01:02:12 -07:00
Alex Newman 2f4de2ba25 chore: bump version to 13.24.15 (#4022)
Package-facing patch bump so 13.24.15 ships #3727 / #3706 (daemon no longer inherits user project cwd). Rebuilds plugin bundles so the injected version matches.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-11 00:30:03 -07:00
Alex Newman dc36ee7d45 chore: bump version to 13.24.14 (#4020)
Package-facing patch bump so 13.24.14 ships the commits now on main after v13.24.13. Rebuilds plugin bundles so the injected version matches.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-11 00:10:44 -07:00
Alex Newman c51d62a4db chore: bump version to 13.24.13 (#4013)
Package-facing patch bump so 13.24.13 ships the commits now on main after v13.24.12. Rebuilds plugin bundles so the injected version matches.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-10 23:35:17 -07:00
Alex Newman ec9e3e32d8 chore: bump version to 13.24.12 (#4007)
Package-facing patch so 13.24.12 ships #4003, #4005, #4006, #3826, and #3773, which landed on main after v13.24.11 was tagged.
2026-09-10 23:12:13 -07:00
Alex Newman 9841dd4120 chore: bump version to 13.24.11 (#4004)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-10 22:25:56 -07:00
Alex Newman 6f9a73c8ca chore: bump version to 13.24.10 (#3993)
Package-facing patch so 13.24.10 ships #3991 (content flush batch 200→40 + requestTimeout settings), which landed on main after v13.24.9 was tagged.
2026-09-10 21:20:08 -07:00
Alex Newman 50b3efb4fa chore: bump version to 13.24.9 (#3990)
Package-facing security patch for the #3861 / #3985 credential-leak fixes
(unauthenticated /api/settings redaction, MCP workspace containment, host
bind tightening). Publish-ready; do not npm publish from this PR.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-10 20:57:20 -07:00
Alex Newman 47c06ff9a1 fix(observer): surface quota cooldown on observer-health and session-start (#3986)
Quota cooldown is an intentional pause, not a failure, so observer-health
stayed green and the session-start banner stayed silent while the worker
queued work. Mirror the breaker into observer-health.json and show a
pause notice on the existing health/banner path without changing
queue-accept or drain-on-clear.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-10 20:49:31 -07:00
Alex Newman 35642e94e3 chore: bump version to 13.24.8
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ah5a7Ygdm3uzBxSFZ8kqx6
2026-09-11 02:11:35 +00:00
Cursor Agent 4890e14c4b chore: bump version to 13.24.7
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-11 01:05:17 +00:00
Alex Newman 22879ef523 fix(supervisor): reap chroma-mcp trees no worker owns at boot (refs #3905)
Co-authored-by: Stefan Nesiu Bedreag <stefan.nesiu-bedreag@gmail.com>
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-10 17:52:30 -07:00
Cursor Agent 9811b0eb78 chore: bump version to 13.24.6
Co-authored-by: Alex Newman <thedotmack@users.noreply.github.com>
2026-09-11 00:27:49 +00:00
Antonio Coppe 29279d9306 fix: validate all shipped runtime bundle versions 2026-09-11 00:08:30 +00:00
Alex Newman fd0ecf0233 feat(sqlite): durable tool_uses backup index + get_tool_uses disclosure (#3898)
Raw tool I/O had no durable home. `pending_messages` is the generation
queue -- rows are claimed, summarized, and deleted -- so once an
observation existed the original tool_input/tool_response were gone.

Adds `tool_uses` (schema v51) as a by-reference side index for those
bodies, written from the one ingest choke point both the PostToolUse hook
route and the transcript-watch processor already share. The JSONL
transcripts and `src/services/transcripts/*` remain the spine and are
untouched.

Schema (Receipt freeze 2026-09-06): UNIQUE(content_session_id,
tool_use_id), nullable `or_generation_id` / `or_session_id` as join keys
back to an OpenRouter spend line, and deliberately no cost_usd/micros --
this table carries tool identity, dollars stay on the OR stamp. No FK on
session_db_id/observation_id: a FK there can abort the constructor
migration chain (#3378), and observation_id is linked late by design.

Write path dual-writes alongside -- never instead of -- the
pending_messages enqueue, and swallows its own failures so an observation
is never lost to a backup-index error. `toolUseId` now actually reaches
the worker from hooks: it was missing from NormalizedHookInput and every
hook adapter, so only the transcript path supplied it. ResponseProcessor
links the batch's claimed ids to the first stored observation.

Read path is progressive-disclosure layer 4: POST /api/tool-uses/batch
requires explicit ids (never a full-table scan), GET /api/tool-uses
returns a cheap index shape with size hints and never the payloads, and
the `get_tool_uses` MCP tool is described as a last resort. claude-mem's
own read tools are skipped by the writer -- without that, every call to
get_tool_uses would store the bodies it just returned.

Payloads are stored in-row with a 64 KB soft cap and a UTF-8-safe
truncation marker; content_hash is computed over the original.

Join contract for Receipt: RECEIPT-JOIN.md


Claude-Session: https://claude.ai/code/session_01QgdJ6gExgBirDoAxknt94m

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 18:25:26 -07:00
Alex Newman f6f72747e1 chore: bump version to 13.24.1
Patch release so marketplace and npm installs actually pick up the rebuilt
plugin bundles from #3878. 13.24.0 shipped manifests that claimed 13.24.0
while plugin/scripts/*.cjs still carried 13.23.1 bytes; the artifacts were
corrected in place, but existing 13.24.0 installs have no version change to
trigger an upgrade. 13.24.1 gives them one.

Version bumped across all 11 manifests and the README badge, then
regenerated via `npm run build-and-sync`. All four .cjs bundles are
byte-identical to 13.24.0 after normalizing the version string -- no source
changed since 4da9ffc6, so this is a pure version delta.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fu9bpdG4AWZNq3m8zkUkYg
2026-09-05 05:22:25 +00:00
Alex Newman 4da9ffc68c fix: rebuild plugin bundles to match manifest 13.24.0 (#3857)
* fix: rebuild plugin bundles so committed artifacts match manifest 13.24.0

The 13.24.0 release commit (85ccd626) bumped the manifests and CHANGELOG
but never re-ran the build, so plugin/scripts/*.cjs kept the 13.23.1 bytes
last produced by 89ca057a. The Claude Code marketplace installs straight
from this repo (.claude-plugin/marketplace.json -> "source": "./plugin"),
so every marketplace user on 13.24.0 has been executing 13.23.1 code.

ensureWorkerRunning() compares the resolved plugin version (13.24.0, taken
from the plugin cache directory name) against the worker's baked-in
__DEFAULT_PACKAGE_VERSION__ (13.23.1, reported by /api/health). The
mismatch SIGKILLs the worker and respawns the same stale file on every
hook event, with no state that survives the hook process to bound it --
an unbounded kill/respawn loop that takes the in-flight observer
generator down with it, so no observations get written.

This is a genuine `npm run build`, not a version-string patch. The
bundles were stale in code, not merely in the constant: src/ moved 704
insertions across 12 files since 13.23.1, including the observer's
<skip_summary reason="noise" /> protocol change, the new manual-session
module, and the platform_source plumbing in SessionStore and MemoryRoutes.

No version bump: the manifests were already correct at 13.24.0. It is the
artifacts that were wrong.

Fixes #3857

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bshprs1vjut2XmaGTRESqX

* fix(tests): restore module mocks so worker-spawner stubs stop leaking

bun runs the whole suite in one process and mock.module is process-global
and sticky, so stubs installed by one test file stay installed for every
file loaded after it.

tests/services/worker-spawner.test.ts mocked
src/services/infrastructure/{ProcessManager,HealthMonitor}.js and never
restored them. tests/infrastructure/{health-monitor,process-manager}.test.ts
import the same symbols through the src/services/infrastructure/index.js
barrel, so they silently exercised those stubs instead of the real code:
isPortInUse returned false without touching net.createServer, waitForHealth
returned false without fetching, getPlatformTimeout skipped the Windows
doubling, cleanStalePidFile always reported 'dead', and spawnDaemon never
returned undefined. waitForPortFree stayed real but resolved through the
stubbed isPortInUse binding, inverting its timeout case.

This is order-dependent, not new: bun walks test files in filesystem order,
and a fresh CI checkout loads worker-spawner (59) well before health-monitor
(169) and process-manager (172), while many local checkouts load
tests/infrastructure first and pass. That ordering is what surfaced 19
failures in Actions run 33939805959.

Snapshot the real namespaces eagerly, before the mock.module calls, and
reinstall them in afterAll. The snapshot must be eager: `import * as x`
yields a live namespace object that bun re-points when the module is mocked,
so spreading it inside afterAll copies the stubs back in. That is exactly
the latent bug in tests/cli/handlers/context-session-start.test.ts, whose
restore was re-installing its own hook-settings, oauth-token, project-name
and worker-utils stubs; fixed here the same way.

Tests only. No source, plugin bundle, or version changes — the committed
artifacts still match manifest 13.24.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcjsK6QqeBcYXbJ8gqBsea

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 21:26:08 -07:00
Alex Newman 89ca057a46 chore: bump version to 13.23.1
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NoBPqpo7YaR3HKipExjAT
2026-09-01 14:00:59 -07:00
Alex Newman 263d8c0083 chore: bump version to 13.23.0
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NoBPqpo7YaR3HKipExjAT
2026-09-01 13:27:31 -07:00
Alex Newman 76088262c3 chore: bump version to 13.22.0
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NoBPqpo7YaR3HKipExjAT
2026-09-01 12:11:29 -07:00
Alex Newman 2aeedb42ac chore: bump version to 13.21.2
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DD5YMaAiXXeY3zaitbGC6n
2026-08-31 14:37:27 -07:00
Alex Newman e9c52a3537 chore: bump version to 13.21.1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DD5YMaAiXXeY3zaitbGC6n
2026-08-31 14:28:16 -07:00
Alex Newman fab75dc3b9 chore: bump version to 13.21.0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DD5YMaAiXXeY3zaitbGC6n
2026-08-31 14:05:20 -07:00
Alex Newman 8545e52207 chore: bump version to 13.20.0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DD5YMaAiXXeY3zaitbGC6n
2026-08-31 13:15:42 -07:00
Alex Newman 60310f86bf fix(quota): claim the cmem gateway re-probe instead of reading the clock
The gateway fallback said "allow one normal gateway request as a probe", but
nothing made it one. shouldUseCmemFallback is a subtraction and a less-than,
and ensureGeneratorRunning gates per session, so 28-69 live sessions are 28-69
independent callers.

It is worse than the in-memory case. The marker lives on disk
(CLAUDE_MEM_PRO_FALLBACK_AT in settings.json, loaded uncached), so every
process parses the same ISO string and computes the same expiry instant -- the
herd was handed a shared clock to synchronize on. Each member's failure then
does a read-modify-write of the user's whole settings.json to re-arm the
marker; the write is atomic but the sequence is not, so concurrent settings
edits can be clobbered.

The re-probe is now claimed through the breaker's existing machinery under a
DISTINCT key, 'cmem-gateway'. Distinct because tryAdmitQuotaProbe takes the
cooldown per call: this path's 15 minutes against the provider breaker's 30
would otherwise let two callers reach contradictory answers about whether the
same breaker is armed, and provider switches (which this branch makes routine)
make the collision reachable in both directions -- a fresh funded key born into
an armed breaker and withheld for a refusal it never earned.

getSelectedProvider stays read-only for diagnostics and status; only the new
selectProviderForGenerator claims. Every path out of ensureGeneratorRunning
that does not actually send releases the claim, including the one where a
generator is already running, so a claim cannot outlive the call that took it.

Also regenerates the plugin bundles rather than hand-merging them, which is
what the five .cjs conflicts in this consolidation always needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AWmJDjFM6BNmGaLJ7Xbrsy
2026-08-31 12:18:30 -07:00
Alex Newman 5a87186191 Merge origin/main into OAuth installer fix 2026-08-31 11:22:33 -07:00
Claude 456e369817 chore: bump version to 13.18.0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123bYqzHGw2dtgN8D8GE3UW
2026-08-29 23:35:26 +00:00
Alex Newman 64ca5a2571 chore: bump version to 13.17.2 2026-08-29 03:03:47 -07:00
Alex Newman 35b833f32b chore: bump version to 13.17.1 2026-08-28 21:22:56 -07:00
Alex Newman b25f56d955 chore: bump version to 13.17.0 2026-08-28 16:19:56 -07:00
Alex Newman 2319050541 fix(installer): harden signed-in provider transitions 2026-08-26 17:27:20 -07:00
Alex Newman 50b84d614f chore: bump version to 13.16.1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JT1VTKoaTf7VfePb7nVfwz
2026-08-26 09:45:52 -07:00
Alex Newman 4ea0906cd2 Merge origin/main (v13.16.0) into windows-megafix
plugin/scripts/*.cjs conflicts resolved by rebuilding plugin/ from the
merged source, same as the prior merge commits on this branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JT1VTKoaTf7VfePb7nVfwz
2026-08-25 16:38:04 -07:00
Alex Newman 73533cd7fc chore: bump version to 13.16.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016T31aDw2WBHVDGmXvnMkZq
2026-08-25 16:28:35 -07:00
Alex Newman 4a671efb60 Merge origin/main into windows-megafix
plugin/scripts/*.cjs conflicts resolved by rebuilding plugin/ from the
merged source (npm run build), same as the original rollup commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JT1VTKoaTf7VfePb7nVfwz
2026-08-25 16:17:06 -07:00
Alex Newman 200457c7f5 chore: bump version to 13.15.3
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193zqc7zHYFkUHB7ZjLFWiT
2026-08-19 15:39:29 -07:00
Alex Newman da4bcadf8e build: rebuild plugin/ from the combined windows-megafix source
The five Windows branches each carried their own build of
plugin/scripts/*.cjs; merging them conflicted on those artifacts. Rebuilt
once from the merged src/ so the shipped scripts contain all five fixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WVK8iVC2dnrqE1fV4ogp2a
2026-08-19 12:31:01 -07:00
Alex Newman 712a6c7987 chore(build): regenerate plugin bundles
Output of `npm run build` for the uncached identity revalidation. No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 02:55:20 -07:00
Alex Newman 70968263cc chore(build): regenerate plugin bundles
Output of `npm run build` for the atomic descendant enumeration. No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 02:31:53 -07:00
Alex Newman 27c759b99b chore(build): regenerate plugin bundles
Output of `npm run build` for the default-safe root identity change. No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 02:04:18 -07:00
Alex Newman 4de9ebe892 chore(build): regenerate plugin bundles
Output of `npm run build` for the identity-revalidation audit. No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 01:43:46 -07:00
Alex Newman a710bfe4c0 chore(build): regenerate plugin bundles
Output of `npm run build` for the identity-revalidation fix. No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 00:44:27 -07:00
Alex Newman 3120a06aa9 chore(build): regenerate plugin bundles
Output of `npm run build` for the process-tree changes in this series.
No hand edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 23:34:01 -07:00
Alex Newman b0194042d5 chore: bump version to 13.15.2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPptieMC1vzUNGtUErU3UM
2026-08-16 12:08:44 -07:00
Alex Newman a4e25d210f chore: bump version to 13.15.1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPptieMC1vzUNGtUErU3UM
2026-08-16 12:00:23 -07:00
Alex Newman 3bf1914503 fix(worker): carry the gateway error envelope end-to-end — stop retrying quota, log once, tell the user what to do (#3601)
* docs: add observer error-path implementation plan

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPptieMC1vzUNGtUErU3UM

* fix(worker): carry the gateway error envelope, stop retrying quota errors, log once

The OpenRouter classifier discarded the upstream body (which contains the
remedy — e.g. "Key limit exceeded … Manage it using <url>"), treated 402 as
unrecoverable, never used the request id it was handed, and each failure
fanned out to five log lines plus two pointless retries.

- provider-errors.ts: ClassifiedProviderError gains optional code/action/url/
  requestId; describeProviderError() is the single renderer
  (message — action url (req id)).
- OpenRouterProvider.ts: classifyOpenRouterError parses the cmem.ai gateway
  envelope {code,message,action,url,request_id} first (six taxonomy codes →
  worker kinds), otherwise legacy classification now includes the upstream
  body in every message, maps 402 and "key limit exceeded"/"limit exceeded"/
  "negative credit" bodies to quota_exhausted (bare "limit exceeded" excluded
  on 429 so real rate limits stay retryable), and sets requestId. The
  200-with-error path now forwards bodyText + requestId.
- error-classification.ts (server mirror): same marker list, no imports.
- Log once: init/message-loop/handleSessionError log at debug for classified
  errors; SessionRoutes emits one "Observer failed" error line with kind/code/
  requestId and the rendered message string (no errorSink re-fire).
- Tests: envelope + legacy cases assert message/code/action/url/requestId;
  new retry-policy.test.ts pins isRetryableKind; server mirror pinned.

Plan: plans/2026-08-16-observer-error-path.md (Phase 2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPptieMC1vzUNGtUErU3UM

* feat(worker): observer-health ledger and session-start warning carry the structured error

Users don't read worker logs; they open Claude Code. The session-start
health warning from #3538 said "check ~/.claude-mem/settings.json", which is
wrong for a Pro user whose allowance is exhausted.

- observer-health.ts: ObserverHealthState gains lastErrorCode/Action/Url/
  RequestId (null by default; old ledgers read back unchanged);
  recordObserverFailure accepts string | ObserverFailureDetail — objects
  populate the new fields (message/action scrubbed, url/requestId as-is);
  renderObserverHealthWarning emits "What to do:", "Link:", "Request id:"
  and drops the generic settings.json remedy when an action exists.
  scrubErrorMessage also masks cm_pro_ tokens.
- SessionRoutes.ts: classified errors record {message, code, action, url,
  requestId} in the ledger — the same words as the "Observer failed" log line.
- tests/observer-health.test.ts: round-trip, backward compat, render with/
  without action, scrub.

Plan: plans/2026-08-16-observer-error-path.md (Phase 3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPptieMC1vzUNGtUErU3UM

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:25:07 -07:00
Alex Newman a38d51169b feat(worker): alert the user at session start when observations stop flowing (#3538)
* feat(worker): surface observer outages at session start via observer-health ledger

Generator failures now record to a file-backed ledger
(~/.claude-mem/observer-health.json); successful observation stores reset
it. Session-start context injection prepends a loud outage warning (with
the provider's last error, which often embeds the remedy URL) once 3+
consecutive failures are newer than the last success — including on the
empty-state and missing-DB paths. Prevents a repeat of the silent
17-hour 2026-08-09 provider-quota outage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(observer-health): lock the ledger, widen credential redaction, plain-language warning

Greptile P1s on #3538:

- Credential redaction leaked provider secrets into injected context.
  scrubErrorMessage only caught `sk-…` and `Bearer …`, so `api_key=…`,
  JSON `"apiKey": "…"`, `Authorization: Basic …` and query-string secrets
  were persisted in observer-health.json and rendered verbatim at session
  start. Redaction now covers the common key/value, JSON, authorization and
  query-string shapes, skips purely numeric values so `max_tokens: 200000`
  style diagnostics survive, and runs again at render time so a ledger
  written by an older build cannot leak.

- Concurrent failure writes could suppress the outage warning. The ledger's
  read-modify-write was unlocked, so simultaneous writers overwrote each
  other's increments and consecutiveFailures stayed under the threshold.
  Serialized with a `wx` lockfile (same idiom as worker-spawn-gate.ts),
  stale-breaking at 5s and failing open after a 2s wait — a racy count beats
  no count. Regression test drives three synchronized writer processes and
  requires the threshold to be reached; it fails ~2 in 3 runs without the lock.

Also rewrites the warning for humans (it is read by the user, not just the
agent) with a describeDuration helper, and rebuilds the plugin artifacts —
the committed context-generator.cjs was stale and shipped without the
observer-health injection.

* test(worker): restore the real ModeManager after session-manager-project mocks it

bun's mock.module is process-global and mock.restore() does not undo it, so
this file's partial ModeManager stub (no class prototype, no loadMode) leaked
into every later test file in the run. When readdir order put it before
tests/server/server-boot.test.ts and the server-runtime smoke, loadServerMode()
hit `modeManager.loadMode is not a function` and CI went red — which is exactly
what happened on this PR while main stayed green.

Applies the snapshot + afterAll re-register pattern already used in
agent-formatter, SearchManager.timeline-anchor, and response-processor tests;
session-manager-project was the last ModeManager mock without it.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 10:42:12 -07:00
Alex Newman a697e4a2d7 chore: bump version to 13.15.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 13:32:34 -07:00
Alex Newman de4930c041 chore: bump version to 13.14.0 2026-08-07 19:21:10 -07:00