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.
Files changed (204) hide show
  1. package/README.md +1248 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +16 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +19 -0
  6. package/dist/commands/branch.d.ts +45 -0
  7. package/dist/commands/branch.js +488 -0
  8. package/dist/commands/clean.d.ts +34 -0
  9. package/dist/commands/clean.js +186 -0
  10. package/dist/commands/clear.d.ts +51 -0
  11. package/dist/commands/clear.js +835 -0
  12. package/dist/commands/init/index.d.ts +107 -0
  13. package/dist/commands/init/index.js +565 -0
  14. package/dist/commands/launch.d.ts +21 -0
  15. package/dist/commands/launch.js +108 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +1 -0
  18. package/dist/lib/base-command.d.ts +114 -0
  19. package/dist/lib/base-command.js +153 -0
  20. package/dist/lib/bmad-installer.d.ts +38 -0
  21. package/dist/lib/bmad-installer.js +145 -0
  22. package/dist/lib/claude-settings-types.d.ts +102 -0
  23. package/dist/lib/claude-settings-types.js +5 -0
  24. package/dist/lib/config.d.ts +25 -0
  25. package/dist/lib/config.js +46 -0
  26. package/dist/lib/debug.d.ts +39 -0
  27. package/dist/lib/debug.js +74 -0
  28. package/dist/lib/env-compat.d.ts +26 -0
  29. package/dist/lib/env-compat.js +35 -0
  30. package/dist/lib/errors.d.ts +126 -0
  31. package/dist/lib/errors.js +145 -0
  32. package/dist/lib/generic-merge.d.ts +74 -0
  33. package/dist/lib/generic-merge.js +105 -0
  34. package/dist/lib/git/branch.d.ts +67 -0
  35. package/dist/lib/git/branch.js +155 -0
  36. package/dist/lib/git/index.d.ts +11 -0
  37. package/dist/lib/git/index.js +13 -0
  38. package/dist/lib/git/safety-checks.d.ts +44 -0
  39. package/dist/lib/git/safety-checks.js +102 -0
  40. package/dist/lib/git/types.d.ts +31 -0
  41. package/dist/lib/git/types.js +6 -0
  42. package/dist/lib/git/worktree.d.ts +67 -0
  43. package/dist/lib/git/worktree.js +220 -0
  44. package/dist/lib/gitignore-manager.d.ts +10 -0
  45. package/dist/lib/gitignore-manager.js +60 -0
  46. package/dist/lib/hooks-merger.d.ts +28 -0
  47. package/dist/lib/hooks-merger.js +94 -0
  48. package/dist/lib/ide-path-resolver.d.ts +102 -0
  49. package/dist/lib/ide-path-resolver.js +129 -0
  50. package/dist/lib/index.d.ts +13 -0
  51. package/dist/lib/index.js +22 -0
  52. package/dist/lib/output.d.ts +51 -0
  53. package/dist/lib/output.js +76 -0
  54. package/dist/lib/paths.d.ts +66 -0
  55. package/dist/lib/paths.js +136 -0
  56. package/dist/lib/quiet.d.ts +12 -0
  57. package/dist/lib/quiet.js +17 -0
  58. package/dist/lib/settings-hierarchy.d.ts +42 -0
  59. package/dist/lib/settings-hierarchy.js +105 -0
  60. package/dist/lib/spawn.d.ts +105 -0
  61. package/dist/lib/spawn.js +157 -0
  62. package/dist/lib/spinner.d.ts +19 -0
  63. package/dist/lib/spinner.js +34 -0
  64. package/dist/lib/stdin.d.ts +48 -0
  65. package/dist/lib/stdin.js +60 -0
  66. package/dist/lib/template-installer.d.ts +92 -0
  67. package/dist/lib/template-installer.js +375 -0
  68. package/dist/lib/template-linter.d.ts +49 -0
  69. package/dist/lib/template-linter.js +173 -0
  70. package/dist/lib/template-merger.d.ts +47 -0
  71. package/dist/lib/template-merger.js +173 -0
  72. package/dist/lib/template-resolver.d.ts +20 -0
  73. package/dist/lib/template-resolver.js +60 -0
  74. package/dist/lib/terminal.d.ts +102 -0
  75. package/dist/lib/terminal.js +245 -0
  76. package/dist/lib/tty-detection.d.ts +62 -0
  77. package/dist/lib/tty-detection.js +83 -0
  78. package/dist/lib/user-utils.d.ts +5 -0
  79. package/dist/lib/user-utils.js +23 -0
  80. package/dist/lib/version.d.ts +99 -0
  81. package/dist/lib/version.js +144 -0
  82. package/dist/lib/watch-templates.d.ts +6 -0
  83. package/dist/lib/watch-templates.js +73 -0
  84. package/dist/lib/windsurf-hooks-hierarchy.d.ts +30 -0
  85. package/dist/lib/windsurf-hooks-hierarchy.js +66 -0
  86. package/dist/lib/windsurf-hooks-merger.d.ts +26 -0
  87. package/dist/lib/windsurf-hooks-merger.js +53 -0
  88. package/dist/lib/windsurf-hooks-types.d.ts +33 -0
  89. package/dist/lib/windsurf-hooks-types.js +5 -0
  90. package/dist/templates/CLAUDE.md +174 -0
  91. package/dist/templates/_shared/.claude/commands/handoff.md +14 -0
  92. package/dist/templates/_shared/.claude/settings.json +61 -0
  93. package/dist/templates/_shared/.codex/workflows/handoff.md +14 -0
  94. package/dist/templates/_shared/.windsurf/workflows/handoff.md +14 -0
  95. package/dist/templates/_shared/hooks/__init__.py +16 -0
  96. package/dist/templates/_shared/hooks/archive_plan.py +270 -0
  97. package/dist/templates/_shared/hooks/context_enforcer.py +621 -0
  98. package/dist/templates/_shared/hooks/context_monitor.py +322 -0
  99. package/dist/templates/_shared/hooks/file-suggestion.py +188 -0
  100. package/dist/templates/_shared/hooks/task_create_capture.py +194 -0
  101. package/dist/templates/_shared/hooks/task_update_capture.py +254 -0
  102. package/dist/templates/_shared/hooks/user_prompt_submit.py +157 -0
  103. package/dist/templates/_shared/lib/__init__.py +1 -0
  104. package/dist/templates/_shared/lib/base/__init__.py +49 -0
  105. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  106. package/dist/templates/_shared/lib/base/atomic_write.py +180 -0
  107. package/dist/templates/_shared/lib/base/constants.py +299 -0
  108. package/dist/templates/_shared/lib/base/inference.py +189 -0
  109. package/dist/templates/_shared/lib/base/utils.py +216 -0
  110. package/dist/templates/_shared/lib/context/__init__.py +119 -0
  111. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  112. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  113. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  114. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  115. package/dist/templates/_shared/lib/context/cache.py +446 -0
  116. package/dist/templates/_shared/lib/context/context_manager.py +1171 -0
  117. package/dist/templates/_shared/lib/context/discovery.py +486 -0
  118. package/dist/templates/_shared/lib/context/event_log.py +308 -0
  119. package/dist/templates/_shared/lib/context/plan_archive.py +247 -0
  120. package/dist/templates/_shared/lib/context/task_sync.py +367 -0
  121. package/dist/templates/_shared/lib/handoff/__init__.py +22 -0
  122. package/dist/templates/_shared/lib/handoff/document_generator.py +307 -0
  123. package/dist/templates/_shared/lib/templates/README.md +215 -0
  124. package/dist/templates/_shared/lib/templates/__init__.py +40 -0
  125. package/dist/templates/_shared/lib/templates/formatters.py +147 -0
  126. package/dist/templates/_shared/lib/templates/plan_context.py +119 -0
  127. package/dist/templates/_shared/scripts/save_handoff.py +99 -0
  128. package/dist/templates/_shared/workflows/handoff.md +212 -0
  129. package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +80 -0
  130. package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +75 -0
  131. package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +239 -0
  132. package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +109 -0
  133. package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +71 -0
  134. package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +104 -0
  135. package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +93 -0
  136. package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +223 -0
  137. package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +73 -0
  138. package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +93 -0
  139. package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +103 -0
  140. package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +145 -0
  141. package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +248 -0
  142. package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +235 -0
  143. package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +80 -0
  144. package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +76 -0
  145. package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +141 -0
  146. package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +240 -0
  147. package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +211 -0
  148. package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +101 -0
  149. package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +197 -0
  150. package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +97 -0
  151. package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +349 -0
  152. package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +106 -0
  153. package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +205 -0
  154. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +8 -0
  155. package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -0
  156. package/dist/templates/cc-native/.claude/settings.json +119 -0
  157. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -0
  158. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +8 -0
  159. package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -0
  160. package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -0
  161. package/dist/templates/cc-native/CC-NATIVE-README.md +192 -0
  162. package/dist/templates/cc-native/MIGRATION.md +86 -0
  163. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +331 -0
  164. package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +147 -0
  165. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  166. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  167. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
  168. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  169. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
  170. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +150 -0
  171. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +746 -0
  172. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +339 -0
  173. package/dist/templates/cc-native/_cc-native/lib/__init__.py +57 -0
  174. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  175. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  176. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  177. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  178. package/dist/templates/cc-native/_cc-native/lib/async_archive.py +68 -0
  179. package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +98 -0
  180. package/dist/templates/cc-native/_cc-native/lib/constants.py +45 -0
  181. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +273 -0
  182. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +28 -0
  183. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  184. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  185. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  186. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  187. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  188. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +164 -0
  189. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +89 -0
  190. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +119 -0
  191. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +103 -0
  192. package/dist/templates/cc-native/_cc-native/lib/state.py +251 -0
  193. package/dist/templates/cc-native/_cc-native/lib/utils.py +830 -0
  194. package/dist/templates/cc-native/_cc-native/plan-review.config.json +76 -0
  195. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  196. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +151 -0
  197. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +134 -0
  198. package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -0
  199. package/dist/types/exit-codes.d.ts +11 -0
  200. package/dist/types/exit-codes.js +10 -0
  201. package/dist/types/index.d.ts +5 -0
  202. package/dist/types/index.js +7 -0
  203. package/oclif.manifest.json +405 -0
  204. 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)