xcoder-dna 0.0.0-stage → 1.3.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 (390) hide show
  1. package/LICENSE +66 -0
  2. package/README.md +87 -2
  3. package/dist/agents/ai-chat-debate.d.ts +36 -0
  4. package/dist/agents/ai-chat-debate.js +300 -0
  5. package/dist/agents/ai-chat-report-writer.d.ts +7 -0
  6. package/dist/agents/ai-chat-report-writer.js +100 -0
  7. package/dist/agents/duplicate-detector.d.ts +41 -0
  8. package/dist/agents/duplicate-detector.js +65 -0
  9. package/dist/agents/genesis-agent.d.ts +61 -0
  10. package/dist/agents/genesis-agent.js +340 -0
  11. package/dist/agents/samurai-agent.d.ts +53 -0
  12. package/dist/agents/samurai-agent.js +279 -0
  13. package/dist/agents/sub-agent.d.ts +56 -0
  14. package/dist/agents/sub-agent.js +353 -0
  15. package/dist/backlog/backlog-requirement-validator.d.ts +10 -0
  16. package/dist/backlog/backlog-requirement-validator.js +60 -0
  17. package/dist/backlog/backlog-store.d.ts +29 -0
  18. package/dist/backlog/backlog-store.js +148 -0
  19. package/dist/backlog/po-agent.d.ts +16 -0
  20. package/dist/backlog/po-agent.js +121 -0
  21. package/dist/backlog/types.d.ts +25 -0
  22. package/dist/backlog/types.js +4 -0
  23. package/dist/bench/run.d.ts +11 -0
  24. package/dist/bench/run.js +185 -0
  25. package/dist/bench/types.d.ts +50 -0
  26. package/dist/bench/types.js +1 -0
  27. package/dist/cli/swarm.d.ts +10 -0
  28. package/dist/cli/swarm.js +100 -0
  29. package/dist/cli/task.d.ts +14 -0
  30. package/dist/cli/task.js +121 -0
  31. package/dist/cli/wbc-arg.d.ts +6 -0
  32. package/dist/cli/wbc-arg.js +40 -0
  33. package/dist/cli/wbc.d.ts +45 -0
  34. package/dist/cli/wbc.js +98 -0
  35. package/dist/commands/license.d.ts +9 -0
  36. package/dist/commands/license.js +140 -0
  37. package/dist/commands/release.d.ts +44 -0
  38. package/dist/commands/release.js +180 -0
  39. package/dist/commands/test.d.ts +50 -0
  40. package/dist/commands/test.js +385 -0
  41. package/dist/config/loadConfig.d.ts +82 -0
  42. package/dist/config/loadConfig.js +240 -0
  43. package/dist/config/secure-mode.d.ts +29 -0
  44. package/dist/config/secure-mode.js +63 -0
  45. package/dist/config/user-config.d.ts +39 -0
  46. package/dist/config/user-config.js +202 -0
  47. package/dist/engine/reasoning-engine.d.ts +21 -0
  48. package/dist/engine/reasoning-engine.js +59 -0
  49. package/dist/events/bus.d.ts +22 -0
  50. package/dist/events/bus.js +18 -0
  51. package/dist/index.d.ts +79 -0
  52. package/dist/index.js +77 -0
  53. package/dist/indexing/ignoreRules.d.ts +1 -0
  54. package/dist/indexing/ignoreRules.js +53 -0
  55. package/dist/instance-swarm/instance-swarm-orchestrator.d.ts +57 -0
  56. package/dist/instance-swarm/instance-swarm-orchestrator.js +204 -0
  57. package/dist/instance-swarm/protocol-name-resolver.d.ts +23 -0
  58. package/dist/instance-swarm/protocol-name-resolver.js +64 -0
  59. package/dist/license/gate.d.ts +31 -0
  60. package/dist/license/gate.js +188 -0
  61. package/dist/license/http-client.d.ts +43 -0
  62. package/dist/license/http-client.js +195 -0
  63. package/dist/license/manager.d.ts +39 -0
  64. package/dist/license/manager.js +175 -0
  65. package/dist/license/receipt.d.ts +27 -0
  66. package/dist/license/receipt.js +108 -0
  67. package/dist/license/state-codec.d.ts +72 -0
  68. package/dist/license/state-codec.js +218 -0
  69. package/dist/license/state-paths.d.ts +17 -0
  70. package/dist/license/state-paths.js +64 -0
  71. package/dist/license/store.d.ts +44 -0
  72. package/dist/license/store.js +223 -0
  73. package/dist/license/trust-anchor.d.ts +24 -0
  74. package/dist/license/trust-anchor.js +74 -0
  75. package/dist/license/types.d.ts +34 -0
  76. package/dist/license/types.js +19 -0
  77. package/dist/llm/budget.d.ts +23 -0
  78. package/dist/llm/budget.js +58 -0
  79. package/dist/llm/client.d.ts +53 -0
  80. package/dist/llm/client.js +122 -0
  81. package/dist/llm/factory.d.ts +14 -0
  82. package/dist/llm/factory.js +32 -0
  83. package/dist/orchestrator/defect-logger.d.ts +31 -0
  84. package/dist/orchestrator/defect-logger.js +101 -0
  85. package/dist/orchestrator/defect-manager.d.ts +118 -0
  86. package/dist/orchestrator/defect-manager.js +338 -0
  87. package/dist/orchestrator/defect-migration.d.ts +14 -0
  88. package/dist/orchestrator/defect-migration.js +174 -0
  89. package/dist/orchestrator/defect-store.d.ts +48 -0
  90. package/dist/orchestrator/defect-store.js +76 -0
  91. package/dist/orchestrator/healing.d.ts +14 -0
  92. package/dist/orchestrator/healing.js +11 -0
  93. package/dist/orchestrator/interactive-steering.d.ts +64 -0
  94. package/dist/orchestrator/interactive-steering.js +107 -0
  95. package/dist/orchestrator/interrupt-handler.d.ts +30 -0
  96. package/dist/orchestrator/interrupt-handler.js +70 -0
  97. package/dist/orchestrator/lesson-manager.d.ts +25 -0
  98. package/dist/orchestrator/lesson-manager.js +122 -0
  99. package/dist/orchestrator/progress-summary.d.ts +15 -0
  100. package/dist/orchestrator/progress-summary.js +106 -0
  101. package/dist/orchestrator/reasoning-score.d.ts +49 -0
  102. package/dist/orchestrator/reasoning-score.js +117 -0
  103. package/dist/orchestrator/swarm.d.ts +36 -0
  104. package/dist/orchestrator/swarm.js +77 -0
  105. package/dist/orchestrator/task-factory.d.ts +15 -0
  106. package/dist/orchestrator/task-factory.js +176 -0
  107. package/dist/orchestrator/validation-gate.d.ts +23 -0
  108. package/dist/orchestrator/validation-gate.js +155 -0
  109. package/dist/protocol/react-contract.d.ts +136 -0
  110. package/dist/protocol/react-contract.js +698 -0
  111. package/dist/protocol/wks-protocol-manager.d.ts +22 -0
  112. package/dist/protocol/wks-protocol-manager.js +72 -0
  113. package/dist/sdlc-runtime/conversation-runner.d.ts +8 -0
  114. package/dist/sdlc-runtime/conversation-runner.js +64 -0
  115. package/dist/sdlc-runtime/dag-utils.d.ts +15 -0
  116. package/dist/sdlc-runtime/dag-utils.js +67 -0
  117. package/dist/sdlc-runtime/defect-integration.d.ts +7 -0
  118. package/dist/sdlc-runtime/defect-integration.js +99 -0
  119. package/dist/sdlc-runtime/execution-loop.d.ts +38 -0
  120. package/dist/sdlc-runtime/execution-loop.js +274 -0
  121. package/dist/sdlc-runtime/lesson-recorder.d.ts +9 -0
  122. package/dist/sdlc-runtime/lesson-recorder.js +27 -0
  123. package/dist/sdlc-runtime/plan-initializer.d.ts +47 -0
  124. package/dist/sdlc-runtime/plan-initializer.js +135 -0
  125. package/dist/sdlc-runtime/progress-persister.d.ts +10 -0
  126. package/dist/sdlc-runtime/progress-persister.js +34 -0
  127. package/dist/sdlc-runtime/protocol-loader.d.ts +10 -0
  128. package/dist/sdlc-runtime/protocol-loader.js +21 -0
  129. package/dist/sdlc-runtime/reporting.d.ts +24 -0
  130. package/dist/sdlc-runtime/reporting.js +68 -0
  131. package/dist/sdlc-runtime/sdlc-orchestrator.d.ts +59 -0
  132. package/dist/sdlc-runtime/sdlc-orchestrator.js +170 -0
  133. package/dist/sdlc-runtime/sdlc-skill.d.ts +44 -0
  134. package/dist/sdlc-runtime/sdlc-skill.js +148 -0
  135. package/dist/sdlc-runtime/steering-handler.d.ts +14 -0
  136. package/dist/sdlc-runtime/steering-handler.js +51 -0
  137. package/dist/sdlc-runtime/trace-recorder.d.ts +10 -0
  138. package/dist/sdlc-runtime/trace-recorder.js +7 -0
  139. package/dist/security/index.d.ts +16 -0
  140. package/dist/security/index.js +12 -0
  141. package/dist/security/input-screen.d.ts +30 -0
  142. package/dist/security/input-screen.js +75 -0
  143. package/dist/security/tool-call-guard.d.ts +16 -0
  144. package/dist/security/tool-call-guard.js +163 -0
  145. package/dist/security/untrusted-content.d.ts +34 -0
  146. package/dist/security/untrusted-content.js +63 -0
  147. package/dist/skills/advanced-dfir/SKILL.md +85 -0
  148. package/dist/skills/advanced-pentest-lab/SKILL.md +88 -0
  149. package/dist/skills/analyst/SKILL.md +55 -0
  150. package/dist/skills/architect/SKILL.md +54 -0
  151. package/dist/skills/aws/SKILL.md +92 -0
  152. package/dist/skills/azure/SKILL.md +90 -0
  153. package/dist/skills/bylaw-context.d.ts +45 -0
  154. package/dist/skills/bylaw-context.js +61 -0
  155. package/dist/skills/bylaw-review.d.ts +20 -0
  156. package/dist/skills/bylaw-review.js +101 -0
  157. package/dist/skills/conversation/SKILL.md +29 -0
  158. package/dist/skills/design-patterns/SKILL.md +190 -0
  159. package/dist/skills/devops/SKILL.md +55 -0
  160. package/dist/skills/directives.d.ts +20 -0
  161. package/dist/skills/directives.js +313 -0
  162. package/dist/skills/docker/SKILL.md +76 -0
  163. package/dist/skills/docker-expert/SKILL.md +56 -0
  164. package/dist/skills/enterprise-systems-analyst/SKILL.md +83 -0
  165. package/dist/skills/enterprise-systems-analyst/references/crm.md +41 -0
  166. package/dist/skills/enterprise-systems-analyst/references/erp.md +40 -0
  167. package/dist/skills/enterprise-systems-analyst/references/financial-systems.md +35 -0
  168. package/dist/skills/enterprise-systems-analyst/references/hcm.md +38 -0
  169. package/dist/skills/enterprise-systems-analyst/references/mrp.md +37 -0
  170. package/dist/skills/enterprise-systems-analyst/references/scm.md +32 -0
  171. package/dist/skills/ethical-hacking-methodology/SKILL.md +119 -0
  172. package/dist/skills/externalSkillLoader.d.ts +25 -0
  173. package/dist/skills/externalSkillLoader.js +65 -0
  174. package/dist/skills/externalSkillRegistry.d.ts +33 -0
  175. package/dist/skills/externalSkillRegistry.js +94 -0
  176. package/dist/skills/filesystem-management/SKILL.md +61 -0
  177. package/dist/skills/first-run-seed.d.ts +26 -0
  178. package/dist/skills/first-run-seed.js +75 -0
  179. package/dist/skills/git-vcs/SKILL.md +84 -0
  180. package/dist/skills/kafka/SKILL.md +89 -0
  181. package/dist/skills/kubernetes/SKILL.md +93 -0
  182. package/dist/skills/kubernetes-expert/SKILL.md +54 -0
  183. package/dist/skills/openshift/SKILL.md +93 -0
  184. package/dist/skills/pentester/SKILL.md +59 -0
  185. package/dist/skills/performance-tester/SKILL.md +57 -0
  186. package/dist/skills/playwright-ui-tester/SKILL.md +67 -0
  187. package/dist/skills/programmer/SKILL.md +58 -0
  188. package/dist/skills/project-scaffolding/SKILL.md +133 -0
  189. package/dist/skills/qa-engineer/SKILL.md +91 -0
  190. package/dist/skills/rca/SKILL.md +58 -0
  191. package/dist/skills/redhat/SKILL.md +92 -0
  192. package/dist/skills/rosa/SKILL.md +80 -0
  193. package/dist/skills/scrum-framework/SKILL.md +74 -0
  194. package/dist/skills/scrum-framework/references/artifacts_and_quality.md +79 -0
  195. package/dist/skills/scrum-framework/references/roles_and_events.md +105 -0
  196. package/dist/skills/scrum-master-agent/SKILL.md +74 -0
  197. package/dist/skills/scrum-master-agent/references/behaviors.md +56 -0
  198. package/dist/skills/sdlc-skill.d.ts +1 -0
  199. package/dist/skills/sdlc-skill.js +4 -0
  200. package/dist/skills/secops/SKILL.md +52 -0
  201. package/dist/skills/secure-architect.bylaws.d.ts +68 -0
  202. package/dist/skills/secure-architect.bylaws.js +525 -0
  203. package/dist/skills/seed-skills.d.ts +48 -0
  204. package/dist/skills/seed-skills.js +213 -0
  205. package/dist/skills/skill-authoring/SKILL.md +123 -0
  206. package/dist/skills/skill-header.d.ts +51 -0
  207. package/dist/skills/skill-header.js +163 -0
  208. package/dist/skills/skill-path-guard.d.ts +41 -0
  209. package/dist/skills/skill-path-guard.js +95 -0
  210. package/dist/skills/skillRouter.d.ts +51 -0
  211. package/dist/skills/skillRouter.js +90 -0
  212. package/dist/skills/skills-root.d.ts +64 -0
  213. package/dist/skills/skills-root.js +168 -0
  214. package/dist/skills/software-architect/SKILL.md +77 -0
  215. package/dist/skills/software-engineer/SKILL.md +74 -0
  216. package/dist/skills/solid-principles/SKILL.md +94 -0
  217. package/dist/skills/task-planning/SKILL.md +115 -0
  218. package/dist/skills/tester/SKILL.md +54 -0
  219. package/dist/skills/ubuntu/SKILL.md +87 -0
  220. package/dist/skills/ui-ux-design/SKILL.md +114 -0
  221. package/dist/skills/workspace-context/SKILL.md +103 -0
  222. package/dist/sprint/controller.d.ts +37 -0
  223. package/dist/sprint/controller.js +220 -0
  224. package/dist/sprint/dag-builder.d.ts +14 -0
  225. package/dist/sprint/dag-builder.js +105 -0
  226. package/dist/sprint/reporter.d.ts +11 -0
  227. package/dist/sprint/reporter.js +97 -0
  228. package/dist/sprint/state-store.d.ts +10 -0
  229. package/dist/sprint/state-store.js +71 -0
  230. package/dist/sprint/types.d.ts +24 -0
  231. package/dist/sprint/types.js +4 -0
  232. package/dist/store/file-version-store.d.ts +24 -0
  233. package/dist/store/file-version-store.js +73 -0
  234. package/dist/store/task-store.d.ts +90 -0
  235. package/dist/store/task-store.js +166 -0
  236. package/dist/task-ingest/architect-detailer.d.ts +43 -0
  237. package/dist/task-ingest/architect-detailer.js +141 -0
  238. package/dist/task-ingest/detail-schema.d.ts +9 -0
  239. package/dist/task-ingest/detail-schema.js +195 -0
  240. package/dist/task-ingest/detailed-run.d.ts +36 -0
  241. package/dist/task-ingest/detailed-run.js +108 -0
  242. package/dist/task-ingest/extract-id.d.ts +9 -0
  243. package/dist/task-ingest/extract-id.js +24 -0
  244. package/dist/task-ingest/index.d.ts +23 -0
  245. package/dist/task-ingest/index.js +14 -0
  246. package/dist/task-ingest/ingest.d.ts +45 -0
  247. package/dist/task-ingest/ingest.js +163 -0
  248. package/dist/task-ingest/list-ingested.d.ts +13 -0
  249. package/dist/task-ingest/list-ingested.js +30 -0
  250. package/dist/task-ingest/pending-filter.d.ts +30 -0
  251. package/dist/task-ingest/pending-filter.js +59 -0
  252. package/dist/task-ingest/scanner.d.ts +56 -0
  253. package/dist/task-ingest/scanner.js +216 -0
  254. package/dist/task-ingest/source-reader.d.ts +25 -0
  255. package/dist/task-ingest/source-reader.js +93 -0
  256. package/dist/task-ingest/spec-builder.d.ts +34 -0
  257. package/dist/task-ingest/spec-builder.js +89 -0
  258. package/dist/task-ingest/wbs-extract.d.ts +50 -0
  259. package/dist/task-ingest/wbs-extract.js +226 -0
  260. package/dist/task-ingest/wbs-parser.d.ts +36 -0
  261. package/dist/task-ingest/wbs-parser.js +170 -0
  262. package/dist/tools/apiTestTool.d.ts +37 -0
  263. package/dist/tools/apiTestTool.js +128 -0
  264. package/dist/tools/ast-tools.d.ts +183 -0
  265. package/dist/tools/ast-tools.js +853 -0
  266. package/dist/tools/browse-tool.d.ts +105 -0
  267. package/dist/tools/browse-tool.js +394 -0
  268. package/dist/tools/credential.d.ts +17 -0
  269. package/dist/tools/credential.js +32 -0
  270. package/dist/tools/dependency-graph.d.ts +23 -0
  271. package/dist/tools/dependency-graph.js +164 -0
  272. package/dist/tools/edit-tool.d.ts +34 -0
  273. package/dist/tools/edit-tool.js +95 -0
  274. package/dist/tools/file-header-manager.d.ts +27 -0
  275. package/dist/tools/file-header-manager.js +153 -0
  276. package/dist/tools/fs-tools.d.ts +154 -0
  277. package/dist/tools/fs-tools.js +337 -0
  278. package/dist/tools/git-tools.d.ts +79 -0
  279. package/dist/tools/git-tools.js +348 -0
  280. package/dist/tools/github-tool.d.ts +48 -0
  281. package/dist/tools/github-tool.js +147 -0
  282. package/dist/tools/globTool.d.ts +20 -0
  283. package/dist/tools/globTool.js +34 -0
  284. package/dist/tools/grepTool.d.ts +19 -0
  285. package/dist/tools/grepTool.js +44 -0
  286. package/dist/tools/index-freshness.d.ts +58 -0
  287. package/dist/tools/index-freshness.js +190 -0
  288. package/dist/tools/index-glob.d.ts +48 -0
  289. package/dist/tools/index-glob.js +175 -0
  290. package/dist/tools/load-skill-tool.d.ts +15 -0
  291. package/dist/tools/load-skill-tool.js +114 -0
  292. package/dist/tools/patch-tools.d.ts +58 -0
  293. package/dist/tools/patch-tools.js +153 -0
  294. package/dist/tools/playwright-tool.d.ts +66 -0
  295. package/dist/tools/playwright-tool.js +121 -0
  296. package/dist/tools/project-detect.d.ts +20 -0
  297. package/dist/tools/project-detect.js +87 -0
  298. package/dist/tools/prompt-guidance.d.ts +22 -0
  299. package/dist/tools/prompt-guidance.js +23 -0
  300. package/dist/tools/scheduleTool.d.ts +19 -0
  301. package/dist/tools/scheduleTool.js +181 -0
  302. package/dist/tools/search-tools.d.ts +27 -0
  303. package/dist/tools/search-tools.js +78 -0
  304. package/dist/tools/sed-tool.d.ts +66 -0
  305. package/dist/tools/sed-tool.js +402 -0
  306. package/dist/tools/shell-result.d.ts +11 -0
  307. package/dist/tools/shell-result.js +1 -0
  308. package/dist/tools/shell-tool.d.ts +45 -0
  309. package/dist/tools/shell-tool.js +141 -0
  310. package/dist/tools/siteCrawlerTool.d.ts +32 -0
  311. package/dist/tools/siteCrawlerTool.js +205 -0
  312. package/dist/tools/tool-registry.d.ts +67 -0
  313. package/dist/tools/tool-registry.js +596 -0
  314. package/dist/tools/validate-tool.d.ts +23 -0
  315. package/dist/tools/validate-tool.js +201 -0
  316. package/dist/tools/workspace-index.d.ts +46 -0
  317. package/dist/tools/workspace-index.js +173 -0
  318. package/dist/types.d.ts +222 -0
  319. package/dist/types.js +7 -0
  320. package/dist/updater/index.d.ts +14 -0
  321. package/dist/updater/index.js +120 -0
  322. package/dist/util/banner.d.ts +25 -0
  323. package/dist/util/banner.js +140 -0
  324. package/dist/util/command-suggester.d.ts +6 -0
  325. package/dist/util/command-suggester.js +25 -0
  326. package/dist/util/confirm-interrupt.d.ts +10 -0
  327. package/dist/util/confirm-interrupt.js +31 -0
  328. package/dist/util/continue-trigger.d.ts +11 -0
  329. package/dist/util/continue-trigger.js +20 -0
  330. package/dist/util/env-info.d.ts +18 -0
  331. package/dist/util/env-info.js +37 -0
  332. package/dist/util/file-access-log.d.ts +35 -0
  333. package/dist/util/file-access-log.js +140 -0
  334. package/dist/util/footer-manager.d.ts +124 -0
  335. package/dist/util/footer-manager.js +195 -0
  336. package/dist/util/footer-renderer.d.ts +67 -0
  337. package/dist/util/footer-renderer.js +319 -0
  338. package/dist/util/footer-state.d.ts +34 -0
  339. package/dist/util/footer-state.js +18 -0
  340. package/dist/util/footer-text.d.ts +51 -0
  341. package/dist/util/footer-text.js +74 -0
  342. package/dist/util/ids.d.ts +1 -0
  343. package/dist/util/ids.js +4 -0
  344. package/dist/util/levenshtein.d.ts +6 -0
  345. package/dist/util/levenshtein.js +34 -0
  346. package/dist/util/logger.d.ts +10 -0
  347. package/dist/util/logger.js +41 -0
  348. package/dist/util/logs.d.ts +26 -0
  349. package/dist/util/logs.js +88 -0
  350. package/dist/util/output-handler.d.ts +89 -0
  351. package/dist/util/output-handler.js +193 -0
  352. package/dist/util/output-interceptor.d.ts +18 -0
  353. package/dist/util/output-interceptor.js +49 -0
  354. package/dist/util/output-paths.d.ts +43 -0
  355. package/dist/util/output-paths.js +121 -0
  356. package/dist/util/package-json.d.ts +6 -0
  357. package/dist/util/package-json.js +36 -0
  358. package/dist/util/process-kill.d.ts +27 -0
  359. package/dist/util/process-kill.js +148 -0
  360. package/dist/util/protocol-error-logger.d.ts +33 -0
  361. package/dist/util/protocol-error-logger.js +73 -0
  362. package/dist/util/redact.d.ts +25 -0
  363. package/dist/util/redact.js +103 -0
  364. package/dist/util/scroll-region-guard.d.ts +33 -0
  365. package/dist/util/scroll-region-guard.js +63 -0
  366. package/dist/util/spinner.d.ts +15 -0
  367. package/dist/util/spinner.js +49 -0
  368. package/dist/util/terminal-output.d.ts +34 -0
  369. package/dist/util/terminal-output.js +1 -0
  370. package/dist/util/terminal-silent.d.ts +6 -0
  371. package/dist/util/terminal-silent.js +20 -0
  372. package/dist/util/terminal.d.ts +56 -0
  373. package/dist/util/terminal.js +124 -0
  374. package/dist/util/text-sanitize.d.ts +8 -0
  375. package/dist/util/text-sanitize.js +45 -0
  376. package/dist/util/thinking-spinner.d.ts +27 -0
  377. package/dist/util/thinking-spinner.js +189 -0
  378. package/dist/util/tool-error-logger.d.ts +33 -0
  379. package/dist/util/tool-error-logger.js +77 -0
  380. package/dist/util/tty.d.ts +13 -0
  381. package/dist/util/tty.js +16 -0
  382. package/dist/util/xcoder-paths.d.ts +56 -0
  383. package/dist/util/xcoder-paths.js +63 -0
  384. package/dist/version.d.ts +2 -0
  385. package/dist/version.js +4 -0
  386. package/dist/worker-agent/to-subtask-node.d.ts +35 -0
  387. package/dist/worker-agent/to-subtask-node.js +41 -0
  388. package/dist/worker-agent/worker-orchestrator.d.ts +104 -0
  389. package/dist/worker-agent/worker-orchestrator.js +201 -0
  390. package/package.json +39 -4
