@kkelly-offical/kkcode 0.1.7 → 0.2.3-preview.1

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 (166) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +474 -387
  3. package/package.json +50 -46
  4. package/src/agent/agent.mjs +228 -220
  5. package/src/agent/custom-agent-loader.mjs +6 -3
  6. package/src/agent/generator.mjs +2 -2
  7. package/src/agent/prompt/assistant.txt +12 -0
  8. package/src/agent/prompt/bug-hunter.txt +89 -89
  9. package/src/agent/prompt/frontend-designer.txt +58 -58
  10. package/src/agent/prompt/guide.txt +1 -1
  11. package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
  12. package/src/agent/prompt/longagent-coding-agent.txt +37 -37
  13. package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
  14. package/src/agent/prompt/longagent-preview-agent.txt +63 -63
  15. package/src/command/custom-commands.mjs +2 -2
  16. package/src/commands/agent.mjs +1 -1
  17. package/src/commands/background.mjs +145 -4
  18. package/src/commands/chat.mjs +117 -76
  19. package/src/commands/config.mjs +148 -1
  20. package/src/commands/doctor.mjs +30 -6
  21. package/src/commands/init.mjs +32 -6
  22. package/src/commands/longagent.mjs +117 -0
  23. package/src/commands/mcp.mjs +275 -43
  24. package/src/commands/permission.mjs +1 -1
  25. package/src/commands/session.mjs +195 -140
  26. package/src/commands/skill.mjs +63 -0
  27. package/src/commands/theme.mjs +1 -1
  28. package/src/commands/update.mjs +32 -0
  29. package/src/config/defaults.mjs +289 -260
  30. package/src/config/import-config.mjs +1 -1
  31. package/src/config/load-config.mjs +61 -4
  32. package/src/config/schema.mjs +604 -574
  33. package/src/context.mjs +4 -1
  34. package/src/core/constants.mjs +97 -91
  35. package/src/core/types.mjs +1 -1
  36. package/src/github/api.mjs +78 -78
  37. package/src/github/auth.mjs +294 -286
  38. package/src/github/flow.mjs +298 -298
  39. package/src/github/workspace.mjs +225 -212
  40. package/src/index.mjs +87 -82
  41. package/src/knowledge/frontend-aesthetics.txt +38 -38
  42. package/src/mcp/client-http.mjs +139 -141
  43. package/src/mcp/client-sse.mjs +297 -288
  44. package/src/mcp/client-stdio.mjs +534 -533
  45. package/src/mcp/constants.mjs +4 -2
  46. package/src/mcp/registry.mjs +498 -479
  47. package/src/mcp/stdio-framing.mjs +135 -133
  48. package/src/mcp/tool-result.mjs +24 -24
  49. package/src/observability/edit-diagnostics.mjs +449 -0
  50. package/src/observability/index.mjs +42 -42
  51. package/src/observability/metrics.mjs +165 -137
  52. package/src/observability/tracer.mjs +137 -137
  53. package/src/onboarding.mjs +209 -0
  54. package/src/orchestration/background-manager.mjs +567 -372
  55. package/src/orchestration/background-worker.mjs +419 -305
  56. package/src/orchestration/interruption-reason.mjs +21 -0
  57. package/src/orchestration/longagent-manager.mjs +197 -171
  58. package/src/orchestration/stage-scheduler.mjs +733 -728
  59. package/src/orchestration/subagent-router.mjs +7 -1
  60. package/src/orchestration/task-scheduler.mjs +219 -7
  61. package/src/permission/engine.mjs +1 -1
  62. package/src/permission/exec-policy.mjs +370 -370
  63. package/src/permission/file-edit-policy.mjs +108 -0
  64. package/src/permission/prompt.mjs +1 -1
  65. package/src/permission/rules.mjs +116 -7
  66. package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
  67. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
  68. package/src/plugin/hook-bus.mjs +19 -5
  69. package/src/plugin/manifest-loader.mjs +222 -0
  70. package/src/provider/anthropic.mjs +396 -390
  71. package/src/provider/ollama.mjs +7 -1
  72. package/src/provider/openai.mjs +382 -340
  73. package/src/provider/retry-policy.mjs +74 -68
  74. package/src/provider/router.mjs +242 -241
  75. package/src/provider/sse.mjs +104 -104
  76. package/src/provider/wizard.mjs +556 -0
  77. package/src/repl/capability-facade.mjs +30 -0
  78. package/src/repl/command-surface.mjs +23 -0
  79. package/src/repl/controller-entry.mjs +40 -0
  80. package/src/repl/core-shell.mjs +208 -0
  81. package/src/repl/dialog-router.mjs +87 -0
  82. package/src/repl/input-engine.mjs +76 -0
  83. package/src/repl/keymap.mjs +7 -0
  84. package/src/repl/operator-surface.mjs +15 -0
  85. package/src/repl/permission-flow.mjs +49 -0
  86. package/src/repl/runtime-facade.mjs +36 -0
  87. package/src/repl/slash-router.mjs +62 -0
  88. package/src/repl/state-store.mjs +29 -0
  89. package/src/repl/turn-controller.mjs +58 -0
  90. package/src/repl/verification.mjs +23 -0
  91. package/src/repl.mjs +3371 -2981
  92. package/src/rules/load-rules.mjs +3 -3
  93. package/src/runtime.mjs +1 -1
  94. package/src/session/agent-transaction.mjs +86 -0
  95. package/src/session/checkpoint.mjs +302 -302
  96. package/src/session/compaction.mjs +298 -298
  97. package/src/session/engine.mjs +417 -232
  98. package/src/session/longagent-4stage.mjs +467 -460
  99. package/src/session/longagent-hybrid.mjs +1344 -1097
  100. package/src/session/longagent-plan.mjs +376 -365
  101. package/src/session/longagent-project-memory.mjs +53 -53
  102. package/src/session/longagent-scaffold.mjs +291 -291
  103. package/src/session/longagent-task-bus.mjs +138 -54
  104. package/src/session/longagent-utils.mjs +828 -472
  105. package/src/session/longagent.mjs +911 -900
  106. package/src/session/loop.mjs +1005 -930
  107. package/src/session/prompt/agent.txt +25 -25
  108. package/src/session/prompt/anthropic.txt +150 -150
  109. package/src/session/prompt/beast.txt +1 -1
  110. package/src/session/prompt/plan.txt +31 -31
  111. package/src/session/prompt/qwen.txt +46 -46
  112. package/src/session/recovery.mjs +21 -0
  113. package/src/session/rollback.mjs +196 -195
  114. package/src/session/routing-observability.mjs +72 -0
  115. package/src/session/runtime-state.mjs +47 -0
  116. package/src/session/store.mjs +523 -519
  117. package/src/session/system-prompt.mjs +308 -273
  118. package/src/session/task-validator.mjs +267 -267
  119. package/src/session/usability-gates.mjs +2 -2
  120. package/src/skill/builtin/commit.mjs +64 -64
  121. package/src/skill/builtin/design.mjs +76 -76
  122. package/src/skill/generator.mjs +18 -2
  123. package/src/skill/registry.mjs +642 -390
  124. package/src/storage/audit-store.mjs +18 -11
  125. package/src/storage/event-log.mjs +7 -1
  126. package/src/storage/ghost-commit-store.mjs +243 -245
  127. package/src/storage/paths.mjs +17 -0
  128. package/src/theme/default-theme.mjs +1 -1
  129. package/src/theme/markdown.mjs +4 -0
  130. package/src/theme/schema.mjs +1 -1
  131. package/src/theme/status-bar.mjs +162 -158
  132. package/src/tool/audit-wrapper.mjs +18 -2
  133. package/src/tool/edit-transaction.mjs +23 -0
  134. package/src/tool/executor.mjs +26 -1
  135. package/src/tool/file-read-state.mjs +65 -0
  136. package/src/tool/git-auto.mjs +526 -526
  137. package/src/tool/git-full-auto.mjs +487 -478
  138. package/src/tool/mutation-guard.mjs +54 -0
  139. package/src/tool/prompt/edit.txt +3 -3
  140. package/src/tool/prompt/multiedit.txt +1 -0
  141. package/src/tool/prompt/notebookedit.txt +2 -1
  142. package/src/tool/prompt/patch.txt +25 -24
  143. package/src/tool/prompt/read.txt +3 -3
  144. package/src/tool/prompt/sysinfo.txt +29 -0
  145. package/src/tool/prompt/task.txt +66 -4
  146. package/src/tool/prompt/write.txt +2 -2
  147. package/src/tool/question-prompt.mjs +99 -93
  148. package/src/tool/registry.mjs +1701 -1343
  149. package/src/tool/task-tool.mjs +14 -6
  150. package/src/ui/activity-renderer.mjs +667 -664
  151. package/src/ui/repl-background-panel.mjs +7 -0
  152. package/src/ui/repl-capability-panel.mjs +9 -0
  153. package/src/ui/repl-dashboard.mjs +54 -4
  154. package/src/ui/repl-help.mjs +110 -0
  155. package/src/ui/repl-operator-panel.mjs +12 -0
  156. package/src/ui/repl-route-feedback.mjs +35 -0
  157. package/src/ui/repl-status-view.mjs +76 -0
  158. package/src/ui/repl-task-panel.mjs +5 -0
  159. package/src/ui/repl-transcript-panel.mjs +56 -0
  160. package/src/ui/repl-turn-summary.mjs +135 -0
  161. package/src/update/checker.mjs +184 -0
  162. package/src/usage/pricing.mjs +122 -121
  163. package/src/usage/usage-meter.mjs +1 -0
  164. package/src/util/git.mjs +562 -519
  165. package/src/util/template.mjs +6 -1
  166. package/src/version.mjs +3 -0
