@memnexus-ai/mx-agent-cli 0.1.166 → 0.1.167

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/__tests__/claude-sync.test.js +15 -0
  2. package/dist/__tests__/claude-sync.test.js.map +1 -1
  3. package/dist/__tests__/config-generation.test.d.ts +7 -0
  4. package/dist/__tests__/config-generation.test.d.ts.map +1 -0
  5. package/dist/__tests__/config-generation.test.js +141 -0
  6. package/dist/__tests__/config-generation.test.js.map +1 -0
  7. package/dist/__tests__/config-sync.test.d.ts +10 -0
  8. package/dist/__tests__/config-sync.test.d.ts.map +1 -0
  9. package/dist/__tests__/config-sync.test.js +180 -0
  10. package/dist/__tests__/config-sync.test.js.map +1 -0
  11. package/dist/__tests__/project-config.test.js +1 -0
  12. package/dist/__tests__/project-config.test.js.map +1 -1
  13. package/dist/agent-config/.mx-config-generation.json +4 -0
  14. package/dist/agent-config/CLAUDE.md.template +140 -0
  15. package/dist/agent-config/OWNERS.md +51 -0
  16. package/dist/agent-config/agents/bar-raiser.md +205 -0
  17. package/dist/agent-config/agents/dogfood-auditor.md +243 -0
  18. package/dist/agent-config/agents/git-expert.md +380 -0
  19. package/dist/agent-config/agents/implementation-engineer.md +387 -0
  20. package/dist/agent-config/agents/memory-creator.md +330 -0
  21. package/dist/agent-config/agents/prd-writer.md +478 -0
  22. package/dist/agent-config/agents/prfaq-writer.md +344 -0
  23. package/dist/agent-config/agents/prior-art-researcher.md +264 -0
  24. package/dist/agent-config/agents/qa-tester.md +406 -0
  25. package/dist/agent-config/agents/red-team.md +330 -0
  26. package/dist/agent-config/agents/security-reviewer.md +300 -0
  27. package/dist/agent-config/agents/status-reporter.md +297 -0
  28. package/dist/agent-config/claude-md/CLAUDE.core.md +105 -0
  29. package/dist/agent-config/claude-md/CLAUDE.overlay.memnexus.md +68 -0
  30. package/dist/agent-config/claude-md/compose.mjs +179 -0
  31. package/dist/agent-config/claude-md/vars.memnexus.json +4 -0
  32. package/dist/agent-config/hooks/auto-capture-precompact.sh +176 -0
  33. package/dist/agent-config/hooks/auto-capture-session-end.sh +178 -0
  34. package/dist/agent-config/hooks/auto-checkpoint.sh +102 -0
  35. package/dist/agent-config/hooks/ci-validate-hook.sh +499 -0
  36. package/dist/agent-config/hooks/ci-validate-routes.conf +16 -0
  37. package/dist/agent-config/hooks/delegation-audit.sh +61 -0
  38. package/dist/agent-config/hooks/deploy-verification-reminder.sh +179 -0
  39. package/dist/agent-config/hooks/git-mutation-guard.sh +219 -0
  40. package/dist/agent-config/hooks/iteration-log-check.sh +212 -0
  41. package/dist/agent-config/hooks/memory-checkpoint-reminder.sh +103 -0
  42. package/dist/agent-config/hooks/mx-guard-hook.sh +77 -0
  43. package/dist/agent-config/hooks/named-memory-write-guard.sh +237 -0
  44. package/dist/agent-config/hooks/reload-checkpoint.sh +68 -0
  45. package/dist/agent-config/hooks/set-terminal-appearance.sh +34 -0
  46. package/dist/agent-config/hooks/workflow-dispatch-guard.sh +184 -0
  47. package/dist/agent-config/hooks/worktree-guard.sh +258 -0
  48. package/dist/agent-config/rules/eval-harness.md +33 -0
  49. package/dist/agent-config/rules/frontend.md +17 -0
  50. package/dist/agent-config/rules/mcp-protocol.md +15 -0
  51. package/dist/agent-config/rules/retrieval.md +17 -0
  52. package/dist/agent-config/settings.json +196 -0
  53. package/dist/agent-config/shared/eval-tiered-rigor.md +15 -0
  54. package/dist/agent-config/shared/team-operating-rules.md +37 -0
  55. package/dist/agent-config/skills/eval-claim-impact/SKILL.md +20 -0
  56. package/dist/agent-config/skills/eval-harness-review/SKILL.md +21 -0
  57. package/dist/agent-config/skills/mx-checkpoint/SKILL.md +111 -0
  58. package/dist/agent-config/skills/mx-fix-pr/SKILL.md +90 -0
  59. package/dist/agent-config/skills/mx-gap-assessment/SKILL.md +90 -0
  60. package/dist/agent-config/skills/mx-iteration-close/SKILL.md +81 -0
  61. package/dist/agent-config/skills/mx-post-merge-sync/SKILL.md +83 -0
  62. package/dist/agent-config/skills/mx-pre-pr-check/SKILL.md +85 -0
  63. package/dist/agent-config/skills/mx-save/SKILL.md +102 -0
  64. package/dist/agent-config/skills/mx-session-start/SKILL.md +85 -0
  65. package/dist/agent-config/skills/team-gate-checklist/SKILL.md +19 -0
  66. package/dist/commands/config-sync.d.ts +39 -0
  67. package/dist/commands/config-sync.d.ts.map +1 -0
  68. package/dist/commands/config-sync.js +212 -0
  69. package/dist/commands/config-sync.js.map +1 -0
  70. package/dist/commands/create.d.ts.map +1 -1
  71. package/dist/commands/create.js +3 -0
  72. package/dist/commands/create.js.map +1 -1
  73. package/dist/commands/init.d.ts.map +1 -1
  74. package/dist/commands/init.js +12 -4
  75. package/dist/commands/init.js.map +1 -1
  76. package/dist/commands/start.d.ts.map +1 -1
  77. package/dist/commands/start.js +6 -0
  78. package/dist/commands/start.js.map +1 -1
  79. package/dist/index.js +23 -0
  80. package/dist/index.js.map +1 -1
  81. package/dist/lib/bundled-config.d.ts +44 -0
  82. package/dist/lib/bundled-config.d.ts.map +1 -0
  83. package/dist/lib/bundled-config.js +164 -0
  84. package/dist/lib/bundled-config.js.map +1 -0
  85. package/dist/lib/claude.d.ts.map +1 -1
  86. package/dist/lib/claude.js +9 -3
  87. package/dist/lib/claude.js.map +1 -1
  88. package/dist/lib/config-generation.d.ts +36 -0
  89. package/dist/lib/config-generation.d.ts.map +1 -0
  90. package/dist/lib/config-generation.js +73 -0
  91. package/dist/lib/config-generation.js.map +1 -0
  92. package/dist/lib/project-config.d.ts +7 -0
  93. package/dist/lib/project-config.d.ts.map +1 -1
  94. package/dist/lib/project-config.js +4 -0
  95. package/dist/lib/project-config.js.map +1 -1
  96. package/package.json +2 -2
