Commit Graph

1590 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
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 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
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
Alex Newman a656af2bff feat: improve Gemini CLI timeline display by stripping ANSI colors and providing markdown fallback 2026-03-25 23:51:56 -07:00
zengyuzhi fe8c65a8cd feat(openclaw): add workerHost config for Docker deployments
When the OpenClaw gateway runs in Docker and the claude-mem worker runs
on the host, localhost:37777 is unreachable from inside the container.

Add a workerHost config option (default: 127.0.0.1) so users can set it
to host.docker.internal for Docker-based deployments.

Changes:
- Add workerHost to ClaudeMemPluginConfig interface
- Read workerHost from plugin config in plugin entry point
- Update workerBaseUrl to use configurable host
- Add workerHost to openclaw.plugin.json config schema
- Update startup log to show configured host
2026-03-25 14:40:33 +08:00
Alex Newman 88636ec012 feat: remove old installer, update docs to npx claude-mem
Removes installer/ directory (16 files) — fully replaced by src/npx-cli/.
Updates install.sh and installer.js to redirect to npx claude-mem.
Adds npx claude-mem as primary install method in docs and README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:18 -07:00
Alex Newman 031513d723 feat: add Codex CLI, OpenClaw, and MCP-based IDE integrations
Codex CLI: transcript-based integration watching ~/.codex/sessions/,
schema bumped to v0.3 with exec_command support, AGENTS.md context.

OpenClaw: installer wires pre-built plugin to ~/.openclaw/extensions/,
registers in openclaw.json with memory slot and sync config.

MCP integrations (6 IDEs): Copilot CLI, Antigravity, Goose, Crush,
Roo Code, and Warp — config writing + context injection. Goose uses
string-based YAML manipulation (no parser dependency).

All 13 IDE targets now supported in npx claude-mem install.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:18 -07:00
Alex Newman f2cc33b494 feat: add Gemini CLI, OpenCode, and Windsurf IDE integrations
Gemini CLI: platform adapter mapping 6 of 11 hooks, settings.json
deep-merge installer, GEMINI.md context injection.

OpenCode: plugin with tool.execute.after interceptor, bus events for
session lifecycle, claude_mem_search custom tool, AGENTS.md context.

Windsurf: platform adapter for tool_info envelope format, hooks.json
installer for 5 post-action hooks, .windsurf/rules context injection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:18 -07:00
Alex Newman 3a09c1bb1a feat: add NPX CLI and OpenClaw build pipeline, optimize npm package size
Adds esbuild steps for npx-cli (57KB, Node.js ESM) and openclaw plugin
(12KB). Creates .npmignore to exclude node_modules and Bun binary from
npm package, reducing pack size from 146MB to 2MB.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:18 -07:00
Alex Newman 85eb796b18 feat: add npx CLI entry point with install, runtime, and IDE detection commands
Replaces the old git-clone installer with a direct npm package copy workflow.
Supports 13 IDE auto-detection targets, runtime delegation to Bun worker,
and pure Node.js install path (no Bun required for installation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:18 -07:00
JasonRD b6f9950bb3 fix(installer): make post-install allowlist write guaranteed
- Remove '|| true' that was hiding write failures
- Add fallback path when config doesn't exist yet (triggers materialization)
- Add logging for allowlist operations
- Report warnings on write failures instead of silent failure

Addresses CodeRabbit review comment on PR #1457
2026-03-24 09:14:27 +08:00
Jason 4324f6bbc1 fix(openclaw): handle stale plugins.allow and non-interactive tty in installer 2026-03-23 18:28:48 +08:00
Alex Newman e2a230286d docs: update CHANGELOG.md for v10.6.2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:14:43 -07:00
Alex Newman 0524fa83cd chore: bump version to 10.6.2
Publish to npm / publish (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v10.6.2
2026-03-21 14:14:09 -07:00
Alex Newman 4d7bec4d05 fix: stop spinner from spinning forever (#1440)
* fix: stop spinner from spinning forever due to orphaned DB messages

The activity spinner never stopped because isAnySessionProcessing() queried
ALL pending/processing messages in the database, including orphaned messages
from dead sessions that no generator would ever process.

Root cause: isAnySessionProcessing() used hasAnyPendingWork() which is a
global DB scan. Changed it to use getTotalQueueDepth() which only checks
sessions in the active in-memory Map.

Additional fixes:
- Add terminateSession() to enforce restart-or-terminate invariant
- Fix 3 zombie paths in .finally() handler that left sessions alive
- Clean up idle sessions from memory on successful completion
- Remove redundant bare isProcessing:true broadcast
- Replace inline require() with proper accessor
- Add 8 regression tests for session termination invariant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review findings — idle-timeout race, double broadcast, query amplification

- Move pendingCount check before idle-timeout termination to prevent
  abandoning fresh messages that arrive between idle abort and .finally()
- Move broadcastProcessingStatus() inside restart branch only — the else
  branch already broadcasts via removeSessionImmediate callback
- Compute queueDepth once in broadcastProcessingStatus() and derive
  isProcessing from it, eliminating redundant double iteration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:13:10 -07:00
Alex Newman 5b041d6b49 refactor: rename formatters to AgentFormatter/HumanFormatter for semantic clarity
ColorFormatter and MarkdownFormatter names obscured their actual purpose.
The formatters serve two distinct audiences: the AI agent (compressed,
token-efficient context) and the human (rich ANSI-colored terminal output).

- MarkdownFormatter → AgentFormatter (renderMarkdown* → renderAgent*)
- ColorFormatter → HumanFormatter (renderColor* → renderHuman*)
- useColors parameter → forHuman across the pipeline
- Import aliases Color/Markdown → Human/Agent
- API query param `colors=true` unchanged (backward compatible)

Pure rename refactor — no logic or behavior changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:50:41 -07:00