@mjasnikovs/pi-task 0.38.29 → 0.38.30

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 (370) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/remote/bridge.d.ts +19 -10
  14. package/dist/remote/bridge.js +3 -2
  15. package/dist/remote/broadcast.js +3 -1
  16. package/dist/remote/events.js +12 -11
  17. package/dist/remote/history.d.ts +1 -1
  18. package/dist/remote/protocol.d.ts +6 -3
  19. package/dist/remote/protocol.js +2 -1
  20. package/dist/remote/push.d.ts +16 -16
  21. package/dist/remote/push.js +27 -27
  22. package/dist/remote/register.d.ts +3 -3
  23. package/dist/remote/register.js +17 -19
  24. package/dist/remote/server.d.ts +9 -8
  25. package/dist/remote/server.js +15 -14
  26. package/dist/remote/session-state.d.ts +5 -4
  27. package/dist/remote/session-state.js +8 -5
  28. package/dist/remote/sw.d.ts +7 -6
  29. package/dist/remote/sw.js +7 -6
  30. package/dist/remote/tailscale.d.ts +4 -2
  31. package/dist/remote/tailscale.js +4 -2
  32. package/dist/remote/ui-highlight.js +6 -5
  33. package/dist/remote/ui-render.js +4 -4
  34. package/dist/remote/ui-script.js +24 -24
  35. package/dist/remote/ui-styles.d.ts +1 -1
  36. package/dist/remote/ui-styles.js +10 -13
  37. package/dist/remote/ui-tools.js +9 -6
  38. package/dist/shared/child-extensions.d.ts +29 -17
  39. package/dist/shared/child-extensions.js +29 -17
  40. package/dist/shared/child-output.d.ts +30 -24
  41. package/dist/shared/child-output.js +25 -17
  42. package/dist/shared/child-process.d.ts +47 -40
  43. package/dist/shared/child-process.js +50 -59
  44. package/dist/shared/command-watchdog.d.ts +22 -16
  45. package/dist/shared/command-watchdog.js +28 -21
  46. package/dist/shared/fs-text.d.ts +16 -10
  47. package/dist/shared/fs-text.js +16 -10
  48. package/dist/shared/git-runner.d.ts +25 -25
  49. package/dist/shared/git-runner.js +25 -25
  50. package/dist/shared/leaked-tool-call.d.ts +17 -11
  51. package/dist/shared/leaked-tool-call.js +23 -15
  52. package/dist/shared/model-endpoint.d.ts +29 -16
  53. package/dist/shared/model-endpoint.js +33 -21
  54. package/dist/shared/pi-invocation.d.ts +7 -4
  55. package/dist/shared/pi-invocation.js +12 -7
  56. package/dist/shared/pkg-version.d.ts +13 -5
  57. package/dist/shared/pkg-version.js +13 -5
  58. package/dist/shared/reasoning-capability.d.ts +35 -24
  59. package/dist/shared/reasoning-capability.js +35 -24
  60. package/dist/shared/stream-watchdog.d.ts +60 -44
  61. package/dist/shared/stream-watchdog.js +62 -45
  62. package/dist/task/accept-debt.d.ts +41 -43
  63. package/dist/task/accept-debt.js +73 -65
  64. package/dist/task/api-synthesis.d.ts +24 -21
  65. package/dist/task/api-synthesis.js +32 -26
  66. package/dist/task/apis-contract.d.ts +32 -64
  67. package/dist/task/apis-contract.js +32 -64
  68. package/dist/task/artifact-closure.d.ts +27 -13
  69. package/dist/task/artifact-closure.js +95 -67
  70. package/dist/task/auto-commit.d.ts +46 -35
  71. package/dist/task/auto-commit.js +51 -38
  72. package/dist/task/auto-io.d.ts +45 -25
  73. package/dist/task/auto-io.js +57 -29
  74. package/dist/task/auto-orchestrator.d.ts +26 -24
  75. package/dist/task/auto-orchestrator.js +178 -162
  76. package/dist/task/auto-prompts.d.ts +36 -24
  77. package/dist/task/auto-prompts.js +40 -26
  78. package/dist/task/autofix-ledger.d.ts +27 -25
  79. package/dist/task/autofix-ledger.js +29 -26
  80. package/dist/task/batch-test-task.d.ts +20 -12
  81. package/dist/task/batch-test-task.js +67 -60
  82. package/dist/task/boot-probe.d.ts +60 -44
  83. package/dist/task/boot-probe.js +91 -72
  84. package/dist/task/cancel-input.d.ts +30 -16
  85. package/dist/task/cancel-input.js +20 -11
  86. package/dist/task/cancel-points.d.ts +27 -20
  87. package/dist/task/cancel-points.js +30 -22
  88. package/dist/task/child-runner.d.ts +46 -51
  89. package/dist/task/child-runner.js +48 -49
  90. package/dist/task/child-status.d.ts +23 -16
  91. package/dist/task/child-status.js +23 -16
  92. package/dist/task/clamp-output.js +12 -5
  93. package/dist/task/command-run.d.ts +31 -28
  94. package/dist/task/command-run.js +44 -35
  95. package/dist/task/command-shrink.d.ts +25 -18
  96. package/dist/task/command-shrink.js +37 -31
  97. package/dist/task/command-watchdog.d.ts +9 -6
  98. package/dist/task/command-watchdog.js +21 -15
  99. package/dist/task/context-attribution.d.ts +34 -26
  100. package/dist/task/context-attribution.js +34 -26
  101. package/dist/task/context-silence.d.ts +39 -29
  102. package/dist/task/context-silence.js +35 -25
  103. package/dist/task/context-usage.d.ts +16 -9
  104. package/dist/task/context-usage.js +16 -9
  105. package/dist/task/contracts.d.ts +8 -4
  106. package/dist/task/contracts.js +25 -17
  107. package/dist/task/coverage-loop.d.ts +22 -18
  108. package/dist/task/coverage-loop.js +35 -30
  109. package/dist/task/critique-probes.d.ts +13 -14
  110. package/dist/task/critique-probes.js +50 -39
  111. package/dist/task/debug-log.d.ts +13 -5
  112. package/dist/task/debug-log.js +32 -20
  113. package/dist/task/decompose-fidelity.d.ts +11 -9
  114. package/dist/task/decompose-fidelity.js +38 -33
  115. package/dist/task/decompose-granularity.d.ts +41 -38
  116. package/dist/task/decompose-granularity.js +41 -38
  117. package/dist/task/deep-render-check.d.ts +22 -14
  118. package/dist/task/deep-render-check.js +40 -31
  119. package/dist/task/dropped-input.d.ts +12 -7
  120. package/dist/task/dropped-input.js +5 -2
  121. package/dist/task/enforce-attribution.d.ts +38 -47
  122. package/dist/task/enforce-attribution.js +46 -52
  123. package/dist/task/enforce-guidelines.d.ts +31 -20
  124. package/dist/task/enforce-guidelines.js +32 -21
  125. package/dist/task/enrichment.d.ts +7 -2
  126. package/dist/task/enrichment.js +26 -14
  127. package/dist/task/env-notes.d.ts +16 -7
  128. package/dist/task/env-notes.js +48 -31
  129. package/dist/task/env-template-closure.d.ts +4 -4
  130. package/dist/task/env-template-closure.js +42 -34
  131. package/dist/task/external-context.d.ts +28 -21
  132. package/dist/task/external-context.js +17 -12
  133. package/dist/task/failure-classifier.d.ts +4 -5
  134. package/dist/task/failure-classifier.js +6 -7
  135. package/dist/task/file-inventory.d.ts +15 -11
  136. package/dist/task/file-inventory.js +25 -22
  137. package/dist/task/final-gate-fix.d.ts +74 -86
  138. package/dist/task/final-gate-fix.js +97 -116
  139. package/dist/task/final-gate-progress.d.ts +29 -46
  140. package/dist/task/final-gate-progress.js +40 -51
  141. package/dist/task/final-gate.d.ts +64 -97
  142. package/dist/task/final-gate.js +192 -199
  143. package/dist/task/fix-child.d.ts +21 -27
  144. package/dist/task/fix-child.js +21 -27
  145. package/dist/task/foreign-path.d.ts +6 -5
  146. package/dist/task/foreign-path.js +0 -0
  147. package/dist/task/frozen-conflict.d.ts +9 -10
  148. package/dist/task/frozen-conflict.js +61 -64
  149. package/dist/task/frozen-path-guard.d.ts +35 -14
  150. package/dist/task/frozen-path-guard.js +56 -39
  151. package/dist/task/gate-child.d.ts +27 -28
  152. package/dist/task/gate-child.js +36 -35
  153. package/dist/task/gate-deps.d.ts +34 -27
  154. package/dist/task/gate-deps.js +169 -159
  155. package/dist/task/gate-tally.d.ts +77 -80
  156. package/dist/task/gate-tally.js +65 -68
  157. package/dist/task/git-state-guard.d.ts +15 -11
  158. package/dist/task/git-state-guard.js +76 -66
  159. package/dist/task/impl-widget.d.ts +25 -16
  160. package/dist/task/impl-widget.js +27 -17
  161. package/dist/task/implementation-thinking.d.ts +33 -31
  162. package/dist/task/implementation-thinking.js +5 -6
  163. package/dist/task/implementation-turn.d.ts +34 -31
  164. package/dist/task/implementation-turn.js +29 -27
  165. package/dist/task/inline-markdown.d.ts +20 -7
  166. package/dist/task/inline-markdown.js +15 -6
  167. package/dist/task/launch-config-gap.js +25 -39
  168. package/dist/task/launch-contract.d.ts +18 -21
  169. package/dist/task/launch-contract.js +28 -30
  170. package/dist/task/launch-manifest.d.ts +6 -2
  171. package/dist/task/launch-manifest.js +35 -34
  172. package/dist/task/ledger.js +16 -14
  173. package/dist/task/lint-fix.d.ts +6 -8
  174. package/dist/task/lint-fix.js +67 -69
  175. package/dist/task/loop-detector.d.ts +9 -8
  176. package/dist/task/loop-detector.js +16 -12
  177. package/dist/task/mid-run-input.d.ts +17 -15
  178. package/dist/task/mid-run-input.js +17 -15
  179. package/dist/task/orchestrator.d.ts +24 -28
  180. package/dist/task/orchestrator.js +62 -64
  181. package/dist/task/orientation.d.ts +18 -23
  182. package/dist/task/orientation.js +24 -31
  183. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  184. package/dist/task/owned-freeze-conflict.js +52 -85
  185. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  186. package/dist/task/owned-freeze-reassign.js +41 -61
  187. package/dist/task/parsers.d.ts +4 -2
  188. package/dist/task/parsers.js +4 -4
  189. package/dist/task/phases.d.ts +41 -48
  190. package/dist/task/phases.js +179 -248
  191. package/dist/task/plan-io.d.ts +6 -7
  192. package/dist/task/plan-io.js +6 -7
  193. package/dist/task/plan-orchestrator.d.ts +10 -8
  194. package/dist/task/plan-orchestrator.js +14 -10
  195. package/dist/task/plan-prompts.d.ts +6 -5
  196. package/dist/task/plan-prompts.js +6 -5
  197. package/dist/task/plan-readonly.d.ts +4 -5
  198. package/dist/task/plan-readonly.js +4 -5
  199. package/dist/task/plan-rounds.d.ts +17 -29
  200. package/dist/task/plan-rounds.js +21 -34
  201. package/dist/task/plan-session.d.ts +58 -72
  202. package/dist/task/plan-session.js +61 -83
  203. package/dist/task/probe-gaming.d.ts +28 -27
  204. package/dist/task/probe-gaming.js +0 -0
  205. package/dist/task/prohibition-probe.d.ts +14 -16
  206. package/dist/task/prompts.d.ts +3 -4
  207. package/dist/task/prompts.js +17 -26
  208. package/dist/task/qa-transcript.d.ts +15 -22
  209. package/dist/task/qa-transcript.js +15 -21
  210. package/dist/task/question-box.d.ts +17 -13
  211. package/dist/task/question-box.js +19 -15
  212. package/dist/task/question-dedup.d.ts +6 -7
  213. package/dist/task/question-dedup.js +13 -14
  214. package/dist/task/question-dialog.d.ts +22 -32
  215. package/dist/task/question-dialog.js +22 -32
  216. package/dist/task/question-source.d.ts +18 -44
  217. package/dist/task/question-source.js +22 -51
  218. package/dist/task/refuted-constraint.d.ts +11 -31
  219. package/dist/task/refuted-constraint.js +27 -51
  220. package/dist/task/regenerable-artifacts.d.ts +12 -31
  221. package/dist/task/regenerable-artifacts.js +12 -31
  222. package/dist/task/render-check.d.ts +11 -22
  223. package/dist/task/render-check.js +33 -46
  224. package/dist/task/repo-health-check.d.ts +10 -14
  225. package/dist/task/repo-health-check.js +17 -23
  226. package/dist/task/requirements.d.ts +38 -71
  227. package/dist/task/requirements.js +78 -126
  228. package/dist/task/research-fanout-budget.d.ts +51 -88
  229. package/dist/task/research-fanout-budget.js +51 -88
  230. package/dist/task/research-worker.d.ts +29 -39
  231. package/dist/task/research-worker.js +37 -61
  232. package/dist/task/resume-gap.d.ts +14 -15
  233. package/dist/task/root-cause-repair.d.ts +9 -9
  234. package/dist/task/root-cause-repair.js +28 -40
  235. package/dist/task/run-bracket.d.ts +10 -13
  236. package/dist/task/run-end.d.ts +12 -22
  237. package/dist/task/run-end.js +8 -16
  238. package/dist/task/run-final-gate.d.ts +19 -21
  239. package/dist/task/run-final-gate.js +62 -80
  240. package/dist/task/runner-globs.d.ts +12 -13
  241. package/dist/task/runner-globs.js +12 -13
  242. package/dist/task/runner-resolve.d.ts +9 -9
  243. package/dist/task/runner-resolve.js +22 -23
  244. package/dist/task/script-escape.d.ts +10 -12
  245. package/dist/task/script-escape.js +13 -14
  246. package/dist/task/serve-entry.d.ts +1 -1
  247. package/dist/task/serve-entry.js +22 -25
  248. package/dist/task/service-blocks.js +4 -2
  249. package/dist/task/shipped-source.d.ts +11 -29
  250. package/dist/task/shipped-source.js +11 -29
  251. package/dist/task/skip-escape.js +10 -14
  252. package/dist/task/spec-urls.d.ts +26 -65
  253. package/dist/task/spec-urls.js +26 -65
  254. package/dist/task/spec-validation.d.ts +17 -20
  255. package/dist/task/spec-validation.js +17 -20
  256. package/dist/task/stall-detector.d.ts +23 -30
  257. package/dist/task/stall-detector.js +23 -30
  258. package/dist/task/stream-watchdog.d.ts +14 -12
  259. package/dist/task/stream-watchdog.js +14 -12
  260. package/dist/task/substitution-probe.d.ts +17 -20
  261. package/dist/task/substitution-probe.js +17 -20
  262. package/dist/task/task-gates.d.ts +36 -41
  263. package/dist/task/task-gates.js +95 -106
  264. package/dist/task/task-io.d.ts +4 -4
  265. package/dist/task/task-io.js +4 -4
  266. package/dist/task/task-parsers.js +4 -3
  267. package/dist/task/task-provenance.d.ts +2 -2
  268. package/dist/task/task-provenance.js +11 -13
  269. package/dist/task/task-types.d.ts +4 -3
  270. package/dist/task/terminal-outcome.d.ts +14 -16
  271. package/dist/task/terminal-outcome.js +12 -14
  272. package/dist/task/test-assembly.d.ts +13 -20
  273. package/dist/task/test-assembly.js +13 -20
  274. package/dist/task/timings.d.ts +5 -3
  275. package/dist/task/timings.js +5 -3
  276. package/dist/task/title-label.d.ts +9 -4
  277. package/dist/task/title-label.js +9 -4
  278. package/dist/task/type-only-answer.d.ts +44 -52
  279. package/dist/task/type-only-answer.js +44 -52
  280. package/dist/task/unfailable-command.d.ts +18 -24
  281. package/dist/task/unfailable-command.js +21 -27
  282. package/dist/task/unknown-routing.d.ts +10 -4
  283. package/dist/task/unknown-routing.js +10 -4
  284. package/dist/task/user-directives.d.ts +5 -8
  285. package/dist/task/user-directives.js +5 -8
  286. package/dist/task/verify-quality.d.ts +18 -22
  287. package/dist/task/verify-quality.js +45 -46
  288. package/dist/task/verify-reconcile.d.ts +15 -10
  289. package/dist/task/verify-reconcile.js +45 -43
  290. package/dist/task/verify-resolution.d.ts +24 -20
  291. package/dist/task/verify-resolution.js +51 -50
  292. package/dist/task/verify-work.d.ts +59 -66
  293. package/dist/task/verify-work.js +101 -138
  294. package/dist/task/widget.d.ts +15 -14
  295. package/dist/task/widget.js +22 -17
  296. package/dist/task/wiring-claims.d.ts +25 -32
  297. package/dist/task/wiring-claims.js +30 -35
  298. package/dist/task/write-guard.d.ts +39 -39
  299. package/dist/task/write-guard.js +48 -51
  300. package/dist/task/yolo.d.ts +34 -30
  301. package/dist/task/yolo.js +42 -37
  302. package/dist/workers/abstention.d.ts +21 -41
  303. package/dist/workers/abstention.js +27 -48
  304. package/dist/workers/brave-search.d.ts +4 -3
  305. package/dist/workers/brave-search.js +5 -2
  306. package/dist/workers/brave-warning.d.ts +7 -4
  307. package/dist/workers/brave-warning.js +19 -7
  308. package/dist/workers/ddg-search.d.ts +6 -6
  309. package/dist/workers/ddg-search.js +18 -12
  310. package/dist/workers/docs-cache.js +5 -2
  311. package/dist/workers/docs-chunk.d.ts +30 -37
  312. package/dist/workers/docs-chunk.js +37 -41
  313. package/dist/workers/docs-core.d.ts +28 -44
  314. package/dist/workers/docs-core.js +25 -44
  315. package/dist/workers/docs-index.js +4 -3
  316. package/dist/workers/docs-lookup.d.ts +15 -22
  317. package/dist/workers/docs-lookup.js +12 -21
  318. package/dist/workers/docs-project.d.ts +15 -9
  319. package/dist/workers/docs-project.js +17 -10
  320. package/dist/workers/docs-resolve.d.ts +19 -20
  321. package/dist/workers/docs-resolve.js +35 -32
  322. package/dist/workers/docs-retrieve.d.ts +5 -6
  323. package/dist/workers/docs-retrieve.js +18 -15
  324. package/dist/workers/exa-search.d.ts +9 -6
  325. package/dist/workers/exa-search.js +23 -12
  326. package/dist/workers/fetch-core.d.ts +13 -16
  327. package/dist/workers/fetch-core.js +23 -23
  328. package/dist/workers/focused-extractor.d.ts +12 -12
  329. package/dist/workers/focused-extractor.js +16 -19
  330. package/dist/workers/html-clean.js +24 -14
  331. package/dist/workers/http-request.d.ts +28 -20
  332. package/dist/workers/http-request.js +22 -17
  333. package/dist/workers/npm-version.d.ts +28 -11
  334. package/dist/workers/npm-version.js +24 -15
  335. package/dist/workers/phantom-imports.d.ts +15 -12
  336. package/dist/workers/phantom-imports.js +30 -24
  337. package/dist/workers/pi-worker-core.d.ts +69 -71
  338. package/dist/workers/pi-worker-core.js +100 -109
  339. package/dist/workers/pi-worker-docs.d.ts +24 -19
  340. package/dist/workers/pi-worker-docs.js +67 -76
  341. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  342. package/dist/workers/pi-worker-fetch.js +27 -19
  343. package/dist/workers/pi-worker-search.js +12 -8
  344. package/dist/workers/pi-worker.d.ts +9 -4
  345. package/dist/workers/pi-worker.js +21 -14
  346. package/dist/workers/reasoning-warning.d.ts +18 -17
  347. package/dist/workers/reasoning-warning.js +22 -20
  348. package/dist/workers/research-cache.js +50 -78
  349. package/dist/workers/search-core.js +7 -5
  350. package/dist/workers/search-types.d.ts +10 -9
  351. package/dist/workers/search-types.js +9 -8
  352. package/dist/workers/session-hint.d.ts +13 -14
  353. package/dist/workers/session-hint.js +8 -9
  354. package/dist/workers/shared.d.ts +21 -25
  355. package/dist/workers/shared.js +0 -0
  356. package/dist/workers/single-read-extension.d.ts +14 -7
  357. package/dist/workers/single-read-extension.js +14 -7
  358. package/dist/workers/single-read-guard.d.ts +25 -28
  359. package/dist/workers/single-read-guard.js +32 -32
  360. package/dist/workers/typeonly-log.d.ts +12 -9
  361. package/dist/workers/typeonly-log.js +29 -33
  362. package/dist/workers/worker-channels.d.ts +15 -23
  363. package/dist/workers/worker-channels.js +15 -23
  364. package/dist/workers/worker-failure.d.ts +38 -46
  365. package/dist/workers/worker-failure.js +31 -39
  366. package/dist/workers/worker-kill.d.ts +25 -26
  367. package/dist/workers/worker-kill.js +16 -19
  368. package/dist/workers/worker-profiles.d.ts +43 -53
  369. package/dist/workers/worker-profiles.js +30 -38
  370. package/package.json +10 -8
