aiwcli 0.9.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 +1248 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +16 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +19 -0
- package/dist/commands/branch.d.ts +45 -0
- package/dist/commands/branch.js +488 -0
- package/dist/commands/clean.d.ts +34 -0
- package/dist/commands/clean.js +186 -0
- package/dist/commands/clear.d.ts +51 -0
- package/dist/commands/clear.js +835 -0
- package/dist/commands/init/index.d.ts +107 -0
- package/dist/commands/init/index.js +565 -0
- package/dist/commands/launch.d.ts +21 -0
- package/dist/commands/launch.js +108 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/base-command.d.ts +114 -0
- package/dist/lib/base-command.js +153 -0
- package/dist/lib/bmad-installer.d.ts +38 -0
- package/dist/lib/bmad-installer.js +145 -0
- package/dist/lib/claude-settings-types.d.ts +102 -0
- package/dist/lib/claude-settings-types.js +5 -0
- package/dist/lib/config.d.ts +25 -0
- package/dist/lib/config.js +46 -0
- package/dist/lib/debug.d.ts +39 -0
- package/dist/lib/debug.js +74 -0
- package/dist/lib/env-compat.d.ts +26 -0
- package/dist/lib/env-compat.js +35 -0
- package/dist/lib/errors.d.ts +126 -0
- package/dist/lib/errors.js +145 -0
- package/dist/lib/generic-merge.d.ts +74 -0
- package/dist/lib/generic-merge.js +105 -0
- package/dist/lib/git/branch.d.ts +67 -0
- package/dist/lib/git/branch.js +155 -0
- package/dist/lib/git/index.d.ts +11 -0
- package/dist/lib/git/index.js +13 -0
- package/dist/lib/git/safety-checks.d.ts +44 -0
- package/dist/lib/git/safety-checks.js +102 -0
- package/dist/lib/git/types.d.ts +31 -0
- package/dist/lib/git/types.js +6 -0
- package/dist/lib/git/worktree.d.ts +67 -0
- package/dist/lib/git/worktree.js +220 -0
- package/dist/lib/gitignore-manager.d.ts +10 -0
- package/dist/lib/gitignore-manager.js +60 -0
- package/dist/lib/hooks-merger.d.ts +28 -0
- package/dist/lib/hooks-merger.js +94 -0
- package/dist/lib/ide-path-resolver.d.ts +102 -0
- package/dist/lib/ide-path-resolver.js +129 -0
- package/dist/lib/index.d.ts +13 -0
- package/dist/lib/index.js +22 -0
- package/dist/lib/output.d.ts +51 -0
- package/dist/lib/output.js +76 -0
- package/dist/lib/paths.d.ts +66 -0
- package/dist/lib/paths.js +136 -0
- package/dist/lib/quiet.d.ts +12 -0
- package/dist/lib/quiet.js +17 -0
- package/dist/lib/settings-hierarchy.d.ts +42 -0
- package/dist/lib/settings-hierarchy.js +105 -0
- package/dist/lib/spawn.d.ts +105 -0
- package/dist/lib/spawn.js +157 -0
- package/dist/lib/spinner.d.ts +19 -0
- package/dist/lib/spinner.js +34 -0
- package/dist/lib/stdin.d.ts +48 -0
- package/dist/lib/stdin.js +60 -0
- package/dist/lib/template-installer.d.ts +92 -0
- package/dist/lib/template-installer.js +375 -0
- package/dist/lib/template-linter.d.ts +49 -0
- package/dist/lib/template-linter.js +173 -0
- package/dist/lib/template-merger.d.ts +47 -0
- package/dist/lib/template-merger.js +173 -0
- package/dist/lib/template-resolver.d.ts +20 -0
- package/dist/lib/template-resolver.js +60 -0
- package/dist/lib/terminal.d.ts +102 -0
- package/dist/lib/terminal.js +245 -0
- package/dist/lib/tty-detection.d.ts +62 -0
- package/dist/lib/tty-detection.js +83 -0
- package/dist/lib/user-utils.d.ts +5 -0
- package/dist/lib/user-utils.js +23 -0
- package/dist/lib/version.d.ts +99 -0
- package/dist/lib/version.js +144 -0
- package/dist/lib/watch-templates.d.ts +6 -0
- package/dist/lib/watch-templates.js +73 -0
- package/dist/lib/windsurf-hooks-hierarchy.d.ts +30 -0
- package/dist/lib/windsurf-hooks-hierarchy.js +66 -0
- package/dist/lib/windsurf-hooks-merger.d.ts +26 -0
- package/dist/lib/windsurf-hooks-merger.js +53 -0
- package/dist/lib/windsurf-hooks-types.d.ts +33 -0
- package/dist/lib/windsurf-hooks-types.js +5 -0
- package/dist/templates/CLAUDE.md +174 -0
- package/dist/templates/_shared/.claude/commands/handoff.md +14 -0
- package/dist/templates/_shared/.claude/settings.json +61 -0
- package/dist/templates/_shared/.codex/workflows/handoff.md +14 -0
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +14 -0
- package/dist/templates/_shared/hooks/__init__.py +16 -0
- package/dist/templates/_shared/hooks/archive_plan.py +270 -0
- package/dist/templates/_shared/hooks/context_enforcer.py +621 -0
- package/dist/templates/_shared/hooks/context_monitor.py +322 -0
- package/dist/templates/_shared/hooks/file-suggestion.py +188 -0
- package/dist/templates/_shared/hooks/task_create_capture.py +194 -0
- package/dist/templates/_shared/hooks/task_update_capture.py +254 -0
- package/dist/templates/_shared/hooks/user_prompt_submit.py +157 -0
- package/dist/templates/_shared/lib/__init__.py +1 -0
- package/dist/templates/_shared/lib/base/__init__.py +49 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/atomic_write.py +180 -0
- package/dist/templates/_shared/lib/base/constants.py +299 -0
- package/dist/templates/_shared/lib/base/inference.py +189 -0
- package/dist/templates/_shared/lib/base/utils.py +216 -0
- package/dist/templates/_shared/lib/context/__init__.py +119 -0
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/cache.py +446 -0
- package/dist/templates/_shared/lib/context/context_manager.py +1171 -0
- package/dist/templates/_shared/lib/context/discovery.py +486 -0
- package/dist/templates/_shared/lib/context/event_log.py +308 -0
- package/dist/templates/_shared/lib/context/plan_archive.py +247 -0
- package/dist/templates/_shared/lib/context/task_sync.py +367 -0
- package/dist/templates/_shared/lib/handoff/__init__.py +22 -0
- package/dist/templates/_shared/lib/handoff/document_generator.py +307 -0
- package/dist/templates/_shared/lib/templates/README.md +215 -0
- package/dist/templates/_shared/lib/templates/__init__.py +40 -0
- package/dist/templates/_shared/lib/templates/formatters.py +147 -0
- package/dist/templates/_shared/lib/templates/plan_context.py +119 -0
- package/dist/templates/_shared/scripts/save_handoff.py +99 -0
- package/dist/templates/_shared/workflows/handoff.md +212 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +75 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +239 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +109 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +71 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +104 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +223 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +73 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +103 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +145 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +248 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +235 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +76 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +141 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +240 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +211 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +101 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +197 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +97 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +349 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +106 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +205 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -0
- package/dist/templates/cc-native/.claude/settings.json +119 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -0
- package/dist/templates/cc-native/CC-NATIVE-README.md +192 -0
- package/dist/templates/cc-native/MIGRATION.md +86 -0
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +331 -0
- package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +147 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +150 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +746 -0
- package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +339 -0
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +57 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/async_archive.py +68 -0
- package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +98 -0
- package/dist/templates/cc-native/_cc-native/lib/constants.py +45 -0
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +273 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +28 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +164 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +89 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +119 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +103 -0
- package/dist/templates/cc-native/_cc-native/lib/state.py +251 -0
- package/dist/templates/cc-native/_cc-native/lib/utils.py +830 -0
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +76 -0
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +151 -0
- package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +134 -0
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -0
- package/dist/types/exit-codes.d.ts +11 -0
- package/dist/types/exit-codes.js +10 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -0
- package/oclif.manifest.json +405 -0
- package/package.json +109 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Template Development Guidelines
|
|
2
|
+
|
|
3
|
+
## Output Directory
|
|
4
|
+
|
|
5
|
+
Write all method outputs to `_output/{method}/`:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
_output/
|
|
9
|
+
├── gsd/.planning/ # GSD planning artifacts
|
|
10
|
+
├── bmad/docs/ # BMAD documentation
|
|
11
|
+
└── {method}/{subdir}/ # Other method outputs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Include `_output/{method}/` in template `.gitignore`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Directory Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
packages/cli/src/templates/{method}/
|
|
22
|
+
├── _{method}/ # Method-specific shared files
|
|
23
|
+
│ ├── templates/*.md.template
|
|
24
|
+
│ └── workflows/*.md # Canonical workflow definitions
|
|
25
|
+
├── .{ide}/{ide-folder}/{method}/*.md # IDE command stubs
|
|
26
|
+
├── .gitignore # Output ignore rules
|
|
27
|
+
├── {METHOD}-README.md # User documentation
|
|
28
|
+
├── TEMPLATE-SCHEMA.md # Schema reference
|
|
29
|
+
└── MIGRATION.md # Breaking changes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Tier Details
|
|
33
|
+
|
|
34
|
+
| Tier | Location | Purpose |
|
|
35
|
+
|------|----------|---------|
|
|
36
|
+
| General | `_{method}/` | IDE-agnostic templates and canonical workflows |
|
|
37
|
+
| IDE | `.{ide}/{folder}/{method}/` | Lightweight stubs that load canonical workflows |
|
|
38
|
+
| Config | `.{ide}/settings.json` | Hooks, model prefs, method settings (merged on install) |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Settings Merge Rules
|
|
43
|
+
|
|
44
|
+
When multiple templates install, settings.json files merge:
|
|
45
|
+
|
|
46
|
+
**Hook merging** - Hooks combine by lifecycle event
|
|
47
|
+
**Method namespacing** - Use method name as top-level key: `"gsd": { ... }`
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"gsd": { "planReview": { "enabled": true } },
|
|
52
|
+
"bmad": { "agents": { "defaultModel": "claude-3-opus" } }
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Hooks
|
|
59
|
+
|
|
60
|
+
**Location:** `.claude/hooks/{method}-{hook-name}.{ext}`
|
|
61
|
+
|
|
62
|
+
**Configuration:**
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"hooks": {
|
|
66
|
+
"PostToolUse": [{
|
|
67
|
+
"matcher": "Write",
|
|
68
|
+
"hooks": [{ "type": "command", "command": "python .claude/hooks/gsd-plan-review.py", "timeout": 300000 }]
|
|
69
|
+
}]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Requirements:**
|
|
75
|
+
- Prefix with method name (e.g., `gsd-plan-review.py`)
|
|
76
|
+
- Use relative paths from project root
|
|
77
|
+
- Write outputs to `_output/{method}/`
|
|
78
|
+
- Specify timeouts
|
|
79
|
+
- Set `blockOnFail: false` unless critical
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Workflow Pattern
|
|
84
|
+
|
|
85
|
+
### Canonical Workflow (`_{method}/workflows/`)
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
# {Method} Workflow: {Name}
|
|
89
|
+
|
|
90
|
+
## Purpose
|
|
91
|
+
Brief description.
|
|
92
|
+
|
|
93
|
+
## Process
|
|
94
|
+
### Step 1: {Name}
|
|
95
|
+
Instructions.
|
|
96
|
+
|
|
97
|
+
## Output Files
|
|
98
|
+
All in `_output/{method}/{subdir}/`:
|
|
99
|
+
- `FILE.md` - Description
|
|
100
|
+
|
|
101
|
+
## Success Criteria
|
|
102
|
+
- [ ] Criterion 1
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### IDE Stub (`.{ide}/{folder}/{method}/`)
|
|
106
|
+
|
|
107
|
+
```markdown
|
|
108
|
+
---
|
|
109
|
+
description: One-line for command palette
|
|
110
|
+
---
|
|
111
|
+
# {Workflow Name}
|
|
112
|
+
Load and execute `_{method}/workflows/{name}.md`.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Reference Patterns
|
|
118
|
+
|
|
119
|
+
| Reference Type | Pattern |
|
|
120
|
+
|----------------|---------|
|
|
121
|
+
| Templates | `_{method}/templates/FILE.md.template` |
|
|
122
|
+
| Workflows (Claude) | `/gsd:other-workflow` |
|
|
123
|
+
| Workflows (Windsurf) | `other-workflow` from GSD workflows |
|
|
124
|
+
| Outputs | `_output/{method}/{subdir}/FILE.md` |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Naming Conventions
|
|
129
|
+
|
|
130
|
+
| Element | Convention | Example |
|
|
131
|
+
|---------|------------|---------|
|
|
132
|
+
| Method folder | `_{lowercase}` | `_gsd` |
|
|
133
|
+
| Template file | `UPPERCASE.md.template` | `PROJECT.md.template` |
|
|
134
|
+
| Workflow file | `kebab-case.md` | `new-project.md` |
|
|
135
|
+
| Output file | `UPPERCASE.md` | `PROJECT.md` |
|
|
136
|
+
| Hook file | `{method}-{name}.{ext}` | `gsd-plan-review.py` |
|
|
137
|
+
| Settings key | `{method}` | `"gsd": {}` |
|
|
138
|
+
| Readme | `{METHOD}-README.md` | `GSD-README.md` |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Checklists
|
|
143
|
+
|
|
144
|
+
**New Template:**
|
|
145
|
+
- [ ] Create `_{method}/` with `templates/` and `workflows/`
|
|
146
|
+
- [ ] Create `.claude/commands/{method}/` stubs
|
|
147
|
+
- [ ] Create `.windsurf/workflows/{method}/` stubs
|
|
148
|
+
- [ ] Add `.gitignore` with `_output/{method}/`
|
|
149
|
+
- [ ] Create `{METHOD}-README.md`, `TEMPLATE-SCHEMA.md`, `MIGRATION.md`
|
|
150
|
+
- [ ] Configure method-namespaced settings in `.claude/settings.json`
|
|
151
|
+
|
|
152
|
+
**New Workflow:**
|
|
153
|
+
- [ ] Create canonical in `_{method}/workflows/{name}.md`
|
|
154
|
+
- [ ] Create stubs in `.claude/commands/{method}/` and `.windsurf/workflows/{method}/`
|
|
155
|
+
- [ ] Update README and TEMPLATE-SCHEMA.md
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Practices
|
|
160
|
+
|
|
161
|
+
**Do:**
|
|
162
|
+
- Write outputs to `_output/{method}/`
|
|
163
|
+
- Namespace settings under method key
|
|
164
|
+
- Prefix hooks with method name
|
|
165
|
+
- Keep canonical workflows in `_{method}/workflows/`
|
|
166
|
+
- Use relative paths from project root
|
|
167
|
+
- Document changes in TEMPLATE-SCHEMA.md
|
|
168
|
+
|
|
169
|
+
**Avoid:**
|
|
170
|
+
- Outputs in project root
|
|
171
|
+
- Generic settings keys that conflict
|
|
172
|
+
- Hooks without method prefix
|
|
173
|
+
- Full workflows in IDE command files
|
|
174
|
+
- Hardcoded paths without method namespace
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate a session handoff document when ending work
|
|
3
|
+
---
|
|
4
|
+
# Session Handoff
|
|
5
|
+
|
|
6
|
+
Generate a handoff document summarizing the current session's work, decisions, and pending items.
|
|
7
|
+
|
|
8
|
+
## Arguments
|
|
9
|
+
|
|
10
|
+
- `$ARGUMENTS` - Optional path to a plan document to update with progress tracking
|
|
11
|
+
|
|
12
|
+
Load and execute `_shared/workflows/handoff.md`.
|
|
13
|
+
|
|
14
|
+
Follow the Gather → Analyze → Write → Update Context pattern using native tools.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fileSuggestion": {
|
|
3
|
+
"type": "command",
|
|
4
|
+
"command": "python .aiwcli/_shared/hooks/file-suggestion.py"
|
|
5
|
+
},
|
|
6
|
+
"hooks": {
|
|
7
|
+
"UserPromptSubmit": [
|
|
8
|
+
{
|
|
9
|
+
"hooks": [
|
|
10
|
+
{
|
|
11
|
+
"type": "command",
|
|
12
|
+
"command": "python .aiwcli/_shared/hooks/user_prompt_submit.py",
|
|
13
|
+
"timeout": 5000
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"PostToolUse": [
|
|
19
|
+
{
|
|
20
|
+
"matcher": "Task|Read|Bash|WebFetch|Edit|Write|NotebookEdit",
|
|
21
|
+
"hooks": [
|
|
22
|
+
{
|
|
23
|
+
"type": "command",
|
|
24
|
+
"command": "python .aiwcli/_shared/hooks/context_monitor.py",
|
|
25
|
+
"timeout": 5000
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"matcher": "TaskCreate",
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "python .aiwcli/_shared/hooks/task_create_capture.py",
|
|
35
|
+
"timeout": 3000
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"matcher": "TaskUpdate",
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "python .aiwcli/_shared/hooks/task_update_capture.py",
|
|
45
|
+
"timeout": 3000
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"matcher": "ExitPlanMode",
|
|
51
|
+
"hooks": [
|
|
52
|
+
{
|
|
53
|
+
"type": "command",
|
|
54
|
+
"command": "python .aiwcli/_shared/hooks/archive_plan.py",
|
|
55
|
+
"timeout": 5000
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate a session handoff document when ending work
|
|
3
|
+
---
|
|
4
|
+
# Session Handoff
|
|
5
|
+
|
|
6
|
+
Generate a handoff document summarizing the current session's work, decisions, and pending items.
|
|
7
|
+
|
|
8
|
+
## Arguments
|
|
9
|
+
|
|
10
|
+
- `$ARGUMENTS` - Optional path to a plan document to update with progress tracking
|
|
11
|
+
|
|
12
|
+
Load and execute `_shared/workflows/handoff.md`.
|
|
13
|
+
|
|
14
|
+
Follow the Gather → Analyze → Write → Update Context pattern.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate a session handoff document when ending work
|
|
3
|
+
---
|
|
4
|
+
# Session Handoff
|
|
5
|
+
|
|
6
|
+
Generate a handoff document summarizing the current session's work, decisions, and pending items.
|
|
7
|
+
|
|
8
|
+
## Arguments
|
|
9
|
+
|
|
10
|
+
- `$ARGUMENTS` - Optional path to a plan document to update with progress tracking
|
|
11
|
+
|
|
12
|
+
Load and execute `_shared/workflows/handoff.md`.
|
|
13
|
+
|
|
14
|
+
Follow the Gather → Analyze → Write → Update Context pattern.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Shared hooks for AIW CLI templates.
|
|
2
|
+
|
|
3
|
+
These hooks integrate with Claude Code's hook system to provide:
|
|
4
|
+
- UserPromptSubmit: Context enforcement (ensures work happens in tracked context)
|
|
5
|
+
- PostToolUse: Context monitoring and handoff warnings
|
|
6
|
+
- ExitPlanMode: Plan archival to context
|
|
7
|
+
|
|
8
|
+
Hooks read JSON input from stdin and output instructions to stdout.
|
|
9
|
+
|
|
10
|
+
Available hooks:
|
|
11
|
+
- user_prompt_submit.py: Runs on user prompt, enforces context tracking
|
|
12
|
+
- context_monitor.py: Runs on PostToolUse, monitors context and warns when low
|
|
13
|
+
- archive_plan.py: Runs on ExitPlanMode, archives plan to context
|
|
14
|
+
- task_create_capture.py: Runs on TaskCreate, captures task events
|
|
15
|
+
- task_update_capture.py: Runs on TaskUpdate, captures task updates
|
|
16
|
+
"""
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Plan archival hook for ExitPlanMode PostToolUse event.
|
|
3
|
+
|
|
4
|
+
This hook runs when ExitPlanMode completes, extracting the plan path from
|
|
5
|
+
the tool result and archiving it to the active context.
|
|
6
|
+
|
|
7
|
+
Actions:
|
|
8
|
+
1. Detect ExitPlanMode PostToolUse event
|
|
9
|
+
2. Extract plan path from tool result
|
|
10
|
+
3. Check if plan already archived (avoid duplicates)
|
|
11
|
+
4. Determine active context
|
|
12
|
+
5. Archive plan to context's plans folder
|
|
13
|
+
6. Set context in_flight.mode = "pending_implementation"
|
|
14
|
+
|
|
15
|
+
Usage in .claude/settings.json:
|
|
16
|
+
{
|
|
17
|
+
"hooks": {
|
|
18
|
+
"PostToolUse": [{
|
|
19
|
+
"matcher": "ExitPlanMode",
|
|
20
|
+
"hooks": [{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "python .aiwcli/_shared/hooks/archive_plan.py",
|
|
23
|
+
"timeout": 5000
|
|
24
|
+
}]
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
"""
|
|
29
|
+
import json
|
|
30
|
+
import sys
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from typing import Optional
|
|
33
|
+
|
|
34
|
+
# Add parent directories to path for imports
|
|
35
|
+
script_dir = Path(__file__).resolve().parent
|
|
36
|
+
lib_dir = script_dir.parent / "lib"
|
|
37
|
+
sys.path.insert(0, str(lib_dir.parent))
|
|
38
|
+
|
|
39
|
+
from lib.context.plan_archive import archive_plan_to_context
|
|
40
|
+
from lib.context.context_manager import get_all_contexts
|
|
41
|
+
from lib.base.utils import eprint, project_dir
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_context_for_session(session_id: str, project_root: Path) -> Optional[str]:
|
|
45
|
+
"""
|
|
46
|
+
Find context that matches this session_id.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
session_id: Session ID to match
|
|
50
|
+
project_root: Project root directory
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Context ID or None if not found
|
|
54
|
+
"""
|
|
55
|
+
contexts = get_all_contexts(status="active", project_root=project_root)
|
|
56
|
+
|
|
57
|
+
# Primary strategy: Find context with matching session_id
|
|
58
|
+
for ctx in contexts:
|
|
59
|
+
if ctx.in_flight and ctx.in_flight.session_ids and session_id in ctx.in_flight.session_ids:
|
|
60
|
+
eprint(f"[archive_plan] Found context by session: {ctx.id}")
|
|
61
|
+
return ctx.id
|
|
62
|
+
|
|
63
|
+
# Fallback: If only one context is planning, assume it's the one
|
|
64
|
+
planning_contexts = [c for c in contexts if c.in_flight and c.in_flight.mode == "planning"]
|
|
65
|
+
if len(planning_contexts) == 1:
|
|
66
|
+
eprint(f"[archive_plan] Fallback: Single planning context: {planning_contexts[0].id}")
|
|
67
|
+
return planning_contexts[0].id
|
|
68
|
+
|
|
69
|
+
eprint(f"[archive_plan] Could not find context for session {session_id}")
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def extract_plan_path_from_result(tool_result: str) -> Optional[str]:
|
|
74
|
+
"""
|
|
75
|
+
Extract plan path from ExitPlanMode tool result.
|
|
76
|
+
|
|
77
|
+
Looks for pattern: "Your plan has been saved to: <path>"
|
|
78
|
+
"""
|
|
79
|
+
import re
|
|
80
|
+
match = re.search(r'Your plan has been saved to:\s*(.+\.md)', tool_result)
|
|
81
|
+
if match:
|
|
82
|
+
return match.group(1).strip()
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def on_plan_archive():
|
|
87
|
+
"""
|
|
88
|
+
Plan archival hook - archives plan when exiting plan mode.
|
|
89
|
+
|
|
90
|
+
Called from PostToolUse on ExitPlanMode - extracts plan path from result
|
|
91
|
+
and archives to the active context.
|
|
92
|
+
"""
|
|
93
|
+
# Read hook input from stdin
|
|
94
|
+
try:
|
|
95
|
+
hook_input = json.load(sys.stdin)
|
|
96
|
+
except json.JSONDecodeError:
|
|
97
|
+
eprint("[archive_plan] No valid JSON input")
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
hook_event = hook_input.get("hook_event_name", "unknown")
|
|
101
|
+
tool_name = hook_input.get("tool_name", "")
|
|
102
|
+
print(f"[archive_plan] Hook triggered: {hook_event}")
|
|
103
|
+
print(f"[archive_plan] Tool name: {tool_name}")
|
|
104
|
+
print(f"[archive_plan] Hook input keys: {list(hook_input.keys())}")
|
|
105
|
+
|
|
106
|
+
# Special handling for ExitPlanMode - don't check permission_mode
|
|
107
|
+
is_exit_plan_mode = (hook_event == "PostToolUse" and tool_name == "ExitPlanMode")
|
|
108
|
+
|
|
109
|
+
if is_exit_plan_mode:
|
|
110
|
+
print("[archive_plan] ExitPlanMode detected, proceeding with archival")
|
|
111
|
+
else:
|
|
112
|
+
# Check if we're in plan mode for other hooks
|
|
113
|
+
permission_mode = hook_input.get("permission_mode", "default")
|
|
114
|
+
print(f"[archive_plan] Permission mode: {permission_mode}")
|
|
115
|
+
|
|
116
|
+
if permission_mode != "plan":
|
|
117
|
+
print("[archive_plan] Not in plan mode, skipping archival")
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
# Prevent infinite loops from stop_hook_active
|
|
121
|
+
if hook_input.get("stop_hook_active", False):
|
|
122
|
+
print("[archive_plan] Stop hook already active, skipping to prevent loop")
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
print(f"[archive_plan] Proceeding with archival via {hook_event}")
|
|
126
|
+
|
|
127
|
+
# Get project root from hook input or environment
|
|
128
|
+
project_root = project_dir(hook_input)
|
|
129
|
+
|
|
130
|
+
# Get plan path from hook input
|
|
131
|
+
tool_input = hook_input.get("tool_input", {})
|
|
132
|
+
tool_result = hook_input.get("tool_result", "")
|
|
133
|
+
|
|
134
|
+
# Try to find plan path in various locations
|
|
135
|
+
plan_path = None
|
|
136
|
+
|
|
137
|
+
# For ExitPlanMode, extract plan path from tool result first
|
|
138
|
+
if is_exit_plan_mode and tool_result:
|
|
139
|
+
plan_path = extract_plan_path_from_result(tool_result)
|
|
140
|
+
if plan_path:
|
|
141
|
+
print(f"[archive_plan] Extracted plan path from ExitPlanMode result: {plan_path}")
|
|
142
|
+
|
|
143
|
+
# Check if plan path is directly provided in tool_input
|
|
144
|
+
if not plan_path and "plan_path" in tool_input:
|
|
145
|
+
plan_path = tool_input["plan_path"]
|
|
146
|
+
elif not plan_path and "planPath" in tool_input:
|
|
147
|
+
plan_path = tool_input["planPath"]
|
|
148
|
+
|
|
149
|
+
# If not found yet, search standard locations
|
|
150
|
+
if not plan_path:
|
|
151
|
+
print("[archive_plan] No plan_path found, searching standard locations...")
|
|
152
|
+
# Look for plan in common locations
|
|
153
|
+
possible_paths = []
|
|
154
|
+
|
|
155
|
+
# Check Claude Code plan directory first (~/.claude/plans/)
|
|
156
|
+
claude_plans_dir = Path.home() / ".claude" / "plans"
|
|
157
|
+
print(f"[archive_plan] Checking Claude plans dir: {claude_plans_dir}")
|
|
158
|
+
if claude_plans_dir.exists():
|
|
159
|
+
# Find any .md file in Claude plans directory
|
|
160
|
+
claude_plans = list(claude_plans_dir.glob("*.md"))
|
|
161
|
+
print(f"[archive_plan] Found {len(claude_plans)} .md files in Claude plans dir")
|
|
162
|
+
# Sort by modification time, newest first
|
|
163
|
+
if claude_plans:
|
|
164
|
+
claude_plans.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
|
165
|
+
possible_paths.extend(claude_plans)
|
|
166
|
+
for p in claude_plans[:3]: # Show first 3
|
|
167
|
+
print(f"[archive_plan] - {p}")
|
|
168
|
+
|
|
169
|
+
# Existing fallback paths
|
|
170
|
+
possible_paths.extend([
|
|
171
|
+
project_root / "_output" / "cc-native" / "plans" / "current-plan.md",
|
|
172
|
+
project_root / "_output" / "plans" / "current-plan.md",
|
|
173
|
+
project_root / "plan.md",
|
|
174
|
+
])
|
|
175
|
+
|
|
176
|
+
for path in possible_paths:
|
|
177
|
+
if path.exists():
|
|
178
|
+
plan_path = str(path)
|
|
179
|
+
break
|
|
180
|
+
|
|
181
|
+
if not plan_path:
|
|
182
|
+
eprint("[archive_plan] Could not determine plan path")
|
|
183
|
+
# Don't block - let ExitPlanMode proceed
|
|
184
|
+
print("[archive_plan] Could not find plan file in any of these locations:")
|
|
185
|
+
print(f" - ~/.claude/plans/*.md")
|
|
186
|
+
print(f" - {project_root}/_output/cc-native/plans/current-plan.md")
|
|
187
|
+
print(f" - {project_root}/_output/plans/current-plan.md")
|
|
188
|
+
print(f" - {project_root}/plan.md")
|
|
189
|
+
print("Plan archival skipped: no plan path found")
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
print(f"[archive_plan] Found plan at: {plan_path}")
|
|
193
|
+
|
|
194
|
+
# Resolve plan path relative to project root
|
|
195
|
+
plan_file = Path(plan_path)
|
|
196
|
+
if not plan_file.is_absolute():
|
|
197
|
+
# Ensure we have a valid project_root
|
|
198
|
+
if project_root is None:
|
|
199
|
+
project_root = project_dir()
|
|
200
|
+
plan_file = project_root / plan_path
|
|
201
|
+
else:
|
|
202
|
+
# On Windows, check if absolute path is on a different drive than project_root
|
|
203
|
+
# In that case, use the absolute path as-is
|
|
204
|
+
if sys.platform == 'win32':
|
|
205
|
+
try:
|
|
206
|
+
# Check if drives match (e.g., C: vs D:)
|
|
207
|
+
plan_drive = plan_file.drive.upper() if plan_file.drive else None
|
|
208
|
+
project_drive = project_root.drive.upper() if hasattr(project_root, 'drive') and project_root.drive else None
|
|
209
|
+
if plan_drive and project_drive and plan_drive != project_drive:
|
|
210
|
+
# Different drives - use absolute path as-is
|
|
211
|
+
pass # plan_file is already set correctly
|
|
212
|
+
except Exception:
|
|
213
|
+
pass # Fall through to use plan_file as-is
|
|
214
|
+
|
|
215
|
+
print(f"[archive_plan] Resolved plan file path: {plan_file}")
|
|
216
|
+
|
|
217
|
+
if not plan_file.exists():
|
|
218
|
+
eprint(f"[archive_plan] Plan file not found: {plan_file}")
|
|
219
|
+
print(f"[archive_plan] ERROR: File does not exist at resolved path")
|
|
220
|
+
print(f"Plan archival skipped: file not found ({plan_path})")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
# Find context by session ID
|
|
224
|
+
session_id = hook_input.get("session_id", "unknown")
|
|
225
|
+
context_id = get_context_for_session(session_id, project_root)
|
|
226
|
+
|
|
227
|
+
if not context_id:
|
|
228
|
+
eprint("[archive_plan] Could not determine context for session")
|
|
229
|
+
print("Plan archival failed: no context found for this session")
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
# Check if plan was already archived (avoid duplicates)
|
|
233
|
+
contexts = get_all_contexts(status="active", project_root=project_root)
|
|
234
|
+
for ctx in contexts:
|
|
235
|
+
if ctx.id == context_id:
|
|
236
|
+
if ctx.in_flight and ctx.in_flight.mode == "pending_implementation":
|
|
237
|
+
print(f"[archive_plan] Plan already archived for context '{context_id}', skipping")
|
|
238
|
+
return
|
|
239
|
+
break
|
|
240
|
+
|
|
241
|
+
# Archive the plan
|
|
242
|
+
archived_path, plan_hash = archive_plan_to_context(
|
|
243
|
+
str(plan_file),
|
|
244
|
+
context_id,
|
|
245
|
+
project_root
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if archived_path:
|
|
249
|
+
print(f"")
|
|
250
|
+
print(f"[archive_plan] SUCCESS!")
|
|
251
|
+
print(f"[archive_plan] Plan archived to context: {context_id}")
|
|
252
|
+
print(f"[archive_plan] Archived path: {archived_path}")
|
|
253
|
+
print(f"[archive_plan] Source path: {plan_file}")
|
|
254
|
+
print(f"[archive_plan] Hash: {plan_hash}")
|
|
255
|
+
print(f"")
|
|
256
|
+
print("After /clear, SessionStart will auto-continue this context for implementation.")
|
|
257
|
+
else:
|
|
258
|
+
print(f"[archive_plan] FAILED: Could not archive plan for context '{context_id}'")
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
if __name__ == "__main__":
|
|
262
|
+
try:
|
|
263
|
+
on_plan_archive()
|
|
264
|
+
except Exception as e:
|
|
265
|
+
# Log errors to stderr
|
|
266
|
+
eprint(f"[archive_plan] Error: {e}")
|
|
267
|
+
import traceback
|
|
268
|
+
eprint(traceback.format_exc())
|
|
269
|
+
# Exit cleanly so hook doesn't block
|
|
270
|
+
sys.exit(0)
|