Commit Graph

1663 Commits

Author SHA1 Message Date
Alex Newman c7c68e81f4 fix: address 10 unresolved PR review threads
- README: add language specifier to fenced code block
- paths.ts: guard npmPackageRootDirectory() against bundle structure drift
- OpenCodeInstaller: resolve bundle from import.meta.url, not process.cwd()
- OpenCodeInstaller: log warnings on AGENTS.md injection failures
- WindsurfHooksInstaller: key registry by full workspace path, not basename
- uninstall.ts: poll health endpoint to wait for worker exit before file deletion
- uninstall.ts: call IDE-specific uninstallers (Gemini, Windsurf, OpenCode, OpenClaw, Codex)
- opencode-plugin: cap session tracking Map at 1000 entries with LRU eviction
- GeminiCliHooksInstaller: document intentional JSON double-escaping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:45:53 -07:00
Alex Newman 21b10b4696 refactor: replace custom installer with native Claude plugin commands
Delegates to `claude plugin marketplace add` + `claude plugin install`
instead of manually copying files, registering marketplace/plugin JSON,
running npm install, and dispatching IDE-specific setup. 536 → 36 lines.

Also fixes double-shebang in npx-cli bundle (source + esbuild banner).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:35:06 -07:00
Alex Newman 4de417663c fix: catch corrupt JSON in Gemini CLI status command
readGeminiSettings() throws on corrupt JSON since ae6915b, but
checkGeminiCliHooksStatus() called it without catching — violating
its "returns 0 always" contract.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:29:08 -07:00
Alex Newman 190c74492f fix: address second PR review — clean replace, IDE failure bubbling, bun validation
- cpSync now does rmSync before copy to avoid stale file merges
- setupIDEs() returns failed IDE list; install reports partial success
- runSmartInstall() returns boolean status instead of void
- Worker port in next-steps URL reads CLAUDE_MEM_WORKER_PORT env var
- Goose YAML regex stops at column-0 keys (prevents eating sibling sections)
- AGENTS.md uninstall removes header-only stub files
- findBunPath() validated before use in WindsurfHooksInstaller
- Cursor marked unsupported in ide-detection until installer is wired

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:17:18 -07:00
Alex Newman ae6915b88e fix: address PR review — shebang, double-escaping, data loss, uninstall scope
- Add shebang banner to NPX CLI esbuild config so npx claude-mem works
- Remove manual backslash pre-escaping in WindsurfHooksInstaller (JSON.stringify handles it)
- Scope cache deletion to claude-mem only, not entire vendor namespace
- Use getWorkerPort() in OpenCodeInstaller instead of hard-coded 37777
- Throw on corrupt JSON in readJsonSafe/readGeminiSettings/Windsurf to prevent data loss
- Fix Cursor install stub to warn instead of silently succeeding
- Fix Gemini uninstall to remove individual hooks within groups, not whole groups
- Update tests for new corrupt-file-throws behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 13:49:14 -07:00
Alex Newman cdffdba97a test: add unit tests for MCP factory, context injection, JSON utils, and non-TTY install
59 tests across 4 files covering:
- context-injection: tag injection, replacement, headerLine support, idempotency
- json-utils: missing/valid/corrupt JSON handling with generic types
- mcp-integrations: factory function, process.execPath, idempotency, merge behavior
- install-non-tty: isInteractive detection, runTasks fallback, log wrapper

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:39:02 -07:00
Alex Newman 2495f98496 refactor: consolidate MCP factory, add non-TTY support, auto-detect transcript watchers
- Phase 1: Replace 5 duplicate MCP installers with config-driven factory, extract
  shared context-injection and json-utils utilities, fix process.execPath usage
- Phase 2: Add non-TTY fallback for @clack/prompts to prevent ENOENT in CI/Docker
- Phase 3: Wire GeminiCliHooksInstaller through hook command framework with adapter
- Phase 4: Auto-start transcript watchers on worker boot when config exists

Net -107 lines via DRY consolidation of duplicated installer logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:35:55 -07:00
Alex Newman a2ac116aac fix: move summary wait + session-complete into Stop hook to prevent lost summaries
SessionEnd has a 1.5s hardcoded cap from Claude Code (CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS),
making it unsuitable for waiting on async work. Previously, the Stop hook would fire-and-forget
the summarize request, then SessionEnd would immediately call deleteSession — aborting the SDK
agent mid-summary.

