@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.
- package/dist/__tests__/claude-sync.test.js +15 -0
- package/dist/__tests__/claude-sync.test.js.map +1 -1
- package/dist/__tests__/config-generation.test.d.ts +7 -0
- package/dist/__tests__/config-generation.test.d.ts.map +1 -0
- package/dist/__tests__/config-generation.test.js +141 -0
- package/dist/__tests__/config-generation.test.js.map +1 -0
- package/dist/__tests__/config-sync.test.d.ts +10 -0
- package/dist/__tests__/config-sync.test.d.ts.map +1 -0
- package/dist/__tests__/config-sync.test.js +180 -0
- package/dist/__tests__/config-sync.test.js.map +1 -0
- package/dist/__tests__/project-config.test.js +1 -0
- package/dist/__tests__/project-config.test.js.map +1 -1
- package/dist/agent-config/.mx-config-generation.json +4 -0
- package/dist/agent-config/CLAUDE.md.template +140 -0
- package/dist/agent-config/OWNERS.md +51 -0
- package/dist/agent-config/agents/bar-raiser.md +205 -0
- package/dist/agent-config/agents/dogfood-auditor.md +243 -0
- package/dist/agent-config/agents/git-expert.md +380 -0
- package/dist/agent-config/agents/implementation-engineer.md +387 -0
- package/dist/agent-config/agents/memory-creator.md +330 -0
- package/dist/agent-config/agents/prd-writer.md +478 -0
- package/dist/agent-config/agents/prfaq-writer.md +344 -0
- package/dist/agent-config/agents/prior-art-researcher.md +264 -0
- package/dist/agent-config/agents/qa-tester.md +406 -0
- package/dist/agent-config/agents/red-team.md +330 -0
- package/dist/agent-config/agents/security-reviewer.md +300 -0
- package/dist/agent-config/agents/status-reporter.md +297 -0
- package/dist/agent-config/claude-md/CLAUDE.core.md +105 -0
- package/dist/agent-config/claude-md/CLAUDE.overlay.memnexus.md +68 -0
- package/dist/agent-config/claude-md/compose.mjs +179 -0
- package/dist/agent-config/claude-md/vars.memnexus.json +4 -0
- package/dist/agent-config/hooks/auto-capture-precompact.sh +176 -0
- package/dist/agent-config/hooks/auto-capture-session-end.sh +178 -0
- package/dist/agent-config/hooks/auto-checkpoint.sh +102 -0
- package/dist/agent-config/hooks/ci-validate-hook.sh +499 -0
- package/dist/agent-config/hooks/ci-validate-routes.conf +16 -0
- package/dist/agent-config/hooks/delegation-audit.sh +61 -0
- package/dist/agent-config/hooks/deploy-verification-reminder.sh +179 -0
- package/dist/agent-config/hooks/git-mutation-guard.sh +219 -0
- package/dist/agent-config/hooks/iteration-log-check.sh +212 -0
- package/dist/agent-config/hooks/memory-checkpoint-reminder.sh +103 -0
- package/dist/agent-config/hooks/mx-guard-hook.sh +77 -0
- package/dist/agent-config/hooks/named-memory-write-guard.sh +237 -0
- package/dist/agent-config/hooks/reload-checkpoint.sh +68 -0
- package/dist/agent-config/hooks/set-terminal-appearance.sh +34 -0
- package/dist/agent-config/hooks/workflow-dispatch-guard.sh +184 -0
- package/dist/agent-config/hooks/worktree-guard.sh +258 -0
- package/dist/agent-config/rules/eval-harness.md +33 -0
- package/dist/agent-config/rules/frontend.md +17 -0
- package/dist/agent-config/rules/mcp-protocol.md +15 -0
- package/dist/agent-config/rules/retrieval.md +17 -0
- package/dist/agent-config/settings.json +196 -0
- package/dist/agent-config/shared/eval-tiered-rigor.md +15 -0
- package/dist/agent-config/shared/team-operating-rules.md +37 -0
- package/dist/agent-config/skills/eval-claim-impact/SKILL.md +20 -0
- package/dist/agent-config/skills/eval-harness-review/SKILL.md +21 -0
- package/dist/agent-config/skills/mx-checkpoint/SKILL.md +111 -0
- package/dist/agent-config/skills/mx-fix-pr/SKILL.md +90 -0
- package/dist/agent-config/skills/mx-gap-assessment/SKILL.md +90 -0
- package/dist/agent-config/skills/mx-iteration-close/SKILL.md +81 -0
- package/dist/agent-config/skills/mx-post-merge-sync/SKILL.md +83 -0
- package/dist/agent-config/skills/mx-pre-pr-check/SKILL.md +85 -0
- package/dist/agent-config/skills/mx-save/SKILL.md +102 -0
- package/dist/agent-config/skills/mx-session-start/SKILL.md +85 -0
- package/dist/agent-config/skills/team-gate-checklist/SKILL.md +19 -0
- package/dist/commands/config-sync.d.ts +39 -0
- package/dist/commands/config-sync.d.ts.map +1 -0
- package/dist/commands/config-sync.js +212 -0
- package/dist/commands/config-sync.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +3 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +6 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/bundled-config.d.ts +44 -0
- package/dist/lib/bundled-config.d.ts.map +1 -0
- package/dist/lib/bundled-config.js +164 -0
- package/dist/lib/bundled-config.js.map +1 -0
- package/dist/lib/claude.d.ts.map +1 -1
- package/dist/lib/claude.js +9 -3
- package/dist/lib/claude.js.map +1 -1
- package/dist/lib/config-generation.d.ts +36 -0
- package/dist/lib/config-generation.d.ts.map +1 -0
- package/dist/lib/config-generation.js +73 -0
- package/dist/lib/config-generation.js.map +1 -0
- package/dist/lib/project-config.d.ts +7 -0
- package/dist/lib/project-config.d.ts.map +1 -1
- package/dist/lib/project-config.js +4 -0
- package/dist/lib/project-config.js.map +1 -1
- 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
|