claude-context-auto-handoff 1.0.4 → 1.0.5
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/.claude-plugin/plugin.json +1 -1
- package/README.ko.md +6 -6
- package/README.md +6 -6
- package/build/index.js +34 -4
- package/hooks/hooks.json +3 -3
- package/package.json +1 -1
- package/scripts/setup.ps1 +2 -2
- package/scripts/setup.sh +2 -2
- package/skills/{resume → handoff-resume}/SKILL.md +2 -2
- package/skills/{handoff → handoff-save}/SKILL.md +2 -2
package/README.ko.md
CHANGED
|
@@ -46,8 +46,8 @@ Claude의 컨텍스트 창이 가득 차면 대화가 자동으로 압축됩니
|
|
|
46
46
|
|
|
47
47
|
| 명령어 | 동작 |
|
|
48
48
|
|--------|------|
|
|
49
|
-
| `/handoff` | 세션 컨텍스트 수집 후 `generate_handoff_manifest` 호출 |
|
|
50
|
-
| `/resume` | `.claude/handoff.md` 읽어 새 세션에서 컨텍스트 복원 |
|
|
49
|
+
| `/handoff-save` | 세션 컨텍스트 수집 후 `generate_handoff_manifest` 호출 |
|
|
50
|
+
| `/handoff-resume` | `.claude/handoff.md` 읽어 새 세션에서 컨텍스트 복원 |
|
|
51
51
|
|
|
52
52
|
### 훅 (Hooks)
|
|
53
53
|
|
|
@@ -93,7 +93,7 @@ claude plugin install claude-context-auto-handoff
|
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
95
|
npm install -g claude-context-auto-handoff
|
|
96
|
-
|
|
96
|
+
claude-context-handoff-setup # hooks.json 자동 배치
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
### MCP 수동 설정 (Claude Code)
|
|
@@ -139,12 +139,12 @@ Claude Code와 동일한 `SessionStart`, `PreCompact`, `Stop` 훅이 활성화
|
|
|
139
139
|
|
|
140
140
|
**수동 체크포인트:**
|
|
141
141
|
```
|
|
142
|
-
/handoff
|
|
142
|
+
/handoff-save
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
**수동 복원 (자동 복원이 실행되지 않은 경우):**
|
|
146
146
|
```
|
|
147
|
-
/resume
|
|
147
|
+
/handoff-resume
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
### Codex
|
|
@@ -186,7 +186,7 @@ Claude Code와 동일한 `SessionStart`, `PreCompact`, `Stop` 훅이 활성화
|
|
|
186
186
|
* Env: NEXT_PUBLIC_SUPABASE_ANON_KEY 사용 중
|
|
187
187
|
|
|
188
188
|
---
|
|
189
|
-
*다음 세션 시작 시 자동으로 컨텍스트가 복원됩니다. 수동 복원: `/resume`*
|
|
189
|
+
*다음 세션 시작 시 자동으로 컨텍스트가 복원됩니다. 수동 복원: `/handoff-resume`*
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
---
|
package/README.md
CHANGED
|
@@ -46,8 +46,8 @@ Handoff content is written in **telegraphese** (no articles, no filler, no code
|
|
|
46
46
|
|
|
47
47
|
| Command | Behavior |
|
|
48
48
|
|---------|----------|
|
|
49
|
-
| `/handoff` | Gather session context and call `generate_handoff_manifest` |
|
|
50
|
-
| `/resume` | Read `.claude/handoff.md` and restore context in a new session |
|
|
49
|
+
| `/handoff-save` | Gather session context and call `generate_handoff_manifest` |
|
|
50
|
+
| `/handoff-resume` | Read `.claude/handoff.md` and restore context in a new session |
|
|
51
51
|
|
|
52
52
|
### Hooks
|
|
53
53
|
|
|
@@ -93,7 +93,7 @@ claude plugin install claude-context-auto-handoff
|
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
95
|
npm install -g claude-context-auto-handoff
|
|
96
|
-
|
|
96
|
+
claude-context-handoff-setup # hooks.json 자동 배치
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
### Manual MCP configuration (Claude Code)
|
|
@@ -139,12 +139,12 @@ All three hooks fire automatically — `SessionStart` restores context on sessio
|
|
|
139
139
|
|
|
140
140
|
**Manual checkpoint:**
|
|
141
141
|
```
|
|
142
|
-
/handoff
|
|
142
|
+
/handoff-save
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
**Manual resume (if auto-restore didn't trigger):**
|
|
146
146
|
```
|
|
147
|
-
/resume
|
|
147
|
+
/handoff-resume
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
### Codex
|
|
@@ -186,7 +186,7 @@ Same three hooks fire automatically via `.codex/hooks.json`. No slash commands
|
|
|
186
186
|
* Env: NEXT_PUBLIC_SUPABASE_ANON_KEY active
|
|
187
187
|
|
|
188
188
|
---
|
|
189
|
-
*Run `/resume` in the next session to restore this context.*
|
|
189
|
+
*Run `/handoff-resume` in the next session to restore this context.*
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
---
|
package/build/index.js
CHANGED
|
@@ -29,11 +29,14 @@ server.tool('generate_handoff_manifest', {
|
|
|
29
29
|
const now = new Date();
|
|
30
30
|
const displayTime = now.toLocaleString();
|
|
31
31
|
const timestamp = now.toISOString().replace(/[:.]/g, '-');
|
|
32
|
-
const content = buildMarkdown({ summary, nextSteps, taskDescription, currentStatus, keyDecisions, failedApproaches, blockers, modifiedFiles, implicitRules, displayTime });
|
|
32
|
+
const content = buildMarkdown({ summary, nextSteps, taskDescription, currentStatus, keyDecisions, failedApproaches, blockers, modifiedFiles, implicitRules, displayTime, project: path.basename(projectRoot), isoDate: now.toISOString() });
|
|
33
33
|
const mainPath = path.join(claudeDir, 'handoff.md');
|
|
34
34
|
fs.writeFileSync(mainPath, content, 'utf-8');
|
|
35
|
-
const
|
|
35
|
+
const dateDir = path.join(handoffsDir, now.toISOString().slice(0, 10));
|
|
36
|
+
fs.mkdirSync(dateDir, { recursive: true });
|
|
37
|
+
const archivePath = path.join(dateDir, `handoff-${timestamp}.md`);
|
|
36
38
|
fs.writeFileSync(archivePath, content, 'utf-8');
|
|
39
|
+
pruneHandoffs(handoffsDir, 50);
|
|
37
40
|
return {
|
|
38
41
|
content: [{
|
|
39
42
|
type: 'text',
|
|
@@ -48,9 +51,36 @@ server.tool('generate_handoff_manifest', {
|
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
53
|
});
|
|
54
|
+
function pruneHandoffs(handoffsDir, keep) {
|
|
55
|
+
const dateDirs = fs.readdirSync(handoffsDir, { withFileTypes: true }).filter(d => d.isDirectory());
|
|
56
|
+
const files = dateDirs.flatMap(d => {
|
|
57
|
+
const dirPath = path.join(handoffsDir, d.name);
|
|
58
|
+
return fs.readdirSync(dirPath).map(name => ({ path: path.join(dirPath, name), name }));
|
|
59
|
+
});
|
|
60
|
+
files.sort((a, b) => a.name.localeCompare(b.name));
|
|
61
|
+
const excess = files.length - keep;
|
|
62
|
+
if (excess > 0) {
|
|
63
|
+
files.slice(0, excess).forEach(f => fs.unlinkSync(f.path));
|
|
64
|
+
}
|
|
65
|
+
for (const d of dateDirs) {
|
|
66
|
+
const dirPath = path.join(handoffsDir, d.name);
|
|
67
|
+
if (fs.readdirSync(dirPath).length === 0)
|
|
68
|
+
fs.rmdirSync(dirPath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
51
71
|
function buildMarkdown(params) {
|
|
52
|
-
const { summary, nextSteps, taskDescription, currentStatus, keyDecisions, failedApproaches, blockers, modifiedFiles, implicitRules, displayTime } = params;
|
|
72
|
+
const { summary, nextSteps, taskDescription, currentStatus, keyDecisions, failedApproaches, blockers, modifiedFiles, implicitRules, displayTime, project, isoDate } = params;
|
|
73
|
+
const frontmatter = [
|
|
74
|
+
`---`,
|
|
75
|
+
`date: ${isoDate}`,
|
|
76
|
+
`project: ${project}`,
|
|
77
|
+
`next_steps_count: ${nextSteps.length}`,
|
|
78
|
+
`has_blockers: ${Boolean(blockers)}`,
|
|
79
|
+
`---`,
|
|
80
|
+
``
|
|
81
|
+
].join('\n');
|
|
53
82
|
const sections = [
|
|
83
|
+
frontmatter,
|
|
54
84
|
`# Session Handoff Snapshot`,
|
|
55
85
|
`> **Generated:** ${displayTime}`,
|
|
56
86
|
``
|
|
@@ -89,7 +119,7 @@ function buildMarkdown(params) {
|
|
|
89
119
|
if (summary) {
|
|
90
120
|
sections.push(`## Summary\n${summary}\n`);
|
|
91
121
|
}
|
|
92
|
-
sections.push(`---\n*Context is auto-restored on session start. Manual restore: \`/resume\`*`);
|
|
122
|
+
sections.push(`---\n*Context is auto-restored on session start. Manual restore: \`/handoff-resume\`*`);
|
|
93
123
|
return sections.join('\n');
|
|
94
124
|
}
|
|
95
125
|
async function main() {
|
package/hooks/hooks.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "prompt",
|
|
8
|
-
"prompt": "Evaluate whether context compaction should proceed.\n\nContext: $ARGUMENTS\n\nRules:\n- If 'generate_handoff_manifest' has already been called in this session, respond: {\"ok\": true}\n- If the session has minimal context (just started, no significant work done), respond: {\"ok\": true}\n- If there is meaningful session context worth preserving (decisions, progress, failures) and 'generate_handoff_manifest' was NOT called yet, respond: {\"ok\": false, \"reason\": \"Context compaction imminent. Call 'generate_handoff_manifest' to preserve session state. Fill all fields: summary (full session recap), taskDescription (goal), currentStatus (done vs remaining), keyDecisions (architecture choices + why), failedApproaches (already-failed — do NOT retry), nextSteps (next session tasks), blockers (unresolved errors). Write ALL field values in English.\"}\n\nIMPORTANT: Respond ONLY with a single JSON object. No markdown formatting, no explanation, no code blocks.",
|
|
8
|
+
"prompt": "Evaluate whether context compaction should proceed.\n\nContext: $ARGUMENTS\n\nRules (check in order, use the first that matches):\n- If 'generate_handoff_manifest' has already been called in this session, respond: {\"ok\": true}\n- If the session has minimal context (just started, no significant work done), respond: {\"ok\": true}\n- If a 'PreCompact hook feedback' message with this same reason already appears earlier in the context (i.e. Claude was already asked to call generate_handoff_manifest before compaction and has not done so after a real opportunity), respond: {\"ok\": true} — do NOT block compaction again; blocking compaction indefinitely risks hitting the hard context limit, which is worse than compacting without a fresh handoff.\n- If there is meaningful session context worth preserving (decisions, progress, failures) and 'generate_handoff_manifest' was NOT called yet, respond: {\"ok\": false, \"reason\": \"Context compaction imminent. Call 'generate_handoff_manifest' to preserve session state. Fill all fields: summary (full session recap), taskDescription (goal), currentStatus (done vs remaining), keyDecisions (architecture choices + why), failedApproaches (already-failed — do NOT retry), nextSteps (next session tasks), blockers (unresolved errors). Write ALL field values in English.\"}\n\nIMPORTANT: Respond ONLY with a single JSON object. No markdown formatting, no explanation, no code blocks.",
|
|
9
9
|
"timeout": 15
|
|
10
10
|
}
|
|
11
11
|
]
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "prompt",
|
|
19
|
-
"prompt": "Evaluate whether Claude should stop working.\n\nContext: $ARGUMENTS\n\nRules:\n- If 'generate_handoff_manifest' has already been called in this session, respond: {\"ok\": true}\n- If no meaningful work was done (e.g., simple Q&A, clarification, no code changes), respond: {\"ok\": true}\n- If
|
|
19
|
+
"prompt": "Evaluate whether Claude should stop working.\n\nContext: $ARGUMENTS\n\nRules (check in order, use the first that matches):\n- If 'generate_handoff_manifest' has already been called in this session, respond: {\"ok\": true}\n- If no meaningful work was done (e.g., simple Q&A, clarification, no code changes), respond: {\"ok\": true}\n- If Claude is only waiting on background/async work (subagents still running, a build/test in progress, an external process not yet finished) and has nothing new to act on right now, respond: {\"ok\": true} — do not force a handoff mid-wait; this hook will fire again once that work actually finishes.\n- If a 'Stop hook feedback' message with this same reason already appears earlier in the context (i.e. Claude was already asked to call generate_handoff_manifest for this work and has not done so after a real opportunity), respond: {\"ok\": true} — do not repeat the same block forever.\n- If the completed work is trivial (a single small edit, a one-line fix, a doc/comment tweak, a config nudge confined to one file), respond: {\"ok\": true} — too small to warrant a handoff.\n- Otherwise, BOTH conditions below must hold before blocking — if either is false, respond {\"ok\": true} and let the session continue normally without a handoff:\n (a) Substantial work was completed: spans multiple files, or is a completed feature/bug fix/refactor with real design decisions behind it.\n (b) The context window actually looks like it is filling up: judge this from what you can observe in the current session — many turns, many tool calls, large files read, long tool outputs, extensive exploration or back-and-forth. A short session with only a few turns/tool calls does NOT meet this bar even if the work itself was substantial — there is no hook-level API for exact token/context-window percentage, so this is a visible-session-size heuristic, not a precise measurement.\n- If (a) AND (b) both hold, 'generate_handoff_manifest' was NOT called yet, this is the first time asking, and no background work is pending, respond: {\"ok\": false, \"reason\": \"A substantial work unit was completed and this session's context looks like it is filling up. Call 'generate_handoff_manifest' with taskDescription, keyDecisions, failedApproaches, and nextSteps so the next session has full context. Write ALL field values in English.\"}\n\nIMPORTANT: Respond ONLY with a single JSON object. No markdown formatting, no explanation, no code blocks.",
|
|
20
20
|
"timeout": 15
|
|
21
21
|
}
|
|
22
22
|
]
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "prompt",
|
|
30
|
-
"prompt": "On session start: if .claude/handoff.md exists, read it and briefly brief the user (in their language) on Task Description, Current Status, Key Decisions, Failed Approaches, Blockers, Next Steps. If
|
|
30
|
+
"prompt": "On session start: check if .claude/handoff.md exists.\n\nRules:\n- If it is missing, or exists but is empty/unparseable (e.g. no frontmatter, no recognizable sections), stay silent.\n- Otherwise, read it and briefly brief the user (in their language) on Task Description, Current Status, Key Decisions, Failed Approaches, Blockers, Next Steps.\n- Check the frontmatter `date` field. If it is more than 3 days before today, prepend a short staleness note to the brief (e.g. 'this handoff is N days old, may be outdated') so the user knows to double-check before trusting it.",
|
|
31
31
|
"timeout": 10
|
|
32
32
|
}
|
|
33
33
|
]
|
package/package.json
CHANGED
package/scripts/setup.ps1
CHANGED
|
@@ -29,7 +29,7 @@ Write-Host ""
|
|
|
29
29
|
Write-Host "[Handoff Setup] Done!"
|
|
30
30
|
Write-Host ""
|
|
31
31
|
Write-Host " Usage:"
|
|
32
|
-
Write-Host " /handoff
|
|
33
|
-
Write-Host " /resume
|
|
32
|
+
Write-Host " /handoff-save -- save current session"
|
|
33
|
+
Write-Host " /handoff-resume -- restore previous session"
|
|
34
34
|
Write-Host ""
|
|
35
35
|
Write-Host " SessionStart hook auto-restores previous context on session open."
|
package/scripts/setup.sh
CHANGED
|
@@ -28,7 +28,7 @@ echo ""
|
|
|
28
28
|
echo "[Handoff Setup] Done!"
|
|
29
29
|
echo ""
|
|
30
30
|
echo " Usage:"
|
|
31
|
-
echo " /handoff
|
|
32
|
-
echo " /resume
|
|
31
|
+
echo " /handoff-save -- save current session"
|
|
32
|
+
echo " /handoff-resume -- restore previous session"
|
|
33
33
|
echo ""
|
|
34
34
|
echo " SessionStart hook auto-restores previous context on session open."
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Restore previous session context from handoff file. Use when user runs /resume or asks to continue from last session.
|
|
2
|
+
description: Restore previous session context from handoff file. Use when user runs /handoff-resume or asks to continue from last session.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Reads `.claude/handoff.md`. Falls back to latest file in `.claude/handoffs/`.
|
|
@@ -8,7 +8,7 @@ Reads `.claude/handoff.md`. Falls back to latest file in `.claude/handoffs/`.
|
|
|
8
8
|
|
|
9
9
|
1. Read `.claude/handoff.md`
|
|
10
10
|
2. If missing, find latest `handoff-*.md` in `.claude/handoffs/`
|
|
11
|
-
3. If neither found: tell user "No handoff file. Run /handoff first."
|
|
11
|
+
3. If neither found: tell user "No handoff file. Run /handoff-save first."
|
|
12
12
|
4. If found:
|
|
13
13
|
- Parse: Task Description, Current Status, Key Decisions, Failed Approaches, Blockers, Next Steps
|
|
14
14
|
- Brief user in their language
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Save current session context to handoff file. Use when user runs /handoff or asks to save session state before ending.
|
|
2
|
+
description: Save current session context to handoff file. Use when user runs /handoff-save or asks to save session state before ending.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Save session context to `.claude/handoff.md` and timestamped archive to `.claude/handoffs/`.
|
|
@@ -34,4 +34,4 @@ Write all field values using telegraphese — drop articles, pronouns, polite wo
|
|
|
34
34
|
3. Confirm to user:
|
|
35
35
|
- Latest: `.claude/handoff.md`
|
|
36
36
|
- Archive: `.claude/handoffs/handoff-{timestamp}.md`
|
|
37
|
-
- Next session: run `/resume` or SessionStart hook auto-restores
|
|
37
|
+
- Next session: run `/handoff-resume` or SessionStart hook auto-restores
|