@iowarp/clio-coder 0.3.0 → 0.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 (988) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +50 -53
  3. package/dist/acp-FPR54DGL.js +138 -0
  4. package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
  5. package/dist/assets/codewiki.json +1 -0
  6. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
  7. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
  8. package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
  9. package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
  10. package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
  11. package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
  12. package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
  13. package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
  14. package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
  15. package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
  16. package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
  17. package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
  18. package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
  19. package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
  20. package/dist/assets/grammars/tree-sitter.wasm +0 -0
  21. package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
  22. package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
  23. package/dist/chunk-3I7MS7N2.js +40 -0
  24. package/dist/chunk-3R73A4XB.js +69 -0
  25. package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
  26. package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
  27. package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
  28. package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
  29. package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
  30. package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
  31. package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
  32. package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
  33. package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
  34. package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
  35. package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
  36. package/dist/chunk-EYOKLTMF.js +170 -0
  37. package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
  38. package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
  39. package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
  40. package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
  41. package/dist/chunk-GB6QRBXN.js +8543 -0
  42. package/dist/chunk-GEP36Y4X.js +12796 -0
  43. package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
  44. package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
  45. package/dist/chunk-IHXBNWMM.js +137 -0
  46. package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
  47. package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
  48. package/dist/chunk-K2ITRMHZ.js +642 -0
  49. package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
  50. package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
  51. package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
  52. package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
  53. package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
  54. package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
  55. package/dist/chunk-N6F52NLF.js +6951 -0
  56. package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
  57. package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
  58. package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
  59. package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
  60. package/dist/chunk-PV4JUBVJ.js +462 -0
  61. package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
  62. package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
  63. package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
  64. package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
  65. package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
  66. package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
  67. package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
  68. package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
  69. package/dist/chunk-TXOTCRLG.js +15 -0
  70. package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
  71. package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
  72. package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
  73. package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
  74. package/dist/cli/index.js +39 -33
  75. package/dist/clio-BZVGEUFJ.js +58 -0
  76. package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
  77. package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
  78. package/dist/configure-S7S6F6CL.js +32 -0
  79. package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
  80. package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
  81. package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
  82. package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
  83. package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
  84. package/dist/doctor-UC5NAJYQ.js +77 -0
  85. package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
  86. package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
  87. package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
  88. package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
  89. package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
  90. package/dist/fleet-preflight-DSNT37JK.js +23 -0
  91. package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
  92. package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
  93. package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
  94. package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
  95. package/dist/preload-6WVMHX3A.js +13 -0
  96. package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
  97. package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
  98. package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
  99. package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
  100. package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
  101. package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
  102. package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
  103. package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
  104. package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
  105. package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
  106. package/dist/version-KGEG7EPO.js +21 -0
  107. package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
  108. package/dist/worker/entry.js +101 -43
  109. package/docs/README.md +12 -9
  110. package/docs/acp.md +28 -5
  111. package/docs/alcf-provider.md +1 -1
  112. package/docs/architecture.md +23 -2
  113. package/docs/artifact-placement.md +101 -0
  114. package/docs/artifact-versions.md +1 -1
  115. package/docs/built-in-agents.md +4 -2
  116. package/docs/capacity-and-scheduling.md +1 -1
  117. package/docs/commands-and-modes.md +125 -41
  118. package/docs/configuration-and-targets.md +88 -18
  119. package/docs/context-engine.md +6 -2
  120. package/docs/development-pipeline.md +77 -0
  121. package/docs/documentation-coverage.md +4 -4
  122. package/docs/documentation-guide.md +3 -3
  123. package/docs/environment-variables.md +2 -1
  124. package/docs/eval-runner.md +3 -3
  125. package/docs/evals-internal.md +2 -2
  126. package/docs/evidence-and-memory.md +6 -2
  127. package/docs/evolution.md +1 -1
  128. package/docs/exit-codes-and-output.md +1 -1
  129. package/docs/extensions-and-sharing.md +18 -11
  130. package/docs/fleet-demo-runbook.md +22 -23
  131. package/docs/fleet-dispatch.md +111 -12
  132. package/docs/glossary.md +107 -15
  133. package/docs/html/agents_blueprint.html +3 -3
  134. package/docs/html/alcf_blueprint.html +3 -3
  135. package/docs/html/architecture_blueprint.html +3 -3
  136. package/docs/html/commands_blueprint.html +187 -42
  137. package/docs/html/configuration_blueprint.html +7 -7
  138. package/docs/html/context_blueprint.html +3 -3
  139. package/docs/html/documentation_blueprint.html +1 -1
  140. package/docs/html/environment_blueprint.html +3 -3
  141. package/docs/html/eval_blueprint.html +4 -4
  142. package/docs/html/evals_internal_blueprint.html +3 -3
  143. package/docs/html/evolution_blueprint.html +3 -3
  144. package/docs/html/extensions_blueprint.html +3 -3
  145. package/docs/html/fleet_dispatch_blueprint.html +8 -8
  146. package/docs/html/index.html +5 -5
  147. package/docs/html/lifecycle_blueprint.html +4 -4
  148. package/docs/html/memory_blueprint.html +3 -3
  149. package/docs/html/middleware_blueprint.html +3 -3
  150. package/docs/html/models_blueprint.html +2 -2
  151. package/docs/html/observability_blueprint.html +2 -2
  152. package/docs/html/provider_adapter_blueprint.html +3 -3
  153. package/docs/html/safety_blueprint.html +3 -3
  154. package/docs/html/skills_blueprint.html +2 -2
  155. package/docs/html/soak_blueprint.html +3 -3
  156. package/docs/html/tool_usage_blueprint.html +4 -4
  157. package/docs/html/tools_blueprint.html +2 -2
  158. package/docs/html/trace_blueprint.html +3 -3
  159. package/docs/html/tui_design_blueprint.html +100 -40
  160. package/docs/html/validation_blueprint.html +1 -1
  161. package/docs/html/worker_dispatch_blueprint.html +3 -3
  162. package/docs/installation-and-lifecycle.md +62 -11
  163. package/docs/middleware-and-components.md +1 -1
  164. package/docs/model-catalog.md +2 -2
  165. package/docs/observability.md +3 -3
  166. package/docs/proactive-memory.md +12 -12
  167. package/docs/prompt-envelope-and-tools.md +2 -2
  168. package/docs/provider-adapter-cookbook.md +1 -1
  169. package/docs/release-cut-checklist.md +4 -0
  170. package/docs/safety-model.md +21 -5
  171. package/docs/scientific-validation.md +3 -3
  172. package/docs/session-lifecycle.md +2 -2
  173. package/docs/skills-marketplace.md +1 -1
  174. package/docs/time-conventions.md +101 -0
  175. package/docs/tool-usage.md +5 -4
  176. package/docs/trace-store.md +1 -1
  177. package/docs/troubleshooting.md +1 -1
  178. package/docs/tui-design.md +83 -27
  179. package/docs/worker-dispatch-mechanics.md +3 -3
  180. package/package.json +16 -16
  181. package/skills/README.md +5 -6
  182. package/skills/git/file-ticket/SKILL.md +107 -0
  183. package/skills/git/file-ticket/evals.md +54 -0
  184. package/skills/git/fix-issue/SKILL.md +106 -0
  185. package/skills/git/fix-issue/evals.md +71 -0
  186. package/skills/git/ship/SKILL.md +92 -0
  187. package/skills/git/ship/evals.md +72 -0
  188. package/skills/skill-marketplace.json +12 -20
  189. package/src/cli/acp.ts +88 -0
  190. package/src/cli/agents.ts +60 -0
  191. package/src/cli/args.ts +280 -0
  192. package/src/cli/argv.ts +170 -0
  193. package/src/cli/ask.ts +34 -0
  194. package/src/cli/auth.ts +468 -0
  195. package/src/cli/bootstrap-generate.ts +498 -0
  196. package/src/cli/clio.ts +34 -0
  197. package/src/cli/components.ts +195 -0
  198. package/src/cli/config-inspect.ts +330 -0
  199. package/src/cli/config.ts +72 -0
  200. package/src/cli/configure-interop.ts +67 -0
  201. package/src/cli/configure-layout.ts +172 -0
  202. package/src/cli/configure.ts +1487 -0
  203. package/src/cli/context-clear.ts +76 -0
  204. package/src/cli/context-index.ts +102 -0
  205. package/src/cli/context.ts +316 -0
  206. package/src/cli/default-target.ts +63 -0
  207. package/src/cli/docs.ts +340 -0
  208. package/src/cli/doctor.ts +54 -0
  209. package/src/cli/eval.ts +315 -0
  210. package/src/cli/evidence.ts +222 -0
  211. package/src/cli/evolve.ts +219 -0
  212. package/src/cli/extensions.ts +205 -0
  213. package/src/cli/fleet.ts +827 -0
  214. package/src/cli/index.ts +309 -0
  215. package/src/cli/init.ts +219 -0
  216. package/src/cli/initial-message.ts +47 -0
  217. package/src/cli/internal-dispatch.ts +55 -0
  218. package/src/cli/memory.ts +180 -0
  219. package/src/cli/models.ts +257 -0
  220. package/src/cli/modes/json-stream.ts +85 -0
  221. package/src/cli/modes/jsonl.ts +9 -0
  222. package/src/cli/modes/print.ts +589 -0
  223. package/src/cli/oauth-manual-input.ts +72 -0
  224. package/src/cli/oauth-select.ts +36 -0
  225. package/src/cli/output-guard.ts +48 -0
  226. package/src/cli/paths.ts +44 -0
  227. package/src/cli/provider-target.ts +113 -0
  228. package/src/cli/removal.ts +72 -0
  229. package/src/cli/reset.ts +253 -0
  230. package/src/cli/run.ts +497 -0
  231. package/src/cli/share.ts +243 -0
  232. package/src/cli/shared.ts +60 -0
  233. package/src/cli/skills-eval.ts +1225 -0
  234. package/src/cli/skills.ts +470 -0
  235. package/src/cli/steer-channel.ts +86 -0
  236. package/src/cli/targets.ts +1150 -0
  237. package/src/cli/text-layout.ts +102 -0
  238. package/src/cli/trace.ts +274 -0
  239. package/src/cli/uninstall.ts +405 -0
  240. package/src/cli/upgrade.ts +270 -0
  241. package/src/cli/usage.ts +869 -0
  242. package/src/cli/validate-model.ts +28 -0
  243. package/src/cli/version.ts +7 -0
  244. package/src/cli/wiki-generate.ts +509 -0
  245. package/src/core/artifact-paths.ts +43 -0
  246. package/src/core/bash-exec.ts +242 -0
  247. package/src/core/boot-trace.ts +37 -0
  248. package/src/core/bus-events.ts +728 -0
  249. package/src/core/bus-trace.ts +53 -0
  250. package/src/core/c-header-language.ts +265 -0
  251. package/src/core/clio-repo.ts +78 -0
  252. package/src/core/config.ts +1593 -0
  253. package/src/core/context-floor.ts +33 -0
  254. package/src/core/defaults.ts +625 -0
  255. package/src/core/domain-loader.ts +170 -0
  256. package/src/core/event-bus.ts +94 -0
  257. package/src/core/file-references.ts +282 -0
  258. package/src/core/guardrails.ts +185 -0
  259. package/src/core/headless-permission.ts +21 -0
  260. package/src/core/init.ts +223 -0
  261. package/src/core/json-payload.ts +58 -0
  262. package/src/core/package-root.ts +54 -0
  263. package/src/core/path-canonical.ts +37 -0
  264. package/src/core/process-identity.ts +41 -0
  265. package/src/core/recent-models.ts +91 -0
  266. package/src/core/release.ts +2 -0
  267. package/src/core/residency-protection.ts +56 -0
  268. package/src/core/resolve-config-value.ts +88 -0
  269. package/src/core/response-schema.ts +279 -0
  270. package/src/core/run-overrides.ts +77 -0
  271. package/src/core/safe-exec.ts +193 -0
  272. package/src/core/safe-id.ts +37 -0
  273. package/src/core/safe-resource-write.ts +162 -0
  274. package/src/core/session-routing.ts +339 -0
  275. package/src/core/settings-layers.ts +220 -0
  276. package/src/core/shared-bus.ts +8 -0
  277. package/src/core/shell-quote.ts +26 -0
  278. package/src/core/skill-activation.ts +190 -0
  279. package/src/core/startup-timer.ts +37 -0
  280. package/src/core/state-file-lock.ts +207 -0
  281. package/src/core/termination.ts +202 -0
  282. package/src/core/timers.ts +38 -0
  283. package/src/core/tool-names.ts +65 -0
  284. package/src/core/verification-scripts.ts +13 -0
  285. package/src/core/workspace-files.ts +492 -0
  286. package/src/core/xdg.ts +177 -0
  287. package/src/domains/agents/builtins/architect.md +4 -4
  288. package/src/domains/agents/builtins/coder.md +3 -2
  289. package/src/domains/agents/builtins/debugger.md +1 -1
  290. package/src/domains/agents/builtins/documenter.md +1 -1
  291. package/src/domains/agents/builtins/git-master.md +3 -3
  292. package/src/domains/agents/builtins/provenance.md +1 -1
  293. package/src/domains/agents/builtins/researcher.md +1 -1
  294. package/src/domains/agents/builtins/scout.md +1 -1
  295. package/src/domains/agents/builtins/tester.md +1 -1
  296. package/src/domains/agents/builtins/verifier.md +1 -1
  297. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  298. package/src/domains/agents/catalog.ts +172 -0
  299. package/src/domains/agents/contract.ts +16 -0
  300. package/src/domains/agents/extension.ts +110 -0
  301. package/src/domains/agents/fleet-commands.ts +154 -0
  302. package/src/domains/agents/fleet-contract.ts +797 -0
  303. package/src/domains/agents/frontmatter.ts +40 -0
  304. package/src/domains/agents/index.ts +102 -0
  305. package/src/domains/agents/manifest.ts +6 -0
  306. package/src/domains/agents/recipe-schema.ts +202 -0
  307. package/src/domains/agents/recipe.ts +125 -0
  308. package/src/domains/agents/registry.ts +111 -0
  309. package/src/domains/agents/result-contract.ts +1265 -0
  310. package/src/domains/agents/spec.ts +371 -0
  311. package/src/domains/agents/write-boundary.ts +109 -0
  312. package/src/domains/components/diff.ts +99 -0
  313. package/src/domains/components/hash.ts +21 -0
  314. package/src/domains/components/index.ts +3 -0
  315. package/src/domains/components/scan.ts +304 -0
  316. package/src/domains/components/snapshot.ts +108 -0
  317. package/src/domains/components/types.ts +82 -0
  318. package/src/domains/config/agent-namespace.ts +13 -0
  319. package/src/domains/config/classify.ts +94 -0
  320. package/src/domains/config/contract.ts +22 -0
  321. package/src/domains/config/extension.ts +136 -0
  322. package/src/domains/config/index.ts +13 -0
  323. package/src/domains/config/keybindings.ts +164 -0
  324. package/src/domains/config/manifest.ts +6 -0
  325. package/src/domains/config/watcher.ts +41 -0
  326. package/src/domains/context/adoption.ts +880 -0
  327. package/src/domains/context/bootstrap-prompt.ts +273 -0
  328. package/src/domains/context/bootstrap.ts +1409 -0
  329. package/src/domains/context/clear.ts +86 -0
  330. package/src/domains/context/clio-md.ts +327 -0
  331. package/src/domains/context/codewiki/cmake.ts +356 -0
  332. package/src/domains/context/codewiki/cooperative.ts +46 -0
  333. package/src/domains/context/codewiki/digest.ts +135 -0
  334. package/src/domains/context/codewiki/grammar-assets.ts +33 -0
  335. package/src/domains/context/codewiki/indexer.ts +1614 -0
  336. package/src/domains/context/codewiki/tree-sitter.ts +771 -0
  337. package/src/domains/context/contract.ts +62 -0
  338. package/src/domains/context/excluded-dirs.ts +1 -0
  339. package/src/domains/context/extension.ts +407 -0
  340. package/src/domains/context/fingerprint.ts +196 -0
  341. package/src/domains/context/index.ts +164 -0
  342. package/src/domains/context/init-options.ts +69 -0
  343. package/src/domains/context/manifest.ts +6 -0
  344. package/src/domains/context/operator-profile.ts +157 -0
  345. package/src/domains/context/project-metadata.ts +510 -0
  346. package/src/domains/context/project-rules.ts +227 -0
  347. package/src/domains/context/prompt-context.ts +62 -0
  348. package/src/domains/context/refresh.ts +170 -0
  349. package/src/domains/context/sibling-files.ts +10 -0
  350. package/src/domains/context/state.ts +237 -0
  351. package/src/domains/context/wiki/assemble.ts +303 -0
  352. package/src/domains/context/wiki/frontmatter.ts +210 -0
  353. package/src/domains/context/wiki/generate.ts +590 -0
  354. package/src/domains/context/wiki/layout.ts +111 -0
  355. package/src/domains/context/wiki/meta.ts +221 -0
  356. package/src/domains/context/wiki/plan-store.ts +217 -0
  357. package/src/domains/context/wiki/plan.ts +250 -0
  358. package/src/domains/context/wiki/prompts.ts +270 -0
  359. package/src/domains/context/wiki/staleness.ts +198 -0
  360. package/src/domains/dispatch/active-route-planner.ts +168 -0
  361. package/src/domains/dispatch/admission-queue.ts +150 -0
  362. package/src/domains/dispatch/admission.ts +334 -0
  363. package/src/domains/dispatch/agent-candidates.ts +307 -0
  364. package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
  365. package/src/domains/dispatch/agent-ledger-store.ts +257 -0
  366. package/src/domains/dispatch/agent-ledger.ts +212 -0
  367. package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
  368. package/src/domains/dispatch/assignment-events.ts +132 -0
  369. package/src/domains/dispatch/assignment-reconcile.ts +76 -0
  370. package/src/domains/dispatch/assignment-store.ts +162 -0
  371. package/src/domains/dispatch/assignment.ts +278 -0
  372. package/src/domains/dispatch/backoff.ts +59 -0
  373. package/src/domains/dispatch/batch-store.ts +134 -0
  374. package/src/domains/dispatch/batch-tracker.ts +66 -0
  375. package/src/domains/dispatch/capability-match.ts +155 -0
  376. package/src/domains/dispatch/capacity-lease.ts +413 -0
  377. package/src/domains/dispatch/code-step-store.ts +52 -0
  378. package/src/domains/dispatch/code-step.ts +368 -0
  379. package/src/domains/dispatch/contract.ts +278 -0
  380. package/src/domains/dispatch/dedup.ts +133 -0
  381. package/src/domains/dispatch/event-pump.ts +251 -0
  382. package/src/domains/dispatch/execution-handoff.ts +29 -0
  383. package/src/domains/dispatch/execution-plan.ts +328 -0
  384. package/src/domains/dispatch/execution-role.ts +277 -0
  385. package/src/domains/dispatch/execution-scheduler.ts +583 -0
  386. package/src/domains/dispatch/extension.ts +5869 -0
  387. package/src/domains/dispatch/failure-classification.ts +141 -0
  388. package/src/domains/dispatch/fleet-plan.ts +225 -0
  389. package/src/domains/dispatch/fleet-preflight.ts +394 -0
  390. package/src/domains/dispatch/gate-decisions.ts +1040 -0
  391. package/src/domains/dispatch/gate-role-prompts.ts +58 -0
  392. package/src/domains/dispatch/heartbeat.ts +27 -0
  393. package/src/domains/dispatch/index.ts +137 -0
  394. package/src/domains/dispatch/joint-route-adapter.ts +114 -0
  395. package/src/domains/dispatch/joint-route-resolver.ts +283 -0
  396. package/src/domains/dispatch/manifest.ts +6 -0
  397. package/src/domains/dispatch/orphan-recovery.ts +224 -0
  398. package/src/domains/dispatch/outcome.ts +109 -0
  399. package/src/domains/dispatch/phase-timing.ts +47 -0
  400. package/src/domains/dispatch/placement.ts +202 -0
  401. package/src/domains/dispatch/receipt-findings.ts +255 -0
  402. package/src/domains/dispatch/receipt-integrity.ts +378 -0
  403. package/src/domains/dispatch/recovery-candidates.ts +74 -0
  404. package/src/domains/dispatch/reproducibility.ts +48 -0
  405. package/src/domains/dispatch/reservation-store.ts +501 -0
  406. package/src/domains/dispatch/route-approval.ts +177 -0
  407. package/src/domains/dispatch/route-candidates.ts +57 -0
  408. package/src/domains/dispatch/route-decision.ts +1079 -0
  409. package/src/domains/dispatch/route-facts.ts +187 -0
  410. package/src/domains/dispatch/route-history.ts +238 -0
  411. package/src/domains/dispatch/route-observer.ts +488 -0
  412. package/src/domains/dispatch/route-policy.ts +327 -0
  413. package/src/domains/dispatch/route-quality.ts +256 -0
  414. package/src/domains/dispatch/route-readiness.ts +120 -0
  415. package/src/domains/dispatch/routing-intent.ts +287 -0
  416. package/src/domains/dispatch/run-identity.ts +56 -0
  417. package/src/domains/dispatch/scout-transition.ts +130 -0
  418. package/src/domains/dispatch/state.ts +277 -0
  419. package/src/domains/dispatch/tool-stats.ts +132 -0
  420. package/src/domains/dispatch/transport.ts +209 -0
  421. package/src/domains/dispatch/types.ts +785 -0
  422. package/src/domains/dispatch/validation-grounding.ts +154 -0
  423. package/src/domains/dispatch/validation.ts +721 -0
  424. package/src/domains/dispatch/worker-protocol.ts +275 -0
  425. package/src/domains/dispatch/worker-spawn.ts +566 -0
  426. package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
  427. package/src/domains/dispatch/write-boundary.ts +426 -0
  428. package/src/domains/eval/artifacts/redact.ts +42 -0
  429. package/src/domains/eval/artifacts/store.ts +173 -0
  430. package/src/domains/eval/compare/compare.ts +33 -0
  431. package/src/domains/eval/compare/gates.ts +66 -0
  432. package/src/domains/eval/compare/thresholds.ts +92 -0
  433. package/src/domains/eval/harness-metrics.ts +62 -0
  434. package/src/domains/eval/index.ts +66 -0
  435. package/src/domains/eval/metrics/chaos-stream.ts +93 -0
  436. package/src/domains/eval/metrics/context.ts +34 -0
  437. package/src/domains/eval/metrics/coverage.ts +21 -0
  438. package/src/domains/eval/metrics/evidence.ts +182 -0
  439. package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
  440. package/src/domains/eval/metrics/invariants.ts +736 -0
  441. package/src/domains/eval/metrics/latency.ts +4 -0
  442. package/src/domains/eval/metrics/token-stream.ts +139 -0
  443. package/src/domains/eval/metrics/tokens.ts +51 -0
  444. package/src/domains/eval/metrics/tool-calls.ts +7 -0
  445. package/src/domains/eval/proactive-memory.ts +279 -0
  446. package/src/domains/eval/provenance.ts +35 -0
  447. package/src/domains/eval/report.ts +234 -0
  448. package/src/domains/eval/reports/json.ts +5 -0
  449. package/src/domains/eval/reports/junit.ts +23 -0
  450. package/src/domains/eval/reports/markdown.ts +20 -0
  451. package/src/domains/eval/reports/swe-jsonl.ts +16 -0
  452. package/src/domains/eval/reports/text.ts +25 -0
  453. package/src/domains/eval/run-compare.ts +274 -0
  454. package/src/domains/eval/runner.ts +244 -0
  455. package/src/domains/eval/runners/clio-run.ts +148 -0
  456. package/src/domains/eval/runners/context-index.ts +56 -0
  457. package/src/domains/eval/runners/context-init.ts +203 -0
  458. package/src/domains/eval/runners/external-command.ts +350 -0
  459. package/src/domains/eval/runtime-paths.ts +171 -0
  460. package/src/domains/eval/schema/artifact.ts +75 -0
  461. package/src/domains/eval/schema/suite.ts +235 -0
  462. package/src/domains/eval/schema/validate.ts +339 -0
  463. package/src/domains/eval/store.ts +392 -0
  464. package/src/domains/eval/suites/load.ts +74 -0
  465. package/src/domains/eval/suites/matrix.ts +19 -0
  466. package/src/domains/eval/suites/resolve.ts +44 -0
  467. package/src/domains/eval/suites/run.ts +325 -0
  468. package/src/domains/eval/task-file.ts +186 -0
  469. package/src/domains/eval/types.ts +141 -0
  470. package/src/domains/eval/verifiers/command.ts +27 -0
  471. package/src/domains/eval/verifiers/file-exists.ts +6 -0
  472. package/src/domains/eval/verifiers/patch.ts +22 -0
  473. package/src/domains/eval/workspaces/git.ts +41 -0
  474. package/src/domains/eval/workspaces/local.ts +17 -0
  475. package/src/domains/eval/workspaces/temp-copy.ts +29 -0
  476. package/src/domains/evidence/build.ts +1714 -0
  477. package/src/domains/evidence/eval.ts +605 -0
  478. package/src/domains/evidence/failure-attribution.ts +54 -0
  479. package/src/domains/evidence/finish-contract-map.ts +42 -0
  480. package/src/domains/evidence/index.ts +55 -0
  481. package/src/domains/evidence/provenance.ts +200 -0
  482. package/src/domains/evidence/redact.ts +81 -0
  483. package/src/domains/evidence/store.ts +291 -0
  484. package/src/domains/evidence/types.ts +325 -0
  485. package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
  486. package/src/domains/evolution/index.ts +26 -0
  487. package/src/domains/evolution/manifest.ts +154 -0
  488. package/src/domains/evolution/validate.ts +304 -0
  489. package/src/domains/extensions/contract.ts +22 -0
  490. package/src/domains/extensions/discovery.ts +193 -0
  491. package/src/domains/extensions/extension.ts +46 -0
  492. package/src/domains/extensions/index.ts +34 -0
  493. package/src/domains/extensions/manager.ts +30 -0
  494. package/src/domains/extensions/manifest.ts +6 -0
  495. package/src/domains/extensions/resources.ts +38 -0
  496. package/src/domains/extensions/state.ts +224 -0
  497. package/src/domains/extensions/types.ts +83 -0
  498. package/src/domains/interop/consent.ts +185 -0
  499. package/src/domains/interop/contract.ts +29 -0
  500. package/src/domains/interop/detect.ts +173 -0
  501. package/src/domains/interop/extension.ts +59 -0
  502. package/src/domains/interop/index.ts +34 -0
  503. package/src/domains/interop/manifest.ts +6 -0
  504. package/src/domains/interop/registry.ts +139 -0
  505. package/src/domains/interop/state.ts +92 -0
  506. package/src/domains/interop/types.ts +109 -0
  507. package/src/domains/lifecycle/contract.ts +11 -0
  508. package/src/domains/lifecycle/doctor.ts +536 -0
  509. package/src/domains/lifecycle/extension.ts +23 -0
  510. package/src/domains/lifecycle/index.ts +21 -0
  511. package/src/domains/lifecycle/install-method.ts +51 -0
  512. package/src/domains/lifecycle/manifest.ts +6 -0
  513. package/src/domains/lifecycle/migrations/index.ts +94 -0
  514. package/src/domains/lifecycle/state.ts +93 -0
  515. package/src/domains/lifecycle/upgrade-notice.ts +35 -0
  516. package/src/domains/lifecycle/version.ts +35 -0
  517. package/src/domains/memory/index.ts +128 -0
  518. package/src/domains/memory/operations.ts +143 -0
  519. package/src/domains/memory/prompt-section.ts +86 -0
  520. package/src/domains/memory/proposal.ts +180 -0
  521. package/src/domains/memory/store.ts +163 -0
  522. package/src/domains/memory/task-bank.ts +229 -0
  523. package/src/domains/memory/task-memory-handoff.ts +222 -0
  524. package/src/domains/memory/task-memory-policy.ts +602 -0
  525. package/src/domains/memory/task-memory-status.ts +58 -0
  526. package/src/domains/memory/task-memory-telemetry.ts +346 -0
  527. package/src/domains/memory/task-memory-trace.ts +89 -0
  528. package/src/domains/memory/types.ts +74 -0
  529. package/src/domains/memory/validate.ts +297 -0
  530. package/src/domains/middleware/budget.ts +216 -0
  531. package/src/domains/middleware/contract.ts +35 -0
  532. package/src/domains/middleware/dispatch-nudge.ts +469 -0
  533. package/src/domains/middleware/extension.ts +129 -0
  534. package/src/domains/middleware/hook-receipts.ts +70 -0
  535. package/src/domains/middleware/hooks-io.ts +174 -0
  536. package/src/domains/middleware/hooks.ts +432 -0
  537. package/src/domains/middleware/index.ts +154 -0
  538. package/src/domains/middleware/manifest.ts +6 -0
  539. package/src/domains/middleware/memory-intervention.ts +701 -0
  540. package/src/domains/middleware/rules.ts +42 -0
  541. package/src/domains/middleware/runtime.ts +333 -0
  542. package/src/domains/middleware/skills-reminder.ts +187 -0
  543. package/src/domains/middleware/snapshot.ts +71 -0
  544. package/src/domains/middleware/stalled-turn.ts +71 -0
  545. package/src/domains/middleware/task-board-reminder.ts +87 -0
  546. package/src/domains/middleware/task-nudge.ts +77 -0
  547. package/src/domains/middleware/tool-choice-control.ts +42 -0
  548. package/src/domains/middleware/types.ts +131 -0
  549. package/src/domains/middleware/validate.ts +329 -0
  550. package/src/domains/observability/accountability.ts +67 -0
  551. package/src/domains/observability/contract.ts +168 -0
  552. package/src/domains/observability/cost.ts +206 -0
  553. package/src/domains/observability/evidence-index.ts +123 -0
  554. package/src/domains/observability/extension.ts +281 -0
  555. package/src/domains/observability/index.ts +78 -0
  556. package/src/domains/observability/manifest.ts +10 -0
  557. package/src/domains/observability/metrics.ts +37 -0
  558. package/src/domains/observability/projection.ts +477 -0
  559. package/src/domains/observability/telemetry.ts +89 -0
  560. package/src/domains/observability/trace-store.ts +1454 -0
  561. package/src/domains/prompts/compiler.ts +556 -0
  562. package/src/domains/prompts/contract.ts +30 -0
  563. package/src/domains/prompts/extension.ts +304 -0
  564. package/src/domains/prompts/fragment-loader.ts +139 -0
  565. package/src/domains/prompts/fragments/identity/clio.md +3 -2
  566. package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
  567. package/src/domains/prompts/fragments/operating/contract.md +10 -1
  568. package/src/domains/prompts/hash.ts +73 -0
  569. package/src/domains/prompts/index.ts +32 -0
  570. package/src/domains/prompts/manifest.ts +8 -0
  571. package/src/domains/prompts/memory-intervention.ts +57 -0
  572. package/src/domains/prompts/preload.ts +82 -0
  573. package/src/domains/providers/auth/api-key.ts +47 -0
  574. package/src/domains/providers/auth/backend-file.ts +69 -0
  575. package/src/domains/providers/auth/backend-memory.ts +17 -0
  576. package/src/domains/providers/auth/index.ts +37 -0
  577. package/src/domains/providers/auth/oauth.ts +36 -0
  578. package/src/domains/providers/auth/storage.ts +667 -0
  579. package/src/domains/providers/capabilities.ts +50 -0
  580. package/src/domains/providers/catalog.ts +162 -0
  581. package/src/domains/providers/contract.ts +151 -0
  582. package/src/domains/providers/credentials.ts +20 -0
  583. package/src/domains/providers/eligibility.ts +24 -0
  584. package/src/domains/providers/errors.ts +64 -0
  585. package/src/domains/providers/extension.ts +536 -0
  586. package/src/domains/providers/index.ts +142 -0
  587. package/src/domains/providers/knowledge-base-path.ts +102 -0
  588. package/src/domains/providers/manifest.ts +6 -0
  589. package/src/domains/providers/model-capabilities.ts +136 -0
  590. package/src/domains/providers/model-discovery.ts +144 -0
  591. package/src/domains/providers/model-family.ts +32 -0
  592. package/src/domains/providers/model-runtime-capabilities.ts +712 -0
  593. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
  594. package/src/domains/providers/plugins.ts +59 -0
  595. package/src/domains/providers/probe/fingerprint.ts +44 -0
  596. package/src/domains/providers/probe/http.ts +114 -0
  597. package/src/domains/providers/probe/reasoning.ts +111 -0
  598. package/src/domains/providers/registry.ts +166 -0
  599. package/src/domains/providers/resolver.ts +156 -0
  600. package/src/domains/providers/runtime-resolution.ts +720 -0
  601. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
  602. package/src/domains/providers/runtimes/builtins.ts +78 -0
  603. package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
  604. package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
  605. package/src/domains/providers/runtimes/claude/common.ts +55 -0
  606. package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
  607. package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
  608. package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
  609. package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
  610. package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
  611. package/src/domains/providers/runtimes/cloud/google.ts +41 -0
  612. package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
  613. package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
  614. package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
  615. package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
  616. package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
  617. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
  618. package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
  619. package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
  620. package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
  621. package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
  622. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
  623. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
  624. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
  625. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
  626. package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
  627. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
  628. package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
  629. package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
  630. package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
  631. package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
  632. package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
  633. package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
  634. package/src/domains/providers/runtimes/protocol/google.ts +27 -0
  635. package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
  636. package/src/domains/providers/support.ts +238 -0
  637. package/src/domains/providers/thinking-control-policy.ts +85 -0
  638. package/src/domains/providers/types/capability-flags.ts +114 -0
  639. package/src/domains/providers/types/cost-provenance.ts +7 -0
  640. package/src/domains/providers/types/inference.ts +41 -0
  641. package/src/domains/providers/types/knowledge-base.ts +156 -0
  642. package/src/domains/providers/types/local-model-quirks.ts +218 -0
  643. package/src/domains/providers/types/runtime-descriptor.ts +170 -0
  644. package/src/domains/providers/types/target-descriptor.ts +38 -0
  645. package/src/domains/resources/collision.ts +92 -0
  646. package/src/domains/resources/common-loader.ts +140 -0
  647. package/src/domains/resources/contract.ts +25 -0
  648. package/src/domains/resources/extension.ts +61 -0
  649. package/src/domains/resources/index.ts +74 -0
  650. package/src/domains/resources/loader.ts +86 -0
  651. package/src/domains/resources/manifest.ts +6 -0
  652. package/src/domains/resources/prompts/loader.ts +232 -0
  653. package/src/domains/resources/prompts/substitute.ts +65 -0
  654. package/src/domains/resources/skills/content-hash.ts +105 -0
  655. package/src/domains/resources/skills/evals.ts +175 -0
  656. package/src/domains/resources/skills/install.ts +410 -0
  657. package/src/domains/resources/skills/loader.ts +978 -0
  658. package/src/domains/resources/skills/marketplace.ts +255 -0
  659. package/src/domains/resources/skills/provenance-pin.ts +115 -0
  660. package/src/domains/safety/action-classifier.ts +268 -0
  661. package/src/domains/safety/approval-axis.ts +23 -0
  662. package/src/domains/safety/audit.ts +487 -0
  663. package/src/domains/safety/autonomy.ts +174 -0
  664. package/src/domains/safety/call-target.ts +59 -0
  665. package/src/domains/safety/contract.ts +65 -0
  666. package/src/domains/safety/damage-control.ts +44 -0
  667. package/src/domains/safety/default-path-policy.ts +117 -0
  668. package/src/domains/safety/extension.ts +383 -0
  669. package/src/domains/safety/finish-contract-registration.ts +128 -0
  670. package/src/domains/safety/finish-contract.ts +554 -0
  671. package/src/domains/safety/index.ts +44 -0
  672. package/src/domains/safety/loop-detector.ts +143 -0
  673. package/src/domains/safety/manifest.ts +6 -0
  674. package/src/domains/safety/path-policy.ts +164 -0
  675. package/src/domains/safety/policy-engine.ts +994 -0
  676. package/src/domains/safety/project-policy.ts +391 -0
  677. package/src/domains/safety/protected-artifacts-registration.ts +189 -0
  678. package/src/domains/safety/protected-artifacts.ts +993 -0
  679. package/src/domains/safety/rejection-feedback.ts +102 -0
  680. package/src/domains/safety/rigor.ts +72 -0
  681. package/src/domains/safety/rule-compiler.ts +48 -0
  682. package/src/domains/safety/rule-pack-loader.ts +92 -0
  683. package/src/domains/safety/run-effects.ts +197 -0
  684. package/src/domains/safety/scope.ts +61 -0
  685. package/src/domains/scheduling/budget.ts +35 -0
  686. package/src/domains/scheduling/cluster.ts +175 -0
  687. package/src/domains/scheduling/contract.ts +30 -0
  688. package/src/domains/scheduling/extension.ts +91 -0
  689. package/src/domains/scheduling/index.ts +12 -0
  690. package/src/domains/scheduling/manifest.ts +6 -0
  691. package/src/domains/session/archive-readers.ts +208 -0
  692. package/src/domains/session/checkpoint.ts +38 -0
  693. package/src/domains/session/compaction/auto.ts +89 -0
  694. package/src/domains/session/compaction/branch-summary.ts +186 -0
  695. package/src/domains/session/compaction/compact.ts +493 -0
  696. package/src/domains/session/compaction/cut-point.ts +171 -0
  697. package/src/domains/session/compaction/defaults.ts +34 -0
  698. package/src/domains/session/compaction/mask-observations.ts +265 -0
  699. package/src/domains/session/compaction/session-entries.ts +18 -0
  700. package/src/domains/session/compaction/tokens.ts +147 -0
  701. package/src/domains/session/context-accounting.ts +583 -0
  702. package/src/domains/session/context-ledger.ts +348 -0
  703. package/src/domains/session/contract.ts +144 -0
  704. package/src/domains/session/cwd-fallback.ts +65 -0
  705. package/src/domains/session/entries.ts +509 -0
  706. package/src/domains/session/extension.ts +322 -0
  707. package/src/domains/session/history.ts +172 -0
  708. package/src/domains/session/index.ts +84 -0
  709. package/src/domains/session/manager.ts +128 -0
  710. package/src/domains/session/manifest.ts +6 -0
  711. package/src/domains/session/migrations/index.ts +27 -0
  712. package/src/domains/session/prompt-manifest.ts +173 -0
  713. package/src/domains/session/protected-artifact-journal.ts +241 -0
  714. package/src/domains/session/protected-artifacts.ts +90 -0
  715. package/src/domains/session/retry.ts +238 -0
  716. package/src/domains/session/task-board.ts +375 -0
  717. package/src/domains/session/tree/active-path.ts +98 -0
  718. package/src/domains/session/tree/fork.ts +160 -0
  719. package/src/domains/session/tree/manager.ts +128 -0
  720. package/src/domains/session/tree/navigator.ts +177 -0
  721. package/src/domains/session/tree/preview.ts +259 -0
  722. package/src/domains/session/usage.ts +148 -0
  723. package/src/domains/session/workspace/git-probe.ts +161 -0
  724. package/src/domains/session/workspace/index.ts +4 -0
  725. package/src/domains/session/workspace/project-type.ts +217 -0
  726. package/src/domains/session/workspace/snapshot.ts +74 -0
  727. package/src/domains/share/archive.ts +684 -0
  728. package/src/domains/share/contract.ts +9 -0
  729. package/src/domains/share/extension.ts +26 -0
  730. package/src/domains/share/index.ts +28 -0
  731. package/src/domains/share/manifest.ts +6 -0
  732. package/src/engine/acp/adapter.ts +397 -0
  733. package/src/engine/acp/errors.ts +32 -0
  734. package/src/engine/acp/event-mapper.ts +154 -0
  735. package/src/engine/acp/server.ts +656 -0
  736. package/src/engine/acp/tool-mediator.ts +686 -0
  737. package/src/engine/acp/transport.ts +654 -0
  738. package/src/engine/acp/types.ts +170 -0
  739. package/src/engine/agent.ts +29 -0
  740. package/src/engine/ai.ts +202 -0
  741. package/src/engine/alcf-oauth.ts +198 -0
  742. package/src/engine/antigravity/subprocess-runtime.ts +205 -0
  743. package/src/engine/apis/degraded-inference.ts +95 -0
  744. package/src/engine/apis/index.ts +20 -0
  745. package/src/engine/apis/llamacpp-residency.ts +252 -0
  746. package/src/engine/apis/lmstudio-native.ts +1438 -0
  747. package/src/engine/apis/lmstudio-residency.ts +92 -0
  748. package/src/engine/apis/ollama-native.ts +507 -0
  749. package/src/engine/apis/openai-completions.ts +716 -0
  750. package/src/engine/apis/output-budget.ts +99 -0
  751. package/src/engine/apis/residency-lock.ts +29 -0
  752. package/src/engine/apis/residency.ts +640 -0
  753. package/src/engine/apis/resident-models.ts +42 -0
  754. package/src/engine/apis/sampling-overrides.ts +38 -0
  755. package/src/engine/apis/thinking-replay.ts +11 -0
  756. package/src/engine/claude/sdk-runtime.ts +685 -0
  757. package/src/engine/claude/session-id.ts +5 -0
  758. package/src/engine/claude/subprocess-runtime.ts +316 -0
  759. package/src/engine/claude/tool-safety.ts +400 -0
  760. package/src/engine/external-subprocess.ts +23 -0
  761. package/src/engine/harmony-response.ts +165 -0
  762. package/src/engine/loop-guard.ts +1127 -0
  763. package/src/engine/oauth.ts +192 -0
  764. package/src/engine/pi-mono-names.ts +13 -0
  765. package/src/engine/provider-payload.ts +315 -0
  766. package/src/engine/select-list.ts +53 -0
  767. package/src/engine/session.ts +834 -0
  768. package/src/engine/strip-tokenizer-sentinels.ts +125 -0
  769. package/src/engine/tui.ts +103 -0
  770. package/src/engine/types.ts +66 -0
  771. package/src/engine/worker-events.ts +100 -0
  772. package/src/engine/worker-runtime.ts +1022 -0
  773. package/src/engine/worker-tools.ts +203 -0
  774. package/src/entry/orchestrator.ts +1873 -0
  775. package/src/interactive/application-controller.ts +346 -0
  776. package/src/interactive/bus-notices.ts +265 -0
  777. package/src/interactive/chat-loop-messages.ts +626 -0
  778. package/src/interactive/chat-loop-policy.ts +18 -0
  779. package/src/interactive/chat-loop.ts +865 -0
  780. package/src/interactive/chat-panel.ts +1694 -0
  781. package/src/interactive/chat-renderer.ts +1038 -0
  782. package/src/interactive/clio-editor.ts +166 -0
  783. package/src/interactive/command-fallbacks.ts +23 -0
  784. package/src/interactive/command-output.ts +85 -0
  785. package/src/interactive/context-activity.ts +203 -0
  786. package/src/interactive/context-meter.ts +223 -0
  787. package/src/interactive/context-overlay.ts +220 -0
  788. package/src/interactive/cost-overlay.ts +279 -0
  789. package/src/interactive/dispatch-board.ts +1319 -0
  790. package/src/interactive/dispatch-steering.ts +86 -0
  791. package/src/interactive/editor-bash.ts +46 -0
  792. package/src/interactive/editor-steer.ts +51 -0
  793. package/src/interactive/editor-submit.ts +303 -0
  794. package/src/interactive/external-editor.ts +67 -0
  795. package/src/interactive/follow-up-queue-panel.ts +75 -0
  796. package/src/interactive/footer/dashboard.ts +534 -0
  797. package/src/interactive/footer/notifications.ts +275 -0
  798. package/src/interactive/footer/widgets.ts +1246 -0
  799. package/src/interactive/footer-panel.ts +187 -0
  800. package/src/interactive/format-time.ts +85 -0
  801. package/src/interactive/index.ts +11 -0
  802. package/src/interactive/interactive-application.ts +755 -0
  803. package/src/interactive/interactive-event-projection.ts +380 -0
  804. package/src/interactive/interactive-input-runtime.ts +261 -0
  805. package/src/interactive/interactive-presentation.ts +452 -0
  806. package/src/interactive/interactive-shell.ts +134 -0
  807. package/src/interactive/interactive-slash-runtime.ts +492 -0
  808. package/src/interactive/interactive-subscriptions.ts +111 -0
  809. package/src/interactive/interactive-tickers.ts +152 -0
  810. package/src/interactive/keybinding-manager.ts +496 -0
  811. package/src/interactive/layout.ts +20 -0
  812. package/src/interactive/leader-key.ts +143 -0
  813. package/src/interactive/loop-guard-interrupt.ts +101 -0
  814. package/src/interactive/memory-overlay.ts +280 -0
  815. package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
  816. package/src/interactive/overlay-auth-lifecycle.ts +308 -0
  817. package/src/interactive/overlay-frame.ts +502 -0
  818. package/src/interactive/overlay-general-openers.ts +217 -0
  819. package/src/interactive/overlay-key-routing.ts +213 -0
  820. package/src/interactive/overlay-lifecycle.ts +413 -0
  821. package/src/interactive/overlay-model-selectors.ts +127 -0
  822. package/src/interactive/overlay-permission-lifecycle.ts +344 -0
  823. package/src/interactive/overlay-resource-openers.ts +112 -0
  824. package/src/interactive/overlay-session-lifecycle.ts +270 -0
  825. package/src/interactive/overlay-transitions.ts +57 -0
  826. package/src/interactive/overlays/agents.ts +69 -0
  827. package/src/interactive/overlays/ask-user.ts +921 -0
  828. package/src/interactive/overlays/auth-dialog.ts +221 -0
  829. package/src/interactive/overlays/context-reset.ts +108 -0
  830. package/src/interactive/overlays/cwd-fallback.ts +141 -0
  831. package/src/interactive/overlays/extensions.ts +54 -0
  832. package/src/interactive/overlays/help-reference.ts +140 -0
  833. package/src/interactive/overlays/interop.ts +139 -0
  834. package/src/interactive/overlays/keybinding-detail.ts +90 -0
  835. package/src/interactive/overlays/list-overlay.ts +606 -0
  836. package/src/interactive/overlays/message-picker.ts +155 -0
  837. package/src/interactive/overlays/model-selector.ts +1091 -0
  838. package/src/interactive/overlays/prompts.ts +72 -0
  839. package/src/interactive/overlays/session-selector-search.ts +31 -0
  840. package/src/interactive/overlays/session-selector.ts +266 -0
  841. package/src/interactive/overlays/settings.ts +3363 -0
  842. package/src/interactive/overlays/skills-hub.ts +237 -0
  843. package/src/interactive/overlays/tree-selector.ts +387 -0
  844. package/src/interactive/permission-overlay.ts +170 -0
  845. package/src/interactive/render-trace.ts +125 -0
  846. package/src/interactive/renderers/branch-summary.ts +86 -0
  847. package/src/interactive/renderers/code-ink.ts +420 -0
  848. package/src/interactive/renderers/compaction-summary.ts +112 -0
  849. package/src/interactive/renderers/diff.ts +126 -0
  850. package/src/interactive/renderers/notice.ts +28 -0
  851. package/src/interactive/renderers/retry-status.ts +31 -0
  852. package/src/interactive/renderers/structured.ts +89 -0
  853. package/src/interactive/renderers/tool-execution.ts +1104 -0
  854. package/src/interactive/renderers/worker-entry.ts +264 -0
  855. package/src/interactive/session-last-turn.ts +186 -0
  856. package/src/interactive/session-transcript.ts +105 -0
  857. package/src/interactive/session-usage-reseed.ts +74 -0
  858. package/src/interactive/slash-autocomplete.ts +364 -0
  859. package/src/interactive/slash-commands.ts +1319 -0
  860. package/src/interactive/slash-spec.ts +453 -0
  861. package/src/interactive/status/controller.ts +256 -0
  862. package/src/interactive/status/index.ts +23 -0
  863. package/src/interactive/status/state-machine.ts +530 -0
  864. package/src/interactive/status/summary.ts +170 -0
  865. package/src/interactive/status/types.ts +121 -0
  866. package/src/interactive/status/verbs.ts +163 -0
  867. package/src/interactive/status/watchdog.ts +24 -0
  868. package/src/interactive/tasks-overlay.ts +186 -0
  869. package/src/interactive/theme/components.ts +55 -0
  870. package/src/interactive/theme/glyphs.ts +70 -0
  871. package/src/interactive/theme/index.ts +15 -0
  872. package/src/interactive/theme/labels.ts +88 -0
  873. package/src/interactive/theme/rules.ts +138 -0
  874. package/src/interactive/theme/segments.ts +88 -0
  875. package/src/interactive/theme/tokens.ts +121 -0
  876. package/src/interactive/thinking-level-policy.ts +6 -0
  877. package/src/interactive/tool-prose-loop.ts +122 -0
  878. package/src/interactive/tool-prose-registration.ts +48 -0
  879. package/src/interactive/turn-context.ts +854 -0
  880. package/src/interactive/turn-middleware.ts +283 -0
  881. package/src/interactive/turn-persistence.ts +441 -0
  882. package/src/interactive/turn-queues.ts +169 -0
  883. package/src/interactive/turn-recovery.ts +306 -0
  884. package/src/interactive/turn-runtime.ts +802 -0
  885. package/src/interactive/turn-state.ts +123 -0
  886. package/src/interactive/view/artifacts.ts +1342 -0
  887. package/src/interactive/view/view-overlay.ts +732 -0
  888. package/src/interactive/welcome-dashboard.ts +536 -0
  889. package/src/interactive/worker-receipts.ts +94 -0
  890. package/src/interactive/worker-replay.ts +111 -0
  891. package/src/interactive/worker-share.ts +100 -0
  892. package/src/interactive/worker-stream.ts +442 -0
  893. package/src/interactive/workspace-facts.ts +141 -0
  894. package/src/tools/agent-tools.ts +382 -0
  895. package/src/tools/artifact.ts +103 -0
  896. package/src/tools/ask-user.ts +656 -0
  897. package/src/tools/bash.ts +176 -0
  898. package/src/tools/bootstrap.ts +474 -0
  899. package/src/tools/codewiki/code-nav.ts +563 -0
  900. package/src/tools/codewiki/shared.ts +115 -0
  901. package/src/tools/compete-worktrees.ts +898 -0
  902. package/src/tools/context/docs-engine.ts +619 -0
  903. package/src/tools/context/index.ts +435 -0
  904. package/src/tools/credential-present.ts +151 -0
  905. package/src/tools/dispatch-arguments.ts +228 -0
  906. package/src/tools/dispatch-plan.ts +741 -0
  907. package/src/tools/dispatch-scout.ts +461 -0
  908. package/src/tools/dispatch.ts +3338 -0
  909. package/src/tools/edit-diff.ts +534 -0
  910. package/src/tools/edit.ts +128 -0
  911. package/src/tools/executables.ts +22 -0
  912. package/src/tools/file-mutation-queue.ts +35 -0
  913. package/src/tools/find.ts +292 -0
  914. package/src/tools/grep.ts +495 -0
  915. package/src/tools/ignore-policy.ts +169 -0
  916. package/src/tools/ledger.ts +206 -0
  917. package/src/tools/ls.ts +110 -0
  918. package/src/tools/monitor.ts +797 -0
  919. package/src/tools/network-policy.ts +29 -0
  920. package/src/tools/observation.ts +421 -0
  921. package/src/tools/observers.ts +99 -0
  922. package/src/tools/path-utils.ts +79 -0
  923. package/src/tools/policy.ts +154 -0
  924. package/src/tools/profiles.ts +108 -0
  925. package/src/tools/read.ts +173 -0
  926. package/src/tools/registry.ts +1157 -0
  927. package/src/tools/result-shaping.ts +204 -0
  928. package/src/tools/safe-exec.ts +128 -0
  929. package/src/tools/spawn-hygiene.ts +182 -0
  930. package/src/tools/steer.ts +88 -0
  931. package/src/tools/string-enum.ts +15 -0
  932. package/src/tools/tasks.ts +168 -0
  933. package/src/tools/truncate-utf8.ts +17 -0
  934. package/src/tools/truncate.ts +202 -0
  935. package/src/tools/verify/frontend.ts +685 -0
  936. package/src/tools/verify/index.ts +66 -0
  937. package/src/tools/verify/scripts.ts +108 -0
  938. package/src/tools/web-fetch.ts +777 -0
  939. package/src/tools/worker-evidence.ts +215 -0
  940. package/src/tools/write.ts +52 -0
  941. package/src/utils/exif-orientation.ts +192 -0
  942. package/src/utils/git.ts +24 -0
  943. package/src/utils/image-resize.ts +148 -0
  944. package/src/utils/photon.ts +103 -0
  945. package/src/worker/control-lane.ts +22 -0
  946. package/src/worker/entry.ts +257 -0
  947. package/src/worker/event-projection.ts +56 -0
  948. package/src/worker/heartbeat.ts +24 -0
  949. package/src/worker/ledger-mirror.ts +95 -0
  950. package/src/worker/ndjson.ts +40 -0
  951. package/src/worker/protocol.ts +529 -0
  952. package/src/worker/resource-facts.ts +79 -0
  953. package/src/worker/runtime-registry.ts +12 -0
  954. package/src/worker/spec-contract.ts +654 -0
  955. package/src/worker/stdin-demux.ts +316 -0
  956. package/dist/acp-UMLFVA3F.js +0 -92
  957. package/dist/chunk-262G75JS.js +0 -35
  958. package/dist/chunk-5LDRNKX2.js +0 -1063
  959. package/dist/chunk-67MTHP2E.js +0 -135
  960. package/dist/chunk-GOTUR54M.js +0 -9
  961. package/dist/chunk-TPOCL34A.js +0 -2876
  962. package/dist/chunk-XV4ZJ6ZM.js +0 -3177
  963. package/dist/clio-KIQ5SNDS.js +0 -53
  964. package/dist/configure-G4E3A2PG.js +0 -27
  965. package/dist/doctor-M5HJJZOL.js +0 -61
  966. package/dist/domains/agents/builtins/architect.md +0 -33
  967. package/dist/domains/agents/builtins/coder.md +0 -31
  968. package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
  969. package/dist/domains/agents/builtins/debugger.md +0 -30
  970. package/dist/domains/agents/builtins/documenter.md +0 -31
  971. package/dist/domains/agents/builtins/git-master.md +0 -30
  972. package/dist/domains/agents/builtins/provenance.md +0 -30
  973. package/dist/domains/agents/builtins/researcher.md +0 -71
  974. package/dist/domains/agents/builtins/scout.md +0 -42
  975. package/dist/domains/agents/builtins/tester.md +0 -31
  976. package/dist/domains/agents/builtins/verifier.md +0 -30
  977. package/dist/domains/agents/builtins/wiki-writer.md +0 -41
  978. package/dist/fleet-preflight-CLIAX7YR.js +0 -21
  979. package/dist/preload-KZVHET2B.js +0 -11
  980. package/dist/version-ROZ6CZKH.js +0 -16
  981. package/skills/git/commit-crafting/SKILL.md +0 -79
  982. package/skills/git/commit-crafting/evals.md +0 -92
  983. package/skills/git/create-pr/SKILL.md +0 -116
  984. package/skills/git/create-pr/evals.md +0 -114
  985. package/skills/git/investigate-issue/SKILL.md +0 -139
  986. package/skills/git/investigate-issue/evals.md +0 -94
  987. package/skills/git/review-changes/SKILL.md +0 -103
  988. package/skills/git/review-changes/evals.md +0 -85