@@ -1,29 +1,24 @@
1
1
  /**
2
- * docs-chunk — cutting source text into retrievable chunks, for every corpus the
3
- * docs Worker tool indexes.
2
+ * docs-chunk — cutting source text into retrievable chunks, for both corpora the
3
+ * docs Worker tool indexes: an npm package's `.d.ts` + README (docs-index.ts),
4
+ * and the local project's own `.ts`/`.tsx` (docs-project.ts).
4
5
  *
5
- * There are two corpora an npm package's `.d.ts` + README, and the local
6
- * project's own `.ts`/`.tsx` and they were chunked by two copies of this code.
7
- * Not similar code: the same chunk-split regex, the same size cap, byte-identical
8
- * `chunkDts`/`chunkTs` bodies, and byte-identical `splitAtMatches`/`sliceBytes`,
9
- * in `docs-index.ts` and `docs-project.ts`. One copy had tests; the other
10
- * (`docs-project.ts`, 319 lines) had no test file at all and was only ever
11
- * reached incidentally through the worker's own suite.
6
+ * The chunk boundary is load-bearing for retrieval: a chunk that splits a
7
+ * declaration in half matches on neither half's terms, so one boundary rule for
8
+ * both corpora is the point of this module.
12
9
  *
13
- * The chunk boundary is load-bearing for retrieval quality a chunk that splits
14
- * a declaration in half retrieves as neither so having it in two places was two
15
- * places for it to drift.
16
- *
17
- * What is NOT unified: the two INDEX bodies. They key on genuinely different
18
- * provenance (a package is name+version with a content hash and keeps its old
19
- * versions; the project is a cwd key with a max-mtime version and drops its old
20
- * ones on every re-index), and collapsing them would change one of those
21
- * behaviours rather than describe them.
10
+ * What is NOT shared: the two INDEX bodies. They key on genuinely different
11
+ * provenance. A package is `(name, version)` with a content hash, and re-indexing
12
+ * runs `DELETE FROM chunks WHERE name = ? AND version = ?`, so older versions
13
+ * survive. The project is a cwd-hash name with a max-mtime version, and
14
+ * re-indexing runs `DELETE FROM chunks WHERE name = ?`, dropping every older
15
+ * version. Collapsing them would change one of those behaviours, not describe it.
22
16
  */
