chore: merge upstream v12.4.7 + keep local fixes

Major upstream changes (v12.3.9 → v12.4.7):

v12.3.9 — Stop hook fire-and-forget (eliminates ~110s terminal block);
  hook port precedence; Telegram notifier; security_alert/security_note
  observation types

v12.4.0/12.4.1 — worker startup streamlined; consolidated DB connections;
  Chroma backfill watermark cache (422% CPU → 0% on restart)

v12.4.2 — context-overflow infinite loop fixed (clears memorySessionId
  on "Prompt is too long"); <task-notification> payload pollution blocked
  at hook + worker boundary

v12.4.3 — one-time pollution cleanup migration (CleanupV12_4_3):
  purges observer-sessions rows + cascade, stuck pending chains, Chroma
  rebuild; auto VACUUM INTO backup. Ran successfully on this DB:
  - 1463 observer-sessions purged
  - 3682 cascade rows
  - 102MB backup at ~/.claude-mem/backups/

v12.4.4 — stop draining queue on /clear (removes SessionEnd shim that
  had been abandoning pending observations for 6 months)

v12.4.5 — fix observation persistence on fresh installs (migration 28
  mirror in SessionStore)

v12.4.7 — cynical-deletion sweep (closes 27 issues); multi-account
  isolation via per-UID worker port (37700 + uid % 100, with explicit
  CLAUDE_MEM_WORKER_PORT override); CLAUDE_MEM_INTERNAL=1 trust boundary
  replaces cwd-based observer-session detection; observations.metadata
  column (migration 30); proxy env vars stripped from spawned subprocs

