clinkx 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +10 -0
  3. package/README.md +113 -18
  4. package/clinkx-workflows/dist/allowed-roots.d.ts +1 -0
  5. package/clinkx-workflows/dist/allowed-roots.js +5 -0
  6. package/clinkx-workflows/dist/allowed-roots.js.map +1 -0
  7. package/clinkx-workflows/dist/artifacts.d.ts +20 -1
  8. package/clinkx-workflows/dist/artifacts.js +38 -9
  9. package/clinkx-workflows/dist/artifacts.js.map +1 -1
  10. package/clinkx-workflows/dist/backend.d.ts +4 -0
  11. package/clinkx-workflows/dist/citation-check.d.ts +40 -0
  12. package/clinkx-workflows/dist/citation-check.js +348 -0
  13. package/clinkx-workflows/dist/citation-check.js.map +1 -0
  14. package/clinkx-workflows/dist/clink-client.d.ts +2 -1
  15. package/clinkx-workflows/dist/clink-client.js +17 -4
  16. package/clinkx-workflows/dist/clink-client.js.map +1 -1
  17. package/clinkx-workflows/dist/config.d.ts +145 -16
  18. package/clinkx-workflows/dist/config.js +384 -26
  19. package/clinkx-workflows/dist/config.js.map +1 -1
  20. package/clinkx-workflows/dist/contained-file.d.ts +172 -0
  21. package/clinkx-workflows/dist/contained-file.js +483 -0
  22. package/clinkx-workflows/dist/contained-file.js.map +1 -0
  23. package/clinkx-workflows/dist/context-builder-lifecycle-contract.d.ts +416 -0
  24. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js +328 -0
  25. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js.map +1 -0
  26. package/clinkx-workflows/dist/context-builder-lifecycle-router.d.ts +24 -0
  27. package/clinkx-workflows/dist/context-builder-lifecycle-router.js +39 -0
  28. package/clinkx-workflows/dist/context-builder-lifecycle-router.js.map +1 -0
  29. package/clinkx-workflows/dist/context-cache-key.d.ts +53 -0
  30. package/clinkx-workflows/dist/context-cache-key.js +91 -0
  31. package/clinkx-workflows/dist/context-cache-key.js.map +1 -0
  32. package/clinkx-workflows/dist/context-mode-resolver.d.ts +27 -0
  33. package/clinkx-workflows/dist/context-mode-resolver.js +126 -0
  34. package/clinkx-workflows/dist/context-mode-resolver.js.map +1 -0
  35. package/clinkx-workflows/dist/context-preflight.d.ts +184 -0
  36. package/clinkx-workflows/dist/context-preflight.js +91 -0
  37. package/clinkx-workflows/dist/context-preflight.js.map +1 -0
  38. package/clinkx-workflows/dist/council-expander.d.ts +1 -1
  39. package/clinkx-workflows/dist/council-expander.js +2 -1
  40. package/clinkx-workflows/dist/council-expander.js.map +1 -1
  41. package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +165 -0
  42. package/clinkx-workflows/dist/dashboard/activity-contract.js +105 -0
  43. package/clinkx-workflows/dist/dashboard/activity-contract.js.map +1 -0
  44. package/clinkx-workflows/dist/dashboard/activity-lease.d.ts +25 -0
  45. package/clinkx-workflows/dist/dashboard/activity-lease.js +34 -0
  46. package/clinkx-workflows/dist/dashboard/activity-lease.js.map +1 -0
  47. package/clinkx-workflows/dist/dashboard/activity-reader.d.ts +86 -0
  48. package/clinkx-workflows/dist/dashboard/activity-reader.js +480 -0
  49. package/clinkx-workflows/dist/dashboard/activity-reader.js.map +1 -0
  50. package/clinkx-workflows/dist/dashboard/api-routes.d.ts +36 -0
  51. package/clinkx-workflows/dist/dashboard/api-routes.js +1047 -0
  52. package/clinkx-workflows/dist/dashboard/api-routes.js.map +1 -0
  53. package/clinkx-workflows/dist/dashboard/artifact-index.d.ts +37 -0
  54. package/clinkx-workflows/dist/dashboard/artifact-index.js +145 -0
  55. package/clinkx-workflows/dist/dashboard/artifact-index.js.map +1 -0
  56. package/clinkx-workflows/dist/dashboard/auth/challenge-store.d.ts +31 -0
  57. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js +65 -0
  58. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js.map +1 -0
  59. package/clinkx-workflows/dist/dashboard/auth/controller.d.ts +26 -0
  60. package/clinkx-workflows/dist/dashboard/auth/controller.js +596 -0
  61. package/clinkx-workflows/dist/dashboard/auth/controller.js.map +1 -0
  62. package/clinkx-workflows/dist/dashboard/auth/credential-store.d.ts +60 -0
  63. package/clinkx-workflows/dist/dashboard/auth/credential-store.js +776 -0
  64. package/clinkx-workflows/dist/dashboard/auth/credential-store.js.map +1 -0
  65. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.d.ts +9 -0
  66. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js +44 -0
  67. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js.map +1 -0
  68. package/clinkx-workflows/dist/dashboard/auth/session-store.d.ts +17 -0
  69. package/clinkx-workflows/dist/dashboard/auth/session-store.js +77 -0
  70. package/clinkx-workflows/dist/dashboard/auth/session-store.js.map +1 -0
  71. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.d.ts +25 -0
  72. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js +71 -0
  73. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js.map +1 -0
  74. package/clinkx-workflows/dist/dashboard/context-run-liveness.d.ts +37 -0
  75. package/clinkx-workflows/dist/dashboard/context-run-liveness.js +49 -0
  76. package/clinkx-workflows/dist/dashboard/context-run-liveness.js.map +1 -0
  77. package/clinkx-workflows/dist/dashboard/context-run-reader.d.ts +222 -0
  78. package/clinkx-workflows/dist/dashboard/context-run-reader.js +1178 -0
  79. package/clinkx-workflows/dist/dashboard/context-run-reader.js.map +1 -0
  80. package/clinkx-workflows/dist/dashboard/contracts.d.ts +8936 -0
  81. package/clinkx-workflows/dist/dashboard/contracts.js +1157 -0
  82. package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -0
  83. package/clinkx-workflows/dist/dashboard/generation.d.ts +14 -0
  84. package/clinkx-workflows/dist/dashboard/generation.js +41 -0
  85. package/clinkx-workflows/dist/dashboard/generation.js.map +1 -0
  86. package/clinkx-workflows/dist/dashboard/index.d.ts +28 -0
  87. package/clinkx-workflows/dist/dashboard/index.js +16 -0
  88. package/clinkx-workflows/dist/dashboard/index.js.map +1 -0
  89. package/clinkx-workflows/dist/dashboard/lazy-content.d.ts +101 -0
  90. package/clinkx-workflows/dist/dashboard/lazy-content.js +748 -0
  91. package/clinkx-workflows/dist/dashboard/lazy-content.js.map +1 -0
  92. package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +303 -0
  93. package/clinkx-workflows/dist/dashboard/progress-report-contract.js +221 -0
  94. package/clinkx-workflows/dist/dashboard/progress-report-contract.js.map +1 -0
  95. package/clinkx-workflows/dist/dashboard/progress-report-reader.d.ts +50 -0
  96. package/clinkx-workflows/dist/dashboard/progress-report-reader.js +581 -0
  97. package/clinkx-workflows/dist/dashboard/progress-report-reader.js.map +1 -0
  98. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +89 -0
  99. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js +71 -0
  100. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js.map +1 -0
  101. package/clinkx-workflows/dist/dashboard/progress-report-status-store.d.ts +28 -0
  102. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js +110 -0
  103. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js.map +1 -0
  104. package/clinkx-workflows/dist/dashboard/read-model.d.ts +86 -0
  105. package/clinkx-workflows/dist/dashboard/read-model.js +440 -0
  106. package/clinkx-workflows/dist/dashboard/read-model.js.map +1 -0
  107. package/clinkx-workflows/dist/dashboard/request-admission.d.ts +31 -0
  108. package/clinkx-workflows/dist/dashboard/request-admission.js +126 -0
  109. package/clinkx-workflows/dist/dashboard/request-admission.js.map +1 -0
  110. package/clinkx-workflows/dist/dashboard/scanner.d.ts +75 -0
  111. package/clinkx-workflows/dist/dashboard/scanner.js +1110 -0
  112. package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -0
  113. package/clinkx-workflows/dist/dashboard/server-factory.d.ts +50 -0
  114. package/clinkx-workflows/dist/dashboard/server-factory.js +431 -0
  115. package/clinkx-workflows/dist/dashboard/server-factory.js.map +1 -0
  116. package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +2611 -0
  117. package/clinkx-workflows/dist/dashboard/session-log-contract.js +480 -0
  118. package/clinkx-workflows/dist/dashboard/session-log-contract.js.map +1 -0
  119. package/clinkx-workflows/dist/dashboard/session-log-identity.d.ts +21 -0
  120. package/clinkx-workflows/dist/dashboard/session-log-identity.js +101 -0
  121. package/clinkx-workflows/dist/dashboard/session-log-identity.js.map +1 -0
  122. package/clinkx-workflows/dist/dashboard/session-log-journal.d.ts +43 -0
  123. package/clinkx-workflows/dist/dashboard/session-log-journal.js +522 -0
  124. package/clinkx-workflows/dist/dashboard/session-log-journal.js.map +1 -0
  125. package/clinkx-workflows/dist/dashboard/session-log-reader.d.ts +61 -0
  126. package/clinkx-workflows/dist/dashboard/session-log-reader.js +378 -0
  127. package/clinkx-workflows/dist/dashboard/session-log-reader.js.map +1 -0
  128. package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +6 -0
  129. package/clinkx-workflows/dist/dashboard/session-log-redaction.js +367 -0
  130. package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -0
  131. package/clinkx-workflows/dist/dashboard/session-log-retention.d.ts +23 -0
  132. package/clinkx-workflows/dist/dashboard/session-log-retention.js +212 -0
  133. package/clinkx-workflows/dist/dashboard/session-log-retention.js.map +1 -0
  134. package/clinkx-workflows/dist/dashboard/static-responses.d.ts +10 -0
  135. package/clinkx-workflows/dist/dashboard/static-responses.js +94 -0
  136. package/clinkx-workflows/dist/dashboard/static-responses.js.map +1 -0
  137. package/clinkx-workflows/dist/dashboard/worker-lock-observer.d.ts +28 -0
  138. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js +241 -0
  139. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js.map +1 -0
  140. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  141. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  142. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  143. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  144. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  145. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  146. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  147. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  148. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  149. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  150. package/clinkx-workflows/dist/dashboard-ui/assets/index-DOkMXTfB.js +25 -0
  151. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  152. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  153. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  154. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  155. package/clinkx-workflows/dist/dashboard-ui/assets/style-ChJsn0KD.css +1 -0
  156. package/clinkx-workflows/dist/dashboard-ui/contracts/council-plan-review-input-v1.json +158 -0
  157. package/clinkx-workflows/dist/dashboard-ui/index.html +15 -0
  158. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Mono-OFL.txt +93 -0
  159. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Sans-OFL.txt +93 -0
  160. package/clinkx-workflows/dist/dashboard-ui/licenses/JetBrains-Mono-OFL.txt +93 -0
  161. package/clinkx-workflows/dist/dashboard-ui/licenses/NOTICE.md +32 -0
  162. package/clinkx-workflows/dist/dashboard-ui/theme-init.js +8 -0
  163. package/clinkx-workflows/dist/definition-normalizer.d.ts +19 -0
  164. package/clinkx-workflows/dist/definition-normalizer.js.map +1 -1
  165. package/clinkx-workflows/dist/delegate-validate.d.ts +78 -0
  166. package/clinkx-workflows/dist/delegate-validate.js +97 -0
  167. package/clinkx-workflows/dist/delegate-validate.js.map +1 -0
  168. package/clinkx-workflows/dist/engine.d.ts +141 -0
  169. package/clinkx-workflows/dist/engine.js +882 -28
  170. package/clinkx-workflows/dist/engine.js.map +1 -1
  171. package/clinkx-workflows/dist/errors.d.ts +2 -0
  172. package/clinkx-workflows/dist/errors.js.map +1 -1
  173. package/clinkx-workflows/dist/fingerprint.d.ts +1 -1
  174. package/clinkx-workflows/dist/fingerprint.js +1 -1
  175. package/clinkx-workflows/dist/index.d.ts +19 -0
  176. package/clinkx-workflows/dist/index.js +15 -0
  177. package/clinkx-workflows/dist/index.js.map +1 -1
  178. package/clinkx-workflows/dist/loader.d.ts +9 -3
  179. package/clinkx-workflows/dist/loader.js +92 -21
  180. package/clinkx-workflows/dist/loader.js.map +1 -1
  181. package/clinkx-workflows/dist/plan-review/admission.d.ts +160 -0
  182. package/clinkx-workflows/dist/plan-review/admission.js +290 -0
  183. package/clinkx-workflows/dist/plan-review/admission.js.map +1 -0
  184. package/clinkx-workflows/dist/plan-review/context-policy.d.ts +55 -0
  185. package/clinkx-workflows/dist/plan-review/context-policy.js +146 -0
  186. package/clinkx-workflows/dist/plan-review/context-policy.js.map +1 -0
  187. package/clinkx-workflows/dist/plan-review/contract.d.ts +763 -0
  188. package/clinkx-workflows/dist/plan-review/contract.js +289 -0
  189. package/clinkx-workflows/dist/plan-review/contract.js.map +1 -0
  190. package/clinkx-workflows/dist/plan-review/digest.d.ts +68 -0
  191. package/clinkx-workflows/dist/plan-review/digest.js +241 -0
  192. package/clinkx-workflows/dist/plan-review/digest.js.map +1 -0
  193. package/clinkx-workflows/dist/plan-review/discovery.d.ts +45 -0
  194. package/clinkx-workflows/dist/plan-review/discovery.js +36 -0
  195. package/clinkx-workflows/dist/plan-review/discovery.js.map +1 -0
  196. package/clinkx-workflows/dist/plan-review/execution-contract.d.ts +298 -0
  197. package/clinkx-workflows/dist/plan-review/execution-contract.js +194 -0
  198. package/clinkx-workflows/dist/plan-review/execution-contract.js.map +1 -0
  199. package/clinkx-workflows/dist/plan-review/expander.d.ts +48 -0
  200. package/clinkx-workflows/dist/plan-review/expander.js +243 -0
  201. package/clinkx-workflows/dist/plan-review/expander.js.map +1 -0
  202. package/clinkx-workflows/dist/plan-review/projector.d.ts +126 -0
  203. package/clinkx-workflows/dist/plan-review/projector.js +437 -0
  204. package/clinkx-workflows/dist/plan-review/projector.js.map +1 -0
  205. package/clinkx-workflows/dist/plan-review/publication.d.ts +95 -0
  206. package/clinkx-workflows/dist/plan-review/publication.js +182 -0
  207. package/clinkx-workflows/dist/plan-review/publication.js.map +1 -0
  208. package/clinkx-workflows/dist/plan-review/ranking-reducer.d.ts +34 -0
  209. package/clinkx-workflows/dist/plan-review/ranking-reducer.js +139 -0
  210. package/clinkx-workflows/dist/plan-review/ranking-reducer.js.map +1 -0
  211. package/clinkx-workflows/dist/plan-review/resume.d.ts +38 -0
  212. package/clinkx-workflows/dist/plan-review/resume.js +122 -0
  213. package/clinkx-workflows/dist/plan-review/resume.js.map +1 -0
  214. package/clinkx-workflows/dist/plan-review/rubric.d.ts +7 -0
  215. package/clinkx-workflows/dist/plan-review/rubric.js +24 -0
  216. package/clinkx-workflows/dist/plan-review/rubric.js.map +1 -0
  217. package/clinkx-workflows/dist/plan-review/run-state.d.ts +398 -0
  218. package/clinkx-workflows/dist/plan-review/run-state.js +183 -0
  219. package/clinkx-workflows/dist/plan-review/run-state.js.map +1 -0
  220. package/clinkx-workflows/dist/plan-review/runtime-policy.d.ts +74 -0
  221. package/clinkx-workflows/dist/plan-review/runtime-policy.js +186 -0
  222. package/clinkx-workflows/dist/plan-review/runtime-policy.js.map +1 -0
  223. package/clinkx-workflows/dist/plan-review/snapshot.d.ts +81 -0
  224. package/clinkx-workflows/dist/plan-review/snapshot.js +170 -0
  225. package/clinkx-workflows/dist/plan-review/snapshot.js.map +1 -0
  226. package/clinkx-workflows/dist/plan-review/stage-error.d.ts +19 -0
  227. package/clinkx-workflows/dist/plan-review/stage-error.js +20 -0
  228. package/clinkx-workflows/dist/plan-review/stage-error.js.map +1 -0
  229. package/clinkx-workflows/dist/post-processors/index.d.ts +20 -0
  230. package/clinkx-workflows/dist/post-processors/index.js +21 -0
  231. package/clinkx-workflows/dist/post-processors/index.js.map +1 -0
  232. package/clinkx-workflows/dist/prompt-budget.d.ts +7 -0
  233. package/clinkx-workflows/dist/prompt-budget.js +7 -1
  234. package/clinkx-workflows/dist/prompt-budget.js.map +1 -1
  235. package/clinkx-workflows/dist/reducers/index.js +2 -0
  236. package/clinkx-workflows/dist/reducers/index.js.map +1 -1
  237. package/clinkx-workflows/dist/run-lock-heartbeat.d.ts +2 -0
  238. package/clinkx-workflows/dist/run-lock-heartbeat.js +3 -0
  239. package/clinkx-workflows/dist/run-lock-heartbeat.js.map +1 -0
  240. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.d.ts +34 -0
  241. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js +74 -0
  242. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js.map +1 -0
  243. package/clinkx-workflows/dist/run-summary/cards/index.js +5 -0
  244. package/clinkx-workflows/dist/run-summary/cards/index.js.map +1 -1
  245. package/clinkx-workflows/dist/run-summary.d.ts +13 -0
  246. package/clinkx-workflows/dist/run-summary.js +29 -1
  247. package/clinkx-workflows/dist/run-summary.js.map +1 -1
  248. package/clinkx-workflows/dist/schema.d.ts +76 -21
  249. package/clinkx-workflows/dist/schema.js +10 -1
  250. package/clinkx-workflows/dist/schema.js.map +1 -1
  251. package/clinkx-workflows/dist/seed-terms.d.ts +30 -0
  252. package/clinkx-workflows/dist/seed-terms.js +176 -0
  253. package/clinkx-workflows/dist/seed-terms.js.map +1 -0
  254. package/clinkx-workflows/dist/server.d.ts +5 -2
  255. package/clinkx-workflows/dist/server.js +82 -52
  256. package/clinkx-workflows/dist/server.js.map +1 -1
  257. package/clinkx-workflows/dist/shutdown.d.ts +18 -20
  258. package/clinkx-workflows/dist/shutdown.js +43 -61
  259. package/clinkx-workflows/dist/shutdown.js.map +1 -1
  260. package/clinkx-workflows/dist/state-schema.d.ts +38 -0
  261. package/clinkx-workflows/dist/state.d.ts +170 -3
  262. package/clinkx-workflows/dist/state.js +1275 -28
  263. package/clinkx-workflows/dist/state.js.map +1 -1
  264. package/clinkx-workflows/dist/transport.d.ts +15 -0
  265. package/clinkx-workflows/dist/transport.js +19 -10
  266. package/clinkx-workflows/dist/transport.js.map +1 -1
  267. package/clinkx-workflows/dist/types.d.ts +14 -2
  268. package/clinkx-workflows/dist/validators/council.d.ts +318 -85
  269. package/clinkx-workflows/dist/validators/council.js +52 -13
  270. package/clinkx-workflows/dist/validators/council.js.map +1 -1
  271. package/clinkx-workflows/dist/validators/index.d.ts +1 -0
  272. package/clinkx-workflows/dist/validators/index.js +3 -0
  273. package/clinkx-workflows/dist/validators/index.js.map +1 -1
  274. package/clinkx-workflows/dist/validators/plan-review.d.ts +398 -0
  275. package/clinkx-workflows/dist/validators/plan-review.js +316 -0
  276. package/clinkx-workflows/dist/validators/plan-review.js.map +1 -0
  277. package/clinkx-workflows/dist/workflow-receipt.js +188 -4
  278. package/clinkx-workflows/dist/workflow-receipt.js.map +1 -1
  279. package/clinkx-workflows/dist/workflow-tools.d.ts +48 -3
  280. package/clinkx-workflows/dist/workflow-tools.js +1402 -59
  281. package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
  282. package/clinkx-workflows/dist/workspace-signature.d.ts +16 -0
  283. package/clinkx-workflows/dist/workspace-signature.js +388 -0
  284. package/clinkx-workflows/dist/workspace-signature.js.map +1 -0
  285. package/clinkx-workflows/templates/council/answer-specialist.txt +2 -1
  286. package/clinkx-workflows/templates/council/code-review-chairman.txt +13 -0
  287. package/clinkx-workflows/templates/council/code-review-cross-reviewer.txt +4 -1
  288. package/clinkx-workflows/templates/council/code-review-reviewer.txt +19 -3
  289. package/clinkx-workflows/templates/council/debug-debugger.txt +2 -1
  290. package/clinkx-workflows/templates/council/discover-analyst.txt +2 -1
  291. package/clinkx-workflows/templates/council/member.txt +2 -1
  292. package/clinkx-workflows/templates/council/plan-review-chairman.txt +68 -0
  293. package/clinkx-workflows/templates/council/plan-review-cross-reviewer.txt +51 -0
  294. package/clinkx-workflows/templates/council/plan-review-reviewer.txt +60 -0
  295. package/clinkx-workflows/templates/plan-review/chairman.txt +48 -0
  296. package/clinkx-workflows/templates/plan-review/cross-review.txt +52 -0
  297. package/clinkx-workflows/templates/plan-review/ranking.txt +16 -0
  298. package/clinkx-workflows/templates/plan-review/reviewer.txt +57 -0
  299. package/clinkx-workflows/workflows/council-answer.yaml +97 -8
  300. package/clinkx-workflows/workflows/council-code-review.yaml +103 -8
  301. package/clinkx-workflows/workflows/council-debug.yaml +97 -8
  302. package/clinkx-workflows/workflows/council-default.yaml +97 -8
  303. package/clinkx-workflows/workflows/council-discover.yaml +97 -8
  304. package/clinkx-workflows/workflows/council-plan-review.yaml +250 -0
  305. package/clinkx-workflows/workflows/plan-review-receipts.yaml +230 -0
  306. package/conf/adapters/agy.json +49 -0
  307. package/conf/adapters/claude.json +5 -0
  308. package/conf/adapters/codex-app-server.json +44 -0
  309. package/conf/adapters/codex.json +7 -2
  310. package/conf/adapters/glm.json +5 -0
  311. package/conf/adapters/grok.json +60 -0
  312. package/conf/adapters/hapi/agy.json +52 -0
  313. package/conf/adapters/hapi/claude.json +5 -0
  314. package/conf/adapters/hapi/codex.json +7 -2
  315. package/conf/adapters/hapi/glm.json +5 -0
  316. package/conf/prompts/json-codereviewer.txt +1 -0
  317. package/conf/prompts/json.txt +1 -0
  318. package/dist/activity-journal.d.ts +42 -0
  319. package/dist/activity-journal.js +381 -0
  320. package/dist/activity-journal.js.map +1 -0
  321. package/dist/allowed-roots.d.ts +53 -0
  322. package/dist/allowed-roots.js +216 -0
  323. package/dist/allowed-roots.js.map +1 -0
  324. package/dist/codex/activity-session-log.d.ts +14 -0
  325. package/dist/codex/activity-session-log.js +206 -0
  326. package/dist/codex/activity-session-log.js.map +1 -0
  327. package/dist/codex/agent-tools.d.ts +23 -0
  328. package/dist/codex/agent-tools.js +1270 -0
  329. package/dist/codex/agent-tools.js.map +1 -0
  330. package/dist/codex/app-server-client.d.ts +76 -0
  331. package/dist/codex/app-server-client.js +582 -0
  332. package/dist/codex/app-server-client.js.map +1 -0
  333. package/dist/codex/app-server-registry.d.ts +389 -0
  334. package/dist/codex/app-server-registry.js +1407 -0
  335. package/dist/codex/app-server-registry.js.map +1 -0
  336. package/dist/codex/client-types.d.ts +109 -0
  337. package/dist/codex/client-types.js +2 -0
  338. package/dist/codex/client-types.js.map +1 -0
  339. package/dist/codex/protocol.d.ts +5375 -0
  340. package/dist/codex/protocol.js +614 -0
  341. package/dist/codex/protocol.js.map +1 -0
  342. package/dist/codex/session.d.ts +263 -0
  343. package/dist/codex/session.js +466 -0
  344. package/dist/codex/session.js.map +1 -0
  345. package/dist/config.d.ts +185 -19
  346. package/dist/config.js +82 -16
  347. package/dist/config.js.map +1 -1
  348. package/dist/context-builder/anchors.d.ts +12 -0
  349. package/dist/context-builder/anchors.js +22 -0
  350. package/dist/context-builder/anchors.js.map +1 -0
  351. package/dist/context-builder/bundle.d.ts +109 -0
  352. package/dist/context-builder/bundle.js +1498 -0
  353. package/dist/context-builder/bundle.js.map +1 -0
  354. package/dist/context-builder/codemap.d.ts +22 -0
  355. package/dist/context-builder/codemap.js +675 -0
  356. package/dist/context-builder/codemap.js.map +1 -0
  357. package/dist/context-builder/config.d.ts +61 -0
  358. package/dist/context-builder/config.js +216 -0
  359. package/dist/context-builder/config.js.map +1 -0
  360. package/dist/context-builder/context-run-catalog.d.ts +17 -0
  361. package/dist/context-builder/context-run-catalog.js +99 -0
  362. package/dist/context-builder/context-run-catalog.js.map +1 -0
  363. package/dist/context-builder/delegate-packet.d.ts +219 -0
  364. package/dist/context-builder/delegate-packet.js +1190 -0
  365. package/dist/context-builder/delegate-packet.js.map +1 -0
  366. package/dist/context-builder/delegate-reconstruction.d.ts +13 -0
  367. package/dist/context-builder/delegate-reconstruction.js +220 -0
  368. package/dist/context-builder/delegate-reconstruction.js.map +1 -0
  369. package/dist/context-builder/delegate-validation.d.ts +27 -0
  370. package/dist/context-builder/delegate-validation.js +479 -0
  371. package/dist/context-builder/delegate-validation.js.map +1 -0
  372. package/dist/context-builder/delegate.d.ts +26 -0
  373. package/dist/context-builder/delegate.js +134 -0
  374. package/dist/context-builder/delegate.js.map +1 -0
  375. package/dist/context-builder/diagnostics.d.ts +36 -0
  376. package/dist/context-builder/diagnostics.js +107 -0
  377. package/dist/context-builder/diagnostics.js.map +1 -0
  378. package/dist/context-builder/discovery.d.ts +146 -0
  379. package/dist/context-builder/discovery.js +2129 -0
  380. package/dist/context-builder/discovery.js.map +1 -0
  381. package/dist/context-builder/globs.d.ts +14 -0
  382. package/dist/context-builder/globs.js +175 -0
  383. package/dist/context-builder/globs.js.map +1 -0
  384. package/dist/context-builder/handler.d.ts +41 -0
  385. package/dist/context-builder/handler.js +2590 -0
  386. package/dist/context-builder/handler.js.map +1 -0
  387. package/dist/context-builder/lifecycle-contract.d.ts +424 -0
  388. package/dist/context-builder/lifecycle-contract.js +523 -0
  389. package/dist/context-builder/lifecycle-contract.js.map +1 -0
  390. package/dist/context-builder/lifecycle-journal.d.ts +62 -0
  391. package/dist/context-builder/lifecycle-journal.js +88 -0
  392. package/dist/context-builder/lifecycle-journal.js.map +1 -0
  393. package/dist/context-builder/lifecycle-observer.d.ts +102 -0
  394. package/dist/context-builder/lifecycle-observer.js +258 -0
  395. package/dist/context-builder/lifecycle-observer.js.map +1 -0
  396. package/dist/context-builder/lifecycle-reconcile.d.ts +32 -0
  397. package/dist/context-builder/lifecycle-reconcile.js +191 -0
  398. package/dist/context-builder/lifecycle-reconcile.js.map +1 -0
  399. package/dist/context-builder/lifecycle-recovery.d.ts +2 -0
  400. package/dist/context-builder/lifecycle-recovery.js +14 -0
  401. package/dist/context-builder/lifecycle-recovery.js.map +1 -0
  402. package/dist/context-builder/path-signals.d.ts +7 -0
  403. package/dist/context-builder/path-signals.js +70 -0
  404. package/dist/context-builder/path-signals.js.map +1 -0
  405. package/dist/context-builder/paths.d.ts +30 -0
  406. package/dist/context-builder/paths.js +153 -0
  407. package/dist/context-builder/paths.js.map +1 -0
  408. package/dist/context-builder/progress.d.ts +17 -0
  409. package/dist/context-builder/progress.js +93 -0
  410. package/dist/context-builder/progress.js.map +1 -0
  411. package/dist/context-builder/receipt.d.ts +91 -0
  412. package/dist/context-builder/receipt.js +180 -0
  413. package/dist/context-builder/receipt.js.map +1 -0
  414. package/dist/context-builder/refine-handler.d.ts +14 -0
  415. package/dist/context-builder/refine-handler.js +790 -0
  416. package/dist/context-builder/refine-handler.js.map +1 -0
  417. package/dist/context-builder/review-coverage.d.ts +84 -0
  418. package/dist/context-builder/review-coverage.js +437 -0
  419. package/dist/context-builder/review-coverage.js.map +1 -0
  420. package/dist/context-builder/run-id.d.ts +7 -0
  421. package/dist/context-builder/run-id.js +31 -0
  422. package/dist/context-builder/run-id.js.map +1 -0
  423. package/dist/context-builder/schema.d.ts +669 -0
  424. package/dist/context-builder/schema.js +399 -0
  425. package/dist/context-builder/schema.js.map +1 -0
  426. package/dist/context-builder/secrets.d.ts +41 -0
  427. package/dist/context-builder/secrets.js +1651 -0
  428. package/dist/context-builder/secrets.js.map +1 -0
  429. package/dist/context-builder/selection.d.ts +56 -0
  430. package/dist/context-builder/selection.js +1111 -0
  431. package/dist/context-builder/selection.js.map +1 -0
  432. package/dist/context-builder/session-log-identity.d.ts +1 -0
  433. package/dist/context-builder/session-log-identity.js +66 -0
  434. package/dist/context-builder/session-log-identity.js.map +1 -0
  435. package/dist/context-builder/slice-range-math.d.ts +16 -0
  436. package/dist/context-builder/slice-range-math.js +137 -0
  437. package/dist/context-builder/slice-range-math.js.map +1 -0
  438. package/dist/context-builder/status.d.ts +66 -0
  439. package/dist/context-builder/status.js +160 -0
  440. package/dist/context-builder/status.js.map +1 -0
  441. package/dist/context-builder/storage.d.ts +118 -0
  442. package/dist/context-builder/storage.js +1003 -0
  443. package/dist/context-builder/storage.js.map +1 -0
  444. package/dist/context-builder/token-estimate.d.ts +19 -0
  445. package/dist/context-builder/token-estimate.js +90 -0
  446. package/dist/context-builder/token-estimate.js.map +1 -0
  447. package/dist/context-builder/versions.d.ts +29 -0
  448. package/dist/context-builder/versions.js +30 -0
  449. package/dist/context-builder/versions.js.map +1 -0
  450. package/dist/context-builder/workflow-runner.d.ts +69 -0
  451. package/dist/context-builder/workflow-runner.js +1051 -0
  452. package/dist/context-builder/workflow-runner.js.map +1 -0
  453. package/dist/context-builder/write-watchdog.d.ts +14 -0
  454. package/dist/context-builder/write-watchdog.js +38 -0
  455. package/dist/context-builder/write-watchdog.js.map +1 -0
  456. package/dist/dashboard-adapter-catalog.d.ts +9 -0
  457. package/dist/dashboard-adapter-catalog.js +46 -0
  458. package/dist/dashboard-adapter-catalog.js.map +1 -0
  459. package/dist/dashboard-cli.d.ts +79 -0
  460. package/dist/dashboard-cli.js +585 -0
  461. package/dist/dashboard-cli.js.map +1 -0
  462. package/dist/dashboard-companion/client.d.ts +36 -0
  463. package/dist/dashboard-companion/client.js +210 -0
  464. package/dist/dashboard-companion/client.js.map +1 -0
  465. package/dist/dashboard-companion/config.d.ts +8 -0
  466. package/dist/dashboard-companion/config.js +52 -0
  467. package/dist/dashboard-companion/config.js.map +1 -0
  468. package/dist/dashboard-companion/http-proxy.d.ts +10 -0
  469. package/dist/dashboard-companion/http-proxy.js +234 -0
  470. package/dist/dashboard-companion/http-proxy.js.map +1 -0
  471. package/dist/dashboard-companion/protocol.d.ts +80 -0
  472. package/dist/dashboard-companion/protocol.js +455 -0
  473. package/dist/dashboard-companion/protocol.js.map +1 -0
  474. package/dist/dashboard-companion/standalone-assets.d.ts +12 -0
  475. package/dist/dashboard-companion/standalone-assets.js +72 -0
  476. package/dist/dashboard-companion/standalone-assets.js.map +1 -0
  477. package/dist/dashboard-companion/standalone-entry.d.ts +1 -0
  478. package/dist/dashboard-companion/standalone-entry.js +17 -0
  479. package/dist/dashboard-companion/standalone-entry.js.map +1 -0
  480. package/dist/dashboard-gateway/config.d.ts +9 -0
  481. package/dist/dashboard-gateway/config.js +44 -0
  482. package/dist/dashboard-gateway/config.js.map +1 -0
  483. package/dist/dashboard-gateway/index.d.ts +11 -0
  484. package/dist/dashboard-gateway/index.js +755 -0
  485. package/dist/dashboard-gateway/index.js.map +1 -0
  486. package/dist/dashboard-gateway/main.d.ts +1 -0
  487. package/dist/dashboard-gateway/main.js +25 -0
  488. package/dist/dashboard-gateway/main.js.map +1 -0
  489. package/dist/dashboard-pairing-token.d.ts +1 -0
  490. package/dist/dashboard-pairing-token.js +5 -0
  491. package/dist/dashboard-pairing-token.js.map +1 -0
  492. package/dist/elaris/client.d.ts +73 -0
  493. package/dist/elaris/client.js +825 -0
  494. package/dist/elaris/client.js.map +1 -0
  495. package/dist/elaris/config.d.ts +18 -0
  496. package/dist/elaris/config.js +75 -0
  497. package/dist/elaris/config.js.map +1 -0
  498. package/dist/elaris/errors.d.ts +41 -0
  499. package/dist/elaris/errors.js +205 -0
  500. package/dist/elaris/errors.js.map +1 -0
  501. package/dist/elaris/github-repo.d.ts +18 -0
  502. package/dist/elaris/github-repo.js +89 -0
  503. package/dist/elaris/github-repo.js.map +1 -0
  504. package/dist/elaris/index.d.ts +10 -0
  505. package/dist/elaris/index.js +11 -0
  506. package/dist/elaris/index.js.map +1 -0
  507. package/dist/elaris/redact.d.ts +89 -0
  508. package/dist/elaris/redact.js +423 -0
  509. package/dist/elaris/redact.js.map +1 -0
  510. package/dist/elaris/run-id.d.ts +5 -0
  511. package/dist/elaris/run-id.js +20 -0
  512. package/dist/elaris/run-id.js.map +1 -0
  513. package/dist/elaris/status.d.ts +45 -0
  514. package/dist/elaris/status.js +122 -0
  515. package/dist/elaris/status.js.map +1 -0
  516. package/dist/elaris/tool-schemas.d.ts +314 -0
  517. package/dist/elaris/tool-schemas.js +208 -0
  518. package/dist/elaris/tool-schemas.js.map +1 -0
  519. package/dist/elaris/tools.d.ts +73 -0
  520. package/dist/elaris/tools.js +1065 -0
  521. package/dist/elaris/tools.js.map +1 -0
  522. package/dist/elaris/types.d.ts +1541 -0
  523. package/dist/elaris/types.js +252 -0
  524. package/dist/elaris/types.js.map +1 -0
  525. package/dist/errors.d.ts +16 -0
  526. package/dist/errors.js +19 -0
  527. package/dist/errors.js.map +1 -1
  528. package/dist/handler.d.ts +4 -0
  529. package/dist/handler.js +10 -1
  530. package/dist/handler.js.map +1 -1
  531. package/dist/index.d.ts +2 -1
  532. package/dist/index.js +13 -3
  533. package/dist/index.js.map +1 -1
  534. package/dist/local-clink-backend.d.ts +3 -0
  535. package/dist/local-clink-backend.js +4 -0
  536. package/dist/local-clink-backend.js.map +1 -1
  537. package/dist/package-info.d.ts +2 -0
  538. package/dist/package-info.js +18 -0
  539. package/dist/package-info.js.map +1 -0
  540. package/dist/parsers/codex-jsonl.js +48 -3
  541. package/dist/parsers/codex-jsonl.js.map +1 -1
  542. package/dist/parsers/extract.d.ts +10 -1
  543. package/dist/parsers/extract.js +11 -3
  544. package/dist/parsers/extract.js.map +1 -1
  545. package/dist/paths.d.ts +8 -0
  546. package/dist/paths.js +31 -43
  547. package/dist/paths.js.map +1 -1
  548. package/dist/pipeline.d.ts +51 -3
  549. package/dist/pipeline.js +264 -47
  550. package/dist/pipeline.js.map +1 -1
  551. package/dist/run-dir.d.ts +24 -0
  552. package/dist/run-dir.js +201 -2
  553. package/dist/run-dir.js.map +1 -1
  554. package/dist/runner.d.ts +13 -0
  555. package/dist/runner.js +184 -15
  556. package/dist/runner.js.map +1 -1
  557. package/dist/safety.d.ts +4 -4
  558. package/dist/safety.js +4 -4
  559. package/dist/schema.d.ts +7 -7
  560. package/dist/server.d.ts +2 -0
  561. package/dist/server.js +396 -24
  562. package/dist/server.js.map +1 -1
  563. package/dist/session-log-stream.d.ts +18 -0
  564. package/dist/session-log-stream.js +319 -0
  565. package/dist/session-log-stream.js.map +1 -0
  566. package/package.json +47 -5
  567. package/conf/adapters/gemini.json +0 -44
  568. package/conf/adapters/hapi/gemini.json +0 -47
  569. package/dist/artifacts.d.ts +0 -9
  570. package/dist/artifacts.js +0 -24
  571. package/dist/artifacts.js.map +0 -1
  572. package/dist/parsers/gemini-json.d.ts +0 -2
  573. package/dist/parsers/gemini-json.js +0 -72
  574. package/dist/parsers/gemini-json.js.map +0 -1