@@ -0,0 +1,176 @@
1
+ #!/bin/bash
2
+ # auto-capture-precompact.sh — Automatic memory capture before context compaction
3
+ #
4
+ # The highest-value automatic capture signal: fires when ~95% of context window
5
+ # is full, meaning rich context (decisions, debugging sessions, architecture
6
+ # discussions) is about to be lost forever.
7
+ #
8
+ # Unlike auto-checkpoint.sh (which saves a resumption checkpoint), this hook
9
+ # extracts structured knowledge — decisions, problems solved, patterns — and
10
+ # saves it as a permanent memory.
11
+ #
12
+ # Fires on: PreCompact
13
+ # Input: JSON on stdin with transcript_path, session_id, trigger
14
+ # Output: none (side-effect only — saves memory via mx CLI)
15
+ # Exit: always 0 (never blocks compaction)
16
+
17
+ # Fail-open: any error -> allow compaction without saving
18
+ trap 'exit 0' ERR
19
+
20
+ # ── 1. Parse hook input ──────────────────────────────────────────────────
21
+ INPUT=$(cat)
22
+
23
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
24
+ _SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
25
+
26
+ # Skip if no transcript or required tools missing
27
+ if [[ -z "$TRANSCRIPT_PATH" || ! -f "$TRANSCRIPT_PATH" ]]; then
28
+ exit 0
29
+ fi
30
+ command -v jq >/dev/null 2>&1 || exit 0
31
+ command -v mx >/dev/null 2>&1 || exit 0
32
+
33
+ # ── 2. Extract structured data from transcript ──────────────────────────
34
+
35
+ tmpdir=$(mktemp -d)
36
+ trap 'rm -rf "$tmpdir"; exit 0' EXIT ERR
37
+
38
+ # Total line count (proxy for session depth)
39
+ _TOTAL_LINES=$(wc -l < "$TRANSCRIPT_PATH" 2>/dev/null || echo "0")
40
+
41
+ # Files modified (Write/Edit tool calls)
42
+ FILES_MODIFIED=$(jq -r '
43
+ select(.type == "assistant") |
44
+ .message.content[]? |
45
+ select(.type == "tool_use" and (.name == "Write" or .name == "Edit")) |
46
+ .input.file_path // empty
47
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | grep -v '^$' | sort -u | head -30)
48
+
49
+ # Files read (Read tool calls — indicates areas of investigation)
50
+ FILES_READ=$(jq -r '
51
+ select(.type == "assistant") |
52
+ .message.content[]? |
53
+ select(.type == "tool_use" and .name == "Read") |
54
+ .input.file_path // empty
55
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | grep -v '^$' | sort | uniq -c | sort -rn | head -15 | awk '{print $2}')
56
+
57
+ # Bash commands run (significant actions)
58
+ BASH_COMMANDS=$(jq -r '
59
+ select(.type == "assistant") |
60
+ .message.content[]? |
61
+ select(.type == "tool_use" and .name == "Bash") |
62
+ .input.command // empty
63
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | grep -v '^$' | grep -vE '^(ls|pwd|echo|cat |head |tail )' | tail -20)
64
+
65
+ # Git activity
66
+ GIT_COMMITS=$(echo "$BASH_COMMANDS" | grep -oE 'git commit' | wc -l | tr -d ' ')
67
+ GIT_PUSHES=$(echo "$BASH_COMMANDS" | grep -oE 'git push' | wc -l | tr -d ' ')
68
+ PR_CREATES=$(echo "$BASH_COMMANDS" | grep -oE 'gh pr create' | wc -l | tr -d ' ')
69
+ PR_MERGES=$(echo "$BASH_COMMANDS" | grep -oE 'gh pr merge' | wc -l | tr -d ' ')
70
+
71
+ # PR and issue references from all text content
72
+ ALL_TEXT=$(jq -r '
73
+ select(.type == "user" or .type == "assistant") |
74
+ .message.content |
75
+ if type == "array" then
76
+ [.[] | select(.type == "text") | .text] | join("\n")
77
+ elif type == "string" then .
78
+ else empty end
79
+ ' "$TRANSCRIPT_PATH" 2>/dev/null)
80
+
81
+ GH_REFS=$(echo "$ALL_TEXT" | grep -oE '(PR |#)[0-9]+' 2>/dev/null | sort -u | head -15 | tr '\n' ', ' | sed 's/,$//')
82
+
83
+ # User messages (to understand intent and topics)
84
+ USER_MESSAGES=$(jq -r '
85
+ select(.type == "user") |
86
+ .message.content |
87
+ if type == "array" then
88
+ [.[] | select(.type == "text") | .text] | join("\n")
89
+ elif type == "string" then .
90
+ else empty end
91
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | head -c 3000)
92
+
93
+ # Last few assistant text blocks (conclusions/results)
94
+ RECENT_RESULTS=$(tail -100 "$TRANSCRIPT_PATH" | jq -r '
95
+ select(.type == "assistant") |
96
+ .message.content |
97
+ if type == "array" then
98
+ [.[] | select(.type == "text") | .text] | join("\n")
99
+ elif type == "string" then .
100
+ else empty end
101
+ ' 2>/dev/null | tail -c 2000)
102
+
103
+ # Tool usage summary
104
+ TOOL_SUMMARY=$(jq -r '
105
+ select(.type == "assistant") |
106
+ .message.content[]? |
107
+ select(.type == "tool_use") | .name
108
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | sort | uniq -c | sort -rn | head -10 | awk '{printf "%s(%d) ", $2, $1}')
109
+
110
+ # ── 3. Significance filter ───────────────────────────────────────────────
111
+ # Skip if session was trivial (very few tool calls, no files modified)
112
+ TOOL_COUNT=$(jq -r '
113
+ select(.type == "assistant") |
114
+ .message.content[]? |
115
+ select(.type == "tool_use") | .name
116
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
117
+
118
+ if [[ "$TOOL_COUNT" -lt 5 && -z "$FILES_MODIFIED" ]]; then
119
+ # Trivial session — not worth capturing
120
+ exit 0
121
+ fi
122
+
123
+ # ── 4. Build structured memory content ───────────────────────────────────
124
+ WORKTREE_NAME="${CLAUDE_WORKTREE_NAME:-unknown}"
125
+ GIT_BRANCH="${CLAUDE_WORKTREE_BRANCH:-$(git branch --show-current 2>/dev/null || echo 'unknown')}"
126
+
127
+ # Build files list
128
+ MOD_LIST=""
129
+ if [[ -n "$FILES_MODIFIED" ]]; then
130
+ MOD_LIST=$(echo "$FILES_MODIFIED" | sed 's|^/workspace/[^/]*/||' | sed 's/^/- /')
131
+ fi
132
+
133
+ READ_LIST=""
134
+ if [[ -n "$FILES_READ" ]]; then
135
+ READ_LIST=$(echo "$FILES_READ" | sed 's|^/workspace/[^/]*/||' | head -10 | sed 's/^/- /')
136
+ fi
137
+
138
+ # Build activity summary
139
+ ACTIVITY=""
140
+ [[ "$GIT_COMMITS" -gt 0 ]] && ACTIVITY="${ACTIVITY}${GIT_COMMITS} commits, "
141
+ [[ "$GIT_PUSHES" -gt 0 ]] && ACTIVITY="${ACTIVITY}${GIT_PUSHES} pushes, "
142
+ [[ "$PR_CREATES" -gt 0 ]] && ACTIVITY="${ACTIVITY}${PR_CREATES} PRs created, "
143
+ [[ "$PR_MERGES" -gt 0 ]] && ACTIVITY="${ACTIVITY}${PR_MERGES} PRs merged, "
144
+ ACTIVITY="${ACTIVITY}${TOOL_COUNT} tool calls"
145
+
146
+ CONTENT="[Auto-Captured] Session context before compaction — ${WORKTREE_NAME}
147
+
148
+ Branch: ${GIT_BRANCH}
149
+ Activity: ${ACTIVITY}
150
+ GitHub refs: ${GH_REFS:-none}
151
+
152
+ Files modified:
153
+ ${MOD_LIST:-None}
154
+
155
+ Files investigated:
156
+ ${READ_LIST:-None}
157
+
158
+ Tools used: ${TOOL_SUMMARY}
159
+
160
+ What the user was working on:
161
+ $(echo "$USER_MESSAGES" | head -c 1500)
162
+
163
+ Recent results/conclusions:
164
+ $(echo "$RECENT_RESULTS" | head -c 1500)"
165
+
166
+ # Truncate total content
167
+ CONTENT=$(echo "$CONTENT" | head -c 6000)
168
+
169
+ # ── 5. Save memory ──────────────────────────────────────────────────────
170
+ mx memories create \
171
+ --conversation-id "NEW" \
172
+ --content "$CONTENT" \
173
+ --topics "auto-captured,context-compaction" \
174
+ >/dev/null 2>&1 || true
175
+
176
+ exit 0
@@ -0,0 +1,178 @@
1
+ #!/bin/bash
2
+ # auto-capture-session-end.sh — Automatic memory capture on session exit
3
+ #
4
+ # Fires when the user exits a Claude Code session. Creates a session-level
5
+ # summary memory capturing what was accomplished, key decisions, and next steps.
6
+ #
7
+ # This is the "wrap-up" signal — holistic view of the session that individual
8
+ # turn-level captures would miss.
9
+ #
10
+ # Fires on: Stop (used as session-end proxy — fires on every turn, but we
11
+ # only save if enough work was done since last save)
12
+ # Input: JSON on stdin with transcript_path, session_id
13
+ # Output: none (side-effect only — saves memory via mx CLI)
14
+ # Exit: always 0 (never blocks)
15
+
16
+ # Fail-open: any error -> allow session to end normally
17
+ trap 'exit 0' ERR
18
+
19
+ # ── 1. Parse hook input ──────────────────────────────────────────────────
20
+ INPUT=$(cat)
21
+
22
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
23
+ _SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
24
+ STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null)
25
+
26
+ # Skip if already in a hook loop
27
+ if [[ "$STOP_HOOK_ACTIVE" == "true" ]]; then
28
+ exit 0
29
+ fi
30
+
31
+ # Skip if no transcript or required tools missing
32
+ if [[ -z "$TRANSCRIPT_PATH" || ! -f "$TRANSCRIPT_PATH" ]]; then
33
+ exit 0
34
+ fi
35
+ command -v jq >/dev/null 2>&1 || exit 0
36
+ command -v mx >/dev/null 2>&1 || exit 0
37
+
38
+ # ── 2. Debounce — only save periodically, not every turn ─────────────────
39
+ WORKTREE_NAME="${CLAUDE_WORKTREE_NAME:-unknown}"
40
+ STATE_FILE="/tmp/.mx-session-capture-${WORKTREE_NAME}"
41
+ CURRENT_LINES=$(wc -l < "$TRANSCRIPT_PATH" 2>/dev/null || echo "0")
42
+
43
+ # Check how many lines since last save
44
+ LAST_SAVED_LINES=0
45
+ if [[ -f "$STATE_FILE" ]]; then
46
+ LAST_SAVED_LINES=$(cat "$STATE_FILE" 2>/dev/null || echo "0")
47
+ fi
48
+
49
+ LINES_SINCE_SAVE=$((CURRENT_LINES - LAST_SAVED_LINES))
50
+
51
+ # Only save if significant work has happened (>100 transcript lines since last save)
52
+ # This prevents saving on every trivial stop event
53
+ if [[ "$LINES_SINCE_SAVE" -lt 100 ]]; then
54
+ exit 0
55
+ fi
56
+
57
+ # ── 3. Extract session summary data ──────────────────────────────────────
58
+
59
+ tmpdir=$(mktemp -d)
60
+ trap 'rm -rf "$tmpdir"; exit 0' EXIT ERR
61
+
62
+ # Only look at lines since last save
63
+ OFFSET=$((LAST_SAVED_LINES + 1))
64
+ if [[ "$LAST_SAVED_LINES" -gt 0 ]]; then
65
+ SEGMENT=$(tail -n +${OFFSET} "$TRANSCRIPT_PATH")
66
+ else
67
+ SEGMENT=$(cat "$TRANSCRIPT_PATH")
68
+ fi
69
+
70
+ # Files modified in this segment
71
+ FILES_MODIFIED=$(echo "$SEGMENT" | jq -r '
72
+ select(.type == "assistant") |
73
+ .message.content[]? |
74
+ select(.type == "tool_use" and (.name == "Write" or .name == "Edit")) |
75
+ .input.file_path // empty
76
+ ' 2>/dev/null | grep -v '^$' | sort -u | head -20)
77
+
78
+ # Tool call count
79
+ TOOL_COUNT=$(echo "$SEGMENT" | jq -r '
80
+ select(.type == "assistant") |
81
+ .message.content[]? |
82
+ select(.type == "tool_use") | .name
83
+ ' 2>/dev/null | wc -l | tr -d ' ')
84
+
85
+ # Skip if segment was trivial
86
+ if [[ "$TOOL_COUNT" -lt 5 && -z "$FILES_MODIFIED" ]]; then
87
+ # Update state but don't save — avoids re-checking trivial segments
88
+ echo "$CURRENT_LINES" > "$STATE_FILE" 2>/dev/null || true
89
+ exit 0
90
+ fi
91
+
92
+ # Git activity in this segment
93
+ BASH_COMMANDS=$(echo "$SEGMENT" | jq -r '
94
+ select(.type == "assistant") |
95
+ .message.content[]? |
96
+ select(.type == "tool_use" and .name == "Bash") |
97
+ .input.command // empty
98
+ ' 2>/dev/null)
99
+
100
+ GIT_COMMITS=$(echo "$BASH_COMMANDS" | grep -cE 'git commit' 2>/dev/null || echo "0")
101
+ PR_REFS=$(echo "$BASH_COMMANDS" | grep -oE 'gh pr (create|merge) [^\n]*' 2>/dev/null | head -5)
102
+
103
+ # User messages (intent)
104
+ USER_MESSAGES=$(echo "$SEGMENT" | jq -r '
105
+ select(.type == "user") |
106
+ .message.content |
107
+ if type == "array" then
108
+ [.[] | select(.type == "text") | .text] | join("\n")
109
+ elif type == "string" then .
110
+ else empty end
111
+ ' 2>/dev/null | head -c 2000)
112
+
113
+ # Recent assistant conclusions
114
+ RECENT_TEXT=$(echo "$SEGMENT" | tail -50 | jq -r '
115
+ select(.type == "assistant") |
116
+ .message.content |
117
+ if type == "array" then
118
+ [.[] | select(.type == "text") | .text] | join("\n")
119
+ elif type == "string" then .
120
+ else empty end
121
+ ' 2>/dev/null | tail -c 1500)
122
+
123
+ # PR and issue references
124
+ GH_REFS=$(echo "$SEGMENT" | jq -r '
125
+ select(.type == "user" or .type == "assistant") |
126
+ .message.content |
127
+ if type == "array" then
128
+ [.[] | select(.type == "text") | .text] | join("\n")
129
+ elif type == "string" then .
130
+ else empty end
131
+ ' 2>/dev/null | grep -oE '(PR |#)[0-9]+' | sort -u | head -10 | tr '\n' ', ' | sed 's/,$//')
132
+
133
+ # ── 4. Build session summary ─────────────────────────────────────────────
134
+ GIT_BRANCH="${CLAUDE_WORKTREE_BRANCH:-$(git branch --show-current 2>/dev/null || echo 'unknown')}"
135
+
136
+ MOD_LIST=""
137
+ if [[ -n "$FILES_MODIFIED" ]]; then
138
+ MOD_LIST=$(echo "$FILES_MODIFIED" | sed 's|^/workspace/[^/]*/||' | sed 's/^/- /')
139
+ fi
140
+
141
+ CONTENT="[Auto-Captured] Session activity — ${WORKTREE_NAME}
142
+
143
+ Branch: ${GIT_BRANCH}
144
+ Commits: ${GIT_COMMITS}
145
+ Tool calls: ${TOOL_COUNT}
146
+ GitHub refs: ${GH_REFS:-none}
147
+
148
+ Files modified:
149
+ ${MOD_LIST:-None}
150
+
151
+ What was worked on:
152
+ $(echo "$USER_MESSAGES" | head -c 1200)
153
+
154
+ Outcomes:
155
+ $(echo "$RECENT_TEXT" | head -c 1200)"
156
+
157
+ # Add PR activity if any
158
+ if [[ -n "$PR_REFS" ]]; then
159
+ CONTENT="${CONTENT}
160
+
161
+ PR activity:
162
+ ${PR_REFS}"
163
+ fi
164
+
165
+ # Truncate
166
+ CONTENT=$(echo "$CONTENT" | head -c 5000)
167
+
168
+ # ── 5. Save memory ──────────────────────────────────────────────────────
169
+ mx memories create \
170
+ --conversation-id "NEW" \
171
+ --content "$CONTENT" \
172
+ --topics "auto-captured,session-summary" \
173
+ >/dev/null 2>&1 || true
174
+
175
+ # ── 6. Update state ──────────────────────────────────────────────────────
176
+ echo "$CURRENT_LINES" > "$STATE_FILE" 2>/dev/null || true
177
+
178
+ exit 0
@@ -0,0 +1,102 @@
1
+ #!/bin/bash
2
+ # auto-checkpoint.sh — Claude Code PreCompact hook
3
+ # Saves a checkpoint memory before context compaction so agents can resume
4
+ # after losing context. Uses the /mx-checkpoint template format.
5
+ #
6
+ # Fires on: PreCompact (auto or manual compaction)
7
+ # Input: JSON on stdin with transcript_path, session_id, trigger
8
+ # Output: none (side-effect only — saves memory via mx CLI)
9
+ # Exit: always 0 (never blocks compaction)
10
+
11
+ # Fail-open: any error → allow compaction without saving
12
+ trap 'exit 0' ERR
13
+
14
+ # ── 1. Parse hook input ──────────────────────────────────────────────────
15
+ INPUT=$(cat)
16
+
17
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
18
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
19
+ TRIGGER=$(echo "$INPUT" | jq -r '.trigger // .source // "auto"' 2>/dev/null)
20
+
21
+ # Skip if no transcript available or jq missing
22
+ if [[ -z "$TRANSCRIPT_PATH" || ! -f "$TRANSCRIPT_PATH" ]]; then
23
+ exit 0
24
+ fi
25
+
26
+ command -v jq >/dev/null 2>&1 || exit 0
27
+ command -v mx >/dev/null 2>&1 || exit 0
28
+
29
+ # ── 2. Extract context from transcript ───────────────────────────────────
30
+
31
+ # Recent user/assistant text (last ~200 lines of transcript, text content only)
32
+ RECENT_TEXT=$(tail -200 "$TRANSCRIPT_PATH" | \
33
+ jq -r '
34
+ select(.type == "user" or .type == "assistant") |
35
+ .message.content[]? |
36
+ select(.type == "text") |
37
+ .text // empty
38
+ ' 2>/dev/null | tail -c 8000)
39
+
40
+ # Files touched (from tool_use entries: Read, Edit, Write, Glob)
41
+ FILES_TOUCHED=$(tail -500 "$TRANSCRIPT_PATH" | \
42
+ jq -r '
43
+ select(.type == "assistant") |
44
+ .message.content[]? |
45
+ select(.type == "tool_use") |
46
+ .input.file_path // empty
47
+ ' 2>/dev/null | grep -v '^$' | sort -u | head -30)
48
+
49
+ # Git branch and PR references
50
+ GIT_BRANCH="${CLAUDE_WORKTREE_BRANCH:-}"
51
+ if [[ -z "$GIT_BRANCH" ]]; then
52
+ GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
53
+ fi
54
+
55
+ # GitHub issue/PR references from recent text
56
+ GH_REFS=$(echo "$RECENT_TEXT" | grep -oE '#[0-9]+|PR #[0-9]+|issue #[0-9]+' 2>/dev/null | sort -u | head -10 | tr '\n' ', ' | sed 's/,$//')
57
+
58
+ # Worktree info
59
+ WORKTREE_NAME="${CLAUDE_WORKTREE_NAME:-unknown}"
60
+
61
+ # ── 3. Format checkpoint memory ─────────────────────────────────────────
62
+
63
+ # Build files list (indented)
64
+ FILES_LIST=""
65
+ if [[ -n "$FILES_TOUCHED" ]]; then
66
+ FILES_LIST=$(echo "$FILES_TOUCHED" | sed 's/^/- /')
67
+ fi
68
+
69
+ CONTENT="[Auto-Checkpoint] Context compaction (${TRIGGER}) — ${WORKTREE_NAME}
70
+
71
+ Branch: ${GIT_BRANCH}
72
+ Session: ${SESSION_ID}
73
+ GitHub refs: ${GH_REFS:-none detected}
74
+
75
+ Goal: [Auto-captured checkpoint before context compaction]
76
+
77
+ Current status: Context window reached capacity. This checkpoint captures the working state just before compaction so the next session can resume.
78
+
79
+ Key files:
80
+ ${FILES_LIST:-No file paths detected in recent transcript.}
81
+
82
+ Key terms: ${WORKTREE_NAME}, ${GIT_BRANCH}, auto-checkpoint, context-compaction
83
+
84
+ Next steps: Resume work from this checkpoint. Review the recent context below to understand what was in progress.
85
+
86
+ ---
87
+ Recent context (last messages before compaction):
88
+
89
+ ${RECENT_TEXT:-No recent text extracted from transcript.}"
90
+
91
+ # ── 4. Save checkpoint memory ───────────────────────────────────────────
92
+
93
+ # Use a named memory so it's easy to find and gets overwritten each compaction
94
+ mx memories create \
95
+ --name "auto-checkpoint-${WORKTREE_NAME}" \
96
+ --conversation-id "NEW" \
97
+ --content "$CONTENT" \
98
+ --topics "checkpoint,context-compaction" \
99
+ >/dev/null 2>&1 || true
100
+
101
+ # Always allow compaction to proceed
102
+ exit 0