@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.
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/app-paths.d.ts +4 -0
- package/dist/app-paths.js +6 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +56 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +95 -0
- package/dist/resource-loader.d.ts +18 -0
- package/dist/resource-loader.js +50 -0
- package/dist/wizard.d.ts +15 -0
- package/dist/wizard.js +159 -0
- package/package.json +50 -21
- package/pkg/dist/modes/interactive/theme/dark.json +85 -0
- package/pkg/dist/modes/interactive/theme/light.json +84 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.js +949 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
- package/pkg/package.json +8 -0
- package/scripts/postinstall.js +45 -0
- package/src/resources/AGENTS.md +108 -0
- package/src/resources/KATA-WORKFLOW.md +661 -0
- package/src/resources/agents/researcher.md +29 -0
- package/src/resources/agents/scout.md +56 -0
- package/src/resources/agents/worker.md +31 -0
- package/src/resources/extensions/ask-user-questions.ts +200 -0
- package/src/resources/extensions/bg-shell/index.ts +2758 -0
- package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/src/resources/extensions/browser-tools/core.js +1057 -0
- package/src/resources/extensions/browser-tools/index.ts +4916 -0
- package/src/resources/extensions/browser-tools/package.json +20 -0
- package/src/resources/extensions/context7/index.ts +428 -0
- package/src/resources/extensions/context7/package.json +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +352 -0
- package/src/resources/extensions/github/formatters.ts +207 -0
- package/src/resources/extensions/github/gh-api.ts +537 -0
- package/src/resources/extensions/github/index.ts +778 -0
- package/src/resources/extensions/kata/activity-log.ts +88 -0
- package/src/resources/extensions/kata/auto.ts +2786 -0
- package/src/resources/extensions/kata/commands.ts +355 -0
- package/src/resources/extensions/kata/crash-recovery.ts +85 -0
- package/src/resources/extensions/kata/dashboard-overlay.ts +516 -0
- package/src/resources/extensions/kata/docs/preferences-reference.md +103 -0
- package/src/resources/extensions/kata/doctor.ts +683 -0
- package/src/resources/extensions/kata/files.ts +730 -0
- package/src/resources/extensions/kata/gitignore.ts +165 -0
- package/src/resources/extensions/kata/guided-flow.ts +976 -0
- package/src/resources/extensions/kata/index.ts +556 -0
- package/src/resources/extensions/kata/metrics.ts +397 -0
- package/src/resources/extensions/kata/observability-validator.ts +408 -0
- package/src/resources/extensions/kata/package.json +11 -0
- package/src/resources/extensions/kata/paths.ts +346 -0
- package/src/resources/extensions/kata/preferences.ts +695 -0
- package/src/resources/extensions/kata/prompt-loader.ts +50 -0
- package/src/resources/extensions/kata/prompts/complete-milestone.md +25 -0
- package/src/resources/extensions/kata/prompts/complete-slice.md +27 -0
- package/src/resources/extensions/kata/prompts/discuss.md +151 -0
- package/src/resources/extensions/kata/prompts/doctor-heal.md +29 -0
- package/src/resources/extensions/kata/prompts/execute-task.md +64 -0
- package/src/resources/extensions/kata/prompts/guided-complete-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-milestone.md +3 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-slice.md +59 -0
- package/src/resources/extensions/kata/prompts/guided-execute-task.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-plan-milestone.md +23 -0
- package/src/resources/extensions/kata/prompts/guided-plan-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-research-slice.md +11 -0
- package/src/resources/extensions/kata/prompts/guided-resume-task.md +1 -0
- package/src/resources/extensions/kata/prompts/plan-milestone.md +47 -0
- package/src/resources/extensions/kata/prompts/plan-slice.md +63 -0
- package/src/resources/extensions/kata/prompts/queue.md +85 -0
- package/src/resources/extensions/kata/prompts/reassess-roadmap.md +48 -0
- package/src/resources/extensions/kata/prompts/replan-slice.md +39 -0
- package/src/resources/extensions/kata/prompts/research-milestone.md +37 -0
- package/src/resources/extensions/kata/prompts/research-slice.md +28 -0
- package/src/resources/extensions/kata/prompts/run-uat.md +109 -0
- package/src/resources/extensions/kata/prompts/system.md +341 -0
- package/src/resources/extensions/kata/session-forensics.ts +550 -0
- package/src/resources/extensions/kata/skill-discovery.ts +137 -0
- package/src/resources/extensions/kata/state.ts +509 -0
- package/src/resources/extensions/kata/templates/context.md +76 -0
- package/src/resources/extensions/kata/templates/decisions.md +8 -0
- package/src/resources/extensions/kata/templates/milestone-summary.md +73 -0
- package/src/resources/extensions/kata/templates/plan.md +133 -0
- package/src/resources/extensions/kata/templates/preferences.md +15 -0
- package/src/resources/extensions/kata/templates/project.md +31 -0
- package/src/resources/extensions/kata/templates/reassessment.md +28 -0
- package/src/resources/extensions/kata/templates/requirements.md +81 -0
- package/src/resources/extensions/kata/templates/research.md +46 -0
- package/src/resources/extensions/kata/templates/roadmap.md +118 -0
- package/src/resources/extensions/kata/templates/slice-context.md +58 -0
- package/src/resources/extensions/kata/templates/slice-summary.md +99 -0
- package/src/resources/extensions/kata/templates/state.md +19 -0
- package/src/resources/extensions/kata/templates/task-plan.md +52 -0
- package/src/resources/extensions/kata/templates/task-summary.md +57 -0
- package/src/resources/extensions/kata/templates/uat.md +54 -0
- package/src/resources/extensions/kata/tests/activity-log-prune.test.ts +327 -0
- package/src/resources/extensions/kata/tests/auto-preflight.test.ts +97 -0
- package/src/resources/extensions/kata/tests/auto-supervisor.test.mjs +53 -0
- package/src/resources/extensions/kata/tests/complete-milestone.test.ts +317 -0
- package/src/resources/extensions/kata/tests/cost-projection.test.ts +160 -0
- package/src/resources/extensions/kata/tests/derive-state-deps.test.ts +477 -0
- package/src/resources/extensions/kata/tests/derive-state.test.ts +1013 -0
- package/src/resources/extensions/kata/tests/doctor.test.ts +718 -0
- package/src/resources/extensions/kata/tests/idle-recovery.test.ts +490 -0
- package/src/resources/extensions/kata/tests/metrics-io.test.ts +254 -0
- package/src/resources/extensions/kata/tests/metrics.test.ts +217 -0
- package/src/resources/extensions/kata/tests/must-have-parser.test.ts +309 -0
- package/src/resources/extensions/kata/tests/parsers.test.ts +1257 -0
- package/src/resources/extensions/kata/tests/plan-milestone.test.ts +185 -0
- package/src/resources/extensions/kata/tests/plan-quality-validator.test.ts +386 -0
- package/src/resources/extensions/kata/tests/reassess-prompt.test.ts +208 -0
- package/src/resources/extensions/kata/tests/replan-slice.test.ts +686 -0
- package/src/resources/extensions/kata/tests/requirements.test.ts +151 -0
- package/src/resources/extensions/kata/tests/resolve-ts-hooks.mjs +17 -0
- package/src/resources/extensions/kata/tests/resolve-ts.mjs +11 -0
- package/src/resources/extensions/kata/tests/run-uat.test.ts +383 -0
- package/src/resources/extensions/kata/tests/unit-runtime.test.ts +388 -0
- package/src/resources/extensions/kata/tests/workspace-index.test.ts +118 -0
- package/src/resources/extensions/kata/tests/worktree.test.ts +222 -0
- package/src/resources/extensions/kata/types.ts +159 -0
- package/src/resources/extensions/kata/unit-runtime.ts +163 -0
- package/src/resources/extensions/kata/workspace-index.ts +203 -0
- package/src/resources/extensions/kata/worktree.ts +182 -0
- package/src/resources/extensions/mac-tools/index.ts +852 -0
- package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/src/resources/extensions/search-the-web/cache.ts +78 -0
- package/src/resources/extensions/search-the-web/format.ts +258 -0
- package/src/resources/extensions/search-the-web/http.ts +238 -0
- package/src/resources/extensions/search-the-web/index.ts +68 -0
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +404 -0
- package/src/resources/extensions/search-the-web/tool-search.ts +503 -0
- package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/src/resources/extensions/shared/confirm-ui.ts +126 -0
- package/src/resources/extensions/shared/interview-ui.ts +822 -0
- package/src/resources/extensions/shared/next-action-ui.ts +235 -0
- package/src/resources/extensions/shared/progress-widget.ts +282 -0
- package/src/resources/extensions/shared/thinking-widget.ts +107 -0
- package/src/resources/extensions/shared/ui.ts +400 -0
- package/src/resources/extensions/shared/wizard-ui.ts +551 -0
- package/src/resources/extensions/slash-commands/audit.ts +92 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +375 -0
- package/src/resources/extensions/slash-commands/create-slash-command.ts +280 -0
- package/src/resources/extensions/slash-commands/index.ts +12 -0
- package/src/resources/extensions/slash-commands/kata-run.ts +34 -0
- package/src/resources/extensions/subagent/agents.ts +126 -0
- package/src/resources/extensions/subagent/index.ts +1293 -0
- package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/src/resources/skills/frontend-design/SKILL.md +45 -0
- package/src/resources/skills/swiftui/SKILL.md +208 -0
- package/src/resources/skills/swiftui/references/animations.md +921 -0
- package/src/resources/skills/swiftui/references/architecture.md +1561 -0
- package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/src/resources/skills/swiftui/references/navigation.md +1492 -0
- package/src/resources/skills/swiftui/references/networking-async.md +214 -0
- package/src/resources/skills/swiftui/references/performance.md +1706 -0
- package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/src/resources/skills/swiftui/references/state-management.md +1443 -0
- package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
- package/dist/commands/task.d.ts +0 -9
- package/dist/commands/task.d.ts.map +0 -1
- package/dist/commands/task.js +0 -129
- package/dist/commands/task.js.map +0 -1
- package/dist/commands/task.test.d.ts +0 -2
- package/dist/commands/task.test.d.ts.map +0 -1
- package/dist/commands/task.test.js +0 -169
- package/dist/commands/task.test.js.map +0 -1
- package/dist/e2e/task-e2e.test.d.ts +0 -2
- package/dist/e2e/task-e2e.test.d.ts.map +0 -1
- package/dist/e2e/task-e2e.test.js +0 -173
- package/dist/e2e/task-e2e.test.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -93
- package/dist/index.js.map +0 -1
- package/dist/slug.d.ts +0 -2
- package/dist/slug.d.ts.map +0 -1
- package/dist/slug.js +0 -12
- package/dist/slug.js.map +0 -1
- package/dist/slug.test.d.ts +0 -2
- package/dist/slug.test.d.ts.map +0 -1
- package/dist/slug.test.js +0 -32
- package/dist/slug.test.js.map +0 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mkdtempSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
rmSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
existsSync,
|
|
8
|
+
} from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import {
|
|
12
|
+
resolveExpectedArtifactPath,
|
|
13
|
+
writeBlockerPlaceholder,
|
|
14
|
+
skipExecuteTask,
|
|
15
|
+
} from "../auto.ts";
|
|
16
|
+
|
|
17
|
+
let passed = 0;
|
|
18
|
+
let failed = 0;
|
|
19
|
+
|
|
20
|
+
function assert(condition: boolean, message: string): void {
|
|
21
|
+
if (condition) passed++;
|
|
22
|
+
else {
|
|
23
|
+
failed++;
|
|
24
|
+
console.error(` FAIL: ${message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function assertEq<T>(actual: T, expected: T, message: string): void {
|
|
29
|
+
if (JSON.stringify(actual) === JSON.stringify(expected)) passed++;
|
|
30
|
+
else {
|
|
31
|
+
failed++;
|
|
32
|
+
console.error(
|
|
33
|
+
` FAIL: ${message} — expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createFixtureBase(): string {
|
|
39
|
+
const base = mkdtempSync(join(tmpdir(), "kata-idle-recovery-test-"));
|
|
40
|
+
mkdirSync(
|
|
41
|
+
join(base, ".kata", "milestones", "M001", "slices", "S01", "tasks"),
|
|
42
|
+
{ recursive: true },
|
|
43
|
+
);
|
|
44
|
+
return base;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function cleanup(base: string): void {
|
|
48
|
+
rmSync(base, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ═══ resolveExpectedArtifactPath ═════════════════════════════════════════════
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
console.log("\n=== resolveExpectedArtifactPath: research-milestone ===");
|
|
55
|
+
const base = createFixtureBase();
|
|
56
|
+
try {
|
|
57
|
+
const result = resolveExpectedArtifactPath(
|
|
58
|
+
"research-milestone",
|
|
59
|
+
"M001",
|
|
60
|
+
base,
|
|
61
|
+
);
|
|
62
|
+
assert(result !== null, "should resolve a path");
|
|
63
|
+
assert(
|
|
64
|
+
result!.endsWith("M001-RESEARCH.md"),
|
|
65
|
+
`path should end with M001-RESEARCH.md, got ${result}`,
|
|
66
|
+
);
|
|
67
|
+
} finally {
|
|
68
|
+
cleanup(base);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
console.log("\n=== resolveExpectedArtifactPath: plan-milestone ===");
|
|
74
|
+
const base = createFixtureBase();
|
|
75
|
+
try {
|
|
76
|
+
const result = resolveExpectedArtifactPath("plan-milestone", "M001", base);
|
|
77
|
+
assert(result !== null, "should resolve a path");
|
|
78
|
+
assert(
|
|
79
|
+
result!.endsWith("M001-ROADMAP.md"),
|
|
80
|
+
`path should end with M001-ROADMAP.md, got ${result}`,
|
|
81
|
+
);
|
|
82
|
+
} finally {
|
|
83
|
+
cleanup(base);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
{
|
|
88
|
+
console.log("\n=== resolveExpectedArtifactPath: research-slice ===");
|
|
89
|
+
const base = createFixtureBase();
|
|
90
|
+
try {
|
|
91
|
+
const result = resolveExpectedArtifactPath(
|
|
92
|
+
"research-slice",
|
|
93
|
+
"M001/S01",
|
|
94
|
+
base,
|
|
95
|
+
);
|
|
96
|
+
assert(result !== null, "should resolve a path");
|
|
97
|
+
assert(
|
|
98
|
+
result!.endsWith("S01-RESEARCH.md"),
|
|
99
|
+
`path should end with S01-RESEARCH.md, got ${result}`,
|
|
100
|
+
);
|
|
101
|
+
} finally {
|
|
102
|
+
cleanup(base);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
console.log("\n=== resolveExpectedArtifactPath: plan-slice ===");
|
|
108
|
+
const base = createFixtureBase();
|
|
109
|
+
try {
|
|
110
|
+
const result = resolveExpectedArtifactPath("plan-slice", "M001/S01", base);
|
|
111
|
+
assert(result !== null, "should resolve a path");
|
|
112
|
+
assert(
|
|
113
|
+
result!.endsWith("S01-PLAN.md"),
|
|
114
|
+
`path should end with S01-PLAN.md, got ${result}`,
|
|
115
|
+
);
|
|
116
|
+
} finally {
|
|
117
|
+
cleanup(base);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
console.log("\n=== resolveExpectedArtifactPath: complete-milestone ===");
|
|
123
|
+
const base = createFixtureBase();
|
|
124
|
+
try {
|
|
125
|
+
const result = resolveExpectedArtifactPath(
|
|
126
|
+
"complete-milestone",
|
|
127
|
+
"M001",
|
|
128
|
+
base,
|
|
129
|
+
);
|
|
130
|
+
assert(result !== null, "should resolve a path");
|
|
131
|
+
assert(
|
|
132
|
+
result!.endsWith("M001-SUMMARY.md"),
|
|
133
|
+
`path should end with M001-SUMMARY.md, got ${result}`,
|
|
134
|
+
);
|
|
135
|
+
} finally {
|
|
136
|
+
cleanup(base);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
{
|
|
141
|
+
console.log(
|
|
142
|
+
"\n=== resolveExpectedArtifactPath: unknown unit type → null ===",
|
|
143
|
+
);
|
|
144
|
+
const base = createFixtureBase();
|
|
145
|
+
try {
|
|
146
|
+
const result = resolveExpectedArtifactPath(
|
|
147
|
+
"unknown-type",
|
|
148
|
+
"M001/S01",
|
|
149
|
+
base,
|
|
150
|
+
);
|
|
151
|
+
assertEq(result, null, "unknown type returns null");
|
|
152
|
+
} finally {
|
|
153
|
+
cleanup(base);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ═══ writeBlockerPlaceholder ═════════════════════════════════════════════════
|
|
158
|
+
|
|
159
|
+
{
|
|
160
|
+
console.log(
|
|
161
|
+
"\n=== writeBlockerPlaceholder: writes file for research-slice ===",
|
|
162
|
+
);
|
|
163
|
+
const base = createFixtureBase();
|
|
164
|
+
try {
|
|
165
|
+
const result = writeBlockerPlaceholder(
|
|
166
|
+
"research-slice",
|
|
167
|
+
"M001/S01",
|
|
168
|
+
base,
|
|
169
|
+
"idle recovery exhausted 2 attempts",
|
|
170
|
+
);
|
|
171
|
+
assert(result !== null, "should return relative path");
|
|
172
|
+
const absPath = resolveExpectedArtifactPath(
|
|
173
|
+
"research-slice",
|
|
174
|
+
"M001/S01",
|
|
175
|
+
base,
|
|
176
|
+
)!;
|
|
177
|
+
assert(existsSync(absPath), "file should exist on disk");
|
|
178
|
+
const content = readFileSync(absPath, "utf-8");
|
|
179
|
+
assert(content.includes("BLOCKER"), "should contain BLOCKER heading");
|
|
180
|
+
assert(
|
|
181
|
+
content.includes("idle recovery exhausted 2 attempts"),
|
|
182
|
+
"should contain the reason",
|
|
183
|
+
);
|
|
184
|
+
assert(content.includes("research-slice"), "should mention the unit type");
|
|
185
|
+
assert(content.includes("M001/S01"), "should mention the unit ID");
|
|
186
|
+
} finally {
|
|
187
|
+
cleanup(base);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
{
|
|
192
|
+
console.log(
|
|
193
|
+
"\n=== writeBlockerPlaceholder: creates directory if missing ===",
|
|
194
|
+
);
|
|
195
|
+
const base = mkdtempSync(join(tmpdir(), "kata-idle-recovery-test-"));
|
|
196
|
+
try {
|
|
197
|
+
// Only create milestone dir, not slice dir
|
|
198
|
+
mkdirSync(join(base, ".kata", "milestones", "M001"), { recursive: true });
|
|
199
|
+
// resolveSlicePath needs the slice dir to exist to resolve, so this should return null
|
|
200
|
+
const result = writeBlockerPlaceholder(
|
|
201
|
+
"research-slice",
|
|
202
|
+
"M001/S01",
|
|
203
|
+
base,
|
|
204
|
+
"test reason",
|
|
205
|
+
);
|
|
206
|
+
// Since the slice dir doesn't exist, resolveExpectedArtifactPath returns null
|
|
207
|
+
assertEq(
|
|
208
|
+
result,
|
|
209
|
+
null,
|
|
210
|
+
"returns null when directory structure doesn't exist",
|
|
211
|
+
);
|
|
212
|
+
} finally {
|
|
213
|
+
cleanup(base);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
{
|
|
218
|
+
console.log(
|
|
219
|
+
"\n=== writeBlockerPlaceholder: writes file for research-milestone ===",
|
|
220
|
+
);
|
|
221
|
+
const base = createFixtureBase();
|
|
222
|
+
try {
|
|
223
|
+
const result = writeBlockerPlaceholder(
|
|
224
|
+
"research-milestone",
|
|
225
|
+
"M001",
|
|
226
|
+
base,
|
|
227
|
+
"hard timeout",
|
|
228
|
+
);
|
|
229
|
+
assert(result !== null, "should return relative path");
|
|
230
|
+
const absPath = resolveExpectedArtifactPath(
|
|
231
|
+
"research-milestone",
|
|
232
|
+
"M001",
|
|
233
|
+
base,
|
|
234
|
+
)!;
|
|
235
|
+
assert(existsSync(absPath), "file should exist on disk");
|
|
236
|
+
const content = readFileSync(absPath, "utf-8");
|
|
237
|
+
assert(content.includes("BLOCKER"), "should contain BLOCKER heading");
|
|
238
|
+
assert(content.includes("hard timeout"), "should contain the reason");
|
|
239
|
+
} finally {
|
|
240
|
+
cleanup(base);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
console.log("\n=== writeBlockerPlaceholder: unknown type → null ===");
|
|
246
|
+
const base = createFixtureBase();
|
|
247
|
+
try {
|
|
248
|
+
const result = writeBlockerPlaceholder(
|
|
249
|
+
"execute-task",
|
|
250
|
+
"M001/S01/T01",
|
|
251
|
+
base,
|
|
252
|
+
"test",
|
|
253
|
+
);
|
|
254
|
+
assertEq(
|
|
255
|
+
result,
|
|
256
|
+
null,
|
|
257
|
+
"execute-task has no single artifact path, returns null",
|
|
258
|
+
);
|
|
259
|
+
} finally {
|
|
260
|
+
cleanup(base);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ═══ skipExecuteTask ═════════════════════════════════════════════════════════
|
|
265
|
+
|
|
266
|
+
{
|
|
267
|
+
console.log(
|
|
268
|
+
"\n=== skipExecuteTask: writes summary and checks plan checkbox ===",
|
|
269
|
+
);
|
|
270
|
+
const base = createFixtureBase();
|
|
271
|
+
try {
|
|
272
|
+
const planPath = join(
|
|
273
|
+
base,
|
|
274
|
+
".kata",
|
|
275
|
+
"milestones",
|
|
276
|
+
"M001",
|
|
277
|
+
"slices",
|
|
278
|
+
"S01",
|
|
279
|
+
"S01-PLAN.md",
|
|
280
|
+
);
|
|
281
|
+
writeFileSync(
|
|
282
|
+
planPath,
|
|
283
|
+
[
|
|
284
|
+
"# S01: Test Slice",
|
|
285
|
+
"",
|
|
286
|
+
"## Tasks",
|
|
287
|
+
"",
|
|
288
|
+
"- [ ] **T01: First task** `est:10m`",
|
|
289
|
+
" Do the first thing.",
|
|
290
|
+
"- [ ] **T02: Second task** `est:15m`",
|
|
291
|
+
" Do the second thing.",
|
|
292
|
+
].join("\n"),
|
|
293
|
+
"utf-8",
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const result = skipExecuteTask(
|
|
297
|
+
base,
|
|
298
|
+
"M001",
|
|
299
|
+
"S01",
|
|
300
|
+
"T01",
|
|
301
|
+
{ summaryExists: false, taskChecked: false },
|
|
302
|
+
"idle",
|
|
303
|
+
2,
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
assert(result === true, "should return true");
|
|
307
|
+
|
|
308
|
+
// Check summary was written
|
|
309
|
+
const summaryPath = join(
|
|
310
|
+
base,
|
|
311
|
+
".kata",
|
|
312
|
+
"milestones",
|
|
313
|
+
"M001",
|
|
314
|
+
"slices",
|
|
315
|
+
"S01",
|
|
316
|
+
"tasks",
|
|
317
|
+
"T01-SUMMARY.md",
|
|
318
|
+
);
|
|
319
|
+
assert(existsSync(summaryPath), "task summary should exist");
|
|
320
|
+
const summaryContent = readFileSync(summaryPath, "utf-8");
|
|
321
|
+
assert(
|
|
322
|
+
summaryContent.includes("BLOCKER"),
|
|
323
|
+
"summary should contain BLOCKER",
|
|
324
|
+
);
|
|
325
|
+
assert(summaryContent.includes("T01"), "summary should mention task ID");
|
|
326
|
+
|
|
327
|
+
// Check plan checkbox was marked
|
|
328
|
+
const planContent = readFileSync(planPath, "utf-8");
|
|
329
|
+
assert(planContent.includes("- [x] **T01:"), "T01 should be checked");
|
|
330
|
+
assert(planContent.includes("- [ ] **T02:"), "T02 should remain unchecked");
|
|
331
|
+
} finally {
|
|
332
|
+
cleanup(base);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
{
|
|
337
|
+
console.log("\n=== skipExecuteTask: skips summary if already exists ===");
|
|
338
|
+
const base = createFixtureBase();
|
|
339
|
+
try {
|
|
340
|
+
const planPath = join(
|
|
341
|
+
base,
|
|
342
|
+
".kata",
|
|
343
|
+
"milestones",
|
|
344
|
+
"M001",
|
|
345
|
+
"slices",
|
|
346
|
+
"S01",
|
|
347
|
+
"S01-PLAN.md",
|
|
348
|
+
);
|
|
349
|
+
writeFileSync(planPath, "- [ ] **T01: Task** `est:10m`\n", "utf-8");
|
|
350
|
+
|
|
351
|
+
// Pre-write a summary
|
|
352
|
+
const summaryPath = join(
|
|
353
|
+
base,
|
|
354
|
+
".kata",
|
|
355
|
+
"milestones",
|
|
356
|
+
"M001",
|
|
357
|
+
"slices",
|
|
358
|
+
"S01",
|
|
359
|
+
"tasks",
|
|
360
|
+
"T01-SUMMARY.md",
|
|
361
|
+
);
|
|
362
|
+
writeFileSync(summaryPath, "# Real summary\nActual work done.", "utf-8");
|
|
363
|
+
|
|
364
|
+
const result = skipExecuteTask(
|
|
365
|
+
base,
|
|
366
|
+
"M001",
|
|
367
|
+
"S01",
|
|
368
|
+
"T01",
|
|
369
|
+
{ summaryExists: true, taskChecked: false },
|
|
370
|
+
"idle",
|
|
371
|
+
2,
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
assert(result === true, "should return true");
|
|
375
|
+
|
|
376
|
+
// Summary should be untouched (not overwritten with blocker)
|
|
377
|
+
const content = readFileSync(summaryPath, "utf-8");
|
|
378
|
+
assert(
|
|
379
|
+
content.includes("Real summary"),
|
|
380
|
+
"original summary should be preserved",
|
|
381
|
+
);
|
|
382
|
+
assert(!content.includes("BLOCKER"), "should not contain BLOCKER");
|
|
383
|
+
|
|
384
|
+
// Plan checkbox should still be marked
|
|
385
|
+
const planContent = readFileSync(planPath, "utf-8");
|
|
386
|
+
assert(planContent.includes("- [x] **T01:"), "T01 should be checked");
|
|
387
|
+
} finally {
|
|
388
|
+
cleanup(base);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
{
|
|
393
|
+
console.log("\n=== skipExecuteTask: skips checkbox if already checked ===");
|
|
394
|
+
const base = createFixtureBase();
|
|
395
|
+
try {
|
|
396
|
+
const planPath = join(
|
|
397
|
+
base,
|
|
398
|
+
".kata",
|
|
399
|
+
"milestones",
|
|
400
|
+
"M001",
|
|
401
|
+
"slices",
|
|
402
|
+
"S01",
|
|
403
|
+
"S01-PLAN.md",
|
|
404
|
+
);
|
|
405
|
+
writeFileSync(planPath, "- [x] **T01: Task** `est:10m`\n", "utf-8");
|
|
406
|
+
|
|
407
|
+
const result = skipExecuteTask(
|
|
408
|
+
base,
|
|
409
|
+
"M001",
|
|
410
|
+
"S01",
|
|
411
|
+
"T01",
|
|
412
|
+
{ summaryExists: false, taskChecked: true },
|
|
413
|
+
"idle",
|
|
414
|
+
2,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
assert(result === true, "should return true");
|
|
418
|
+
|
|
419
|
+
// Summary should be written (since summaryExists was false)
|
|
420
|
+
const summaryPath = join(
|
|
421
|
+
base,
|
|
422
|
+
".kata",
|
|
423
|
+
"milestones",
|
|
424
|
+
"M001",
|
|
425
|
+
"slices",
|
|
426
|
+
"S01",
|
|
427
|
+
"tasks",
|
|
428
|
+
"T01-SUMMARY.md",
|
|
429
|
+
);
|
|
430
|
+
assert(existsSync(summaryPath), "task summary should exist");
|
|
431
|
+
|
|
432
|
+
// Plan checkbox should be untouched
|
|
433
|
+
const planContent = readFileSync(planPath, "utf-8");
|
|
434
|
+
assert(planContent.includes("- [x] **T01:"), "T01 should remain checked");
|
|
435
|
+
} finally {
|
|
436
|
+
cleanup(base);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
{
|
|
441
|
+
console.log(
|
|
442
|
+
"\n=== skipExecuteTask: handles special regex chars in task ID ===",
|
|
443
|
+
);
|
|
444
|
+
const base = createFixtureBase();
|
|
445
|
+
try {
|
|
446
|
+
const planPath = join(
|
|
447
|
+
base,
|
|
448
|
+
".kata",
|
|
449
|
+
"milestones",
|
|
450
|
+
"M001",
|
|
451
|
+
"slices",
|
|
452
|
+
"S01",
|
|
453
|
+
"S01-PLAN.md",
|
|
454
|
+
);
|
|
455
|
+
writeFileSync(planPath, "- [ ] **T01.1: Sub-task** `est:10m`\n", "utf-8");
|
|
456
|
+
|
|
457
|
+
const result = skipExecuteTask(
|
|
458
|
+
base,
|
|
459
|
+
"M001",
|
|
460
|
+
"S01",
|
|
461
|
+
"T01.1",
|
|
462
|
+
{ summaryExists: false, taskChecked: false },
|
|
463
|
+
"idle",
|
|
464
|
+
2,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
assert(result === true, "should return true");
|
|
468
|
+
|
|
469
|
+
const planContent = readFileSync(planPath, "utf-8");
|
|
470
|
+
assert(
|
|
471
|
+
planContent.includes("- [x] **T01.1:"),
|
|
472
|
+
"T01.1 should be checked (regex chars escaped)",
|
|
473
|
+
);
|
|
474
|
+
} finally {
|
|
475
|
+
cleanup(base);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
480
|
+
// Results
|
|
481
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
482
|
+
|
|
483
|
+
console.log(`\n${"=".repeat(40)}`);
|
|
484
|
+
if (failed > 0) {
|
|
485
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
486
|
+
process.exit(1);
|
|
487
|
+
} else {
|
|
488
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
489
|
+
console.log("All tests passed ✓");
|
|
490
|
+
}
|