xcoder-dna 0.0.0-stage → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/LICENSE +21 -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 +38 -3
@@ -0,0 +1,58 @@
1
+ import { type WorkspaceIndex } from "./workspace-index.js";
2
+ /** The stat-only subset of an index entry that staleness detection needs. */
3
+ export interface ManifestEntry {
4
+ relPath: string;
5
+ sizeBytes: number;
6
+ mtimeMs: number;
7
+ }
8
+ export interface WorkspaceManifest {
9
+ root: string;
10
+ scannedAt: string;
11
+ entries: ManifestEntry[];
12
+ }
13
+ /** Stat-only walk of the tree. Never throws; unreadable paths are skipped. */
14
+ export declare function scanManifest(root: string): Promise<WorkspaceManifest>;
15
+ export interface FreshnessCounts {
16
+ added: number;
17
+ removed: number;
18
+ changed: number;
19
+ }
20
+ export interface FreshnessVerdict {
21
+ fresh: boolean;
22
+ /** Machine-readable cause; `ok` when nothing differs. */
23
+ reason: "ok" | "added" | "removed" | "changed" | "empty-index";
24
+ added: string[];
25
+ removed: string[];
26
+ changed: string[];
27
+ /** Totals, regardless of how many paths the arrays carry. */
28
+ counts: FreshnessCounts;
29
+ }
30
+ /**
31
+ * Pure comparison of a stored index against a freshly scanned manifest.
32
+ *
33
+ * Free of I/O so the comparator is directly unit-testable and reusable
34
+ * without accidentally triggering a rebuild.
35
+ */
36
+ export declare function diffIndexAgainstManifest(index: WorkspaceIndex, manifest: WorkspaceManifest, maxReportedPaths?: number): FreshnessVerdict;
37
+ export type EnsureFreshAction = "reused" | "rebuilt" | "degraded";
38
+ export interface EnsureFreshResult {
39
+ /** Always usable — an empty-but-valid index if the tree could not be read. */
40
+ index: WorkspaceIndex;
41
+ action: EnsureFreshAction;
42
+ reason: string;
43
+ counts: FreshnessCounts;
44
+ durationMs: number;
45
+ }
46
+ export interface EnsureFreshOptions {
47
+ /** Rebuild regardless of the probe result — backs `--reindex`. */
48
+ force?: boolean;
49
+ /** Set false to skip the manifest scan and rebuild immediately. */
50
+ probe?: boolean;
51
+ /** How many differing paths to carry in the result. */
52
+ maxReportedPaths?: number;
53
+ }
54
+ /**
55
+ * Gate the index before a task runs: reuse it when it still describes the
56
+ * tree, otherwise rebuild exactly once. Never throws.
57
+ */
58
+ export declare function ensureFreshIndex(root: string, opts?: EnsureFreshOptions): Promise<EnsureFreshResult>;
@@ -0,0 +1,190 @@
1
+ // xcoder:version 1 | xcoder:task task-e16f85 | xcoder:updated 2026-10-30T18:14:02.928Z | xcoder:subtask code-st-791be4
2
+ // Freshness gate for the workspace index.
3
+ //
4
+ // The index is the source of truth for *which files exist*, so it must be
5
+ // trustworthy before a task starts. `getOrBuildIndex()` returns any index it
6
+ // can parse no matter how old, so a task could run its whole lifetime against
7
+ // a snapshot that no longer describes the tree.
8
+ //
9
+ // Rebuilding unconditionally fixes staleness but reintroduces the exact cost
10
+ // the index exists to avoid: `buildIndex` reads and SHA-1s every file. The
11
+ // probe here is deliberately cheaper — it walks the tree collecting only
12
+ // (relPath, sizeBytes, mtimeMs) and diffs that against the stored entries. No
13
+ // file contents are read. A same-size edit inside the filesystem's mtime
14
+ // granularity is the residual blind spot; it is bounded and self-healing via
15
+ // `upsertEntry` on write plus the next run's probe.
16
+ //
17
+ // This module never throws: the index is a cache of the filesystem, not an
18
+ // authorization artifact. The real boundary is `resolveInWorkspace()`'s escape
19
+ // guard, which is untouched and still fails closed. Aborting a task because a
20
+ // cache refresh hiccuped would be a denial of service for no security gain, so
21
+ // the failure mode is `degraded`.
22
+ import { promises as fs } from "node:fs";
23
+ import path from "node:path";
24
+ import { buildIndex, IGNORE_DIRS, loadIndex, MAX_INDEXED_FILE_BYTES, toPosixPath, } from "./workspace-index.js";
25
+ /** How many differing paths a verdict carries before its arrays stop growing. */
26
+ const DEFAULT_MAX_REPORTED_PATHS = 20;
27
+ async function scanDir(dir, root, acc) {
28
+ let entries;
29
+ try {
30
+ entries = await fs.readdir(dir, { withFileTypes: true });
31
+ }
32
+ catch {
33
+ return; // unreadable directory — nothing to report from it
34
+ }
35
+ for (const entry of entries) {
36
+ // Mirrors `walk()` in workspace-index.ts exactly. Divergence here would
37
+ // surface as permanent false staleness (or permanent blindness).
38
+ if (entry.name.startsWith(".") && entry.name !== ".env.example")
39
+ continue;
40
+ const full = path.join(dir, entry.name);
41
+ if (entry.isDirectory()) {
42
+ if (IGNORE_DIRS.has(entry.name))
43
+ continue;
44
+ await scanDir(full, root, acc);
45
+ }
46
+ else if (entry.isFile()) {
47
+ try {
48
+ const stat = await fs.stat(full);
49
+ if (stat.size > MAX_INDEXED_FILE_BYTES)
50
+ continue;
51
+ acc.push({
52
+ relPath: toPosixPath(path.relative(root, full)),
53
+ sizeBytes: stat.size,
54
+ mtimeMs: stat.mtimeMs,
55
+ });
56
+ }
57
+ catch {
58
+ // raced with a delete, or unreadable — next probe reconciles
59
+ }
60
+ }
61
+ }
62
+ }
63
+ /** Stat-only walk of the tree. Never throws; unreadable paths are skipped. */
64
+ export async function scanManifest(root) {
65
+ const entries = [];
66
+ await scanDir(root, root, entries);
67
+ entries.sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0));
68
+ return { root, scannedAt: new Date().toISOString(), entries };
69
+ }
70
+ /**
71
+ * Pure comparison of a stored index against a freshly scanned manifest.
72
+ *
73
+ * Free of I/O so the comparator is directly unit-testable and reusable
74
+ * without accidentally triggering a rebuild.
75
+ */
76
+ export function diffIndexAgainstManifest(index, manifest, maxReportedPaths = DEFAULT_MAX_REPORTED_PATHS) {
77
+ const cap = Math.max(0, maxReportedPaths);
78
+ const added = [];
79
+ const removed = [];
80
+ const changed = [];
81
+ let addedCount = 0;
82
+ let removedCount = 0;
83
+ let changedCount = 0;
84
+ const byPath = new Map();
85
+ for (const e of index.entries) {
86
+ byPath.set(toPosixPath(e.relPath), { sizeBytes: e.sizeBytes, mtimeMs: e.mtimeMs });
87
+ }
88
+ const builtAtMs = Date.parse(index.builtAt);
89
+ const builtAtKnown = Number.isFinite(builtAtMs);
90
+ for (const m of manifest.entries) {
91
+ const prior = byPath.get(m.relPath);
92
+ if (!prior) {
93
+ addedCount++;
94
+ if (added.length < cap)
95
+ added.push(m.relPath);
96
+ continue;
97
+ }
98
+ // A manifest entry newer than the index build is conclusive even when the
99
+ // size happens to match — belt and braces against same-size edits.
100
+ const newerThanBuild = builtAtKnown && m.mtimeMs > builtAtMs;
101
+ if (prior.sizeBytes !== m.sizeBytes || prior.mtimeMs !== m.mtimeMs || newerThanBuild) {
102
+ changedCount++;
103
+ if (changed.length < cap)
104
+ changed.push(m.relPath);
105
+ }
106
+ byPath.delete(m.relPath);
107
+ }
108
+ // Whatever is left in the map no longer exists on disk.
109
+ for (const stalePath of byPath.keys()) {
110
+ removedCount++;
111
+ if (removed.length < cap)
112
+ removed.push(stalePath);
113
+ }
114
+ const counts = { added: addedCount, removed: removedCount, changed: changedCount };
115
+ if (index.entries.length === 0 && manifest.entries.length > 0) {
116
+ return { fresh: false, reason: "empty-index", added, removed, changed, counts };
117
+ }
118
+ if (addedCount > 0)
119
+ return { fresh: false, reason: "added", added, removed, changed, counts };
120
+ if (removedCount > 0)
121
+ return { fresh: false, reason: "removed", added, removed, changed, counts };
122
+ if (changedCount > 0)
123
+ return { fresh: false, reason: "changed", added, removed, changed, counts };
124
+ return { fresh: true, reason: "ok", added, removed, changed, counts };
125
+ }
126
+ function emptyIndex(root) {
127
+ return { root, builtAt: new Date().toISOString(), entries: [] };
128
+ }
129
+ /**
130
+ * Gate the index before a task runs: reuse it when it still describes the
131
+ * tree, otherwise rebuild exactly once. Never throws.
132
+ */
133
+ export async function ensureFreshIndex(root, opts = {}) {
134
+ const startedAt = Date.now();
135
+ const elapsed = () => Math.max(0, Date.now() - startedAt);
136
+ const existing = await loadIndex(root);
137
+ if (!opts.force && opts.probe !== false && existing) {
138
+ try {
139
+ const manifest = await scanManifest(root);
140
+ const verdict = diffIndexAgainstManifest(existing, manifest, opts.maxReportedPaths);
141
+ if (verdict.fresh) {
142
+ return {
143
+ index: existing,
144
+ action: "reused",
145
+ reason: "ok",
146
+ counts: verdict.counts,
147
+ durationMs: elapsed(),
148
+ };
149
+ }
150
+ const rebuilt = await buildIndex(root);
151
+ return {
152
+ index: rebuilt,
153
+ action: "rebuilt",
154
+ reason: verdict.reason,
155
+ counts: verdict.counts,
156
+ durationMs: elapsed(),
157
+ };
158
+ }
159
+ catch {
160
+ // Probe or rebuild blew up — degrade rather than fail the task over a
161
+ // cache refresh.
162
+ return {
163
+ index: existing ?? (await loadIndex(root)) ?? emptyIndex(root),
164
+ action: "degraded",
165
+ reason: "probe-failed",
166
+ counts: { added: 0, removed: 0, changed: 0 },
167
+ durationMs: elapsed(),
168
+ };
169
+ }
170
+ }
171
+ try {
172
+ const rebuilt = await buildIndex(root);
173
+ return {
174
+ index: rebuilt,
175
+ action: "rebuilt",
176
+ reason: existing ? (opts.force ? "forced" : "probe-skipped") : "missing",
177
+ counts: { added: 0, removed: 0, changed: 0 },
178
+ durationMs: elapsed(),
179
+ };
180
+ }
181
+ catch {
182
+ return {
183
+ index: existing ?? (await loadIndex(root)) ?? emptyIndex(root),
184
+ action: "degraded",
185
+ reason: "build-failed",
186
+ counts: { added: 0, removed: 0, changed: 0 },
187
+ durationMs: elapsed(),
188
+ };
189
+ }
190
+ }
@@ -0,0 +1,48 @@
1
+ import type { WorkspaceIndex } from "./workspace-index.js";
2
+ /** Hard ceiling on results so a broad pattern cannot flood a model's context. */
3
+ export declare const MAX_GLOB_RESULTS = 5000;
4
+ /** Hard ceiling on pattern length — model-supplied input hits a regex. */
5
+ export declare const MAX_PATTERN_LENGTH = 512;
6
+ /**
7
+ * Expand one level of `{a,b,c}` alternation into separate patterns.
8
+ * Nested braces are expanded recursively; an unbalanced brace is treated
9
+ * as a literal character. Exported for tests.
10
+ */
11
+ export declare function expandBraces(pattern: string): string[];
12
+ /**
13
+ * Compile a brace-free glob into an anchored RegExp.
14
+ *
15
+ * Supports `**` (any depth, `**\/` also matches zero directories), `*`
16
+ * (within one segment) and `?` (one character within a segment).
17
+ */
18
+ export declare function globToRegExp(pattern: string): RegExp;
19
+ export interface CompiledGlob {
20
+ /** True when `relPath` matches any expanded alternative. */
21
+ test(relPath: string): boolean;
22
+ }
23
+ /** Compile a (possibly brace-containing) glob once, for repeated matching. */
24
+ export declare function compileGlob(pattern: string): CompiledGlob;
25
+ /** Convenience: does a single relPath match this glob pattern? */
26
+ export declare function matchesGlob(relPath: string, pattern: string): boolean;
27
+ /**
28
+ * Decide whether a workspace-relative path is excluded by a set of ignore
29
+ * rules (as produced by `loadIgnoreRules`).
30
+ *
31
+ * Rules are matched with the same compiled-glob engine, so ignore semantics
32
+ * and glob semantics cannot drift apart.
33
+ */
34
+ export declare function isIgnoredByRules(relPath: string, rules: readonly string[]): boolean;
35
+ export interface GlobIndexOptions {
36
+ /** Ignore rules to subtract from the result set. */
37
+ ignore?: readonly string[];
38
+ /** Maximum number of results (defaults to MAX_GLOB_RESULTS). */
39
+ limit?: number;
40
+ }
41
+ /**
42
+ * Glob the index with zero filesystem access.
43
+ *
44
+ * Results are sorted for deterministic output and are always a subset of
45
+ * `index.entries[].relPath` — that containment is the property the
46
+ * index-only-discovery contract test asserts.
47
+ */
48
+ export declare function globIndex(index: WorkspaceIndex, pattern: string, opts?: GlobIndexOptions): string[];
@@ -0,0 +1,175 @@
1
+ // xcoder:version 1 | xcoder:task task-e16f85 | xcoder:updated 2026-10-30T18:13:01.840Z | xcoder:subtask code-st-791be4
2
+ // Pure, in-memory glob matching over `WorkspaceIndex.entries`.
3
+ //
4
+ // This module never touches the filesystem. It exists so that *which files
5
+ // exist* is answered by the workspace index alone — the single source of
6
+ // truth — instead of by an independent directory walk that can disagree
7
+ // with it.
8
+ //
9
+ // The matcher was promoted from `search-tools.ts` (which had its own copy)
10
+ // and extended with brace alternation `{a,b}`, because delegating pattern
11
+ // matching to a second implementation is precisely the inconsistency this
12
+ // change removes. No external dependency: `picomatch` is present on disk
13
+ // only as a transitive hoist of `tinyglobby` and ships no type declarations,
14
+ // so importing it would add a supply-chain edge for no behavioural gain.
15
+ import { toPosixPath } from "./workspace-index.js";
16
+ /** Hard ceiling on results so a broad pattern cannot flood a model's context. */
17
+ export const MAX_GLOB_RESULTS = 5000;
18
+ /** Hard ceiling on pattern length — model-supplied input hits a regex. */
19
+ export const MAX_PATTERN_LENGTH = 512;
20
+ /**
21
+ * Expand one level of `{a,b,c}` alternation into separate patterns.
22
+ * Nested braces are expanded recursively; an unbalanced brace is treated
23
+ * as a literal character. Exported for tests.
24
+ */
25
+ export function expandBraces(pattern) {
26
+ const open = pattern.indexOf("{");
27
+ if (open === -1)
28
+ return [pattern];
29
+ let depth = 0;
30
+ let close = -1;
31
+ for (let i = open; i < pattern.length; i++) {
32
+ if (pattern[i] === "{")
33
+ depth++;
34
+ else if (pattern[i] === "}") {
35
+ depth--;
36
+ if (depth === 0) {
37
+ close = i;
38
+ break;
39
+ }
40
+ }
41
+ }
42
+ if (close === -1)
43
+ return [pattern];
44
+ const prefix = pattern.slice(0, open);
45
+ const body = pattern.slice(open + 1, close);
46
+ const suffix = pattern.slice(close + 1);
47
+ // Split the body on top-level commas only (so `{a,{b,c}}` splits correctly).
48
+ const parts = [];
49
+ let partStart = 0;
50
+ let innerDepth = 0;
51
+ for (let i = 0; i < body.length; i++) {
52
+ if (body[i] === "{")
53
+ innerDepth++;
54
+ else if (body[i] === "}")
55
+ innerDepth--;
56
+ else if (body[i] === "," && innerDepth === 0) {
57
+ parts.push(body.slice(partStart, i));
58
+ partStart = i + 1;
59
+ }
60
+ }
61
+ parts.push(body.slice(partStart));
62
+ if (parts.length === 1) {
63
+ // `{single}` is not alternation — treat the braces as literal.
64
+ return [pattern];
65
+ }
66
+ const expanded = [];
67
+ for (const part of parts) {
68
+ for (const rest of expandBraces(prefix + part + suffix)) {
69
+ expanded.push(rest);
70
+ }
71
+ }
72
+ return expanded;
73
+ }
74
+ /**
75
+ * Compile a brace-free glob into an anchored RegExp.
76
+ *
77
+ * Supports `**` (any depth, `**\/` also matches zero directories), `*`
78
+ * (within one segment) and `?` (one character within a segment).
79
+ */
80
+ export function globToRegExp(pattern) {
81
+ const p = toPosixPath(pattern);
82
+ let re = "";
83
+ for (let i = 0; i < p.length; i++) {
84
+ const c = p[i];
85
+ if (c === "*") {
86
+ if (p[i + 1] === "*") {
87
+ // Consume every following `*`, then an optional single `/` so that
88
+ // `src/**/*.ts` matches `src/app.ts` as well as `src/sub/util.ts`.
89
+ while (p[i + 1] === "*")
90
+ i++;
91
+ if (p[i + 1] === "/") {
92
+ re += "(?:.*/)?";
93
+ i++;
94
+ }
95
+ else {
96
+ re += ".*";
97
+ }
98
+ }
99
+ else {
100
+ re += "[^/]*";
101
+ }
102
+ }
103
+ else if (c === "?") {
104
+ re += "[^/]";
105
+ }
106
+ else if (".+^${}()|[]\\/".includes(c)) {
107
+ re += "\\" + c;
108
+ }
109
+ else {
110
+ re += c;
111
+ }
112
+ }
113
+ return new RegExp(`^${re}$`);
114
+ }
115
+ /** Compile a (possibly brace-containing) glob once, for repeated matching. */
116
+ export function compileGlob(pattern) {
117
+ const alternatives = expandBraces(pattern).map(globToRegExp);
118
+ return {
119
+ test(relPath) {
120
+ const normalized = toPosixPath(relPath);
121
+ return alternatives.some((re) => re.test(normalized));
122
+ },
123
+ };
124
+ }
125
+ /** Convenience: does a single relPath match this glob pattern? */
126
+ export function matchesGlob(relPath, pattern) {
127
+ return compileGlob(pattern).test(relPath);
128
+ }
129
+ /**
130
+ * Decide whether a workspace-relative path is excluded by a set of ignore
131
+ * rules (as produced by `loadIgnoreRules`).
132
+ *
133
+ * Rules are matched with the same compiled-glob engine, so ignore semantics
134
+ * and glob semantics cannot drift apart.
135
+ */
136
+ export function isIgnoredByRules(relPath, rules) {
137
+ const normalized = toPosixPath(relPath);
138
+ for (const rule of rules) {
139
+ const raw = rule.trim();
140
+ if (!raw)
141
+ continue;
142
+ // A rule that names a directory at any depth — `**/dist/**` — also
143
+ // excludes anything beneath it, which `compileGlob` already handles.
144
+ if (compileGlob(raw).test(normalized))
145
+ return true;
146
+ }
147
+ return false;
148
+ }
149
+ /**
150
+ * Glob the index with zero filesystem access.
151
+ *
152
+ * Results are sorted for deterministic output and are always a subset of
153
+ * `index.entries[].relPath` — that containment is the property the
154
+ * index-only-discovery contract test asserts.
155
+ */
156
+ export function globIndex(index, pattern, opts = {}) {
157
+ const limit = Math.max(0, opts.limit ?? MAX_GLOB_RESULTS);
158
+ if (limit === 0)
159
+ return [];
160
+ if (pattern.length > MAX_PATTERN_LENGTH)
161
+ return [];
162
+ const compiled = compileGlob(pattern);
163
+ const ignore = opts.ignore ?? [];
164
+ const out = [];
165
+ for (const entry of index.entries) {
166
+ if (out.length >= limit)
167
+ break;
168
+ if (!compiled.test(entry.relPath))
169
+ continue;
170
+ if (ignore.length && isIgnoredByRules(entry.relPath, ignore))
171
+ continue;
172
+ out.push(entry.relPath);
173
+ }
174
+ return out.sort();
175
+ }
@@ -0,0 +1,15 @@
1
+ import type { ToolCallResult } from "./tool-registry.js";
2
+ export interface LoadSkillInput {
3
+ role?: string;
4
+ keyword?: string;
5
+ }
6
+ /**
7
+ * Load the full bodies of external skill files (SKILL.md) by role or keyword.
8
+ *
9
+ * Modes (mutually exclusive):
10
+ * - role: looks up ROLE_SKILL_ALLOWLIST[role] and loads each allowed skill.
11
+ * - keyword: calls registry.route(keyword) and returns top 5 matches.
12
+ */
13
+ export declare function loadSkillTool(input: LoadSkillInput, opts: {
14
+ skillDir?: string;
15
+ }): Promise<ToolCallResult>;
@@ -0,0 +1,114 @@
1
+ import { SkillRegistry } from "../skills/externalSkillRegistry.js";
2
+ import { isExternalSkillsEnabled } from "../skills/externalSkillLoader.js";
3
+ import { ROLE_SKILL_ALLOWLIST } from "../skills/skillRouter.js";
4
+ /**
5
+ * Load the full bodies of external skill files (SKILL.md) by role or keyword.
6
+ *
7
+ * Modes (mutually exclusive):
8
+ * - role: looks up ROLE_SKILL_ALLOWLIST[role] and loads each allowed skill.
9
+ * - keyword: calls registry.route(keyword) and returns top 5 matches.
10
+ */
11
+ export async function loadSkillTool(input, opts) {
12
+ // ── Flag gate ──────────────────────────────────────────────────────
13
+ if (!isExternalSkillsEnabled()) {
14
+ return {
15
+ tool: "load_skill",
16
+ ok: true, // valid response, not an error
17
+ output: { skills: [], reason: "external skills disabled" },
18
+ };
19
+ }
20
+ const { role, keyword } = input;
21
+ // ── Modal validation: role XOR keyword must be a non-empty string ──
22
+ const hasRole = typeof role === "string" && role.trim().length > 0;
23
+ const hasKeyword = typeof keyword === "string" && keyword.trim().length > 0;
24
+ if (!hasRole && !hasKeyword) {
25
+ return {
26
+ tool: "load_skill",
27
+ ok: false,
28
+ output: {
29
+ error: '"load_skill" requires exactly one of "role" or "keyword" to be a non-empty string. ' +
30
+ 'Provide either { "role": "tester" } or { "keyword": "penetration testing" } — not both and not neither.',
31
+ },
32
+ };
33
+ }
34
+ if (hasRole && hasKeyword) {
35
+ return {
36
+ tool: "load_skill",
37
+ ok: false,
38
+ output: {
39
+ error: '"load_skill" received both "role" and "keyword". Choose one mode — ' +
40
+ 'role-based lookup OR keyword-based search — not both at once.',
41
+ },
42
+ };
43
+ }
44
+ // ── Fresh registry per call (see tradeoff #1 in design) ─────────────
45
+ const registry = new SkillRegistry(opts.skillDir);
46
+ registry.loadHeaders();
47
+ try {
48
+ if (hasRole) {
49
+ const skills = getSkillsForRole(registry, role.trim());
50
+ return {
51
+ tool: "load_skill",
52
+ ok: true,
53
+ output: {
54
+ skills: skills.map(formatLoadedSkillForOutput),
55
+ mode: "role",
56
+ role: role.trim(),
57
+ },
58
+ };
59
+ }
60
+ // hasKeyword branch
61
+ const skills = getSkillsForKeyword(registry, keyword.trim(), 5);
62
+ return {
63
+ tool: "load_skill",
64
+ ok: true,
65
+ output: {
66
+ skills: skills.map(formatLoadedSkillForOutput),
67
+ mode: "keyword",
68
+ keyword: keyword.trim(),
69
+ },
70
+ };
71
+ }
72
+ catch (e) {
73
+ return {
74
+ tool: "load_skill",
75
+ ok: false,
76
+ output: { error: `load_skill unexpected error: ${e.message}` },
77
+ };
78
+ }
79
+ }
80
+ // ── Private helpers ────────────────────────────────────────────────────────
81
+ function getSkillsForRole(registry, role) {
82
+ const allowedNames = ROLE_SKILL_ALLOWLIST[role];
83
+ if (!allowedNames || allowedNames.length === 0) {
84
+ return [];
85
+ }
86
+ const skills = [];
87
+ for (const name of allowedNames) {
88
+ const skill = registry.loadSkill(name);
89
+ if (skill) {
90
+ skills.push(skill);
91
+ }
92
+ }
93
+ return skills;
94
+ }
95
+ function getSkillsForKeyword(registry, keyword, maxResults) {
96
+ const headers = registry.route(keyword);
97
+ const top = headers.slice(0, maxResults);
98
+ const skills = [];
99
+ for (const header of top) {
100
+ const skill = registry.loadSkill(header.name);
101
+ if (skill) {
102
+ skills.push(skill);
103
+ }
104
+ }
105
+ return skills;
106
+ }
107
+ function formatLoadedSkillForOutput(skill) {
108
+ return {
109
+ name: skill.header.name,
110
+ description: skill.header.description,
111
+ body: skill.body,
112
+ path: skill.path,
113
+ };
114
+ }
@@ -0,0 +1,58 @@
1
+ export declare class WorkspaceEscapeError extends Error {
2
+ }
3
+ /**
4
+ * Every path a tool touches is resolved and pinned inside the workspace root.
5
+ * No `..` escapes — the same 8-line guard every other path-taking tool uses.
6
+ */
7
+ export declare function resolveInWorkspace(root: string, relPath: string): string;
8
+ /**
9
+ * Full-file sha1, byte-for-byte identical to the one `workspace-index.ts`
10
+ * stores per entry — so a sha1 taken here is directly comparable with the
11
+ * index's value and with the `readSha1` returned by range reads.
12
+ */
13
+ export declare function hashFile(fullPath: string): Promise<string>;
14
+ /**
15
+ * The reusable staleness core behind every stale-enforced write tool.
16
+ * Compares the file's CURRENT sha1 against the sha1 the caller observed
17
+ * earlier (via read_file's `readSha1`). A mismatch means the file changed
18
+ * under the caller — the write MUST NOT proceed.
19
+ */
20
+ export declare function assertFileUnchanged(fullPath: string, expectedSha1: string): Promise<{
21
+ ok: true;
22
+ } | {
23
+ ok: false;
24
+ actualSha1: string;
25
+ }>;
26
+ export interface LinePatchInput {
27
+ path: string;
28
+ startLine: number;
29
+ endLine: number;
30
+ newContent: string;
31
+ expectedSha1: string;
32
+ }
33
+ export type LinePatchResult = {
34
+ ok: true;
35
+ relPath: string;
36
+ replacedLines: [number, number];
37
+ newContentChars: number;
38
+ linesAfter: number;
39
+ sha1After: string;
40
+ } | {
41
+ ok: false;
42
+ error: string;
43
+ code: "stale" | "stale_field_missing" | "file_not_found" | "workspace_escape" | "invalid_range" | "io_error";
44
+ actualSha1?: string;
45
+ };
46
+ /**
47
+ * Replace lines [startLine..endLine] (1-indexed, inclusive) with newContent.
48
+ *
49
+ * Staleness contract: `expectedSha1` is REQUIRED. It must come from the
50
+ * `readSha1` field of a prior read_file range call. The file is hashed
51
+ * immediately before any mutation; a mismatch returns `stale` and performs
52
+ * ZERO writes — never a blind line splice onto a file that changed under
53
+ * the agent.
54
+ */
55
+ export declare function linePatchTool(root: string, input: LinePatchInput, ctx?: {
56
+ taskId: string;
57
+ subtaskId: string;
58
+ }): Promise<LinePatchResult>;