@kata-sh/cli 0.1.0 → 0.1.2

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 (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/dist/app-paths.d.ts +4 -0
  4. package/dist/app-paths.js +6 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +56 -0
  7. package/dist/loader.d.ts +2 -0
  8. package/dist/loader.js +95 -0
  9. package/dist/resource-loader.d.ts +18 -0
  10. package/dist/resource-loader.js +50 -0
  11. package/dist/wizard.d.ts +15 -0
  12. package/dist/wizard.js +159 -0
  13. package/package.json +50 -21
  14. package/pkg/dist/modes/interactive/theme/dark.json +85 -0
  15. package/pkg/dist/modes/interactive/theme/light.json +84 -0
  16. package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
  17. package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
  18. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  19. package/pkg/dist/modes/interactive/theme/theme.js +949 -0
  20. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
  21. package/pkg/package.json +8 -0
  22. package/scripts/postinstall.js +45 -0
  23. package/src/resources/AGENTS.md +108 -0
  24. package/src/resources/KATA-WORKFLOW.md +661 -0
  25. package/src/resources/agents/researcher.md +29 -0
  26. package/src/resources/agents/scout.md +56 -0
  27. package/src/resources/agents/worker.md +31 -0
  28. package/src/resources/extensions/ask-user-questions.ts +200 -0
  29. package/src/resources/extensions/bg-shell/index.ts +2758 -0
  30. package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  31. package/src/resources/extensions/browser-tools/core.js +1057 -0
  32. package/src/resources/extensions/browser-tools/index.ts +4916 -0
  33. package/src/resources/extensions/browser-tools/package.json +20 -0
  34. package/src/resources/extensions/context7/index.ts +428 -0
  35. package/src/resources/extensions/context7/package.json +11 -0
  36. package/src/resources/extensions/get-secrets-from-user.ts +352 -0
  37. package/src/resources/extensions/github/formatters.ts +207 -0
  38. package/src/resources/extensions/github/gh-api.ts +537 -0
  39. package/src/resources/extensions/github/index.ts +778 -0
  40. package/src/resources/extensions/kata/activity-log.ts +88 -0
  41. package/src/resources/extensions/kata/auto.ts +2786 -0
  42. package/src/resources/extensions/kata/commands.ts +355 -0
  43. package/src/resources/extensions/kata/crash-recovery.ts +85 -0
  44. package/src/resources/extensions/kata/dashboard-overlay.ts +516 -0
  45. package/src/resources/extensions/kata/docs/preferences-reference.md +103 -0
  46. package/src/resources/extensions/kata/doctor.ts +683 -0
  47. package/src/resources/extensions/kata/files.ts +730 -0
  48. package/src/resources/extensions/kata/gitignore.ts +165 -0
  49. package/src/resources/extensions/kata/guided-flow.ts +976 -0
  50. package/src/resources/extensions/kata/index.ts +556 -0
  51. package/src/resources/extensions/kata/metrics.ts +397 -0
  52. package/src/resources/extensions/kata/observability-validator.ts +408 -0
  53. package/src/resources/extensions/kata/package.json +11 -0
  54. package/src/resources/extensions/kata/paths.ts +346 -0
  55. package/src/resources/extensions/kata/preferences.ts +695 -0
  56. package/src/resources/extensions/kata/prompt-loader.ts +50 -0
  57. package/src/resources/extensions/kata/prompts/complete-milestone.md +25 -0
  58. package/src/resources/extensions/kata/prompts/complete-slice.md +27 -0
  59. package/src/resources/extensions/kata/prompts/discuss.md +151 -0
  60. package/src/resources/extensions/kata/prompts/doctor-heal.md +29 -0
  61. package/src/resources/extensions/kata/prompts/execute-task.md +64 -0
  62. package/src/resources/extensions/kata/prompts/guided-complete-slice.md +1 -0
  63. package/src/resources/extensions/kata/prompts/guided-discuss-milestone.md +3 -0
  64. package/src/resources/extensions/kata/prompts/guided-discuss-slice.md +59 -0
  65. package/src/resources/extensions/kata/prompts/guided-execute-task.md +1 -0
  66. package/src/resources/extensions/kata/prompts/guided-plan-milestone.md +23 -0
  67. package/src/resources/extensions/kata/prompts/guided-plan-slice.md +1 -0
  68. package/src/resources/extensions/kata/prompts/guided-research-slice.md +11 -0
  69. package/src/resources/extensions/kata/prompts/guided-resume-task.md +1 -0
  70. package/src/resources/extensions/kata/prompts/plan-milestone.md +47 -0
  71. package/src/resources/extensions/kata/prompts/plan-slice.md +63 -0
  72. package/src/resources/extensions/kata/prompts/queue.md +85 -0
  73. package/src/resources/extensions/kata/prompts/reassess-roadmap.md +48 -0
  74. package/src/resources/extensions/kata/prompts/replan-slice.md +39 -0
  75. package/src/resources/extensions/kata/prompts/research-milestone.md +37 -0
  76. package/src/resources/extensions/kata/prompts/research-slice.md +28 -0
  77. package/src/resources/extensions/kata/prompts/run-uat.md +109 -0
  78. package/src/resources/extensions/kata/prompts/system.md +341 -0
  79. package/src/resources/extensions/kata/session-forensics.ts +550 -0
  80. package/src/resources/extensions/kata/skill-discovery.ts +137 -0
  81. package/src/resources/extensions/kata/state.ts +509 -0
  82. package/src/resources/extensions/kata/templates/context.md +76 -0
  83. package/src/resources/extensions/kata/templates/decisions.md +8 -0
  84. package/src/resources/extensions/kata/templates/milestone-summary.md +73 -0
  85. package/src/resources/extensions/kata/templates/plan.md +133 -0
  86. package/src/resources/extensions/kata/templates/preferences.md +15 -0
  87. package/src/resources/extensions/kata/templates/project.md +31 -0
  88. package/src/resources/extensions/kata/templates/reassessment.md +28 -0
  89. package/src/resources/extensions/kata/templates/requirements.md +81 -0
  90. package/src/resources/extensions/kata/templates/research.md +46 -0
  91. package/src/resources/extensions/kata/templates/roadmap.md +118 -0
  92. package/src/resources/extensions/kata/templates/slice-context.md +58 -0
  93. package/src/resources/extensions/kata/templates/slice-summary.md +99 -0
  94. package/src/resources/extensions/kata/templates/state.md +19 -0
  95. package/src/resources/extensions/kata/templates/task-plan.md +52 -0
  96. package/src/resources/extensions/kata/templates/task-summary.md +57 -0
  97. package/src/resources/extensions/kata/templates/uat.md +54 -0
  98. package/src/resources/extensions/kata/tests/activity-log-prune.test.ts +327 -0
  99. package/src/resources/extensions/kata/tests/auto-preflight.test.ts +97 -0
  100. package/src/resources/extensions/kata/tests/auto-supervisor.test.mjs +53 -0
  101. package/src/resources/extensions/kata/tests/complete-milestone.test.ts +317 -0
  102. package/src/resources/extensions/kata/tests/cost-projection.test.ts +160 -0
  103. package/src/resources/extensions/kata/tests/derive-state-deps.test.ts +477 -0
  104. package/src/resources/extensions/kata/tests/derive-state.test.ts +1013 -0
  105. package/src/resources/extensions/kata/tests/doctor.test.ts +718 -0
  106. package/src/resources/extensions/kata/tests/idle-recovery.test.ts +490 -0
  107. package/src/resources/extensions/kata/tests/metrics-io.test.ts +254 -0
  108. package/src/resources/extensions/kata/tests/metrics.test.ts +217 -0
  109. package/src/resources/extensions/kata/tests/must-have-parser.test.ts +309 -0
  110. package/src/resources/extensions/kata/tests/parsers.test.ts +1257 -0
  111. package/src/resources/extensions/kata/tests/plan-milestone.test.ts +185 -0
  112. package/src/resources/extensions/kata/tests/plan-quality-validator.test.ts +386 -0
  113. package/src/resources/extensions/kata/tests/reassess-prompt.test.ts +208 -0
  114. package/src/resources/extensions/kata/tests/replan-slice.test.ts +686 -0
  115. package/src/resources/extensions/kata/tests/requirements.test.ts +151 -0
  116. package/src/resources/extensions/kata/tests/resolve-ts-hooks.mjs +17 -0
  117. package/src/resources/extensions/kata/tests/resolve-ts.mjs +11 -0
  118. package/src/resources/extensions/kata/tests/run-uat.test.ts +383 -0
  119. package/src/resources/extensions/kata/tests/unit-runtime.test.ts +388 -0
  120. package/src/resources/extensions/kata/tests/workspace-index.test.ts +118 -0
  121. package/src/resources/extensions/kata/tests/worktree.test.ts +222 -0
  122. package/src/resources/extensions/kata/types.ts +159 -0
  123. package/src/resources/extensions/kata/unit-runtime.ts +163 -0
  124. package/src/resources/extensions/kata/workspace-index.ts +203 -0
  125. package/src/resources/extensions/kata/worktree.ts +182 -0
  126. package/src/resources/extensions/mac-tools/index.ts +852 -0
  127. package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  128. package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  129. package/src/resources/extensions/search-the-web/cache.ts +78 -0
  130. package/src/resources/extensions/search-the-web/format.ts +258 -0
  131. package/src/resources/extensions/search-the-web/http.ts +238 -0
  132. package/src/resources/extensions/search-the-web/index.ts +68 -0
  133. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
  134. package/src/resources/extensions/search-the-web/tool-llm-context.ts +404 -0
  135. package/src/resources/extensions/search-the-web/tool-search.ts +503 -0
  136. package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
  137. package/src/resources/extensions/shared/confirm-ui.ts +126 -0
  138. package/src/resources/extensions/shared/interview-ui.ts +822 -0
  139. package/src/resources/extensions/shared/next-action-ui.ts +235 -0
  140. package/src/resources/extensions/shared/progress-widget.ts +282 -0
  141. package/src/resources/extensions/shared/thinking-widget.ts +107 -0
  142. package/src/resources/extensions/shared/ui.ts +400 -0
  143. package/src/resources/extensions/shared/wizard-ui.ts +551 -0
  144. package/src/resources/extensions/slash-commands/audit.ts +92 -0
  145. package/src/resources/extensions/slash-commands/create-extension.ts +375 -0
  146. package/src/resources/extensions/slash-commands/create-slash-command.ts +280 -0
  147. package/src/resources/extensions/slash-commands/index.ts +12 -0
  148. package/src/resources/extensions/slash-commands/kata-run.ts +34 -0
  149. package/src/resources/extensions/subagent/agents.ts +126 -0
  150. package/src/resources/extensions/subagent/index.ts +1293 -0
  151. package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
  152. package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  153. package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  154. package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  155. package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  156. package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  157. package/src/resources/skills/frontend-design/SKILL.md +45 -0
  158. package/src/resources/skills/swiftui/SKILL.md +208 -0
  159. package/src/resources/skills/swiftui/references/animations.md +921 -0
  160. package/src/resources/skills/swiftui/references/architecture.md +1561 -0
  161. package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
  162. package/src/resources/skills/swiftui/references/navigation.md +1492 -0
  163. package/src/resources/skills/swiftui/references/networking-async.md +214 -0
  164. package/src/resources/skills/swiftui/references/performance.md +1706 -0
  165. package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
  166. package/src/resources/skills/swiftui/references/state-management.md +1443 -0
  167. package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
  168. package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
  169. package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  170. package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
  171. package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  172. package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  173. package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  174. package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
  175. package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
  176. package/dist/commands/task.d.ts +0 -9
  177. package/dist/commands/task.d.ts.map +0 -1
  178. package/dist/commands/task.js +0 -129
  179. package/dist/commands/task.js.map +0 -1
  180. package/dist/commands/task.test.d.ts +0 -2
  181. package/dist/commands/task.test.d.ts.map +0 -1
  182. package/dist/commands/task.test.js +0 -169
  183. package/dist/commands/task.test.js.map +0 -1
  184. package/dist/e2e/task-e2e.test.d.ts +0 -2
  185. package/dist/e2e/task-e2e.test.d.ts.map +0 -1
  186. package/dist/e2e/task-e2e.test.js +0 -173
  187. package/dist/e2e/task-e2e.test.js.map +0 -1
  188. package/dist/index.d.ts +0 -3
  189. package/dist/index.d.ts.map +0 -1
  190. package/dist/index.js +0 -93
  191. package/dist/index.js.map +0 -1
  192. package/dist/slug.d.ts +0 -2
  193. package/dist/slug.d.ts.map +0 -1
  194. package/dist/slug.js +0 -12
  195. package/dist/slug.js.map +0 -1
  196. package/dist/slug.test.d.ts +0 -2
  197. package/dist/slug.test.d.ts.map +0 -1
  198. package/dist/slug.test.js +0 -32
  199. package/dist/slug.test.js.map +0 -1
@@ -0,0 +1,309 @@
1
+ import { parseTaskPlanMustHaves } from '../files.ts';
2
+
3
+ let passed = 0;
4
+ let failed = 0;
5
+
6
+ function assert(condition: boolean, message: string): void {
7
+ if (condition) passed++;
8
+ else {
9
+ failed++;
10
+ console.error(` FAIL: ${message}`);
11
+ }
12
+ }
13
+
14
+ function assertEq<T>(actual: T, expected: T, message: string): void {
15
+ if (JSON.stringify(actual) === JSON.stringify(expected)) passed++;
16
+ else {
17
+ failed++;
18
+ console.error(` FAIL: ${message} — expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
19
+ }
20
+ }
21
+
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+ // (a) Standard unchecked format: - [ ] text
24
+ // ═══════════════════════════════════════════════════════════════════════════
25
+
26
+ console.log('\n=== parseTaskPlanMustHaves: standard unchecked ===');
27
+ {
28
+ const content = `# T01: Test Task
29
+
30
+ ## Must-Haves
31
+
32
+ - [ ] First must-have item
33
+ - [ ] Second must-have item
34
+ `;
35
+ const result = parseTaskPlanMustHaves(content);
36
+ assertEq(result.length, 2, 'should return 2 items');
37
+ assertEq(result[0].text, 'First must-have item', 'first item text');
38
+ assertEq(result[0].checked, false, 'first item unchecked');
39
+ assertEq(result[1].text, 'Second must-have item', 'second item text');
40
+ assertEq(result[1].checked, false, 'second item unchecked');
41
+ }
42
+
43
+ // ═══════════════════════════════════════════════════════════════════════════
44
+ // (b) Checked variants: - [x] and - [X]
45
+ // ═══════════════════════════════════════════════════════════════════════════
46
+
47
+ console.log('\n=== parseTaskPlanMustHaves: checked [x] and [X] ===');
48
+ {
49
+ const content = `## Must-Haves
50
+
51
+ - [x] Lowercase checked item
52
+ - [X] Uppercase checked item
53
+ `;
54
+ const result = parseTaskPlanMustHaves(content);
55
+ assertEq(result.length, 2, 'should return 2 items');
56
+ assertEq(result[0].checked, true, 'lowercase x is checked');
57
+ assertEq(result[0].text, 'Lowercase checked item', 'lowercase x text');
58
+ assertEq(result[1].checked, true, 'uppercase X is checked');
59
+ assertEq(result[1].text, 'Uppercase checked item', 'uppercase X text');
60
+ }
61
+
62
+ // ═══════════════════════════════════════════════════════════════════════════
63
+ // (c) No-checkbox bullets: - text
64
+ // ═══════════════════════════════════════════════════════════════════════════
65
+
66
+ console.log('\n=== parseTaskPlanMustHaves: no-checkbox bullets ===');
67
+ {
68
+ const content = `## Must-Haves
69
+
70
+ - Plain bullet item
71
+ - Another plain item
72
+ `;
73
+ const result = parseTaskPlanMustHaves(content);
74
+ assertEq(result.length, 2, 'should return 2 items');
75
+ assertEq(result[0].text, 'Plain bullet item', 'plain bullet text');
76
+ assertEq(result[0].checked, false, 'plain bullet defaults to unchecked');
77
+ assertEq(result[1].text, 'Another plain item', 'second plain bullet text');
78
+ }
79
+
80
+ // ═══════════════════════════════════════════════════════════════════════════
81
+ // (d) Indented variants
82
+ // ═══════════════════════════════════════════════════════════════════════════
83
+
84
+ console.log('\n=== parseTaskPlanMustHaves: indented variants ===');
85
+ {
86
+ const content = `## Must-Haves
87
+
88
+ - [ ] Indented unchecked item
89
+ - [x] Indented checked item
90
+ - Plain indented item
91
+ `;
92
+ const result = parseTaskPlanMustHaves(content);
93
+ assertEq(result.length, 3, 'should return 3 items');
94
+ assertEq(result[0].text, 'Indented unchecked item', 'indented unchecked text');
95
+ assertEq(result[0].checked, false, 'indented unchecked state');
96
+ assertEq(result[1].text, 'Indented checked item', 'indented checked text');
97
+ assertEq(result[1].checked, true, 'indented checked state');
98
+ assertEq(result[2].text, 'Plain indented item', 'indented plain text');
99
+ assertEq(result[2].checked, false, 'indented plain state');
100
+ }
101
+
102
+ // ═══════════════════════════════════════════════════════════════════════════
103
+ // (e) Mixed checkbox states in one section
104
+ // ═══════════════════════════════════════════════════════════════════════════
105
+
106
+ console.log('\n=== parseTaskPlanMustHaves: mixed states ===');
107
+ {
108
+ const content = `## Must-Haves
109
+
110
+ - [ ] Unchecked one
111
+ - [x] Checked one
112
+ - [X] Also checked
113
+ - Plain bullet
114
+ - [ ] Another unchecked
115
+ `;
116
+ const result = parseTaskPlanMustHaves(content);
117
+ assertEq(result.length, 5, 'should return 5 items');
118
+ assertEq(result[0].checked, false, 'first is unchecked');
119
+ assertEq(result[1].checked, true, 'second is checked');
120
+ assertEq(result[2].checked, true, 'third is checked (uppercase)');
121
+ assertEq(result[3].checked, false, 'fourth (plain) is unchecked');
122
+ assertEq(result[4].checked, false, 'fifth is unchecked');
123
+ }
124
+
125
+ // ═══════════════════════════════════════════════════════════════════════════
126
+ // (f) Missing Must-Haves section → empty array
127
+ // ═══════════════════════════════════════════════════════════════════════════
128
+
129
+ console.log('\n=== parseTaskPlanMustHaves: missing section ===');
130
+ {
131
+ const content = `# T01: Some Task
132
+
133
+ ## Description
134
+
135
+ Some description here.
136
+
137
+ ## Verification
138
+
139
+ - Run tests
140
+ `;
141
+ const result = parseTaskPlanMustHaves(content);
142
+ assertEq(result.length, 0, 'returns empty array when section missing');
143
+ assert(Array.isArray(result), 'result is an array');
144
+ }
145
+
146
+ // ═══════════════════════════════════════════════════════════════════════════
147
+ // (g) Empty Must-Haves section → empty array
148
+ // ═══════════════════════════════════════════════════════════════════════════
149
+
150
+ console.log('\n=== parseTaskPlanMustHaves: empty section ===');
151
+ {
152
+ const content = `## Must-Haves
153
+
154
+ ## Verification
155
+
156
+ - Run tests
157
+ `;
158
+ const result = parseTaskPlanMustHaves(content);
159
+ assertEq(result.length, 0, 'returns empty array when section is empty');
160
+ }
161
+
162
+ // ═══════════════════════════════════════════════════════════════════════════
163
+ // (h) Content with YAML frontmatter
164
+ // ═══════════════════════════════════════════════════════════════════════════
165
+
166
+ console.log('\n=== parseTaskPlanMustHaves: YAML frontmatter ===');
167
+ {
168
+ const content = `---
169
+ estimated_steps: 5
170
+ estimated_files: 3
171
+ ---
172
+
173
+ # T01: Task with frontmatter
174
+
175
+ ## Must-Haves
176
+
177
+ - [ ] Real must-have after frontmatter
178
+ - [x] Checked must-have after frontmatter
179
+ `;
180
+ const result = parseTaskPlanMustHaves(content);
181
+ assertEq(result.length, 2, 'frontmatter does not pollute results');
182
+ assertEq(result[0].text, 'Real must-have after frontmatter', 'first item text correct');
183
+ assertEq(result[0].checked, false, 'first item unchecked');
184
+ assertEq(result[1].text, 'Checked must-have after frontmatter', 'second item text correct');
185
+ assertEq(result[1].checked, true, 'second item checked');
186
+ }
187
+
188
+ // Verify frontmatter content is not misinterpreted as must-haves
189
+ console.log('\n=== parseTaskPlanMustHaves: frontmatter-only content ===');
190
+ {
191
+ const content = `---
192
+ estimated_steps: 5
193
+ estimated_files: 3
194
+ ---
195
+
196
+ # T01: Task with only frontmatter
197
+
198
+ ## Description
199
+
200
+ No must-haves section here.
201
+ `;
202
+ const result = parseTaskPlanMustHaves(content);
203
+ assertEq(result.length, 0, 'frontmatter-only content returns empty array');
204
+ }
205
+
206
+ // ═══════════════════════════════════════════════════════════════════════════
207
+ // (i) Real task plan format (based on S01/T01-PLAN.md structure)
208
+ // ═══════════════════════════════════════════════════════════════════════════
209
+
210
+ console.log('\n=== parseTaskPlanMustHaves: real task plan format ===');
211
+ {
212
+ const content = `---
213
+ estimated_steps: 5
214
+ estimated_files: 3
215
+ ---
216
+
217
+ # T01: Add completing-milestone phase to deriveState with tests
218
+
219
+ **Slice:** S01 — Milestone Completion Unit
220
+ **Milestone:** M002
221
+
222
+ ## Description
223
+
224
+ Add the \`completing-milestone\` phase to the Kata state machine.
225
+
226
+ ## Steps
227
+
228
+ 1. Add \`'completing-milestone'\` to the \`Phase\` union type in \`types.ts\`.
229
+ 2. In \`state.ts\`, modify the registry-building loop.
230
+
231
+ ## Must-Haves
232
+
233
+ - [ ] \`Phase\` type includes \`'completing-milestone'\`
234
+ - [ ] \`deriveState\` returns \`phase: 'completing-milestone'\` when all slices are \`[x]\` and no \`M00x-SUMMARY.md\` exists
235
+ - [ ] \`deriveState\` returns milestone as \`'complete'\` and advances when summary exists
236
+ - [ ] All 63+ existing \`deriveState\` tests pass without modification
237
+ - [ ] New test fixtures cover single-milestone and multi-milestone completing-milestone scenarios
238
+
239
+ ## Verification
240
+
241
+ - Run tests
242
+ - All existing 63 assertions pass
243
+
244
+ ## Observability Impact
245
+
246
+ - Signals added/changed: \`completing-milestone\` phase now visible
247
+ - How a future agent inspects this: Run \`deriveState(basePath)\`
248
+ - Failure state exposed: If \`deriveState\` doesn't detect the phase
249
+
250
+ ## Inputs
251
+
252
+ - \`agent/extensions/kata/types.ts\` — Phase type definition
253
+
254
+ ## Expected Output
255
+
256
+ - \`agent/extensions/kata/types.ts\` — Phase union includes \`'completing-milestone'\`
257
+ `;
258
+ const result = parseTaskPlanMustHaves(content);
259
+ assertEq(result.length, 5, 'real plan has 5 must-haves');
260
+ assert(result[0].text.includes('`Phase` type includes'), 'first must-have text matches');
261
+ assert(result[1].text.includes('`deriveState` returns'), 'second must-have text matches');
262
+ assertEq(result[0].checked, false, 'all real must-haves are unchecked');
263
+ assertEq(result[4].checked, false, 'last real must-have is unchecked');
264
+ assert(result[4].text.includes('multi-milestone'), 'last must-have references multi-milestone');
265
+ }
266
+
267
+ // ═══════════════════════════════════════════════════════════════════════════
268
+ // Edge cases
269
+ // ═══════════════════════════════════════════════════════════════════════════
270
+
271
+ console.log('\n=== parseTaskPlanMustHaves: empty string ===');
272
+ {
273
+ const result = parseTaskPlanMustHaves('');
274
+ assertEq(result.length, 0, 'empty string returns empty array');
275
+ }
276
+
277
+ console.log('\n=== parseTaskPlanMustHaves: must-haves with inline code and backticks ===');
278
+ {
279
+ const content = `## Must-Haves
280
+
281
+ - [ ] \`functionName\` is exported from \`module.ts\`
282
+ - [x] Returns \`Array<{ text: string }>\` with correct extraction
283
+ `;
284
+ const result = parseTaskPlanMustHaves(content);
285
+ assertEq(result.length, 2, 'handles backtick content');
286
+ assert(result[0].text.includes('`functionName`'), 'preserves backticks in text');
287
+ assertEq(result[0].checked, false, 'backtick item unchecked');
288
+ assertEq(result[1].checked, true, 'backtick item checked');
289
+ }
290
+
291
+ console.log('\n=== parseTaskPlanMustHaves: asterisk bullets ===');
292
+ {
293
+ const content = `## Must-Haves
294
+
295
+ * [ ] Asterisk unchecked
296
+ * [x] Asterisk checked
297
+ * Plain asterisk
298
+ `;
299
+ const result = parseTaskPlanMustHaves(content);
300
+ assertEq(result.length, 3, 'handles asterisk bullets');
301
+ assertEq(result[0].checked, false, 'asterisk unchecked');
302
+ assertEq(result[1].checked, true, 'asterisk checked');
303
+ assertEq(result[2].checked, false, 'plain asterisk unchecked');
304
+ }
305
+
306
+ // ═══════════════════════════════════════════════════════════════════════════
307
+
308
+ console.log(`\n=== Results: ${passed} passed, ${failed} failed ===\n`);
309
+ process.exit(failed > 0 ? 1 : 0);