claude-code-handoff 1.3.2 → 1.5.0
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 +63 -17
- 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
|
@@ -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
|
+
**New in v1.4:** Auto-handoff monitors your context usage and **automatically triggers a handoff** when the transcript reaches 90% capacity — so you never forget to save.
|
|
53
|
+
|
|
51
54
|
Session state is stored in `.claude/handoffs/` (gitignored) — each developer keeps their own context, no conflicts.
|
|
52
55
|
|
|
53
56
|
---
|
|
@@ -152,13 +155,49 @@ graph TD
|
|
|
152
155
|
|
|
153
156
|
---
|
|
154
157
|
|
|
158
|
+
## Auto-Handoff (Context Monitor)
|
|
159
|
+
|
|
160
|
+
The biggest risk with handoffs is **forgetting to save**. Auto-handoff eliminates this by monitoring your transcript size and forcing a save when context is running low.
|
|
161
|
+
|
|
162
|
+
### How It Works
|
|
163
|
+
|
|
164
|
+
```mermaid
|
|
165
|
+
flowchart TD
|
|
166
|
+
A[Claude responds] --> B[Stop hook fires]
|
|
167
|
+
B --> C{Transcript > 90%?}
|
|
168
|
+
C -->|No| D[Continue normally]
|
|
169
|
+
C -->|Yes| E{Already triggered?}
|
|
170
|
+
E -->|Yes| D
|
|
171
|
+
E -->|No| F[Create flag file]
|
|
172
|
+
F --> G["Block: force handoff save"]
|
|
173
|
+
G --> H[Claude saves _active.md]
|
|
174
|
+
H --> I["User: /clear → /resume"]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- **Detection**: Measures transcript file size (default 90% of ~500KB max context)
|
|
178
|
+
- **One-shot**: Uses a flag file in `/tmp` to prevent infinite loops — triggers only once per session
|
|
179
|
+
- **Configurable**: Adjust threshold % via `CLAUDE_CONTEXT_THRESHOLD` env var or `/auto-handoff`
|
|
180
|
+
- **Disableable**: Run `/auto-handoff` to turn it off
|
|
181
|
+
|
|
182
|
+
### Configuration
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Change threshold (default: 90% of context)
|
|
186
|
+
export CLAUDE_CONTEXT_THRESHOLD=80 # trigger at 80% instead
|
|
187
|
+
|
|
188
|
+
# Or use the interactive toggle
|
|
189
|
+
/auto-handoff
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
155
194
|
## Install
|
|
156
195
|
|
|
157
196
|
### Option A: npx (recommended)
|
|
158
197
|
|
|
159
198
|
```bash
|
|
160
199
|
cd your-project
|
|
161
|
-
npx claude-code-handoff@
|
|
200
|
+
npx claude-code-handoff@latest
|
|
162
201
|
```
|
|
163
202
|
|
|
164
203
|
### Option B: curl
|
|
@@ -182,22 +221,29 @@ cd your-project
|
|
|
182
221
|
your-project/
|
|
183
222
|
└── .claude/
|
|
184
223
|
├── commands/
|
|
185
|
-
│ ├── handoff.md
|
|
186
|
-
│ ├── resume.md
|
|
187
|
-
│ ├── save-handoff.md
|
|
188
|
-
│ ├── switch-context.md
|
|
189
|
-
│
|
|
224
|
+
│ ├── handoff.md ← /handoff (auto-save)
|
|
225
|
+
│ ├── resume.md ← /resume (interactive picker)
|
|
226
|
+
│ ├── save-handoff.md ← /save-handoff (wizard)
|
|
227
|
+
│ ├── switch-context.md ← /switch-context (workstream switch)
|
|
228
|
+
│ ├── delete-handoff.md ← /delete-handoff (remove handoffs)
|
|
229
|
+
│ └── auto-handoff.md ← /auto-handoff (on/off)
|
|
190
230
|
├── rules/
|
|
191
|
-
│
|
|
192
|
-
└──
|
|
193
|
-
|
|
194
|
-
|
|
231
|
+
│ ├── session-continuity.md ← Auto-loaded behavioral rules
|
|
232
|
+
│ └── auto-handoff.md ← Auto-handoff trigger rules
|
|
233
|
+
├── hooks/
|
|
234
|
+
│ ├── context-monitor.sh ← Stop hook (monitors context size)
|
|
235
|
+
│ └── session-cleanup.sh ← SessionStart hook (cleans old flags)
|
|
236
|
+
├── settings.json ← Hook configuration
|
|
237
|
+
└── handoffs/ ← Session state (gitignored)
|
|
238
|
+
├── _active.md ← Current workstream
|
|
239
|
+
└── archive/ ← Paused workstreams
|
|
195
240
|
```
|
|
196
241
|
|
|
197
242
|
The installer also:
|
|
198
243
|
- Creates the full `.claude/handoffs/archive/` directory structure
|
|
199
244
|
- Adds `.claude/handoffs/` to `.gitignore`
|
|
200
245
|
- Adds a `Session Continuity` section to `.claude/CLAUDE.md` (creates one if missing)
|
|
246
|
+
- Configures auto-handoff hooks in `.claude/settings.json`
|
|
201
247
|
|
|
202
248
|
---
|
|
203
249
|
|
|
@@ -338,12 +384,12 @@ graph TD
|
|
|
338
384
|
style SW fill:#7c2d12,stroke:#fb923c,color:#fff
|
|
339
385
|
```
|
|
340
386
|
|
|
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 |
|
|
387
|
+
| | `/handoff` | `/save-handoff` | `/resume` | `/switch-context` | `/auto-handoff` |
|
|
388
|
+
|---|---|---|---|---|---|
|
|
389
|
+
| **When** | Before `/clear` | When you need options | Start of session | Mid-session | Anytime |
|
|
390
|
+
| **Interactive** | No | Yes (wizard) | Yes (picker) | No (with arg) | Yes (wizard) |
|
|
391
|
+
| **Creates files** | Auto | User chooses | No | Auto | Toggle file |
|
|
392
|
+
| **Reads files** | `_active.md` | `_active.md` + `archive/` | All handoffs | `_active.md` + target | Hook config |
|
|
347
393
|
|
|
348
394
|
---
|
|
349
395
|
|
|
@@ -418,7 +464,7 @@ rm -rf .claude/handoffs/ # ⚠️ deletes all session history
|
|
|
418
464
|
A: Yes. Handoff files are gitignored, so each developer has their own session state. No conflicts.
|
|
419
465
|
|
|
420
466
|
**Q: What happens if I forget to `/handoff` before `/clear`?**
|
|
421
|
-
A:
|
|
467
|
+
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
468
|
|
|
423
469
|
**Q: Can I have unlimited workstreams?**
|
|
424
470
|
A: Yes. The `archive/` folder has no limit. Each workstream is a single `.md` file.
|
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.0",
|
|
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))
|