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,174 @@
1
+ // xcoder:version 2 | xcoder:task swarm-swarm-is-b22287 | xcoder:updated 2026-08-04T12:12:06.562Z | xcoder:subtask swarm-swarm-is-b22287/1
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ import { loadDefectsIndex, saveDefectsIndex } from "./defect-store.js";
5
+ import { logMigration } from "./defect-logger.js";
6
+ import { createXcoderPaths } from "../util/xcoder-paths.js";
7
+ // ---------------------------------------------------------------------------
8
+ // Path resolution
9
+ // ---------------------------------------------------------------------------
10
+ const DEFECT_FILE_RE = /^defect(\d{4})\.md$/;
11
+ function sentinelPath(workspaceRoot) {
12
+ return path.join(createXcoderPaths(workspaceRoot).root, ".migrated");
13
+ }
14
+ function legacyDefectsDir(workspaceRoot) {
15
+ return path.join(workspaceRoot, "defects");
16
+ }
17
+ function newDefectsDir(workspaceRoot) {
18
+ return createXcoderPaths(workspaceRoot).defectsDir();
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Public API
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * One-time auto-detection and migration of a legacy `defects/` directory
25
+ * into `.xcoder/defects/`. Runs once per workspace lifetime (guarded by a
26
+ * `.xcoder/.migrated` sentinel file).
27
+ *
28
+ * If the sentinel is absent, checks for a `defects/` directory. If found,
29
+ * moves all `defect*.md` files to `.xcoder/defects/`, writes a
30
+ * `_defects.json` with `status: 'open'` for each, writes
31
+ * `.log/migration.log`, creates the sentinel, and returns the migrated
32
+ * records. If `defects/` doesn't exist, still creates the sentinel to
33
+ * avoid future checks.
34
+ */
35
+ export async function migrateLegacyDefects(workspaceRoot) {
36
+ // Guard: check for sentinel file.
37
+ try {
38
+ await fs.access(sentinelPath(workspaceRoot));
39
+ }
40
+ catch {
41
+ // Sentinel doesn't exist — proceed with migration.
42
+ return runMigration(workspaceRoot);
43
+ }
44
+ // Sentinel exists — migration already performed.
45
+ return [];
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Internal
49
+ // ---------------------------------------------------------------------------
50
+ async function runMigration(workspaceRoot) {
51
+ const migrationEntries = [];
52
+ const timestamp = new Date().toISOString();
53
+ const migrated = [];
54
+ // Check for legacy defects/ directory.
55
+ let entries = [];
56
+ try {
57
+ entries = await fs.readdir(legacyDefectsDir(workspaceRoot));
58
+ }
59
+ catch {
60
+ // No legacy defects/ directory — nothing to migrate. Still create
61
+ // the sentinel so we don't check again.
62
+ await touchSentinel(workspaceRoot);
63
+ return [];
64
+ }
65
+ // Ensure target directory exists.
66
+ await fs.mkdir(newDefectsDir(workspaceRoot), { recursive: true });
67
+ for (const entry of entries) {
68
+ const match = entry.match(DEFECT_FILE_RE);
69
+ if (!match) {
70
+ migrationEntries.push({
71
+ timestamp,
72
+ oldPath: `defects/${entry}`,
73
+ newPath: "",
74
+ defectId: "",
75
+ status: "skipped",
76
+ reason: `File "${entry}" does not match defect pattern (defectNNNN.md).`,
77
+ });
78
+ continue;
79
+ }
80
+ const numericId = match[1];
81
+ const defectId = `DEFECT-${numericId}`;
82
+ const oldAbs = path.join(legacyDefectsDir(workspaceRoot), entry);
83
+ const newAbs = path.join(newDefectsDir(workspaceRoot), entry);
84
+ const oldRel = `defects/${entry}`;
85
+ const newRel = `.xcoder/defects/${entry}`;
86
+ // Only migrate regular files — skip directories, symlinks, etc.
87
+ let stat;
88
+ try {
89
+ stat = await fs.stat(oldAbs);
90
+ }
91
+ catch {
92
+ migrationEntries.push({
93
+ timestamp,
94
+ oldPath: oldRel,
95
+ newPath: newRel,
96
+ defectId,
97
+ status: "failed",
98
+ reason: `Cannot stat entry: may not exist or be inaccessible.`,
99
+ });
100
+ continue;
101
+ }
102
+ if (!stat.isFile()) {
103
+ migrationEntries.push({
104
+ timestamp,
105
+ oldPath: oldRel,
106
+ newPath: "",
107
+ defectId,
108
+ status: "skipped",
109
+ reason: `Entry "${entry}" matched defect pattern but is not a regular file (type: ${stat.isDirectory() ? 'directory' : 'other'}).`,
110
+ });
111
+ continue;
112
+ }
113
+ try {
114
+ await fs.rename(oldAbs, newAbs);
115
+ migrationEntries.push({
116
+ timestamp,
117
+ oldPath: oldRel,
118
+ newPath: newRel,
119
+ defectId,
120
+ status: "migrated",
121
+ reason: "Successfully moved from legacy defects/ to .xcoder/defects/.",
122
+ });
123
+ migrated.push({
124
+ id: defectId,
125
+ path: newRel,
126
+ status: "open",
127
+ discoveredAt: timestamp,
128
+ lastUpdated: timestamp,
129
+ severity: "medium",
130
+ fixAttempts: [],
131
+ });
132
+ }
133
+ catch (e) {
134
+ migrationEntries.push({
135
+ timestamp,
136
+ oldPath: oldRel,
137
+ newPath: newRel,
138
+ defectId,
139
+ status: "failed",
140
+ reason: `Rename failed: ${e.message}`,
141
+ });
142
+ }
143
+ }
144
+ // Write migration log.
145
+ if (migrationEntries.length > 0) {
146
+ await logMigration(workspaceRoot, migrationEntries);
147
+ }
148
+ // Write _defects.json with migrated records merged into existing index.
149
+ const index = await loadDefectsIndex(workspaceRoot);
150
+ for (const record of migrated) {
151
+ // Only add if not already present (shouldn't happen, but defensive).
152
+ if (!(record.id in index)) {
153
+ index[record.id] = record;
154
+ }
155
+ }
156
+ await saveDefectsIndex(workspaceRoot, index);
157
+ // Touch sentinel.
158
+ await touchSentinel(workspaceRoot);
159
+ // Cleanup: remove the legacy defects/ directory if it's now empty.
160
+ try {
161
+ const remaining = await fs.readdir(legacyDefectsDir(workspaceRoot));
162
+ if (remaining.length === 0) {
163
+ await fs.rmdir(legacyDefectsDir(workspaceRoot));
164
+ }
165
+ }
166
+ catch {
167
+ // Directory already gone or unreadable — nothing to clean up.
168
+ }
169
+ return migrated;
170
+ }
171
+ async function touchSentinel(workspaceRoot) {
172
+ await fs.mkdir(path.dirname(sentinelPath(workspaceRoot)), { recursive: true });
173
+ await fs.writeFile(sentinelPath(workspaceRoot), `${new Date().toISOString()}\n`, "utf-8");
174
+ }
@@ -0,0 +1,48 @@
1
+ export type DefectStatus = "open" | "in_progress" | "resolved" | "closed";
2
+ export interface FixAttempt {
3
+ attemptNumber: number;
4
+ fixNodeId: string;
5
+ startedAt: string;
6
+ completedAt?: string;
7
+ passed: boolean;
8
+ notes?: string;
9
+ }
10
+ export interface DefectRecord {
11
+ id: string;
12
+ path: string;
13
+ status: DefectStatus;
14
+ discoveredAt: string;
15
+ lastUpdated: string;
16
+ severity: "low" | "medium" | "high" | "critical";
17
+ fixAttempts: FixAttempt[];
18
+ resolvedAt?: string;
19
+ resolvedBy?: string;
20
+ }
21
+ /** Flat map keyed by defect id (e.g., "DEFECT-0001"). */
22
+ export type DefectsIndex = Record<string, DefectRecord>;
23
+ /**
24
+ * Reads and parses `_defects.json` from the Xcoder SDLC data directory.
25
+ * Returns an empty object if the file doesn't exist or is malformed.
26
+ */
27
+ export declare function loadDefectsIndex(workspaceRoot: string): Promise<DefectsIndex>;
28
+ /**
29
+ * Writes the full index atomically (temp file + rename) to
30
+ * `.xcoder/_defects.json`. Matches the same pattern from `task-store.ts`.
31
+ */
32
+ export declare function saveDefectsIndex(workspaceRoot: string, index: DefectsIndex): Promise<void>;
33
+ /**
34
+ * Loads the index, upserts the record by defect id, saves. Returns the
35
+ * fresh index. Used after discovery, status changes, and resolution.
36
+ */
37
+ export declare function upsertDefect(workspaceRoot: string, record: DefectRecord): Promise<DefectsIndex>;
38
+ /**
39
+ * Loads the index, returns only entries whose status is "open". Used by
40
+ * the orchestrator to answer "what open defects exist?" without a
41
+ * file-system scan.
42
+ */
43
+ export declare function getOpenDefects(workspaceRoot: string): Promise<DefectRecord[]>;
44
+ /**
45
+ * Quick check whether a defect id is in the index (any status) — replaces
46
+ * the old fs.access() check for resolution logic.
47
+ */
48
+ export declare function defectExists(workspaceRoot: string, defectId: string): Promise<boolean>;
@@ -0,0 +1,76 @@
1
+ // xcoder:version 3 | xcoder:task task-12fb57 | xcoder:updated 2026-08-04T14:29:08.438Z | xcoder:subtask test-st-0a9eed
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ import { createXcoderPaths } from "../util/xcoder-paths.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Path resolution
7
+ // ---------------------------------------------------------------------------
8
+ function indexFilePath(workspaceRoot) {
9
+ return path.join(createXcoderPaths(workspaceRoot).root, "_defects.json");
10
+ }
11
+ // ---------------------------------------------------------------------------
12
+ // Public API
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Reads and parses `_defects.json` from the Xcoder SDLC data directory.
16
+ * Returns an empty object if the file doesn't exist or is malformed.
17
+ */
18
+ export async function loadDefectsIndex(workspaceRoot) {
19
+ try {
20
+ const raw = await fs.readFile(indexFilePath(workspaceRoot), "utf-8");
21
+ const parsed = JSON.parse(raw);
22
+ // Basic structural validation: must be an object.
23
+ if (typeof parsed !== "object" || Array.isArray(parsed) || parsed === null) {
24
+ return {};
25
+ }
26
+ // Filter out any non-object entries (shouldn't happen, but defensive).
27
+ const index = {};
28
+ for (const [id, record] of Object.entries(parsed)) {
29
+ if (record && typeof record === "object" && !Array.isArray(record)) {
30
+ index[id] = record;
31
+ }
32
+ }
33
+ return index;
34
+ }
35
+ catch {
36
+ return {};
37
+ }
38
+ }
39
+ /**
40
+ * Writes the full index atomically (temp file + rename) to
41
+ * `.xcoder/_defects.json`. Matches the same pattern from `task-store.ts`.
42
+ */
43
+ export async function saveDefectsIndex(workspaceRoot, index) {
44
+ const file = indexFilePath(workspaceRoot);
45
+ await fs.mkdir(path.dirname(file), { recursive: true });
46
+ const tmp = `${file}.tmp`;
47
+ await fs.writeFile(tmp, JSON.stringify(index, null, 2), "utf8");
48
+ await fs.rename(tmp, file);
49
+ }
50
+ /**
51
+ * Loads the index, upserts the record by defect id, saves. Returns the
52
+ * fresh index. Used after discovery, status changes, and resolution.
53
+ */
54
+ export async function upsertDefect(workspaceRoot, record) {
55
+ const index = await loadDefectsIndex(workspaceRoot);
56
+ index[record.id] = record;
57
+ await saveDefectsIndex(workspaceRoot, index);
58
+ return index;
59
+ }
60
+ /**
61
+ * Loads the index, returns only entries whose status is "open". Used by
62
+ * the orchestrator to answer "what open defects exist?" without a
63
+ * file-system scan.
64
+ */
65
+ export async function getOpenDefects(workspaceRoot) {
66
+ const index = await loadDefectsIndex(workspaceRoot);
67
+ return Object.values(index).filter((r) => r.status === "open");
68
+ }
69
+ /**
70
+ * Quick check whether a defect id is in the index (any status) — replaces
71
+ * the old fs.access() check for resolution logic.
72
+ */
73
+ export async function defectExists(workspaceRoot, defectId) {
74
+ const index = await loadDefectsIndex(workspaceRoot);
75
+ return defectId in index;
76
+ }
@@ -0,0 +1,14 @@
1
+ import type { SubtaskNode } from "../types.js";
2
+ /**
3
+ * The healing loop from the original brief had no attempt cap — "self
4
+ * healing kicks in and corrects the situation" with no bound is exactly
5
+ * the runaway-retry risk called out in review. This is the fix: every
6
+ * subtask carries `healing.maxAttempts` (from `TaskSpec.constraints`,
7
+ * default 2), and once exhausted the subtask is escalated, never retried
8
+ * again silently.
9
+ */
10
+ export interface HealingDecision {
11
+ action: "retry" | "escalate";
12
+ hint?: string;
13
+ }
14
+ export declare function decideHealing(node: SubtaskNode, failureReport: string): HealingDecision;
@@ -0,0 +1,11 @@
1
+ export function decideHealing(node, failureReport) {
2
+ node.healing.log.push(failureReport);
3
+ if (node.healing.attempts >= node.healing.maxAttempts) {
4
+ return { action: "escalate" };
5
+ }
6
+ node.healing.attempts += 1;
7
+ return {
8
+ action: "retry",
9
+ hint: `Attempt ${node.healing.attempts}/${node.healing.maxAttempts}. Previous failure: ${failureReport}`,
10
+ };
11
+ }
@@ -0,0 +1,64 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { SubtaskNode } from "../types.js";
3
+ /** A single interactive steering event — serialisable so it can be persisted in a TaskRun. */
4
+ export interface SteeringInjection {
5
+ /** Raw text the user typed. */
6
+ userInput: string;
7
+ /** ISO-8601 timestamp captured at injection time. */
8
+ capturedAt: string;
9
+ /** Node ids that were still pending/ready/in_progress (or healing/validating/blocked) when the pause was triggered — i.e. all nodes NOT already done, failed, or escalated. */
10
+ affectedNodeIds: string[];
11
+ }
12
+ /**
13
+ * InteractiveSteeringManager encapsulates the pause/resolve lifecycle for
14
+ * user steering injection into the DAG. It owns NO I/O (stdin, readline,
15
+ * keypress) — it is a pure logical controller driven by the orchestrator
16
+ * loop and the CLI keypress handler.
17
+ *
18
+ * Pattern: identical to genesis-agent's `GenesisReActOrchestrator`
19
+ * pause/inject lifecycle (triggerInterrupt → handleInterruptPause →
20
+ * injectUserInput), but extracted into a composable manager so the
21
+ * SdlcOrchestrator can own one without mixing TTY concerns into its
22
+ * module.
23
+ */
24
+ export declare class InteractiveSteeringManager extends EventEmitter {
25
+ private _isPauseRequested;
26
+ private _resolveWait;
27
+ private _lastInjection;
28
+ /** True after requestPause() is called and before injectAndResume() resolves the pause. */
29
+ get isPauseRequested(): boolean;
30
+ /** The most recent injection, or null if none has happened yet. */
31
+ get lastInjection(): SteeringInjection | null;
32
+ /**
33
+ * Call from the keypress handler (or any external trigger). Sets the
34
+ * pause flag; the executeLoop checks this at the next round boundary.
35
+ *
36
+ * Idempotent — subsequent calls while already paused are no-ops,
37
+ * handling debounce/re-entrancy (AC3).
38
+ */
39
+ requestPause(): void;
40
+ /**
41
+ * Called by executeLoop at the round boundary when isPauseRequested is
42
+ * true. Returns a Promise that resolves only after `injectAndResume()`
43
+ * is called (from the CLI layer, after the user has typed their input).
44
+ *
45
+ * Emits the "paused" event so external listeners (CLI, UI) can prompt
46
+ * the user.
47
+ */
48
+ waitForInjection(): Promise<SteeringInjection>;
49
+ /**
50
+ * Call from the CLI layer after the user has entered their steering
51
+ * text. Mutates the DAG in place (see Tradeoff 1 in the design doc) and
52
+ * resolves the promise returned by waitForInjection().
53
+ *
54
+ * For every node in `dag` whose status is NOT `done`, `failed`, or
55
+ * `escalated`:
56
+ * 1. Appends `[USER STEERING — injected at <ISO>]: <text>` to `goal`.
57
+ * 2. Sets/updates `upstreamContext.user_steering` with the structured record.
58
+ *
59
+ * @param userInput The raw text the user typed (may be empty).
60
+ * @param dag The live DAG array — mutated in place.
61
+ * @returns The SteeringInjection record (also pushed to run.steeringLog by the caller).
62
+ */
63
+ injectAndResume(userInput: string, dag: SubtaskNode[]): SteeringInjection;
64
+ }
@@ -0,0 +1,107 @@
1
+ import { EventEmitter } from "node:events";
2
+ /**
3
+ * InteractiveSteeringManager encapsulates the pause/resolve lifecycle for
4
+ * user steering injection into the DAG. It owns NO I/O (stdin, readline,
5
+ * keypress) — it is a pure logical controller driven by the orchestrator
6
+ * loop and the CLI keypress handler.
7
+ *
8
+ * Pattern: identical to genesis-agent's `GenesisReActOrchestrator`
9
+ * pause/inject lifecycle (triggerInterrupt → handleInterruptPause →
10
+ * injectUserInput), but extracted into a composable manager so the
11
+ * SdlcOrchestrator can own one without mixing TTY concerns into its
12
+ * module.
13
+ */
14
+ export class InteractiveSteeringManager extends EventEmitter {
15
+ _isPauseRequested = false;
16
+ _resolveWait = null;
17
+ _lastInjection = null;
18
+ // ── Read-only flags ──
19
+ /** True after requestPause() is called and before injectAndResume() resolves the pause. */
20
+ get isPauseRequested() {
21
+ return this._isPauseRequested;
22
+ }
23
+ /** The most recent injection, or null if none has happened yet. */
24
+ get lastInjection() {
25
+ return this._lastInjection;
26
+ }
27
+ // ── Pause lifecycle ──
28
+ /**
29
+ * Call from the keypress handler (or any external trigger). Sets the
30
+ * pause flag; the executeLoop checks this at the next round boundary.
31
+ *
32
+ * Idempotent — subsequent calls while already paused are no-ops,
33
+ * handling debounce/re-entrancy (AC3).
34
+ */
35
+ requestPause() {
36
+ if (this._isPauseRequested)
37
+ return; // already paused — debounce
38
+ this._isPauseRequested = true;
39
+ }
40
+ /**
41
+ * Called by executeLoop at the round boundary when isPauseRequested is
42
+ * true. Returns a Promise that resolves only after `injectAndResume()`
43
+ * is called (from the CLI layer, after the user has typed their input).
44
+ *
45
+ * Emits the "paused" event so external listeners (CLI, UI) can prompt
46
+ * the user.
47
+ */
48
+ waitForInjection() {
49
+ this.emit("paused");
50
+ return new Promise((resolve) => {
51
+ this._resolveWait = resolve;
52
+ });
53
+ }
54
+ // ── Injection & resume ──
55
+ /**
56
+ * Call from the CLI layer after the user has entered their steering
57
+ * text. Mutates the DAG in place (see Tradeoff 1 in the design doc) and
58
+ * resolves the promise returned by waitForInjection().
59
+ *
60
+ * For every node in `dag` whose status is NOT `done`, `failed`, or
61
+ * `escalated`:
62
+ * 1. Appends `[USER STEERING — injected at <ISO>]: <text>` to `goal`.
63
+ * 2. Sets/updates `upstreamContext.user_steering` with the structured record.
64
+ *
65
+ * @param userInput The raw text the user typed (may be empty).
66
+ * @param dag The live DAG array — mutated in place.
67
+ * @returns The SteeringInjection record (also pushed to run.steeringLog by the caller).
68
+ */
69
+ injectAndResume(userInput, dag) {
70
+ const capturedAt = new Date().toISOString();
71
+ const affectedNodeIds = [];
72
+ const STEERING_PREFIX = `\n\n[USER STEERING — injected at ${capturedAt}]: ${userInput}`;
73
+ for (const node of dag) {
74
+ // Skip nodes that are already finished or permanently failed.
75
+ if (node.status === "done" || node.status === "failed" || node.status === "escalated") {
76
+ continue;
77
+ }
78
+ affectedNodeIds.push(node.id);
79
+ // 1. Goal append (see Tradeoff 2).
80
+ node.goal += STEERING_PREFIX;
81
+ // 2. Structured upstreamContext entry.
82
+ const existing = node.upstreamContext["user_steering"];
83
+ if (Array.isArray(existing)) {
84
+ existing.push({ userInput, capturedAt, affectedNodeIds });
85
+ }
86
+ else if (existing) {
87
+ node.upstreamContext["user_steering"] = [
88
+ existing,
89
+ { userInput, capturedAt, affectedNodeIds },
90
+ ];
91
+ }
92
+ else {
93
+ node.upstreamContext["user_steering"] = { userInput, capturedAt, affectedNodeIds };
94
+ }
95
+ }
96
+ const injection = { userInput, capturedAt, affectedNodeIds };
97
+ this._lastInjection = injection;
98
+ // Resolve the wait promise.
99
+ if (this._resolveWait) {
100
+ this._resolveWait(injection);
101
+ this._resolveWait = null;
102
+ }
103
+ // Clear the pause flag — execution can continue.
104
+ this._isPauseRequested = false;
105
+ return injection;
106
+ }
107
+ }
@@ -0,0 +1,30 @@
1
+ import type { SubtaskNode } from "../types.js";
2
+ export interface InterruptContext {
3
+ taskId: string;
4
+ dag: SubtaskNode[];
5
+ totalSubtasks: number;
6
+ doneCount: number;
7
+ workspaceRoot: string;
8
+ signal: "SIGINT" | "INTERACTIVE";
9
+ isDoubleInterrupt: boolean;
10
+ }
11
+ export interface InterruptAction {
12
+ kind: "halt" | "force_exit" | "interactive_pause";
13
+ rolledBackNodeIds: string[];
14
+ updatedDag: SubtaskNode[];
15
+ summary: {
16
+ taskId: string;
17
+ doneCount: number;
18
+ totalCount: number;
19
+ resumeCommand: string;
20
+ taskFilePath: string;
21
+ };
22
+ exitCode: 0 | 1;
23
+ stderrWarning?: string;
24
+ }
25
+ /**
26
+ * Pure function that computes the state transition for an interrupt.
27
+ * Callers pass the live state; it returns what to do. The orchestrator
28
+ * is responsible for persisting (saveTaskRun) and printing (terminal).
29
+ */
30
+ export declare function computeInterruptAction(ctx: InterruptContext): InterruptAction;
@@ -0,0 +1,70 @@
1
+ /** Statuses that should be rolled back to "ready" on interrupt. */
2
+ const ROLLBACK_STATUSES = new Set([
3
+ "in_progress",
4
+ "healing",
5
+ "validating",
6
+ ]);
7
+ /**
8
+ * Pure function that computes the state transition for an interrupt.
9
+ * Callers pass the live state; it returns what to do. The orchestrator
10
+ * is responsible for persisting (saveTaskRun) and printing (terminal).
11
+ */
12
+ export function computeInterruptAction(ctx) {
13
+ // Double-interrupt: force exit, no graceful save.
14
+ if (ctx.isDoubleInterrupt) {
15
+ return {
16
+ kind: "force_exit",
17
+ rolledBackNodeIds: [],
18
+ updatedDag: ctx.dag,
19
+ summary: {
20
+ taskId: ctx.taskId,
21
+ doneCount: ctx.doneCount,
22
+ totalCount: ctx.totalSubtasks,
23
+ resumeCommand: `xcoder resume ${ctx.taskId}`,
24
+ taskFilePath: `.xcoder/tasks/${ctx.taskId}.json`,
25
+ },
26
+ exitCode: 1,
27
+ stderrWarning: `Force exit after second interrupt — in-flight work may not be fully saved. ` +
28
+ `Use "xcoder resume ${ctx.taskId}" to recover.`,
29
+ };
30
+ }
31
+ // Interactive pause: no rollback — in-flight nodes stay as they are.
32
+ if (ctx.signal === "INTERACTIVE") {
33
+ return {
34
+ kind: "interactive_pause",
35
+ rolledBackNodeIds: [],
36
+ updatedDag: ctx.dag,
37
+ summary: {
38
+ taskId: ctx.taskId,
39
+ doneCount: ctx.doneCount,
40
+ totalCount: ctx.totalSubtasks,
41
+ resumeCommand: `xcoder resume ${ctx.taskId}`,
42
+ taskFilePath: `.xcoder/tasks/${ctx.taskId}.json`,
43
+ },
44
+ exitCode: 0,
45
+ };
46
+ }
47
+ // Normal interrupt: roll back in_progress / healing / validating → ready.
48
+ const rolledBackNodeIds = [];
49
+ const updatedDag = ctx.dag.map((node) => {
50
+ if (ROLLBACK_STATUSES.has(node.status)) {
51
+ rolledBackNodeIds.push(node.id);
52
+ return { ...node, status: "ready" };
53
+ }
54
+ return node;
55
+ });
56
+ const actualDoneCount = updatedDag.filter((n) => n.status === "done").length;
57
+ return {
58
+ kind: "halt",
59
+ rolledBackNodeIds,
60
+ updatedDag,
61
+ summary: {
62
+ taskId: ctx.taskId,
63
+ doneCount: actualDoneCount,
64
+ totalCount: ctx.totalSubtasks,
65
+ resumeCommand: `xcoder resume ${ctx.taskId}`,
66
+ taskFilePath: `.xcoder/tasks/${ctx.taskId}.json`,
67
+ },
68
+ exitCode: 0,
69
+ };
70
+ }
@@ -0,0 +1,25 @@
1
+ import type { LessonEntry } from "../types.js";
2
+ /**
3
+ * Resolve whether lesson-learned is enabled from CLI option + env var.
4
+ * CLI flag "--lesson-learned" → true; "--no-lesson-learned" → false.
5
+ * If neither is passed, check XCODER_LESSON_LEARNED ("true" → true).
6
+ * Default: false.
7
+ */
8
+ export declare function resolveLessonFlag(cliFlag: boolean | undefined, env: typeof process.env): boolean;
9
+ /**
10
+ * Read the full contents of .xcoder/lesson.md.
11
+ * Returns the raw Markdown string (empty string if the file doesn't exist).
12
+ */
13
+ export declare function loadLessons(workspaceRoot: string): Promise<string>;
14
+ /**
15
+ * Check if the lessons file exceeds 64 KB.
16
+ * Returns a warning string if it does, or null if it's within bounds.
17
+ */
18
+ export declare function checkLessonFileSize(workspaceRoot: string): Promise<string | null>;
19
+ /**
20
+ * Record a lesson into .xcoder/lesson.md with an atomic write.
21
+ * Uses temp-file + rename for concurrency safety.
22
+ * Creates .xcoder/ dir and lesson.md on first write.
23
+ * Non-fatal: if the write fails, the caller logs a warning and continues.
24
+ */
25
+ export declare function recordLesson(workspaceRoot: string, entry: LessonEntry): Promise<void>;