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,223 @@
1
+ // xcoder:version 8 | xcoder:task task-689517 | xcoder:updated 2026-11-01T08:21:37.747Z | xcoder:subtask code-st-828150
2
+ // Atomic per-user license state persistence.
3
+ //
4
+ // Canonical location: <homedir>/.xcoder/license/activation.json — per-user,
5
+ // next to config.json, NOT inside the workspace. A license belongs to the
6
+ // person/machine, so a fresh `git clone` must not silently consume another
7
+ // seat.
8
+ //
9
+ // SHARED STATE: the canonical file is the SAME file v3 and ronin read and
10
+ // write. One activation therefore covers every xcoder binary on the machine —
11
+ // the bug was never config.json (already shared) but the receipt living at
12
+ // different paths in different schemas. Reads walk the discovery list, writes
13
+ // land on the primary path in the superset shape all readers accept.
14
+ //
15
+ // Contains no secrets by construction: the serial key is never written to
16
+ // disk. `receipt` is a public, signed artifact whose only use is offline
17
+ // verification against the build-pinned key.
18
+ import fs from "node:fs";
19
+ import os from "node:os";
20
+ import path from "node:path";
21
+ import { randomUUID } from "node:crypto";
22
+ import { resolveStateCandidates } from "./state-paths.js";
23
+ import { decodeStateFile, recordFromClaims, writeStateFile, } from "./state-codec.js";
24
+ const DIR_MODE = 0o700;
25
+ const FILE_MODE = 0o600;
26
+ export function defaultLicenseDir() {
27
+ return path.join(os.homedir(), ".xcoder", "license");
28
+ }
29
+ function isObject(value) {
30
+ return typeof value === "object" && value !== null && !Array.isArray(value);
31
+ }
32
+ function asString(value) {
33
+ return typeof value === "string" && value.length > 0 ? value : null;
34
+ }
35
+ /**
36
+ * Every FILE an activation may be stored in, highest priority first.
37
+ *
38
+ * Candidates are files, not directories: $XCODER_LICENSE_FILE names an
39
+ * arbitrary file and the legacy host store is license.json. Collapsing them to
40
+ * their parent directory and re-appending a hard-coded activation.json silently
41
+ * ignored both, which is exactly the v1-asks-for-a-key bug that this sharing
42
+ * work exists to fix. Reads, writes and clears all use this one list.
43
+ */
44
+ export function resolveCandidateFiles(env = process.env) {
45
+ const seen = new Set();
46
+ const files = [];
47
+ for (const candidate of resolveStateCandidates(env)) {
48
+ const key = path.resolve(candidate.path).toLowerCase();
49
+ if (seen.has(key))
50
+ continue;
51
+ seen.add(key);
52
+ files.push(candidate.path);
53
+ }
54
+ return files;
55
+ }
56
+ /**
57
+ * Directories of the candidate files, highest priority first.
58
+ *
59
+ * Kept for callers that reason about the installation sidecar next to the
60
+ * activation; activation I/O must use resolveCandidateFiles().
61
+ */
62
+ export function resolveCandidateDirs(env = process.env) {
63
+ const seen = new Set();
64
+ const dirs = [];
65
+ for (const file of resolveCandidateFiles(env)) {
66
+ const dir = path.dirname(file);
67
+ const key = path.resolve(dir).toLowerCase();
68
+ if (seen.has(key))
69
+ continue;
70
+ seen.add(key);
71
+ dirs.push(dir);
72
+ }
73
+ return dirs;
74
+ }
75
+ export function createLicenseStore(opts) {
76
+ const dir = opts?.dir ?? defaultLicenseDir();
77
+ // An explicitly injected dir is a fixture: stay inside it, so a test never
78
+ // reads (or is shadowed by) the developer's real activation on this machine.
79
+ const candidateFiles = opts?.dir ? [path.join(dir, "activation.json")] : resolveCandidateFiles();
80
+ // Writes follow the SAME priority list as reads (including the documented
81
+ // XCODER_LICENSE_FILE override). Writing to defaultLicenseDir() while reading
82
+ // from an override would store the activation where no subsequent read looks.
83
+ const activationFile = candidateFiles[0] ?? path.join(dir, "activation.json");
84
+ const writeDir = path.dirname(activationFile);
85
+ const installationFile = path.join(writeDir, "installation.json");
86
+ function ensureDir() {
87
+ fs.mkdirSync(writeDir, { recursive: true, mode: DIR_MODE });
88
+ }
89
+ /** The decoded shared record from the first candidate that has one. */
90
+ function readShared() {
91
+ for (const candidateFile of candidateFiles) {
92
+ const decoded = decodeStateFile(candidateFile);
93
+ if (decoded.ok)
94
+ return decoded.record;
95
+ }
96
+ return null;
97
+ }
98
+ /** Read raw JSON from one file. Symlinks are never followed. */
99
+ function readJson(file) {
100
+ let raw;
101
+ try {
102
+ const stat = fs.lstatSync(file);
103
+ if (stat.isSymbolicLink() || !stat.isFile())
104
+ return null;
105
+ raw = fs.readFileSync(file, "utf8");
106
+ }
107
+ catch {
108
+ return null; // missing / unreadable → caller sees "nothing stored"
109
+ }
110
+ try {
111
+ const parsed = JSON.parse(raw);
112
+ return isObject(parsed) ? parsed : null;
113
+ }
114
+ catch {
115
+ // Deliberately do NOT delete the file: the gate maps this to
116
+ // `corrupt-store` and fails closed, and a human can still inspect it.
117
+ return null;
118
+ }
119
+ }
120
+ function readInstallation() {
121
+ const raw = readJson(installationFile);
122
+ if (raw) {
123
+ const installationId = asString(raw.installationId);
124
+ const createdAt = asString(raw.createdAt);
125
+ if (installationId)
126
+ return { installationId, createdAt: createdAt ?? new Date(0).toISOString() };
127
+ }
128
+ // A machine activated by another binary never wrote installation.json; the
129
+ // id lives in the shared activation instead. Without this fallback
130
+ // refresh() would refuse with "no installation id" on a machine that is
131
+ // plainly activated.
132
+ const shared = readShared();
133
+ if (!shared)
134
+ return null;
135
+ return { installationId: shared.installationId, createdAt: shared.savedAt };
136
+ }
137
+ function ensureInstallation() {
138
+ const existing = readInstallation();
139
+ if (existing) {
140
+ // Adopt-on-read: materialise the id in this dir so older builds keep
141
+ // working, but never replace an existing file.
142
+ if (!fs.existsSync(installationFile)) {
143
+ try {
144
+ ensureDir();
145
+ fs.writeFileSync(installationFile, `${JSON.stringify({ installationId: existing.installationId, createdAt: existing.createdAt }, null, 2)}\n`, { encoding: "utf8", mode: FILE_MODE, flag: "wx" });
146
+ }
147
+ catch {
148
+ /* a concurrent writer won the race; its id is equivalent */
149
+ }
150
+ }
151
+ return existing;
152
+ }
153
+ const record = {
154
+ installationId: randomUUID(),
155
+ createdAt: new Date().toISOString(),
156
+ };
157
+ ensureDir();
158
+ try {
159
+ // `wx` fails if the file appeared between our read and this write, so a
160
+ // concurrent process can never clobber another installation's id.
161
+ fs.writeFileSync(installationFile, `${JSON.stringify(record, null, 2)}\n`, {
162
+ encoding: "utf8",
163
+ mode: FILE_MODE,
164
+ flag: "wx",
165
+ });
166
+ return record;
167
+ }
168
+ catch (err) {
169
+ const code = err.code;
170
+ if (code === "EEXIST") {
171
+ const winner = readInstallation();
172
+ if (winner)
173
+ return winner;
174
+ }
175
+ throw err;
176
+ }
177
+ }
178
+ function readActivation() {
179
+ // First candidate wins; the file is the superset every binary shares, but
180
+ // this module keeps speaking the 7-field shape to its callers.
181
+ for (const candidateFile of candidateFiles) {
182
+ const decoded = decodeStateFile(candidateFile);
183
+ if (!decoded.ok)
184
+ continue;
185
+ const record = decoded.record;
186
+ return {
187
+ activationId: record.activationId,
188
+ licenseId: record.licenseId,
189
+ plan: record.plan,
190
+ receipt: record.receipt,
191
+ expiresAt: record.expiresAt,
192
+ refreshBy: record.refreshBy,
193
+ savedAt: record.savedAt,
194
+ };
195
+ }
196
+ return null;
197
+ }
198
+ function writeActivation(rec) {
199
+ // Replace, never append: exactly one activation per installation (AC3).
200
+ // Always the PRIMARY file, in the superset shape, so v3 and ronin read the
201
+ // very same activation without re-activating.
202
+ const installation = ensureInstallation();
203
+ const record = recordFromClaims(rec, {
204
+ installationId: installation.installationId,
205
+ receipt: rec.receipt,
206
+ savedAt: rec.savedAt,
207
+ });
208
+ writeStateFile(activationFile, record);
209
+ }
210
+ function clearActivation() {
211
+ // Clear every candidate so a released seat cannot be re-adopted from a
212
+ // lower-priority copy on the next read.
213
+ for (const candidateFile of candidateFiles) {
214
+ try {
215
+ fs.rmSync(candidateFile, { force: true });
216
+ }
217
+ catch {
218
+ /* already absent — clearing is idempotent */
219
+ }
220
+ }
221
+ }
222
+ return { dir, readInstallation, ensureInstallation, readActivation, writeActivation, clearActivation };
223
+ }
@@ -0,0 +1,24 @@
1
+ export interface TrustAnchor {
2
+ /** SPKI PEM, Ed25519. */
3
+ readonly publicKeyPem: string;
4
+ /** True only while the labelled development key is pinned. */
5
+ readonly isDevelopment: boolean;
6
+ /** Set by scripts/fetch-public-key.mjs during release prep. */
7
+ readonly source: "release" | "development";
8
+ }
9
+ /** The `iss` claim the service signs with. */
10
+ export declare const LICENSE_ISSUER = "https://license.coderph.dev";
11
+ /** The `aud` claim; also the product ID sent at activation. */
12
+ export declare const LICENSE_PRODUCT_ID: "xcoder-sdlc-cli";
13
+ /**
14
+ * Default activation API base: exactly `<LICENSE_ISSUER>/activation/v1`.
15
+ *
16
+ * Asserted at import time: a mismatch means the binary would activate against
17
+ * a surface the Key System does not serve, which fails for every user at
18
+ * runtime and is invisible in a unit test that injects its own base URL. A
19
+ * throw here turns that into an immediate, unmissable build/test failure.
20
+ */
21
+ export declare const LICENSE_API_BASE_URL: string;
22
+ /** The maximum offline window a receipt may claim: 7 days. */
23
+ export declare const RECEIPT_TTL_MS: number;
24
+ export declare const TRUST_ANCHOR: TrustAnchor;
@@ -0,0 +1,74 @@
1
+ // xcoder:version 2 | xcoder:task task-689517 | xcoder:updated 2026-11-01T08:22:00.385Z | xcoder:subtask code-st-828150
2
+ // The pinned license trust anchor — a build artifact, NOT runtime configuration.
3
+ //
4
+ // Invariants (each enforced by src/license/trust-anchor.test.ts):
5
+ // 1. This module contains no `process.env` reference, so neither the
6
+ // environment nor ~/.xcoder/config.json can replace the pinned key.
7
+ // 2. publicKeyPem parses via crypto.createPublicKey() as Ed25519 SPKI.
8
+ // 3. A release build (XCODER_RELEASE_BUILD=1) carrying the DEV-ONLY key
9
+ // fails the test suite — release prep must run scripts/fetch-public-key.mjs.
10
+ // 4. The dev key is labelled DEV-ONLY in its comment with source "development".
11
+ // 5. LICENSE_API_BASE_URL is exactly `<LICENSE_ISSUER>/activation/v1` — the
12
+ // serial-key gateway route the Key System is published behind. A mismatch
13
+ // throws at import time rather than silently activating against the wrong
14
+ // surface (v1 shipped `/api/v1`, so every valid key 404'd as bad-response).
15
+ //
16
+ // scripts/fetch-public-key.mjs rewrites everything between the BEGIN/END
17
+ // markers below. Never hand-edit the PEM inside those markers.
18
+ /** The `iss` claim the service signs with. */
19
+ export const LICENSE_ISSUER = "https://license.coderph.dev";
20
+ /** The `aud` claim; also the product ID sent at activation. */
21
+ export const LICENSE_PRODUCT_ID = "xcoder-sdlc-cli";
22
+ /**
23
+ * The path the serial-key gateway mounts the Key System's `/v1/` API under.
24
+ * Kept as a literal (not derived from the client) so the client module stays
25
+ * unchanged and the route is pinned in one auditable place.
26
+ */
27
+ const GATEWAY_BASE_PATH = "/activation/v1";
28
+ /**
29
+ * The pinned activation API base — rewritten by hand, never at runtime.
30
+ *
31
+ * v1 shipped `<origin>/api/v1`, but the gateway publishes `POST
32
+ * <origin>/activation/v1/activations` (and /refresh, /release). Every valid
33
+ * serial key therefore hit a 404, surfaced to the user as `bad-response`: this
34
+ * is the reason v1 rejected a key v3 accepted. The value lives OUTSIDE the
35
+ * BEGIN/END marker block because scripts/fetch-public-key.mjs rewrites only
36
+ * the PEM and the key source, and a release build must not drop the route.
37
+ */
38
+ const PINNED_API_BASE_URL = "https://license.coderph.dev/activation/v1";
39
+ /** Strip trailing slashes so `<origin>/` and `<origin>` compare equal. */
40
+ function stripTrailingSlashes(value) {
41
+ return value.replace(/\/+$/, "");
42
+ }
43
+ /**
44
+ * Default activation API base: exactly `<LICENSE_ISSUER>/activation/v1`.
45
+ *
46
+ * Asserted at import time: a mismatch means the binary would activate against
47
+ * a surface the Key System does not serve, which fails for every user at
48
+ * runtime and is invisible in a unit test that injects its own base URL. A
49
+ * throw here turns that into an immediate, unmissable build/test failure.
50
+ */
51
+ export const LICENSE_API_BASE_URL = (() => {
52
+ const expected = `${LICENSE_ISSUER}${GATEWAY_BASE_PATH}`;
53
+ const pinned = stripTrailingSlashes(PINNED_API_BASE_URL);
54
+ if (pinned !== expected) {
55
+ throw new Error(`license trust anchor: PINNED_API_BASE_URL must be ${expected} (got ${pinned}) — re-pin it so it is the issuer origin plus ${GATEWAY_BASE_PATH}`);
56
+ }
57
+ return expected;
58
+ })();
59
+ /** The maximum offline window a receipt may claim: 7 days. */
60
+ export const RECEIPT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
61
+ // BEGIN XCODER LICENSE PUBLIC KEY (managed by scripts/fetch-public-key.mjs)
62
+ // DEV-ONLY — this Ed25519 key is published with the source tree and MUST NOT
63
+ // be trusted in a release. Release prep replaces it and flips `source`.
64
+ const PINNED_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
65
+ MCowBQYDK2VwAyEABJbTsj5H+GLJJEpA0X5m2+UofSkDAg/y7Z0ahE6c05Y=
66
+ -----END PUBLIC KEY-----
67
+ `;
68
+ const PINNED_KEY_SOURCE = "development";
69
+ // END XCODER LICENSE PUBLIC KEY
70
+ export const TRUST_ANCHOR = Object.freeze({
71
+ publicKeyPem: PINNED_PUBLIC_KEY_PEM,
72
+ isDevelopment: PINNED_KEY_SOURCE === "development",
73
+ source: PINNED_KEY_SOURCE,
74
+ });
@@ -0,0 +1,34 @@
1
+ /** The signed claim set embedded in a license receipt (segment 0). */
2
+ export interface LicenseClaims {
3
+ iss: string;
4
+ aud: string;
5
+ licenseId: string;
6
+ activationId: string;
7
+ plan: string;
8
+ /** ISO-8601, e.g. "2026-11-01T10:00:00.000Z" */
9
+ issuedAt: string;
10
+ /** Subscription expiry. */
11
+ expiresAt: string;
12
+ /** <= min(expiresAt, issuedAt + 7d) — the offline grace boundary. */
13
+ refreshBy: string;
14
+ }
15
+ /** Distinct, user-actionable denial codes. */
16
+ export type LicenseDenialReason = "no-activation" | "corrupt-store" | "malformed-receipt" | "bad-signature" | "untrusted-key" | "wrong-issuer" | "wrong-audience" | "expired" | "not-yet-valid" | "refresh-overdue";
17
+ export type VerifyResult = {
18
+ ok: true;
19
+ claims: LicenseClaims;
20
+ } | {
21
+ ok: false;
22
+ reason: LicenseDenialReason;
23
+ detail?: string;
24
+ };
25
+ export type LicenseGateResult = {
26
+ allowed: true;
27
+ claims: LicenseClaims;
28
+ } | {
29
+ allowed: false;
30
+ reason: LicenseDenialReason;
31
+ message: string;
32
+ };
33
+ /** Human-readable, non-leaking explanation for each denial code. */
34
+ export declare const DENIAL_DETAIL: Record<LicenseDenialReason, string>;
@@ -0,0 +1,19 @@
1
+ // xcoder:version 1 | xcoder:task task-1d9460 | xcoder:updated 2026-10-25T17:01:22.522Z | xcoder:subtask code-st-4b0403
2
+ // Client licensing — shared type layer.
3
+ //
4
+ // Type-only by design: no I/O, no `node:fs`, no `process`. Every other
5
+ // module in src/license/ imports its vocabulary from here so the denial
6
+ // codes and the gate result cannot drift apart.
7
+ /** Human-readable, non-leaking explanation for each denial code. */
8
+ export const DENIAL_DETAIL = {
9
+ "no-activation": "no activation found on this machine",
10
+ "corrupt-store": "stored license state is unreadable",
11
+ "malformed-receipt": "the stored receipt is malformed",
12
+ "bad-signature": "the receipt signature does not verify",
13
+ "untrusted-key": "the receipt was signed by a key that is not pinned",
14
+ "wrong-issuer": "the receipt was issued by an unexpected issuer",
15
+ "wrong-audience": "the receipt is not for this product",
16
+ expired: "the subscription has expired",
17
+ "not-yet-valid": "the receipt is not valid yet",
18
+ "refresh-overdue": "the offline window has elapsed — refresh required",
19
+ };
@@ -0,0 +1,23 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export declare const requestScope: AsyncLocalStorage<{
3
+ budget?: RequestBudget;
4
+ recordUsage?: (entry: Record<string, unknown>) => void;
5
+ /** In-memory mirror prevents a successful call from disappearing if ledger I/O fails. */
6
+ usageEvents?: Record<string, unknown>[];
7
+ }>;
8
+ /** Shared synchronous reservations prevent concurrent requests overspending a cap.
9
+ * Unknown/time-out usage retains its reservation until explicit reconciliation.
10
+ */
11
+ export declare class RequestBudget {
12
+ readonly capUsd: number;
13
+ readonly inputPerMillion: number;
14
+ readonly outputPerMillion: number;
15
+ private committed;
16
+ private reserved;
17
+ constructor(capUsd: number, inputPerMillion: number, outputPerMillion: number);
18
+ reserve(input: number, output: number): (usage?: {
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ }) => void;
22
+ restore(jsonl: string): void;
23
+ }
@@ -0,0 +1,58 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export const requestScope = new AsyncLocalStorage();
3
+ /** Shared synchronous reservations prevent concurrent requests overspending a cap.
4
+ * Unknown/time-out usage retains its reservation until explicit reconciliation.
5
+ */
6
+ export class RequestBudget {
7
+ capUsd;
8
+ inputPerMillion;
9
+ outputPerMillion;
10
+ committed = 0;
11
+ reserved = 0;
12
+ constructor(capUsd, inputPerMillion, outputPerMillion) {
13
+ this.capUsd = capUsd;
14
+ this.inputPerMillion = inputPerMillion;
15
+ this.outputPerMillion = outputPerMillion;
16
+ if (![capUsd, inputPerMillion, outputPerMillion].every(n => Number.isFinite(n) && n >= 0)) {
17
+ throw new Error("A dollar budget requires non-negative cap and explicit input/output prices");
18
+ }
19
+ }
20
+ reserve(input, output) {
21
+ if (![input, output].every(n => Number.isFinite(n) && n >= 0))
22
+ throw new Error("Invalid token reservation");
23
+ const amount = (input * this.inputPerMillion + output * this.outputPerMillion) / 1e6;
24
+ if (this.committed + this.reserved + amount > this.capUsd)
25
+ throw new Error("Request refused: task dollar budget exhausted");
26
+ this.reserved += amount;
27
+ let settled = false;
28
+ return usage => {
29
+ if (settled)
30
+ throw new Error("Budget reservation already settled");
31
+ settled = true;
32
+ if (!usage)
33
+ return; // Unknown charge stays reserved.
34
+ this.reserved -= amount;
35
+ this.committed += (usage.inputTokens * this.inputPerMillion + usage.outputTokens * this.outputPerMillion) / 1e6;
36
+ };
37
+ }
38
+ restore(jsonl) {
39
+ const requests = new Map();
40
+ for (const line of jsonl.split("\n").filter(line => line.trim())) {
41
+ const entry = JSON.parse(line);
42
+ if (typeof entry.requestId !== "string")
43
+ throw new Error("Invalid usage ledger");
44
+ requests.set(entry.requestId, { ...requests.get(entry.requestId), ...entry });
45
+ }
46
+ for (const entry of requests.values()) {
47
+ if (entry.inputPrice !== this.inputPerMillion || entry.outputPrice !== this.outputPerMillion) {
48
+ throw new Error("Budget pricing changed or is missing from the ledger; reconcile prior charges before resume");
49
+ }
50
+ if (entry.status === "completed" && entry.usageKnown === true && entry.usage) {
51
+ this.reserve(entry.usage.inputTokens, entry.usage.outputTokens)(entry.usage);
52
+ }
53
+ else {
54
+ this.reserve(entry.estimatedInputTokens ?? NaN, entry.maxOutputTokens ?? NaN)();
55
+ }
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,53 @@
1
+ export type LlmProvider = "deepseek" | "openai-compatible" | "anthropic";
2
+ export interface LlmMessage {
3
+ role: "user" | "assistant";
4
+ content: string;
5
+ }
6
+ export interface LlmClientOptions {
7
+ model?: string;
8
+ maxTokens?: number;
9
+ temperature?: number;
10
+ provider?: LlmProvider;
11
+ baseUrl?: string;
12
+ endpoint?: string;
13
+ apiKeyEnv?: string;
14
+ apiKey?: string;
15
+ }
16
+ export interface LlmCompletion {
17
+ text: string;
18
+ usage: {
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ };
22
+ /** The API's stop reason: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use' | 'length' | 'stop' | 'tool_calls' | null. */
23
+ stopReason: string | null;
24
+ /** The model name used for this completion. */
25
+ model: string;
26
+ }
27
+ /**
28
+ * One call per ReAct turn: system prompt + running transcript in, raw text
29
+ * + token usage out. Deliberately thin — the contract parsing lives in
30
+ * `protocol/react-contract.ts`, not here, so this file never needs to know
31
+ * what a valid response looks like. Callers are responsible for their own
32
+ * try/catch around `complete()` — a transient API error here must not be
33
+ * allowed to propagate all the way up and take the Master Orchestrator
34
+ * down with it (see `agents/sub-agent.ts`).
35
+ *
36
+ * Transport selection:
37
+ * - `"deepseek"` (default) — DeepSeek's Anthropic-compatible endpoint via
38
+ * `@anthropic-ai/sdk`; zero-config behavior is unchanged.
39
+ * - `"openai-compatible"` — any OpenAI `chat/completions` provider via the
40
+ * `openai` SDK (OpenAI, Groq, OpenRouter, Ollama, LM Studio, vLLM, ...).
41
+ * - `"anthropic"` — native Claude via `@anthropic-ai/sdk`.
42
+ */
43
+ export declare class LlmClient {
44
+ private anthropic;
45
+ private openai;
46
+ private provider;
47
+ private model;
48
+ private maxTokens;
49
+ private temperature;
50
+ private endpoint;
51
+ constructor(opts?: LlmClientOptions);
52
+ complete(systemPrompt: string, transcript: LlmMessage[]): Promise<LlmCompletion>;
53
+ }
@@ -0,0 +1,122 @@
1
+ // xcoder:version 1 | xcoder:task task-c49600 | xcoder:updated 2026-08-13T13:50:08.142Z | xcoder:subtask code-st-6d79ef
2
+ import Anthropic from "@anthropic-ai/sdk";
3
+ import OpenAI from "openai";
4
+ /**
5
+ * One call per ReAct turn: system prompt + running transcript in, raw text
6
+ * + token usage out. Deliberately thin — the contract parsing lives in
7
+ * `protocol/react-contract.ts`, not here, so this file never needs to know
8
+ * what a valid response looks like. Callers are responsible for their own
9
+ * try/catch around `complete()` — a transient API error here must not be
10
+ * allowed to propagate all the way up and take the Master Orchestrator
11
+ * down with it (see `agents/sub-agent.ts`).
12
+ *
13
+ * Transport selection:
14
+ * - `"deepseek"` (default) — DeepSeek's Anthropic-compatible endpoint via
15
+ * `@anthropic-ai/sdk`; zero-config behavior is unchanged.
16
+ * - `"openai-compatible"` — any OpenAI `chat/completions` provider via the
17
+ * `openai` SDK (OpenAI, Groq, OpenRouter, Ollama, LM Studio, vLLM, ...).
18
+ * - `"anthropic"` — native Claude via `@anthropic-ai/sdk`.
19
+ */
20
+ export class LlmClient {
21
+ anthropic = null;
22
+ openai = null;
23
+ provider;
24
+ model;
25
+ maxTokens;
26
+ temperature;
27
+ endpoint;
28
+ constructor(opts = {}) {
29
+ this.provider = opts.provider ?? "deepseek";
30
+ this.model = opts.model ?? process.env.XCODER_MODEL ?? "deepseek-chat";
31
+ this.maxTokens = opts.maxTokens ?? 16384;
32
+ this.temperature = opts.temperature;
33
+ if (this.provider === "openai-compatible") {
34
+ let apiKey = opts.apiKey;
35
+ if (!apiKey && opts.apiKeyEnv) {
36
+ apiKey = process.env[opts.apiKeyEnv];
37
+ }
38
+ // Keyless local providers (Ollama, LM Studio) accept any placeholder.
39
+ if (!apiKey)
40
+ apiKey = "ollama";
41
+ this.openai = new OpenAI({
42
+ apiKey,
43
+ baseURL: opts.baseUrl,
44
+ });
45
+ this.endpoint = opts.endpoint ?? "/chat/completions";
46
+ return;
47
+ }
48
+ // `deepseek` (the zero-config default) and native `anthropic` both speak
49
+ // the Anthropic Messages protocol.
50
+ let apiKey = opts.apiKey;
51
+ if (!apiKey && opts.apiKeyEnv) {
52
+ apiKey = process.env[opts.apiKeyEnv];
53
+ }
54
+ if (!apiKey) {
55
+ if (this.provider === "anthropic") {
56
+ apiKey = process.env.ANTHROPIC_API_KEY ?? process.env.DEEPSEEK_API_KEY;
57
+ if (!apiKey) {
58
+ throw new Error("ANTHROPIC_API_KEY (or DEEPSEEK_API_KEY) is not set. Export it before running xcoder, e.g.\n" +
59
+ ' export ANTHROPIC_API_KEY="sk-ant-..."');
60
+ }
61
+ }
62
+ else {
63
+ apiKey = process.env.DEEPSEEK_API_KEY;
64
+ if (!apiKey) {
65
+ throw new Error("DEEPSEEK_API_KEY is not set. Export it before running xcoder, e.g.\n" +
66
+ ' export DEEPSEEK_API_KEY="sk-..."');
67
+ }
68
+ }
69
+ }
70
+ const baseURL = opts.baseUrl ??
71
+ (this.provider === "anthropic"
72
+ ? "https://api.anthropic.com"
73
+ : "https://api.deepseek.com/anthropic");
74
+ this.anthropic = new Anthropic({ apiKey, baseURL });
75
+ }
76
+ async complete(systemPrompt, transcript) {
77
+ if (this.provider === "openai-compatible" && this.openai) {
78
+ const response = await this.openai.chat.completions.create({
79
+ model: this.model,
80
+ max_tokens: this.maxTokens,
81
+ ...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
82
+ messages: [
83
+ { role: "system", content: systemPrompt },
84
+ ...transcript.map((m) => ({ role: m.role, content: m.content })),
85
+ ],
86
+ });
87
+ const choice = response.choices?.[0];
88
+ return {
89
+ text: choice?.message?.content ?? "",
90
+ usage: {
91
+ inputTokens: response.usage?.prompt_tokens ?? 0,
92
+ outputTokens: response.usage?.completion_tokens ?? 0,
93
+ },
94
+ stopReason: choice?.finish_reason ?? null,
95
+ model: this.model,
96
+ };
97
+ }
98
+ if (!this.anthropic) {
99
+ throw new Error(`LLM transport not initialized for provider "${this.provider}"`);
100
+ }
101
+ const response = await this.anthropic.messages.create({
102
+ model: this.model,
103
+ max_tokens: this.maxTokens,
104
+ ...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
105
+ system: systemPrompt,
106
+ messages: transcript.map((m) => ({ role: m.role, content: m.content })),
107
+ });
108
+ const text = response.content
109
+ .map((block) => (block.type === "text" ? block.text : ""))
110
+ .join("\n")
111
+ .trim();
112
+ return {
113
+ text,
114
+ usage: {
115
+ inputTokens: response.usage?.input_tokens ?? 0,
116
+ outputTokens: response.usage?.output_tokens ?? 0,
117
+ },
118
+ stopReason: response.stop_reason ?? null,
119
+ model: this.model,
120
+ };
121
+ }
122
+ }
@@ -0,0 +1,14 @@
1
+ import { LlmClient } from "./client.js";
2
+ import { type AgentRole } from "../config/loadConfig.js";
3
+ /**
4
+ * Sole production constructor path for LLM clients. Resolves the effective
5
+ * per-role configuration from `.xcoder/config/llm.yaml` (or built-in
6
+ * DeepSeek defaults) and returns a transport ready for that role.
7
+ *
8
+ * Precedence in `resolveLlmConfig`: role block → `default` block → built-in
9
+ * DeepSeek; `XCODER_MODEL` applies to `model` only.
10
+ */
11
+ export declare function createLlmClient(role: AgentRole, overrides?: {
12
+ model?: string;
13
+ maxTokens?: number;
14
+ }): LlmClient;