Files
thedotmack__claude-mem/cowork/test
Alex Newman 2dcb556d26 feat: cowork plugin + Memory Prize scorecard (worktree consolidation) (#3733)
* feat(cowork): add claude-mem-cowork plugin — memory for Claude app cloud sessions

Cowork/Claude-app cloud sessions run in ephemeral containers where the
local worker can't live. This plugin replaces it with thin HTTP hook
shims: PostToolUse streams raw tool-use fragments to POST /api/hooks/ingest
(spool + batch-flush on failure), SessionStart injects compiled context
from GET /api/hooks/context with a project-scoped fallback to the live
/api/mcp memory_search, and PreToolUse on Task/Agent prepends relevant
observations into every spawned agent's prompt via updatedInput.

- project naming is always automatic (cmem_work_root / cmem_work_<folder>),
  deliberately not a setting
- empty projects inject a 'Claude-Mem is taking notes' notice with the
  local worker viewer link (port from ~/.claude-mem/settings.json)
- unpaired installs are fully inert; every hook exits 0 unconditionally
- bundled skills: mem-search (progressive search) and mem-setup (pairing)
- PRO-ENDPOINT-SPEC.md documents the two server endpoints; ingest maps 1:1
  onto the existing worker fragment queue
- 32-test mock-server suite in cowork/test/run-tests.mjs
- registered in .claude-plugin/marketplace.json

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

* fix(cowork): read real claude-mem settings keys in the ~/.claude-mem fallback

The compat fallback looked for syncToken/userId/syncHubUrl/workerPort, but a
local claude-mem install writes CLAUDE_MEM_CLOUD_SYNC_TOKEN / _USER_ID /
_HUB_URL / CLAUDE_MEM_WORKER_PORT (SettingsDefaultsManager). Honor those
first (old short names still accepted), update mem-setup + README, and make
the fallback test use the real key names.

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

* fix(cowork): include cwd in the session-end envelope so the summary lands on the session's project

Verified live: a session-end sent from a different working directory filed
its summary under the hook process's project instead of the session's.

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

* fix(cowork): redact secrets before envelope, per-user 0600 spool, merge-don't-clobber spool recovery

Addresses greptile P1 findings on PR #3707:
- observation/prompt payloads pass a secret-redaction pass (PEM blocks, auth
  headers, JWTs, vendor token prefixes, key=value assignments) before the
  envelope is built, so neither ingest nor the retry spool sees raw credentials
- spool moved from world-readable /tmp to ~/.claude-mem/cowork-spool.jsonl,
  created 0600
- failed spool flush now merges the claim back via append instead of
  renameSync over a replacement spool created by a concurrent hook, so
  concurrent events are no longer dropped
- test harness: hermetic $HOME, redaction + spool-permission checks (38 checks)

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

* fix(cowork): strip <private>-tagged regions before observation envelopes

Ports the local plugin's tag-stripping convention (src/utils/tag-stripping.ts)
into the cowork shim: <private>, <claude-mem-context>, <system-instruction>,
<persisted-output>, and <system-reminder> regions are removed from tool
payloads and session-init prompts before the envelope exists, so explicitly
non-storable content reaches neither ingest nor the retry spool. Stripping
runs before truncation so a cut-off closing tag can never leak a partial
private region. 4 new harness checks (42 total).

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

* fix(cowork): redact connection-string credentials (scheme://user:pass@)

URI userinfo with a password now redacts to scheme://[cmem-redacted]@host —
covers postgres/mysql/redis/amqp/mongodb-style DATABASE_URLs that matched
neither the vendor-token patterns nor KEYVALUE_RE. Bare user@ URIs
(ssh://git@github.com) stay intact — that's signal, not secret. Mirrors the
userinfo rule in src/services/telemetry/error-scrub.ts. 3 new harness checks
(45 total).

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

* fix(cowork): full URI userinfo redaction, Cookie header redaction, oldest-first spool recovery

Round 3 of greptile P1s:
- URI credential redaction now covers passwords containing literal '/', ':'
  or '@' — userinfo is everything up to the LAST '@' in the URI token, so
  postgresql://admin:pa/ss@host and admin:pa@ss@host both fully redact
  (bare user@ like ssh://git@github.com still passes through as signal)
- Cookie:/Set-Cookie: header values redact wholesale regardless of cookie name
- failed-flush recovery drains a concurrent replacement spool onto the claim's
  tail (old→new) and restores via wx (no clobber, append fallback); flushSpool
  additionally stable-sorts the batch by ts so replay is always oldest-first
- 6 new harness checks (50 total)

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

* fix(cowork): overflow spool re-spools the remainder instead of dropping oldest events

flushSpool sent only the newest SPOOL_MAX lines but deleted the whole claim on
success, permanently losing anything older once the spool exceeded 200 events.
It now sends the OLDEST 200 and re-spools the remainder for the next flush —
bounded batches, zero silent drops. On failure the untouched claim still
restores in full. 4 new harness checks incl. a 201-event drain (54 total).

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

* fix(cowork): claim spool before reading it; redact any Authorization scheme

- flushSpool now renames (claims) the spool FIRST and reads the claim, so an
  event appended between read and rename can no longer travel into the claim
  unread and be deleted on success — later appenders always write a fresh spool
- Authorization/Proxy-Authorization header values redact wholesale regardless
  of scheme (Token, ApiKey, custom), and the inline scheme pattern gains Token
- 2 new harness checks: Token credential absent from request body and from the
  failed-delivery spool (56 total)

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

* docs: add Memory Prize scorecard and slides (hackathon 05)

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

* fix(cowork): redact short and whitespace-bearing credential values; align marketplace version

- KEYVALUE_RE no longer requires 6+ non-whitespace chars: sensitive-key
  values are redacted in full through the line or record delimiter, so
  short passwords and passphrases containing spaces never reach the
  ingest payload or spool (Greptile P1)
- marketplace.json bumped to 0.1.3 to match plugin.json and the
  X-CMEM-Plugin runtime header (Greptile P2)
- regression tests for short, whitespace-bearing, and short query-string
  credential values

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 16:01:35 -07:00
..