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,9 @@
1
+ import type { SubtaskResult, TaskRun } from "../types.js";
2
+ /**
3
+ * Records a lesson learned from a subtask result into .xcoder/lesson.md
4
+ * if the result passed validation and subtask.role is not "conversation".
5
+ * Checks file size before appending to prevent unbounded growth.
6
+ */
7
+ export declare function recordTaskLesson(workspaceRoot: string, result: SubtaskResult, run: TaskRun, nodeId: string): Promise<void>;
8
+ /** Re-export for convenience */
9
+ export { checkLessonFileSize } from "../orchestrator/lesson-manager.js";
@@ -0,0 +1,27 @@
1
+ import { checkLessonFileSize, recordLesson } from "../orchestrator/lesson-manager.js";
2
+ /**
3
+ * Records a lesson learned from a subtask result into .xcoder/lesson.md
4
+ * if the result passed validation and subtask.role is not "conversation".
5
+ * Checks file size before appending to prevent unbounded growth.
6
+ */
7
+ export async function recordTaskLesson(workspaceRoot, result, run, nodeId) {
8
+ if (result.crashed)
9
+ return;
10
+ // Only record for non-conversation roles with a valid self-check.
11
+ if (!result.selfCheck?.passed)
12
+ return;
13
+ // Check file size before recording.
14
+ const ok = await checkLessonFileSize(workspaceRoot);
15
+ if (typeof ok === "string")
16
+ return; // warning string returned, skip
17
+ const entry = {
18
+ source: `sub-agent:${nodeId}`,
19
+ taskId: run.spec.taskId,
20
+ tags: ["lesson"],
21
+ context: result.summary.slice(0, 200),
22
+ lesson: result.summary,
23
+ };
24
+ await recordLesson(workspaceRoot, entry);
25
+ }
26
+ /** Re-export for convenience */
27
+ export { checkLessonFileSize } from "../orchestrator/lesson-manager.js";
@@ -0,0 +1,47 @@
1
+ import type { SubtaskNode, SubtaskStatus, TaskRun, TaskSpec } from "../types.js";
2
+ import type { WksProtocolMap } from "../protocol/wks-protocol-manager.js";
3
+ import type { OrchestratorOptions } from "./sdlc-orchestrator.js";
4
+ /** Shared result from initialization. */
5
+ export interface InitializationResult {
6
+ run: TaskRun;
7
+ isConversation: boolean;
8
+ lessonContext: string | undefined;
9
+ }
10
+ /**
11
+ * Builds or loads the initial DAG for a task run.
12
+ * - For new tasks: builds the initial plan via task-factory
13
+ * - For resume tasks: loads the existing TaskRun from disk
14
+ * - Migrates legacy defects
15
+ * - Reconciles orphaned tasks
16
+ * - Runs initial lesson loading if lessonLearned
17
+ */
18
+ export declare function initializeRun(spec: TaskSpec, opts: OrchestratorOptions, protocolMap: WksProtocolMap, masterProtocolSection: string | undefined, customDag?: SubtaskNode[]): Promise<InitializationResult>;
19
+ /**
20
+ * Resumes an existing TaskRun from disk, resetting healing budgets
21
+ * on escalated/healing nodes while preserving healing.log.
22
+ */
23
+ export declare function resumeRun(taskId: string, opts: OrchestratorOptions, protocolMap: WksProtocolMap, masterProtocolSection: string | undefined): Promise<InitializationResult>;
24
+ /**
25
+ * Node statuses that must be returned to an executable state before a resumed
26
+ * run can pick them up. A process that died mid-flight leaves nodes at
27
+ * `in_progress`/`validating`; a blocked dependency leaves `blocked`/`failed`.
28
+ * `recomputeReady()` only ever promotes `pending`, so nothing re-arms these by
29
+ * itself — the execution loop would find zero ready nodes and exit silently.
30
+ */
31
+ export declare const REARM_ON_RESUME: readonly SubtaskStatus[];
32
+ /**
33
+ * Returns nodes to an executable state for a resumed run. Mutates in place.
34
+ *
35
+ * Rules (by precedence):
36
+ * 1. "done" → untouched. Never re-executed, results kept.
37
+ * 2. "pending"/"ready" → untouched; recomputeReady() promotes pending
38
+ * once its dependencies land.
39
+ * 3. escalated/healing/failed/blocked
40
+ * 4. in_progress/validating (crash-orphaned)
41
+ * → status="ready", healing.attempts=0, healing.log
42
+ * kept so the failure history is not lost.
43
+ * 5. unknown status → left alone (fail-safe; never guessed into ready).
44
+ *
45
+ * @returns number of nodes re-armed.
46
+ */
47
+ export declare function rearmForResume(dag: SubtaskNode[]): number;
@@ -0,0 +1,135 @@
1
+ import { buildInitialPlan, isConversation } from "../orchestrator/task-factory.js";
2
+ import { loadTaskRun, reconcileOrphanedTasks } from "../store/task-store.js";
3
+ import { getOrBuildIndex } from "../tools/workspace-index.js";
4
+ import { migrateLegacyDefects } from "../orchestrator/defect-migration.js";
5
+ import { loadLessons, checkLessonFileSize } from "../orchestrator/lesson-manager.js";
6
+ import * as term from "../util/terminal.js";
7
+ import { emitXcoderEvent } from "../events/bus.js";
8
+ import { dagSnapshot } from "./dag-utils.js";
9
+ /**
10
+ * Builds or loads the initial DAG for a task run.
11
+ * - For new tasks: builds the initial plan via task-factory
12
+ * - For resume tasks: loads the existing TaskRun from disk
13
+ * - Migrates legacy defects
14
+ * - Reconciles orphaned tasks
15
+ * - Runs initial lesson loading if lessonLearned
16
+ */
17
+ export async function initializeRun(spec, opts, protocolMap, masterProtocolSection, customDag) {
18
+ await getOrBuildIndex(opts.workspaceRoot);
19
+ // One-time migration of legacy defects/ -> .xcoder/defects/
20
+ try {
21
+ await migrateLegacyDefects(opts.workspaceRoot);
22
+ }
23
+ catch (e) {
24
+ term.orchestratorNote(`defect migration warning: ${e.message}`);
25
+ }
26
+ const orphaned = await reconcileOrphanedTasks(opts.workspaceRoot);
27
+ for (const o of orphaned) {
28
+ term.orchestratorNote(`reconciled orphaned task ${o.taskId} ("${o.goal.slice(0, 50)}...") — was stuck at "running" from a prior process, marked halted`);
29
+ }
30
+ // Load lessons learned if enabled.
31
+ let lessonContext;
32
+ if (opts.lessonLearned) {
33
+ const warning = await checkLessonFileSize(opts.workspaceRoot);
34
+ if (warning) {
35
+ term.orchestratorNote(warning);
36
+ }
37
+ lessonContext = await loadLessons(opts.workspaceRoot);
38
+ }
39
+ if (isConversation(spec)) {
40
+ return { run: null, isConversation: true, lessonContext };
41
+ }
42
+ const dag = customDag ?? buildInitialPlan(spec);
43
+ const run = {
44
+ spec,
45
+ dag,
46
+ status: "running",
47
+ escalations: [],
48
+ orchestratorTrace: [],
49
+ finalDeliverable: undefined,
50
+ totalTokenUsage: { inputTokens: 0, outputTokens: 0 },
51
+ };
52
+ term.taskIntro(spec.taskId, spec.goal);
53
+ emitXcoderEvent({ type: "task:intro", taskId: spec.taskId, data: { goal: spec.goal } });
54
+ term.orchestratorNote(`plan built: ${dag.map((n) => n.id).join(" → ")}`);
55
+ term.orchestratorNote(`logs: ${spec.taskId}`);
56
+ emitXcoderEvent({ type: "task:dag", taskId: spec.taskId, data: dagSnapshot(dag) });
57
+ return { run, isConversation: false, lessonContext };
58
+ }
59
+ /**
60
+ * Resumes an existing TaskRun from disk, resetting healing budgets
61
+ * on escalated/healing nodes while preserving healing.log.
62
+ */
63
+ export async function resumeRun(taskId, opts, protocolMap, masterProtocolSection) {
64
+ const run = await loadTaskRun(opts.workspaceRoot, taskId);
65
+ if (!run) {
66
+ throw new Error(`no task "${taskId}" found in ${opts.workspaceRoot} to resume.`);
67
+ }
68
+ if (run.status === "done") {
69
+ term.orchestratorNote(`${taskId} is already done — nothing to resume.`);
70
+ return { run, isConversation: false, lessonContext: undefined };
71
+ }
72
+ await getOrBuildIndex(opts.workspaceRoot);
73
+ const orphaned = await reconcileOrphanedTasks(opts.workspaceRoot);
74
+ for (const o of orphaned) {
75
+ if (o.taskId !== taskId)
76
+ term.orchestratorNote(`also reconciled orphaned task ${o.taskId}`);
77
+ else
78
+ term.orchestratorNote(`${taskId} was still marked "running" (a prior process died) — reconciled to "halted" and resuming.`);
79
+ }
80
+ const resumeCount = rearmForResume(run.dag);
81
+ term.taskIntro(run.spec.taskId, `[resume] ${run.spec.goal}`);
82
+ emitXcoderEvent({ type: "task:intro", taskId: run.spec.taskId, data: { goal: run.spec.goal, resumed: true } });
83
+ term.orchestratorNote(`resuming ${taskId}: ${resumeCount} subtask(s) reset to ready with a fresh healing budget, ${run.dag.filter((n) => n.status === "done").length}/${run.dag.length} already done`);
84
+ run.status = "running";
85
+ run.orchestratorTrace.push({
86
+ thought: "resumed by user request",
87
+ action: null,
88
+ observation: `${resumeCount} subtask(s) re-armed for another attempt; already-done subtasks and their outputs were kept as-is.`,
89
+ });
90
+ emitXcoderEvent({ type: "task:dag", taskId: run.spec.taskId, data: dagSnapshot(run.dag) });
91
+ return { run, isConversation: false, lessonContext: undefined };
92
+ }
93
+ /**
94
+ * Node statuses that must be returned to an executable state before a resumed
95
+ * run can pick them up. A process that died mid-flight leaves nodes at
96
+ * `in_progress`/`validating`; a blocked dependency leaves `blocked`/`failed`.
97
+ * `recomputeReady()` only ever promotes `pending`, so nothing re-arms these by
98
+ * itself — the execution loop would find zero ready nodes and exit silently.
99
+ */
100
+ export const REARM_ON_RESUME = [
101
+ "escalated",
102
+ "healing",
103
+ "failed",
104
+ "blocked",
105
+ "in_progress",
106
+ "validating",
107
+ ];
108
+ /**
109
+ * Returns nodes to an executable state for a resumed run. Mutates in place.
110
+ *
111
+ * Rules (by precedence):
112
+ * 1. "done" → untouched. Never re-executed, results kept.
113
+ * 2. "pending"/"ready" → untouched; recomputeReady() promotes pending
114
+ * once its dependencies land.
115
+ * 3. escalated/healing/failed/blocked
116
+ * 4. in_progress/validating (crash-orphaned)
117
+ * → status="ready", healing.attempts=0, healing.log
118
+ * kept so the failure history is not lost.
119
+ * 5. unknown status → left alone (fail-safe; never guessed into ready).
120
+ *
121
+ * @returns number of nodes re-armed.
122
+ */
123
+ export function rearmForResume(dag) {
124
+ let rearmed = 0;
125
+ for (const node of dag) {
126
+ if (node.status === "done" || node.status === "pending" || node.status === "ready")
127
+ continue;
128
+ if (!REARM_ON_RESUME.includes(node.status))
129
+ continue;
130
+ node.status = "ready";
131
+ node.healing.attempts = 0;
132
+ rearmed++;
133
+ }
134
+ return rearmed;
135
+ }
@@ -0,0 +1,10 @@
1
+ import type { TaskRun } from "../types.js";
2
+ /**
3
+ * Persists the current DAG state and progress summary to disk.
4
+ * Emits task:dag event, saves TaskRun atomically, and writes progress summary markdown.
5
+ */
6
+ export declare function saveProgress(workspaceRoot: string, run: TaskRun): Promise<void>;
7
+ /**
8
+ * Persists the DAG state (synchronous fallback when event loop may be draining).
9
+ */
10
+ export declare function saveProgressWithFallback(workspaceRoot: string, run: TaskRun, saveTaskRunSync: (root: string, run: TaskRun) => void): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { saveTaskRun } from "../store/task-store.js";
2
+ import { saveProgressSummary } from "../store/task-store.js";
3
+ import { buildProgressSummaryMarkdown } from "../orchestrator/progress-summary.js";
4
+ import { emitXcoderEvent } from "../events/bus.js";
5
+ import { dagSnapshot } from "./dag-utils.js";
6
+ import * as term from "../util/terminal.js";
7
+ /**
8
+ * Persists the current DAG state and progress summary to disk.
9
+ * Emits task:dag event, saves TaskRun atomically, and writes progress summary markdown.
10
+ */
11
+ export async function saveProgress(workspaceRoot, run) {
12
+ await saveTaskRun(workspaceRoot, run);
13
+ emitXcoderEvent({ type: "task:dag", taskId: run.spec.taskId, data: dagSnapshot(run.dag) });
14
+ const progressMd = buildProgressSummaryMarkdown(run);
15
+ await saveProgressSummary(workspaceRoot, run.spec.taskId, progressMd);
16
+ term.orchestratorNote(`progress summary written: .xcoder/tasks/${run.spec.taskId}.md`);
17
+ }
18
+ /**
19
+ * Persists the DAG state (synchronous fallback when event loop may be draining).
20
+ */
21
+ export async function saveProgressWithFallback(workspaceRoot, run, saveTaskRunSync) {
22
+ try {
23
+ await Promise.race([
24
+ saveTaskRun(workspaceRoot, run),
25
+ new Promise((_, reject) => setTimeout(() => reject(new Error("save timed out")), 500)),
26
+ ]);
27
+ }
28
+ catch {
29
+ saveTaskRunSync(workspaceRoot, run);
30
+ }
31
+ emitXcoderEvent({ type: "task:dag", taskId: run.spec.taskId, data: dagSnapshot(run.dag) });
32
+ const progressMd = buildProgressSummaryMarkdown(run);
33
+ await saveProgressSummary(workspaceRoot, run.spec.taskId, progressMd);
34
+ }
@@ -0,0 +1,10 @@
1
+ import type { WksProtocolMap } from "../protocol/wks-protocol-manager.js";
2
+ /**
3
+ * Reads and parses wks_protocol.md from the workspace root.
4
+ * Returns the parsed map and the optional masterProtocolSection.
5
+ * If the file is missing or empty, returns empty map/undefined.
6
+ */
7
+ export declare function loadProtocol(workspaceRoot: string): Promise<{
8
+ protocolMap: WksProtocolMap;
9
+ masterProtocolSection: string | undefined;
10
+ }>;
@@ -0,0 +1,21 @@
1
+ import { parseWksProtocol } from "../protocol/wks-protocol-manager.js";
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ /**
5
+ * Reads and parses wks_protocol.md from the workspace root.
6
+ * Returns the parsed map and the optional masterProtocolSection.
7
+ * If the file is missing or empty, returns empty map/undefined.
8
+ */
9
+ export async function loadProtocol(workspaceRoot) {
10
+ try {
11
+ const filePath = path.join(workspaceRoot, "wks_protocol.md");
12
+ const content = await fs.readFile(filePath, "utf-8");
13
+ const protocolMap = parseWksProtocol(content);
14
+ // "sdlc-orchestrator" is reserved for future LLM-driven orchestrator engines.
15
+ const masterProtocolSection = protocolMap["sdlc-orchestrator"];
16
+ return { protocolMap, masterProtocolSection };
17
+ }
18
+ catch {
19
+ return { protocolMap: {}, masterProtocolSection: undefined };
20
+ }
21
+ }
@@ -0,0 +1,24 @@
1
+ import type { SubtaskNode, SubtaskResult, TaskRun, TaskSpec } from "../types.js";
2
+ /**
3
+ * Pure function: computes the orchestration trace entry, event data, and
4
+ * idempotent defect ID for an iteration-exhausted SubtaskResult. Called
5
+ * by handleResult() during the orchestrator loop; also exported for test.
6
+ */
7
+ export declare function buildExhaustionTrace(nodeId: string, taskId: string, result: SubtaskResult): {
8
+ trace: {
9
+ thought: string;
10
+ action: null;
11
+ observation: string;
12
+ };
13
+ event: {
14
+ type: "agent:exhausted";
15
+ taskId: string;
16
+ subtaskId: string;
17
+ data: {
18
+ maxIterations: number;
19
+ iterationsUsed: number;
20
+ };
21
+ };
22
+ defectId: string;
23
+ };
24
+ export declare function summarize(dag: SubtaskNode[], run: TaskRun, spec: TaskSpec, workspaceRoot: string): string;
@@ -0,0 +1,68 @@
1
+ import { taskLogDir } from "../util/logs.js";
2
+ /**
3
+ * Pure function: computes the orchestration trace entry, event data, and
4
+ * idempotent defect ID for an iteration-exhausted SubtaskResult. Called
5
+ * by handleResult() during the orchestrator loop; also exported for test.
6
+ */
7
+ export function buildExhaustionTrace(nodeId, taskId, result) {
8
+ const maxIterations = result.iterations || 200;
9
+ return {
10
+ trace: {
11
+ thought: `${nodeId} exhausted its ${maxIterations} iterations without a final_answer`,
12
+ action: null,
13
+ observation: result.summary,
14
+ },
15
+ event: {
16
+ type: "agent:exhausted",
17
+ taskId,
18
+ subtaskId: nodeId,
19
+ data: { maxIterations, iterationsUsed: result.iterations },
20
+ },
21
+ defectId: `DEFECT-EXH-${nodeId}`,
22
+ };
23
+ }
24
+ export function summarize(dag, run, spec, workspaceRoot) {
25
+ const lines = [
26
+ `# ${spec.goal}`,
27
+ "",
28
+ `Status: ${run.status}`,
29
+ `Tokens: ${run.totalTokenUsage.inputTokens} in / ${run.totalTokenUsage.outputTokens} out`,
30
+ `Logs: ${taskLogDir(workspaceRoot, spec.taskId)}`,
31
+ "",
32
+ ];
33
+ for (const node of dag) {
34
+ lines.push(`## ${node.id} (${node.role}) — ${node.status}`);
35
+ if (node.result)
36
+ lines.push(node.result.summary);
37
+ if (node.result?.crashed)
38
+ lines.push(`**Crashed** — see sys.log for the stack trace.`);
39
+ if (node.status === "escalated") {
40
+ const esc = run.escalations.find((e) => e.subtaskId === node.id);
41
+ lines.push(`**Escalated:** ${esc?.reason}`);
42
+ }
43
+ lines.push("");
44
+ }
45
+ // --- Files touched section
46
+ const nodesWithFiles = dag.filter((n) => n.result && ((n.result._filesTouchedMeta?.length ?? 0) > 0 || n.result.filesTouched.length > 0));
47
+ if (nodesWithFiles.length > 0) {
48
+ lines.push("## Files touched");
49
+ lines.push("");
50
+ for (const node of nodesWithFiles) {
51
+ lines.push(`### ${node.id}`);
52
+ const meta = node.result._filesTouchedMeta;
53
+ if (meta && meta.length > 0) {
54
+ for (const entry of meta) {
55
+ const label = entry.operation === "created" ? "[created]" : "[modified]";
56
+ lines.push(`- \`${entry.path}\` ${label}`);
57
+ }
58
+ }
59
+ else {
60
+ for (const f of node.result.filesTouched) {
61
+ lines.push(`- \`${f}\` [touched]`);
62
+ }
63
+ }
64
+ lines.push("");
65
+ }
66
+ }
67
+ return lines.join("\n");
68
+ }
@@ -0,0 +1,59 @@
1
+ import type { SubtaskNode, TaskRun, TaskSpec } from "../types.js";
2
+ import type { InterruptAction } from "../orchestrator/interrupt-handler.js";
3
+ import { LlmClient } from "../llm/client.js";
4
+ import { InteractiveSteeringManager } from "../orchestrator/interactive-steering.js";
5
+ export { dagSnapshot, recomputeReady, inlineIntoDependents } from "./dag-utils.js";
6
+ export { summarize, buildExhaustionTrace } from "./reporting.js";
7
+ export interface OrchestratorOptions {
8
+ workspaceRoot: string;
9
+ /** Orchestrator role client — used by the coordinator/conversation loops. */
10
+ llm: LlmClient;
11
+ /** Swarm/Sub Agent role client — used by dispatchSwarm workers. Defaults to `llm`. */
12
+ subAgentLlm?: LlmClient;
13
+ /** Explicit per-role clients — highest priority when all are provided. */
14
+ roleLlm?: Partial<Record<import("../config/loadConfig.js").AgentRole, LlmClient>>;
15
+ concurrency: number;
16
+ maxRounds?: number;
17
+ lessonLearned?: boolean;
18
+ signal?: AbortSignal;
19
+ quiet?: boolean;
20
+ /**
21
+ * Force a full index rebuild before the run instead of probing it first.
22
+ * Backs the `--reindex` flag; freshness is otherwise automatic, so this is
23
+ * an override rather than the only route to an up-to-date index.
24
+ */
25
+ reindex?: boolean;
26
+ }
27
+ export declare class SdlcOrchestrator {
28
+ private opts;
29
+ private protocolMap;
30
+ private masterProtocolSection;
31
+ private lessonContext;
32
+ private _abortController;
33
+ private _steering;
34
+ private _currentRun;
35
+ private _haltDeferred;
36
+ private _index?;
37
+ constructor(opts: OrchestratorOptions);
38
+ /**
39
+ * Gate the workspace index once per task run.
40
+ *
41
+ * Every ingress path needs this: the index is the source of truth for which
42
+ * files exist, and it used to be reused no matter how stale it was. The gate
43
+ * is stat-only while the index is still accurate, so the price of
44
+ * correctness here is one filesystem walk, not a full re-hash.
45
+ *
46
+ * It never throws. A cache refresh failure degrades to the best index
47
+ * available rather than aborting the run — the authorization boundary is
48
+ * `resolveInWorkspace()`, which is untouched and still fails closed.
49
+ */
50
+ private gateIndex;
51
+ /** The index gated for the current run, if a run has started. */
52
+ get index(): import("../tools/workspace-index.js").WorkspaceIndex | undefined;
53
+ get currentRun(): TaskRun | null;
54
+ get steering(): InteractiveSteeringManager;
55
+ run(spec: TaskSpec, customDag?: SubtaskNode[]): Promise<TaskRun>;
56
+ resume(taskId: string): Promise<TaskRun>;
57
+ halt(currentRun: TaskRun): Promise<InterruptAction["summary"]>;
58
+ private _runLoop;
59
+ }
@@ -0,0 +1,170 @@
1
+ import { ensureFreshIndex } from "../tools/index-freshness.js";
2
+ import { logIndexRefresh } from "../util/file-access-log.js";
3
+ import { saveTaskRunSync } from "../store/task-store.js";
4
+ import { FooterManager } from "../util/footer-manager.js";
5
+ import { isInteractiveStdout } from "../util/tty.js";
6
+ import { InteractiveSteeringManager } from "../orchestrator/interactive-steering.js";
7
+ // Helper modules
8
+ import { loadProtocol } from "./protocol-loader.js";
9
+ import { initializeRun, resumeRun } from "./plan-initializer.js";
10
+ import { runConversation } from "./conversation-runner.js";
11
+ import { executeLoop } from "./execution-loop.js";
12
+ import { saveProgress } from "./progress-persister.js";
13
+ import { haltInternal, checkSteeringInjection } from "./steering-handler.js";
14
+ // Re-exported for consumer compatibility
15
+ export { dagSnapshot, recomputeReady, inlineIntoDependents } from "./dag-utils.js";
16
+ export { summarize, buildExhaustionTrace } from "./reporting.js";
17
+ export class SdlcOrchestrator {
18
+ opts;
19
+ protocolMap = {};
20
+ masterProtocolSection = undefined;
21
+ lessonContext = undefined;
22
+ _abortController = null;
23
+ _steering = new InteractiveSteeringManager();
24
+ _currentRun = null;
25
+ _haltDeferred = null;
26
+ _index;
27
+ constructor(opts) {
28
+ this.opts = opts;
29
+ }
30
+ /**
31
+ * Gate the workspace index once per task run.
32
+ *
33
+ * Every ingress path needs this: the index is the source of truth for which
34
+ * files exist, and it used to be reused no matter how stale it was. The gate
35
+ * is stat-only while the index is still accurate, so the price of
36
+ * correctness here is one filesystem walk, not a full re-hash.
37
+ *
38
+ * It never throws. A cache refresh failure degrades to the best index
39
+ * available rather than aborting the run — the authorization boundary is
40
+ * `resolveInWorkspace()`, which is untouched and still fails closed.
41
+ */
42
+ async gateIndex(taskId) {
43
+ const result = await ensureFreshIndex(this.opts.workspaceRoot, {
44
+ force: this.opts.reindex === true,
45
+ });
46
+ this._index = result.index;
47
+ if (!this.opts.quiet) {
48
+ try {
49
+ await logIndexRefresh(this.opts.workspaceRoot, result, {
50
+ taskId: taskId ?? "session",
51
+ subtaskId: "-",
52
+ });
53
+ }
54
+ catch {
55
+ // observability must never break a run
56
+ }
57
+ }
58
+ }
59
+ /** The index gated for the current run, if a run has started. */
60
+ get index() {
61
+ return this._index;
62
+ }
63
+ get currentRun() {
64
+ return this._currentRun;
65
+ }
66
+ get steering() {
67
+ return this._steering;
68
+ }
69
+ // ── run ──────────────────────────────────────────────────────────
70
+ async run(spec, customDag) {
71
+ await this.gateIndex();
72
+ // Load protocol.
73
+ const { protocolMap, masterProtocolSection } = await loadProtocol(this.opts.workspaceRoot);
74
+ this.protocolMap = protocolMap;
75
+ this.masterProtocolSection = masterProtocolSection;
76
+ const init = await initializeRun(spec, this.opts, protocolMap, masterProtocolSection, customDag);
77
+ this.lessonContext = init.lessonContext;
78
+ if (init.isConversation) {
79
+ return runConversation(spec, this.opts, protocolMap, masterProtocolSection);
80
+ }
81
+ const run = init.run;
82
+ await saveProgress(this.opts.workspaceRoot, run);
83
+ return this._runLoop(run);
84
+ }
85
+ // ── resume ───────────────────────────────────────────────────────
86
+ async resume(taskId) {
87
+ await this.gateIndex();
88
+ const { protocolMap, masterProtocolSection } = await loadProtocol(this.opts.workspaceRoot);
89
+ this.protocolMap = protocolMap;
90
+ this.masterProtocolSection = masterProtocolSection;
91
+ const init = await resumeRun(taskId, this.opts, protocolMap, masterProtocolSection);
92
+ if (init.run.status === "done")
93
+ return init.run;
94
+ const run = init.run;
95
+ await saveProgress(this.opts.workspaceRoot, run);
96
+ return this._runLoop(run);
97
+ }
98
+ // ── halt ─────────────────────────────────────────────────────────
99
+ async halt(currentRun) {
100
+ if (!this._abortController) {
101
+ this._abortController = new AbortController();
102
+ }
103
+ this._abortController.abort();
104
+ if (this._currentRun) {
105
+ return new Promise((resolve, reject) => {
106
+ this._haltDeferred = { resolve, reject };
107
+ });
108
+ }
109
+ // Not running — compute halt inline.
110
+ const summary = await haltInternal(currentRun, this.opts, saveTaskRunSync);
111
+ return summary;
112
+ }
113
+ // ── Private: wraps executeLoop with halt/abort lifecycle ────────
114
+ async _runLoop(run) {
115
+ this._currentRun = run;
116
+ this._abortController = new AbortController();
117
+ const signal = this.opts.signal ?? this._abortController.signal;
118
+ // Wire up the orchestration context with callbacks.
119
+ const ctx = {
120
+ opts: this.opts,
121
+ protocolMap: this.protocolMap,
122
+ masterProtocolSection: this.masterProtocolSection,
123
+ lessonContext: this.lessonContext,
124
+ signal,
125
+ steering: this._steering,
126
+ quiet: this.opts.quiet ?? false,
127
+ onSteeringInjection: async (r) => {
128
+ return checkSteeringInjection(r, this.opts, this._steering);
129
+ },
130
+ onSaveProgress: async (r) => {
131
+ await saveProgress(this.opts.workspaceRoot, r);
132
+ },
133
+ };
134
+ try {
135
+ // Initialize footer iff the interactive gate passes.
136
+ // Availability matrix (single source of truth in src/util/tty.ts):
137
+ // TTY attached AND NO_COLOR unset. Quiet run mode mutes painting.
138
+ FooterManager.init({
139
+ tty: isInteractiveStdout(),
140
+ // Raw goal — the renderer owns the ≤50-char title field (footer-text.ts).
141
+ taskTitle: run.spec.goal,
142
+ quiet: this.opts.quiet ?? false,
143
+ });
144
+ const result = await executeLoop(run, ctx);
145
+ // Cleanup.
146
+ this._currentRun = null;
147
+ this._abortController = null;
148
+ // If halt() was called but the task finished before the abort check,
149
+ // still provide a summary.
150
+ if (this._haltDeferred) {
151
+ const dag = result.dag;
152
+ const summary = {
153
+ taskId: result.spec.taskId,
154
+ doneCount: dag.filter((n) => n.status === "done").length,
155
+ totalCount: dag.length,
156
+ resumeCommand: `xcoder resume ${result.spec.taskId}`,
157
+ taskFilePath: `.xcoder/tasks/${result.spec.taskId}.json`,
158
+ };
159
+ this._haltDeferred.resolve(summary);
160
+ this._haltDeferred = null;
161
+ }
162
+ return result;
163
+ }
164
+ catch (e) {
165
+ this._currentRun = null;
166
+ this._abortController = null;
167
+ throw e;
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,44 @@
1
+ import type { Role, SdlcStage, TaskInputs } from "../types.js";
2
+ export declare const SDLC_STAGES: {
3
+ stage: SdlcStage;
4
+ description: string;
5
+ }[];
6
+ export declare const STAGE_ROLE: Record<SdlcStage, Role>;
7
+ /**
8
+ * Internal roles that exist for traceability and system functions but are
9
+ * not mapped to any DAG stage — they are invoked inline by the orchestrator
10
+ * rather than dispatched as standalone Sub Agents.
11
+ */
12
+ export declare const INTERNAL_ROLES: Role[];
13
+ /**
14
+ * Explicit intake classification. This exists specifically because "the
15
+ * orchestrator infers where to start" was a hidden judgment call in the
16
+ * original sketch — inconsistent behavior waiting to happen. Every rule
17
+ * here is a plain, inspectable predicate over what inputs are actually
18
+ * present, checked top to bottom, first match wins.
19
+ */
20
+ export interface IntakeRule {
21
+ name: string;
22
+ when: (inputs: TaskInputs) => boolean;
23
+ startStage: SdlcStage;
24
+ /** The stage sequence this kind of task walks, in order. */
25
+ sequence: SdlcStage[];
26
+ }
27
+ export declare const INTAKE_RULES: IntakeRule[];
28
+ export declare const CONVERSATION_RULE: IntakeRule;
29
+ export declare function classifyIntake(inputs: TaskInputs): IntakeRule;
30
+ export declare function classifyDesignRole(inputs: TaskInputs): Role;
31
+ /**
32
+ * Returns the Role for a given SdlcStage. For the `design` stage, when
33
+ * `inputs` is provided, this delegates to `classifyDesignRole` to decide
34
+ * between `architect` and `business-analyst`. All other stages — and the
35
+ * `design` stage when `inputs` is omitted — use the static default mapping
36
+ * below, preserving backward compatibility with every existing call site.
37
+ */
38
+ export declare function getStageRole(stage: SdlcStage, inputs?: TaskInputs): Role;
39
+ /**
40
+ * Returns true when the given role is one of the internal (non-DAG-stage)
41
+ * roles such as `defect-manager`. These roles are never dispatched as Sub
42
+ * Agents — they exist for traceability and orchestrator-inline decisions.
43
+ */
44
+ export declare function isInternalRole(role: Role): boolean;