@@ -0,0 +1,698 @@
1
+ // xcoder:version 3 | xcoder:task task-f1ac77 | xcoder:updated 2026-10-17T04:10:38.741Z | xcoder:subtask code-st-1d0003
2
+ import { z } from "zod";
3
+ import { environmentPromptBlock } from "../util/env-info.js";
4
+ import { detectedCommandsPromptBlock } from "../tools/project-detect.js";
5
+ /**
6
+ * THE CONTRACT.
7
+ *
8
+ * Every turn, in both directions, is exactly this shape. No prose outside
9
+ * the JSON, no partial objects, no both-action-and-final_answer. A message
10
+ * that doesn't parse against this schema is never silently "interpreted" —
11
+ * it's bounced back to the model as a typed protocol_error observation, and
12
+ * that costs it an iteration. This is what "protocol to adhere to" means in
13
+ * practice: the parser is the enforcement mechanism, not the prompt wording.
14
+ */
15
+ export const ReactMessageSchema = z
16
+ .object({
17
+ thought: z.string().min(1, "thought must be non-empty"),
18
+ action: z
19
+ .object({
20
+ tool: z.string().min(1),
21
+ // .optional() matters here, not just cosmetic: under Zod v4, an
22
+ // `unknown()` field must still have its key present in the object —
23
+ // a tool call with genuinely no arguments (key omitted entirely,
24
+ // e.g. after the command->tool alias normalization) would otherwise
25
+ // fail validation even though the action itself is perfectly valid.
26
+ input: z.unknown().optional(),
27
+ })
28
+ .nullable()
29
+ .default(null),
30
+ final_answer: z
31
+ .object({
32
+ summary: z.string().min(1),
33
+ deliverable: z.unknown(),
34
+ files_touched: z.array(z.string()).default([]),
35
+ self_check: z
36
+ .object({
37
+ ran: z.boolean(),
38
+ passed: z.boolean(),
39
+ detail: z.string(),
40
+ })
41
+ .optional(),
42
+ })
43
+ .nullable()
44
+ .default(null),
45
+ })
46
+ .superRefine((msg, ctx) => {
47
+ const hasAction = msg.action !== null && msg.action !== undefined;
48
+ const hasFinal = msg.final_answer !== null && msg.final_answer !== undefined;
49
+ if (hasAction === hasFinal) {
50
+ ctx.addIssue({
51
+ code: z.ZodIssueCode.custom,
52
+ message: "exactly one of `action` or `final_answer` must be non-null, never both, never neither",
53
+ });
54
+ }
55
+ });
56
+ /**
57
+ * Layer 1: Strip outermost XML envelope tags from model output.
58
+ * Handles tags like <thought>, <thinking>, <response>, <answer>
59
+ * (case-insensitive, outer-tags only). This prevents "Unexpected token '<'"
60
+ * parse errors when the model wraps JSON inside XML-style tags.
61
+ */
62
+ export function stripXmlTags(raw) {
63
+ const trimmed = raw.trim();
64
+ const XML_TAG_PATTERN = /^<\s*(\/?)\s*(thought|thinking|response|answer)\s*>\s*/i;
65
+ const XML_CLOSE_PATTERN = /\s*<\s*\/\s*(thought|thinking|response|answer)\s*>\s*$/i;
66
+ let result = trimmed;
67
+ // Remove opening tag (with optional leading slash for self-closing variants)
68
+ const openMatch = result.match(XML_TAG_PATTERN);
69
+ if (openMatch && !openMatch[1]) {
70
+ // Only strip if it's an opening tag (not </tag>)
71
+ result = result.slice(openMatch[0].length);
72
+ }
73
+ // Only remove closing tag if we actually stripped an opening tag.
74
+ // If no opening tag was matched (e.g. it had attributes), we must
75
+ // preserve the closing tag too to avoid asymmetric partial stripping.
76
+ if (openMatch && !openMatch[1]) {
77
+ result = result.replace(XML_CLOSE_PATTERN, "");
78
+ }
79
+ return result;
80
+ }
81
+ /**
82
+ * Layer 1.5: Escape raw control characters (newline, tab, CR, etc.) that
83
+ * appear *inside* JSON string literals.
84
+ *
85
+ * Root cause this repairs: the JSON spec forbids literal U+0000–U+001F
86
+ * inside a string value — they must be written as `\n`, `\t`, `\uXXXX`,
87
+ * etc. Models very frequently violate this when a string value itself
88
+ * contains multi-line content (e.g. `action.input.content` for a
89
+ * write_file call carrying markdown/code). `JSON.parse` rejects the whole
90
+ * payload with "Bad control character in string literal" and none of the
91
+ * other layers repair it — XML-stripping and outermost-extraction only
92
+ * fix structural wrapping, not the string contents. Left unrepaired, the
93
+ * model has to reproduce the *entire* (often large) payload again with
94
+ * manual escaping, and frequently fails repeatedly, burning tokens each
95
+ * retry.
96
+ *
97
+ * Uses the same string-aware, escape-aware single pass as
98
+ * extractOutermostJson so it never touches control characters that sit
99
+ * outside of a string literal (e.g. the newlines a model puts between
100
+ * prose and the JSON block, which are harmless and should be left alone).
101
+ */
102
+ export function sanitizeControlCharacters(raw) {
103
+ const CONTROL_CHAR_ESCAPES = {
104
+ "\n": "\\n",
105
+ "\r": "\\r",
106
+ "\t": "\\t",
107
+ "\b": "\\b",
108
+ "\f": "\\f",
109
+ };
110
+ let inString = false;
111
+ let inEscape = false;
112
+ let result = "";
113
+ let mutated = false;
114
+ for (let i = 0; i < raw.length; i++) {
115
+ const ch = raw[i];
116
+ if (inEscape) {
117
+ inEscape = false;
118
+ result += ch;
119
+ continue;
120
+ }
121
+ if (ch === "\\" && inString) {
122
+ inEscape = true;
123
+ result += ch;
124
+ continue;
125
+ }
126
+ if (ch === '"' && !inEscape) {
127
+ inString = !inString;
128
+ result += ch;
129
+ continue;
130
+ }
131
+ if (inString) {
132
+ const code = ch.charCodeAt(0);
133
+ if (code >= 0x00 && code <= 0x1f) {
134
+ result += CONTROL_CHAR_ESCAPES[ch] ?? `\\u${code.toString(16).padStart(4, "0")}`;
135
+ mutated = true;
136
+ continue;
137
+ }
138
+ }
139
+ result += ch;
140
+ }
141
+ return mutated ? result : raw;
142
+ }
143
+ /**
144
+ * Layer 2: Extract the outermost balanced {...} JSON block from a string.
145
+ * Uses a single-pass O(n) brace counter with string-awareness (handles
146
+ * escaped quotes inside strings). Returns the JSON substring, or empty
147
+ * string if no balanced braces are found.
148
+ */
149
+ export function extractOutermostJson(raw) {
150
+ let braceDepth = 0;
151
+ let inString = false;
152
+ let inEscape = false;
153
+ let start = -1;
154
+ let end = -1;
155
+ for (let i = 0; i < raw.length; i++) {
156
+ const ch = raw[i];
157
+ if (inEscape) {
158
+ inEscape = false;
159
+ continue;
160
+ }
161
+ if (ch === "\\" && inString) {
162
+ inEscape = true;
163
+ continue;
164
+ }
165
+ if (ch === '"' && !inEscape) {
166
+ inString = !inString;
167
+ continue;
168
+ }
169
+ if (inString) {
170
+ continue;
171
+ }
172
+ if (ch === "{") {
173
+ if (braceDepth === 0) {
174
+ start = i;
175
+ }
176
+ braceDepth++;
177
+ }
178
+ else if (ch === "}") {
179
+ braceDepth--;
180
+ if (braceDepth === 0 && start !== -1) {
181
+ end = i;
182
+ break; // outermost block found, stop scanning
183
+ }
184
+ if (braceDepth < 0) {
185
+ // Unbalanced closing brace before any opening — reset
186
+ braceDepth = 0;
187
+ start = -1;
188
+ }
189
+ }
190
+ }
191
+ if (start !== -1 && end !== -1) {
192
+ return raw.slice(start, end + 1);
193
+ }
194
+ return "";
195
+ }
196
+ /**
197
+ * Extract the prose text before the first '{' in the raw model output.
198
+ * Used to backfill missing `thought` fields from the model's opening prose.
199
+ * Returns trimmed prose, or "" if no '{' is found or it's at position 0.
200
+ *
201
+ * Tradeoff: uses the first literal '{' as delimiter, not a full brace-
202
+ * counting parser. Prose containing '{' before the JSON block (extremely
203
+ * rare in LLM output) will be truncated. Accepted as an edge case.
204
+ */
205
+ function extractProsePrefix(raw) {
206
+ const idx = raw.indexOf("{");
207
+ if (idx <= 0)
208
+ return "";
209
+ return raw.slice(0, idx).trim();
210
+ }
211
+ /**
212
+ * Layer 3: Normalize known LLM JSON-shape drifts before Zod validation.
213
+ * Operates on the already-parsed (but not yet schema-validated) object.
214
+ *
215
+ * Four drifts repaired, in fixed order:
216
+ * 1. Missing top-level `thought` — backfilled from prose preceding the JSON.
217
+ * 2. Bare `{tool, input}` — auto-wrapped as `{action: {tool, input}}`.
218
+ * 3. `thought` nested inside `action` — hoisted to top level.
219
+ * 4. Legacy `command` key inside `action` — renamed to `tool` (only when `tool` is absent).
220
+ *
221
+ * @param raw - The post-Layer-1 string (still contains prose prefix if present).
222
+ * @param json - The parsed JSON `unknown` object from Layer 2.
223
+ * @returns - `{ normalized: unknown; applied: boolean; steps: string[] }`
224
+ */
225
+ export function normalizeReactShape(raw, json) {
226
+ if (json === null || typeof json !== "object") {
227
+ return { normalized: json, applied: false, steps: [] };
228
+ }
229
+ const obj = json;
230
+ let mutated = false;
231
+ const appliedSteps = [];
232
+ // ── Step 1: Prose prefix → thought backfill ──
233
+ const hasThought = "thought" in obj;
234
+ const thoughtValue = obj.thought;
235
+ const thoughtEmpty = !hasThought ||
236
+ thoughtValue === null ||
237
+ thoughtValue === undefined ||
238
+ (typeof thoughtValue === "string" && thoughtValue.trim() === "");
239
+ if (thoughtEmpty) {
240
+ const prefix = extractProsePrefix(raw);
241
+ if (prefix.length > 0) {
242
+ obj.thought = prefix;
243
+ mutated = true;
244
+ appliedSteps.push("prose backfill");
245
+ }
246
+ }
247
+ // ── Step 2: Bare {tool, input} → auto-wrap ──
248
+ // Guard: only when NO `action` key exists, AND `tool` is a non-empty string,
249
+ // AND this is NOT a bare final_answer shape (AC-8: has summary/deliverable/files_touched).
250
+ const hasAction = "action" in obj;
251
+ const hasTool = "tool" in obj;
252
+ const toolValue = obj.tool;
253
+ const isBareTool = !hasAction &&
254
+ hasTool &&
255
+ typeof toolValue === "string" &&
256
+ toolValue.length > 0;
257
+ const hasFinalAnswerKeys = ("summary" in obj && typeof obj.summary === "string" && obj.summary.length > 0) ||
258
+ "deliverable" in obj ||
259
+ "files_touched" in obj;
260
+ if (isBareTool && !hasFinalAnswerKeys) {
261
+ const actionObj = { tool: obj.tool };
262
+ if ("input" in obj) {
263
+ actionObj.input = obj.input;
264
+ }
265
+ delete obj.tool;
266
+ delete obj.input;
267
+ obj.action = actionObj;
268
+ mutated = true;
269
+ appliedSteps.push("bare-tool wrap");
270
+ }
271
+ // ── Step 2.5: Arguments → input alias inside action ──
272
+ // Guard: action exists as non-null object, has `arguments` key,
273
+ // and does NOT already have an `input` key.
274
+ // Transform: action.input = action.arguments; delete action.arguments.
275
+ const actionValForArgs = obj.action;
276
+ if (actionValForArgs !== null &&
277
+ typeof actionValForArgs === "object") {
278
+ const actionObj = actionValForArgs;
279
+ if ("arguments" in actionObj && !("input" in actionObj)) {
280
+ actionObj.input = actionObj.arguments;
281
+ delete actionObj.arguments;
282
+ mutated = true;
283
+ appliedSteps.push("arguments→input alias");
284
+ }
285
+ }
286
+ // ── Step 3: Nested thought hoisting ──
287
+ // Guard: only when action is an object with a `thought` key,
288
+ // AND top-level thought is missing or empty.
289
+ const topThoughtEmpty = !("thought" in obj) ||
290
+ obj.thought === null ||
291
+ obj.thought === undefined ||
292
+ (typeof obj.thought === "string" && obj.thought.trim() === "");
293
+ const actionVal = obj.action;
294
+ if (topThoughtEmpty &&
295
+ actionVal !== null &&
296
+ typeof actionVal === "object" &&
297
+ "thought" in actionVal) {
298
+ const actionObj = actionVal;
299
+ const nestedThought = actionObj.thought;
300
+ if (typeof nestedThought === "string" &&
301
+ nestedThought.trim().length > 0) {
302
+ obj.thought = nestedThought;
303
+ delete actionObj.thought;
304
+ mutated = true;
305
+ appliedSteps.push("nested-thought hoist");
306
+ }
307
+ }
308
+ // ── Step 4: Command → tool alias inside action ──
309
+ // Guard: action exists as non-null object, has `command` key with
310
+ // non-empty string value, and does NOT already have a `tool` key.
311
+ // Transform: action.tool = action.command; delete action.command.
312
+ const actionValForCmd = obj.action;
313
+ if (actionValForCmd !== null &&
314
+ typeof actionValForCmd === "object") {
315
+ const actionObj = actionValForCmd;
316
+ const hasCommand = "command" in actionObj &&
317
+ typeof actionObj.command === "string" &&
318
+ actionObj.command.length > 0;
319
+ const hasTool = "tool" in actionObj;
320
+ if (hasCommand && !hasTool) {
321
+ actionObj.tool = actionObj.command;
322
+ delete actionObj.command;
323
+ mutated = true;
324
+ appliedSteps.push("command→tool alias");
325
+ }
326
+ }
327
+ return {
328
+ normalized: obj,
329
+ applied: mutated,
330
+ steps: appliedSteps,
331
+ };
332
+ }
333
+ /**
334
+ * Layer 5 helper: generates a contextual default thought when the LLM
335
+ * omitted the required `thought` field but provided a structurally valid
336
+ * action or final_answer. The [auto] prefix makes recovery visible in
337
+ * transcripts without blocking the message.
338
+ */
339
+ function generateDefaultThought(context) {
340
+ if (context.hasAction) {
341
+ const tool = context.toolName ? ` ${context.toolName}` : "";
342
+ return `[auto] calling${tool}`;
343
+ }
344
+ if (context.hasFinalAnswer) {
345
+ return "[auto] final answer";
346
+ }
347
+ return "[auto]";
348
+ }
349
+ /**
350
+ * Layer 5 helper: determines if a Zod validation failure is eligible for
351
+ * auto-thought recovery. Recovery is allowed when:
352
+ * - `thought` is missing or undefined (the primary failure mode)
353
+ * - AND exactly one of `action` or `final_answer` is present and
354
+ * structurally valid (so we're not recovering a genuinely confused
355
+ * message that has both or neither).
356
+ */
357
+ function canAutoRecover(result, json) {
358
+ const issues = result.error.issues;
359
+ const hasThoughtIssue = issues.some((i) => i.path.length === 1 &&
360
+ i.path[0] === "thought" &&
361
+ (i.code === z.ZodIssueCode.invalid_type ||
362
+ i.code === z.ZodIssueCode.too_small));
363
+ if (!hasThoughtIssue)
364
+ return false;
365
+ const hasAction = json.action !== null &&
366
+ json.action !== undefined &&
367
+ typeof json.action === "object";
368
+ const hasFinal = json.final_answer !== null &&
369
+ json.final_answer !== undefined &&
370
+ typeof json.final_answer === "object";
371
+ // Must have exactly one of action/final_answer (mutual exclusion)
372
+ if (hasAction === hasFinal)
373
+ return false;
374
+ // Action must have a tool key with non-empty string value
375
+ if (hasAction) {
376
+ const actionObj = json.action;
377
+ const toolOk = "tool" in actionObj &&
378
+ typeof actionObj.tool === "string" &&
379
+ actionObj.tool.length > 0;
380
+ if (!toolOk)
381
+ return false;
382
+ }
383
+ // Final answer must have summary or deliverable
384
+ if (hasFinal) {
385
+ const faObj = json.final_answer;
386
+ if (!("summary" in faObj || "deliverable" in faObj))
387
+ return false;
388
+ }
389
+ return true;
390
+ }
391
+ /**
392
+ * Parses a raw model completion against the contract with layered defence.
393
+ *
394
+ * Layer 0: trim + markdown fence removal (existing tolerance)
395
+ * Layer 1: xml tag stripping (prevents "Unexpected token '<'")
396
+ * Layer 2: outermost-JSON extraction on initial parse failure
397
+ * Layer 3: normalize known LLM JSON-shape drifts (new)
398
+ * Layer 4a: prose-only recovery (no `{` → treat full text as thought)
399
+ * Layer 4b: XML-enveloped prose recovery (has `{` but extraction failed → re-strip XML, treat as thought)
400
+ * Final gate: Zod ReactMessageSchema.safeParse — no interpretation without validation
401
+ */
402
+ /**
403
+ * Extracts a byte-position context window from a SyntaxError thrown by JSON.parse.
404
+ * Returns the excerpt (±80 chars around the error position) and the byte offset,
405
+ * or null if the position cannot be extracted.
406
+ */
407
+ function extractErrorContext(source, error) {
408
+ const match = error.message.match(/position\s+(\d+)/i);
409
+ if (!match)
410
+ return null;
411
+ const pos = parseInt(match[1], 10);
412
+ if (isNaN(pos))
413
+ return null;
414
+ const start = Math.max(0, pos - 80);
415
+ const end = Math.min(source.length, pos + 80);
416
+ return { excerpt: source.slice(start, end), position: pos };
417
+ }
418
+ /**
419
+ * Builds a diagnostic error string for unrecoverable parse failures.
420
+ * Includes the original parse error, list of attempted recovery layers,
421
+ * optional byte-position context window, and a raw input preview.
422
+ */
423
+ function buildErrorDiagnostic(parseError, layersAttempted, context, rawPreview) {
424
+ const lines = [
425
+ `response was not valid JSON: ${parseError}`,
426
+ `[layers attempted: ${layersAttempted.join(", ")}]`,
427
+ ];
428
+ if (context !== null) {
429
+ lines.push(`[context at byte ${context.position}: …${context.excerpt}…]`);
430
+ }
431
+ lines.push(`[raw preview: ${rawPreview}]`);
432
+ return lines.join("\n");
433
+ }
434
+ export function parseReactMessage(raw) {
435
+ // Layer 0: trim + markdown fence removal (original tolerance)
436
+ const stripped = raw
437
+ .trim()
438
+ .replace(/^```(?:json)?\s*/i, "")
439
+ .replace(/\s*```$/i, "");
440
+ // Attempt 1: direct JSON.parse (with xml stripping)
441
+ const layer1 = stripXmlTags(stripped);
442
+ // Layer 1.5: escape raw control characters inside string literals
443
+ // (e.g. literal newlines in multi-line file content) before any parse
444
+ // attempt — this is a common failure mode `JSON.parse` cannot recover
445
+ // from on its own, and letting it through unpatched would defeat the
446
+ // string-awareness of Layer 2's extraction too.
447
+ const sanitized = sanitizeControlCharacters(layer1);
448
+ let json;
449
+ let parseError = null;
450
+ let parseErrObj = null;
451
+ let usedRecovery = false;
452
+ const layersAttempted = [];
453
+ try {
454
+ json = JSON.parse(sanitized);
455
+ }
456
+ catch (e) {
457
+ parseErrObj = e;
458
+ parseError = e.message;
459
+ usedRecovery = true;
460
+ layersAttempted.push("XML-strip", "control-char sanitize");
461
+ // Layer 2: outermost-JSON extraction
462
+ const extracted = extractOutermostJson(sanitized);
463
+ if (extracted) {
464
+ try {
465
+ json = JSON.parse(extracted);
466
+ parseError = null; // recovered successfully
467
+ }
468
+ catch (_e2) {
469
+ // extraction didn't help, keep original parseError
470
+ layersAttempted.push("outermost-JSON extract");
471
+ }
472
+ }
473
+ // Layer 4a: prose-only recovery — no `{` means model sent pure reasoning prose.
474
+ // Only recovers when the resulting thought is non-empty after trimming.
475
+ // An empty/whitespace-only thought is rejected to uphold the Zod schema
476
+ // requirement thought: z.string().min(1).
477
+ if (parseError !== null && !sanitized.includes("{")) {
478
+ const trimmed = sanitized.trim();
479
+ if (trimmed.length > 0) {
480
+ layersAttempted.push("prose-to-thought");
481
+ return {
482
+ ok: true,
483
+ message: {
484
+ thought: trimmed,
485
+ action: null,
486
+ final_answer: null,
487
+ },
488
+ };
489
+ }
490
+ // Empty/whitespace-only prose — reject with clear error
491
+ parseError = `prose-only recovery rejected: thought is empty or whitespace-only after trimming`;
492
+ }
493
+ // Layer 4b: XML-enveloped prose recovery — has `{` but outermost extraction returned empty;
494
+ // re-strip XML tags from the raw stripped text and treat remaining prose as thought.
495
+ // Only fires when stripXmlTags actually removed an XML envelope (reStripped ≠ stripped).
496
+ // Only recovers when the resulting thought is non-empty after trimming.
497
+ if (parseError !== null && !extracted) {
498
+ const reStripped = stripXmlTags(stripped).trim();
499
+ if (reStripped.length > 0 && reStripped !== stripped.trim()) {
500
+ layersAttempted.push("XML-enveloped-prose-to-thought");
501
+ return {
502
+ ok: true,
503
+ message: {
504
+ thought: reStripped,
505
+ action: null,
506
+ final_answer: null,
507
+ },
508
+ };
509
+ }
510
+ }
511
+ }
512
+ if (parseError !== null) {
513
+ const context = parseErrObj ? extractErrorContext(sanitized, parseErrObj) : null;
514
+ const rawPreview = raw.slice(0, 200) + (raw.length > 200 ? "..." : "");
515
+ return {
516
+ ok: false,
517
+ error: buildErrorDiagnostic(parseError, layersAttempted, context, rawPreview),
518
+ };
519
+ }
520
+ // Layer 3: normalize known LLM JSON-shape drifts
521
+ const { normalized: jsonForValidation, applied: normalizationApplied, steps: normalizationSteps } = normalizeReactShape(layer1, json);
522
+ const result = ReactMessageSchema.safeParse(jsonForValidation);
523
+ if (!result.success) {
524
+ // Layer 5: auto-thought recovery — when LLM omitted thought but
525
+ // provided a structurally valid action or final_answer, inject a
526
+ // contextual default thought and retry validation.
527
+ const normObj = jsonForValidation;
528
+ if (canAutoRecover(result, normObj)) {
529
+ const hasAction = normObj.action !== null &&
530
+ normObj.action !== undefined &&
531
+ typeof normObj.action === "object";
532
+ const toolName = hasAction
533
+ ? normObj.action.tool
534
+ : undefined;
535
+ normObj.thought = generateDefaultThought({
536
+ hasAction,
537
+ toolName,
538
+ hasFinalAnswer: normObj.final_answer !== null &&
539
+ normObj.final_answer !== undefined &&
540
+ typeof normObj.final_answer === "object",
541
+ });
542
+ const retryResult = ReactMessageSchema.safeParse(normObj);
543
+ if (retryResult.success) {
544
+ return { ok: true, message: retryResult.data };
545
+ }
546
+ // Retry failed — fall through to error with accurate suffix
547
+ const recoveryNote = usedRecovery ? " [parsed via recovery, but failed schema validation]" : "";
548
+ const normNote = normalizationApplied
549
+ ? " [normalization ran but thought still missing]"
550
+ : "";
551
+ return {
552
+ ok: false,
553
+ error: result.error.issues.map((i) => i.message).join("; ") +
554
+ recoveryNote +
555
+ normNote,
556
+ };
557
+ }
558
+ const recoveryNote = usedRecovery ? " [parsed via recovery, but failed schema validation]" : "";
559
+ const normNote = normalizationApplied ? " [normalization applied]" : "";
560
+ return {
561
+ ok: false,
562
+ error: result.error.issues.map((i) => i.message).join("; ") +
563
+ recoveryNote +
564
+ normNote,
565
+ };
566
+ }
567
+ return { ok: true, message: result.data };
568
+ }
569
+ const CONTRACT_SPEC = `
570
+ # RESPONSE CONTRACT — read carefully, this is enforced by a parser, not a suggestion
571
+
572
+ Respond with ONE JSON object and nothing else. No prose before or after it,
573
+ no markdown commentary — a fenced \`\`\`json block is fine, plain JSON is fine,
574
+ anything else fails to parse and costs you a turn.
575
+
576
+ Do NOT wrap your JSON response in XML tags (no <thought>, <thinking>,
577
+ <response>, <answer>, or any other XML/HTML envelope).
578
+
579
+ Shape:
580
+ {
581
+ "thought": "<your reasoning about what to do next, always present>",
582
+ "action": { "tool": "<tool_name>", "input": { ...tool-specific } } | null,
583
+ "final_answer": {
584
+ "summary": "<what you did, in plain language>",
585
+ "deliverable": <the actual output this subtask promised — shape depends on the subtask>,
586
+ "files_touched": ["path/one", "path/two"],
587
+ "self_check": { "ran": true, "passed": true, "detail": "<what you ran and what it showed>" }
588
+ } | null
589
+ }
590
+
591
+ Rules:
592
+ - Exactly one of "action" / "final_answer" is non-null. Never both, never neither.
593
+ - Use "action" every turn you still need to gather information or make a change.
594
+ - Use "final_answer" only once — it ends your run for this subtask.
595
+ - If your role has a mechanical way to check your own work (running tests, a
596
+ build, a linter, the tool this subtask exists to exercise), do that at
597
+ least once via "action" before you emit "final_answer", and report it in
598
+ "self_check". This does not replace the Master Orchestrator's own
599
+ validation — it's how you catch your own mistakes early, cheaply.
600
+ `.trim();
601
+ /**
602
+ * Build a system prompt for any agent (Sub Agent or Samurai) from a common
603
+ * set of inputs. The prompt format is shared across both agent types — only
604
+ * the identity block, goal/context section, and framing differ.
605
+ */
606
+ export function buildAgentSystemPrompt(opts) {
607
+ const toolDocs = opts.tools
608
+ .map((t) => `- \`${t.name}\` — ${t.description}\n input: ${t.inputHint}`)
609
+ .join("\n");
610
+ const identityBlock = opts.isStandalone
611
+ ? `You are ${opts.agentName}, a standalone AI agent CLI with full access to the tool suite below.`
612
+ : `You are the "${opts.agentName}" role inside Xcoder SDLC, a SDLC-aware multi-agent CLI.
613
+ You are running as an isolated Sub Agent: this subtask, the tools below, and
614
+ your own memory of this conversation are the ONLY things you have. You
615
+ cannot see other subtasks' internal reasoning, only whatever has been
616
+ inlined into your context below.
617
+
618
+ If you crash or throw partway through, the Master Orchestrator does NOT
619
+ crash with you — it records what happened and, where possible, retries you
620
+ through the normal bounded healing process. That doesn't mean take
621
+ reckless actions; it means a tool failing is something to observe and
622
+ adapt to, not something to be blocked by.`;
623
+ const goalBlock = opts.goal
624
+ ? `\n## Your directive\n${opts.roleDescription}\n\n## Your subtask\n- goal: ${opts.goal}`
625
+ : `\n## Your directive\n${opts.roleDescription}`;
626
+ const bylawBlock = opts.bylawContext
627
+ ? `\n\n${opts.bylawContext}`
628
+ : "";
629
+ const contextBlock = opts.upstreamContext
630
+ ? `\n\n## Inlined context from upstream subtasks\n\`\`\`json\n${opts.upstreamContext}\n\`\`\``
631
+ : "";
632
+ const lessonBlock = opts.lessonContext
633
+ ? `\n\n## Relevant lessons learned\n${opts.lessonContext}`
634
+ : "";
635
+ return `
636
+ ${identityBlock}
637
+
638
+ ${environmentPromptBlock(opts.environment)}
639
+
640
+ ${detectedCommandsPromptBlock(opts.detectedCommands)}
641
+ ${goalBlock}${bylawBlock}
642
+
643
+ ## Relevant skills
644
+ ${opts.skills.map((s) => `- ${s}`).join("\n") || "- (none bound for this role)"}
645
+
646
+ ${opts.protocolOverride
647
+ ? `## Workspace-level protocol\n${opts.protocolOverride}\n`
648
+ : ""}${contextBlock}${lessonBlock}
649
+
650
+ ## Tools available to you
651
+ ${toolDocs}
652
+
653
+ The workspace index is your source of truth for what files exist. If a
654
+ \`read_file\` call tells you a path isn't in the index, the tool will
655
+ automatically reindex once and retry before giving up — you don't need to
656
+ call \`reindex_workspace\` yourself unless you suspect the index is stale
657
+ after a lot of your own writes.
658
+
659
+ For any non-trivial change to an EXISTING file, prefer \`edit_file\` over
660
+ \`write_file\` — \`write_file\` requires you to reproduce the entire file
661
+ correctly, which is exactly where large files go wrong. Use \`glob\`/\`grep\`
662
+ to find things instead of guessing paths or shelling out to \`find\`/\`grep\`.
663
+
664
+ ${CONTRACT_SPEC}
665
+ `.trim();
666
+ }
667
+ /**
668
+ * Thin wrapper around buildAgentSystemPrompt that maps a SubtaskNode onto
669
+ * the generic AgentSystemPromptOptions shape. Kept for backward
670
+ * compatibility with the existing SubAgent caller.
671
+ */
672
+ export function buildSystemPrompt(opts) {
673
+ const upstreamCtx = Object.keys(opts.subtask.upstreamContext).length
674
+ ? JSON.stringify(opts.subtask.upstreamContext, null, 2)
675
+ : undefined;
676
+ const goalText = [
677
+ `- id: ${opts.subtask.id}`,
678
+ `- stage: ${opts.subtask.stage}`,
679
+ `- goal: ${opts.subtask.goal}`,
680
+ `- what you must deliver back to the Master Orchestrator: ${opts.subtask.deliverableSpec}`,
681
+ `- acceptance criteria (the Validation Gate checks these independently — you`,
682
+ ` are not the one who decides you passed):`,
683
+ ...opts.subtask.acceptanceCriteria.map((ac) => ` - [${ac.id}] (${ac.type}) ${ac.description}`),
684
+ ].join("\n");
685
+ return buildAgentSystemPrompt({
686
+ agentName: opts.role,
687
+ roleDescription: opts.directive,
688
+ directive: opts.directive,
689
+ skills: opts.skills,
690
+ tools: opts.tools,
691
+ environment: opts.environment,
692
+ detectedCommands: opts.detectedCommands,
693
+ goal: goalText,
694
+ upstreamContext: upstreamCtx,
695
+ protocolOverride: opts.protocolOverride,
696
+ isStandalone: false,
697
+ });
698
+ }