aiwcli 0.12.2 → 0.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +8 -60
- package/dist/templates/_shared/.claude/commands/handoff.md +6 -226
- package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +1 -1
- package/dist/templates/_shared/handoff-system/CLAUDE.md +421 -0
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/document-generator.ts +10 -11
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/handoff-reader.ts +5 -6
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/resume_handoff.ts +19 -16
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/save_handoff.ts +153 -43
- package/dist/templates/_shared/handoff-system/workflows/handoff-resume.md +66 -0
- package/dist/templates/_shared/{workflows → handoff-system/workflows}/handoff.md +31 -9
- package/dist/templates/_shared/hooks-ts/session_end.ts +66 -48
- package/dist/templates/_shared/hooks-ts/session_start.ts +62 -47
- package/dist/templates/_shared/lib-ts/base/inference.ts +73 -24
- package/dist/templates/_shared/lib-ts/base/state-io.ts +88 -11
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +56 -0
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +8 -2
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +79 -70
- package/dist/templates/_shared/lib-ts/context/context-store.ts +90 -85
- package/dist/templates/_shared/lib-ts/types.ts +71 -64
- package/dist/templates/_shared/scripts/resolve_context.ts +14 -5
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/ask.md +136 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/index.md +21 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/overview.md +56 -0
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +4 -4
- package/dist/templates/cc-native/_cc-native/{plan-review.config.json → cc-native.config.json} +12 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +3 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/review-pipeline.ts +26 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +1 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +1 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/CLAUDE.md +480 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +287 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +148 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +54 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +58 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +208 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +460 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +446 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +280 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +274 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +201 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +278 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +2 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# Handoff System
|
|
2
|
+
|
|
3
|
+
Comprehensive specification for the handoff workflow system.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
- **Purpose:** Capture session state for asynchronous handoff to next session
|
|
8
|
+
- **Philosophy:** Structured sections (dead-ends, pending, decisions, etc.) + executable restoration
|
|
9
|
+
- **When to use:** End of work session when context needs preservation
|
|
10
|
+
- **Runtime location:** `_output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/`
|
|
11
|
+
|
|
12
|
+
## Directory Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
handoff-system/
|
|
16
|
+
├── CLAUDE.md # This file — comprehensive spec
|
|
17
|
+
├── lib/ # Reusable modules
|
|
18
|
+
│ ├── handoff-reader.ts # Read and parse handoff sections
|
|
19
|
+
│ └── document-generator.ts # Generate handoff markdown (not currently imported)
|
|
20
|
+
├── scripts/ # CLI entry points
|
|
21
|
+
│ ├── save_handoff.ts # Create handoff from stdin markdown
|
|
22
|
+
│ └── resume_handoff.ts # Load handoff and format for restoration
|
|
23
|
+
└── workflows/ # Procedural documentation
|
|
24
|
+
├── handoff.md # Creation workflow
|
|
25
|
+
└── handoff-resume.md # Restoration workflow
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Data Model & Schema
|
|
29
|
+
|
|
30
|
+
### Handoff Folder Structure
|
|
31
|
+
|
|
32
|
+
Runtime location: `_output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/`
|
|
33
|
+
|
|
34
|
+
**Files created:**
|
|
35
|
+
- `index.md` — Entry point with frontmatter
|
|
36
|
+
- `completed-work.md` — What was accomplished
|
|
37
|
+
- `dead-ends.md` — Failed approaches to avoid
|
|
38
|
+
- `decisions.md` — Key decisions made
|
|
39
|
+
- `pending.md` — Incomplete work items
|
|
40
|
+
- `context.md` — Background context
|
|
41
|
+
- `plan.md` — Optional, copied from context if plan exists
|
|
42
|
+
|
|
43
|
+
### HandoffSections Interface
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// From _shared/lib-ts/types.ts
|
|
47
|
+
interface HandoffSections {
|
|
48
|
+
index: string; // Entry point with frontmatter
|
|
49
|
+
deadEnds: string | null; // Failed approaches to avoid
|
|
50
|
+
pending: string | null; // Incomplete work items
|
|
51
|
+
plan: string | null; // Copy of plan file if exists
|
|
52
|
+
decisions: string | null; // Key decisions made
|
|
53
|
+
completedWork: string | null; // What was accomplished
|
|
54
|
+
context: string | null; // Background context
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Why inline interfaces:** Makes CLAUDE.md self-contained — agents don't jump between files.
|
|
59
|
+
|
|
60
|
+
### Section Markers
|
|
61
|
+
|
|
62
|
+
Content parsed via HTML comments: `<!-- SECTION: name -->`
|
|
63
|
+
|
|
64
|
+
**Valid section names:**
|
|
65
|
+
- `CONTEXT`
|
|
66
|
+
- `COMPLETED_WORK`
|
|
67
|
+
- `DEAD_ENDS`
|
|
68
|
+
- `DECISIONS`
|
|
69
|
+
- `PENDING`
|
|
70
|
+
- `PLAN`
|
|
71
|
+
|
|
72
|
+
**Critical:** Markers must be HTML comments, not markdown headings. Parser searches for `<!-- SECTION: -->` format.
|
|
73
|
+
|
|
74
|
+
### Frontmatter Schema
|
|
75
|
+
|
|
76
|
+
YAML frontmatter in index.md:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
---
|
|
80
|
+
title: Handoff - {project_name}
|
|
81
|
+
date: {ISO timestamp}
|
|
82
|
+
session_id: {Claude session ID}
|
|
83
|
+
project: {context directory name}
|
|
84
|
+
plan_document: {path to plan file if exists}
|
|
85
|
+
---
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Lifecycle & Hook Integration
|
|
89
|
+
|
|
90
|
+
### Creation Flow (save_handoff.ts script)
|
|
91
|
+
|
|
92
|
+
**Trigger:** `/handoff` command invokes script with stdin markdown
|
|
93
|
+
|
|
94
|
+
**Process:**
|
|
95
|
+
1. Parse frontmatter and section markers from stdin
|
|
96
|
+
2. Resolve context ID (5-tier resolution: `--context-id`, `--session-id`, frontmatter, `CLAUDE_SESSION_ID`, fallback to active)
|
|
97
|
+
3. Create timestamped folder: `_output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/`
|
|
98
|
+
4. Shard content into section files
|
|
99
|
+
5. Update state.json with handoff metadata
|
|
100
|
+
|
|
101
|
+
**State updates:**
|
|
102
|
+
- `handoff_path`: Set to `handoffs/{timestamp}/index.md` (relative to context folder)
|
|
103
|
+
- `work_consumed`: Set to `false` (enables staging)
|
|
104
|
+
- `next_artifact_type`: Set to `"handoff"` (explicit artifact tracking)
|
|
105
|
+
- **Latest-wins replacement:** If `plan_hash` exists, clear plan fields (`plan_path`, `plan_hash`, `plan_signature`)
|
|
106
|
+
|
|
107
|
+
**Context resolution tiers** (first match wins):
|
|
108
|
+
1. `--context-id` CLI arg
|
|
109
|
+
2. `--session-id` CLI arg (lookup via CLAUDE_SESSION_ID → context)
|
|
110
|
+
3. `session_id` in frontmatter (lookup via session → context)
|
|
111
|
+
4. `CLAUDE_SESSION_ID` env var (lookup via session → context)
|
|
112
|
+
5. Fallback: most recent active context
|
|
113
|
+
|
|
114
|
+
### Staging (session_end.ts hook)
|
|
115
|
+
|
|
116
|
+
**Trigger:** SessionEnd event
|
|
117
|
+
|
|
118
|
+
**Condition for staging:**
|
|
119
|
+
```typescript
|
|
120
|
+
if (state.handoff_path && !state.work_consumed) {
|
|
121
|
+
state.mode = "has_staged_work";
|
|
122
|
+
state.next_artifact_type = "handoff";
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Latest-wins detection:**
|
|
127
|
+
If `plan_hash` differs from `plan_hash_consumed`, new plan detected:
|
|
128
|
+
- Clear `handoff_path` (plan wins)
|
|
129
|
+
- Set `work_consumed = false`
|
|
130
|
+
- Set `next_artifact_type = "plan"`
|
|
131
|
+
|
|
132
|
+
**Unified staging mode:** `has_staged_work` replaces old `has_plan` and `has_handoff` modes (v0.13.0+).
|
|
133
|
+
|
|
134
|
+
### Restoration (session_start.ts hook)
|
|
135
|
+
|
|
136
|
+
**Trigger:** SessionStart event with `source = "clear"`
|
|
137
|
+
|
|
138
|
+
**Process:**
|
|
139
|
+
1. Find context with `mode = "has_staged_work"`
|
|
140
|
+
2. Dispatch by `next_artifact_type`:
|
|
141
|
+
- If `"handoff"`: call `formatHandoffContinuation(ctx)`
|
|
142
|
+
- If `"plan"`: inject plan content
|
|
143
|
+
3. Bind session to context
|
|
144
|
+
4. Transition `has_staged_work` → `active`
|
|
145
|
+
5. Set `work_consumed = true` (one-shot latch prevents re-staging)
|
|
146
|
+
|
|
147
|
+
**formatHandoffContinuation()** (from context-formatter.ts):
|
|
148
|
+
- Reads handoff sections via `readHandoffSections()`
|
|
149
|
+
- Assembles restoration context: dead-ends → pending → plan remaining → decisions → git delta → completed work
|
|
150
|
+
- Injects as system-reminder for Claude
|
|
151
|
+
|
|
152
|
+
### Fallback Matching (user_prompt_submit.ts hook)
|
|
153
|
+
|
|
154
|
+
**Trigger:** UserPromptSubmit when no staged work mode detected
|
|
155
|
+
|
|
156
|
+
**Process in determineContext():**
|
|
157
|
+
1. Filter contexts by `has_staged_work` mode
|
|
158
|
+
2. Separate by `determineArtifactType()`:
|
|
159
|
+
- Plan artifacts: check `plan_hash` and `plan_path`
|
|
160
|
+
- Handoff artifacts: check `handoff_path`
|
|
161
|
+
3. Try plan match first (content-based via plan hash)
|
|
162
|
+
4. Fall back to handoff match (first-match by recency)
|
|
163
|
+
5. Set `work_consumed = true` if match found
|
|
164
|
+
|
|
165
|
+
**determineArtifactType() utility:**
|
|
166
|
+
- Checks `next_artifact_type` field first (authoritative)
|
|
167
|
+
- Fallback: field detection (`plan_hash` + `plan_path` vs `handoff_path`)
|
|
168
|
+
- Logs warning if both plan and handoff fields exist (bug - violates latest-wins)
|
|
169
|
+
|
|
170
|
+
## Scripts
|
|
171
|
+
|
|
172
|
+
### save_handoff.ts
|
|
173
|
+
|
|
174
|
+
**Usage:**
|
|
175
|
+
```bash
|
|
176
|
+
bun .aiwcli/_shared/handoff-system/scripts/save_handoff.ts [--context-id ID] [--session-id SID] < handoff.md
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Stdin format:**
|
|
180
|
+
```markdown
|
|
181
|
+
---
|
|
182
|
+
title: Handoff - Project Name
|
|
183
|
+
session_id: abc123
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
# Handoff Document
|
|
187
|
+
|
|
188
|
+
<!-- SECTION: CONTEXT -->
|
|
189
|
+
Context details here...
|
|
190
|
+
|
|
191
|
+
<!-- SECTION: PENDING -->
|
|
192
|
+
Pending items...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Output:**
|
|
196
|
+
- Creates folder: `_output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/`
|
|
197
|
+
- Shards to files: `index.md`, `pending.md`, `dead-ends.md`, etc.
|
|
198
|
+
- Updates `state.json`: `handoff_path`, `work_consumed=false`, `next_artifact_type="handoff"`
|
|
199
|
+
|
|
200
|
+
**Collision handling:**
|
|
201
|
+
If timestamp folder exists, appends `-2`, `-3`, etc.
|
|
202
|
+
|
|
203
|
+
**State updates (latest-wins):**
|
|
204
|
+
- Sets handoff fields
|
|
205
|
+
- **Clears plan fields if they exist** (`plan_path`, `plan_hash`, `plan_signature` → null)
|
|
206
|
+
|
|
207
|
+
### resume_handoff.ts
|
|
208
|
+
|
|
209
|
+
**Usage:**
|
|
210
|
+
```bash
|
|
211
|
+
# Auto-discover from current session
|
|
212
|
+
bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts
|
|
213
|
+
|
|
214
|
+
# Explicit handoff path
|
|
215
|
+
bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts path/to/handoff/index.md
|
|
216
|
+
|
|
217
|
+
# Explicit context
|
|
218
|
+
bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts --context context-id
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Output format (to stdout):**
|
|
222
|
+
```markdown
|
|
223
|
+
# Handoff Restoration
|
|
224
|
+
|
|
225
|
+
## Dead Ends (Priority: Address First)
|
|
226
|
+
...
|
|
227
|
+
|
|
228
|
+
## Pending Items
|
|
229
|
+
...
|
|
230
|
+
|
|
231
|
+
## Plan Status
|
|
232
|
+
42% complete (5/12 tasks)
|
|
233
|
+
|
|
234
|
+
## Decisions Made
|
|
235
|
+
...
|
|
236
|
+
|
|
237
|
+
## Git Delta
|
|
238
|
+
Changed files since handoff...
|
|
239
|
+
|
|
240
|
+
## Completed Work
|
|
241
|
+
...
|
|
242
|
+
|
|
243
|
+
## Full Plan (Appendix)
|
|
244
|
+
...
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Features:**
|
|
248
|
+
- **Staleness warnings:** If handoff > 7 days old, warns in output
|
|
249
|
+
- **Plan progress:** Calculates % complete from plan anchors
|
|
250
|
+
- **Git delta:** Compares current git state to plan's git anchors
|
|
251
|
+
- **Priority ordering:** Dead-ends first, then pending, then context
|
|
252
|
+
|
|
253
|
+
**Auto-discovery:**
|
|
254
|
+
Uses `CLAUDE_SESSION_ID` env var → lookup context → find latest handoff in `handoffs/` folder.
|
|
255
|
+
|
|
256
|
+
## Library Modules
|
|
257
|
+
|
|
258
|
+
### handoff-reader.ts
|
|
259
|
+
|
|
260
|
+
**Location:** `_shared/handoff-system/lib/handoff-reader.ts`
|
|
261
|
+
|
|
262
|
+
**Exports:**
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// Find most recent handoff in context
|
|
266
|
+
function findLatestHandoff(contextPath: string): string | null
|
|
267
|
+
|
|
268
|
+
// Read and parse handoff sections
|
|
269
|
+
function readHandoffSections(handoffPath: string): HandoffSections
|
|
270
|
+
|
|
271
|
+
// Extract timestamp from handoff path
|
|
272
|
+
function getHandoffTimestamp(handoffPath: string): Date | null
|
|
273
|
+
|
|
274
|
+
// Get plan reference from handoff frontmatter
|
|
275
|
+
function getHandoffPlanReference(handoffPath: string): string | null
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Section mapping:**
|
|
279
|
+
```typescript
|
|
280
|
+
const SECTION_FILES = {
|
|
281
|
+
index: "index.md",
|
|
282
|
+
deadEnds: "dead-ends.md",
|
|
283
|
+
pending: "pending.md",
|
|
284
|
+
plan: "plan.md",
|
|
285
|
+
decisions: "decisions.md",
|
|
286
|
+
completedWork: "completed-work.md",
|
|
287
|
+
context: "context.md",
|
|
288
|
+
};
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Returns null for missing optional sections** (dead-ends, pending, etc.).
|
|
292
|
+
|
|
293
|
+
### document-generator.ts
|
|
294
|
+
|
|
295
|
+
**Location:** `_shared/handoff-system/lib/document-generator.ts`
|
|
296
|
+
|
|
297
|
+
**Exports:**
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Generate complete handoff markdown with sections
|
|
301
|
+
function generateHandoffDocument(options: HandoffOptions): string
|
|
302
|
+
|
|
303
|
+
// Section builders
|
|
304
|
+
function buildContextSection(ctx: ContextState): string
|
|
305
|
+
function buildCompletedWorkSection(history: WorkHistory): string
|
|
306
|
+
function buildDeadEndsSection(deadEnds: DeadEnd[]): string
|
|
307
|
+
// ... (other section builders)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Used by:** `/handoff` workflow to programmatically generate handoff content before piping to `save_handoff.ts`.
|
|
311
|
+
|
|
312
|
+
**Note:** Currently not imported by any files. Moved here for logical grouping and completeness.
|
|
313
|
+
|
|
314
|
+
## Command Integration
|
|
315
|
+
|
|
316
|
+
**Thin pointer pattern:**
|
|
317
|
+
|
|
318
|
+
`.claude/commands/handoff.md` (user-facing, discoverable via `/`)
|
|
319
|
+
→ References `.aiwcli/_shared/handoff-system/workflows/handoff.md` (detailed procedural steps)
|
|
320
|
+
|
|
321
|
+
**Benefits:**
|
|
322
|
+
- Command files stay concise (easy to scan in `/` menu)
|
|
323
|
+
- Workflow files can expand without bloating command discovery
|
|
324
|
+
- Single source of truth for procedural details
|
|
325
|
+
|
|
326
|
+
**Example reference format:**
|
|
327
|
+
```markdown
|
|
328
|
+
See `.aiwcli/_shared/handoff-system/workflows/handoff.md` for complete process documentation.
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Testing
|
|
332
|
+
|
|
333
|
+
**Integration test:**
|
|
334
|
+
`_shared/lib-ts/__tests__/integration/handoff-lifecycle.test.ts`
|
|
335
|
+
|
|
336
|
+
**Coverage:**
|
|
337
|
+
- Creation: active + handoff → session_end → has_staged_work
|
|
338
|
+
- Restoration: /clear → session_start → active + work_consumed=true
|
|
339
|
+
- One-shot latch: subsequent session_end does NOT re-stage (work_consumed=true)
|
|
340
|
+
|
|
341
|
+
**Hook execution test:**
|
|
342
|
+
```bash
|
|
343
|
+
echo '{"hook_event_name":"SessionStart","session_id":"test","source":"clear"}' | \
|
|
344
|
+
bun .aiwcli/_shared/hooks-ts/session_start.ts
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Expected: No import errors, clean execution.
|
|
348
|
+
|
|
349
|
+
## Migration Notes (v0.13.0+)
|
|
350
|
+
|
|
351
|
+
**Unified lifecycle:**
|
|
352
|
+
- Old modes `has_plan` and `has_handoff` → unified `has_staged_work`
|
|
353
|
+
- Old flags `plan_consumed` and `handoff_consumed` → unified `work_consumed`
|
|
354
|
+
- New field `next_artifact_type` (`"plan" | "handoff" | null`) for explicit artifact tracking
|
|
355
|
+
|
|
356
|
+
**Migration handled by migrateConsumedFlags()** in `state-io.ts`:
|
|
357
|
+
- Runs on every `state.json` read
|
|
358
|
+
- Transparently converts old modes to new structure
|
|
359
|
+
- Idempotent (safe to run multiple times)
|
|
360
|
+
|
|
361
|
+
**Latest-wins principle:**
|
|
362
|
+
- Only ONE artifact staged at a time
|
|
363
|
+
- New handoff clears plan fields
|
|
364
|
+
- New plan clears handoff_path
|
|
365
|
+
- Most recent creation wins
|
|
366
|
+
|
|
367
|
+
**Work consumed as one-shot latch:**
|
|
368
|
+
- Set to `true` when `has_staged_work` → `active` transition occurs
|
|
369
|
+
- Prevents `session_end` from re-staging same artifact
|
|
370
|
+
- Reset to `false` when new artifact created
|
|
371
|
+
|
|
372
|
+
## Architecture Decisions
|
|
373
|
+
|
|
374
|
+
**Why folder sharding (not single file)?**
|
|
375
|
+
- Enables selective loading (resume script loads only needed sections)
|
|
376
|
+
- Allows future extensions (e.g., attachments, screenshots)
|
|
377
|
+
- Chronological discovery via timestamp folders
|
|
378
|
+
|
|
379
|
+
**Why section markers (not frontmatter)?**
|
|
380
|
+
- Flexible content generation (Claude outputs sections in natural flow)
|
|
381
|
+
- No strict ordering required (script extracts by marker)
|
|
382
|
+
- Easy to extend (add new sections without schema version bump)
|
|
383
|
+
|
|
384
|
+
**Why latest-wins (not dual artifact tracking)?**
|
|
385
|
+
- Simplifies state machine (one artifact, one mode transition)
|
|
386
|
+
- Prevents ambiguity (which artifact to restore?)
|
|
387
|
+
- Matches user mental model (most recent work is relevant)
|
|
388
|
+
|
|
389
|
+
**Why unified work_consumed flag?**
|
|
390
|
+
- Prevents infinite re-staging loop
|
|
391
|
+
- Simpler than per-artifact flags (plan_consumed, handoff_consumed)
|
|
392
|
+
- One-shot latch pattern is well-understood
|
|
393
|
+
|
|
394
|
+
## Gotchas
|
|
395
|
+
|
|
396
|
+
**Template sync is mandatory:**
|
|
397
|
+
Both `.aiwcli/_shared/handoff-system/` (working copy) and `packages/cli/src/templates/_shared/handoff-system/` (template source) must stay in sync per CLAUDE.md template sync rules.
|
|
398
|
+
|
|
399
|
+
**Import paths after move:**
|
|
400
|
+
- From `scripts/resume_handoff.ts` → `lib/handoff-reader.ts`: `../lib/handoff-reader.js`
|
|
401
|
+
- From `lib/handoff-reader.ts` → `lib-ts/base/constants.ts`: `../../lib-ts/base/constants.js`
|
|
402
|
+
|
|
403
|
+
**Hooks don't import handoff-reader:**
|
|
404
|
+
- `session_start.ts` uses `formatHandoffContinuation()` from `context-formatter.ts`
|
|
405
|
+
- `context-formatter.ts` reads `ctx.handoff_path` directly
|
|
406
|
+
- No direct handoff-reader dependency in hooks
|
|
407
|
+
|
|
408
|
+
**Command file script paths are absolute:**
|
|
409
|
+
- Reference from project root: `.aiwcli/_shared/handoff-system/scripts/save_handoff.ts`
|
|
410
|
+
- NOT relative to command file location
|
|
411
|
+
|
|
412
|
+
**Section markers must be HTML comments:**
|
|
413
|
+
```markdown
|
|
414
|
+
<!-- SECTION: PENDING --> ✅ Correct
|
|
415
|
+
# SECTION: PENDING ❌ Incorrect (parsed as heading, not marker)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Windsurf and Codex workflows also reference scripts:**
|
|
419
|
+
When updating script paths, check:
|
|
420
|
+
- `packages/cli/src/templates/_shared/.windsurf/workflows/handoff.md`
|
|
421
|
+
- `packages/cli/src/templates/_shared/.codex/workflows/handoff.md`
|
|
@@ -6,18 +6,17 @@
|
|
|
6
6
|
* work to a new session (typically due to context window limits).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import * as crypto from "node:crypto";
|
|
10
9
|
import * as fs from "node:fs";
|
|
11
10
|
import * as path from "node:path";
|
|
12
|
-
|
|
11
|
+
import * as crypto from "node:crypto";
|
|
12
|
+
import { getContextHandoffsDir, getContextDir } from "../base/constants.js";
|
|
13
13
|
import { atomicWrite } from "../base/atomic-write.js";
|
|
14
|
-
import {
|
|
15
|
-
import { logError, logInfo } from "../base/logger.js";
|
|
14
|
+
import { logInfo, logError } from "../base/logger.js";
|
|
16
15
|
import { nowIso } from "../base/utils.js";
|
|
17
|
-
import { getContext, saveState
|
|
16
|
+
import { getContext, saveState } from "../context/context-store.js";
|
|
18
17
|
import { getTasks } from "../context/task-tracker.js";
|
|
19
|
-
import { formatContinuationHeader, formatReason
|
|
20
|
-
import type { HandoffDocument, Task
|
|
18
|
+
import { renderTaskList, formatContinuationHeader, formatReason } from "../templates/formatters.js";
|
|
19
|
+
import type { HandoffDocument, Task } from "../types.js";
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* Generate and save a handoff document for a context.
|
|
@@ -125,7 +124,8 @@ function renderHandoffMarkdown(doc: HandoffDocument): string {
|
|
|
125
124
|
);
|
|
126
125
|
|
|
127
126
|
// Active tasks
|
|
128
|
-
lines.push(renderTaskList(doc.active_tasks, "Active Tasks", true).trimEnd()
|
|
127
|
+
lines.push(renderTaskList(doc.active_tasks, "Active Tasks", true).trimEnd());
|
|
128
|
+
lines.push("");
|
|
129
129
|
|
|
130
130
|
// Completed this session
|
|
131
131
|
if (doc.completed_tasks_this_session.length > 0) {
|
|
@@ -133,7 +133,8 @@ function renderHandoffMarkdown(doc: HandoffDocument): string {
|
|
|
133
133
|
doc.completed_tasks_this_session as any[],
|
|
134
134
|
"Completed This Session",
|
|
135
135
|
false,
|
|
136
|
-
).trimEnd()
|
|
136
|
+
).trimEnd());
|
|
137
|
+
lines.push("");
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
// Work summary
|
|
@@ -147,7 +148,6 @@ function renderHandoffMarkdown(doc: HandoffDocument): string {
|
|
|
147
148
|
for (let i = 0; i < doc.next_steps.length; i++) {
|
|
148
149
|
lines.push(`${i + 1}. ${doc.next_steps[i]}`);
|
|
149
150
|
}
|
|
150
|
-
|
|
151
151
|
lines.push("");
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -157,7 +157,6 @@ function renderHandoffMarkdown(doc: HandoffDocument): string {
|
|
|
157
157
|
for (const note of doc.important_notes) {
|
|
158
158
|
lines.push(`- ${note}`);
|
|
159
159
|
}
|
|
160
|
-
|
|
161
160
|
lines.push("");
|
|
162
161
|
}
|
|
163
162
|
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import * as fs from "node:fs";
|
|
10
|
-
import * as path from "node:path";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import type { HandoffSections } from "../types.js";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { getContextHandoffsDir } from "../../lib-ts/base/constants.js";
|
|
12
|
+
import { getContext } from "../../lib-ts/context/context-store.js";
|
|
13
|
+
import type { HandoffSections } from "../../lib-ts/types.js";
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Find the most recent handoff folder for a context.
|
|
@@ -30,7 +29,7 @@ export function findLatestHandoff(contextId: string, projectRoot?: string): stri
|
|
|
30
29
|
.sort();
|
|
31
30
|
|
|
32
31
|
if (entries.length === 0) return null;
|
|
33
|
-
return path.join(handoffsDir, entries.
|
|
32
|
+
return path.join(handoffsDir, entries[entries.length - 1]!);
|
|
34
33
|
} catch {
|
|
35
34
|
return null;
|
|
36
35
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* a structured briefing to stdout.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* bun .aiwcli/_shared/scripts/resume_handoff.ts <handoff_folder_or_index>
|
|
8
|
-
* bun .aiwcli/_shared/scripts/resume_handoff.ts --context <context_id>
|
|
7
|
+
* bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts <handoff_folder_or_index>
|
|
8
|
+
* bun .aiwcli/_shared/handoff-system/scripts/resume_handoff.ts --context <context_id>
|
|
9
9
|
*
|
|
10
10
|
* If no args, auto-discovers the active context and finds the latest handoff.
|
|
11
11
|
*
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
import * as fs from "node:fs";
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
|
|
18
|
-
import { getProjectRoot } from "../lib-ts/base/constants.js";
|
|
19
|
-
import { getGitStatusShort } from "../lib-ts/base/git-state.js";
|
|
20
|
-
import { eprint } from "../lib-ts/base/utils.js";
|
|
21
|
-
import { findActiveContextId } from "../lib-ts/context/context-store.js";
|
|
22
18
|
import {
|
|
23
19
|
findLatestHandoff,
|
|
24
20
|
readHandoffSections,
|
|
25
21
|
getHandoffTimestamp,
|
|
26
22
|
getHandoffPlanReference,
|
|
27
|
-
} from "../lib
|
|
23
|
+
} from "../lib/handoff-reader.js";
|
|
24
|
+
import { getProjectRoot } from "../../lib-ts/base/constants.js";
|
|
25
|
+
import { getContextBySessionId } from "../../lib-ts/context/context-store.js";
|
|
26
|
+
import { getGitStatusShort } from "../../lib-ts/base/git-state.js";
|
|
27
|
+
import { eprint } from "../../lib-ts/base/utils.js";
|
|
28
28
|
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Helpers
|
|
@@ -117,19 +117,22 @@ function resolveHandoffFolder(args: string[]): [string, string | null] {
|
|
|
117
117
|
return [target, null];
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
// Auto-discover
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
// Auto-discover via session ID (when running from Claude Code)
|
|
121
|
+
const sessionId = process.env.CLAUDE_SESSION_ID;
|
|
122
|
+
if (sessionId) {
|
|
123
|
+
const context = getContextBySessionId(sessionId, projectRoot);
|
|
124
|
+
if (context) {
|
|
125
|
+
const folder = findLatestHandoff(context.id, projectRoot);
|
|
126
|
+
if (!folder) {
|
|
127
|
+
eprint(`No handoff folders found for context: ${context.id} (from session ${sessionId})`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
return [folder, context.id];
|
|
127
131
|
}
|
|
128
|
-
return [folder, discoveredId];
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
eprint(
|
|
132
|
-
"No
|
|
135
|
+
"No context found for current session.\n\n" +
|
|
133
136
|
"Usage: bun resume_handoff.ts <handoff_folder_or_index>\n" +
|
|
134
137
|
" bun resume_handoff.ts --context <context_id>",
|
|
135
138
|
);
|