Local fixes preserved:
- env-sanitizer PATH extension for claude CLI lookup (auto-merged
  cleanly with upstream's new ENV_PROXY_VARS proxy stripping)
- SessionStore stale session reset (mac sleep / 4h wall-clock)

Settings: CLAUDE_MEM_WORKER_PORT=37777 explicit override preserved
through the per-UID port migration. Worker restarted to v12.4.7.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
JOUNGWOOK KWON
2026-04-26 18:13:22 +09:00
212 changed files with 20972 additions and 6600 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claude-mem",
"version": "12.3.8",
"version": "12.4.7",
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
"author": {
"name": "Alex Newman"
+17 -20
View File
@@ -7,7 +7,8 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$HOME/.nvm/versions/node/v$(ls \\\"$HOME/.nvm/versions/node\\\" 2>/dev/null | sed 's/^v//' | sort -t. -k1,1n -k2,2n -k3,3n | tail -1)/bin:$HOME/.local/bin:/usr/local/bin:/opt/homebrew/bin:$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/smart-install.js\"",
"shell": "bash",
"command": "export PATH=\"$HOME/.nvm/versions/node/v$(ls \\\"$HOME/.nvm/versions/node\\\" 2>/dev/null | sed 's/^v//' | sort -t. -k1,1n -k2,2n -k3,3n | tail -1)/bin:$HOME/.local/bin:/usr/local/bin:/opt/homebrew/bin:$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/smart-install.js\"",
"timeout": 300
}
]
@@ -19,17 +20,20 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/smart-install.js\"",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/smart-install.js\"",
"timeout": 300
},
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" start; for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1 && break; sleep 1; done; curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1 || true; echo '{\"continue\":true,\"suppressOutput\":true}'",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" start; echo '{\"continue\":true,\"suppressOutput\":true}'",
"timeout": 60
},
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1 && break; sleep 1; done; if curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1; then node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code context || true; fi",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code context",
"timeout": 60
}
]
@@ -40,7 +44,8 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; _HEALTH=0; curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1 && _HEALTH=1 || for i in 1 2 3 4 5 6 7 8 9 10; do sleep 1; curl -sf http://localhost:$((37700 + $(id -u 2>/dev/null || echo 77) % 100))/health >/dev/null 2>&1 && _HEALTH=1 && break; done; [ \"$_HEALTH\" = \"1\" ] && node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-init",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-init",
"timeout": 60
}
]
@@ -52,7 +57,8 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code observation",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code observation",
"timeout": 120
}
]
@@ -64,8 +70,9 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code file-context",
"timeout": 2000
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code file-context",
"timeout": 60
}
]
}
@@ -75,22 +82,12 @@
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code summarize",
"shell": "bash",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt \"$HOME/.claude/plugins/cache/thedotmack/claude-mem\"/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; command -v cygpath >/dev/null 2>&1 && { _W=$(cygpath -w \"$_R\" 2>/dev/null); [ -n \"$_W\" ] && _R=\"$_W\"; }; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code summarize",
"timeout": 120
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-complete",
"timeout": 30
}
]
}
]
}
}
+14
View File
@@ -44,6 +44,20 @@
"description": "Architectural/design choice with rationale",
"emoji": "⚖️",
"work_emoji": "⚖️"
},
{
"id": "security_alert",
"label": "Security Alert",
"description": "A security issue that needs attention before continuing.",
"emoji": "🚨",
"work_emoji": "🚨"
},
{
"id": "security_note",
"label": "Security Note",
"description": "A security-relevant observation worth recording, but not urgent.",
"emoji": "🔐",
"work_emoji": "🔐"
}
],
"observation_concepts": [
+2 -1
View File
@@ -1,10 +1,11 @@
{
"name": "claude-mem-plugin",
"version": "12.3.8",
"version": "12.4.7",
"private": true,
"description": "Runtime dependencies for claude-mem bundled hooks",
"type": "module",
"dependencies": {
"zod": "^4.3.6",
"tree-sitter-cli": "^0.26.5",
"tree-sitter-c": "^0.24.1",
"tree-sitter-cpp": "^0.23.4",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -57
View File
@@ -339,61 +339,6 @@ function installUv() {
}
}
/**
* Add shell alias for claude-mem command
*/
function installCLI() {
const WORKER_CLI = join(ROOT, 'scripts', 'worker-service.cjs');
const bunPath = getBunPath() || 'bun';
const aliasLine = `alias claude-mem='${bunPath} "${WORKER_CLI}"'`;
const markerPath = join(ROOT, '.cli-installed');
// Skip if already installed
if (existsSync(markerPath)) return;
try {
if (IS_WINDOWS) {
// Windows: Add to PATH via PowerShell profile
const profilePath = join(process.env.USERPROFILE || homedir(), 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');
const profileDir = join(process.env.USERPROFILE || homedir(), 'Documents', 'PowerShell');
const functionDef = `function claude-mem { & "${bunPath}" "${WORKER_CLI}" $args }\n`;
if (!existsSync(profileDir)) {
execSync(`mkdir "${profileDir}"`, { stdio: 'ignore', shell: true });
}
const existingContent = existsSync(profilePath) ? readFileSync(profilePath, 'utf-8') : '';
if (!existingContent.includes('function claude-mem')) {
writeFileSync(profilePath, existingContent + '\n' + functionDef);
console.error(`✅ PowerShell function added to profile`);
console.error(' Restart your terminal to use: claude-mem <command>');
}
} else {
// Unix: Add alias to shell configs
const shellConfigs = [
join(homedir(), '.bashrc'),
join(homedir(), '.zshrc')
];
for (const config of shellConfigs) {
if (existsSync(config)) {
const content = readFileSync(config, 'utf-8');
if (!content.includes('alias claude-mem=')) {
writeFileSync(config, content + '\n' + aliasLine + '\n');
console.error(`✅ Alias added to ${config}`);
}
}
}
console.error(' Restart your terminal to use: claude-mem <command>');
}
writeFileSync(markerPath, new Date().toISOString());
} catch (error) {
console.error(`⚠️ Could not add shell alias: ${error.message}`);
console.error(` Use directly: ${bunPath} "${WORKER_CLI}" <command>`);
}
}
/**
* Check if dependencies need to be installed
*/
@@ -629,8 +574,8 @@ try {
// Worker will be started fresh by next hook in chain (worker-service.cjs start)
}
// Step 4: Install CLI to PATH
installCLI();
// Step 4 (removed in #2054): legacy `claude-mem` shell alias was deleted.
// Users invoke the CLI via `npx claude-mem <cmd>` or `bunx claude-mem <cmd>`.
// Step 5: Warn if the bundled native binary is incompatible with this platform
checkBinaryPlatformCompatibility();
File diff suppressed because one or more lines are too long
+111
View File
@@ -0,0 +1,111 @@
---
name: pathfinder
description: Map a codebase into feature-grouped flowcharts, identify duplicated concerns across features, and propose a unified architecture. Use when asked to "find the ideal path," unify duplicated systems, or audit architecture before a refactor. Emits a proposed unified flowchart plus per-system /make-plan prompts.
---
# Pathfinder
You are an ORCHESTRATOR. Map the codebase into feature-grouped flowcharts, identify duplicated concerns, propose the simplest unified architecture, and hand off per-system plans to `/make-plan`.
You do not write implementation code. You produce diagrams, a duplication report, a proposed unified flowchart, and handoff prompts.
## Delegation Model
Use subagents for *discovery and extraction* (file reading, flow tracing, grep, diagramming). Keep *synthesis* (deciding feature boundaries, picking unification strategies, final flowchart) with the orchestrator. Reject subagent reports that lack source citations and redeploy.
### Subagent Reporting Contract (MANDATORY)
Each subagent response must include:
1. Sources consulted — exact file paths and line ranges read
2. Concrete findings — exact function names, call sites, data flow
3. Mermaid diagram(s) with nodes labeled by `file:line`
4. Confidence note + known gaps
## Output Artifacts
All artifacts go in `PATHFINDER-<YYYY-MM-DD>/` at repo root:
- `00-features.md` — feature inventory with boundaries
- `01-flowcharts/<feature>.md` — one Mermaid flowchart per feature
- `02-duplication-report.md` — cross-cutting duplicated concerns with evidence
- `03-unified-proposal.md` — proposed unified architecture + Mermaid
- `04-handoff-prompts.md` — copy-pasteable `/make-plan` prompts per unified system
## Phases
### Phase 0: Feature Discovery (ALWAYS FIRST)
Deploy ONE "Feature Discovery" subagent to:
1. Walk the source tree (not built artifacts) and read top-level README / CLAUDE.md
2. Propose feature boundaries based on directory structure, import graph, and naming
3. Return a flat list of features with: name, entry points (file:line), core files, brief purpose
Orchestrator reviews the proposal, adjusts boundaries if needed, writes `00-features.md`. Do NOT fan out until feature boundaries are approved.
### Phase 1: Per-Feature Flowcharts (FAN OUT)
Deploy ONE "Flowchart" subagent per feature in parallel. Each receives only its feature's scope. Each must:
1. Trace the feature's primary happy path from entry point to terminal state
2. Identify side effects (DB writes, HTTP calls, file I/O, process spawns)
3. Note error and fallback branches but do not let them dominate the diagram
4. Produce a Mermaid `flowchart TD` with every node labeled `Name<br/>file:line`
5. List external dependencies (other features it calls into) at the bottom
Orchestrator writes each flowchart to `01-flowcharts/<feature>.md`. Reject any diagram missing `file:line` labels.
### Phase 2: Duplication Hunt
Deploy TWO subagents in parallel:
**"Within-Feature Duplication"** subagent:
- For each feature, find repeated code/logic patterns inside the feature only
- Report only duplications worth consolidating (ignore trivial repetition)
**"Cross-Feature Duplication"** subagent:
- Compare flowcharts across features for concerns that appear in multiple places
- Examples of what to look for: multiple capture paths, parallel queue implementations, duplicated storage/migration code, repeated agent scaffolding, parallel parsing layers
- For each duplication, report: (a) the concern, (b) every location with `file:line`, (c) why they diverged, (d) whether the divergence is legitimate specialization or accidental
Orchestrator synthesizes both into `02-duplication-report.md`. Every duplication claim must cite ≥2 `file:line` locations.
### Phase 3: Unified Proposal (ORCHESTRATOR)
The orchestrator writes `03-unified-proposal.md` itself — do not delegate synthesis.
For each duplicated concern from Phase 2 that is NOT legitimate specialization:
1. Propose the simplest unified design (one path, one store, one handler — whatever applies)
2. Name the consolidated component and its single entry point
3. Show what each old call site becomes
4. Call out any loss of capability and whether it's acceptable
End the document with ONE combined Mermaid flowchart showing the proposed unified system. Nodes still labeled with target `file:line` (new or existing) where knowable.
**Anti-patterns to reject in your own proposal:**
- Adding a new abstraction layer "for flexibility"
- Keeping both old paths behind a feature flag
- Introducing a registry/factory when a switch statement suffices
- Preserving divergent behavior "just in case"
### Phase 4: Per-System Handoff Prompts
For each unified system in the proposal, write a ready-to-run `/make-plan` prompt to `04-handoff-prompts.md`. Each prompt must:
1. State the target unified component and its single entry point
2. List the exact call sites to rewrite (from Phase 2 evidence)
3. Cite the relevant flowchart file from `01-flowcharts/`
4. Include anti-pattern guards specific to this system
Format each as a fenced code block the user can copy directly into `/make-plan`.
## Key Principles
- **Evidence over intuition** — every diagram node and duplication claim cites `file:line`
- **Current state before ideal state** — Phases 02 describe what IS; Phase 3 describes what SHOULD BE
- **Simplest unification wins** — prefer deletion over abstraction; prefer one path over configurable paths
- **Specialization is not duplication** — two components serving different trust models or data sources are legitimate even if their code looks similar
- **Handoff, don't implement** — Pathfinder ends at plan prompts; `/make-plan` and `/do` take it from there
## Failure Modes to Prevent
- Drawing flowcharts from memory instead of source — redeploy subagent with grep evidence requirement
- Proposing unification of legitimately specialized components — re-examine trust/data-source divergence
- Handoff prompts that lack concrete call sites — rewrite with Phase 2 evidence
- Skipping Phase 0 boundary review — fanning out on bad feature boundaries wastes all of Phase 1
+15 -7
View File
@@ -20,7 +20,15 @@ Use when users ask for:
## Prerequisites
The claude-mem worker must be running on localhost:37777. The project must have claude-mem observations recorded.
The claude-mem worker must be running. The project must have claude-mem observations recorded.
**Resolve the worker port** (do this once at the start and reuse `$WORKER_PORT` in every curl call below):
```bash
WORKER_PORT="${CLAUDE_MEM_WORKER_PORT:-$(node -e "const fs=require('fs'),p=require('path'),os=require('os');const uid=(typeof process.getuid==='function'?process.getuid():77);const fallback=String(37700+(uid%100));try{const s=JSON.parse(fs.readFileSync(p.join(os.homedir(),'.claude-mem','settings.json'),'utf-8'));process.stdout.write(String(s.CLAUDE_MEM_WORKER_PORT||fallback));}catch{process.stdout.write(fallback);}" 2>/dev/null)}"
```
This honors `CLAUDE_MEM_WORKER_PORT` env, then `~/.claude-mem/settings.json`, then falls back to the per-UID default `37700 + (uid % 100)` — matching how the worker itself picks its port. Required for multi-account setups (#2101) and any user who has overridden the default port (#2103).
## Workflow
@@ -50,7 +58,7 @@ If a worktree is detected, use `$parent_project` (the basename of the parent rep
Use Bash to fetch the complete timeline from the claude-mem worker API:
```bash
curl -s "http://localhost:37777/api/context/inject?project=PROJECT_NAME&full=true"
curl -s "http://localhost:${WORKER_PORT}/api/context/inject?project=PROJECT_NAME&full=true"
```
This returns the entire compressed timeline -- every observation, session boundary, and summary across the project's full history. The response is pre-formatted markdown optimized for LLM consumption.
@@ -60,7 +68,7 @@ This returns the entire compressed timeline -- every observation, session bounda
- Medium project (1,000-10,000 observations): ~50-300K tokens
- Large project (10,000-35,000 observations): ~300-750K tokens
If the response is empty or returns an error, the worker may not be running or the project name may be wrong. Try `curl -s "http://localhost:37777/api/search?query=*&limit=1"` to verify the worker is healthy.
If the response is empty or returns an error, the worker may not be running or the project name may be wrong. Try `curl -s "http://localhost:${WORKER_PORT}/api/search?query=*&limit=1"` to verify the worker is healthy.
### Step 3: Estimate Token Count
@@ -187,15 +195,15 @@ Tell the user:
## Error Handling
- **Empty timeline:** "No observations found for project 'X'. Check the project name with: `curl -s 'http://localhost:37777/api/search?query=*&limit=1'`"
- **Worker not running:** "The claude-mem worker is not responding on port 37777. Start it with your usual method or check `ps aux | grep worker-service`."
- **Timeline too large:** For projects with 50,000+ observations, the timeline may exceed context limits. Suggest using date range filtering: `curl -s "http://localhost:37777/api/context/inject?project=X&full=true"` -- the current endpoint returns all observations; for extremely large projects, the user may want to analyze in time-windowed segments.
- **Empty timeline:** "No observations found for project 'X'. Check the project name with: `curl -s \"http://localhost:${WORKER_PORT}/api/search?query=*&limit=1\"`"
- **Worker not running:** "The claude-mem worker is not responding on port ${WORKER_PORT}. Start it with your usual method or check `ps aux | grep worker-service`."
- **Timeline too large:** For projects with 50,000+ observations, the timeline may exceed context limits. Suggest using date range filtering: `curl -s "http://localhost:${WORKER_PORT}/api/context/inject?project=X&full=true"` -- the current endpoint returns all observations; for extremely large projects, the user may want to analyze in time-windowed segments.
## Example
User: "Write a journey report for the tokyo project"
1. Fetch: `curl -s "http://localhost:37777/api/context/inject?project=tokyo&full=true"`
1. Fetch: `curl -s "http://localhost:${WORKER_PORT}/api/context/inject?project=tokyo&full=true"`
2. Estimate: "Timeline fetched: ~34,722 observations, estimated ~718K tokens. Proceed?"
3. User confirms
4. Deploy analysis agent with full timeline
+38 -18
View File
@@ -1,42 +1,62 @@
---
name: claude-code-plugin-release
description: Automated semantic versioning and release workflow for Claude Code plugins. Handles version increments across package.json, marketplace.json, and plugin.json, build verification, git tagging, GitHub releases, and changelog generation.
description: Automated semantic versioning and release workflow for Claude Code plugins. Handles version increments across package.json, marketplace.json, plugin.json manifests, npm publishing (so `npx claude-mem@X.Y.Z` resolves), build verification, git tagging, GitHub releases, and changelog generation.
---
# Version Bump & Release Workflow
**IMPORTANT:** You must first plan and write detailed release notes before starting the version bump workflow.
**IMPORTANT:** Plan and write detailed release notes before starting.
**CRITICAL:** ALWAYS commit EVERYTHING (including build artifacts). At the end of this workflow, NOTHING should be left uncommitted or unpushed. Run `git status` at the end to verify.
**CRITICAL:** Commit EVERYTHING (including build artifacts). At the end of this workflow, NOTHING should be left uncommitted or unpushed. Run `git status` at the end to verify.
## Preparation
1. **Analyze**: Determine if the change is a **PATCH** (bug fixes), **MINOR** (features), or **MAJOR** (breaking) update.
2. **Environment**: Identify the repository owner and name (e.g., from `git remote -v`).
3. **Paths**: Verify existence of `package.json`, `.claude-plugin/marketplace.json`, and `plugin/.claude-plugin/plugin.json`.
1. **Analyze**: Determine if the change is **PATCH** (bug fixes), **MINOR** (features), or **MAJOR** (breaking).
2. **Environment**: Identify repository owner/name from `git remote -v`.
3. **Paths — every file that carries the version string**:
- `package.json`**the npm/npx-published version** (`npx claude-mem@X.Y.Z` resolves from this)
- `plugin/package.json` — bundled plugin runtime deps
- `.claude-plugin/marketplace.json` — version inside `plugins[0].version`
- `.claude-plugin/plugin.json` — top-level Claude-plugin manifest
- `plugin/.claude-plugin/plugin.json` — bundled Claude-plugin manifest
- `.codex-plugin/plugin.json` — Codex-plugin manifest
Verify coverage before editing: `git grep -l "\"version\": \"<OLD>\""` should list all six. If a new manifest has been added since this doc was last updated, update this list.
## Workflow
1. **Update**: Increment version strings in all configuration files.
2. **Verify**: Use `grep` to ensure all files match the new version.
3. **Build**: Run `npm run build` to generate fresh artifacts.
4. **Commit**: Stage all changes including artifacts: `git add -A && git commit -m "chore: bump version to X.Y.Z"`.
5. **Tag**: Create an annotated tag: `git tag -a vX.Y.Z -m "Version X.Y.Z"`.
1. **Update**: Increment the version string in every path above. Do NOT touch `CHANGELOG.md` — it's regenerated.
2. **Verify**: `git grep -n "\"version\": \"<NEW>\""` — confirm all six files match. `git grep -n "\"version\": \"<OLD>\""` — should return zero hits.
3. **Build**: `npm run build` to regenerate artifacts.
4. **Commit**: `git add -A && git commit -m "chore: bump version to X.Y.Z"`.
5. **Tag**: `git tag -a vX.Y.Z -m "Version X.Y.Z"`.
6. **Push**: `git push origin main && git push origin vX.Y.Z`.
7. **Release**: `gh release create vX.Y.Z --title "vX.Y.Z" --notes "RELEASE_NOTES"`.
8. **Changelog**: Regenerate `CHANGELOG.md` using the GitHub API and the provided script:
7. **Publish to npm** (this is what makes `npx claude-mem@X.Y.Z` work):
```bash
gh api repos/{owner}/{repo}/releases --paginate | ./scripts/generate_changelog.js > CHANGELOG.md
npm publish
```
9. **Sync**: Commit and push the updated `CHANGELOG.md`.
10. **Notify**: Run `npm run discord:notify vX.Y.Z` if applicable.
11. **Finalize**: Run `git status` to ensure a clean working tree.
The `prepublishOnly` script re-runs `npm run build` automatically. Confirm publish succeeded:
```bash
npm view claude-mem@X.Y.Z version # should print X.Y.Z
```
Alternative: `npm run release:patch` / `release:minor` / `release:major` invokes `np` and handles tag+push+publish in one shot — use ONLY if you skipped steps 46, otherwise `np` will error on the existing tag.
8. **GitHub release**: `gh release create vX.Y.Z --title "vX.Y.Z" --notes "RELEASE_NOTES"`.
9. **Changelog**: Regenerate via the project's changelog script:
```bash
npm run changelog:generate
```
(Runs `node scripts/generate-changelog.js`, which pulls releases from the GitHub API and rewrites `CHANGELOG.md`.)
10. **Sync changelog**: Commit and push the updated `CHANGELOG.md`.
11. **Notify**: `npm run discord:notify vX.Y.Z` if applicable.
12. **Finalize**: `git status` — working tree must be clean.
## Checklist
- [ ] All config files have matching versions
- [ ] All six config files have matching versions
- [ ] `git grep` for old version returns zero hits
- [ ] `npm run build` succeeded
- [ ] Git tag created and pushed
- [ ] **`npm publish` succeeded and `npm view claude-mem@X.Y.Z version` confirms it** (so `npx claude-mem@X.Y.Z` resolves)
- [ ] GitHub release created with notes
- [ ] `CHANGELOG.md` updated and pushed
- [ ] `git status` shows clean tree