@@ -1,291 +1,291 @@
1
- import { processTurnLoop } from "./loop.mjs"
2
- import { EventBus } from "../core/events.mjs"
3
- import { EVENT_TYPES } from "../core/constants.mjs"
4
- import { stat } from "node:fs/promises"
5
- import path from "node:path"
6
-
7
- function buildScaffoldPrompt(objective, stagePlan) {
8
- const tasksByFile = new Map()
9
- const taskSpecs = []
10
-
11
- for (const stage of stagePlan.stages || []) {
12
- for (const task of stage.tasks || []) {
13
- for (const file of task.plannedFiles || []) {
14
- tasksByFile.set(file, { taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, acceptance: task.acceptance })
15
- }
16
- taskSpecs.push({ taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, plannedFiles: task.plannedFiles, acceptance: task.acceptance })
17
- }
18
- }
19
-
20
- const fileList = [...tasksByFile.keys()].sort()
21
- if (!fileList.length) return null
22
-
23
- const fileContext = fileList.map((f) => {
24
- const t = tasksByFile.get(f)
25
- return `- ${f} (task: ${t.taskId}, stage: ${t.stageId})`
26
- })
27
-
28
- return [
29
- "You are the ARCHITECT agent for a production-grade parallel coding pipeline.",
30
- "Your job: create ALL project files as detailed scaffolds that guide independent sub-agents to produce compatible, integrable code.",
31
- "",
32
- "CRITICAL CONTEXT: Each sub-agent works in ISOLATION. It can only see:",
33
- "- The scaffold file you create (with your inline comments)",
34
- "- Its task prompt and file ownership list",
35
- "- Files created by PREVIOUS stages (not the current stage)",
36
- "Your scaffold is the sub-agent's PRIMARY source of truth. Ambiguous or incomplete scaffolds cause integration failures.",
37
- "",
38
- "## Objective",
39
- objective,
40
- "",
41
- "## Files to create:",
42
- ...fileContext,
43
- "",
44
- "## Task plan (each task assigned to an independent sub-agent):",
45
- JSON.stringify(taskSpecs, null, 2),
46
- "",
47
- "## Scaffold Specification (follow EXACTLY)",
48
- "",
49
- "Create EVERY file listed above using the `write` tool. Each file MUST contain:",
50
- "",
51
- "### 1. File Header Block",
52
- "```",
53
- "// FILE: <relative path>",
54
- "// PURPOSE: <one-sentence description of this file's responsibility>",
55
- "// DEPENDS ON: <list of files this imports from, with what symbols>",
56
- "// USED BY: <list of files that import from this>",
57
- "// OWNER: task <taskId> | stage <stageId>",
58
- "```",
59
- "",
60
- "### 2. Complete Import Statements",
61
- "- Write ALL import/require statements with CORRECT relative paths",
62
- "- Include the exact symbol names being imported: `import { foo, bar } from './module.mjs'`",
63
- "- This is the dependency contract — sub-agents rely on these paths being accurate",
64
- "- If importing from a file owned by a DIFFERENT task in the same stage, add a comment: `// CROSS-TASK: implemented by <taskId>`",
65
- "",
66
- "### 3. Exported API Surface",
67
- "- Declare ALL exports with full signatures (function name, parameters with types, return type)",
68
- "- For each export, add a one-line JSDoc/docstring describing its contract",
69
- "- This is the integration contract — other files depend on these exact signatures",
70
- "",
71
- "### 4. Implementation Blueprint (THE CORE)",
72
- "For every function, class, method, handler, route:",
73
- "- Write the complete signature/declaration",
74
- "- Inside the body, write NUMBERED STEP comments describing:",
75
- " 1. Input validation: what to check, what errors to throw for invalid input",
76
- " 2. Core algorithm: step-by-step logic flow with concrete details",
77
- " 3. Data transformations: input shape → processing → output shape",
78
- " 4. Error handling: what to catch, what to throw, what to log",
79
- " 5. Side effects: DB writes, API calls, event emissions, file I/O",
80
- " 6. Return value: exact shape and type of the return value",
81
- "",
82
- "### 5. Strict Prohibitions",
83
- "- Do NOT write actual implementation code — only signatures + comment blueprints",
84
- "- Do NOT write vague placeholders like `// TODO` or `pass` without detailed steps",
85
- "- Do NOT skip any file — every file in the list MUST be created",
86
- "- Do NOT invent files not in the plan — only create files listed above",
87
- "- Do NOT use generic comments like 'handle errors' — specify WHICH errors and HOW",
88
- "",
89
- "### Language-specific patterns",
90
- "",
91
- "**JavaScript/TypeScript:**",
92
- "```js",
93
- "// FILE: src/auth/jwt.mjs",
94
- "// PURPOSE: JWT token generation and verification",
95
- "// DEPENDS ON: src/config/env.mjs (reads JWT_SECRET)",
96
- "// USED BY: src/middleware/auth.mjs, src/routes/login.mjs",
97
- "// TASK: s1_auth | STAGE: s1",
98
- "",
99
- "import { getEnv } from '../config/env.mjs'",
100
- "",
101
- "export function generateToken(userId, role) {",
102
- " // 1. Read JWT_SECRET from getEnv('JWT_SECRET')",
103
- " // 2. Build payload: { sub: userId, role, iat: now, exp: now + 24h }",
104
- " // 3. Sign with HS256 algorithm using jsonwebtoken.sign()",
105
- " // 4. Return the signed token string",
106
- " // ERROR: throw if JWT_SECRET is missing",
107
- "}",
108
- "```",
109
- "",
110
- "**Python:**",
111
- "```python",
112
- "# FILE: app/services/user_service.py",
113
- "# PURPOSE: User CRUD operations",
114
- "# DEPENDS ON: app/models/user.py, app/db/session.py",
115
- "# USED BY: app/routes/users.py",
116
- "# TASK: s1_users | STAGE: s1",
117
- "",
118
- "from app.models.user import User",
119
- "from app.db.session import get_db",
120
- "",
121
- "async def create_user(email: str, password: str) -> User:",
122
- " # 1. Validate email format with regex",
123
- " # 2. Check if email already exists in DB → raise DuplicateError",
124
- " # 3. Hash password with bcrypt (12 rounds)",
125
- " # 4. Insert new User record into DB",
126
- " # 5. Return the created User object (without password hash)",
127
- " pass",
128
- "```",
129
- "",
130
- "**React/Vue components:**",
131
- "```jsx",
132
- "// FILE: src/components/UserList.tsx",
133
- "// PURPOSE: Paginated user list with search and sort",
134
- "// DEPENDS ON: src/api/users.ts, src/components/Pagination.tsx",
135
- "// USED BY: src/pages/AdminDashboard.tsx",
136
- "// TASK: s2_ui | STAGE: s2",
137
- "",
138
- "// PROPS: { pageSize?: number, onSelect: (user) => void }",
139
- "// STATE: users[], loading, error, searchQuery, sortField, currentPage",
140
- "// EFFECTS:",
141
- "// - On mount + searchQuery/sortField/page change → fetch users from API",
142
- "// - Debounce search input by 300ms",
143
- "// RENDER:",
144
- "// - Search input at top",
145
- "// - Table with columns: name, email, role, created_at (all sortable)",
146
- "// - Loading skeleton while fetching",
147
- "// - Error banner with retry button",
148
- "// - Pagination component at bottom",
149
- "// STYLE:",
150
- "// - Use project's CSS framework (Tailwind/CSS vars) — read config first",
151
- "// - Hover states on table rows, focus ring on search input",
152
- "// - Consistent spacing from project's design tokens",
153
- "```",
154
- "",
155
- "## Tool Usage Rules",
156
- "- USE `write` to create each file — this is your PRIMARY and MAIN tool",
157
- "- USE `read` ONLY to check existing project files (package.json, tsconfig.json, existing modules) for conventions and patterns",
158
- "- Do NOT use `edit`, `bash`, `grep`, or `glob` — you are creating new scaffolds, not modifying existing code",
159
- "- Create files in dependency order: shared types/interfaces first, then modules that import them",
160
- "",
161
- "## Quality Checklist (verify before completing)",
162
- "- [ ] Every file in the list has been created",
163
- "- [ ] All import paths are correct relative paths",
164
- "- [ ] All exported function signatures include parameter names and types",
165
- "- [ ] Every function body has numbered step comments (not just '// implement')",
166
- "- [ ] Cross-task dependencies are marked with `// CROSS-TASK: implemented by <taskId>`",
167
- "- [ ] File headers include DEPENDS ON and USED BY sections",
168
- "",
169
- "## Completion",
170
- "When ALL files are created and the checklist is satisfied, say [SCAFFOLD_COMPLETE].",
171
- "",
172
- "Start now. Create files in dependency order (shared types first, then consumers)."
173
- ].join("\n")
174
- }
175
-
176
- function buildTddScaffoldPrompt(objective, stagePlan) {
177
- const taskSpecs = []
178
- const allFiles = new Set()
179
- for (const stage of stagePlan.stages || []) {
180
- for (const task of stage.tasks || []) {
181
- taskSpecs.push({ taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, plannedFiles: task.plannedFiles, acceptance: task.acceptance })
182
- for (const f of task.plannedFiles || []) allFiles.add(f)
183
- }
184
- }
185
- if (!allFiles.size) return null
186
-
187
- return [
188
- "You are the TDD ARCHITECT agent for a production-grade parallel coding pipeline.",
189
- "Your job: create TEST FILES FIRST to define the contract, then implementation scaffolds with inline blueprints.",
190
- "",
191
- "## Objective",
192
- objective,
193
- "",
194
- "## Task plan:",
195
- JSON.stringify(taskSpecs, null, 2),
196
- "",
197
- "## TDD Workflow (strict order)",
198
- "",
199
- "For EACH planned source file, create TWO files in this order:",
200
- "",
201
- "### Step 1: Test File",
202
- "- Create the test file BEFORE the implementation file",
203
- "- Write concrete test cases derived from the task's acceptance criteria",
204
- "- Each test must have: descriptive name, setup, action, assertion",
205
- "- Cover: happy path, error cases, edge cases (null/empty/invalid input), boundary conditions",
206
- "- Tests should be runnable but FAIL (because implementation is a stub)",
207
- "- Import the source module using the correct relative path",
208
- "",
209
- "### Step 2: Implementation Scaffold",
210
- "- Create the source file with full signatures + numbered step comments (same as normal scaffold)",
211
- "- Functions should have minimal stub bodies (throw or return placeholder) so tests can import them",
212
- "",
213
- "## Test File Naming Convention",
214
- "- JS/TS: `<name>.test.mjs` or `<name>.spec.ts` (match project convention)",
215
- "- Python: `test_<name>.py` in same directory or `tests/` directory",
216
- "- Check existing test files in the project to match the convention",
217
- "",
218
- "## Completion",
219
- "When ALL files (tests + stubs) are created, say [SCAFFOLD_COMPLETE].",
220
- "",
221
- "Start now. Create test files first, then implementation stubs."
222
- ].join("\n")
223
- }
224
-
225
- export async function runScaffoldPhase({
226
- objective,
227
- stagePlan,
228
- model,
229
- providerType,
230
- sessionId,
231
- configState,
232
- baseUrl = null,
233
- apiKeyEnv = null,
234
- agent = null,
235
- signal = null,
236
- toolContext = {},
237
- tddMode = false
238
- }) {
239
- const prompt = tddMode
240
- ? buildTddScaffoldPrompt(objective, stagePlan)
241
- : buildScaffoldPrompt(objective, stagePlan)
242
- if (!prompt) {
243
- return { scaffolded: false, fileCount: 0, files: [], errors: [] }
244
- }
245
-
246
- const out = await processTurnLoop({
247
- prompt,
248
- mode: "agent",
249
- model,
250
- providerType,
251
- sessionId,
252
- configState,
253
- baseUrl,
254
- apiKeyEnv,
255
- agent,
256
- signal,
257
- allowQuestion: false,
258
- toolContext
259
- })
260
-
261
- // Extract files created from tool events
262
- const createdFiles = (out.toolEvents || [])
263
- .filter((e) => e.name === "write" && e.status === "completed")
264
- .map((e) => e.args?.path)
265
- .filter(Boolean)
266
-
267
- // Verify files actually exist on disk
268
- const verified = []
269
- const missing = []
270
- for (const file of createdFiles) {
271
- const abs = path.isAbsolute(file) ? file : path.join(process.cwd(), file)
272
- try {
273
- await stat(abs)
274
- verified.push(file)
275
- } catch {
276
- missing.push(file)
277
- }
278
- }
279
-
280
- return {
281
- scaffolded: true,
282
- fileCount: verified.length,
283
- files: verified,
284
- missingFiles: missing,
285
- usage: out.usage,
286
- toolEvents: out.toolEvents,
287
- errors: missing.length > 0
288
- ? [`${missing.length} file(s) reported created but not found on disk: ${missing.slice(0, 5).join(", ")}`]
289
- : []
290
- }
291
- }
1
+ import { processTurnLoop } from "./loop.mjs"
2
+ import { EventBus } from "../core/events.mjs"
3
+ import { EVENT_TYPES } from "../core/constants.mjs"
4
+ import { stat } from "node:fs/promises"
5
+ import path from "node:path"
6
+
7
+ function buildScaffoldPrompt(objective, stagePlan) {
8
+ const tasksByFile = new Map()
9
+ const taskSpecs = []
10
+
11
+ for (const stage of stagePlan.stages || []) {
12
+ for (const task of stage.tasks || []) {
13
+ for (const file of task.plannedFiles || []) {
14
+ tasksByFile.set(file, { taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, acceptance: task.acceptance })
15
+ }
16
+ taskSpecs.push({ taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, plannedFiles: task.plannedFiles, acceptance: task.acceptance })
17
+ }
18
+ }
19
+
20
+ const fileList = [...tasksByFile.keys()].sort()
21
+ if (!fileList.length) return null
22
+
23
+ const fileContext = fileList.map((f) => {
24
+ const t = tasksByFile.get(f)
25
+ return `- ${f} (task: ${t.taskId}, stage: ${t.stageId})`
26
+ })
27
+
28
+ return [
29
+ "You are the ARCHITECT agent for a production-grade parallel coding pipeline.",
30
+ "Your job: create ALL project files as detailed scaffolds that guide independent sub-agents to produce compatible, integrable code.",
31
+ "",
32
+ "CRITICAL CONTEXT: Each sub-agent works in ISOLATION. It can only see:",
33
+ "- The scaffold file you create (with your inline comments)",
34
+ "- Its task prompt and file ownership list",
35
+ "- Files created by PREVIOUS stages (not the current stage)",
36
+ "Your scaffold is the sub-agent's PRIMARY source of truth. Ambiguous or incomplete scaffolds cause integration failures.",
37
+ "",
38
+ "## Objective",
39
+ objective,
40
+ "",
41
+ "## Files to create:",
42
+ ...fileContext,
43
+ "",
44
+ "## Task plan (each task assigned to an independent sub-agent):",
45
+ JSON.stringify(taskSpecs, null, 2),
46
+ "",
47
+ "## Scaffold Specification (follow EXACTLY)",
48
+ "",
49
+ "Create EVERY file listed above using the `write` tool. Each file MUST contain:",
50
+ "",
51
+ "### 1. File Header Block",
52
+ "```",
53
+ "// FILE: <relative path>",
54
+ "// PURPOSE: <one-sentence description of this file's responsibility>",
55
+ "// DEPENDS ON: <list of files this imports from, with what symbols>",
56
+ "// USED BY: <list of files that import from this>",
57
+ "// OWNER: task <taskId> | stage <stageId>",
58
+ "```",
59
+ "",
60
+ "### 2. Complete Import Statements",
61
+ "- Write ALL import/require statements with CORRECT relative paths",
62
+ "- Include the exact symbol names being imported: `import { foo, bar } from './module.mjs'`",
63
+ "- This is the dependency contract — sub-agents rely on these paths being accurate",
64
+ "- If importing from a file owned by a DIFFERENT task in the same stage, add a comment: `// CROSS-TASK: implemented by <taskId>`",
65
+ "",
66
+ "### 3. Exported API Surface",
67
+ "- Declare ALL exports with full signatures (function name, parameters with types, return type)",
68
+ "- For each export, add a one-line JSDoc/docstring describing its contract",
69
+ "- This is the integration contract — other files depend on these exact signatures",
70
+ "",
71
+ "### 4. Implementation Blueprint (THE CORE)",
72
+ "For every function, class, method, handler, route:",
73
+ "- Write the complete signature/declaration",
74
+ "- Inside the body, write NUMBERED STEP comments describing:",
75
+ " 1. Input validation: what to check, what errors to throw for invalid input",
76
+ " 2. Core algorithm: step-by-step logic flow with concrete details",
77
+ " 3. Data transformations: input shape → processing → output shape",
78
+ " 4. Error handling: what to catch, what to throw, what to log",
79
+ " 5. Side effects: DB writes, API calls, event emissions, file I/O",
80
+ " 6. Return value: exact shape and type of the return value",
81
+ "",
82
+ "### 5. Strict Prohibitions",
83
+ "- Do NOT write actual implementation code — only signatures + comment blueprints",
84
+ "- Do NOT write vague placeholders like `// TODO` or `pass` without detailed steps",
85
+ "- Do NOT skip any file — every file in the list MUST be created",
86
+ "- Do NOT invent files not in the plan — only create files listed above",
87
+ "- Do NOT use generic comments like 'handle errors' — specify WHICH errors and HOW",
88
+ "",
89
+ "### Language-specific patterns",
90
+ "",
91
+ "**JavaScript/TypeScript:**",
92
+ "```js",
93
+ "// FILE: src/auth/jwt.mjs",
94
+ "// PURPOSE: JWT token generation and verification",
95
+ "// DEPENDS ON: src/config/env.mjs (reads JWT_SECRET)",
96
+ "// USED BY: src/middleware/auth.mjs, src/routes/login.mjs",
97
+ "// TASK: s1_auth | STAGE: s1",
98
+ "",
99
+ "import { getEnv } from '../config/env.mjs'",
100
+ "",
101
+ "export function generateToken(userId, role) {",
102
+ " // 1. Read JWT_SECRET from getEnv('JWT_SECRET')",
103
+ " // 2. Build payload: { sub: userId, role, iat: now, exp: now + 24h }",
104
+ " // 3. Sign with HS256 algorithm using jsonwebtoken.sign()",
105
+ " // 4. Return the signed token string",
106
+ " // ERROR: throw if JWT_SECRET is missing",
107
+ "}",
108
+ "```",
109
+ "",
110
+ "**Python:**",
111
+ "```python",
112
+ "# FILE: app/services/user_service.py",
113
+ "# PURPOSE: User CRUD operations",
114
+ "# DEPENDS ON: app/models/user.py, app/db/session.py",
115
+ "# USED BY: app/routes/users.py",
116
+ "# TASK: s1_users | STAGE: s1",
117
+ "",
118
+ "from app.models.user import User",
119
+ "from app.db.session import get_db",
120
+ "",
121
+ "async def create_user(email: str, password: str) -> User:",
122
+ " # 1. Validate email format with regex",
123
+ " # 2. Check if email already exists in DB → raise DuplicateError",
124
+ " # 3. Hash password with bcrypt (12 rounds)",
125
+ " # 4. Insert new User record into DB",
126
+ " # 5. Return the created User object (without password hash)",
127
+ " pass",
128
+ "```",
129
+ "",
130
+ "**React/Vue components:**",
131
+ "```jsx",
132
+ "// FILE: src/components/UserList.tsx",
133
+ "// PURPOSE: Paginated user list with search and sort",
134
+ "// DEPENDS ON: src/api/users.ts, src/components/Pagination.tsx",
135
+ "// USED BY: src/pages/AdminDashboard.tsx",
136
+ "// TASK: s2_ui | STAGE: s2",
137
+ "",
138
+ "// PROPS: { pageSize?: number, onSelect: (user) => void }",
139
+ "// STATE: users[], loading, error, searchQuery, sortField, currentPage",
140
+ "// EFFECTS:",
141
+ "// - On mount + searchQuery/sortField/page change → fetch users from API",
142
+ "// - Debounce search input by 300ms",
143
+ "// RENDER:",
144
+ "// - Search input at top",
145
+ "// - Table with columns: name, email, role, created_at (all sortable)",
146
+ "// - Loading skeleton while fetching",
147
+ "// - Error banner with retry button",
148
+ "// - Pagination component at bottom",
149
+ "// STYLE:",
150
+ "// - Use project's CSS framework (Tailwind/CSS vars) — read config first",
151
+ "// - Hover states on table rows, focus ring on search input",
152
+ "// - Consistent spacing from project's design tokens",
153
+ "```",
154
+ "",
155
+ "## Tool Usage Rules",
156
+ "- USE `write` to create each file — this is your PRIMARY and MAIN tool",
157
+ "- USE `read` ONLY to check existing project files (package.json, tsconfig.json, existing modules) for conventions and patterns",
158
+ "- Do NOT use `edit`, `bash`, `grep`, or `glob` — you are creating new scaffolds, not modifying existing code",
159
+ "- Create files in dependency order: shared types/interfaces first, then modules that import them",
160
+ "",
161
+ "## Quality Checklist (verify before completing)",
162
+ "- [ ] Every file in the list has been created",
163
+ "- [ ] All import paths are correct relative paths",
164
+ "- [ ] All exported function signatures include parameter names and types",
165
+ "- [ ] Every function body has numbered step comments (not just '// implement')",
166
+ "- [ ] Cross-task dependencies are marked with `// CROSS-TASK: implemented by <taskId>`",
167
+ "- [ ] File headers include DEPENDS ON and USED BY sections",
168
+ "",
169
+ "## Completion",
170
+ "When ALL files are created and the checklist is satisfied, say [SCAFFOLD_COMPLETE].",
171
+ "",
172
+ "Start now. Create files in dependency order (shared types first, then consumers)."
173
+ ].join("\n")
174
+ }
175
+
176
+ function buildTddScaffoldPrompt(objective, stagePlan) {
177
+ const taskSpecs = []
178
+ const allFiles = new Set()
179
+ for (const stage of stagePlan.stages || []) {
180
+ for (const task of stage.tasks || []) {
181
+ taskSpecs.push({ taskId: task.taskId, stageId: stage.stageId, prompt: task.prompt, plannedFiles: task.plannedFiles, acceptance: task.acceptance })
182
+ for (const f of task.plannedFiles || []) allFiles.add(f)
183
+ }
184
+ }
185
+ if (!allFiles.size) return null
186
+
187
+ return [
188
+ "You are the TDD ARCHITECT agent for a production-grade parallel coding pipeline.",
189
+ "Your job: create TEST FILES FIRST to define the contract, then implementation scaffolds with inline blueprints.",
190
+ "",
191
+ "## Objective",
192
+ objective,
193
+ "",
194
+ "## Task plan:",
195
+ JSON.stringify(taskSpecs, null, 2),
196
+ "",
197
+ "## TDD Workflow (strict order)",
198
+ "",
199
+ "For EACH planned source file, create TWO files in this order:",
200
+ "",
201
+ "### Step 1: Test File",
202
+ "- Create the test file BEFORE the implementation file",
203
+ "- Write concrete test cases derived from the task's acceptance criteria",
204
+ "- Each test must have: descriptive name, setup, action, assertion",
205
+ "- Cover: happy path, error cases, edge cases (null/empty/invalid input), boundary conditions",
206
+ "- Tests should be runnable but FAIL (because implementation is a stub)",
207
+ "- Import the source module using the correct relative path",
208
+ "",
209
+ "### Step 2: Implementation Scaffold",
210
+ "- Create the source file with full signatures + numbered step comments (same as normal scaffold)",
211
+ "- Functions should have minimal stub bodies (throw or return placeholder) so tests can import them",
212
+ "",
213
+ "## Test File Naming Convention",
214
+ "- JS/TS: `<name>.test.mjs` or `<name>.spec.ts` (match project convention)",
215
+ "- Python: `test_<name>.py` in same directory or `tests/` directory",
216
+ "- Check existing test files in the project to match the convention",
217
+ "",
218
+ "## Completion",
219
+ "When ALL files (tests + stubs) are created, say [SCAFFOLD_COMPLETE].",
220
+ "",
221
+ "Start now. Create test files first, then implementation stubs."
222
+ ].join("\n")
223
+ }
224
+
225
+ export async function runScaffoldPhase({
226
+ objective,
227
+ stagePlan,
228
+ model,
229
+ providerType,
230
+ sessionId,
231
+ configState,
232
+ baseUrl = null,
233
+ apiKeyEnv = null,
234
+ agent = null,
235
+ signal = null,
236
+ toolContext = {},
237
+ tddMode = false
238
+ }) {
239
+ const prompt = tddMode
240
+ ? buildTddScaffoldPrompt(objective, stagePlan)
241
+ : buildScaffoldPrompt(objective, stagePlan)
242
+ if (!prompt) {
243
+ return { scaffolded: false, fileCount: 0, files: [], errors: [] }
244
+ }
245
+
246
+ const out = await processTurnLoop({
247
+ prompt,
248
+ mode: "agent",
249
+ model,
250
+ providerType,
251
+ sessionId,
252
+ configState,
253
+ baseUrl,
254
+ apiKeyEnv,
255
+ agent,
256
+ signal,
257
+ allowQuestion: false,
258
+ toolContext
259
+ })
260
+
261
+ // Extract files created from tool events
262
+ const createdFiles = (out.toolEvents || [])
263
+ .filter((e) => e.name === "write" && e.status === "completed")
264
+ .map((e) => e.args?.path)
265
+ .filter(Boolean)
266
+
267
+ // Verify files actually exist on disk
268
+ const verified = []
269
+ const missing = []
270
+ for (const file of createdFiles) {
271
+ const abs = path.isAbsolute(file) ? file : path.join(process.cwd(), file)
272
+ try {
273
+ await stat(abs)
274
+ verified.push(file)
275
+ } catch {
276
+ missing.push(file)
277
+ }
278
+ }
279
+
280
+ return {
281
+ scaffolded: true,
282
+ fileCount: verified.length,
283
+ files: verified,
284
+ missingFiles: missing,
285
+ usage: out.usage,
286
+ toolEvents: out.toolEvents,
287
+ errors: missing.length > 0
288
+ ? [`${missing.length} file(s) reported created but not found on disk: ${missing.slice(0, 5).join(", ")}`]
289
+ : []
290
+ }
291
+ }