@@ -0,0 +1,1614 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { readFile as readFileAsync } from "node:fs/promises";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
+ import { classifyCHeaderLanguage, isAmbiguousHeaderPath } from "../../../core/c-header-language.js";
6
+ import { safeResourceWrite } from "../../../core/safe-resource-write.js";
7
+ import { enumerateWorkspaceFilesAsync, filterWorkspaceFileCandidates } from "../../../core/workspace-files.js";
8
+ import type { ProjectType, SourceProjectType } from "../../session/workspace/project-type.js";
9
+ import { EXCLUDED_DIRS } from "../excluded-dirs.js";
10
+ import { extractCMake, isCMakePath } from "./cmake.js";
11
+ import { type CooperativeSlicer, createSlicer } from "./cooperative.js";
12
+ import { createTreeSitterExtractor, type TreeSitterExtractor } from "./tree-sitter.js";
13
+
14
+ export type CodewikiLanguage = SourceProjectType | "config";
15
+ export type CodewikiFileRole = "entry" | "test" | "module" | "config";
16
+ export type CodewikiSymbolKind = "func" | "class" | "method" | "type" | "const" | "var" | "trait" | "iface";
17
+ const CODEWIKI_SYMBOL_KINDS_WITH_SIG = new Set<CodewikiSymbolKind>(["func", "class", "method", "type"]);
18
+
19
+ export interface CodewikiFile {
20
+ id: string;
21
+ path: string;
22
+ lang: CodewikiLanguage;
23
+ loc: number;
24
+ role: CodewikiFileRole;
25
+ hash: string;
26
+ imports: string[];
27
+ summary?: string;
28
+ }
29
+
30
+ export interface CodewikiSymbol {
31
+ name: string;
32
+ kind: CodewikiSymbolKind;
33
+ fileId: string;
34
+ line: number;
35
+ sig?: string;
36
+ }
37
+
38
+ export interface CodewikiInternalEdge {
39
+ fileId: string;
40
+ toFileId: string;
41
+ }
42
+
43
+ export interface CodewikiExternalEdge {
44
+ fileId: string;
45
+ externalModule: string;
46
+ }
47
+
48
+ export type CodewikiEdge = CodewikiInternalEdge | CodewikiExternalEdge;
49
+
50
+ export const CODEWIKI_VERSION = 5 as const;
51
+
52
+ export interface Codewiki {
53
+ version: typeof CODEWIKI_VERSION;
54
+ language: ProjectType;
55
+ files: CodewikiFile[];
56
+ symbols: CodewikiSymbol[];
57
+ edges: CodewikiEdge[];
58
+ }
59
+
60
+ export interface CodewikiEntry {
61
+ path: string;
62
+ exports: string[];
63
+ imports: string[];
64
+ kind: "entry-point" | "test" | "module";
65
+ summary?: string;
66
+ }
67
+
68
+ export interface BuildCodewikiInput {
69
+ cwd: string;
70
+ language: ProjectType;
71
+ generatedAt?: string;
72
+ }
73
+
74
+ export type CodewikiReadFile = (path: string) => string | null;
75
+
76
+ export interface CodewikiBuildOptions {
77
+ readFile?: CodewikiReadFile;
78
+ /**
79
+ * Slice budget shared across a whole index run. Callers that chain several
80
+ * phases pass one slicer so the budget applies end to end rather than
81
+ * resetting at each phase boundary. Defaults to a fresh slicer.
82
+ */
83
+ slicer?: CooperativeSlicer;
84
+ }
85
+
86
+ export interface ExtractedSymbol {
87
+ name: string;
88
+ kind: CodewikiSymbolKind;
89
+ line: number;
90
+ sig?: string;
91
+ }
92
+
93
+ export interface LanguageExtraction {
94
+ symbols: ExtractedSymbol[];
95
+ imports: string[];
96
+ }
97
+
98
+ export interface LanguageExtractor {
99
+ langs: ReadonlyArray<CodewikiLanguage>;
100
+ extractImports?(path: string, text: string): string[];
101
+ extract(path: string, text: string): LanguageExtraction;
102
+ }
103
+
104
+ let treeSitterExtractorPromise: Promise<TreeSitterExtractor> | null = null;
105
+
106
+ function loadTreeSitterExtractor(): Promise<TreeSitterExtractor> {
107
+ treeSitterExtractorPromise ??= createTreeSitterExtractor();
108
+ return treeSitterExtractorPromise;
109
+ }
110
+
111
+ const SOURCE_EXTENSIONS = new Map<string, SourceProjectType>([
112
+ [".ts", "typescript"],
113
+ [".tsx", "typescript"],
114
+ [".mts", "typescript"],
115
+ [".cts", "typescript"],
116
+ [".js", "javascript"],
117
+ [".jsx", "javascript"],
118
+ [".mjs", "javascript"],
119
+ [".cjs", "javascript"],
120
+ [".py", "python"],
121
+ [".pyw", "python"],
122
+ [".rs", "rust"],
123
+ [".go", "go"],
124
+ [".c", "c"],
125
+ [".h", "c"],
126
+ [".cc", "c++"],
127
+ [".cpp", "c++"],
128
+ [".cxx", "c++"],
129
+ [".hpp", "c++"],
130
+ [".hh", "c++"],
131
+ [".hxx", "c++"],
132
+ [".cu", "c++"],
133
+ [".cuh", "c++"],
134
+ [".java", "java"],
135
+ [".rb", "ruby"],
136
+ [".cs", "c#"],
137
+ ]);
138
+
139
+ const CONFIG_FILE_NAMES = new Set([
140
+ "package.json",
141
+ "pyproject.toml",
142
+ "setup.py",
143
+ "Cargo.toml",
144
+ "go.mod",
145
+ "pom.xml",
146
+ "CMakeLists.txt",
147
+ "compile_commands.json",
148
+ "Gemfile",
149
+ ]);
150
+
151
+ const RESOLUTION_EXTENSIONS = [
152
+ ".ts",
153
+ ".tsx",
154
+ ".mts",
155
+ ".cts",
156
+ ".js",
157
+ ".jsx",
158
+ ".mjs",
159
+ ".cjs",
160
+ ".py",
161
+ ".go",
162
+ ".rs",
163
+ ".c",
164
+ ".h",
165
+ ".cc",
166
+ ".cpp",
167
+ ".cxx",
168
+ ".hpp",
169
+ ".hh",
170
+ ".hxx",
171
+ ".cu",
172
+ ".cuh",
173
+ ".java",
174
+ ".rb",
175
+ ".cs",
176
+ ];
177
+
178
+ function compareStrings(a: string, b: string): number {
179
+ return a.localeCompare(b);
180
+ }
181
+
182
+ function stableFileId(path: string): string {
183
+ return `f_${createHash("sha256").update(path).digest("hex").slice(0, 16)}`;
184
+ }
185
+
186
+ function contentHash(text: string): string {
187
+ return createHash("sha256").update(text).digest("hex").slice(0, 16);
188
+ }
189
+
190
+ function defaultReadFile(path: string): string | null {
191
+ try {
192
+ return readFileSync(path, "utf8");
193
+ } catch {
194
+ return null;
195
+ }
196
+ }
197
+
198
+ function extensionOf(name: string): string {
199
+ const index = name.lastIndexOf(".");
200
+ return index === -1 ? "" : name.slice(index);
201
+ }
202
+
203
+ function normalizeRel(cwd: string, filePath: string): string {
204
+ return relative(cwd, filePath).split("\\").join("/");
205
+ }
206
+
207
+ function normalizeInputPath(path: string): string {
208
+ return path.split("\\").join("/").replace(/^\.\//, "");
209
+ }
210
+
211
+ function sourceLanguageForPath(relPath: string): SourceProjectType | null {
212
+ if (relPath.endsWith(".d.ts")) return null;
213
+ return SOURCE_EXTENSIONS.get(extensionOf(relPath)) ?? null;
214
+ }
215
+
216
+ function languageForPath(relPath: string): CodewikiLanguage | null {
217
+ const source = sourceLanguageForPath(relPath);
218
+ if (source) return source;
219
+ const name = relPath.split("/").pop() ?? relPath;
220
+ return CONFIG_FILE_NAMES.has(name) || name.endsWith(".csproj") || name.toLowerCase().endsWith(".cmake")
221
+ ? "config"
222
+ : null;
223
+ }
224
+
225
+ export function isIndexablePath(relPath: string): boolean {
226
+ if (relPath.split("/").some((segment) => EXCLUDED_DIRS.has(segment))) return false;
227
+ return languageForPath(relPath) !== null;
228
+ }
229
+
230
+ function lineCount(text: string): number {
231
+ if (text.length === 0) return 0;
232
+ return text.endsWith("\n") ? text.split("\n").length - 1 : text.split("\n").length;
233
+ }
234
+
235
+ function roleFor(relPath: string, language: CodewikiLanguage): CodewikiFileRole {
236
+ if (language === "config") return "config";
237
+ const lower = relPath.toLowerCase();
238
+ if (
239
+ lower.includes("/test/") ||
240
+ lower.includes("/tests/") ||
241
+ /\.(test|spec)\.[cm]?[jt]sx?$/.test(lower) ||
242
+ /(^|\/)test_.*\.py$/.test(lower) ||
243
+ /(^|\/).*_test\.(go|rs|rb)$/.test(lower)
244
+ ) {
245
+ return "test";
246
+ }
247
+ if (/(^|\/)(index|main|server|cli|orchestrator|bootstrap)\.[^.]+$/.test(lower) || lower.endsWith("/__main__.py")) {
248
+ return "entry";
249
+ }
250
+ return "module";
251
+ }
252
+
253
+ function firstDocSummary(text: string): string | null {
254
+ const jsDoc = /\/\*\*([\s\S]*?)\*\//.exec(text)?.[1];
255
+ const pythonDoc = /^\s*(?:"""([\s\S]*?)"""|'''([\s\S]*?)''')/.exec(text);
256
+ const raw = jsDoc ?? pythonDoc?.[1] ?? pythonDoc?.[2];
257
+ if (!raw) return null;
258
+ const cleaned = raw
259
+ .split("\n")
260
+ .map((line) => line.replace(/^\s*\*\s?/, "").trim())
261
+ .filter((line) => line.length > 0 && !line.startsWith("@"))
262
+ .join(" ")
263
+ .replace(/\s+/g, " ")
264
+ .trim();
265
+ return cleaned.length > 0 ? cleaned.slice(0, 160) : null;
266
+ }
267
+
268
+ function sanitizeSymbolName(value: string): string {
269
+ return value
270
+ .trim()
271
+ .replace(/^self\./, "")
272
+ .replace(/^this\./, "")
273
+ .slice(0, 160);
274
+ }
275
+
276
+ function addSymbol(
277
+ target: ExtractedSymbol[],
278
+ seen: Set<string>,
279
+ name: string | undefined,
280
+ kind: CodewikiSymbolKind,
281
+ line: number,
282
+ sig?: string,
283
+ ): void {
284
+ if (!name) return;
285
+ const clean = sanitizeSymbolName(name);
286
+ if (clean.length === 0) return;
287
+ const key = `${clean}\0${kind}\0${line}`;
288
+ if (seen.has(key)) return;
289
+ seen.add(key);
290
+ target.push({
291
+ name: clean,
292
+ kind,
293
+ line,
294
+ ...(sig && sig.trim().length > 0 ? { sig: sig.trim().slice(0, 240) } : {}),
295
+ });
296
+ }
297
+
298
+ function uniqueSorted(values: Iterable<string>): string[] {
299
+ return [...new Set([...values].filter((item) => item.length > 0))].sort(compareStrings);
300
+ }
301
+
302
+ function extractWithLineRegex(
303
+ text: string,
304
+ patterns: ReadonlyArray<{ regex: RegExp; kind: CodewikiSymbolKind; nameIndex?: number }>,
305
+ ): ExtractedSymbol[] {
306
+ const symbols: ExtractedSymbol[] = [];
307
+ const seen = new Set<string>();
308
+ const lines = text.split(/\r?\n/);
309
+ for (const [index, line] of lines.entries()) {
310
+ for (const pattern of patterns) {
311
+ const match = pattern.regex.exec(line);
312
+ if (!match) continue;
313
+ const name = match[pattern.nameIndex ?? 1];
314
+ addSymbol(symbols, seen, name, pattern.kind, index + 1, line.trim());
315
+ }
316
+ }
317
+ return symbols.sort(compareSymbols);
318
+ }
319
+
320
+ function compareSymbols(
321
+ a: Pick<CodewikiSymbol, "name" | "kind" | "line">,
322
+ b: Pick<CodewikiSymbol, "name" | "kind" | "line">,
323
+ ): number {
324
+ return a.line - b.line || a.name.localeCompare(b.name) || a.kind.localeCompare(b.kind);
325
+ }
326
+
327
+ function extractMatches(text: string, regex: RegExp, group = 1): string[] {
328
+ const out: string[] = [];
329
+ for (const match of text.matchAll(regex)) {
330
+ const value = match[group];
331
+ if (value) out.push(value);
332
+ }
333
+ return out;
334
+ }
335
+
336
+ interface CFamilyAliasStatement {
337
+ text: string;
338
+ masked: string;
339
+ line: number;
340
+ }
341
+
342
+ function maskCFamilyCommentsAndStrings(text: string): string {
343
+ // split("") preserves UTF-16 offsets so slices of the masked text line up
344
+ // exactly with slices of the original source, including astral characters.
345
+ const chars = text.split("");
346
+ let state: "code" | "line-comment" | "block-comment" | "single-quote" | "double-quote" = "code";
347
+ for (let index = 0; index < chars.length; index += 1) {
348
+ const current = chars[index] ?? "";
349
+ const next = chars[index + 1] ?? "";
350
+ if (state === "code") {
351
+ if (current === "/" && next === "/") {
352
+ chars[index] = " ";
353
+ chars[index + 1] = " ";
354
+ state = "line-comment";
355
+ index += 1;
356
+ } else if (current === "/" && next === "*") {
357
+ chars[index] = " ";
358
+ chars[index + 1] = " ";
359
+ state = "block-comment";
360
+ index += 1;
361
+ } else if (current === "'") {
362
+ chars[index] = " ";
363
+ state = "single-quote";
364
+ } else if (current === '"') {
365
+ chars[index] = " ";
366
+ state = "double-quote";
367
+ }
368
+ continue;
369
+ }
370
+ if (current === "\n") {
371
+ if (state === "line-comment") state = "code";
372
+ continue;
373
+ }
374
+ chars[index] = " ";
375
+ if (state === "block-comment" && current === "*" && next === "/") {
376
+ chars[index + 1] = " ";
377
+ state = "code";
378
+ index += 1;
379
+ continue;
380
+ }
381
+ if ((state === "single-quote" || state === "double-quote") && current === "\\") {
382
+ if (index + 1 < chars.length && chars[index + 1] !== "\n") {
383
+ chars[index + 1] = " ";
384
+ index += 1;
385
+ }
386
+ continue;
387
+ }
388
+ if (state === "single-quote" && current === "'") state = "code";
389
+ if (state === "double-quote" && current === '"') state = "code";
390
+ }
391
+ return chars.join("");
392
+ }
393
+
394
+ function cFamilyAliasStatements(text: string): CFamilyAliasStatement[] {
395
+ const masked = maskCFamilyCommentsAndStrings(text);
396
+ const statements: CFamilyAliasStatement[] = [];
397
+ const token = /\b(?:typedef|using)\b/g;
398
+ for (let match = token.exec(masked); match; match = token.exec(masked)) {
399
+ const start = match.index;
400
+ const lineStart = masked.lastIndexOf("\n", start - 1) + 1;
401
+ if (masked.slice(lineStart, start).trimStart().startsWith("#")) continue;
402
+ let braces = 0;
403
+ let parentheses = 0;
404
+ let brackets = 0;
405
+ let end = -1;
406
+ for (let index = token.lastIndex; index < masked.length; index += 1) {
407
+ const current = masked[index];
408
+ if (current === "{") braces += 1;
409
+ else if (current === "}") braces = Math.max(0, braces - 1);
410
+ else if (current === "(") parentheses += 1;
411
+ else if (current === ")") parentheses = Math.max(0, parentheses - 1);
412
+ else if (current === "[") brackets += 1;
413
+ else if (current === "]") brackets = Math.max(0, brackets - 1);
414
+ else if (current === ";" && braces === 0 && parentheses === 0 && brackets === 0) {
415
+ end = index + 1;
416
+ break;
417
+ }
418
+ }
419
+ if (end === -1) continue;
420
+ statements.push({
421
+ text: text.slice(start, end),
422
+ masked: masked.slice(start, end),
423
+ line: 1 + Array.from(masked.slice(0, start).matchAll(/\n/g)).length,
424
+ });
425
+ token.lastIndex = end;
426
+ }
427
+ return statements;
428
+ }
429
+
430
+ function stripCFamilyBraceBodies(statement: string): string {
431
+ let depth = 0;
432
+ let result = "";
433
+ for (const current of statement) {
434
+ if (current === "{") {
435
+ depth += 1;
436
+ result += " ";
437
+ continue;
438
+ }
439
+ if (current === "}") {
440
+ depth = Math.max(0, depth - 1);
441
+ result += " ";
442
+ continue;
443
+ }
444
+ result += depth === 0 || current === "\n" ? current : " ";
445
+ }
446
+ return result;
447
+ }
448
+
449
+ function splitCFamilyDeclarators(value: string): string[] {
450
+ const parts: string[] = [];
451
+ let start = 0;
452
+ let parentheses = 0;
453
+ let brackets = 0;
454
+ let angles = 0;
455
+ for (let index = 0; index < value.length; index += 1) {
456
+ const current = value[index];
457
+ if (current === "(") parentheses += 1;
458
+ else if (current === ")") parentheses = Math.max(0, parentheses - 1);
459
+ else if (current === "[") brackets += 1;
460
+ else if (current === "]") brackets = Math.max(0, brackets - 1);
461
+ else if (current === "<") angles += 1;
462
+ else if (current === ">") angles = Math.max(0, angles - 1);
463
+ else if (current === "," && parentheses === 0 && brackets === 0 && angles === 0) {
464
+ parts.push(value.slice(start, index));
465
+ start = index + 1;
466
+ }
467
+ }
468
+ parts.push(value.slice(start));
469
+ return parts;
470
+ }
471
+
472
+ const C_FAMILY_TYPE_WORDS = new Set([
473
+ "typedef",
474
+ "const",
475
+ "volatile",
476
+ "restrict",
477
+ "signed",
478
+ "unsigned",
479
+ "short",
480
+ "long",
481
+ "void",
482
+ "char",
483
+ "int",
484
+ "float",
485
+ "double",
486
+ "struct",
487
+ "union",
488
+ "enum",
489
+ "class",
490
+ "typename",
491
+ "auto",
492
+ ]);
493
+
494
+ function stripTrailingCFamilyDeclaratorSuffixes(value: string): string {
495
+ let end = value.length;
496
+ while (end > 0) {
497
+ while (end > 0 && /\s/.test(value[end - 1] ?? "")) end -= 1;
498
+ const close = value[end - 1];
499
+ if (close !== ")" && close !== "]") break;
500
+ const open = close === ")" ? "(" : "[";
501
+ let depth = 1;
502
+ let start = end - 1;
503
+ for (start -= 1; start >= 0; start -= 1) {
504
+ const current = value[start];
505
+ if (current === close) depth += 1;
506
+ else if (current === open) {
507
+ depth -= 1;
508
+ if (depth === 0) break;
509
+ }
510
+ }
511
+ if (start < 0) break;
512
+ // A suffix follows an identifier, another completed declarator group, or
513
+ // an array. A standalone `(Alias)` is a wrapper around the name itself and
514
+ // must remain available to the identifier search below. Requiring direct
515
+ // adjacency is what distinguishes `callable_t(...)` from `int (Wrapped)`.
516
+ if (start === 0 || !/[A-Za-z_0-9)\]]/.test(value[start - 1] ?? "")) break;
517
+ end = start;
518
+ }
519
+ return value.slice(0, end);
520
+ }
521
+
522
+ function cFamilyTypedefNames(maskedStatement: string): string[] {
523
+ const withoutBodies = stripCFamilyBraceBodies(maskedStatement)
524
+ .replace(/^\s*typedef\b/, "")
525
+ .replace(/;\s*$/, "");
526
+ const names: string[] = [];
527
+ for (const declarator of splitCFamilyDeclarators(withoutBodies)) {
528
+ const functionPointerNames = Array.from(
529
+ declarator.matchAll(
530
+ /\(\s*(?:[A-Za-z_]\w*\s+)*[*&]+\s*(?:(?:const|volatile|restrict)\s+)*([A-Za-z_]\w*)\s*(?:\[[^\]]*\]\s*)*\)(?=\s*\()/g,
531
+ ),
532
+ (match) => match[1] ?? "",
533
+ ).filter((name) => name.length > 0);
534
+ if (functionPointerNames.length > 0) {
535
+ names.push(...functionPointerNames);
536
+ continue;
537
+ }
538
+ const declaratorWithoutSuffixes = stripTrailingCFamilyDeclaratorSuffixes(declarator);
539
+ const identifiers = Array.from(declaratorWithoutSuffixes.matchAll(/\b[A-Za-z_]\w*\b/g), (match) => match[0]).filter(
540
+ (name) => !C_FAMILY_TYPE_WORDS.has(name),
541
+ );
542
+ const name = identifiers.at(-1);
543
+ if (name) names.push(name);
544
+ }
545
+ return uniqueSorted(names);
546
+ }
547
+
548
+ function extractCFamilyAliasSymbols(text: string): ExtractedSymbol[] {
549
+ const symbols: ExtractedSymbol[] = [];
550
+ const seen = new Set<string>();
551
+ for (const statement of cFamilyAliasStatements(text)) {
552
+ const usingName = /^\s*using\s+([A-Za-z_]\w*)\s*=/.exec(statement.masked)?.[1];
553
+ const names = usingName
554
+ ? [usingName]
555
+ : /^\s*typedef\b/.test(statement.masked)
556
+ ? cFamilyTypedefNames(statement.masked)
557
+ : [];
558
+ const signature = statement.text.replace(/\s+/g, " ").trim();
559
+ for (const name of names) addSymbol(symbols, seen, name, "type", statement.line, signature);
560
+ }
561
+ return symbols;
562
+ }
563
+
564
+ const tsJsExtractor: LanguageExtractor = {
565
+ langs: ["typescript", "javascript"],
566
+ extractImports(_path, text) {
567
+ return uniqueSorted([
568
+ ...extractMatches(text, /\bimport\s+(?:type\s+)?(?:[^'"]*?\s+from\s+)?["']([^"']+)["']/g),
569
+ ...extractMatches(text, /\bexport\s+[^'"]*?\s+from\s+["']([^"']+)["']/g),
570
+ ...extractMatches(text, /\brequire\s*\(\s*["']([^"']+)["']\s*\)/g),
571
+ ...extractMatches(text, /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g),
572
+ ]);
573
+ },
574
+ extract(_path, text) {
575
+ const symbols = extractWithLineRegex(text, [
576
+ { regex: /^\s*export\s+default\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)?/, kind: "func" },
577
+ { regex: /^\s*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/, kind: "func" },
578
+ { regex: /^\s*(?:export\s+)?class\s+([A-Za-z_$][\w$]*)\b/, kind: "class" },
579
+ { regex: /^\s*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)\b/, kind: "iface" },
580
+ { regex: /^\s*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)\b/, kind: "type" },
581
+ { regex: /^\s*(?:export\s+)?enum\s+([A-Za-z_$][\w$]*)\b/, kind: "type" },
582
+ { regex: /^(?:\s*export\s+)?const\s+([A-Za-z_$][\w$]*)\b/, kind: "const" },
583
+ { regex: /^(?:\s*export\s+)?(?:let|var)\s+([A-Za-z_$][\w$]*)\b/, kind: "var" },
584
+ {
585
+ regex:
586
+ /^(?: {2,}|\t+)(?:public\s+|private\s+|protected\s+|static\s+|override\s+|abstract\s+|async\s+|get\s+|set\s+)*(?!(?:if|for|while|switch|catch|return|typeof|else|do|new|await|yield)\b)([A-Za-z_$][\w$]*)\s*\([^)]*\)\s*\{?$/,
587
+ kind: "method",
588
+ },
589
+ ]);
590
+ return { symbols, imports: tsJsExtractor.extractImports?.(_path, text) ?? [] };
591
+ },
592
+ };
593
+
594
+ const pythonExtractor: LanguageExtractor = {
595
+ langs: ["python"],
596
+ extractImports(_path, text) {
597
+ return uniqueSorted([
598
+ ...extractMatches(text, /^\s*import\s+([A-Za-z_][\w.]*)(?:\s+as\s+\w+)?/gm),
599
+ ...extractMatches(text, /^\s*from\s+([.\w]+)\s+import\s+/gm),
600
+ ]);
601
+ },
602
+ extract(_path, text) {
603
+ const rawSymbols = extractWithLineRegex(text, [
604
+ { regex: /^(\s*)def\s+([A-Za-z_]\w*)\s*\(/, kind: "func", nameIndex: 2 },
605
+ { regex: /^(\s*)async\s+def\s+([A-Za-z_]\w*)\s*\(/, kind: "func", nameIndex: 2 },
606
+ { regex: /^\s*class\s+([A-Za-z_]\w*)\b/, kind: "class" },
607
+ { regex: /^([A-Z][A-Z0-9_]*)\s*=/, kind: "const" },
608
+ { regex: /^([A-Za-z_]\w*)\s*=/, kind: "var" },
609
+ ]);
610
+ const symbols: ExtractedSymbol[] = rawSymbols.map((symbol) => {
611
+ if ((symbol.kind === "func" || symbol.kind === "var") && /^\s+/.test(symbol.sig ?? "")) {
612
+ return { ...symbol, kind: symbol.kind === "func" ? "method" : symbol.kind };
613
+ }
614
+ return symbol;
615
+ });
616
+ return { symbols: symbols.sort(compareSymbols), imports: pythonExtractor.extractImports?.(_path, text) ?? [] };
617
+ },
618
+ };
619
+
620
+ const goExtractor: LanguageExtractor = {
621
+ langs: ["go"],
622
+ extractImports(_path, text) {
623
+ return uniqueSorted([
624
+ ...extractMatches(text, /^\s*import\s+"([^"]+)"/gm),
625
+ ...extractMatches(text, /^\s*"([^"]+)"\s*$/gm),
626
+ ]);
627
+ },
628
+ extract(_path, text) {
629
+ const rawSymbols = extractWithLineRegex(text, [
630
+ { regex: /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)\s*\(/, kind: "func" },
631
+ { regex: /^\s*type\s+([A-Za-z_]\w*)\s+interface\b/, kind: "iface" },
632
+ { regex: /^\s*type\s+([A-Za-z_]\w*)\s+struct\b/, kind: "type" },
633
+ { regex: /^\s*type\s+([A-Za-z_]\w*)\b/, kind: "type" },
634
+ { regex: /^const\s+([A-Za-z_]\w*)\b/, kind: "const" },
635
+ { regex: /^var\s+([A-Za-z_]\w*)\b/, kind: "var" },
636
+ ]);
637
+ const symbols: ExtractedSymbol[] = rawSymbols.map((symbol) => {
638
+ if (symbol.kind === "func" && /^\s*func\s+\(/.test(symbol.sig ?? "")) return { ...symbol, kind: "method" };
639
+ return symbol;
640
+ });
641
+ return { symbols: symbols.sort(compareSymbols), imports: goExtractor.extractImports?.(_path, text) ?? [] };
642
+ },
643
+ };
644
+
645
+ const rustExtractor: LanguageExtractor = {
646
+ langs: ["rust"],
647
+ extractImports(_path, text) {
648
+ return uniqueSorted([
649
+ ...extractMatches(text, /^\s*use\s+([^;]+);/gm).map((item) => item.trim()),
650
+ ...extractMatches(text, /^\s*extern\s+crate\s+([A-Za-z_]\w*)/gm),
651
+ ]);
652
+ },
653
+ extract(_path, text) {
654
+ const symbols = extractWithLineRegex(text, [
655
+ { regex: /^\s*(?:pub(?:\([^)]*\))?\s+)?fn\s+([A-Za-z_]\w*)\s*[<(]/, kind: "func" },
656
+ { regex: /^\s*(?:pub(?:\([^)]*\))?\s+)?struct\s+([A-Za-z_]\w*)\b/, kind: "type" },
657
+ { regex: /^\s*(?:pub(?:\([^)]*\))?\s+)?enum\s+([A-Za-z_]\w*)\b/, kind: "type" },
658
+ { regex: /^\s*(?:pub(?:\([^)]*\))?\s+)?trait\s+([A-Za-z_]\w*)\b/, kind: "trait" },
659
+ { regex: /^\s*(?:pub(?:\([^)]*\))?\s+)?type\s+([A-Za-z_]\w*)\b/, kind: "type" },
660
+ { regex: /^(?:\s*pub(?:\([^)]*\))?\s+)?const\s+([A-Za-z_]\w*)\b/, kind: "const" },
661
+ { regex: /^(?:\s*pub(?:\([^)]*\))?\s+)?static\s+([A-Za-z_]\w*)\b/, kind: "var" },
662
+ ]);
663
+ return { symbols, imports: rustExtractor.extractImports?.(_path, text) ?? [] };
664
+ },
665
+ };
666
+
667
+ const cFamilyExtractor: LanguageExtractor = {
668
+ langs: ["c", "c++"],
669
+ extractImports(_path, text) {
670
+ const imports: string[] = [];
671
+ for (const match of text.matchAll(/^\s*#\s*include\s*(?:"([^"]+)"|<([^>]+)>)/gm)) {
672
+ const quoted = match[1];
673
+ const system = match[2];
674
+ if (quoted) imports.push(quoted.startsWith(".") || quoted.startsWith("/") ? quoted : `./${quoted}`);
675
+ else if (system) imports.push(system);
676
+ }
677
+ return uniqueSorted(imports);
678
+ },
679
+ extract(_path, text) {
680
+ const regexSymbols = extractWithLineRegex(text, [
681
+ { regex: /^\s*class\s+([A-Za-z_]\w*)\b/, kind: "class" },
682
+ {
683
+ regex: /^\s*(?:typedef\s+)?(?:struct\s+|union\s+|enum\s+(?:(?:class|struct)\s+)?)([A-Za-z_]\w*)\b/,
684
+ kind: "type",
685
+ },
686
+ {
687
+ regex:
688
+ /^\s*(?!(?:typedef|using)\b)(?:template\s*<[^>]+>\s*)?(?:[A-Za-z_][\w:<>,*&\s]+\s+)+(?:(?:[A-Za-z_]\w*)::)*([~A-Za-z_]\w*)\s*\([^;]*\)\s*(?:const\s*)?(?:noexcept\s*)?(?:;|\{)?$/,
689
+ kind: "func",
690
+ },
691
+ { regex: /^(?:const\s+)?[A-Za-z_][\w:<>,*&\s]+\s+([A-Z][A-Z0-9_]*)\s*=/, kind: "const" },
692
+ ]);
693
+ const symbolsByKey = new Map<string, ExtractedSymbol>();
694
+ for (const symbol of [...regexSymbols, ...extractCFamilyAliasSymbols(text)]) {
695
+ const key = `${symbol.name}\0${symbol.kind}\0${symbol.line}`;
696
+ if (!symbolsByKey.has(key)) symbolsByKey.set(key, symbol);
697
+ }
698
+ const symbols = [...symbolsByKey.values()].sort(compareSymbols);
699
+ return { symbols, imports: cFamilyExtractor.extractImports?.(_path, text) ?? [] };
700
+ },
701
+ };
702
+
703
+ const javaExtractor: LanguageExtractor = {
704
+ langs: ["java"],
705
+ extractImports(_path, text) {
706
+ return uniqueSorted(extractMatches(text, /^\s*import\s+(?:static\s+)?([A-Za-z_][\w.*]*);/gm));
707
+ },
708
+ extract(_path, text) {
709
+ const symbols = extractWithLineRegex(text, [
710
+ { regex: /^\s*(?:public\s+|private\s+|protected\s+|abstract\s+|final\s+)*class\s+([A-Za-z_]\w*)\b/, kind: "class" },
711
+ {
712
+ regex: /^\s*(?:public\s+|private\s+|protected\s+|abstract\s+|final\s+)*interface\s+([A-Za-z_]\w*)\b/,
713
+ kind: "iface",
714
+ },
715
+ { regex: /^\s*(?:public\s+|private\s+|protected\s+|abstract\s+|final\s+)*enum\s+([A-Za-z_]\w*)\b/, kind: "type" },
716
+ {
717
+ regex:
718
+ /^\s*(?:public\s+|private\s+|protected\s+|static\s+|final\s+|synchronized\s+)*[A-Za-z_][\w<>,[\]\s]*\s+([A-Za-z_]\w*)\s*\([^)]*\)\s*\{?$/,
719
+ kind: "method",
720
+ },
721
+ {
722
+ regex: /^\s*public\s+(?:static\s+|final\s+)*[A-Za-z_][\w<>,[\]\s]*\s+([A-Z][A-Z0-9_]*)\s*=/,
723
+ kind: "const",
724
+ },
725
+ ]);
726
+ return { symbols, imports: javaExtractor.extractImports?.(_path, text) ?? [] };
727
+ },
728
+ };
729
+
730
+ const rubyExtractor: LanguageExtractor = {
731
+ langs: ["ruby"],
732
+ extractImports(_path, text) {
733
+ return uniqueSorted([
734
+ ...extractMatches(text, /^\s*require\s+["']([^"']+)["']/gm),
735
+ ...extractMatches(text, /^\s*require_relative\s+["']([^"']+)["']/gm).map((item) => `./${item}`),
736
+ ]);
737
+ },
738
+ extract(_path, text) {
739
+ const symbols = extractWithLineRegex(text, [
740
+ { regex: /^\s*class\s+([A-Z]\w*(?:::[A-Z]\w*)*)\b/, kind: "class" },
741
+ { regex: /^\s*module\s+([A-Z]\w*(?:::[A-Z]\w*)*)\b/, kind: "type" },
742
+ { regex: /^\s*def\s+(?:self\.)?([A-Za-z_]\w*[!?=]?)\b/, kind: "func" },
743
+ { regex: /^([A-Z][A-Z0-9_]*)\s*=/, kind: "const" },
744
+ ]);
745
+ return { symbols, imports: rubyExtractor.extractImports?.(_path, text) ?? [] };
746
+ },
747
+ };
748
+
749
+ const csharpExtractor: LanguageExtractor = {
750
+ langs: ["c#"],
751
+ extractImports(_path, text) {
752
+ // Mirrors the tree-sitter using-directive handling: static prefixes are
753
+ // stripped and alias directives resolve to their right-hand side.
754
+ return uniqueSorted(
755
+ extractMatches(text, /^\s*using\s+(?:static\s+)?(?:[A-Za-z_]\w*\s*=\s*)?([A-Za-z_][\w.]*)\s*;/gm),
756
+ );
757
+ },
758
+ extract(_path, text) {
759
+ const symbols = extractWithLineRegex(text, [
760
+ {
761
+ regex:
762
+ /^\s*(?:public\s+|private\s+|protected\s+|internal\s+|static\s+|sealed\s+|abstract\s+|partial\s+)*class\s+([A-Za-z_]\w*)\b/,
763
+ kind: "class",
764
+ },
765
+ {
766
+ regex: /^\s*(?:public\s+|private\s+|protected\s+|internal\s+|partial\s+)*interface\s+([A-Za-z_]\w*)\b/,
767
+ kind: "iface",
768
+ },
769
+ {
770
+ regex:
771
+ /^\s*(?:public\s+|private\s+|protected\s+|internal\s+|readonly\s+|partial\s+)*(?:enum|struct|record)\s+([A-Za-z_]\w*)\b/,
772
+ kind: "type",
773
+ },
774
+ {
775
+ regex:
776
+ /^\s*(?:public\s+|private\s+|protected\s+|internal\s+|static\s+|virtual\s+|override\s+|abstract\s+|sealed\s+|async\s+|partial\s+|new\s+)*(?!(?:if|for|foreach|while|switch|catch|return|using|else|do|new|class|interface|enum|struct|record|namespace|lock|throw)\b)[A-Za-z_][\w<>,[\].?\s]*\s+([A-Za-z_]\w*)\s*\([^)]*\)\s*\{?$/,
777
+ kind: "method",
778
+ },
779
+ {
780
+ regex:
781
+ /^\s*(?:public\s+|private\s+|protected\s+|internal\s+|static\s+)*const\s+[A-Za-z_][\w<>,[\]\s]*\s+([A-Za-z_]\w*)\s*=/,
782
+ kind: "const",
783
+ },
784
+ ]);
785
+ return { symbols, imports: csharpExtractor.extractImports?.(_path, text) ?? [] };
786
+ },
787
+ };
788
+
789
+ const fallbackExtractors: ReadonlyArray<LanguageExtractor> = [
790
+ tsJsExtractor,
791
+ pythonExtractor,
792
+ goExtractor,
793
+ rustExtractor,
794
+ cFamilyExtractor,
795
+ javaExtractor,
796
+ rubyExtractor,
797
+ csharpExtractor,
798
+ ];
799
+
800
+ function extractWithExtractors(
801
+ extractors: ReadonlyArray<LanguageExtractor>,
802
+ language: CodewikiLanguage,
803
+ relPath: string,
804
+ text: string,
805
+ ): LanguageExtraction {
806
+ const symbols = new Map<string, ExtractedSymbol>();
807
+ const imports: string[] = [];
808
+ for (const extractor of extractors) {
809
+ if (!extractor.langs.includes(language)) continue;
810
+ const extracted = extractor.extract(relPath, text);
811
+ for (const symbol of extracted.symbols) {
812
+ const key = `${symbol.name}\0${symbol.kind}\0${symbol.line}`;
813
+ if (!symbols.has(key)) symbols.set(key, symbol);
814
+ }
815
+ imports.push(...extracted.imports);
816
+ }
817
+ return {
818
+ symbols: [...symbols.values()].sort(compareSymbols),
819
+ imports: uniqueSorted(imports),
820
+ };
821
+ }
822
+
823
+ function extractImportsWithExtractors(
824
+ extractors: ReadonlyArray<LanguageExtractor>,
825
+ language: CodewikiLanguage,
826
+ relPath: string,
827
+ text: string,
828
+ ): string[] {
829
+ const imports: string[] = [];
830
+ for (const extractor of extractors) {
831
+ if (!extractor.langs.includes(language) || !extractor.extractImports) continue;
832
+ imports.push(...extractor.extractImports(relPath, text));
833
+ }
834
+ return uniqueSorted(imports);
835
+ }
836
+
837
+ interface BuiltFile {
838
+ file: CodewikiFile;
839
+ symbols: CodewikiSymbol[];
840
+ }
841
+
842
+ function mergeTreeSitterWithRegexImports(
843
+ language: CodewikiLanguage,
844
+ relPath: string,
845
+ text: string,
846
+ extracted: LanguageExtraction,
847
+ ): LanguageExtraction {
848
+ const regexImports = extractImportsWithExtractors(fallbackExtractors, language, relPath, text);
849
+ return {
850
+ symbols: extracted.symbols.sort(compareSymbols),
851
+ imports: uniqueSorted([...extracted.imports, ...regexImports]),
852
+ };
853
+ }
854
+
855
+ export function fallbackExtraction(language: CodewikiLanguage, relPath: string, text: string): LanguageExtraction {
856
+ return extractWithExtractors(fallbackExtractors, language, relPath, text);
857
+ }
858
+
859
+ function extractSourceFile(
860
+ language: CodewikiLanguage,
861
+ relPath: string,
862
+ text: string,
863
+ treeSitterExtractor: LanguageExtractor,
864
+ ): LanguageExtraction {
865
+ if (!treeSitterExtractor.langs.includes(language)) return fallbackExtraction(language, relPath, text);
866
+ try {
867
+ return mergeTreeSitterWithRegexImports(language, relPath, text, treeSitterExtractor.extract(relPath, text));
868
+ } catch {
869
+ return fallbackExtraction(language, relPath, text);
870
+ }
871
+ }
872
+
873
+ function buildFile(
874
+ cwd: string,
875
+ relPath: string,
876
+ treeSitterExtractor: LanguageExtractor,
877
+ readFile: CodewikiReadFile,
878
+ ): BuiltFile | null {
879
+ const pathLanguage = languageForPath(relPath);
880
+ if (!pathLanguage) return null;
881
+ let text: string | null;
882
+ try {
883
+ text = readFile(join(cwd, relPath));
884
+ } catch {
885
+ return null;
886
+ }
887
+ if (text === null) return null;
888
+ // Ambiguous `.h` headers classify from content so both full builds and
889
+ // incremental updates land on the same C/C++ decision.
890
+ const language = pathLanguage === "c" && isAmbiguousHeaderPath(relPath) ? classifyCHeaderLanguage(text) : pathLanguage;
891
+ const file: CodewikiFile = {
892
+ id: stableFileId(relPath),
893
+ path: relPath,
894
+ lang: language,
895
+ loc: lineCount(text),
896
+ role: roleFor(relPath, language),
897
+ hash: contentHash(text),
898
+ imports: [],
899
+ };
900
+ if (text.trim().length === 0) return { file, symbols: [] };
901
+ const extracted = isCMakePath(relPath)
902
+ ? extractCMake(text)
903
+ : language !== "config"
904
+ ? extractSourceFile(language, relPath, text, treeSitterExtractor)
905
+ : null;
906
+ if (!extracted) return { file, symbols: [] };
907
+ const summary = firstDocSummary(text);
908
+ const sourceFile: CodewikiFile = {
909
+ ...file,
910
+ imports: extracted.imports,
911
+ ...(summary ? { summary } : {}),
912
+ };
913
+ const symbols = extracted.symbols.map((symbol) => ({
914
+ name: symbol.name,
915
+ kind: symbol.kind,
916
+ fileId: sourceFile.id,
917
+ line: symbol.line,
918
+ ...symbolSigFields(symbol.kind, symbol.sig),
919
+ }));
920
+ return {
921
+ file: sourceFile,
922
+ symbols,
923
+ };
924
+ }
925
+
926
+ function candidatePathsForImport(cwd: string, fromRel: string, specifier: string): string[] {
927
+ const fromDir = dirname(join(cwd, fromRel));
928
+ const cleaned = specifier.replace(/\\/g, "/");
929
+ const base = cleaned.startsWith(".") || cleaned.startsWith("/") ? resolve(fromDir, cleaned) : "";
930
+ if (!base) return [];
931
+ const candidates = [base];
932
+ for (const ext of RESOLUTION_EXTENSIONS) candidates.push(`${base}${ext}`);
933
+ for (const ext of RESOLUTION_EXTENSIONS) candidates.push(join(base, `index${ext}`));
934
+ if (cleaned.endsWith(".js")) {
935
+ const stripped = base.replace(/\.js$/, "");
936
+ for (const ext of [".ts", ".tsx", ".mts", ".cts"]) candidates.push(`${stripped}${ext}`);
937
+ }
938
+ if (/^[.]+[A-Za-z_]/.test(cleaned)) {
939
+ const pythonModule = cleaned.replace(/^\.+/, "").replace(/\./g, "/");
940
+ const pythonBase = resolve(fromDir, pythonModule);
941
+ candidates.push(`${pythonBase}.py`, join(pythonBase, "__init__.py"));
942
+ }
943
+ return uniqueSorted(
944
+ candidates.map((candidate) => normalizeRel(cwd, candidate)).filter((candidate) => !candidate.startsWith("..")),
945
+ );
946
+ }
947
+
948
+ /**
949
+ * Per-run memo for import resolution.
950
+ *
951
+ * A candidate list depends only on the importing file's directory and the
952
+ * specifier, and a candidate's on-disk status cannot change while a single edge
953
+ * rebuild is in flight, so both collapse to a map lookup after the first miss.
954
+ * Uncached, one rebuild of a 1100-file TypeScript repo issued roughly 80 000
955
+ * `statSync` calls, most of them for paths that do not exist, and spent about
956
+ * four seconds doing it.
957
+ */
958
+ function createImportResolver(cwd: string): {
959
+ resolve(fromRel: string, specifier: string, pathToId: ReadonlyMap<string, string>): string | null;
960
+ } {
961
+ const candidatesByOrigin = new Map<string, string[]>();
962
+ const onDisk = new Map<string, boolean>();
963
+ const candidatesFor = (fromRel: string, specifier: string): string[] => {
964
+ // The candidate set is a function of the directory, not the file: every
965
+ // sibling importing the same specifier resolves through the same list.
966
+ const key = `${dirname(fromRel)}\0${specifier}`;
967
+ let candidates = candidatesByOrigin.get(key);
968
+ if (!candidates) {
969
+ candidates = candidatePathsForImport(cwd, fromRel, specifier);
970
+ candidatesByOrigin.set(key, candidates);
971
+ }
972
+ return candidates;
973
+ };
974
+ const isFile = (candidate: string): boolean => {
975
+ const cached = onDisk.get(candidate);
976
+ if (cached !== undefined) return cached;
977
+ let exists: boolean;
978
+ try {
979
+ exists = statSync(join(cwd, candidate)).isFile();
980
+ } catch {
981
+ exists = false;
982
+ }
983
+ onDisk.set(candidate, exists);
984
+ return exists;
985
+ };
986
+ return {
987
+ resolve(fromRel, specifier, pathToId): string | null {
988
+ for (const candidate of candidatesFor(fromRel, specifier)) {
989
+ if (pathToId.has(candidate)) return pathToId.get(candidate) ?? null;
990
+ // An unindexed file that exists still claims the specifier: it shadows
991
+ // any later candidate, and having no id makes the edge external.
992
+ if (isFile(candidate)) return null;
993
+ }
994
+ return null;
995
+ },
996
+ };
997
+ }
998
+
999
+ async function buildEdges(
1000
+ cwd: string,
1001
+ files: ReadonlyArray<CodewikiFile>,
1002
+ slicer: CooperativeSlicer,
1003
+ ): Promise<CodewikiEdge[]> {
1004
+ const pathToId = new Map(files.map((file) => [file.path, file.id] as const));
1005
+ const resolver = createImportResolver(cwd);
1006
+ const edges: CodewikiEdge[] = [];
1007
+ const seen = new Set<string>();
1008
+ for (const file of files) {
1009
+ for (const specifier of file.imports) {
1010
+ await slicer.tick();
1011
+ const target = resolver.resolve(file.path, specifier, pathToId);
1012
+ const edge = target
1013
+ ? ({ fileId: file.id, toFileId: target } satisfies CodewikiInternalEdge)
1014
+ : ({ fileId: file.id, externalModule: specifier } satisfies CodewikiExternalEdge);
1015
+ const key = "toFileId" in edge ? `${edge.fileId}\0${edge.toFileId}` : `${edge.fileId}\0${edge.externalModule}`;
1016
+ if (seen.has(key)) continue;
1017
+ seen.add(key);
1018
+ edges.push(edge);
1019
+ }
1020
+ }
1021
+ return edges.sort(compareEdges);
1022
+ }
1023
+
1024
+ function compareFiles(a: CodewikiFile, b: CodewikiFile): number {
1025
+ return a.path.localeCompare(b.path);
1026
+ }
1027
+
1028
+ function compareCodewikiSymbols(a: CodewikiSymbol, b: CodewikiSymbol): number {
1029
+ const pathCmp = a.fileId.localeCompare(b.fileId);
1030
+ return pathCmp || a.line - b.line || a.name.localeCompare(b.name) || a.kind.localeCompare(b.kind);
1031
+ }
1032
+
1033
+ function compareEdges(a: CodewikiEdge, b: CodewikiEdge): number {
1034
+ const fileCmp = a.fileId.localeCompare(b.fileId);
1035
+ if (fileCmp !== 0) return fileCmp;
1036
+ const aTarget = "toFileId" in a ? a.toFileId : `~${a.externalModule}`;
1037
+ const bTarget = "toFileId" in b ? b.toFileId : `~${b.externalModule}`;
1038
+ return aTarget.localeCompare(bTarget);
1039
+ }
1040
+
1041
+ function promoteSingleSourceEntry(files: CodewikiFile[]): CodewikiFile[] {
1042
+ const sourceFiles = files.filter((file) => file.lang !== "config");
1043
+ if (sourceFiles.length !== 1) return files;
1044
+ const only = sourceFiles[0];
1045
+ if (only?.role !== "module") return files;
1046
+ return files.map((file) => (file.id === only.id ? { ...file, role: "entry" } : file));
1047
+ }
1048
+
1049
+ async function codewikiFromBuiltFiles(
1050
+ cwd: string,
1051
+ language: ProjectType,
1052
+ builtFiles: ReadonlyArray<BuiltFile>,
1053
+ slicer: CooperativeSlicer,
1054
+ ): Promise<Codewiki> {
1055
+ const baseBuiltFiles = builtFiles.map((item) => ({
1056
+ ...item,
1057
+ file: { ...item.file, role: roleFor(item.file.path, item.file.lang) },
1058
+ }));
1059
+ const files = promoteSingleSourceEntry(baseBuiltFiles.map((item) => item.file).sort(compareFiles));
1060
+ const roleById = new Map(files.map((file) => [file.id, file.role] as const));
1061
+ const normalizedBuilt = baseBuiltFiles.map((item) => {
1062
+ const role = roleById.get(item.file.id);
1063
+ return role && role !== item.file.role ? { ...item, file: { ...item.file, role } } : item;
1064
+ });
1065
+ const normalizedFiles = normalizedBuilt.map((item) => item.file).sort(compareFiles);
1066
+ return {
1067
+ version: CODEWIKI_VERSION,
1068
+ language,
1069
+ files: normalizedFiles,
1070
+ symbols: normalizedBuilt.flatMap((item) => item.symbols).sort(compareCodewikiSymbols),
1071
+ edges: await buildEdges(cwd, normalizedFiles, slicer),
1072
+ };
1073
+ }
1074
+
1075
+ async function buildFromPaths(
1076
+ cwd: string,
1077
+ language: ProjectType,
1078
+ relPaths: ReadonlyArray<string>,
1079
+ options: CodewikiBuildOptions = {},
1080
+ ): Promise<Codewiki> {
1081
+ const slicer = options.slicer ?? createSlicer();
1082
+ const sortedPaths = [...relPaths].sort(compareStrings);
1083
+ const treeSitterExtractor = await loadTreeSitterExtractor();
1084
+ await treeSitterExtractor.ensureGrammarsForPaths(sortedPaths);
1085
+ const readFile = options.readFile ?? defaultReadFile;
1086
+ const builtFiles: BuiltFile[] = [];
1087
+ for (const relPath of sortedPaths) {
1088
+ // One read plus one tree-sitter parse per file; a full build of a large
1089
+ // repo is thousands of them and must not land as a single turn.
1090
+ await slicer.tick();
1091
+ const built = buildFile(cwd, relPath, treeSitterExtractor, readFile);
1092
+ if (built) builtFiles.push(built);
1093
+ }
1094
+ return codewikiFromBuiltFiles(cwd, language, builtFiles, slicer);
1095
+ }
1096
+
1097
+ export async function buildCodewiki(input: BuildCodewikiInput, options: CodewikiBuildOptions = {}): Promise<Codewiki> {
1098
+ const slicer = options.slicer ?? createSlicer();
1099
+ const files = (await enumerateWorkspaceFilesAsync(input.cwd, EXCLUDED_DIRS, undefined, slicer)).filter(
1100
+ isIndexablePath,
1101
+ );
1102
+ return buildFromPaths(input.cwd, input.language, files, { ...options, slicer });
1103
+ }
1104
+
1105
+ /**
1106
+ * Apply an incremental update for a set of changed paths. The changed file
1107
+ * records and symbols are replaced in-place, and edges are rebuilt from stored
1108
+ * imports across the merged file set.
1109
+ */
1110
+ export async function updateCodewikiPaths(
1111
+ cwd: string,
1112
+ codewiki: Codewiki,
1113
+ paths: ReadonlyArray<string>,
1114
+ options: CodewikiBuildOptions = {},
1115
+ ): Promise<Codewiki> {
1116
+ const normalizedPaths = uniqueSorted(
1117
+ paths.map(normalizeInputPath).filter((path) => path.length > 0 && !path.startsWith("..")),
1118
+ );
1119
+ if (normalizedPaths.length === 0) return codewiki;
1120
+ if (
1121
+ normalizedPaths.some(
1122
+ (path) =>
1123
+ path === ".gitignore" ||
1124
+ path.endsWith("/.gitignore") ||
1125
+ path === ".git/info/exclude" ||
1126
+ path === ".git/index" ||
1127
+ path === ".gitmodules",
1128
+ )
1129
+ ) {
1130
+ // Ignore and index metadata can add or remove paths that are not present in
1131
+ // the mutation batch itself. Re-enumerate once so incremental visibility
1132
+ // remains byte-equivalent to a full build.
1133
+ return buildCodewiki({ cwd, language: codewiki.language }, options);
1134
+ }
1135
+ const slicer = options.slicer ?? createSlicer();
1136
+ const existingPaths = new Set(codewiki.files.map((file) => file.path));
1137
+ const visiblePaths = new Set(filterWorkspaceFileCandidates(cwd, normalizedPaths, EXCLUDED_DIRS));
1138
+ const readFile = options.readFile ?? defaultReadFile;
1139
+ const changedPathSet = new Set(normalizedPaths);
1140
+ const rebuildPaths: string[] = [];
1141
+ let hasIndexChange = false;
1142
+ for (const relPath of normalizedPaths) {
1143
+ const wasIndexed = existingPaths.has(relPath);
1144
+ const isCurrentIndexableFile = isIndexablePath(relPath) && visiblePaths.has(relPath);
1145
+ if (!wasIndexed && !isCurrentIndexableFile) continue;
1146
+ hasIndexChange = true;
1147
+ if (isCurrentIndexableFile) rebuildPaths.push(relPath);
1148
+ }
1149
+ if (!hasIndexChange) return codewiki;
1150
+ const rebuiltFiles: BuiltFile[] = [];
1151
+ if (rebuildPaths.length > 0) {
1152
+ const treeSitterExtractor = await loadTreeSitterExtractor();
1153
+ await treeSitterExtractor.ensureGrammarsForPaths(rebuildPaths);
1154
+ for (const relPath of rebuildPaths) {
1155
+ await slicer.tick();
1156
+ const built = buildFile(cwd, relPath, treeSitterExtractor, readFile);
1157
+ if (built) rebuiltFiles.push(built);
1158
+ }
1159
+ }
1160
+ const removedFileIds = new Set(codewiki.files.filter((file) => changedPathSet.has(file.path)).map((file) => file.id));
1161
+ const symbolsByFileId = new Map<string, CodewikiSymbol[]>();
1162
+ for (const symbol of codewiki.symbols) {
1163
+ if (removedFileIds.has(symbol.fileId)) continue;
1164
+ const symbols = symbolsByFileId.get(symbol.fileId) ?? [];
1165
+ symbols.push(symbol);
1166
+ symbolsByFileId.set(symbol.fileId, symbols);
1167
+ }
1168
+ const keptFiles: BuiltFile[] = codewiki.files
1169
+ .filter((file) => !changedPathSet.has(file.path))
1170
+ .map((file) => ({ file, symbols: symbolsByFileId.get(file.id) ?? [] }));
1171
+ return codewikiFromBuiltFiles(cwd, codewiki.language, [...keptFiles, ...rebuiltFiles], slicer);
1172
+ }
1173
+
1174
+ /**
1175
+ * Reconcile an existing index with the current workspace without parsing
1176
+ * unchanged files. The scan reads and hashes candidate files, then delegates
1177
+ * extraction to the incremental updater only for additions, removals, and
1178
+ * content changes. Callers can still use buildCodewiki when the artifact is
1179
+ * missing or structurally incompatible.
1180
+ */
1181
+ export async function syncCodewiki(
1182
+ cwd: string,
1183
+ codewiki: Codewiki,
1184
+ options: CodewikiBuildOptions = {},
1185
+ ): Promise<Codewiki> {
1186
+ const slicer = options.slicer ?? createSlicer();
1187
+ const readFile = options.readFile ?? defaultReadFile;
1188
+ const currentPaths = (await enumerateWorkspaceFilesAsync(cwd, EXCLUDED_DIRS, undefined, slicer)).filter(
1189
+ isIndexablePath,
1190
+ );
1191
+ const currentFiles = new Map<string, string>();
1192
+ const currentTexts = new Map<string, string>();
1193
+ for (const relPath of currentPaths) {
1194
+ // Reads and hashes every visible file in the workspace. Cheap per file,
1195
+ // seconds in aggregate on a large repo.
1196
+ await slicer.tick();
1197
+ const text = readFile(join(cwd, relPath));
1198
+ if (text !== null) {
1199
+ currentFiles.set(relPath, contentHash(text));
1200
+ currentTexts.set(relPath, text);
1201
+ }
1202
+ }
1203
+ const indexedFiles = new Map(codewiki.files.map((file) => [file.path, file] as const));
1204
+ const changedPaths = new Set<string>();
1205
+ for (const [relPath, hash] of currentFiles) {
1206
+ if (indexedFiles.get(relPath)?.hash !== hash) changedPaths.add(relPath);
1207
+ }
1208
+ for (const relPath of indexedFiles.keys()) {
1209
+ if (!currentFiles.has(relPath)) changedPaths.add(relPath);
1210
+ }
1211
+ if (changedPaths.size === 0) return codewiki;
1212
+ const syncOptions: CodewikiBuildOptions = {
1213
+ ...options,
1214
+ slicer,
1215
+ readFile: (path) => currentTexts.get(normalizeRel(cwd, path)) ?? readFile(path),
1216
+ };
1217
+ return updateCodewikiPaths(cwd, codewiki, [...changedPaths], syncOptions);
1218
+ }
1219
+
1220
+ export function codewikiPath(cwd: string): string {
1221
+ return join(cwd, ".clio-coder", "codewiki.json");
1222
+ }
1223
+
1224
+ export function serializeCodewiki(codewiki: Codewiki): string {
1225
+ return `${JSON.stringify(normalizeCodewiki(codewiki))}\n`;
1226
+ }
1227
+
1228
+ export function writeCodewiki(cwd: string, codewiki: Codewiki): string {
1229
+ const serialized = serializeCodewiki(codewiki);
1230
+ safeResourceWrite(codewikiPath(cwd), serialized, {
1231
+ encoding: "utf8",
1232
+ });
1233
+ return serialized;
1234
+ }
1235
+
1236
+ export function parseCodewikiRaw(raw: string): Codewiki | null {
1237
+ let parsed: unknown;
1238
+ try {
1239
+ parsed = JSON.parse(raw);
1240
+ } catch {
1241
+ return null;
1242
+ }
1243
+ return upgradeCodewiki(parsed);
1244
+ }
1245
+
1246
+ function readCodewikiRaw(cwd: string): { raw: string; codewiki: Codewiki } | null {
1247
+ const filePath = codewikiPath(cwd);
1248
+ if (!existsSync(filePath)) return null;
1249
+ let raw: string;
1250
+ try {
1251
+ raw = readFileSync(filePath, "utf8");
1252
+ } catch {
1253
+ return null;
1254
+ }
1255
+ const codewiki = parseCodewikiRaw(raw);
1256
+ return codewiki ? { raw, codewiki } : null;
1257
+ }
1258
+
1259
+ export function readCodewiki(cwd: string): Codewiki | null {
1260
+ return readCodewikiRaw(cwd)?.codewiki ?? null;
1261
+ }
1262
+
1263
+ /**
1264
+ * Read and parse the artifact without blocking on the file read. The parse
1265
+ * itself still runs as one turn, which is what a JSON artifact costs; the read
1266
+ * is the part that scales with repository size and it now happens off the loop.
1267
+ * For status surfaces that poll, prefer this over `readCodewiki`.
1268
+ */
1269
+ export async function readCodewikiAsync(cwd: string): Promise<Codewiki | null> {
1270
+ let raw: string;
1271
+ try {
1272
+ raw = await readFileAsync(codewikiPath(cwd), "utf8");
1273
+ } catch {
1274
+ return null;
1275
+ }
1276
+ return parseCodewikiRaw(raw);
1277
+ }
1278
+
1279
+ export function codewikiEntries(codewiki: Codewiki): CodewikiEntry[] {
1280
+ const fileById = new Map(codewiki.files.map((file) => [file.id, file] as const));
1281
+ const exportsByFile = new Map<string, string[]>();
1282
+ for (const symbol of codewiki.symbols) {
1283
+ const list = exportsByFile.get(symbol.fileId) ?? [];
1284
+ list.push(symbol.name);
1285
+ exportsByFile.set(symbol.fileId, list);
1286
+ }
1287
+ const importsByFile = new Map<string, string[]>();
1288
+ for (const edge of codewiki.edges) {
1289
+ const list = importsByFile.get(edge.fileId) ?? [];
1290
+ if ("toFileId" in edge) {
1291
+ const target = fileById.get(edge.toFileId);
1292
+ if (target) list.push(target.path);
1293
+ } else {
1294
+ list.push(edge.externalModule);
1295
+ }
1296
+ importsByFile.set(edge.fileId, list);
1297
+ }
1298
+ return codewiki.files
1299
+ .filter((file) => file.lang !== "config")
1300
+ .map<CodewikiEntry>((file) => ({
1301
+ path: file.path,
1302
+ exports: uniqueSorted(exportsByFile.get(file.id) ?? []),
1303
+ imports: uniqueSorted(importsByFile.get(file.id) ?? []),
1304
+ kind: file.role === "entry" ? "entry-point" : file.role === "test" ? "test" : "module",
1305
+ ...(file.summary ? { summary: file.summary } : {}),
1306
+ }))
1307
+ .sort((a, b) => a.path.localeCompare(b.path));
1308
+ }
1309
+
1310
+ export function codewikiNeedsBackfill(codewiki: Codewiki): boolean {
1311
+ return codewiki.files.some((file) => file.lang !== "config" && file.hash.length === 0);
1312
+ }
1313
+
1314
+ export function structuralCodewikiHash(codewiki: Codewiki): string {
1315
+ return createHash("sha256")
1316
+ .update(JSON.stringify(normalizeCodewiki(codewiki)))
1317
+ .digest("hex");
1318
+ }
1319
+
1320
+ function normalizeCodewikiFile(file: CodewikiFile): CodewikiFile {
1321
+ return {
1322
+ id: file.id,
1323
+ path: file.path,
1324
+ lang: file.lang,
1325
+ loc: file.loc,
1326
+ role: file.role,
1327
+ hash: file.hash,
1328
+ imports: uniqueSorted(file.imports),
1329
+ ...(file.summary ? { summary: file.summary } : {}),
1330
+ };
1331
+ }
1332
+
1333
+ function symbolSigFields(kind: CodewikiSymbolKind, sig: string | undefined): Pick<CodewikiSymbol, "sig"> {
1334
+ if (!CODEWIKI_SYMBOL_KINDS_WITH_SIG.has(kind)) return {};
1335
+ const clean = sig?.trim().slice(0, 240);
1336
+ return clean && clean.length > 0 ? { sig: clean } : {};
1337
+ }
1338
+
1339
+ function normalizeCodewikiSymbol(symbol: CodewikiSymbol): CodewikiSymbol {
1340
+ return {
1341
+ name: symbol.name,
1342
+ kind: symbol.kind,
1343
+ fileId: symbol.fileId,
1344
+ line: symbol.line,
1345
+ ...symbolSigFields(symbol.kind, symbol.sig),
1346
+ };
1347
+ }
1348
+
1349
+ function normalizeCodewiki(codewiki: Codewiki): Codewiki {
1350
+ return {
1351
+ version: CODEWIKI_VERSION,
1352
+ language: codewiki.language,
1353
+ files: codewiki.files.map(normalizeCodewikiFile).sort(compareFiles),
1354
+ symbols: codewiki.symbols.map(normalizeCodewikiSymbol).sort(compareCodewikiSymbols),
1355
+ edges: [...codewiki.edges].sort(compareEdges),
1356
+ };
1357
+ }
1358
+
1359
+ function upgradeCodewiki(value: unknown): Codewiki | null {
1360
+ if (isCodewikiV5(value)) return normalizeCodewiki(value);
1361
+ if (isCodewikiV4(value)) return upgradeV4Codewiki(value);
1362
+ if (isCodewikiV3(value)) return upgradeV3Codewiki(value);
1363
+ if (isCodewikiV2(value)) return upgradeV2Codewiki(value);
1364
+ return null;
1365
+ }
1366
+
1367
+ interface CodewikiFileV3 {
1368
+ id: string;
1369
+ path: string;
1370
+ lang: CodewikiLanguage;
1371
+ loc: number;
1372
+ role: CodewikiFileRole;
1373
+ }
1374
+
1375
+ interface CodewikiV3 {
1376
+ version: 3;
1377
+ language: ProjectType;
1378
+ files: CodewikiFileV3[];
1379
+ symbols: CodewikiSymbol[];
1380
+ edges: CodewikiEdge[];
1381
+ }
1382
+
1383
+ interface CodewikiV4 {
1384
+ version: 4;
1385
+ language: ProjectType;
1386
+ files: CodewikiFile[];
1387
+ symbols: CodewikiSymbol[];
1388
+ edges: CodewikiEdge[];
1389
+ }
1390
+
1391
+ interface CodewikiV2 {
1392
+ version: 2;
1393
+ generatedAt: string;
1394
+ language: ProjectType;
1395
+ entries: CodewikiEntry[];
1396
+ }
1397
+
1398
+ function upgradeV3Codewiki(value: CodewikiV3): Codewiki {
1399
+ return normalizeCodewiki({
1400
+ version: CODEWIKI_VERSION,
1401
+ language: value.language,
1402
+ files: value.files.map((file) => ({
1403
+ ...file,
1404
+ hash: "",
1405
+ imports: [],
1406
+ })),
1407
+ symbols: value.symbols,
1408
+ edges: value.edges,
1409
+ });
1410
+ }
1411
+
1412
+ function upgradeV4Codewiki(value: CodewikiV4): Codewiki {
1413
+ return normalizeCodewiki({
1414
+ version: CODEWIKI_VERSION,
1415
+ language: value.language,
1416
+ // v5 changes C-family extraction and adds CUDA paths. Blank hashes force
1417
+ // one complete rebuild instead of treating a structurally obsolete v4
1418
+ // artifact as fresh.
1419
+ files: value.files.map((file) => ({ ...file, hash: "" })),
1420
+ symbols: value.symbols,
1421
+ edges: value.edges,
1422
+ });
1423
+ }
1424
+
1425
+ function upgradeV2Codewiki(value: CodewikiV2): Codewiki {
1426
+ const files: CodewikiFileV3[] = value.entries.map((entry) => {
1427
+ const lang =
1428
+ languageForPath(entry.path) ??
1429
+ (value.language === "unknown" || value.language === "polyglot" || value.language === "dotfiles"
1430
+ ? "config"
1431
+ : value.language);
1432
+ return {
1433
+ id: stableFileId(entry.path),
1434
+ path: entry.path,
1435
+ lang,
1436
+ loc: 0,
1437
+ role: entry.kind === "entry-point" ? "entry" : entry.kind === "test" ? "test" : "module",
1438
+ };
1439
+ });
1440
+ const pathToId = new Map(files.map((file) => [file.path, file.id] as const));
1441
+ const symbols: CodewikiSymbol[] = [];
1442
+ for (const entry of value.entries) {
1443
+ const fileId = pathToId.get(entry.path);
1444
+ if (!fileId) continue;
1445
+ for (const name of entry.exports) symbols.push({ name, kind: "const", fileId, line: 1 });
1446
+ }
1447
+ const edges: CodewikiEdge[] = [];
1448
+ for (const entry of value.entries) {
1449
+ const fileId = pathToId.get(entry.path);
1450
+ if (!fileId) continue;
1451
+ for (const item of entry.imports) {
1452
+ const toFileId = pathToId.get(item);
1453
+ edges.push(toFileId ? { fileId, toFileId } : { fileId, externalModule: item });
1454
+ }
1455
+ }
1456
+ return upgradeV3Codewiki({
1457
+ version: 3,
1458
+ language: value.language,
1459
+ files,
1460
+ symbols,
1461
+ edges,
1462
+ });
1463
+ }
1464
+
1465
+ function isNormalizedRelativeCodewikiPath(path: string): boolean {
1466
+ if (path.length === 0 || path.includes("\0") || path.includes("\\") || path.startsWith("/")) return false;
1467
+ if (/^[A-Za-z]:\//.test(path)) return false;
1468
+ const segments = path.split("/");
1469
+ return segments.every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
1470
+ }
1471
+
1472
+ function hasValidNativeV5Semantics(value: Codewiki): boolean {
1473
+ const fileIds = new Set<string>();
1474
+ const filePaths = new Set<string>();
1475
+ const locByFileId = new Map<string, number>();
1476
+ for (const file of value.files) {
1477
+ if (fileIds.has(file.id) || filePaths.has(file.path)) return false;
1478
+ if (!isNormalizedRelativeCodewikiPath(file.path) || !/^[0-9a-f]{16}$/.test(file.hash)) return false;
1479
+ fileIds.add(file.id);
1480
+ filePaths.add(file.path);
1481
+ locByFileId.set(file.id, file.loc);
1482
+ }
1483
+ for (const symbol of value.symbols) {
1484
+ const loc = locByFileId.get(symbol.fileId);
1485
+ if (loc === undefined || symbol.line > loc) return false;
1486
+ }
1487
+ for (const edge of value.edges) {
1488
+ if (!fileIds.has(edge.fileId)) return false;
1489
+ if ("toFileId" in edge && !fileIds.has(edge.toFileId)) return false;
1490
+ }
1491
+ return true;
1492
+ }
1493
+
1494
+ function isCodewikiV5(value: unknown): value is Codewiki {
1495
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1496
+ const obj = value as Record<string, unknown>;
1497
+ if (obj.version !== CODEWIKI_VERSION || typeof obj.language !== "string") return false;
1498
+ if (!Array.isArray(obj.files) || !Array.isArray(obj.symbols) || !Array.isArray(obj.edges)) return false;
1499
+ if (!obj.files.every(isCodewikiFile) || !obj.symbols.every(isCodewikiSymbol) || !obj.edges.every(isCodewikiEdge)) {
1500
+ return false;
1501
+ }
1502
+ return hasValidNativeV5Semantics(obj as unknown as Codewiki);
1503
+ }
1504
+
1505
+ function isCodewikiV4(value: unknown): value is CodewikiV4 {
1506
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1507
+ const obj = value as Record<string, unknown>;
1508
+ if (obj.version !== 4 || typeof obj.language !== "string") return false;
1509
+ if (!Array.isArray(obj.files) || !Array.isArray(obj.symbols) || !Array.isArray(obj.edges)) return false;
1510
+ return obj.files.every(isCodewikiFile) && obj.symbols.every(isCodewikiSymbol) && obj.edges.every(isCodewikiEdge);
1511
+ }
1512
+
1513
+ function isCodewikiV3(value: unknown): value is CodewikiV3 {
1514
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1515
+ const obj = value as Record<string, unknown>;
1516
+ if (obj.version !== 3 || typeof obj.language !== "string") return false;
1517
+ if (!Array.isArray(obj.files) || !Array.isArray(obj.symbols) || !Array.isArray(obj.edges)) return false;
1518
+ return obj.files.every(isCodewikiFileV3) && obj.symbols.every(isCodewikiSymbol) && obj.edges.every(isCodewikiEdge);
1519
+ }
1520
+
1521
+ function isCodewikiV2(value: unknown): value is CodewikiV2 {
1522
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1523
+ const obj = value as Record<string, unknown>;
1524
+ if (obj.version !== 2 || typeof obj.generatedAt !== "string" || typeof obj.language !== "string") return false;
1525
+ if (!Array.isArray(obj.entries)) return false;
1526
+ return obj.entries.every(isCodewikiEntry);
1527
+ }
1528
+
1529
+ const CODEWIKI_LANGUAGES = new Set<CodewikiLanguage>([
1530
+ "typescript",
1531
+ "javascript",
1532
+ "python",
1533
+ "rust",
1534
+ "go",
1535
+ "c",
1536
+ "c++",
1537
+ "java",
1538
+ "ruby",
1539
+ "c#",
1540
+ "config",
1541
+ ]);
1542
+ const FILE_ROLES = new Set<CodewikiFileRole>(["entry", "test", "module", "config"]);
1543
+ const SYMBOL_KINDS = new Set<CodewikiSymbolKind>(["func", "class", "method", "type", "const", "var", "trait", "iface"]);
1544
+
1545
+ function isCodewikiFile(value: unknown): value is CodewikiFile {
1546
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1547
+ const obj = value as Record<string, unknown>;
1548
+ return (
1549
+ typeof obj.id === "string" &&
1550
+ typeof obj.path === "string" &&
1551
+ typeof obj.lang === "string" &&
1552
+ CODEWIKI_LANGUAGES.has(obj.lang as CodewikiLanguage) &&
1553
+ typeof obj.loc === "number" &&
1554
+ Number.isInteger(obj.loc) &&
1555
+ obj.loc >= 0 &&
1556
+ typeof obj.role === "string" &&
1557
+ FILE_ROLES.has(obj.role as CodewikiFileRole) &&
1558
+ typeof obj.hash === "string" &&
1559
+ Array.isArray(obj.imports) &&
1560
+ obj.imports.every((item) => typeof item === "string") &&
1561
+ (!("summary" in obj) || typeof obj.summary === "string")
1562
+ );
1563
+ }
1564
+
1565
+ function isCodewikiFileV3(value: unknown): value is CodewikiFileV3 {
1566
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1567
+ const obj = value as Record<string, unknown>;
1568
+ return (
1569
+ typeof obj.id === "string" &&
1570
+ typeof obj.path === "string" &&
1571
+ typeof obj.lang === "string" &&
1572
+ CODEWIKI_LANGUAGES.has(obj.lang as CodewikiLanguage) &&
1573
+ typeof obj.loc === "number" &&
1574
+ Number.isInteger(obj.loc) &&
1575
+ obj.loc >= 0 &&
1576
+ typeof obj.role === "string" &&
1577
+ FILE_ROLES.has(obj.role as CodewikiFileRole)
1578
+ );
1579
+ }
1580
+
1581
+ function isCodewikiSymbol(value: unknown): value is CodewikiSymbol {
1582
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1583
+ const obj = value as Record<string, unknown>;
1584
+ return (
1585
+ typeof obj.name === "string" &&
1586
+ typeof obj.kind === "string" &&
1587
+ SYMBOL_KINDS.has(obj.kind as CodewikiSymbolKind) &&
1588
+ typeof obj.fileId === "string" &&
1589
+ typeof obj.line === "number" &&
1590
+ Number.isInteger(obj.line) &&
1591
+ obj.line >= 1 &&
1592
+ (!("sig" in obj) || typeof obj.sig === "string")
1593
+ );
1594
+ }
1595
+
1596
+ function isCodewikiEdge(value: unknown): value is CodewikiEdge {
1597
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1598
+ const obj = value as Record<string, unknown>;
1599
+ if (typeof obj.fileId !== "string") return false;
1600
+ const hasToFile = typeof obj.toFileId === "string";
1601
+ const hasExternal = typeof obj.externalModule === "string";
1602
+ return hasToFile !== hasExternal;
1603
+ }
1604
+
1605
+ function isCodewikiEntry(value: unknown): value is CodewikiEntry {
1606
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1607
+ const obj = value as Record<string, unknown>;
1608
+ if (typeof obj.path !== "string") return false;
1609
+ if (!Array.isArray(obj.exports) || obj.exports.some((item) => typeof item !== "string")) return false;
1610
+ if (!Array.isArray(obj.imports) || obj.imports.some((item) => typeof item !== "string")) return false;
1611
+ if (obj.kind !== "entry-point" && obj.kind !== "test" && obj.kind !== "module") return false;
1612
+ if ("summary" in obj && typeof obj.summary !== "string") return false;
1613
+ return true;
1614
+ }