Now the Stop hook (120s timeout, no cap) owns the full lifecycle:
1. Queue summarize request
2. Poll new GET /api/sessions/status endpoint until queue drains
3. Call /api/sessions/complete after summary finishes

SessionEnd is now a true fire-and-forget fallback (process.exit(0) immediately).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:05:53 -07:00
Alex Newman 8265fc7aa1 Merge remote-tracking branch 'origin/thedotmack/npx-gemini-cli' into thedotmack/npx-gemini-cli
Resolve merge conflicts in adapter index, gemini-cli adapter, and rebuilt CJS artifacts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:47:49 -07:00
Alex Newman 76a880a3d6 feat: update install CLI, ESM compat, and Gemini CLI docs
Fixes CursorHooksInstaller ESM compatibility, updates install command
with improved path resolution, and refreshes built plugin artifacts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:38:45 -07:00
suyua9 8c03704246 docs: tighten session architecture wording 2026-04-04 01:38:49 +08:00
suyua9 91f73a83bc docs: align session architecture with current semantics 2026-04-04 01:24:48 +08:00
Octopus c74101b7f7 fix: handle bare filenames in regenerate-claude-md.ts (fixes #1514) 2026-04-03 10:07:11 +08:00
Octopus 1b5d1a1234 fix: handle bare filenames in path-utils.ts isDirectChild 2026-04-03 10:07:03 +08:00
Octopus c4146cca67 fix: provide empty JSON fallback when stdin is not piped (fixes #1560) 2026-04-03 10:03:29 +08:00
ming eea9c100ba fix: harden plugin manifest sync script 2026-04-02 20:15:26 +08:00
ming 16f79d6f71 chore: sync plugin manifest metadata from package 2026-04-02 20:07:00 +08:00
ming a74ff0034f fix: add Codex plugin manifest for discoverability 2026-04-02 18:44:59 +08:00
Alex Newman a66b98bcdd fix: strip <system-reminder> tags from persisted memory and DRY up regex
System reminders (CLAUDE.md contents, deferred tool lists) were being
stored in memory observations. Add system-reminder to the tag stripping
pipeline alongside <private> and <system_instruction>, and extract the
duplicated regex into a shared SYSTEM_REMINDER_REGEX constant.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:25:13 -07:00
Jarvis bd47a919a8 fix: use cmd /c to execute bun.cmd on Windows
Instead of using shell:true with spawn(), use cmd.exe as the command
with /c flag to properly execute bun.cmd on Windows.

Without this, spawn() with shell:true fails because cmd.exe doesn't
know how to handle the bun shell script directly.

Fixes: Stop hook "Failed to start Bun: spawn bun ENOENT"
2026-04-02 13:06:12 +08:00
Jarvis 4d4b0a2f24 fix: prefer bun.cmd over bun shell script on Windows
Windows npm installs both bun (shell script) and bun.cmd (batch file).
When spawning bun, cmd.exe cannot execute the shell script directly.
This change makes findBun() return the full path to bun.cmd on Windows.

Fixes: Stop hook "spawn bun ENOENT" on Windows
2026-04-02 13:00:15 +08:00
Jarvis 472d302133 fix: add shell:true on Windows to spawn bun from npm
Windows npm installs bun as a shell script (C:\Users\...\AppData\Roaming\npm\bun),
not a native executable. Without shell:true, spawn() fails with ENOENT
when trying to execute it.

Fixes Stop hook failure: "Failed to start Bun: spawn bun ENOENT"
2026-04-02 12:50:56 +08:00
Alex Newman 303aafa64b chore: rebuild after merge from main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:11:49 -07:00
Alex Newman 67645041fa Merge main into thedotmack/file-read-timeline-inject
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:11:41 -07:00
Ousama Ben Younes d8eb2fa9f9 fix: resolve hook failures when CLAUDE_PLUGIN_ROOT is not injected (#1533)
The fallback path for CLAUDE_PLUGIN_ROOT was pointing to the old
marketplaces install location which no longer exists. Hooks now first
try to find the latest versioned cache directory
(~/.claude/plugins/cache/thedotmack/claude-mem/<version>/) using ls -dt,
with the marketplaces path kept as a final fallback.

This mirrors the self-resolution pattern already used in bun-runner.js
(resolve(__bun_runner_dirname, '..')) but at the shell level, so node
can find bun-runner.js in the first place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 07:01:37 +00:00
Ousama Ben Younes 93a30c5c8f fix: skip parseSummary false positives with no sub-tags (#1360)
When an observation response accidentally contains a <summary> tag with
plain text (no <request>/<investigated>/etc. sub-tags), parseSummary was
creating empty SESSION SUMMARY records with all fields as empty strings.

Add an all-null guard AFTER field extraction: if none of the 5 sub-tags
matched, the <summary> match is a false positive and we return null.

This is distinct from the commented-out validation above (which rejected
summaries with SOME missing fields). We only reject when ALL are absent —
real partial summaries are still saved per the maintainer's explicit note.

Closes #1360

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-01 06:51:33 +00:00
Ousama Ben Younes 2a304d59eb fix: handle bare path strings in files_modified/files_read columns (#1359)
JSON.parse('/path/to/file') throws SyntaxError, crashing the viewer and
any code reading observations with legacy bare-path data in those columns.

- Add parseFileList() helper in observations/files.ts — tries JSON.parse,
  falls back to wrapping bare strings in an array
- Replace unsafe JSON.parse calls in files.ts, SessionStore.ts, ChromaSync.ts
- Add 9 unit tests covering null, empty, valid JSON, bare paths, invalid JSON

Closes #1359

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-01 06:17:35 +00:00
Ousama Ben Younes 12501412b9 fix: persist session completion to database in completeByDbId (#1532)
completeByDbId only cleaned up in-memory state, leaving sdk_sessions rows
with status='active' and completed_at=NULL indefinitely. Ghost sessions
accumulated and exhausted the agent pool, causing 60s timeout errors.

- Add SessionStore.markSessionCompleted() to set status/completed_at/completed_at_epoch
- Call it at the start of completeByDbId before in-memory cleanup
- Inject SessionStore into SessionCompletionHandler via constructor
- Add 4 tests covering status, timestamps, isolation, and non-existent IDs

Closes #1532

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-01 06:02:14 +00:00
Ousama Ben Younes fb8c9dbdbe fix: prevent shell injection in summary workflow (#1285)
The gh issue comment command was interpolating the LLM response via
${{ steps.inference.outputs.response }} directly in the shell, allowing
single-quote escaping if the response contained untrusted content.
RESPONSE was already declared as an env var but unused — now using it.

Closes #1285

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-01 05:13:53 +00:00
Ousama Ben Younes b81281fd6c fix: update default model from claude-sonnet-4-5 to claude-sonnet-4-6 (#1390)
CLAUDE_MEM_MODEL defaulted to the deprecated claude-sonnet-4-5 across source,
installer, tests, and documentation. Updated all references to claude-sonnet-4-6.

Closes #1390

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-31 22:42:23 +00:00
Kevin Crawley 247d287bdc Fix error log message to use dynamic target filename 2026-03-31 06:20:33 -05:00
Kevin Crawley 2a6c9ea2b7 Add CLAUDE.local.md support via CLAUDE_MEM_FOLDER_USE_LOCAL_MD setting
When CLAUDE_MEM_FOLDER_USE_LOCAL_MD is set to 'true' in settings,
claude-mem writes auto-generated context to CLAUDE.local.md instead
of CLAUDE.md. This separates personal machine-generated context from
shared project instructions, aligning with Claude Code's native
CLAUDE.local.md convention where:

- CLAUDE.md = team-shared project instructions (checked into git)
- CLAUDE.local.md = personal/local context (gitignored)

Changes:
- Add CLAUDE_MEM_FOLDER_USE_LOCAL_MD setting (default: false)
- Add getTargetFilename() helper to resolve target based on settings
- Update writeClaudeMdToFolder() to accept optional target filename
- Update active-file detection to skip folders with either CLAUDE.md
  or CLAUDE.local.md being actively read/modified (issue #859 compat)
- Add 8 new tests covering filename selection, write behavior,
  content preservation, atomic writes, and active-file detection

Closes #632
2026-03-31 06:20:33 -05:00
Oracle Public Cloud User 4589b34eab fix: decouple mcp health from loopback self-check 2026-03-30 16:37:56 +00:00
GigiTiti-Kai 7fce21c145 fix: deduplicate session init to prevent multiple prompt records
When using the OpenClaw integration, a single user message would produce
3 prompt records because session_start, message_received, after_compaction,
and before_agent_start each independently called /api/sessions/init with
different session keys.

Changes:
- Centralize /api/sessions/init to before_agent_start only
- Add canonical session key unification (sessionKey, conversationId,
  channelId mapped to a single contentSessionId)
- Add 2-second dedup guard for edge cases
- Fix cwd: "" in tool_result_persist (use workspaceDir fallback chain,
  skip + warn if unavailable)
- Add delayed session completion (configurable, default 5s) to avoid
  race with in-flight observations
- Clean up all tracking Maps on session_end and gateway_start

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:20:18 +09:00
Ryan Malia b0f1a458cf fix: log warning when readiness times out on reused-worker path (#1491)
Mirror the fresh-spawn path's timeout logging for debugging parity.
CodeRabbit nitpick on PR #1491.

Co-Authored-By: CC <noreply@anthropic.com>
2026-03-30 03:47:08 -07:00
Ryan Malia 83f61177c7 fix: address CodeRabbit review feedback on PR #1491
- Update POST_SPAWN_WAIT test assertion from 5000 to 15000 to match
  the constant change in hook-constants.ts
- Remove redundant readPidFile() from aggressiveStartupCleanup() —
  start() writes the new PID before this runs, so it always returns
  process.pid (already protected)
- Add waitForReadiness() to the reused-worker path in
  ensureWorkerStarted() to prevent concurrent hooks from racing
  past a cold-starting worker's initialization guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 03:43:36 -07:00
Ryan Malia 88b47f9e9c fix: prevent worker daemon from being killed by its own hooks (#1490)
Three independent fixes for worker daemon instability:

1. Remove version mismatch auto-restart from ensureWorkerStarted() (#1435).
   The marketplace bundle ships with __DEFAULT_PACKAGE_VERSION__ unbaked,
   causing BUILT_IN_VERSION to fall back to "development". This creates a
   100% reproducible mismatch on every hook call, killing a healthy worker
   and often failing to restart. Same pattern across #566, #665, #667,
   #669, #689, #1124, #1145 (8+ releases).

2. Add process.ppid and PID-file PID to aggressiveStartupCleanup()
   exclusions (#1426). Without this, a newly spawned daemon SIGKILLs
   the hook process that spawned it and any already-running worker
   the PID file points to.

3. Increase POST_SPAWN_WAIT from 5s to 15s (#1423). The 5s timeout was
   sized for Linux (<1s startup) but macOS ARM64 cold starts take 6-8s
   with Chroma enabled.
2026-03-30 03:43:36 -07:00
JasonOA888 f86be1ef2b fix(project-name): expand ~ to home directory before project resolution
Fixes #1478

When a terminal reports cwd as '~' or '~/subpath' instead of the full
path, getProjectName() fell through to the 'unknown-project' fallback
because path.basename('~') returns '~' as-is.

Added expandTilde() helper that resolves leading ~ to os.homedir(),
called in both getProjectName() and getProjectContext() before path
operations and worktree detection.
2026-03-30 09:12:23 +08:00
Alex Newman d06882126f docs: update CHANGELOG.md for v10.6.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:50:03 -07:00
Alex Newman ddb57ea598 chore: bump version to 10.6.3
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v10.6.3
2026-03-28 19:49:24 -07:00
Alex Newman 6885bdb019 Merge pull request #1518 from thedotmack/thedotmack/patch-plan-issues
fix: patch 7 critical bugs for v10.6.3
2026-03-28 19:48:43 -07:00
Alex Newman 0321f4266d fix: remove import.meta.url banner from CJS files run by Node.js
The MCP server (#!/usr/bin/env node) and context generator run under
Node.js, where import.meta.url throws SyntaxError in CJS mode. Only
the worker-service needs the banner since it runs under Bun.

CJS files under Node.js already have __dirname/__filename natively.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:32:43 -07:00
Alex Newman 80d1deedbe fix: address PR review feedback from CodeRabbit
- Add sessionId to summarize.ts warning log for easier triage
- Add APPROVED OVERRIDE annotation to Windows spawn catch block

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:34:42 -07:00
Alex Newman 07ab7000a8 fix: patch 7 critical bugs affecting all non-dev-machine users and Windows
1. Fix esbuild inlining build-machine __dirname as string literal — use
   CJS-compatible runtime banner with require("node:url").fileURLToPath
   across worker-service, mcp-server, and context-generator builds.

2. Fix isMainModule check missing .cjs extension and Windows backslash
   path normalization.

3. Wrap extractLastMessage in try-catch to prevent infinite Stop hook
   feedback loop on malformed transcripts (exit 0 instead of exit 2).

4. Replace heavy SessionEnd hook (Node→Bun→1.7MB CJS→HTTP) with
   lightweight inline node -e one-liner (~200ms vs >1s).

5. Add 7 Gemini/OpenRouter error patterns to unrecoverablePatterns
   circuit breaker to prevent 77K+ retry loops on expired API keys.

6. Preserve CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_CODE_GIT_BASH_PATH in
   sanitizeEnv instead of stripping them with the CLAUDE_CODE_ prefix.

7. Use PowerShell -EncodedCommand for spawnDaemon to fix path quoting
   when Windows usernames contain spaces.

Closes #1515, #1495, #1475, #1465, #1500, #1513, #1512, #1450, #1460,
#1486, #1449, #1481, #1451, #1480, #1453, #1445

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:20:29 -07:00
nimesh-kumar-sh a48bf89963 fix: fail worker-start hook if worker never becomes healthy
Address CodeRabbit review: add a final health check after the retry
loop so genuine worker startup failures surface as hook errors instead
of being silently masked.
2026-03-27 13:03:05 -07:00
nimesh-kumar-sh 368daddd88 fix(bun-runner): treat signal-based exits for 'start' as success
Defense-in-depth for #1505. When the 'start' subcommand forks a daemon,
the parent bun process may be killed by signal (exit > 128). If the
close handler fires, treat this as success since the daemon started fine.

Note: the primary fix is in hooks.json since the SIGKILL often kills
the entire process group before this handler fires.
2026-03-27 12:52:36 -07:00
nimesh-kumar-sh ed444dfec7 fix: SessionStart hooks fail on cold start due to worker race condition
The worker-start hook's `start` subcommand forks a daemon then SIGKILLs
its own process group, killing bun-runner.js before it can report exit 0.
Since all SessionStart hooks run in parallel, the context hook also fails
because the worker isn't listening yet.

Fix:
- worker-start: continue after the SIGKILL via `;`, poll the worker
  health endpoint until ready, then output valid JSON (exit 0)
- context: wait for worker health before attempting to fetch context

Fixes #1505
2026-03-27 12:52:02 -07:00
Alan T Miller 4aa7119d7d fix: remove dead USER_MESSAGE_ONLY exit code that caused SessionStart hook errors
The USER_MESSAGE_ONLY (exit code 3) constant was used by the old
user-message-hook.js (removed in the hooks refactor). Claude Code only
recognizes exit codes 0 (success) and 2 (blocking error) — any other
non-zero exit code is treated as a hook failure, causing the
"SessionStart:startup hook error" message on every session start for
users still running v8.x.

This removes the dead constant and improves the exit code documentation
to prevent reintroduction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:59:53 -07:00
Conductor 5621b67ccd Saving uncommitted changes before archiving 2026-03-26 19:35:27 -07:00
79475432@qq.com 9cfa57d498 fix: use null-byte delimiter in observation content hash to prevent collisions
Fields concatenated without separators allowed different tuples to produce
identical hashes (e.g. session="ab", title="cd" vs session="abc", title="d").
This could cause legitimate observations to be silently deduplicated.

Join with \x00 so field boundaries are unambiguous.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:16:17 +08:00