@@ -0,0 +1,1111 @@
1
+ import { mergeLineRanges, splitTextLines, } from "./discovery.js";
2
+ import { buildFileCodemap } from "./codemap.js";
3
+ import { directoryDistance, genericPathKind, isTestPath, normalizedPathStem, } from "./path-signals.js";
4
+ import { estimateContextBuilderTokensFromUtf8Bytes } from "./token-estimate.js";
5
+ export function selectContextBuilderFinalContext(input) {
6
+ const rankedPending = buildPendingSelections(input.slices, input.search, input.task ?? "", input.budget);
7
+ const obligationRanges = input.coverage_policy?.id === "review_deep_v1"
8
+ ? buildObligationRangeIndex(input.review_obligations)
9
+ : new Map();
10
+ const pending = reserveRequiredCoverageCandidates({
11
+ pending: rankedPending,
12
+ budget: input.budget,
13
+ policy: input.coverage_policy,
14
+ evidenceClassesByCandidate: input.evidence_classes_by_candidate,
15
+ obligations: input.review_obligations,
16
+ obligationRanges,
17
+ });
18
+ const selected = [];
19
+ const omissions = [];
20
+ const summaryFiles = [];
21
+ let totalBytes = 0;
22
+ let totalTokens = 0;
23
+ for (const item of pending) {
24
+ const root_index = item.root_index;
25
+ const paths = [item.path];
26
+ if (selected.length >= input.budget.max_files) {
27
+ omissions.push({
28
+ root_index,
29
+ reason: "max_files",
30
+ message: "Selected context omitted by max_files budget",
31
+ paths,
32
+ });
33
+ summaryFiles.push(selectionSummaryFile(item, "omitted", "max_files"));
34
+ continue;
35
+ }
36
+ const selectedItem = budgetedSelectionForItem(item, input.budget, { totalBytes, totalTokens }, obligationRanges.get(contextReviewCandidateId(item)));
37
+ if (selectedItem.kind === "omitted") {
38
+ omissions.push({
39
+ root_index,
40
+ reason: selectedItem.reason,
41
+ message: selectedItem.message,
42
+ paths,
43
+ });
44
+ summaryFiles.push(selectionSummaryFile(item, "omitted", selectedItem.reason));
45
+ continue;
46
+ }
47
+ selected.push({
48
+ root_index: selectedItem.file.root_index,
49
+ path: selectedItem.file.path,
50
+ ranges: selectedItem.file.ranges,
51
+ content: selectedItem.file.content,
52
+ bytes: selectedItem.file.bytes,
53
+ estimated_tokens: selectedItem.file.estimated_tokens,
54
+ source: selectedItem.file.source,
55
+ ...(selectedItem.file.disposition == null
56
+ ? {}
57
+ : { disposition: selectedItem.file.disposition }),
58
+ });
59
+ summaryFiles.push(selectionSummaryFile(selectedItem.file, selectedItem.tier, selectedItem.reason));
60
+ totalBytes += selectedItem.file.bytes;
61
+ totalTokens += selectedItem.file.estimated_tokens;
62
+ }
63
+ return {
64
+ selected,
65
+ tree: [...input.tree].sort(compareTreeFiles),
66
+ search: [...input.search].sort(compareSearchRecords),
67
+ slices: [...input.slices].sort(compareSlices),
68
+ omissions,
69
+ metrics: {
70
+ files_selected: selected.length,
71
+ files_omitted: omissions.length,
72
+ bytes_selected: totalBytes,
73
+ estimated_tokens: totalTokens,
74
+ truncated: omissions.length > 0,
75
+ },
76
+ summary: {
77
+ files: summaryFiles,
78
+ },
79
+ };
80
+ }
81
+ function reserveRequiredCoverageCandidates(input) {
82
+ const policy = input.policy;
83
+ if (policy?.id == null ||
84
+ policy.required_when_available.length === 0) {
85
+ return input.pending;
86
+ }
87
+ const reserved = [];
88
+ const reservedKeys = new Set();
89
+ const pendingByCandidateId = new Map();
90
+ for (const item of input.pending) {
91
+ const candidateId = contextReviewCandidateId(item);
92
+ if (!pendingByCandidateId.has(candidateId)) {
93
+ pendingByCandidateId.set(candidateId, item);
94
+ }
95
+ }
96
+ let totalBytes = 0;
97
+ let totalTokens = 0;
98
+ const reserveCandidate = (candidateIds) => {
99
+ if (reserved.length >= input.budget.max_files) {
100
+ return false;
101
+ }
102
+ for (const candidateId of candidateIds) {
103
+ const item = pendingByCandidateId.get(candidateId);
104
+ if (item == null) {
105
+ continue;
106
+ }
107
+ const key = pendingCandidateKey(item);
108
+ if (reservedKeys.has(key)) {
109
+ return true;
110
+ }
111
+ const budgeted = budgetedSelectionForItem(item, input.budget, { totalBytes, totalTokens }, input.obligationRanges.get(candidateId));
112
+ if (budgeted.kind === "omitted") {
113
+ continue;
114
+ }
115
+ reserved.push(item);
116
+ reservedKeys.add(key);
117
+ totalBytes += budgeted.file.bytes;
118
+ totalTokens += budgeted.file.estimated_tokens;
119
+ return true;
120
+ }
121
+ return false;
122
+ };
123
+ if (input.obligations != null) {
124
+ for (const target of input.obligations.targets) {
125
+ reserveCandidate([target.candidate_id]);
126
+ if (target.regression_links.length > 0) {
127
+ reserveCandidate(target.regression_links.map((link) => link.candidate_id));
128
+ }
129
+ }
130
+ }
131
+ else if (input.evidenceClassesByCandidate != null) {
132
+ const evidenceClassesByCandidate = input.evidenceClassesByCandidate;
133
+ for (const evidenceClass of policy.required_when_available) {
134
+ if (reserved.some((item) => evidenceClassesForPending(item, evidenceClassesByCandidate).includes(evidenceClass))) {
135
+ continue;
136
+ }
137
+ if (reserved.length >= input.budget.max_files) {
138
+ break;
139
+ }
140
+ for (const item of input.pending) {
141
+ const key = pendingCandidateKey(item);
142
+ if (reservedKeys.has(key) ||
143
+ !evidenceClassesForPending(item, evidenceClassesByCandidate).includes(evidenceClass)) {
144
+ continue;
145
+ }
146
+ const budgeted = budgetedSelectionForItem(item, input.budget, {
147
+ totalBytes,
148
+ totalTokens,
149
+ });
150
+ if (budgeted.kind === "omitted") {
151
+ continue;
152
+ }
153
+ reserved.push(item);
154
+ reservedKeys.add(key);
155
+ totalBytes += budgeted.file.bytes;
156
+ totalTokens += budgeted.file.estimated_tokens;
157
+ break;
158
+ }
159
+ }
160
+ }
161
+ if (reserved.length === 0) {
162
+ return input.pending;
163
+ }
164
+ return [
165
+ ...reserved,
166
+ ...input.pending.filter((item) => !reservedKeys.has(pendingCandidateKey(item))),
167
+ ];
168
+ }
169
+ function evidenceClassesForPending(item, byCandidate) {
170
+ return byCandidate.get(pendingCandidateKey(item)) ?? [];
171
+ }
172
+ function pendingCandidateKey(item) {
173
+ return `${item.root_index}\u0000${item.path}`;
174
+ }
175
+ function contextReviewCandidateId(item) {
176
+ return `c:${String(item.root_index)}:${item.path}`;
177
+ }
178
+ function buildObligationRangeIndex(obligations) {
179
+ const ranges = new Map();
180
+ for (const target of obligations?.targets ?? []) {
181
+ appendObligationRanges(ranges, target.candidate_id, target.ranges);
182
+ for (const link of target.regression_links) {
183
+ appendObligationRanges(ranges, link.candidate_id, link.ranges);
184
+ }
185
+ }
186
+ return ranges;
187
+ }
188
+ function appendObligationRanges(index, candidateId, ranges) {
189
+ index.set(candidateId, mergeLineRanges([...(index.get(candidateId) ?? []), ...ranges]));
190
+ }
191
+ function budgetedSelectionForItem(item, budget, totals, preferredRanges) {
192
+ const full = selectedFileFromPending(item);
193
+ const obligationSelection = preferredRanges == null
194
+ ? null
195
+ : budgetFittingSelectionForRanges(item, preferredRanges, budget, totals);
196
+ if (obligationSelection != null) {
197
+ return {
198
+ kind: "selected",
199
+ file: obligationSelection,
200
+ tier: obligationSelection.bytes === full.bytes
201
+ ? "full_file"
202
+ : "signature_slices",
203
+ ...(obligationSelection.bytes === full.bytes
204
+ ? {}
205
+ : { reason: "review_coverage_obligation" }),
206
+ };
207
+ }
208
+ if (shouldPreferSignatureSlicesForLargeFocus(item, full, budget)) {
209
+ const degraded = compactLargeFocusSelection(item) ?? signatureSliceSelection(item);
210
+ if (degraded != null &&
211
+ degraded.bytes < full.bytes &&
212
+ fitsBudget(degraded, budget, totals)) {
213
+ return {
214
+ kind: "selected",
215
+ file: degraded,
216
+ tier: "signature_slices",
217
+ reason: "large_focus_file",
218
+ };
219
+ }
220
+ }
221
+ if (fitsBudget(full, budget, totals)) {
222
+ return {
223
+ kind: "selected",
224
+ file: full,
225
+ tier: "full_file",
226
+ };
227
+ }
228
+ const degraded = item.source === "focus" && !item.has_search_evidence
229
+ ? compactLargeFocusSelection(item) ?? signatureSliceSelection(item)
230
+ : signatureSliceSelection(item);
231
+ if (degraded != null && fitsBudget(degraded, budget, totals)) {
232
+ return {
233
+ kind: "selected",
234
+ file: degraded,
235
+ tier: "signature_slices",
236
+ reason: budgetFailureReason(full, budget, totals),
237
+ };
238
+ }
239
+ const reason = budgetFailureReason(full, budget, totals);
240
+ return {
241
+ kind: "omitted",
242
+ reason,
243
+ message: budgetOmissionMessage(reason),
244
+ };
245
+ }
246
+ function budgetFittingSelectionForRanges(item, requestedRanges, budget, totals) {
247
+ let best = null;
248
+ const admitted = [];
249
+ for (const range of [...requestedRanges].sort((left, right) => left.start_line - right.start_line || left.end_line - right.end_line)) {
250
+ const candidate = selectionForRanges(item, [...admitted, range]);
251
+ if (candidate == null || !fitsBudget(candidate, budget, totals)) {
252
+ continue;
253
+ }
254
+ admitted.push(range);
255
+ best = candidate;
256
+ }
257
+ return best;
258
+ }
259
+ function selectionForRanges(item, requestedRanges) {
260
+ const renderedLineNumbers = renderedContentLineNumbers(item.ranges);
261
+ const lines = splitTextLines(item.content);
262
+ const linesByOriginalLine = linesByOriginalLineNumber(lines, renderedLineNumbers);
263
+ const selectedLines = new Set();
264
+ for (const requested of requestedRanges) {
265
+ for (let line = requested.start_line; line <= requested.end_line; line++) {
266
+ if (linesByOriginalLine.has(line)) {
267
+ selectedLines.add(line);
268
+ }
269
+ }
270
+ }
271
+ if (selectedLines.size === 0) {
272
+ return null;
273
+ }
274
+ const ranges = mergeLineRanges([...selectedLines].map((line) => ({ start_line: line, end_line: line })));
275
+ const content = ranges
276
+ .flatMap((range) => linesForOriginalRange(range, linesByOriginalLine))
277
+ .join("\n");
278
+ const bytes = Buffer.byteLength(content, "utf8");
279
+ return {
280
+ root_index: item.root_index,
281
+ path: item.path,
282
+ ranges,
283
+ content,
284
+ bytes,
285
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
286
+ source: item.source,
287
+ };
288
+ }
289
+ const LARGE_FOCUS_OUTLINE_HEAD_LINES = 80;
290
+ const LARGE_FOCUS_OUTLINE_SYMBOL_LINES = 12;
291
+ const LARGE_FOCUS_RELEVANT_SYMBOL_LINES = 96;
292
+ const LARGE_FOCUS_RELEVANT_LINE_CONTEXT = 24;
293
+ const LARGE_FOCUS_OUTLINE_MAX_LINES = 320;
294
+ const LARGE_TEST_OUTLINE_MAX_LINES = 240;
295
+ function compactLargeFocusSelection(item) {
296
+ if (item.source !== "focus") {
297
+ return null;
298
+ }
299
+ const renderedLineNumbers = renderedContentLineNumbers(item.ranges);
300
+ if (renderedLineNumbers.length <= LARGE_FOCUS_OUTLINE_HEAD_LINES) {
301
+ return null;
302
+ }
303
+ const codemap = buildFileCodemap(item.path, item.content);
304
+ if (codemap.symbols.length === 0) {
305
+ return null;
306
+ }
307
+ const maxLines = isTestPath(item.path)
308
+ ? LARGE_TEST_OUTLINE_MAX_LINES
309
+ : LARGE_FOCUS_OUTLINE_MAX_LINES;
310
+ const selectedLineNumbers = new Set();
311
+ const lines = splitTextLines(item.content);
312
+ const relevanceTokens = combinedRelevanceTokens(item);
313
+ const relevantWindows = relevanceTokens.size > 0
314
+ ? relevantSymbolWindows(codemap.symbols, lines, relevanceTokens)
315
+ : [];
316
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, 1, LARGE_FOCUS_OUTLINE_HEAD_LINES, maxLines);
317
+ for (const window of relevantWindows) {
318
+ if (selectedLineNumbers.size >= maxLines) {
319
+ break;
320
+ }
321
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, window.start_line, window.end_line, maxLines);
322
+ }
323
+ for (const symbol of codemap.symbols) {
324
+ if (selectedLineNumbers.size >= maxLines) {
325
+ break;
326
+ }
327
+ const symbolWindowEnd = symbol.kind === "import" ||
328
+ symbol.kind === "export" ||
329
+ symbol.kind === "interface" ||
330
+ symbol.kind === "type"
331
+ ? symbol.end_line
332
+ : Math.min(symbol.end_line, symbol.start_line + LARGE_FOCUS_OUTLINE_SYMBOL_LINES - 1);
333
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, symbol.start_line, symbolWindowEnd, maxLines);
334
+ }
335
+ if (selectedLineNumbers.size === 0) {
336
+ return null;
337
+ }
338
+ const linesByOriginalLine = linesByOriginalLineNumber(lines, renderedLineNumbers);
339
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((lineNumber) => ({
340
+ start_line: lineNumber,
341
+ end_line: lineNumber,
342
+ })));
343
+ const content = ranges
344
+ .flatMap((range) => linesForOriginalRange(range, linesByOriginalLine))
345
+ .join("\n");
346
+ const bytes = Buffer.byteLength(content, "utf8");
347
+ if (bytes >= item.bytes) {
348
+ return null;
349
+ }
350
+ return {
351
+ root_index: item.root_index,
352
+ path: item.path,
353
+ ranges,
354
+ content,
355
+ bytes,
356
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
357
+ source: item.source,
358
+ };
359
+ }
360
+ function combinedRelevanceTokens(item) {
361
+ if (item.task_tokens.size === 0 && item.search_term_tokens.size === 0) {
362
+ return new Set();
363
+ }
364
+ return new Set([...item.task_tokens, ...item.search_term_tokens]);
365
+ }
366
+ function relevantSymbolWindows(symbols, lines, tokens) {
367
+ const windows = [];
368
+ for (const symbol of symbols) {
369
+ const nameMatches = countTokenMatches(tokenizeGenericWords(symbol.name), tokens);
370
+ const matchingLines = matchingRenderedLinesForSymbol(symbol, lines, tokens);
371
+ if (nameMatches === 0 && matchingLines.length === 0) {
372
+ continue;
373
+ }
374
+ windows.push({
375
+ start_line: symbol.start_line,
376
+ end_line: Math.min(symbol.end_line, symbol.start_line + LARGE_FOCUS_RELEVANT_SYMBOL_LINES - 1),
377
+ rank: nameMatches * 100 + matchingLines.length * 10,
378
+ });
379
+ for (const line of matchingLines) {
380
+ windows.push({
381
+ start_line: Math.max(symbol.start_line, line - LARGE_FOCUS_RELEVANT_LINE_CONTEXT),
382
+ end_line: Math.min(symbol.end_line, line + LARGE_FOCUS_RELEVANT_LINE_CONTEXT),
383
+ rank: nameMatches * 100 + 50,
384
+ });
385
+ }
386
+ }
387
+ return windows.sort((left, right) => right.rank - left.rank ||
388
+ left.start_line - right.start_line ||
389
+ left.end_line - right.end_line);
390
+ }
391
+ function matchingRenderedLinesForSymbol(symbol, lines, tokens) {
392
+ const matchingLines = [];
393
+ for (let line = symbol.start_line; line <= symbol.end_line; line++) {
394
+ const content = lines[line - 1];
395
+ if (content == null) {
396
+ continue;
397
+ }
398
+ if (countTokenMatches(tokenizeGenericWords(content), tokens) > 0) {
399
+ matchingLines.push(line);
400
+ }
401
+ }
402
+ return matchingLines;
403
+ }
404
+ function countTokenMatches(candidates, tokens) {
405
+ let matches = 0;
406
+ for (const candidate of new Set(candidates)) {
407
+ if (tokens.has(candidate)) {
408
+ matches += 1;
409
+ }
410
+ }
411
+ return matches;
412
+ }
413
+ function addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, startLine, endLine, maxLines) {
414
+ for (let renderedLine = startLine; renderedLine <= endLine; renderedLine++) {
415
+ if (selectedLineNumbers.size >= maxLines) {
416
+ return;
417
+ }
418
+ const originalLine = renderedLineNumbers[renderedLine - 1];
419
+ if (originalLine != null) {
420
+ selectedLineNumbers.add(originalLine);
421
+ }
422
+ }
423
+ }
424
+ function shouldPreferSignatureSlicesForLargeFocus(item, file, budget) {
425
+ if (item.source !== "focus") {
426
+ return false;
427
+ }
428
+ if (item.has_search_evidence && !isTestPath(item.path)) {
429
+ return false;
430
+ }
431
+ return file.estimated_tokens > focusWholeFileTokenTarget(item.path, budget);
432
+ }
433
+ function selectedFileFromPending(item) {
434
+ return {
435
+ root_index: item.root_index,
436
+ path: item.path,
437
+ ranges: item.ranges,
438
+ content: item.content,
439
+ bytes: item.bytes,
440
+ estimated_tokens: item.estimated_tokens,
441
+ source: item.source,
442
+ };
443
+ }
444
+ function fitsBudget(file, budget, totals) {
445
+ return (file.bytes <= budget.max_bytes_per_file &&
446
+ totals.totalBytes + file.bytes <= budget.max_total_bytes &&
447
+ totals.totalTokens + file.estimated_tokens <= budget.target_estimated_tokens);
448
+ }
449
+ function budgetFailureReason(file, budget, totals) {
450
+ if (file.bytes > budget.max_bytes_per_file) {
451
+ return "max_bytes_per_file";
452
+ }
453
+ if (totals.totalBytes + file.bytes > budget.max_total_bytes) {
454
+ return "max_total_bytes";
455
+ }
456
+ return "target_estimated_tokens";
457
+ }
458
+ function budgetOmissionMessage(reason) {
459
+ if (reason === "max_bytes_per_file") {
460
+ return "Selected context omitted by max_bytes_per_file budget";
461
+ }
462
+ if (reason === "max_total_bytes") {
463
+ return "Selected context omitted by max_total_bytes budget";
464
+ }
465
+ return "Selected context omitted by target estimated token budget";
466
+ }
467
+ function signatureSliceSelection(item) {
468
+ const codemap = buildFileCodemap(item.path, item.content);
469
+ const signatures = codemap.symbols.filter((symbol) => symbol.kind !== "import");
470
+ if (signatures.length === 0) {
471
+ return null;
472
+ }
473
+ const lines = splitTextLines(item.content);
474
+ const renderedLineNumbers = renderedContentLineNumbers(item.ranges);
475
+ const selectedLineNumbers = new Set();
476
+ const linesByOriginalLine = linesByOriginalLineNumber(lines, renderedLineNumbers);
477
+ for (const symbol of signatures) {
478
+ const lineIndexes = renderedLineIndexesForRange(symbol.start_line, symbol.end_line, renderedLineNumbers);
479
+ if (lineIndexes.length === 0) {
480
+ continue;
481
+ }
482
+ for (const index of lineIndexes) {
483
+ const originalLine = renderedLineNumbers[index];
484
+ if (originalLine != null) {
485
+ selectedLineNumbers.add(originalLine);
486
+ }
487
+ }
488
+ }
489
+ if (selectedLineNumbers.size === 0) {
490
+ return null;
491
+ }
492
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((lineNumber) => ({
493
+ start_line: lineNumber,
494
+ end_line: lineNumber,
495
+ })));
496
+ const content = ranges
497
+ .flatMap((range) => linesForOriginalRange(range, linesByOriginalLine))
498
+ .join("\n");
499
+ const bytes = Buffer.byteLength(content, "utf8");
500
+ return {
501
+ root_index: item.root_index,
502
+ path: item.path,
503
+ ranges,
504
+ content,
505
+ bytes,
506
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
507
+ source: item.source,
508
+ };
509
+ }
510
+ function linesByOriginalLineNumber(lines, renderedLineNumbers) {
511
+ const linesByOriginalLine = new Map();
512
+ for (let index = 0; index < renderedLineNumbers.length; index++) {
513
+ const originalLine = renderedLineNumbers[index];
514
+ if (originalLine != null && !linesByOriginalLine.has(originalLine)) {
515
+ linesByOriginalLine.set(originalLine, lines[index] ?? "");
516
+ }
517
+ }
518
+ return linesByOriginalLine;
519
+ }
520
+ function renderedContentLineNumbers(ranges) {
521
+ const lineNumbers = [];
522
+ ranges.forEach((range) => {
523
+ for (let line = range.start_line; line <= range.end_line; line++) {
524
+ lineNumbers.push(line);
525
+ }
526
+ });
527
+ return lineNumbers;
528
+ }
529
+ function renderedLineIndexesForRange(startLine, endLine, renderedLineNumbers) {
530
+ const indexes = [];
531
+ for (let line = startLine; line <= endLine; line++) {
532
+ const index = line - 1;
533
+ if (index >= 0 && index < renderedLineNumbers.length) {
534
+ indexes.push(index);
535
+ }
536
+ }
537
+ return indexes;
538
+ }
539
+ function linesForOriginalRange(range, linesByOriginalLine) {
540
+ const lines = [];
541
+ for (let lineNumber = range.start_line; lineNumber <= range.end_line; lineNumber++) {
542
+ lines.push(linesByOriginalLine.get(lineNumber) ?? "");
543
+ }
544
+ return lines;
545
+ }
546
+ function selectionSummaryFile(file, tier, reason) {
547
+ return {
548
+ root_index: file.root_index,
549
+ path: file.path,
550
+ tier,
551
+ bytes: file.bytes,
552
+ estimated_tokens: file.estimated_tokens,
553
+ ...(reason == null ? {} : { reason }),
554
+ };
555
+ }
556
+ function buildPendingSelections(slices, search, task, budget) {
557
+ const grouped = new Map();
558
+ for (const slice of slices) {
559
+ const key = `${slice.root_index}\u0000${slice.path}`;
560
+ const existing = grouped.get(key) ?? [];
561
+ existing.push(slice);
562
+ grouped.set(key, existing);
563
+ }
564
+ const pathSearchTermRanks = buildPathSearchTermRanks(search);
565
+ const searchHitCounts = buildSearchHitCounts(search);
566
+ const focusPaths = buildFocusPaths(slices);
567
+ const taskTokens = tokenizeTaskWords(task);
568
+ const searchTermTokens = tokenizeSearchTerms(search);
569
+ const normalizedTask = task.toLowerCase();
570
+ const adjacencyRanks = buildAdjacencyRanks(slices);
571
+ const pending = [];
572
+ for (const records of grouped.values()) {
573
+ const first = records[0];
574
+ if (first == null) {
575
+ continue;
576
+ }
577
+ const hasSearchEvidence = records.some((slice) => slice.source === "search");
578
+ const focusRecords = records.filter((slice) => slice.source === "focus");
579
+ const searchRecords = records.filter((slice) => slice.source === "search");
580
+ const rawEvidenceRecords = (focusRecords.length > 0 &&
581
+ shouldPreferFullFocusEvidence(focusRecords, budget))
582
+ ? focusRecords
583
+ : hasSearchEvidence
584
+ ? searchRecords
585
+ : records;
586
+ const evidenceRecords = rawEvidenceRecords;
587
+ if (evidenceRecords.length === 0) {
588
+ continue;
589
+ }
590
+ const sorted = [...evidenceRecords].sort(compareSlices);
591
+ const ranges = mergeLineRanges(sorted);
592
+ const content = ranges.map((range) => renderMergedRange(range, sorted)).join("\n");
593
+ const bytes = Buffer.byteLength(content, "utf8");
594
+ const contentTokens = boundedContentTokens(content);
595
+ const hasContentSupport = contentTokens != null && taskTokens.size > 0
596
+ ? hasAnyTaskToken(contentTokens, taskTokens)
597
+ : false;
598
+ pending.push({
599
+ root_index: first.root_index,
600
+ path: first.path,
601
+ ranges,
602
+ content,
603
+ bytes,
604
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
605
+ source: records.some((record) => record.source === "focus")
606
+ ? "focus"
607
+ : "search",
608
+ first_line: Math.min(...ranges.map((range) => range.start_line)),
609
+ first_search_term_index: Math.min(...sorted.map((slice) => slice.search_term_index ?? Number.MAX_SAFE_INTEGER)),
610
+ task_support_rank: taskSupportRank(first.path, normalizedTask, hasContentSupport),
611
+ content_match_rank: contentMatchRank(contentTokens, taskTokens),
612
+ path_search_term_rank: pathSearchTermRanks.get(`${first.root_index}\u0000${first.path}`) ?? 0,
613
+ focus_proximity_rank: focusProximityRank(first.path, focusPaths),
614
+ search_hit_density_rank: searchHitDensityRank(searchHitCounts.get(`${first.root_index}\u0000${first.path}`) ?? 0),
615
+ name_overlap_rank: nameOverlapRank(first.path, taskTokens),
616
+ adjacency_rank: adjacencyRanks.get(`${first.root_index}\u0000${first.path}`) ?? 0,
617
+ small_closure_rank: smallClosureRank(first.path, bytes, contentTokens, taskTokens, searchTermTokens),
618
+ has_search_evidence: hasSearchEvidence,
619
+ task_tokens: taskTokens,
620
+ search_term_tokens: searchTermTokens,
621
+ });
622
+ }
623
+ return pending.sort(comparePendingSelections);
624
+ }
625
+ function shouldPreferFullFocusEvidence(records, budget) {
626
+ const first = records[0];
627
+ if (first == null) {
628
+ return false;
629
+ }
630
+ const { bytes, estimatedTokens } = fullEvidenceStats(records);
631
+ return (bytes <= budget.max_bytes_per_file &&
632
+ estimatedTokens <= focusWholeFileTokenTarget(first.path, budget));
633
+ }
634
+ function fullEvidenceStats(records) {
635
+ const sorted = [...records].sort(compareSlices);
636
+ const ranges = mergeLineRanges(sorted);
637
+ const content = ranges.map((range) => renderMergedRange(range, sorted)).join("\n");
638
+ const bytes = Buffer.byteLength(content, "utf8");
639
+ return {
640
+ bytes,
641
+ estimatedTokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
642
+ };
643
+ }
644
+ function focusWholeFileTokenTarget(path, budget) {
645
+ return isTestPath(path)
646
+ ? Math.min(8_000, Math.floor(budget.target_estimated_tokens * 0.12))
647
+ : Math.min(12_000, Math.floor(budget.target_estimated_tokens * 0.18));
648
+ }
649
+ function taskSupportRank(path, normalizedTask, hasContentSupport) {
650
+ if (normalizedTask.length === 0) {
651
+ return 0;
652
+ }
653
+ let rank = 0;
654
+ // Corroboration requirement: a path-name match with the task intent only
655
+ // earns the implementation- or test-intent boost when the file's CONTENT also
656
+ // carries at least one task token. A broad path token (e.g. "provider") can
657
+ // collide with the task vocabulary while the file's content is off-topic;
658
+ // requiring content support stops such path noise from being lifted into
659
+ // top-R. Content support reuses the same task-token logic as content_match_rank.
660
+ if (hasContentSupport &&
661
+ isImplementationPath(path) &&
662
+ pathMatchesTaskIntent(path, normalizedTask)) {
663
+ rank -= 8;
664
+ }
665
+ const asksForTestSafety = /\btests?\b/.test(normalizedTask) ||
666
+ /\bwithout breaking\b/.test(normalizedTask) ||
667
+ /\bsafely\b/.test(normalizedTask) ||
668
+ /\bregression\b/.test(normalizedTask);
669
+ // Only boost a test path when the task explicitly asks for test/safety
670
+ // coverage AND the path is topically related to the task AND the file's
671
+ // content actually carries a task token. A test that merely exists, or whose
672
+ // name collides with the task but whose content is off-topic, must not be
673
+ // promoted ahead of related implementation evidence once task_support_rank
674
+ // leads the comparator.
675
+ if (asksForTestSafety &&
676
+ hasContentSupport &&
677
+ isTestPath(path) &&
678
+ pathMatchesTaskIntent(path, normalizedTask)) {
679
+ rank -= 4;
680
+ }
681
+ // The endpoint/route/api and redact/sanitize boosts are path-intent boosts
682
+ // too, so they carry the same corroboration requirement: a file that merely
683
+ // lives under an endpoints/ directory (or whose path mentions redact) but whose
684
+ // CONTENT has no task token must not be lifted ahead of content-relevant
685
+ // evidence.
686
+ if (hasContentSupport &&
687
+ /\b(endpoint|route|api)\b/.test(normalizedTask) &&
688
+ isGenericEndpointPath(path)) {
689
+ rank -= 4;
690
+ }
691
+ if (hasContentSupport &&
692
+ /\b(redact|redacted|redaction|sanitize|sanitization)\b/.test(normalizedTask) &&
693
+ /redact|redaction|sanitize/.test(path.toLowerCase())) {
694
+ rank -= 4;
695
+ }
696
+ return rank;
697
+ }
698
+ function isGenericEndpointPath(path) {
699
+ // The endpoint/route/api intent boost targets implementation endpoint files.
700
+ // A test path that merely lives under an api/ directory must NOT inherit this
701
+ // implementation-intent boost, or it would outrank genuine implementation
702
+ // evidence once task_support_rank leads the comparator. The separate
703
+ // test-safety rule covers test paths.
704
+ if (isTestPath(path)) {
705
+ return false;
706
+ }
707
+ const directoryTokens = tokenizePath(path).directories;
708
+ return (directoryTokens.has("api") ||
709
+ directoryTokens.has("endpoint") ||
710
+ directoryTokens.has("route"));
711
+ }
712
+ function buildSearchHitCounts(search) {
713
+ const counts = new Map();
714
+ for (const record of search) {
715
+ const key = `${record.root_index}\u0000${record.path}`;
716
+ counts.set(key, (counts.get(key) ?? 0) + 1);
717
+ }
718
+ return counts;
719
+ }
720
+ function buildFocusPaths(slices) {
721
+ return [
722
+ ...new Set(slices
723
+ .filter((slice) => slice.source === "focus")
724
+ .map((slice) => slice.path)),
725
+ ].sort();
726
+ }
727
+ function focusProximityRank(path, focusPaths) {
728
+ if (focusPaths.length === 0) {
729
+ return 0;
730
+ }
731
+ return Math.min(...focusPaths.map((focusPath) => directoryDistance(path, focusPath)));
732
+ }
733
+ function searchHitDensityRank(hitCount) {
734
+ return -hitCount;
735
+ }
736
+ function nameOverlapRank(path, taskTokens) {
737
+ if (taskTokens.size === 0) {
738
+ return 0;
739
+ }
740
+ const pathTokens = tokenizePath(path);
741
+ let score = 0;
742
+ for (const token of pathTokens.basename) {
743
+ if (taskTokens.has(token)) {
744
+ score += 2;
745
+ }
746
+ }
747
+ for (const token of pathTokens.directories) {
748
+ if (taskTokens.has(token)) {
749
+ score += 1;
750
+ }
751
+ }
752
+ return -score;
753
+ }
754
+ const SMALL_CLOSURE_MAX_BYTES = 24_000;
755
+ function smallClosureRank(path, bytes, contentTokens, taskTokens, searchTermTokens) {
756
+ if (bytes > SMALL_CLOSURE_MAX_BYTES || !isSmallClosurePath(path)) {
757
+ return 0;
758
+ }
759
+ const tokens = new Set([...taskTokens, ...searchTermTokens]);
760
+ if (tokens.size === 0 || contentTokens == null) {
761
+ return 0;
762
+ }
763
+ const contentMatches = countTokenMatches([...contentTokens], tokens);
764
+ const pathMatches = countTokenMatches([
765
+ ...tokenizePath(path).basename,
766
+ ...tokenizePath(path).directories,
767
+ ], tokens);
768
+ if (contentMatches === 0 || pathMatches === 0) {
769
+ return 0;
770
+ }
771
+ return -Math.min(10, contentMatches + pathMatches);
772
+ }
773
+ function isSmallClosurePath(path) {
774
+ const normalized = path.toLowerCase();
775
+ const basename = normalized.split("/").at(-1) ?? normalized;
776
+ return (normalized.includes("/types/") ||
777
+ normalized.includes("/schemas/") ||
778
+ normalized.includes("/models/schemas/") ||
779
+ normalized.includes("/constants.") ||
780
+ normalized.includes("/config.") ||
781
+ basename.endsWith(".types.ts") ||
782
+ basename.endsWith(".types.tsx") ||
783
+ basename === "types.ts" ||
784
+ basename === "schema.ts" ||
785
+ basename === "schemas.ts" ||
786
+ basename === "constants.ts" ||
787
+ basename === "constants.py" ||
788
+ basename === "config.ts" ||
789
+ basename === "config.py");
790
+ }
791
+ // Tokenize the (bounded) content of a pending selection into the distinct
792
+ // generic words it contains. Computed once per pending item and reused by both
793
+ // content_match_rank and the task_support_rank corroboration check, so the two
794
+ // signals always agree on what "content support" means.
795
+ //
796
+ // Literal-free: tokens come entirely from the content via tokenizeGenericWords
797
+ // (camelCase split, plural stem, GENERIC_TASK_WORDS / short-token drop). Empty
798
+ // content => null (no tokens, treated as no content support / neutral rank).
799
+ //
800
+ // Cost bound: tokenizing arbitrarily large repeated content is wasteful, so we
801
+ // only tokenize the first ~64K CHARACTERS of content. Task-relevant matches
802
+ // saturate the distinct-token set long before that cap, so truncation cannot
803
+ // lose a match that would have changed the rank in practice. The cap measures
804
+ // UTF-16 code units (content.length), not bytes — hence the CHAR naming.
805
+ const CONTENT_MATCH_RANK_CHAR_CAP = 64 * 1024;
806
+ function boundedContentTokens(content) {
807
+ if (content.length === 0) {
808
+ return null;
809
+ }
810
+ const bounded = content.length > CONTENT_MATCH_RANK_CHAR_CAP
811
+ ? content.slice(0, CONTENT_MATCH_RANK_CHAR_CAP)
812
+ : content;
813
+ return new Set(tokenizeGenericWords(bounded));
814
+ }
815
+ function hasAnyTaskToken(contentTokens, taskTokens) {
816
+ for (const token of taskTokens) {
817
+ if (contentTokens.has(token)) {
818
+ return true;
819
+ }
820
+ }
821
+ return false;
822
+ }
823
+ // Generic content-relevance signal. Ranks a pending selection by how many
824
+ // DISTINCT task tokens appear in its sliced CONTENT (not its path name). More
825
+ // distinct matches => more negative => sorts earlier (kept). This is the only
826
+ // signal that inspects what a file actually contains rather than its name,
827
+ // search-hit density, or path kind — so an off-topic file with incidental name
828
+ // overlap and high line count can no longer outrank a content-relevant file.
829
+ //
830
+ // Empty task tokens or empty content => 0 (neutral, no effect on ordering).
831
+ function contentMatchRank(contentTokens, taskTokens) {
832
+ if (taskTokens.size === 0 || contentTokens == null) {
833
+ return 0;
834
+ }
835
+ let distinctMatches = 0;
836
+ for (const token of taskTokens) {
837
+ if (contentTokens.has(token)) {
838
+ distinctMatches += 1;
839
+ }
840
+ }
841
+ return -distinctMatches;
842
+ }
843
+ function buildAdjacencyRanks(slices) {
844
+ const byRoot = new Map();
845
+ for (const slice of slices) {
846
+ const paths = byRoot.get(slice.root_index) ?? [];
847
+ paths.push(slice.path);
848
+ byRoot.set(slice.root_index, paths);
849
+ }
850
+ const ranks = new Map();
851
+ // O(P^2) per root group, but P is bounded by the discovery candidate cap
852
+ // (max_discovery_candidates), so the quadratic is safe in practice.
853
+ for (const [rootIndex, paths] of byRoot) {
854
+ const uniquePaths = [...new Set(paths)].sort();
855
+ for (const candidatePath of uniquePaths) {
856
+ ranks.set(`${rootIndex}\u0000${candidatePath}`, siblingAdjacencyScore(candidatePath, uniquePaths));
857
+ }
858
+ }
859
+ return ranks;
860
+ }
861
+ function siblingAdjacencyScore(path, allPaths) {
862
+ const stem = normalizedPathStem(path);
863
+ const pathKind = genericPathKind(path);
864
+ let score = 0;
865
+ for (const other of allPaths) {
866
+ if (other === path || normalizedPathStem(other) !== stem) {
867
+ continue;
868
+ }
869
+ const otherKind = genericPathKind(other);
870
+ if (pathKind !== otherKind) {
871
+ score += 1;
872
+ }
873
+ }
874
+ return -score;
875
+ }
876
+ function tokenizeTaskWords(task) {
877
+ return new Set(tokenizeGenericWords(task));
878
+ }
879
+ function tokenizeSearchTerms(search) {
880
+ return new Set(search.flatMap((record) => tokenizeGenericWords(record.search_term)));
881
+ }
882
+ function tokenizePath(path) {
883
+ const parts = path.split("/");
884
+ const basename = parts.pop() ?? path;
885
+ return {
886
+ basename: new Set(tokenizeGenericWords(basename.replace(/\.[^.]+$/, ""))),
887
+ directories: new Set(parts.flatMap((part) => tokenizeGenericWords(part))),
888
+ };
889
+ }
890
+ function tokenizeGenericWords(value) {
891
+ return value
892
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
893
+ .split(/[^A-Za-z0-9]+/)
894
+ .map((word) => normalizeGenericWord(word))
895
+ .filter((word) => word.length >= 3 && !GENERIC_TASK_WORDS.has(word));
896
+ }
897
+ function normalizeGenericWord(word) {
898
+ const lower = word.toLowerCase();
899
+ if (lower.length > 4 && lower.endsWith("ies")) {
900
+ return `${lower.slice(0, -3)}y`;
901
+ }
902
+ if (lower.length > 3 && lower.endsWith("s")) {
903
+ return lower.slice(0, -1);
904
+ }
905
+ return lower;
906
+ }
907
+ const GENERIC_TASK_WORDS = new Set([
908
+ "the",
909
+ "and",
910
+ "for",
911
+ "with",
912
+ "that",
913
+ "this",
914
+ "from",
915
+ "into",
916
+ "without",
917
+ "breaking",
918
+ "change",
919
+ "fix",
920
+ "add",
921
+ "new",
922
+ "safe",
923
+ "safely",
924
+ "test",
925
+ "tests",
926
+ ]);
927
+ function buildPathSearchTermRanks(search) {
928
+ const ranks = new Map();
929
+ for (const record of search) {
930
+ const normalizedPath = normalizePathForSearchTermRank(record.path);
931
+ const normalizedTerm = normalizePathForSearchTermRank(record.search_term);
932
+ if (normalizedTerm.length < 3 || !normalizedPath.includes(normalizedTerm)) {
933
+ continue;
934
+ }
935
+ const key = `${record.root_index}\u0000${record.path}`;
936
+ const rank = -normalizedTerm.length;
937
+ ranks.set(key, Math.min(ranks.get(key) ?? 0, rank));
938
+ }
939
+ return ranks;
940
+ }
941
+ function normalizePathForSearchTermRank(value) {
942
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
943
+ }
944
+ function pathMatchesTaskIntent(path, normalizedTask) {
945
+ const taskWords = new Set(normalizedTask.match(/[a-z0-9]+/g) ?? []);
946
+ const pathWords = path
947
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
948
+ .toLowerCase()
949
+ .split(/[^a-z0-9]+/)
950
+ .filter((word) => word.length >= 6 && !GENERIC_TASK_PATH_WORDS.has(word));
951
+ return pathWords.some((word) => taskWords.has(word));
952
+ }
953
+ const GENERIC_TASK_PATH_WORDS = new Set([
954
+ "backend",
955
+ "frontend",
956
+ "components",
957
+ "endpoints",
958
+ "models",
959
+ "queries",
960
+ "schemas",
961
+ "services",
962
+ ]);
963
+ function renderMergedRange(range, records) {
964
+ const linesByNumber = new Map();
965
+ for (const record of records) {
966
+ const lines = splitTextLines(record.content);
967
+ for (let index = 0; index < lines.length; index++) {
968
+ const lineNumber = record.start_line + index;
969
+ if (lineNumber >= range.start_line &&
970
+ lineNumber <= range.end_line &&
971
+ !linesByNumber.has(lineNumber)) {
972
+ linesByNumber.set(lineNumber, lines[index] ?? "");
973
+ }
974
+ }
975
+ }
976
+ const lines = [];
977
+ for (let lineNumber = range.start_line; lineNumber <= range.end_line; lineNumber++) {
978
+ lines.push(linesByNumber.get(lineNumber) ?? "");
979
+ }
980
+ return lines.join("\n");
981
+ }
982
+ function comparePendingSelections(left, right) {
983
+ const baseComparison = crossSourceFocusedSafetyTestRank(left, right) ||
984
+ relevanceRank(left) - relevanceRank(right) ||
985
+ sourceRank(left.source) - sourceRank(right.source);
986
+ if (baseComparison !== 0) {
987
+ return baseComparison;
988
+ }
989
+ if (left.source === "focus" && right.source === "focus") {
990
+ return (strongImplementationPathSearchRank(left) -
991
+ strongImplementationPathSearchRank(right) ||
992
+ left.task_support_rank - right.task_support_rank ||
993
+ focusedSafetyTestRank(left) - focusedSafetyTestRank(right) ||
994
+ // Explicit task intent (task_support_rank) wins first; then a file whose
995
+ // actual CONTENT matches the task outranks the generic structural
996
+ // impl>test>doc prior. The structural prior remains the tiebreak when
997
+ // content match is equal, so the common no-task-token case is unchanged.
998
+ left.content_match_rank - right.content_match_rank ||
999
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1000
+ left.path_search_term_rank - right.path_search_term_rank ||
1001
+ left.first_search_term_index - right.first_search_term_index ||
1002
+ left.search_hit_density_rank - right.search_hit_density_rank ||
1003
+ left.small_closure_rank - right.small_closure_rank ||
1004
+ left.name_overlap_rank - right.name_overlap_rank ||
1005
+ left.adjacency_rank - right.adjacency_rank ||
1006
+ left.focus_proximity_rank - right.focus_proximity_rank ||
1007
+ left.root_index - right.root_index ||
1008
+ left.path.localeCompare(right.path) ||
1009
+ left.first_line - right.first_line);
1010
+ }
1011
+ return (strongImplementationPathSearchRank(left) -
1012
+ strongImplementationPathSearchRank(right) ||
1013
+ left.task_support_rank - right.task_support_rank ||
1014
+ // Explicit task intent (task_support_rank) wins first; then a file whose
1015
+ // actual CONTENT matches the task outranks the generic structural
1016
+ // impl>test>doc prior. The structural prior remains the tiebreak when
1017
+ // content match is equal, so the common no-task-token case is unchanged.
1018
+ left.content_match_rank - right.content_match_rank ||
1019
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1020
+ left.path_search_term_rank - right.path_search_term_rank ||
1021
+ left.first_search_term_index - right.first_search_term_index ||
1022
+ left.search_hit_density_rank - right.search_hit_density_rank ||
1023
+ left.small_closure_rank - right.small_closure_rank ||
1024
+ left.name_overlap_rank - right.name_overlap_rank ||
1025
+ left.adjacency_rank - right.adjacency_rank ||
1026
+ left.focus_proximity_rank - right.focus_proximity_rank ||
1027
+ left.root_index - right.root_index ||
1028
+ left.path.localeCompare(right.path) ||
1029
+ left.first_line - right.first_line);
1030
+ }
1031
+ function strongImplementationPathSearchRank(item) {
1032
+ return isImplementationPath(item.path) && item.path_search_term_rank <= -20 ? -1 : 0;
1033
+ }
1034
+ function crossSourceFocusedSafetyTestRank(left, right) {
1035
+ if (left.source === right.source) {
1036
+ return 0;
1037
+ }
1038
+ return focusedSafetyTestRank(left) - focusedSafetyTestRank(right);
1039
+ }
1040
+ function focusedSafetyTestRank(item) {
1041
+ return item.source === "focus" && isTestPath(item.path) && item.task_support_rank < 0
1042
+ ? -1
1043
+ : 0;
1044
+ }
1045
+ function pathEvidenceRank(path) {
1046
+ if (isImplementationPath(path)) {
1047
+ return 0;
1048
+ }
1049
+ if (isTestPath(path)) {
1050
+ return 1;
1051
+ }
1052
+ if (isHiddenOrGeneratedPath(path)) {
1053
+ return 4;
1054
+ }
1055
+ if (isProjectDocPath(path)) {
1056
+ return 2;
1057
+ }
1058
+ return 3;
1059
+ }
1060
+ function isImplementationPath(path) {
1061
+ if (isTestPath(path)) {
1062
+ return false;
1063
+ }
1064
+ return (path.startsWith("src/") ||
1065
+ path.includes("/src/") ||
1066
+ path.includes("/app/"));
1067
+ }
1068
+ function isProjectDocPath(path) {
1069
+ return (path.startsWith("docs/") ||
1070
+ path === "README.md" ||
1071
+ path === "CLAUDE.md" ||
1072
+ path === "AGENTS.md" ||
1073
+ path === "PRODUCT.md" ||
1074
+ path.endsWith(".md"));
1075
+ }
1076
+ function isHiddenOrGeneratedPath(path) {
1077
+ return (path.startsWith(".") ||
1078
+ path.includes("/.") ||
1079
+ path.includes("/dist/") ||
1080
+ path.includes("/build/") ||
1081
+ path.endsWith("package-lock.json"));
1082
+ }
1083
+ function relevanceRank(item) {
1084
+ return item.has_search_evidence ? 0 : 1;
1085
+ }
1086
+ function compareTreeFiles(left, right) {
1087
+ return left.root_index - right.root_index || left.path.localeCompare(right.path);
1088
+ }
1089
+ function compareSearchRecords(left, right) {
1090
+ return (left.root_index - right.root_index ||
1091
+ left.path.localeCompare(right.path) ||
1092
+ left.line - right.line ||
1093
+ left.search_term_index - right.search_term_index);
1094
+ }
1095
+ function compareSlices(left, right) {
1096
+ return (sliceRelevanceRank(left) - sliceRelevanceRank(right) ||
1097
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1098
+ (left.search_term_index ?? Number.MAX_SAFE_INTEGER) -
1099
+ (right.search_term_index ?? Number.MAX_SAFE_INTEGER) ||
1100
+ sourceRank(left.source) - sourceRank(right.source) ||
1101
+ left.root_index - right.root_index ||
1102
+ left.path.localeCompare(right.path) ||
1103
+ left.start_line - right.start_line);
1104
+ }
1105
+ function sliceRelevanceRank(slice) {
1106
+ return slice.source === "search" ? 0 : 1;
1107
+ }
1108
+ function sourceRank(source) {
1109
+ return source === "focus" ? 0 : 1;
1110
+ }
1111
+ //# sourceMappingURL=selection.js.map