23
17
  /**
24
- * Chunk ceiling. Chosen against the retrieval budget: chunks are assembled into
25
- * a fixed character budget for the extraction child, so a chunk larger than this
26
- * would crowd out every other result.
18
+ * Chunk ceiling, in UTF-8 bytes. Sized against the retrieval budget: retrieved
19
+ * chunks are assembled into `RETRIEVE_CONTENT_BUDGET` (24,000 characters) before
20
+ * going to the extraction child, so this caps any one chunk at about a third of
21
+ * what the child will ever see.
27
22
  */
28
23
  export const MAX_CHUNK_BYTES = 8 * 1024;
29
24
  /**
@@ -47,8 +42,10 @@ export function splitAtMatches(text, re) {
47
42
  if (m.index > lastIndex)
48
43
  parts.push(text.slice(lastIndex, m.index));
49
44
  lastIndex = m.index;
50
- // Advance by ONE, not by the match length: the next declaration can begin
51
- // inside what this match consumed (`export default async function`).
45
+ // Advance by ONE, not by the match length. The regex's trailing `\s+` can
46
+ // span a newline, so the next line-anchored declaration may start INSIDE
47
+ // what this match consumed: `export\nfunction a(){}` is two chunks here
48
+ // and one if the scan resumes past the match.
52
49
  re.lastIndex = m.index + 1;
53
50
  }
54
51
  if (lastIndex < text.length)
@@ -59,19 +56,17 @@ export function splitAtMatches(text, re) {
59
56
  * Cut a string into pieces of at most `maxBytes` UTF-8 bytes, never splitting a
60
57
  * character.
61
58
  *
62
- * The cut point is walked BACK to a UTF-8 lead byte first. Both copies of this
63
- * function used to cut at exactly `maxBytes` and rely on
64
- * `Buffer.toString('utf8')` to tidy up, which it does not: decoding a buffer that
65
- * ends mid-character yields a U+FFFD replacement character. That replacement is
66
- * 3 bytes wide, so measuring the advance by the decoded slice's byte length then
67
- * skipped PAST the straddling character. A `€`-dense chunk came out as
68
- * `€€€�€€€�…` — corrupted, and one character shorter per slice.
59
+ * The cut point is walked BACK to a UTF-8 lead byte first. Cutting at exactly
60
+ * `maxBytes` and letting `Buffer.toString('utf8')` tidy up does not work: decoding
61
+ * a buffer that ends mid-character yields U+FFFD. That replacement is 3 bytes
62
+ * wide, so the decoded slice measures LONGER than the cut — a 100-byte cut of
63
+ * `€`-dense text decodes to 102 bytes and advancing by the decoded length then
64
+ * skips past the straddling character entirely.
69
65
  *
70
66
  * It matters beyond looking wrong: a chunk is quoted back as an `<excerpt>` and
71
- * checked verbatim against the source, and an excerpt carrying a replacement
72
- * character can never be found, so the answer is flagged as a possible
73
- * hallucination. Only reachable on non-ASCII text past the 8 KB chunk ceiling,
74
- * which is why two copies of it survived untested.
67
+ * checked verbatim against the source (`excerptVerified`), and an excerpt carrying
68
+ * a replacement character can never be found, so the answer is flagged as a
69
+ * possible hallucination. Only reachable on non-ASCII text past the chunk ceiling.
75
70
  */
