claude-code-handoff 1.3.2 → 1.5.1
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/README.md +175 -27
- package/cli.js +54 -18
- package/commands/auto-handoff.md +37 -0
- package/hooks/context-monitor.sh +52 -0
- package/hooks/session-cleanup.sh +7 -0
- package/install.sh +157 -19
- package/package.json +2 -1
- package/rules/auto-handoff.md +13 -0
- package/uninstall.sh +30 -8
- package/update.sh +35 -5
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Either way, you lose. Auto-compact gives you a degraded Claude that forgets. Man
|
|
|
36
36
|
|
|
37
37
|
## The Solution
|
|
38
38
|
|
|
39
|
-
Instead of relying on lossy compression or starting from zero, **claude-code-handoff** gives Claude **structured persistent memory** —
|
|
39
|
+
Instead of relying on lossy compression or starting from zero, **claude-code-handoff** gives Claude **structured persistent memory** — 6 slash commands that capture exactly what matters and restore it cleanly:
|
|
40
40
|
|
|
41
41
|
| Command | Description |
|
|
42
42
|
|---------|-------------|
|
|
@@ -45,9 +45,12 @@ Instead of relying on lossy compression or starting from zero, **claude-code-han
|
|
|
45
45
|
| `/save-handoff` | Save with options — choose where and how |
|
|
46
46
|
| `/switch-context <topic>` | Switch between parallel workstreams |
|
|
47
47
|
| `/delete-handoff` | Delete one or more saved handoffs |
|
|
48
|
+
| `/auto-handoff` | Enable/disable auto-handoff or adjust threshold |
|
|
48
49
|
|
|
49
50
|
The workflow becomes: work until context is full → `/handoff` → `/clear` → `/resume` → continue with full context. No degradation, no amnesia. Just clean handoffs.
|
|
50
51
|
|
|
52
|
+
**Auto-handoff** (since v1.4) monitors your context usage and **automatically triggers a handoff** when the transcript reaches a configurable threshold (default: **90%**) — so you never forget to save. Since v1.5, the threshold is configured as a **percentage of context** instead of fixed bytes, making it intuitive and portable across different setups.
|
|
53
|
+
|
|
51
54
|
Session state is stored in `.claude/handoffs/` (gitignored) — each developer keeps their own context, no conflicts.
|
|
52
55
|
|
|
53
56
|
---
|
|
@@ -59,7 +62,7 @@ cd your-project
|
|
|
59
62
|
npx claude-code-handoff
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
That's it. Open Claude Code and your
|
|
65
|
+
That's it. Open Claude Code and your 6 commands are ready. Auto-handoff is enabled by default at 90%.
|
|
63
66
|
|
|
64
67
|
---
|
|
65
68
|
|
|
@@ -152,13 +155,99 @@ graph TD
|
|
|
152
155
|
|
|
153
156
|
---
|
|
154
157
|
|
|
158
|
+
## Auto-Handoff (Context Monitor)
|
|
159
|
+
|
|
160
|
+
The biggest risk with handoffs is **forgetting to save**. You're deep in a task, context fills up, and everything is lost. Auto-handoff eliminates this by monitoring your transcript size and **forcing Claude to save the handoff** before it's too late.
|
|
161
|
+
|
|
162
|
+
### How It Works
|
|
163
|
+
|
|
164
|
+
A [Claude Code hook](https://docs.anthropic.com/en/docs/claude-code/hooks) runs after every Claude response (Stop event). It checks the transcript file size against a configurable threshold. When the threshold is exceeded, it **blocks** Claude's next action and forces an immediate handoff save.
|
|
165
|
+
|
|
166
|
+
```mermaid
|
|
167
|
+
flowchart TD
|
|
168
|
+
A[Claude responds] --> B[Stop hook fires]
|
|
169
|
+
B --> C["Transcript size > threshold?"]
|
|
170
|
+
C -->|No| D[Continue normally]
|
|
171
|
+
C -->|Yes| E{Already triggered this session?}
|
|
172
|
+
E -->|Yes| D
|
|
173
|
+
E -->|No| F[Create flag file in /tmp]
|
|
174
|
+
F --> G["Block Claude: force handoff save"]
|
|
175
|
+
G --> H[Claude writes _active.md]
|
|
176
|
+
H --> I["User: /clear → /resume"]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Threshold Configuration
|
|
180
|
+
|
|
181
|
+
The threshold is configured as a **percentage of the estimated maximum context** (~500KB transcript). This makes it intuitive — you think in terms of "how full is my context?" rather than raw byte counts.
|
|
182
|
+
|
|
183
|
+
| Preset | Value | Triggers at | Best for |
|
|
184
|
+
|--------|-------|-------------|----------|
|
|
185
|
+
| **90% (default)** | `THRESHOLD_PERCENT=90` | ~450KB | Maximizing context usage |
|
|
186
|
+
| **80%** | `THRESHOLD_PERCENT=80` | ~400KB | Balance between space and safety |
|
|
187
|
+
| **75%** | `THRESHOLD_PERCENT=75` | ~375KB | Short sessions, early handoff |
|
|
188
|
+
|
|
189
|
+
The calculation is straightforward:
|
|
190
|
+
```
|
|
191
|
+
MAX_CONTEXT_SIZE = 500000 (500KB — estimated max transcript)
|
|
192
|
+
THRESHOLD = MAX_CONTEXT_SIZE × THRESHOLD_PERCENT / 100
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Three Ways to Configure
|
|
196
|
+
|
|
197
|
+
**1. Environment variable** (per-session override):
|
|
198
|
+
```bash
|
|
199
|
+
# Trigger at 80% instead of the default
|
|
200
|
+
export CLAUDE_CONTEXT_THRESHOLD=80
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**2. Interactive wizard** (`/auto-handoff` command):
|
|
204
|
+
```
|
|
205
|
+
you: /auto-handoff
|
|
206
|
+
claude: Auto-handoff is ENABLED (threshold: 90%). What would you like to do?
|
|
207
|
+
1. Disable
|
|
208
|
+
2. Adjust threshold
|
|
209
|
+
|
|
210
|
+
you: [selects "Adjust threshold"]
|
|
211
|
+
claude: Which threshold do you want?
|
|
212
|
+
1. 90% (Recommended) — Default, maximizes context usage
|
|
213
|
+
2. 80% — Balance between space and safety
|
|
214
|
+
3. 75% — Short sessions, saves handoff earlier
|
|
215
|
+
4. Other — Type a custom value
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**3. Edit the script directly**:
|
|
219
|
+
```bash
|
|
220
|
+
# In .claude/hooks/context-monitor.sh, change the default:
|
|
221
|
+
THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-90} # change 90 to your value
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Safety Mechanisms
|
|
225
|
+
|
|
226
|
+
- **One-shot trigger**: A flag file in `/tmp` (per session ID) prevents infinite loops — the hook triggers exactly once per session, even if Claude's handoff response pushes the transcript further
|
|
227
|
+
- **Session cleanup**: A `SessionStart` hook automatically cleans up stale flag files older than 24 hours
|
|
228
|
+
- **Disable switch**: Create `.claude/hooks/.auto-handoff-disabled` to completely disable the monitor (or use `/auto-handoff` to toggle)
|
|
229
|
+
- **Non-destructive**: The hook only blocks and instructs — it never modifies files directly. Claude performs the actual handoff save
|
|
230
|
+
|
|
231
|
+
### What Happens When It Triggers
|
|
232
|
+
|
|
233
|
+
When the threshold is hit, Claude receives a block message like:
|
|
234
|
+
|
|
235
|
+
> ⚠️ AUTO-HANDOFF: Context reached 90% of the limit. You MUST save the handoff NOW.
|
|
236
|
+
|
|
237
|
+
Claude will then:
|
|
238
|
+
1. Analyze the full conversation
|
|
239
|
+
2. Write the handoff to `.claude/handoffs/_active.md`
|
|
240
|
+
3. Tell you: "Handoff saved automatically. Use `/clear` then `/resume` to continue."
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
155
244
|
## Install
|
|
156
245
|
|
|
157
246
|
### Option A: npx (recommended)
|
|
158
247
|
|
|
159
248
|
```bash
|
|
160
249
|
cd your-project
|
|
161
|
-
npx claude-code-handoff@
|
|
250
|
+
npx claude-code-handoff@latest
|
|
162
251
|
```
|
|
163
252
|
|
|
164
253
|
### Option B: curl
|
|
@@ -182,22 +271,29 @@ cd your-project
|
|
|
182
271
|
your-project/
|
|
183
272
|
└── .claude/
|
|
184
273
|
├── commands/
|
|
185
|
-
│ ├── handoff.md
|
|
186
|
-
│ ├── resume.md
|
|
187
|
-
│ ├── save-handoff.md
|
|
188
|
-
│ ├── switch-context.md
|
|
189
|
-
│
|
|
274
|
+
│ ├── handoff.md ← /handoff (auto-save)
|
|
275
|
+
│ ├── resume.md ← /resume (interactive picker)
|
|
276
|
+
│ ├── save-handoff.md ← /save-handoff (wizard)
|
|
277
|
+
│ ├── switch-context.md ← /switch-context (workstream switch)
|
|
278
|
+
│ ├── delete-handoff.md ← /delete-handoff (remove handoffs)
|
|
279
|
+
│ └── auto-handoff.md ← /auto-handoff (on/off + threshold)
|
|
190
280
|
├── rules/
|
|
191
|
-
│
|
|
192
|
-
└──
|
|
193
|
-
|
|
194
|
-
|
|
281
|
+
│ ├── session-continuity.md ← Auto-loaded behavioral rules
|
|
282
|
+
│ └── auto-handoff.md ← Auto-handoff trigger rules
|
|
283
|
+
├── hooks/
|
|
284
|
+
│ ├── context-monitor.sh ← Stop hook (monitors context size)
|
|
285
|
+
│ └── session-cleanup.sh ← SessionStart hook (cleans old flags)
|
|
286
|
+
├── settings.json ← Hook configuration
|
|
287
|
+
└── handoffs/ ← Session state (gitignored)
|
|
288
|
+
├── _active.md ← Current workstream
|
|
289
|
+
└── archive/ ← Paused workstreams
|
|
195
290
|
```
|
|
196
291
|
|
|
197
292
|
The installer also:
|
|
198
293
|
- Creates the full `.claude/handoffs/archive/` directory structure
|
|
199
294
|
- Adds `.claude/handoffs/` to `.gitignore`
|
|
200
295
|
- Adds a `Session Continuity` section to `.claude/CLAUDE.md` (creates one if missing)
|
|
296
|
+
- Configures auto-handoff hooks in `.claude/settings.json`
|
|
201
297
|
|
|
202
298
|
---
|
|
203
299
|
|
|
@@ -252,6 +348,45 @@ claude: Where should this session's handoff be saved?
|
|
|
252
348
|
3. Replace active
|
|
253
349
|
```
|
|
254
350
|
|
|
351
|
+
### Auto-handoff in action
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
you: [working normally on a long session...]
|
|
355
|
+
claude: [responds to your request]
|
|
356
|
+
|
|
357
|
+
── context reaches 90% ──
|
|
358
|
+
|
|
359
|
+
claude: ⚠️ AUTO-HANDOFF: Context reached 90% of the limit.
|
|
360
|
+
Handoff saved automatically.
|
|
361
|
+
Use /clear then /resume to continue.
|
|
362
|
+
|
|
363
|
+
you: /clear
|
|
364
|
+
|
|
365
|
+
── new session ──
|
|
366
|
+
|
|
367
|
+
you: /resume
|
|
368
|
+
claude: ## Resuming session
|
|
369
|
+
[full context restored, continues exactly where you left off]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Adjusting auto-handoff threshold
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
you: /auto-handoff
|
|
376
|
+
claude: Auto-handoff is ENABLED (threshold: 90%). What would you like to do?
|
|
377
|
+
1. Disable
|
|
378
|
+
2. Adjust threshold
|
|
379
|
+
|
|
380
|
+
you: [selects "Adjust threshold"]
|
|
381
|
+
claude: Which threshold do you want?
|
|
382
|
+
1. 90% (Recommended)
|
|
383
|
+
2. 80%
|
|
384
|
+
3. 75%
|
|
385
|
+
|
|
386
|
+
you: [types "95" via Other]
|
|
387
|
+
claude: ✅ Threshold updated to 95%.
|
|
388
|
+
```
|
|
389
|
+
|
|
255
390
|
---
|
|
256
391
|
|
|
257
392
|
## What Gets Captured
|
|
@@ -338,12 +473,12 @@ graph TD
|
|
|
338
473
|
style SW fill:#7c2d12,stroke:#fb923c,color:#fff
|
|
339
474
|
```
|
|
340
475
|
|
|
341
|
-
| | `/handoff` | `/save-handoff` | `/resume` | `/switch-context` |
|
|
342
|
-
|
|
343
|
-
| **When** | Before `/clear` | When you need options | Start of session | Mid-session |
|
|
344
|
-
| **Interactive** | No | Yes (wizard) | Yes (picker) | No (with arg) |
|
|
345
|
-
| **Creates files** | Auto | User chooses | No | Auto |
|
|
346
|
-
| **Reads files** | `_active.md` | `_active.md` + `archive/` | All handoffs | `_active.md` + target |
|
|
476
|
+
| | `/handoff` | `/save-handoff` | `/resume` | `/switch-context` | `/auto-handoff` |
|
|
477
|
+
|---|---|---|---|---|---|
|
|
478
|
+
| **When** | Before `/clear` | When you need options | Start of session | Mid-session | Anytime |
|
|
479
|
+
| **Interactive** | No | Yes (wizard) | Yes (picker) | No (with arg) | Yes (wizard) |
|
|
480
|
+
| **Creates files** | Auto | User chooses | No | Auto | Toggle file |
|
|
481
|
+
| **Reads files** | `_active.md` | `_active.md` + `archive/` | All handoffs | `_active.md` + target | Hook config |
|
|
347
482
|
|
|
348
483
|
---
|
|
349
484
|
|
|
@@ -353,7 +488,8 @@ The installer adds a `session-continuity.md` rules file that Claude auto-loads o
|
|
|
353
488
|
|
|
354
489
|
- **On session start**: Claude knows `_active.md` exists but doesn't read it unless asked
|
|
355
490
|
- **During work**: Claude proactively reminds you to save after significant milestones
|
|
356
|
-
- **Command awareness**: Claude understands all
|
|
491
|
+
- **Command awareness**: Claude understands all 6 commands natively
|
|
492
|
+
- **Auto-handoff awareness**: When the context monitor triggers, Claude knows exactly what to do — save the handoff immediately without asking
|
|
357
493
|
|
|
358
494
|
---
|
|
359
495
|
|
|
@@ -375,9 +511,10 @@ curl -fsSL https://raw.githubusercontent.com/eximIA-Ventures/claude-code-handoff
|
|
|
375
511
|
|
|
376
512
|
This will:
|
|
377
513
|
- Overwrite command files with the latest versions
|
|
378
|
-
- Update
|
|
379
|
-
-
|
|
380
|
-
-
|
|
514
|
+
- Update rules and hooks to latest
|
|
515
|
+
- Ensure hooks are configured in `settings.json`
|
|
516
|
+
- Remove legacy files if present (`auto-handoff-toggle.md`, Portuguese commands)
|
|
517
|
+
- **Not touch** your `.claude/handoffs/` data or custom threshold settings
|
|
381
518
|
|
|
382
519
|
---
|
|
383
520
|
|
|
@@ -389,16 +526,18 @@ curl -fsSL https://raw.githubusercontent.com/eximIA-Ventures/claude-code-handoff
|
|
|
389
526
|
```
|
|
390
527
|
|
|
391
528
|
The uninstaller:
|
|
392
|
-
- Removes all
|
|
393
|
-
- Removes
|
|
529
|
+
- Removes all 6 command files (including legacy `auto-handoff-toggle.md`)
|
|
530
|
+
- Removes rules and hooks
|
|
531
|
+
- Cleans hooks from `settings.json` (requires `jq`)
|
|
394
532
|
- Preserves handoff data if sessions exist (won't delete your session history)
|
|
395
533
|
- Cleans `.gitignore` entries
|
|
396
534
|
- Leaves `CLAUDE.md` unchanged (remove the section manually if desired)
|
|
397
535
|
|
|
398
536
|
Or remove manually:
|
|
399
537
|
```bash
|
|
400
|
-
rm .claude/commands/{handoff,resume,save-handoff,switch-context,delete-handoff}.md
|
|
401
|
-
rm .claude/rules/session-continuity.md
|
|
538
|
+
rm .claude/commands/{handoff,resume,save-handoff,switch-context,delete-handoff,auto-handoff}.md
|
|
539
|
+
rm .claude/rules/{session-continuity,auto-handoff}.md
|
|
540
|
+
rm .claude/hooks/{context-monitor,session-cleanup}.sh
|
|
402
541
|
rm -rf .claude/handoffs/ # ⚠️ deletes all session history
|
|
403
542
|
```
|
|
404
543
|
|
|
@@ -418,7 +557,7 @@ rm -rf .claude/handoffs/ # ⚠️ deletes all session history
|
|
|
418
557
|
A: Yes. Handoff files are gitignored, so each developer has their own session state. No conflicts.
|
|
419
558
|
|
|
420
559
|
**Q: What happens if I forget to `/handoff` before `/clear`?**
|
|
421
|
-
A:
|
|
560
|
+
A: With auto-handoff enabled (default since v1.4), Claude will automatically save the handoff when the context reaches 90%. Without it, the context is lost for that session — the previous handoff is still there, but you won't have the latest session recorded.
|
|
422
561
|
|
|
423
562
|
**Q: Can I have unlimited workstreams?**
|
|
424
563
|
A: Yes. The `archive/` folder has no limit. Each workstream is a single `.md` file.
|
|
@@ -432,6 +571,15 @@ A: The commands automatically summarize older sessions into a "Prior Sessions Su
|
|
|
432
571
|
**Q: Can I edit the handoff files manually?**
|
|
433
572
|
A: Absolutely. They're plain markdown. You can add notes, reorder next steps, or clean up history.
|
|
434
573
|
|
|
574
|
+
**Q: How does the auto-handoff threshold work?**
|
|
575
|
+
A: The threshold is a percentage of the estimated maximum transcript size (~500KB). At 90% (default), the hook triggers when the transcript reaches ~450KB. You can set any value from 1-100 via env var (`CLAUDE_CONTEXT_THRESHOLD=80`) or the `/auto-handoff` command.
|
|
576
|
+
|
|
577
|
+
**Q: Can I disable auto-handoff?**
|
|
578
|
+
A: Yes. Run `/auto-handoff` and select "Disable", or manually create the file `.claude/hooks/.auto-handoff-disabled`. Delete the file to re-enable.
|
|
579
|
+
|
|
580
|
+
**Q: What if auto-handoff triggers too early/late?**
|
|
581
|
+
A: Adjust the threshold. If it triggers too early, increase to 95%. If you're running out of context before it triggers, lower to 80% or 75%. Use `/auto-handoff` to change it interactively.
|
|
582
|
+
|
|
435
583
|
---
|
|
436
584
|
|
|
437
585
|
## Contributing
|
package/cli.js
CHANGED
|
@@ -36,27 +36,54 @@ function copyFile(src, dst) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// 1. Create directories
|
|
39
|
-
console.log(` ${YELLOW}[1/
|
|
39
|
+
console.log(` ${YELLOW}[1/10]${NC} Creating directories...`);
|
|
40
40
|
ensureDir(path.join(CLAUDE_DIR, 'commands'));
|
|
41
41
|
ensureDir(path.join(CLAUDE_DIR, 'rules'));
|
|
42
|
+
ensureDir(path.join(CLAUDE_DIR, 'hooks'));
|
|
42
43
|
ensureDir(path.join(CLAUDE_DIR, 'handoffs', 'archive'));
|
|
43
44
|
|
|
44
45
|
// 2. Copy commands
|
|
45
|
-
console.log(` ${YELLOW}[2/
|
|
46
|
+
console.log(` ${YELLOW}[2/10]${NC} Installing commands...`);
|
|
46
47
|
copyFile('commands/resume.md', path.join(CLAUDE_DIR, 'commands', 'resume.md'));
|
|
47
48
|
copyFile('commands/save-handoff.md', path.join(CLAUDE_DIR, 'commands', 'save-handoff.md'));
|
|
48
49
|
copyFile('commands/switch-context.md', path.join(CLAUDE_DIR, 'commands', 'switch-context.md'));
|
|
49
50
|
copyFile('commands/handoff.md', path.join(CLAUDE_DIR, 'commands', 'handoff.md'));
|
|
50
51
|
copyFile('commands/delete-handoff.md', path.join(CLAUDE_DIR, 'commands', 'delete-handoff.md'));
|
|
52
|
+
copyFile('commands/auto-handoff.md', path.join(CLAUDE_DIR, 'commands', 'auto-handoff.md'));
|
|
51
53
|
|
|
52
54
|
// 3. Copy rules
|
|
53
|
-
console.log(` ${YELLOW}[3/
|
|
55
|
+
console.log(` ${YELLOW}[3/10]${NC} Installing rules...`);
|
|
54
56
|
copyFile('rules/session-continuity.md', path.join(CLAUDE_DIR, 'rules', 'session-continuity.md'));
|
|
57
|
+
copyFile('rules/auto-handoff.md', path.join(CLAUDE_DIR, 'rules', 'auto-handoff.md'));
|
|
58
|
+
|
|
59
|
+
// 4. Install hooks
|
|
60
|
+
console.log(` ${YELLOW}[4/10]${NC} Installing hooks...`);
|
|
61
|
+
copyFile('hooks/context-monitor.sh', path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'));
|
|
62
|
+
copyFile('hooks/session-cleanup.sh', path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'));
|
|
63
|
+
fs.chmodSync(path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'), 0o755);
|
|
64
|
+
fs.chmodSync(path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'), 0o755);
|
|
65
|
+
|
|
66
|
+
// 5. Configure hooks in settings.json
|
|
67
|
+
console.log(` ${YELLOW}[5/10]${NC} Configuring hooks in settings.json...`);
|
|
68
|
+
const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
|
|
69
|
+
const hooksConfig = {
|
|
70
|
+
Stop: [{ hooks: [{ type: 'command', command: '"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh"', timeout: 10 }] }],
|
|
71
|
+
SessionStart: [{ hooks: [{ type: 'command', command: '"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh"', timeout: 5 }] }]
|
|
72
|
+
};
|
|
73
|
+
if (fs.existsSync(settingsPath)) {
|
|
74
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
75
|
+
if (!JSON.stringify(settings).includes('context-monitor')) {
|
|
76
|
+
settings.hooks = hooksConfig;
|
|
77
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
fs.writeFileSync(settingsPath, JSON.stringify({ hooks: hooksConfig }, null, 2) + '\n');
|
|
81
|
+
}
|
|
55
82
|
|
|
56
83
|
// 4. Create initial _active.md
|
|
57
84
|
const activePath = path.join(CLAUDE_DIR, 'handoffs', '_active.md');
|
|
58
85
|
if (!fs.existsSync(activePath)) {
|
|
59
|
-
console.log(` ${YELLOW}[
|
|
86
|
+
console.log(` ${YELLOW}[6/10]${NC} Creating initial handoff...`);
|
|
60
87
|
fs.writeFileSync(activePath, `# Session Handoff
|
|
61
88
|
|
|
62
89
|
> No active session yet. Use \`/handoff\` or \`/save-handoff\` to save your first session state.
|
|
@@ -83,11 +110,11 @@ if (!fs.existsSync(activePath)) {
|
|
|
83
110
|
(none)
|
|
84
111
|
`);
|
|
85
112
|
} else {
|
|
86
|
-
console.log(` ${YELLOW}[
|
|
113
|
+
console.log(` ${YELLOW}[6/10]${NC} Handoff already exists, keeping it`);
|
|
87
114
|
}
|
|
88
115
|
|
|
89
|
-
//
|
|
90
|
-
console.log(` ${YELLOW}[
|
|
116
|
+
// 7. Update .gitignore
|
|
117
|
+
console.log(` ${YELLOW}[7/10]${NC} Updating .gitignore...`);
|
|
91
118
|
const gitignorePath = path.join(PROJECT_DIR, '.gitignore');
|
|
92
119
|
if (fs.existsSync(gitignorePath)) {
|
|
93
120
|
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
@@ -98,8 +125,8 @@ if (fs.existsSync(gitignorePath)) {
|
|
|
98
125
|
fs.writeFileSync(gitignorePath, '# claude-code-handoff (personal session state)\n.claude/handoffs/\n');
|
|
99
126
|
}
|
|
100
127
|
|
|
101
|
-
//
|
|
102
|
-
console.log(` ${YELLOW}[
|
|
128
|
+
// 8. Update CLAUDE.md
|
|
129
|
+
console.log(` ${YELLOW}[8/10]${NC} Updating CLAUDE.md...`);
|
|
103
130
|
const claudeMdPath = path.join(CLAUDE_DIR, 'CLAUDE.md');
|
|
104
131
|
const continuityBlock = `## Session Continuity (MANDATORY)
|
|
105
132
|
|
|
@@ -123,20 +150,23 @@ if (fs.existsSync(claudeMdPath)) {
|
|
|
123
150
|
fs.writeFileSync(claudeMdPath, `# Project Rules\n\n${continuityBlock}\n`);
|
|
124
151
|
}
|
|
125
152
|
|
|
126
|
-
//
|
|
127
|
-
console.log(` ${YELLOW}[
|
|
153
|
+
// 9. Verify
|
|
154
|
+
console.log(` ${YELLOW}[9/10]${NC} Verifying installation...`);
|
|
128
155
|
let installed = 0;
|
|
129
|
-
for (const f of ['resume.md', 'save-handoff.md', 'switch-context.md', 'handoff.md', 'delete-handoff.md']) {
|
|
156
|
+
for (const f of ['resume.md', 'save-handoff.md', 'switch-context.md', 'handoff.md', 'delete-handoff.md', 'auto-handoff.md']) {
|
|
130
157
|
if (fs.existsSync(path.join(CLAUDE_DIR, 'commands', f))) installed++;
|
|
131
158
|
}
|
|
159
|
+
let hooksOk = 0;
|
|
160
|
+
if (fs.existsSync(path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'))) hooksOk++;
|
|
161
|
+
if (fs.existsSync(path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'))) hooksOk++;
|
|
132
162
|
|
|
133
163
|
console.log('');
|
|
134
|
-
console.log(` ${YELLOW}[
|
|
164
|
+
console.log(` ${YELLOW}[10/10]${NC} Done!`);
|
|
135
165
|
console.log('');
|
|
136
|
-
if (installed ===
|
|
137
|
-
console.log(`${GREEN} Installed successfully! (${installed}/
|
|
166
|
+
if (installed === 6 && hooksOk === 2) {
|
|
167
|
+
console.log(`${GREEN} Installed successfully! (${installed}/6 commands, ${hooksOk}/2 hooks)${NC}`);
|
|
138
168
|
} else {
|
|
139
|
-
console.log(`${YELLOW} Partial install: ${installed}/
|
|
169
|
+
console.log(`${YELLOW} Partial install: ${installed}/6 commands, ${hooksOk}/2 hooks${NC}`);
|
|
140
170
|
}
|
|
141
171
|
console.log('');
|
|
142
172
|
console.log(' Commands available:');
|
|
@@ -145,10 +175,16 @@ console.log(` ${CYAN}/resume${NC} Resume with wizard`);
|
|
|
145
175
|
console.log(` ${CYAN}/save-handoff${NC} Save session state (wizard)`);
|
|
146
176
|
console.log(` ${CYAN}/switch-context${NC} Switch workstream`);
|
|
147
177
|
console.log(` ${CYAN}/delete-handoff${NC} Delete handoff(s)`);
|
|
178
|
+
console.log(` ${CYAN}/auto-handoff${NC} Toggle auto-handoff on/off`);
|
|
179
|
+
console.log('');
|
|
180
|
+
console.log(' Auto-handoff:');
|
|
181
|
+
console.log(' Context monitor hook installed (triggers at 90% of context)');
|
|
182
|
+
console.log(` Use ${CYAN}/auto-handoff${NC} to enable/disable or adjust threshold`);
|
|
148
183
|
console.log('');
|
|
149
184
|
console.log(' Files:');
|
|
150
|
-
console.log(' .claude/commands/
|
|
151
|
-
console.log(' .claude/rules/ session-continuity.md');
|
|
185
|
+
console.log(' .claude/commands/ 6 command files');
|
|
186
|
+
console.log(' .claude/rules/ session-continuity.md, auto-handoff.md');
|
|
187
|
+
console.log(' .claude/hooks/ context-monitor.sh, session-cleanup.sh');
|
|
152
188
|
console.log(' .claude/handoffs/ session state (gitignored)');
|
|
153
189
|
console.log('');
|
|
154
190
|
console.log(` ${YELLOW}Start Claude Code and use /resume to begin.${NC}`);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Auto-Handoff
|
|
2
|
+
|
|
3
|
+
Toggle the automatic handoff context monitor on/off and configure the threshold.
|
|
4
|
+
|
|
5
|
+
## Instructions
|
|
6
|
+
|
|
7
|
+
### Step 1: Check current state
|
|
8
|
+
|
|
9
|
+
Check if `.claude/hooks/.auto-handoff-disabled` exists:
|
|
10
|
+
- If exists → currently DISABLED
|
|
11
|
+
- If not exists → currently ENABLED
|
|
12
|
+
|
|
13
|
+
Also read the current `THRESHOLD_PERCENT` value from `.claude/hooks/context-monitor.sh` (the default value in `THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-XX}`).
|
|
14
|
+
|
|
15
|
+
### Step 2: Present wizard
|
|
16
|
+
|
|
17
|
+
Use AskUserQuestion:
|
|
18
|
+
- Question: "Auto-handoff está [ATIVADO/DESATIVADO] (threshold: [XX]%). O que deseja fazer?"
|
|
19
|
+
- Options based on current state:
|
|
20
|
+
- If enabled: "Desativar" / "Ajustar threshold"
|
|
21
|
+
- If disabled: "Ativar" / "Ativar com threshold customizado"
|
|
22
|
+
|
|
23
|
+
### Step 3: Execute
|
|
24
|
+
|
|
25
|
+
- Toggle: create or delete `.claude/hooks/.auto-handoff-disabled`
|
|
26
|
+
- Threshold: If user chose to adjust threshold, ask with AskUserQuestion:
|
|
27
|
+
- Question: "Qual threshold deseja usar?"
|
|
28
|
+
- Options:
|
|
29
|
+
- "90% (Recomendado)" — Padrão, maximiza o uso do contexto
|
|
30
|
+
- "80%" — Equilíbrio entre espaço e segurança
|
|
31
|
+
- "75%" — Para sessões curtas, salva handoff mais cedo
|
|
32
|
+
- The user can also type a custom value via "Other"
|
|
33
|
+
- Update the `THRESHOLD_PERCENT` default value in `context-monitor.sh` by changing `THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-XX}` to the chosen value
|
|
34
|
+
|
|
35
|
+
### Step 4: Confirm
|
|
36
|
+
|
|
37
|
+
Show current state after change.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Auto-Handoff Context Monitor
|
|
3
|
+
# Detecta quando o contexto está próximo do limite e força o salvamento do handoff.
|
|
4
|
+
# Usado como hook "Stop" do Claude Code.
|
|
5
|
+
|
|
6
|
+
# Check if auto-handoff is disabled
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
if [ -f "$SCRIPT_DIR/.auto-handoff-disabled" ]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Contexto máximo estimado (bytes). 500KB ~ transcript máximo típico
|
|
13
|
+
MAX_CONTEXT_SIZE=500000
|
|
14
|
+
# Threshold configurável (% do contexto). 90% padrão — maximiza uso do contexto
|
|
15
|
+
THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-90}
|
|
16
|
+
THRESHOLD=$((MAX_CONTEXT_SIZE * THRESHOLD_PERCENT / 100))
|
|
17
|
+
|
|
18
|
+
INPUT=$(cat)
|
|
19
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')
|
|
20
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty')
|
|
21
|
+
|
|
22
|
+
# Validações
|
|
23
|
+
if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if [ -z "$SESSION_ID" ]; then
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Verifica tamanho do transcript
|
|
32
|
+
SIZE=$(wc -c < "$TRANSCRIPT_PATH" 2>/dev/null || echo 0)
|
|
33
|
+
SIZE=$(echo "$SIZE" | tr -d ' ')
|
|
34
|
+
|
|
35
|
+
if [ "$SIZE" -lt "$THRESHOLD" ]; then
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Flag para não re-triggerar (prevenção de loop infinito)
|
|
40
|
+
FLAG="/tmp/claude_handoff_triggered_${SESSION_ID}"
|
|
41
|
+
if [ -f "$FLAG" ]; then
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
touch "$FLAG"
|
|
45
|
+
|
|
46
|
+
# Bloqueia e força handoff
|
|
47
|
+
cat <<HOOKEOF
|
|
48
|
+
{
|
|
49
|
+
"decision": "block",
|
|
50
|
+
"reason": "⚠️ AUTO-HANDOFF: O contexto atingiu ${THRESHOLD_PERCENT}% do limite. Você DEVE salvar o handoff AGORA.\n\nSiga estes passos IMEDIATAMENTE:\n1. Analise a conversa inteira e extraia: o que foi feito, próximos passos, arquivos-chave, decisões\n2. Escreva o handoff em .claude/handoffs/_active.md seguindo o template padrão\n3. Diga ao usuário: 'Handoff salvo automaticamente. Use /clear e depois /resume para continuar.'\n\nNÃO continue com outro trabalho até o handoff estar salvo."
|
|
51
|
+
}
|
|
52
|
+
HOOKEOF
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Session Cleanup
|
|
3
|
+
# Limpa flag files de sessões anteriores (> 24h) para não acumular lixo no /tmp.
|
|
4
|
+
# Usado como hook "SessionStart" do Claude Code.
|
|
5
|
+
|
|
6
|
+
find /private/tmp -maxdepth 1 -name "claude_handoff_triggered_*" -mmin +1440 -delete 2>/dev/null
|
|
7
|
+
exit 0
|
package/install.sh
CHANGED
|
@@ -45,26 +45,155 @@ download_file() {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
# 1. Create directories
|
|
48
|
-
echo -e " ${YELLOW}[1/
|
|
48
|
+
echo -e " ${YELLOW}[1/10]${NC} Creating directories..."
|
|
49
49
|
mkdir -p "$CLAUDE_DIR/commands"
|
|
50
50
|
mkdir -p "$CLAUDE_DIR/rules"
|
|
51
|
+
mkdir -p "$CLAUDE_DIR/hooks"
|
|
51
52
|
mkdir -p "$CLAUDE_DIR/handoffs/archive"
|
|
52
53
|
|
|
53
54
|
# 2. Download/copy commands
|
|
54
|
-
echo -e " ${YELLOW}[2/
|
|
55
|
+
echo -e " ${YELLOW}[2/10]${NC} Installing commands..."
|
|
55
56
|
download_file "commands/resume.md" "$CLAUDE_DIR/commands/resume.md"
|
|
56
57
|
download_file "commands/save-handoff.md" "$CLAUDE_DIR/commands/save-handoff.md"
|
|
57
58
|
download_file "commands/switch-context.md" "$CLAUDE_DIR/commands/switch-context.md"
|
|
58
59
|
download_file "commands/handoff.md" "$CLAUDE_DIR/commands/handoff.md"
|
|
59
60
|
download_file "commands/delete-handoff.md" "$CLAUDE_DIR/commands/delete-handoff.md"
|
|
61
|
+
download_file "commands/auto-handoff.md" "$CLAUDE_DIR/commands/auto-handoff.md"
|
|
60
62
|
|
|
61
63
|
# 3. Download/copy rules
|
|
62
|
-
echo -e " ${YELLOW}[3/
|
|
64
|
+
echo -e " ${YELLOW}[3/10]${NC} Installing rules..."
|
|
63
65
|
download_file "rules/session-continuity.md" "$CLAUDE_DIR/rules/session-continuity.md"
|
|
66
|
+
download_file "rules/auto-handoff.md" "$CLAUDE_DIR/rules/auto-handoff.md"
|
|
64
67
|
|
|
65
|
-
# 4.
|
|
68
|
+
# 4. Install hooks (auto-handoff context monitor)
|
|
69
|
+
echo -e " ${YELLOW}[4/10]${NC} Installing hooks..."
|
|
70
|
+
download_file "hooks/context-monitor.sh" "$CLAUDE_DIR/hooks/context-monitor.sh"
|
|
71
|
+
download_file "hooks/session-cleanup.sh" "$CLAUDE_DIR/hooks/session-cleanup.sh"
|
|
72
|
+
chmod +x "$CLAUDE_DIR/hooks/context-monitor.sh"
|
|
73
|
+
chmod +x "$CLAUDE_DIR/hooks/session-cleanup.sh"
|
|
74
|
+
|
|
75
|
+
# 5. Configure hooks in settings.json
|
|
76
|
+
echo -e " ${YELLOW}[5/10]${NC} Configuring hooks in settings.json..."
|
|
77
|
+
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
|
78
|
+
if [ -f "$SETTINGS_FILE" ]; then
|
|
79
|
+
# Check if hooks already configured
|
|
80
|
+
if ! grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
|
|
81
|
+
# Merge hooks into existing settings.json using jq if available
|
|
82
|
+
if command -v jq &>/dev/null; then
|
|
83
|
+
HOOKS_JSON='{
|
|
84
|
+
"hooks": {
|
|
85
|
+
"Stop": [{"hooks": [{"type": "command", "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh\"", "timeout": 10}]}],
|
|
86
|
+
"SessionStart": [{"hooks": [{"type": "command", "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"", "timeout": 5}]}]
|
|
87
|
+
}
|
|
88
|
+
}'
|
|
89
|
+
jq --argjson hooks "$(echo "$HOOKS_JSON" | jq '.hooks')" '. + {hooks: $hooks}' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
|
|
90
|
+
else
|
|
91
|
+
# Fallback: rewrite settings.json preserving existing keys
|
|
92
|
+
echo -e " ${YELLOW} ⚠ jq not found. Adding hooks config manually...${NC}"
|
|
93
|
+
# Read existing content, strip trailing brace, append hooks
|
|
94
|
+
EXISTING=$(cat "$SETTINGS_FILE")
|
|
95
|
+
# Remove trailing } and whitespace
|
|
96
|
+
EXISTING=$(echo "$EXISTING" | sed '$ s/}$//')
|
|
97
|
+
cat > "$SETTINGS_FILE" << 'SETTINGSEOF'
|
|
98
|
+
{
|
|
99
|
+
"hooks": {
|
|
100
|
+
"Stop": [
|
|
101
|
+
{
|
|
102
|
+
"hooks": [
|
|
103
|
+
{
|
|
104
|
+
"type": "command",
|
|
105
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh\"",
|
|
106
|
+
"timeout": 10
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"SessionStart": [
|
|
112
|
+
{
|
|
113
|
+
"hooks": [
|
|
114
|
+
{
|
|
115
|
+
"type": "command",
|
|
116
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"",
|
|
117
|
+
"timeout": 5
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
SETTINGSEOF
|
|
125
|
+
# Merge with original using jq-less approach: just add hooks key
|
|
126
|
+
# Since we can't reliably merge JSON without jq, write a complete file
|
|
127
|
+
# preserving the language setting if it exists
|
|
128
|
+
LANG_SETTING=$(echo "$EXISTING" | grep '"language"' | head -1 | sed 's/,$//')
|
|
129
|
+
if [ -n "$LANG_SETTING" ]; then
|
|
130
|
+
cat > "$SETTINGS_FILE" << SETTINGSEOF
|
|
131
|
+
{
|
|
132
|
+
${LANG_SETTING},
|
|
133
|
+
"hooks": {
|
|
134
|
+
"Stop": [
|
|
135
|
+
{
|
|
136
|
+
"hooks": [
|
|
137
|
+
{
|
|
138
|
+
"type": "command",
|
|
139
|
+
"command": "\"\$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh\"",
|
|
140
|
+
"timeout": 10
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"SessionStart": [
|
|
146
|
+
{
|
|
147
|
+
"hooks": [
|
|
148
|
+
{
|
|
149
|
+
"type": "command",
|
|
150
|
+
"command": "\"\$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"",
|
|
151
|
+
"timeout": 5
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
SETTINGSEOF
|
|
159
|
+
fi
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
else
|
|
163
|
+
# Create new settings.json with hooks
|
|
164
|
+
cat > "$SETTINGS_FILE" << 'SETTINGSEOF'
|
|
165
|
+
{
|
|
166
|
+
"hooks": {
|
|
167
|
+
"Stop": [
|
|
168
|
+
{
|
|
169
|
+
"hooks": [
|
|
170
|
+
{
|
|
171
|
+
"type": "command",
|
|
172
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh\"",
|
|
173
|
+
"timeout": 10
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"SessionStart": [
|
|
179
|
+
{
|
|
180
|
+
"hooks": [
|
|
181
|
+
{
|
|
182
|
+
"type": "command",
|
|
183
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"",
|
|
184
|
+
"timeout": 5
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
SETTINGSEOF
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
# 6. Create initial _active.md if not exists
|
|
66
195
|
if [ ! -f "$CLAUDE_DIR/handoffs/_active.md" ]; then
|
|
67
|
-
echo -e " ${YELLOW}[
|
|
196
|
+
echo -e " ${YELLOW}[6/10]${NC} Creating initial handoff..."
|
|
68
197
|
cat > "$CLAUDE_DIR/handoffs/_active.md" << 'HANDOFF'
|
|
69
198
|
# Session Handoff
|
|
70
199
|
|
|
@@ -92,11 +221,11 @@ if [ ! -f "$CLAUDE_DIR/handoffs/_active.md" ]; then
|
|
|
92
221
|
(none)
|
|
93
222
|
HANDOFF
|
|
94
223
|
else
|
|
95
|
-
echo -e " ${YELLOW}[
|
|
224
|
+
echo -e " ${YELLOW}[6/10]${NC} Handoff already exists, keeping it"
|
|
96
225
|
fi
|
|
97
226
|
|
|
98
|
-
#
|
|
99
|
-
echo -e " ${YELLOW}[
|
|
227
|
+
# 7. Add to .gitignore
|
|
228
|
+
echo -e " ${YELLOW}[7/10]${NC} Updating .gitignore..."
|
|
100
229
|
GITIGNORE="$PROJECT_DIR/.gitignore"
|
|
101
230
|
if [ -f "$GITIGNORE" ]; then
|
|
102
231
|
if ! grep -q ".claude/handoffs/" "$GITIGNORE" 2>/dev/null; then
|
|
@@ -109,8 +238,8 @@ else
|
|
|
109
238
|
echo ".claude/handoffs/" >> "$GITIGNORE"
|
|
110
239
|
fi
|
|
111
240
|
|
|
112
|
-
#
|
|
113
|
-
echo -e " ${YELLOW}[
|
|
241
|
+
# 8. Add to CLAUDE.md
|
|
242
|
+
echo -e " ${YELLOW}[8/10]${NC} Updating CLAUDE.md..."
|
|
114
243
|
CLAUDE_MD="$CLAUDE_DIR/CLAUDE.md"
|
|
115
244
|
CONTINUITY_BLOCK='## Session Continuity (MANDATORY)
|
|
116
245
|
|
|
@@ -150,20 +279,23 @@ Use `/handoff` before `/clear`. Use `/resume` to pick up. Use `/switch-context <
|
|
|
150
279
|
CLAUDEMD
|
|
151
280
|
fi
|
|
152
281
|
|
|
153
|
-
#
|
|
154
|
-
echo -e " ${YELLOW}[
|
|
282
|
+
# 9. Summary
|
|
283
|
+
echo -e " ${YELLOW}[9/10]${NC} Verifying installation..."
|
|
155
284
|
INSTALLED=0
|
|
156
|
-
for f in resume.md save-handoff.md switch-context.md handoff.md delete-handoff.md; do
|
|
285
|
+
for f in resume.md save-handoff.md switch-context.md handoff.md delete-handoff.md auto-handoff.md; do
|
|
157
286
|
[ -f "$CLAUDE_DIR/commands/$f" ] && INSTALLED=$((INSTALLED + 1))
|
|
158
287
|
done
|
|
288
|
+
HOOKS_OK=0
|
|
289
|
+
[ -f "$CLAUDE_DIR/hooks/context-monitor.sh" ] && HOOKS_OK=$((HOOKS_OK + 1))
|
|
290
|
+
[ -f "$CLAUDE_DIR/hooks/session-cleanup.sh" ] && HOOKS_OK=$((HOOKS_OK + 1))
|
|
159
291
|
|
|
160
292
|
echo ""
|
|
161
|
-
echo -e " ${YELLOW}[
|
|
293
|
+
echo -e " ${YELLOW}[10/10]${NC} Done!"
|
|
162
294
|
echo ""
|
|
163
|
-
if [ "$INSTALLED" -eq
|
|
164
|
-
echo -e "${GREEN} Installed successfully! ($INSTALLED/
|
|
295
|
+
if [ "$INSTALLED" -eq 6 ] && [ "$HOOKS_OK" -eq 2 ]; then
|
|
296
|
+
echo -e "${GREEN} Installed successfully! ($INSTALLED/6 commands, $HOOKS_OK/2 hooks)${NC}"
|
|
165
297
|
else
|
|
166
|
-
echo -e "${YELLOW} Partial install: $INSTALLED/
|
|
298
|
+
echo -e "${YELLOW} Partial install: $INSTALLED/6 commands, $HOOKS_OK/2 hooks${NC}"
|
|
167
299
|
fi
|
|
168
300
|
echo ""
|
|
169
301
|
echo -e " Commands available:"
|
|
@@ -172,10 +304,16 @@ echo -e " ${CYAN}/resume${NC} Resume with wizard"
|
|
|
172
304
|
echo -e " ${CYAN}/save-handoff${NC} Save session state (wizard)"
|
|
173
305
|
echo -e " ${CYAN}/switch-context${NC} Switch workstream"
|
|
174
306
|
echo -e " ${CYAN}/delete-handoff${NC} Delete handoff(s)"
|
|
307
|
+
echo -e " ${CYAN}/auto-handoff${NC} Toggle auto-handoff on/off"
|
|
308
|
+
echo ""
|
|
309
|
+
echo -e " Auto-handoff:"
|
|
310
|
+
echo -e " Context monitor hook installed (triggers at 90% of context)"
|
|
311
|
+
echo -e " Use ${CYAN}/auto-handoff${NC} to enable/disable or adjust threshold"
|
|
175
312
|
echo ""
|
|
176
313
|
echo -e " Files:"
|
|
177
|
-
echo -e " .claude/commands/
|
|
178
|
-
echo -e " .claude/rules/ session-continuity.md"
|
|
314
|
+
echo -e " .claude/commands/ 6 command files"
|
|
315
|
+
echo -e " .claude/rules/ session-continuity.md, auto-handoff.md"
|
|
316
|
+
echo -e " .claude/hooks/ context-monitor.sh, session-cleanup.sh"
|
|
179
317
|
echo -e " .claude/handoffs/ session state (gitignored)"
|
|
180
318
|
echo ""
|
|
181
319
|
echo -e " ${YELLOW}Start Claude Code and use /resume to begin.${NC}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-handoff",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Session continuity for Claude Code — 5 slash commands to save, resume, delete, and switch workstreams across /clear",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-code-handoff": "./cli.js"
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"update.sh",
|
|
13
13
|
"commands/",
|
|
14
14
|
"rules/",
|
|
15
|
+
"hooks/",
|
|
15
16
|
"LICENSE",
|
|
16
17
|
"README.md"
|
|
17
18
|
],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Auto-Handoff Rule
|
|
2
|
+
|
|
3
|
+
When you receive a message containing "AUTO-HANDOFF" from a hook, you MUST:
|
|
4
|
+
|
|
5
|
+
1. IMMEDIATELY stop any current task
|
|
6
|
+
2. Analyze the full conversation and extract all relevant information
|
|
7
|
+
3. Write the handoff to `.claude/handoffs/_active.md` following the standard template
|
|
8
|
+
4. Tell the user the handoff was auto-saved and they should `/clear` then `/resume`
|
|
9
|
+
|
|
10
|
+
Do NOT:
|
|
11
|
+
- Continue with previous work
|
|
12
|
+
- Ask the user for permission first
|
|
13
|
+
- Skip any section of the handoff template
|
package/uninstall.sh
CHANGED
|
@@ -27,39 +27,61 @@ if [ ! -d "$CLAUDE_DIR" ]; then
|
|
|
27
27
|
fi
|
|
28
28
|
|
|
29
29
|
# 1. Remove commands
|
|
30
|
-
echo -e " ${YELLOW}[1/
|
|
30
|
+
echo -e " ${YELLOW}[1/6]${NC} Removing commands..."
|
|
31
31
|
rm -f "$CLAUDE_DIR/commands/handoff.md"
|
|
32
32
|
rm -f "$CLAUDE_DIR/commands/resume.md"
|
|
33
33
|
rm -f "$CLAUDE_DIR/commands/save-handoff.md"
|
|
34
34
|
rm -f "$CLAUDE_DIR/commands/switch-context.md"
|
|
35
35
|
rm -f "$CLAUDE_DIR/commands/delete-handoff.md"
|
|
36
|
+
rm -f "$CLAUDE_DIR/commands/auto-handoff.md"
|
|
37
|
+
# Also remove legacy commands if present
|
|
38
|
+
rm -f "$CLAUDE_DIR/commands/auto-handoff-toggle.md"
|
|
36
39
|
# Also remove legacy Portuguese commands if present
|
|
37
40
|
rm -f "$CLAUDE_DIR/commands/retomar.md"
|
|
38
41
|
rm -f "$CLAUDE_DIR/commands/salvar-handoff.md"
|
|
39
42
|
rm -f "$CLAUDE_DIR/commands/trocar-contexto.md"
|
|
40
43
|
|
|
41
44
|
# 2. Remove rules
|
|
42
|
-
echo -e " ${YELLOW}[2/
|
|
45
|
+
echo -e " ${YELLOW}[2/6]${NC} Removing rules..."
|
|
43
46
|
rm -f "$CLAUDE_DIR/rules/session-continuity.md"
|
|
47
|
+
rm -f "$CLAUDE_DIR/rules/auto-handoff.md"
|
|
44
48
|
|
|
45
|
-
# 3. Remove
|
|
49
|
+
# 3. Remove hooks
|
|
50
|
+
echo -e " ${YELLOW}[3/6]${NC} Removing hooks..."
|
|
51
|
+
rm -f "$CLAUDE_DIR/hooks/context-monitor.sh"
|
|
52
|
+
rm -f "$CLAUDE_DIR/hooks/session-cleanup.sh"
|
|
53
|
+
rm -f "$CLAUDE_DIR/hooks/.auto-handoff-disabled"
|
|
54
|
+
rmdir "$CLAUDE_DIR/hooks" 2>/dev/null || true
|
|
55
|
+
|
|
56
|
+
# 4. Clean hooks from settings.json
|
|
57
|
+
echo -e " ${YELLOW}[4/6]${NC} Cleaning settings.json..."
|
|
58
|
+
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
|
59
|
+
if [ -f "$SETTINGS_FILE" ] && grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
|
|
60
|
+
if command -v jq &>/dev/null; then
|
|
61
|
+
jq 'del(.hooks)' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
|
|
62
|
+
else
|
|
63
|
+
echo -e " ${YELLOW}⚠ jq not found — remove hooks from .claude/settings.json manually${NC}"
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# 5. Remove handoffs (with confirmation)
|
|
46
68
|
if [ -d "$CLAUDE_DIR/handoffs" ]; then
|
|
47
69
|
# Check if there's actual content
|
|
48
70
|
ACTIVE_CONTENT=$(cat "$CLAUDE_DIR/handoffs/_active.md" 2>/dev/null || echo "")
|
|
49
71
|
if echo "$ACTIVE_CONTENT" | grep -q "No active session yet\|not started"; then
|
|
50
|
-
echo -e " ${YELLOW}[
|
|
72
|
+
echo -e " ${YELLOW}[5/6]${NC} Removing handoffs (no session data)..."
|
|
51
73
|
rm -rf "$CLAUDE_DIR/handoffs"
|
|
52
74
|
else
|
|
53
|
-
echo -e " ${YELLOW}[
|
|
75
|
+
echo -e " ${YELLOW}[5/6]${NC} ${RED}Handoffs contain session data!${NC}"
|
|
54
76
|
echo -e " Kept: .claude/handoffs/"
|
|
55
77
|
echo -e " Remove manually with: rm -rf .claude/handoffs/"
|
|
56
78
|
fi
|
|
57
79
|
else
|
|
58
|
-
echo -e " ${YELLOW}[
|
|
80
|
+
echo -e " ${YELLOW}[5/6]${NC} No handoffs directory found"
|
|
59
81
|
fi
|
|
60
82
|
|
|
61
|
-
#
|
|
62
|
-
echo -e " ${YELLOW}[
|
|
83
|
+
# 6. Clean .gitignore
|
|
84
|
+
echo -e " ${YELLOW}[6/6]${NC} Cleaning .gitignore..."
|
|
63
85
|
GITIGNORE="$PROJECT_DIR/.gitignore"
|
|
64
86
|
if [ -f "$GITIGNORE" ]; then
|
|
65
87
|
# Remove the handoff lines
|
package/update.sh
CHANGED
|
@@ -45,20 +45,50 @@ download_file() {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
# 1. Update commands
|
|
48
|
-
echo -e " ${YELLOW}[1/
|
|
48
|
+
echo -e " ${YELLOW}[1/5]${NC} Updating commands..."
|
|
49
49
|
download_file "commands/handoff.md" "$CLAUDE_DIR/commands/handoff.md"
|
|
50
50
|
download_file "commands/resume.md" "$CLAUDE_DIR/commands/resume.md"
|
|
51
51
|
download_file "commands/save-handoff.md" "$CLAUDE_DIR/commands/save-handoff.md"
|
|
52
52
|
download_file "commands/switch-context.md" "$CLAUDE_DIR/commands/switch-context.md"
|
|
53
|
+
download_file "commands/delete-handoff.md" "$CLAUDE_DIR/commands/delete-handoff.md"
|
|
54
|
+
download_file "commands/auto-handoff.md" "$CLAUDE_DIR/commands/auto-handoff.md"
|
|
53
55
|
|
|
54
56
|
# 2. Update rules
|
|
55
|
-
echo -e " ${YELLOW}[2/
|
|
57
|
+
echo -e " ${YELLOW}[2/5]${NC} Updating rules..."
|
|
56
58
|
download_file "rules/session-continuity.md" "$CLAUDE_DIR/rules/session-continuity.md"
|
|
59
|
+
download_file "rules/auto-handoff.md" "$CLAUDE_DIR/rules/auto-handoff.md"
|
|
57
60
|
|
|
58
|
-
# 3.
|
|
59
|
-
echo -e " ${YELLOW}[3/
|
|
61
|
+
# 3. Update hooks
|
|
62
|
+
echo -e " ${YELLOW}[3/5]${NC} Updating hooks..."
|
|
63
|
+
mkdir -p "$CLAUDE_DIR/hooks"
|
|
64
|
+
download_file "hooks/context-monitor.sh" "$CLAUDE_DIR/hooks/context-monitor.sh"
|
|
65
|
+
download_file "hooks/session-cleanup.sh" "$CLAUDE_DIR/hooks/session-cleanup.sh"
|
|
66
|
+
chmod +x "$CLAUDE_DIR/hooks/context-monitor.sh"
|
|
67
|
+
chmod +x "$CLAUDE_DIR/hooks/session-cleanup.sh"
|
|
68
|
+
|
|
69
|
+
# 4. Ensure hooks are configured in settings.json
|
|
70
|
+
echo -e " ${YELLOW}[4/5]${NC} Checking settings.json hooks..."
|
|
71
|
+
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
|
72
|
+
if [ -f "$SETTINGS_FILE" ]; then
|
|
73
|
+
if ! grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
|
|
74
|
+
if command -v jq &>/dev/null; then
|
|
75
|
+
HOOKS_JSON='{"Stop":[{"hooks":[{"type":"command","command":"\"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh\"","timeout":10}]}],"SessionStart":[{"hooks":[{"type":"command","command":"\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"","timeout":5}]}]}'
|
|
76
|
+
jq --argjson hooks "$HOOKS_JSON" '. + {hooks: $hooks}' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
|
|
77
|
+
echo -e " Hooks added to settings.json"
|
|
78
|
+
else
|
|
79
|
+
echo -e " ${YELLOW}⚠ jq not found — add hooks to .claude/settings.json manually${NC}"
|
|
80
|
+
fi
|
|
81
|
+
else
|
|
82
|
+
echo -e " Hooks already configured"
|
|
83
|
+
fi
|
|
84
|
+
else
|
|
85
|
+
echo -e " ${YELLOW}⚠ settings.json not found — run install first${NC}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# 5. Remove legacy files if present
|
|
89
|
+
echo -e " ${YELLOW}[5/5]${NC} Cleaning up legacy files..."
|
|
60
90
|
CLEANED=0
|
|
61
|
-
for f in retomar.md salvar-handoff.md trocar-contexto.md; do
|
|
91
|
+
for f in retomar.md salvar-handoff.md trocar-contexto.md auto-handoff-toggle.md; do
|
|
62
92
|
if [ -f "$CLAUDE_DIR/commands/$f" ]; then
|
|
63
93
|
rm -f "$CLAUDE_DIR/commands/$f"
|
|
64
94
|
CLEANED=$((CLEANED + 1))
|