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:
@@ -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
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
+303
-324
File diff suppressed because one or more lines are too long
@@ -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 0–2 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
|
||||
@@ -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
|
||||
|
||||
@@ -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 4–6, 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
|
||||
|
||||
Reference in New Issue
Block a user