76
71
  export function sliceBytes(s, maxBytes) {
77
72
  const out = [];
@@ -82,8 +77,9 @@ export function sliceBytes(s, maxBytes) {
82
77
  let end = maxBytes;
83
78
  while (end > 0 && (buf[end] & 0xc0) === 0x80)
84
79
  end--;
85
- // A single character wider than the whole cap cannot be placed. Cut
86
- // anyway rather than loop forever; unreachable for any cap >= 4.
80
+ // A single character wider than the whole cap cannot be placed. Cut anyway
81
+ // rather than loop forever this is the one path that DOES emit U+FFFD.
82
+ // Unreachable for any cap >= 4: the widest UTF-8 character is 4 bytes.
87
83
  if (end === 0)
88
84
  end = maxBytes;
89
85
  out.push(buf.subarray(0, end).toString('utf8'));
@@ -97,11 +93,11 @@ export function sliceBytes(s, maxBytes) {
97
93
  * Chunk a declaration file (`.d.ts`, `.ts`, `.tsx`), one chunk per declaration,
98
94
  * each labelled with the file it came from.
99
95
  *
100
- * `relPath` is a MODEL-FACING label and is used exactly as given — the npm path
101
- * normalises it to POSIX first so an index is identical across platforms, while
102
- * the project path keeps the native separator. It is never re-joined to the
103
- * filesystem, so neither choice is wrong; passing it through keeps that decision
104
- * with the caller that has a reason for it.
96
+ * `relPath` is a MODEL-FACING label and is used exactly as given. docs-index.ts
97
+ * normalises it to POSIX (`.replace(/\\/g, '/')`) so a package index is identical
98
+ * across platforms; docs-project.ts passes `path.relative` through with the native
99
+ * separator. It is never re-joined to the filesystem, so neither is wrong this
100
+ * leaves the choice with the caller that has a reason for it.
105
101
  */
106
102
  export function chunkDeclarations(content, relPath) {
107
103
  const chunks = [];
@@ -11,9 +11,9 @@ import { type ExcerptVerification } from '../shared/child-output.js';
11
11
  * what the version is grounded in instead of leaving it buried in tool details.
12
12
  * - 'declared-range': install was pinned to the project's own package.json range
13
13
  * (the resolved version therefore matches project intent).
14
- * - 'npm-latest': nothing in the project declared the dep, so the install fell
15
- * back to whatever npm tags `latest` — which may be a newer MAJOR than the
16
- * project targets (this is what a scaffolding task hits, and needs a banner).
14
+ * - 'npm-latest': nothing usable in the project declared the dep, so the install
15
+ * fell back to whatever npm tags `latest` — which may be a newer MAJOR than the
16
+ * project targets, which is what the banner warns about.
17
17
  */
18
18
  export interface AutoInstallPin {
19
19
  source: 'declared-range' | 'npm-latest';
@@ -74,9 +74,9 @@ export interface DocsRawInput {
74
74
  export interface DocsFocusedResult {
75
75
  /**
76
76
  * The child's answer — EMPTY when `failure` is set. A failed child's stdout is never
77
- * parsed as an answer (it used to be: `parseChildOutput` returns the whole trimmed
78
- * stdout when there is no `<answer>` tag, so a crashed child's error dump was handed
79
- * to phaseAutoAnswer as if it were package documentation).
77
+ * parsed as an answer. `parseChildOutput` returns the whole trimmed stdout when
78
+ * there is no `<answer>` tag, so parsing one hands a crashed child's error dump
79
+ * to phaseAutoAnswer as if it were package documentation.
80
80
  */
81
81
  answer: string;
82
82
  excerpt?: string;
@@ -117,9 +117,10 @@ export interface Declaration {
117
117
  * The names a declaration for `asked` can honestly live under, nearest first:
118
118
  * the package itself, its DefinitelyTyped package, and the terminal the type
119
119
  * resolution chain landed on. A project that uses Bun declares `@types/bun`, not
120
- * `bun`; asking only about the terminal `bun-types` finds nothing at all, which
121
- * is how 35 of run 20's 48 banners came to report on a package nobody asked
122
- * about.
120
+ * `bun`; asking only about the terminal `bun-types` finds nothing at all, so a
121
+ * banner keyed on the terminal would report on a package nobody asked about. The
122
+ * terminal is deduped: `declarationChain('hono', 'hono')` is
123
+ * `['hono', '@types/hono']`.
123
124
  */
124
125
  export declare function declarationChain(asked: string, resolved?: string): string[];
125
126
  /**
@@ -127,8 +128,8 @@ export declare function declarationChain(asked: string, resolved?: string): stri
127
128
  * dependency maps of `cwd`'s package.json. A USABLE declaration always wins;
128
129
  * only if none of the names has one does an unusable declaration (a dist-tag or
129
130
  * a non-registry protocol) come back, so the caller can tell "declared as
130
- * `latest`" apart from "not declared at all" — two different facts that used to
131
- * produce the same sentence. Returns null when no name appears anywhere, or the
131
+ * `latest`" apart from "not declared at all" — two different facts that would
132
+ * otherwise produce the same sentence. Returns null when no name appears anywhere, or the
132
133
  * package.json is missing or unparseable. Best-effort; never throws.
133
134
  */
134
135
  export declare function findDeclaration(names: string[], cwd: string): Declaration | null;
@@ -165,10 +166,9 @@ export declare function buildVersionBanner(pin: AutoInstallPin | undefined, reso
165
166
  export declare function getDocsModulesDir(): string;
166
167
  export declare function ensureDocsModulesDir(dir: string): void;
167
168
  /**
168
- * Options rather than a positional tail: `signal` and `versionRange` sat adjacent,
169
- * and reaching the range meant writing `undefined` into the signal slot which is
170
- * exactly how the primary acquisition path lost its abort signal while the hop path
171
- * kept it.
169
+ * An options object, not a positional tail. Two adjacent optionals mean reaching
170
+ * the second requires writing `undefined` into the firstand an abort signal
171
+ * dropped that way is not a type error, so nothing catches it.
172
172
  */
173
173
  export interface AutoInstallOptions {
174
174
  signal?: AbortSignal | undefined;
@@ -215,42 +215,25 @@ export interface AcquireInput {
215
215
  * `not_installed` install it — at the range the PROJECT declares when it declares
216
216
  * one — then resolve again from the install dir.
217
217
  *
218
- * One statement of the ladder, for both callers. It was written twice: inline in
219
- * `docsRaw` for the requested package, and in `tryResolveOrInstall` for each hop
220
- * of the type-redirect chain and the copies had drifted on all three things
221
- * that matter.
218
+ * ONE statement of the ladder, for both callers: `docsRaw` for the requested
219
+ * package, and `tryResolveOrInstall` for each hop of the type-redirect chain.
220
+ * Three things must come out the same on either path, and each is silent when it
221
+ * does not — no test fails, the answer just gets worse:
222
222
  *
223
- * - The abort signal. The hop copy passed it; the primary copy passed a bare
224
- * `undefined` placeholder to reach the fourth positional, while
225
- * `DocsRawInput.signal` was honoured on either side of that call. So a user
226
- * cancel during the MAIN `npm install` of a model-chosen package was not
227
- * delivered. `runAutoInstall` takes an options object now, so a hole like that
228
- * cannot be typed.
229
- * - The version pin. `findDeclaredRange` had exactly one call site — the primary
230
- * copy. The hop copy installed `latest` unconditionally, on the hop most likely
231
- * to be the declared one: `declarationChain` exists precisely because "a
232
- * project that uses Bun declares `@types/bun`, not `bun`".
233
- * - The provenance. `autoInstalled`/`autoInstallPin` were locals of `docsRaw`, so
234
- * a package acquired only through a hop reported neither and got no version
235
- * banner.
223
+ * - the abort signal reaching the `npm install`, so a user cancel is delivered;
224
+ * - the version pin, so a hop installs the project's declared range rather than
225
+ * `latest` and the hop is the LIKELIER one to be declared, since a project
226
+ * that uses Bun declares `@types/bun`, not `bun`;
227
+ * - the provenance (`autoInstalled` and the pin), without which a package
228
+ * acquired only through a hop gets no version banner.
236
229
  *
237
- * CONTEXT.md records the redirect WALK as unified (`resolveTypeSource`) and its
238
- * `resolveHop` seam as "the one thing its two call sites disagree about". They
239
- * should disagree only about WHETHER to install, never about HOW.
230
+ * The redirect WALK itself is `resolveTypeSource` in docs-resolve.ts. Its two call
231
+ * sites should differ only about WHETHER to install, never about HOW.
240
232
  */
241
233
  export declare function acquirePackage(input: AcquireInput): Promise<AcquireOutcome>;
242
234
  export declare function docsRaw(input: DocsRawInput): Promise<DocsRawResult>;
243
235
  export declare function docsFocused(input: DocsFocusedInput): Promise<DocsFocusedResult>;
244
236
  export declare function buildPrompt(pkg: ResolvedPackage, query: string, content: string): string;
245
- /** Thin wrapper so existing callers using the pkg-based signature still work. */
246
- /**
247
- * The provenance header a docs answer carries. Takes the HEADER, not a package:
248
- * the whole body is one string, and the project-source path — which has no
249
- * package — used to fabricate a `ResolvedPackage`
250
- * (`{name, version: 'local', root, entryDts: null, readme: null}`) purely to make
251
- * this call compile, with three of the five fields existing only for that.
252
- */
253
- /** The header for an npm package answer. */
254
237
  /**
255
238
  * The PACKAGE corpus row: an npm package's `.d.ts` + README chunks.
256
239
  *
@@ -258,4 +241,5 @@ export declare function buildPrompt(pkg: ResolvedPackage, query: string, content
258
241
  * prompt and the header name the exact `name@version` that was read.
259
242
  */
260
243
  export declare function packageCorpus(pkg: ResolvedPackage): DocsCorpus;
244
+ /** The provenance line that leads a package answer. */
261
245
  export declare function packageHeader(pkg: ResolvedPackage): string;
@@ -10,6 +10,7 @@ import { npmVersionLookup as defaultNpmVersionLookup } from './npm-version.js';
10
10
  import { runChild } from '../shared/child-process.js';
11
11
  import { docsLookup } from './docs-lookup.js';
12
12
  import { buildExtractionPrompt } from './abstention.js';
13
+ import {} from '../shared/child-output.js';
13
14
  import { groupThinkingArgs } from '../config/reasoning-args.js';
14
15
  const DEFAULT_LIMIT = PACKAGE_RETRIEVE_LIMIT;
15
16
  const DEFAULT_BUDGET = RETRIEVE_CONTENT_BUDGET;
@@ -45,9 +46,10 @@ function isUsableRange(range) {
45
46
  * The names a declaration for `asked` can honestly live under, nearest first:
46
47
  * the package itself, its DefinitelyTyped package, and the terminal the type
47
48
  * resolution chain landed on. A project that uses Bun declares `@types/bun`, not
48
- * `bun`; asking only about the terminal `bun-types` finds nothing at all, which
49
- * is how 35 of run 20's 48 banners came to report on a package nobody asked
50
- * about.
49
+ * `bun`; asking only about the terminal `bun-types` finds nothing at all, so a
50
+ * banner keyed on the terminal would report on a package nobody asked about. The
51
+ * terminal is deduped: `declarationChain('hono', 'hono')` is
52
+ * `['hono', '@types/hono']`.
51
53
  */
52
54
  export function declarationChain(asked, resolved) {
53
55
  const out = [asked];
@@ -63,8 +65,8 @@ export function declarationChain(asked, resolved) {
63
65
  * dependency maps of `cwd`'s package.json. A USABLE declaration always wins;
64
66
  * only if none of the names has one does an unusable declaration (a dist-tag or
65
67
  * a non-registry protocol) come back, so the caller can tell "declared as
66
- * `latest`" apart from "not declared at all" — two different facts that used to
67
- * produce the same sentence. Returns null when no name appears anywhere, or the
68
+ * `latest`" apart from "not declared at all" — two different facts that would
69
+ * otherwise produce the same sentence. Returns null when no name appears anywhere, or the
68
70
  * package.json is missing or unparseable. Best-effort; never throws.
69
71
  */
70
72
  export function findDeclaration(names, cwd) {
@@ -187,9 +189,7 @@ export async function runAutoInstall(spawn, packageName, opts = {}) {
187
189
  // `--ignore-scripts` is not optional here. The package NAME is model-chosen —
188
190
  // it comes out of a worker's question, or out of a `/// <reference types="X" />`
189
191
  // line in someone else's declaration file — so a hallucinated or typosquatted
190
- // name would otherwise run its preinstall/postinstall as the user. This cache
191
- // has already run install hooks for `node`, `argon2`, `onnxruntime-node` and
192
- // `sharp`, next to fetched names like `app.ts`, `pkg.json` and `tsconfig.json`.
192
+ // name would otherwise run its preinstall/postinstall hooks as the user.
193
193
  // Nothing is lost: the docs worker only ever READS `.d.ts` files and the README
194
194
  // out of the installed tree, and those ship in the tarball.
195
195
  const result = await runChild(spawn, {
@@ -210,28 +210,20 @@ export async function runAutoInstall(spawn, packageName, opts = {}) {
210
210
  * `not_installed` install it — at the range the PROJECT declares when it declares
211
211
  * one — then resolve again from the install dir.
212
212
  *
213
- * One statement of the ladder, for both callers. It was written twice: inline in
214
- * `docsRaw` for the requested package, and in `tryResolveOrInstall` for each hop
215
- * of the type-redirect chain and the copies had drifted on all three things
216
- * that matter.
213
+ * ONE statement of the ladder, for both callers: `docsRaw` for the requested
214
+ * package, and `tryResolveOrInstall` for each hop of the type-redirect chain.
215
+ * Three things must come out the same on either path, and each is silent when it
216
+ * does not — no test fails, the answer just gets worse:
217
217
  *
218
- * - The abort signal. The hop copy passed it; the primary copy passed a bare
219
- * `undefined` placeholder to reach the fourth positional, while
220
- * `DocsRawInput.signal` was honoured on either side of that call. So a user
221
- * cancel during the MAIN `npm install` of a model-chosen package was not
222
- * delivered. `runAutoInstall` takes an options object now, so a hole like that
223
- * cannot be typed.
224
- * - The version pin. `findDeclaredRange` had exactly one call site — the primary
225
- * copy. The hop copy installed `latest` unconditionally, on the hop most likely
226
- * to be the declared one: `declarationChain` exists precisely because "a
227
- * project that uses Bun declares `@types/bun`, not `bun`".
228
- * - The provenance. `autoInstalled`/`autoInstallPin` were locals of `docsRaw`, so
229
- * a package acquired only through a hop reported neither and got no version
230
- * banner.
218
+ * - the abort signal reaching the `npm install`, so a user cancel is delivered;
219
+ * - the version pin, so a hop installs the project's declared range rather than
220
+ * `latest` and the hop is the LIKELIER one to be declared, since a project
221
+ * that uses Bun declares `@types/bun`, not `bun`;
222
+ * - the provenance (`autoInstalled` and the pin), without which a package
223
+ * acquired only through a hop gets no version banner.
231
224
  *
232
- * CONTEXT.md records the redirect WALK as unified (`resolveTypeSource`) and its
233
- * `resolveHop` seam as "the one thing its two call sites disagree about". They
234
- * should disagree only about WHETHER to install, never about HOW.
225
+ * The redirect WALK itself is `resolveTypeSource` in docs-resolve.ts. Its two call
226
+ * sites should differ only about WHETHER to install, never about HOW.
235
227
  */
236
228
  export async function acquirePackage(input) {
237
229
  const { name, cwd, spawn, resolvePackage, signal } = input;
@@ -285,10 +277,9 @@ async function tryResolveOrInstall(name, cwd, spawn, resolvePackage, signal, onA
285
277
  * hops resolve through the auto-installing lookup, so a declaration package that is
286
278
  * declared but not yet on disk is fetched rather than abandoned. */
287
279
  async function resolveTypeSourceForDocs(pkg, requested, cwd, spawn, resolvePackage, signal) {
288
- // A package acquired ONLY through a hop used to report neither `autoInstalled`
289
- // nor a pin, so `pi-worker-docs` emitted no version banner for it — while the
290
- // banner's own text ("only its types are, as `@types/bun` `^1.2`") claims a
291
- // range as provenance. Report the last hop that actually installed.
280
+ // A package acquired ONLY through a hop reports neither `autoInstalled` nor a
281
+ // pin unless this runs, so pi-worker-docs would emit no version banner for it.
282
+ // Report the last hop that actually installed.
292
283
  let installed = false;
293
284
  let pin;
294
285
  const out = await resolveTypeSource(pkg, extractParentPackage(requested), next => tryResolveOrInstall(next, cwd, spawn, resolvePackage, signal, hopPin => {
@@ -317,8 +308,7 @@ export async function docsRaw(input) {
317
308
  }).catch(() => null);
318
309
  // Step 1: acquire the package — resolve, or install-at-the-declared-range and
319
310
  // resolve again. The ladder is `acquirePackage`; this maps its stages onto the
320
- // rich error results the docs tool reports. `input.signal` now reaches the
321
- // install, which it never did while the range was a fourth positional.
311
+ // rich error results the docs tool reports.
322
312
  const got = await acquirePackage({
323
313
  name: requested,
324
314
  cwd: input.cwd,
@@ -598,16 +588,6 @@ export function buildPrompt(pkg, query, content) {
598
588
  content
599
589
  });
600
590
  }
601
- // ─── Backward-compatible wrappers (thin — delegates to shared/) ─────────────
602
- /** Thin wrapper so existing callers using the pkg-based signature still work. */
603
- /**
604
- * The provenance header a docs answer carries. Takes the HEADER, not a package:
605
- * the whole body is one string, and the project-source path — which has no
606
- * package — used to fabricate a `ResolvedPackage`
607
- * (`{name, version: 'local', root, entryDts: null, readme: null}`) purely to make
608
- * this call compile, with three of the five fields existing only for that.
609
- */
610
- /** The header for an npm package answer. */
611
591
  /**
612
592
  * The PACKAGE corpus row: an npm package's `.d.ts` + README chunks.
613
593
  *
@@ -622,6 +602,7 @@ export function packageCorpus(pkg) {
622
602
  abortedMessage: 'Docs lookup aborted.'
623
603
  };
624
604
  }
605
+ /** The provenance line that leads a package answer. */
625
606
  export function packageHeader(pkg) {
626
607
  return `Per ${pkg.name}@${pkg.version}:`;
627
608
  }
@@ -78,9 +78,10 @@ function ingestBody(cache, pkg, contentHash) {
78
78
  let filesIngested = 0;
79
79
  const insertChunk = cache.db.prepare('INSERT INTO chunks (name, version, file_path, kind, content) VALUES (?, ?, ?, ?, ?)');
80
80
  for (const abs of files.dts) {
81
- // Store the file identifier POSIX-style so indexed docs are identical
82
- // across platforms (this value is a model-facing label, never re-joined
83
- // to the filesystem node reads forward slashes fine on Windows too).
81
+ // Normalise the separator before storing, so the same package indexes to
82
+ // the same rows whatever built the path. The value is a MODEL-FACING
83
+ // label: chunkDeclarations turns it into the chunk's `// <path>` header,
84
+ // and nothing ever joins it back to the filesystem.
84
85
  const rel = path.relative(pkg.root, abs).replace(/\\/g, '/');
85
86
  let raw;
86
87
  try {
@@ -1,28 +1,20 @@
1
1
  /**
2
2
  * The docs TAIL — concatenate the chunks, extract against them, verify the
3
- * citation, format the answer — written once, with the corpus as a row.
3
+ * citation, format the answer — written once, with the corpus as a row. Its three
4
+ * callers are pi-worker-docs' project arm, its package arm, and `docsFocused` in
5
+ * docs-core.
4
6
  *
5
- * WHY. This sequence existed three times: the project-source arm of
6
- * `pi-worker-docs`, its package arm, and `docsFocused` in `docs-core`. The fetch
7
- * channel proves the shape is avoidable`fetchFocused` is one core and
8
- * `pi-worker-fetch`'s `run` is 60 lines, while the docs registration was 293 for
9
- * the same job over two corpora.
10
- *
11
- * The copies had drifted, in the place hand-flattening always drifts: the
12
- * package arm's ERROR path dropped `autoInstallPin`, which both of its sibling
13
- * paths keep — so a package that was auto-installed and then failed to re-resolve
14
- * lost the `versionSource`/`declaredRange` provenance the last defect in this
15
- * area was about.
16
- *
17
- * A CORPUS is what genuinely varies: the prompt, the header the answer is
18
- * introduced by, and what an abort of it is called. Everything a corpus does NOT
19
- * vary — where the content comes from, the version banner, the type-only
20
- * detector, the details bag — stays with its caller, because those differ in kind
21
- * and not in value.
7
+ * A CORPUS is exactly what varies between them, and it is three fields: the
8
+ * prompt, the header the answer is introduced by, and what an abort is called.
9
+ * Everything a corpus does NOT varywhere the content comes from, the version
10
+ * banner, the type-only detector, the details bag stays with the caller,
11
+ * because those differ in kind rather than in value.
22
12
  */
23
13
  import type { SpawnFn } from '../shared/child-process.js';
24
14
  import { type FocusedAnswer, type FocusedFailure } from './focused-extractor.js';
25
- /** The two corpora a docs lookup can read. A third (`page`) already has a prompt. */
15
+ /** The two corpora a docs lookup can read. A fetched `page` is a third corpus in
16
+ * spirit, but it lives on the fetch channel: fetch-core builds its own prompt and
17
+ * never comes through here. */
26
18
  export type DocsCorpusId = 'package' | 'project';
27
19
  export interface DocsCorpus {
28
20
  id: DocsCorpusId;
@@ -65,8 +57,9 @@ export type DocsLookup = {
65
57
  /**
66
58
  * Run one docs lookup over already-retrieved chunks.
67
59
  *
68
- * The citation is verified against exactly the text that was prompted with the
69
- * concatenation, not a superset. (`fetch` is the one site that verifies against a
70
- * superset; see `FocusedRequest.verifyAgainst`.)
60
+ * The citation is verified against exactly the text that was prompted with: the
61
+ * `\n\n`-joined chunks are passed as BOTH the prompt content and `verifyAgainst`.
62
+ * fetch-core is the only call site in this repo that passes a superset instead
63
+ * see `FocusedRequest.verifyAgainst`.
71
64
  */
72
65
  export declare function docsLookup(input: DocsLookupInput): Promise<DocsLookup>;
@@ -1,33 +1,24 @@
1
1
  /**
2
2
  * The docs TAIL — concatenate the chunks, extract against them, verify the
3
- * citation, format the answer — written once, with the corpus as a row.
3
+ * citation, format the answer — written once, with the corpus as a row. Its three
4
+ * callers are pi-worker-docs' project arm, its package arm, and `docsFocused` in
5
+ * docs-core.
4
6
  *
5
- * WHY. This sequence existed three times: the project-source arm of
6
- * `pi-worker-docs`, its package arm, and `docsFocused` in `docs-core`. The fetch
7
- * channel proves the shape is avoidable`fetchFocused` is one core and
8
- * `pi-worker-fetch`'s `run` is 60 lines, while the docs registration was 293 for
9
- * the same job over two corpora.
10
- *
11
- * The copies had drifted, in the place hand-flattening always drifts: the
12
- * package arm's ERROR path dropped `autoInstallPin`, which both of its sibling
13
- * paths keep — so a package that was auto-installed and then failed to re-resolve
14
- * lost the `versionSource`/`declaredRange` provenance the last defect in this
15
- * area was about.
16
- *
17
- * A CORPUS is what genuinely varies: the prompt, the header the answer is
18
- * introduced by, and what an abort of it is called. Everything a corpus does NOT
19
- * vary — where the content comes from, the version banner, the type-only
20
- * detector, the details bag — stays with its caller, because those differ in kind
21
- * and not in value.
7
+ * A CORPUS is exactly what varies between them, and it is three fields: the
8
+ * prompt, the header the answer is introduced by, and what an abort is called.
9
+ * Everything a corpus does NOT varywhere the content comes from, the version
10
+ * banner, the type-only detector, the details bag stays with the caller,
11
+ * because those differ in kind rather than in value.
22
12
  */
23
13
  import { formatResultText } from '../shared/child-output.js';
24
14
  import { runFocusedExtraction } from './focused-extractor.js';
25
15
  /**
26
16
  * Run one docs lookup over already-retrieved chunks.
27
17
  *
28
- * The citation is verified against exactly the text that was prompted with the
29
- * concatenation, not a superset. (`fetch` is the one site that verifies against a
30
- * superset; see `FocusedRequest.verifyAgainst`.)
18
+ * The citation is verified against exactly the text that was prompted with: the
19
+ * `\n\n`-joined chunks are passed as BOTH the prompt content and `verifyAgainst`.
20
+ * fetch-core is the only call site in this repo that passes a superset instead
21
+ * see `FocusedRequest.verifyAgainst`.
31
22
  */
32
23
  export async function docsLookup(input) {
33
24
  const content = input.chunks.map(c => c.content).join('\n\n');
@@ -7,14 +7,20 @@ export declare function cwdKey(cwd: string): string;
7
7
  /**
8
8
  * Which source files make up the project.
9
9
  *
10
- * `git ls-files` is the source of truth when there is one — it already knows
10
+ * `git ls-files` is the source of truth whenever it answers: it already knows
11
11
  * what is tracked and what `.gitignore` excludes, which no hand-rolled walk gets
12
- * right and the walk is the fallback for a directory that is not a repo.
12
+ * right. `walkTsFiles` is the fallback, and it is reached in TWO cases no git
13
+ * repo, and a repo where git matched nothing.
13
14
  *
14
- * Injectable through `projectDocsRaw` because it is the only unmockable
15
- * dependency left in the docs cluster: without a seam, ANY test of the project
16
- * path needs a real temp directory, real files on disk, and a machine where git
17
- * is installed and the temp dir is not itself inside a repo.
15
+ * The two disagree in both directions, so which one ran is observable:
16
+ * - git honours `.gitignore`; the walk does not, so a repo whose only `.ts`
17
+ * files are all gitignored falls through and indexes them anyway.
18
+ * - the walk skips node_modules, .git, dist, build and coverage outright; git
19
+ * lists whatever those contain unless `.gitignore` says otherwise.
20
+ *
21
+ * Injectable through `projectDocsRaw` because without a seam, ANY test of the
22
+ * project path needs a real temp directory, real files on disk, git installed,
23
+ * and a temp dir that is not itself inside a repo.
18
24
  */
19
25
  export declare function getProjectFiles(cwd: string): string[];
20
26
  export declare function getMaxMtime(files: string[]): string;
@@ -54,8 +60,8 @@ export declare function buildProjectPrompt(projectName: string, query: string, c
54
60
  /**
55
61
  * The PROJECT corpus row: the current repo's own indexed `.ts`/`.tsx` source.
56
62
  *
57
- * Named after the project so a reader of the answer can tell a project-source
58
- * citation from a package one at a glance — they are read and cited the same way
59
- * and mean very different things.
63
+ * The header reads `Per <name> (project source):`, where the package corpus reads
64
+ * `Per <name>@<version>:`. Both are read and cited the same way and mean very
65
+ * different things, so the answer has to say which it came from.
60
66
  */
61
67
  export declare function projectCorpus(projectName: string): DocsCorpus;
@@ -22,14 +22,20 @@ export function cwdKey(cwd) {
22
22
  /**
23
23
  * Which source files make up the project.
24
24
  *
25
- * `git ls-files` is the source of truth when there is one — it already knows
25
+ * `git ls-files` is the source of truth whenever it answers: it already knows
26
26
  * what is tracked and what `.gitignore` excludes, which no hand-rolled walk gets
27
- * right and the walk is the fallback for a directory that is not a repo.
27
+ * right. `walkTsFiles` is the fallback, and it is reached in TWO cases no git
28
+ * repo, and a repo where git matched nothing.
28
29
  *
29
- * Injectable through `projectDocsRaw` because it is the only unmockable
30
- * dependency left in the docs cluster: without a seam, ANY test of the project
31
- * path needs a real temp directory, real files on disk, and a machine where git
32
- * is installed and the temp dir is not itself inside a repo.
30
+ * The two disagree in both directions, so which one ran is observable:
31
+ * - git honours `.gitignore`; the walk does not, so a repo whose only `.ts`
32
+ * files are all gitignored falls through and indexes them anyway.
33
+ * - the walk skips node_modules, .git, dist, build and coverage outright; git
34
+ * lists whatever those contain unless `.gitignore` says otherwise.
35
+ *
36
+ * Injectable through `projectDocsRaw` because without a seam, ANY test of the
37
+ * project path needs a real temp directory, real files on disk, git installed,
38
+ * and a temp dir that is not itself inside a repo.
33
39
  */
34
40
  export function getProjectFiles(cwd) {
35
41
  try {
@@ -93,7 +99,8 @@ export function ensureProjectIndexed(cache, name, version, files, cwd) {
93
99
  const t0 = Date.now();
94
100
  cache.db.exec('BEGIN IMMEDIATE');
95
101
  try {
96
- // Clear all old versions of this project
102
+ // Delete by NAME with no version: unlike the package index, a project
103
+ // keeps only its newest max-mtime version, so every older one goes.
97
104
  cache.db.prepare('DELETE FROM chunks WHERE name = ?').run(name);
98
105
  cache.db.prepare('DELETE FROM packages WHERE name = ?').run(name);
99
106
  const insertChunk = cache.db.prepare('INSERT INTO chunks (name, version, file_path, kind, content) VALUES (?, ?, ?, ?, ?)');
@@ -211,9 +218,9 @@ export function buildProjectPrompt(projectName, query, content) {
211
218
  /**
212
219
  * The PROJECT corpus row: the current repo's own indexed `.ts`/`.tsx` source.
213
220
  *
214
- * Named after the project so a reader of the answer can tell a project-source
215
- * citation from a package one at a glance — they are read and cited the same way
216
- * and mean very different things.
221
+ * The header reads `Per <name> (project source):`, where the package corpus reads
222
+ * `Per <name>@<version>:`. Both are read and cited the same way and mean very
223
+ * different things, so the answer has to say which it came from.
217
224
  */
218
225
  export function projectCorpus(projectName) {
219
226
  return {