clinkx 0.3.0 → 1.1.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 (669) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/LICENSE +10 -0
  3. package/README.md +154 -26
  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/chairman-knobs.d.ts +24 -0
  12. package/clinkx-workflows/dist/chairman-knobs.js +27 -0
  13. package/clinkx-workflows/dist/chairman-knobs.js.map +1 -0
  14. package/clinkx-workflows/dist/citation-check.d.ts +40 -0
  15. package/clinkx-workflows/dist/citation-check.js +348 -0
  16. package/clinkx-workflows/dist/citation-check.js.map +1 -0
  17. package/clinkx-workflows/dist/clink-client.d.ts +12 -1
  18. package/clinkx-workflows/dist/clink-client.js +56 -5
  19. package/clinkx-workflows/dist/clink-client.js.map +1 -1
  20. package/clinkx-workflows/dist/config.d.ts +173 -16
  21. package/clinkx-workflows/dist/config.js +417 -26
  22. package/clinkx-workflows/dist/config.js.map +1 -1
  23. package/clinkx-workflows/dist/contained-file.d.ts +172 -0
  24. package/clinkx-workflows/dist/contained-file.js +483 -0
  25. package/clinkx-workflows/dist/contained-file.js.map +1 -0
  26. package/clinkx-workflows/dist/context-builder-lifecycle-contract.d.ts +416 -0
  27. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js +328 -0
  28. package/clinkx-workflows/dist/context-builder-lifecycle-contract.js.map +1 -0
  29. package/clinkx-workflows/dist/context-builder-lifecycle-router.d.ts +24 -0
  30. package/clinkx-workflows/dist/context-builder-lifecycle-router.js +39 -0
  31. package/clinkx-workflows/dist/context-builder-lifecycle-router.js.map +1 -0
  32. package/clinkx-workflows/dist/context-cache-key.d.ts +53 -0
  33. package/clinkx-workflows/dist/context-cache-key.js +91 -0
  34. package/clinkx-workflows/dist/context-cache-key.js.map +1 -0
  35. package/clinkx-workflows/dist/context-mode-resolver.d.ts +27 -0
  36. package/clinkx-workflows/dist/context-mode-resolver.js +126 -0
  37. package/clinkx-workflows/dist/context-mode-resolver.js.map +1 -0
  38. package/clinkx-workflows/dist/context-preflight.d.ts +189 -0
  39. package/clinkx-workflows/dist/context-preflight.js +91 -0
  40. package/clinkx-workflows/dist/context-preflight.js.map +1 -0
  41. package/clinkx-workflows/dist/council-execution-policy.d.ts +68 -0
  42. package/clinkx-workflows/dist/council-execution-policy.js +110 -0
  43. package/clinkx-workflows/dist/council-execution-policy.js.map +1 -0
  44. package/clinkx-workflows/dist/council-expander.d.ts +10 -9
  45. package/clinkx-workflows/dist/council-expander.js +20 -10
  46. package/clinkx-workflows/dist/council-expander.js.map +1 -1
  47. package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +5718 -0
  48. package/clinkx-workflows/dist/dashboard/activity-contract.js +157 -0
  49. package/clinkx-workflows/dist/dashboard/activity-contract.js.map +1 -0
  50. package/clinkx-workflows/dist/dashboard/activity-lease.d.ts +25 -0
  51. package/clinkx-workflows/dist/dashboard/activity-lease.js +34 -0
  52. package/clinkx-workflows/dist/dashboard/activity-lease.js.map +1 -0
  53. package/clinkx-workflows/dist/dashboard/activity-reader.d.ts +90 -0
  54. package/clinkx-workflows/dist/dashboard/activity-reader.js +493 -0
  55. package/clinkx-workflows/dist/dashboard/activity-reader.js.map +1 -0
  56. package/clinkx-workflows/dist/dashboard/api-routes.d.ts +40 -0
  57. package/clinkx-workflows/dist/dashboard/api-routes.js +1155 -0
  58. package/clinkx-workflows/dist/dashboard/api-routes.js.map +1 -0
  59. package/clinkx-workflows/dist/dashboard/artifact-index.d.ts +37 -0
  60. package/clinkx-workflows/dist/dashboard/artifact-index.js +145 -0
  61. package/clinkx-workflows/dist/dashboard/artifact-index.js.map +1 -0
  62. package/clinkx-workflows/dist/dashboard/auth/challenge-store.d.ts +31 -0
  63. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js +65 -0
  64. package/clinkx-workflows/dist/dashboard/auth/challenge-store.js.map +1 -0
  65. package/clinkx-workflows/dist/dashboard/auth/controller.d.ts +26 -0
  66. package/clinkx-workflows/dist/dashboard/auth/controller.js +596 -0
  67. package/clinkx-workflows/dist/dashboard/auth/controller.js.map +1 -0
  68. package/clinkx-workflows/dist/dashboard/auth/credential-store.d.ts +60 -0
  69. package/clinkx-workflows/dist/dashboard/auth/credential-store.js +776 -0
  70. package/clinkx-workflows/dist/dashboard/auth/credential-store.js.map +1 -0
  71. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.d.ts +9 -0
  72. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js +44 -0
  73. package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js.map +1 -0
  74. package/clinkx-workflows/dist/dashboard/auth/session-store.d.ts +17 -0
  75. package/clinkx-workflows/dist/dashboard/auth/session-store.js +77 -0
  76. package/clinkx-workflows/dist/dashboard/auth/session-store.js.map +1 -0
  77. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.d.ts +25 -0
  78. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js +71 -0
  79. package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js.map +1 -0
  80. package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.d.ts +3865 -0
  81. package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.js +69 -0
  82. package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.js.map +1 -0
  83. package/clinkx-workflows/dist/dashboard/context-run-liveness.d.ts +37 -0
  84. package/clinkx-workflows/dist/dashboard/context-run-liveness.js +49 -0
  85. package/clinkx-workflows/dist/dashboard/context-run-liveness.js.map +1 -0
  86. package/clinkx-workflows/dist/dashboard/context-run-reader.d.ts +256 -0
  87. package/clinkx-workflows/dist/dashboard/context-run-reader.js +1301 -0
  88. package/clinkx-workflows/dist/dashboard/context-run-reader.js.map +1 -0
  89. package/clinkx-workflows/dist/dashboard/contracts.d.ts +28483 -0
  90. package/clinkx-workflows/dist/dashboard/contracts.js +1284 -0
  91. package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -0
  92. package/clinkx-workflows/dist/dashboard/generation.d.ts +14 -0
  93. package/clinkx-workflows/dist/dashboard/generation.js +41 -0
  94. package/clinkx-workflows/dist/dashboard/generation.js.map +1 -0
  95. package/clinkx-workflows/dist/dashboard/index.d.ts +32 -0
  96. package/clinkx-workflows/dist/dashboard/index.js +20 -0
  97. package/clinkx-workflows/dist/dashboard/index.js.map +1 -0
  98. package/clinkx-workflows/dist/dashboard/invocation-contract.d.ts +786 -0
  99. package/clinkx-workflows/dist/dashboard/invocation-contract.js +201 -0
  100. package/clinkx-workflows/dist/dashboard/invocation-contract.js.map +1 -0
  101. package/clinkx-workflows/dist/dashboard/lazy-content.d.ts +114 -0
  102. package/clinkx-workflows/dist/dashboard/lazy-content.js +799 -0
  103. package/clinkx-workflows/dist/dashboard/lazy-content.js.map +1 -0
  104. package/clinkx-workflows/dist/dashboard/native-transcript/contract.d.ts +90 -0
  105. package/clinkx-workflows/dist/dashboard/native-transcript/contract.js +31 -0
  106. package/clinkx-workflows/dist/dashboard/native-transcript/contract.js.map +1 -0
  107. package/clinkx-workflows/dist/dashboard/native-transcript/projection.d.ts +12 -0
  108. package/clinkx-workflows/dist/dashboard/native-transcript/projection.js +286 -0
  109. package/clinkx-workflows/dist/dashboard/native-transcript/projection.js.map +1 -0
  110. package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +446 -0
  111. package/clinkx-workflows/dist/dashboard/progress-report-contract.js +221 -0
  112. package/clinkx-workflows/dist/dashboard/progress-report-contract.js.map +1 -0
  113. package/clinkx-workflows/dist/dashboard/progress-report-reader.d.ts +50 -0
  114. package/clinkx-workflows/dist/dashboard/progress-report-reader.js +529 -0
  115. package/clinkx-workflows/dist/dashboard/progress-report-reader.js.map +1 -0
  116. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +89 -0
  117. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js +71 -0
  118. package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js.map +1 -0
  119. package/clinkx-workflows/dist/dashboard/progress-report-status-store.d.ts +29 -0
  120. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js +111 -0
  121. package/clinkx-workflows/dist/dashboard/progress-report-status-store.js.map +1 -0
  122. package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.d.ts +194 -0
  123. package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.js +89 -0
  124. package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.js.map +1 -0
  125. package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.d.ts +26 -0
  126. package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.js +102 -0
  127. package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.js.map +1 -0
  128. package/clinkx-workflows/dist/dashboard/read-model.d.ts +86 -0
  129. package/clinkx-workflows/dist/dashboard/read-model.js +440 -0
  130. package/clinkx-workflows/dist/dashboard/read-model.js.map +1 -0
  131. package/clinkx-workflows/dist/dashboard/request-admission.d.ts +31 -0
  132. package/clinkx-workflows/dist/dashboard/request-admission.js +130 -0
  133. package/clinkx-workflows/dist/dashboard/request-admission.js.map +1 -0
  134. package/clinkx-workflows/dist/dashboard/scanner.d.ts +78 -0
  135. package/clinkx-workflows/dist/dashboard/scanner.js +1154 -0
  136. package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -0
  137. package/clinkx-workflows/dist/dashboard/server-factory.d.ts +63 -0
  138. package/clinkx-workflows/dist/dashboard/server-factory.js +483 -0
  139. package/clinkx-workflows/dist/dashboard/server-factory.js.map +1 -0
  140. package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +2778 -0
  141. package/clinkx-workflows/dist/dashboard/session-log-contract.js +506 -0
  142. package/clinkx-workflows/dist/dashboard/session-log-contract.js.map +1 -0
  143. package/clinkx-workflows/dist/dashboard/session-log-identity.d.ts +21 -0
  144. package/clinkx-workflows/dist/dashboard/session-log-identity.js +101 -0
  145. package/clinkx-workflows/dist/dashboard/session-log-identity.js.map +1 -0
  146. package/clinkx-workflows/dist/dashboard/session-log-journal.d.ts +43 -0
  147. package/clinkx-workflows/dist/dashboard/session-log-journal.js +529 -0
  148. package/clinkx-workflows/dist/dashboard/session-log-journal.js.map +1 -0
  149. package/clinkx-workflows/dist/dashboard/session-log-reader.d.ts +61 -0
  150. package/clinkx-workflows/dist/dashboard/session-log-reader.js +378 -0
  151. package/clinkx-workflows/dist/dashboard/session-log-reader.js.map +1 -0
  152. package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +14 -0
  153. package/clinkx-workflows/dist/dashboard/session-log-redaction.js +1101 -0
  154. package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -0
  155. package/clinkx-workflows/dist/dashboard/session-log-retention.d.ts +23 -0
  156. package/clinkx-workflows/dist/dashboard/session-log-retention.js +212 -0
  157. package/clinkx-workflows/dist/dashboard/session-log-retention.js.map +1 -0
  158. package/clinkx-workflows/dist/dashboard/static-responses.d.ts +10 -0
  159. package/clinkx-workflows/dist/dashboard/static-responses.js +94 -0
  160. package/clinkx-workflows/dist/dashboard/static-responses.js.map +1 -0
  161. package/clinkx-workflows/dist/dashboard/worker-lock-observer.d.ts +28 -0
  162. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js +241 -0
  163. package/clinkx-workflows/dist/dashboard/worker-lock-observer.js.map +1 -0
  164. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  165. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  166. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  167. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  168. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  169. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  170. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  171. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  172. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  173. package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  174. package/clinkx-workflows/dist/dashboard-ui/assets/index-JPHQVtn9.js +106 -0
  175. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  176. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  177. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  178. package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  179. package/clinkx-workflows/dist/dashboard-ui/assets/style-DOMHk-j6.css +1 -0
  180. package/clinkx-workflows/dist/dashboard-ui/contracts/council-plan-review-input-v1.json +158 -0
  181. package/clinkx-workflows/dist/dashboard-ui/index.html +15 -0
  182. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Mono-OFL.txt +93 -0
  183. package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Sans-OFL.txt +93 -0
  184. package/clinkx-workflows/dist/dashboard-ui/licenses/JetBrains-Mono-OFL.txt +93 -0
  185. package/clinkx-workflows/dist/dashboard-ui/licenses/NOTICE.md +32 -0
  186. package/clinkx-workflows/dist/dashboard-ui/theme-init.js +8 -0
  187. package/clinkx-workflows/dist/definition-normalizer.d.ts +19 -0
  188. package/clinkx-workflows/dist/definition-normalizer.js.map +1 -1
  189. package/clinkx-workflows/dist/delegate-finalizer-policy.d.ts +26 -0
  190. package/clinkx-workflows/dist/delegate-finalizer-policy.js +72 -0
  191. package/clinkx-workflows/dist/delegate-finalizer-policy.js.map +1 -0
  192. package/clinkx-workflows/dist/delegate-signature.d.ts +14 -0
  193. package/clinkx-workflows/dist/delegate-signature.js +14 -0
  194. package/clinkx-workflows/dist/delegate-signature.js.map +1 -0
  195. package/clinkx-workflows/dist/delegate-validate.d.ts +108 -0
  196. package/clinkx-workflows/dist/delegate-validate.js +148 -0
  197. package/clinkx-workflows/dist/delegate-validate.js.map +1 -0
  198. package/clinkx-workflows/dist/engine.d.ts +251 -0
  199. package/clinkx-workflows/dist/engine.js +1342 -92
  200. package/clinkx-workflows/dist/engine.js.map +1 -1
  201. package/clinkx-workflows/dist/errors.d.ts +24 -2
  202. package/clinkx-workflows/dist/errors.js +30 -2
  203. package/clinkx-workflows/dist/errors.js.map +1 -1
  204. package/clinkx-workflows/dist/fidelity.d.ts +47 -1
  205. package/clinkx-workflows/dist/fidelity.js +54 -1
  206. package/clinkx-workflows/dist/fidelity.js.map +1 -1
  207. package/clinkx-workflows/dist/fingerprint.d.ts +25 -7
  208. package/clinkx-workflows/dist/fingerprint.js +33 -10
  209. package/clinkx-workflows/dist/fingerprint.js.map +1 -1
  210. package/clinkx-workflows/dist/index.d.ts +19 -0
  211. package/clinkx-workflows/dist/index.js +68 -1
  212. package/clinkx-workflows/dist/index.js.map +1 -1
  213. package/clinkx-workflows/dist/loader.d.ts +9 -3
  214. package/clinkx-workflows/dist/loader.js +92 -21
  215. package/clinkx-workflows/dist/loader.js.map +1 -1
  216. package/clinkx-workflows/dist/logger.d.ts +1 -1
  217. package/clinkx-workflows/dist/logger.js +17 -3
  218. package/clinkx-workflows/dist/logger.js.map +1 -1
  219. package/clinkx-workflows/dist/monotonic-clock.d.ts +19 -0
  220. package/clinkx-workflows/dist/monotonic-clock.js +22 -0
  221. package/clinkx-workflows/dist/monotonic-clock.js.map +1 -0
  222. package/clinkx-workflows/dist/plan-review/admission.d.ts +160 -0
  223. package/clinkx-workflows/dist/plan-review/admission.js +290 -0
  224. package/clinkx-workflows/dist/plan-review/admission.js.map +1 -0
  225. package/clinkx-workflows/dist/plan-review/context-policy.d.ts +55 -0
  226. package/clinkx-workflows/dist/plan-review/context-policy.js +146 -0
  227. package/clinkx-workflows/dist/plan-review/context-policy.js.map +1 -0
  228. package/clinkx-workflows/dist/plan-review/contract.d.ts +763 -0
  229. package/clinkx-workflows/dist/plan-review/contract.js +289 -0
  230. package/clinkx-workflows/dist/plan-review/contract.js.map +1 -0
  231. package/clinkx-workflows/dist/plan-review/digest.d.ts +68 -0
  232. package/clinkx-workflows/dist/plan-review/digest.js +241 -0
  233. package/clinkx-workflows/dist/plan-review/digest.js.map +1 -0
  234. package/clinkx-workflows/dist/plan-review/discovery.d.ts +45 -0
  235. package/clinkx-workflows/dist/plan-review/discovery.js +36 -0
  236. package/clinkx-workflows/dist/plan-review/discovery.js.map +1 -0
  237. package/clinkx-workflows/dist/plan-review/execution-contract.d.ts +298 -0
  238. package/clinkx-workflows/dist/plan-review/execution-contract.js +194 -0
  239. package/clinkx-workflows/dist/plan-review/execution-contract.js.map +1 -0
  240. package/clinkx-workflows/dist/plan-review/expander.d.ts +48 -0
  241. package/clinkx-workflows/dist/plan-review/expander.js +243 -0
  242. package/clinkx-workflows/dist/plan-review/expander.js.map +1 -0
  243. package/clinkx-workflows/dist/plan-review/projector.d.ts +126 -0
  244. package/clinkx-workflows/dist/plan-review/projector.js +437 -0
  245. package/clinkx-workflows/dist/plan-review/projector.js.map +1 -0
  246. package/clinkx-workflows/dist/plan-review/publication.d.ts +95 -0
  247. package/clinkx-workflows/dist/plan-review/publication.js +182 -0
  248. package/clinkx-workflows/dist/plan-review/publication.js.map +1 -0
  249. package/clinkx-workflows/dist/plan-review/ranking-reducer.d.ts +34 -0
  250. package/clinkx-workflows/dist/plan-review/ranking-reducer.js +139 -0
  251. package/clinkx-workflows/dist/plan-review/ranking-reducer.js.map +1 -0
  252. package/clinkx-workflows/dist/plan-review/resume.d.ts +38 -0
  253. package/clinkx-workflows/dist/plan-review/resume.js +122 -0
  254. package/clinkx-workflows/dist/plan-review/resume.js.map +1 -0
  255. package/clinkx-workflows/dist/plan-review/rubric.d.ts +7 -0
  256. package/clinkx-workflows/dist/plan-review/rubric.js +24 -0
  257. package/clinkx-workflows/dist/plan-review/rubric.js.map +1 -0
  258. package/clinkx-workflows/dist/plan-review/run-state.d.ts +398 -0
  259. package/clinkx-workflows/dist/plan-review/run-state.js +183 -0
  260. package/clinkx-workflows/dist/plan-review/run-state.js.map +1 -0
  261. package/clinkx-workflows/dist/plan-review/runtime-policy.d.ts +74 -0
  262. package/clinkx-workflows/dist/plan-review/runtime-policy.js +186 -0
  263. package/clinkx-workflows/dist/plan-review/runtime-policy.js.map +1 -0
  264. package/clinkx-workflows/dist/plan-review/snapshot.d.ts +81 -0
  265. package/clinkx-workflows/dist/plan-review/snapshot.js +170 -0
  266. package/clinkx-workflows/dist/plan-review/snapshot.js.map +1 -0
  267. package/clinkx-workflows/dist/plan-review/stage-error.d.ts +19 -0
  268. package/clinkx-workflows/dist/plan-review/stage-error.js +20 -0
  269. package/clinkx-workflows/dist/plan-review/stage-error.js.map +1 -0
  270. package/clinkx-workflows/dist/post-processors/index.d.ts +20 -0
  271. package/clinkx-workflows/dist/post-processors/index.js +21 -0
  272. package/clinkx-workflows/dist/post-processors/index.js.map +1 -0
  273. package/clinkx-workflows/dist/prompt-budget.d.ts +7 -0
  274. package/clinkx-workflows/dist/prompt-budget.js +7 -1
  275. package/clinkx-workflows/dist/prompt-budget.js.map +1 -1
  276. package/clinkx-workflows/dist/reducers/index.js +2 -0
  277. package/clinkx-workflows/dist/reducers/index.js.map +1 -1
  278. package/clinkx-workflows/dist/roster-contract.d.ts +889 -0
  279. package/clinkx-workflows/dist/roster-contract.js +180 -0
  280. package/clinkx-workflows/dist/roster-contract.js.map +1 -0
  281. package/clinkx-workflows/dist/rosters.d.ts +14 -0
  282. package/clinkx-workflows/dist/rosters.js +169 -0
  283. package/clinkx-workflows/dist/rosters.js.map +1 -0
  284. package/clinkx-workflows/dist/run-health.d.ts +7 -0
  285. package/clinkx-workflows/dist/run-health.js +25 -0
  286. package/clinkx-workflows/dist/run-health.js.map +1 -0
  287. package/clinkx-workflows/dist/run-lock-heartbeat.d.ts +2 -0
  288. package/clinkx-workflows/dist/run-lock-heartbeat.js +3 -0
  289. package/clinkx-workflows/dist/run-lock-heartbeat.js.map +1 -0
  290. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.d.ts +34 -0
  291. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js +74 -0
  292. package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js.map +1 -0
  293. package/clinkx-workflows/dist/run-summary/cards/index.js +5 -0
  294. package/clinkx-workflows/dist/run-summary/cards/index.js.map +1 -1
  295. package/clinkx-workflows/dist/run-summary.d.ts +13 -0
  296. package/clinkx-workflows/dist/run-summary.js +29 -1
  297. package/clinkx-workflows/dist/run-summary.js.map +1 -1
  298. package/clinkx-workflows/dist/schema.d.ts +140 -21
  299. package/clinkx-workflows/dist/schema.js +34 -1
  300. package/clinkx-workflows/dist/schema.js.map +1 -1
  301. package/clinkx-workflows/dist/seed-terms.d.ts +30 -0
  302. package/clinkx-workflows/dist/seed-terms.js +176 -0
  303. package/clinkx-workflows/dist/seed-terms.js.map +1 -0
  304. package/clinkx-workflows/dist/server.d.ts +5 -2
  305. package/clinkx-workflows/dist/server.js +84 -52
  306. package/clinkx-workflows/dist/server.js.map +1 -1
  307. package/clinkx-workflows/dist/shutdown.d.ts +29 -18
  308. package/clinkx-workflows/dist/shutdown.js +90 -64
  309. package/clinkx-workflows/dist/shutdown.js.map +1 -1
  310. package/clinkx-workflows/dist/state-schema.d.ts +61 -0
  311. package/clinkx-workflows/dist/state.d.ts +175 -3
  312. package/clinkx-workflows/dist/state.js +1398 -44
  313. package/clinkx-workflows/dist/state.js.map +1 -1
  314. package/clinkx-workflows/dist/stdio-watchdog.d.ts +52 -0
  315. package/clinkx-workflows/dist/stdio-watchdog.js +212 -0
  316. package/clinkx-workflows/dist/stdio-watchdog.js.map +1 -0
  317. package/clinkx-workflows/dist/transport.d.ts +15 -0
  318. package/clinkx-workflows/dist/transport.js +19 -10
  319. package/clinkx-workflows/dist/transport.js.map +1 -1
  320. package/clinkx-workflows/dist/types.d.ts +20 -2
  321. package/clinkx-workflows/dist/validators/council.d.ts +334 -101
  322. package/clinkx-workflows/dist/validators/council.js +52 -13
  323. package/clinkx-workflows/dist/validators/council.js.map +1 -1
  324. package/clinkx-workflows/dist/validators/index.d.ts +1 -0
  325. package/clinkx-workflows/dist/validators/index.js +3 -0
  326. package/clinkx-workflows/dist/validators/index.js.map +1 -1
  327. package/clinkx-workflows/dist/validators/plan-review.d.ts +398 -0
  328. package/clinkx-workflows/dist/validators/plan-review.js +316 -0
  329. package/clinkx-workflows/dist/validators/plan-review.js.map +1 -0
  330. package/clinkx-workflows/dist/workflow-receipt.js +188 -4
  331. package/clinkx-workflows/dist/workflow-receipt.js.map +1 -1
  332. package/clinkx-workflows/dist/workflow-tools.d.ts +118 -3
  333. package/clinkx-workflows/dist/workflow-tools.js +2110 -175
  334. package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
  335. package/clinkx-workflows/dist/workspace-signature.d.ts +16 -0
  336. package/clinkx-workflows/dist/workspace-signature.js +388 -0
  337. package/clinkx-workflows/dist/workspace-signature.js.map +1 -0
  338. package/clinkx-workflows/templates/council/answer-chairman.txt +3 -0
  339. package/clinkx-workflows/templates/council/answer-cross-reviewer.txt +3 -0
  340. package/clinkx-workflows/templates/council/answer-specialist.txt +5 -1
  341. package/clinkx-workflows/templates/council/chairman.txt +3 -0
  342. package/clinkx-workflows/templates/council/code-review-chairman.txt +16 -0
  343. package/clinkx-workflows/templates/council/code-review-cross-reviewer.txt +7 -1
  344. package/clinkx-workflows/templates/council/code-review-reviewer.txt +22 -3
  345. package/clinkx-workflows/templates/council/debug-chairman.txt +3 -0
  346. package/clinkx-workflows/templates/council/debug-cross-reviewer.txt +3 -0
  347. package/clinkx-workflows/templates/council/debug-debugger.txt +5 -1
  348. package/clinkx-workflows/templates/council/discover-analyst.txt +5 -1
  349. package/clinkx-workflows/templates/council/discover-chairman.txt +3 -0
  350. package/clinkx-workflows/templates/council/discover-cross-reviewer.txt +3 -0
  351. package/clinkx-workflows/templates/council/member.txt +5 -1
  352. package/clinkx-workflows/templates/council/plan-review-chairman.txt +71 -0
  353. package/clinkx-workflows/templates/council/plan-review-cross-reviewer.txt +54 -0
  354. package/clinkx-workflows/templates/council/plan-review-reviewer.txt +63 -0
  355. package/clinkx-workflows/templates/council/reviewer.txt +3 -0
  356. package/clinkx-workflows/templates/plan-review/chairman.txt +48 -0
  357. package/clinkx-workflows/templates/plan-review/cross-review.txt +52 -0
  358. package/clinkx-workflows/templates/plan-review/ranking.txt +16 -0
  359. package/clinkx-workflows/templates/plan-review/reviewer.txt +57 -0
  360. package/clinkx-workflows/workflows/council-answer.yaml +100 -8
  361. package/clinkx-workflows/workflows/council-code-review.yaml +106 -8
  362. package/clinkx-workflows/workflows/council-debug.yaml +100 -8
  363. package/clinkx-workflows/workflows/council-default.yaml +104 -8
  364. package/clinkx-workflows/workflows/council-discover.yaml +100 -8
  365. package/clinkx-workflows/workflows/council-plan-review.yaml +253 -0
  366. package/clinkx-workflows/workflows/plan-review-receipts.yaml +230 -0
  367. package/conf/adapters/agy.json +56 -0
  368. package/conf/adapters/claude.json +12 -0
  369. package/conf/adapters/codex-app-server.json +44 -0
  370. package/conf/adapters/codex.json +14 -2
  371. package/conf/adapters/glm.json +24 -3
  372. package/conf/adapters/grok.json +67 -0
  373. package/conf/adapters/hapi/agy.json +59 -0
  374. package/conf/adapters/hapi/claude.json +12 -0
  375. package/conf/adapters/hapi/codex.json +14 -2
  376. package/conf/adapters/hapi/glm.json +25 -4
  377. package/conf/rosters/default-council.json +21 -0
  378. package/dist/activity-journal.d.ts +56 -0
  379. package/dist/activity-journal.js +706 -0
  380. package/dist/activity-journal.js.map +1 -0
  381. package/dist/allowed-roots.d.ts +41 -0
  382. package/dist/allowed-roots.js +125 -3
  383. package/dist/allowed-roots.js.map +1 -1
  384. package/dist/codex/activity-session-log.d.ts +14 -0
  385. package/dist/codex/activity-session-log.js +206 -0
  386. package/dist/codex/activity-session-log.js.map +1 -0
  387. package/dist/codex/agent-tools.d.ts +23 -0
  388. package/dist/codex/agent-tools.js +1306 -0
  389. package/dist/codex/agent-tools.js.map +1 -0
  390. package/dist/codex/app-server-client.d.ts +79 -0
  391. package/dist/codex/app-server-client.js +593 -0
  392. package/dist/codex/app-server-client.js.map +1 -0
  393. package/dist/codex/app-server-registry.d.ts +407 -0
  394. package/dist/codex/app-server-registry.js +1493 -0
  395. package/dist/codex/app-server-registry.js.map +1 -0
  396. package/dist/codex/client-types.d.ts +115 -0
  397. package/dist/codex/client-types.js +2 -0
  398. package/dist/codex/client-types.js.map +1 -0
  399. package/dist/codex/protocol.d.ts +5375 -0
  400. package/dist/codex/protocol.js +614 -0
  401. package/dist/codex/protocol.js.map +1 -0
  402. package/dist/codex/session.d.ts +263 -0
  403. package/dist/codex/session.js +466 -0
  404. package/dist/codex/session.js.map +1 -0
  405. package/dist/config.d.ts +386 -23
  406. package/dist/config.js +184 -15
  407. package/dist/config.js.map +1 -1
  408. package/dist/context-builder/anchors.d.ts +1 -0
  409. package/dist/context-builder/anchors.js +3 -0
  410. package/dist/context-builder/anchors.js.map +1 -1
  411. package/dist/context-builder/bundle.d.ts +48 -2
  412. package/dist/context-builder/bundle.js +388 -2417
  413. package/dist/context-builder/bundle.js.map +1 -1
  414. package/dist/context-builder/codemap.d.ts +5 -0
  415. package/dist/context-builder/codemap.js +387 -13
  416. package/dist/context-builder/codemap.js.map +1 -1
  417. package/dist/context-builder/config.d.ts +1 -0
  418. package/dist/context-builder/config.js +12 -0
  419. package/dist/context-builder/config.js.map +1 -1
  420. package/dist/context-builder/context-run-catalog.d.ts +17 -0
  421. package/dist/context-builder/context-run-catalog.js +99 -0
  422. package/dist/context-builder/context-run-catalog.js.map +1 -0
  423. package/dist/context-builder/delegate-finalizer-effective.d.ts +33 -0
  424. package/dist/context-builder/delegate-finalizer-effective.js +82 -0
  425. package/dist/context-builder/delegate-finalizer-effective.js.map +1 -0
  426. package/dist/context-builder/delegate-packet.d.ts +55 -0
  427. package/dist/context-builder/delegate-packet.js +430 -74
  428. package/dist/context-builder/delegate-packet.js.map +1 -1
  429. package/dist/context-builder/delegate-reconstruction.d.ts +29 -0
  430. package/dist/context-builder/delegate-reconstruction.js +110 -41
  431. package/dist/context-builder/delegate-reconstruction.js.map +1 -1
  432. package/dist/context-builder/delegate-validation.d.ts +41 -1
  433. package/dist/context-builder/delegate-validation.js +237 -48
  434. package/dist/context-builder/delegate-validation.js.map +1 -1
  435. package/dist/context-builder/delegate.d.ts +11 -0
  436. package/dist/context-builder/delegate.js +210 -58
  437. package/dist/context-builder/delegate.js.map +1 -1
  438. package/dist/context-builder/diagnostics.d.ts +11 -2
  439. package/dist/context-builder/diagnostics.js +39 -6
  440. package/dist/context-builder/diagnostics.js.map +1 -1
  441. package/dist/context-builder/discovery-progress.d.ts +25 -0
  442. package/dist/context-builder/discovery-progress.js +64 -0
  443. package/dist/context-builder/discovery-progress.js.map +1 -0
  444. package/dist/context-builder/discovery-watchdog.d.ts +15 -0
  445. package/dist/context-builder/discovery-watchdog.js +39 -0
  446. package/dist/context-builder/discovery-watchdog.js.map +1 -0
  447. package/dist/context-builder/discovery.d.ts +36 -1
  448. package/dist/context-builder/discovery.js +584 -172
  449. package/dist/context-builder/discovery.js.map +1 -1
  450. package/dist/context-builder/external-gaps.d.ts +73 -0
  451. package/dist/context-builder/external-gaps.js +248 -0
  452. package/dist/context-builder/external-gaps.js.map +1 -0
  453. package/dist/context-builder/globs.d.ts +1 -0
  454. package/dist/context-builder/globs.js +25 -10
  455. package/dist/context-builder/globs.js.map +1 -1
  456. package/dist/context-builder/handler.d.ts +67 -2
  457. package/dist/context-builder/handler.js +1810 -2440
  458. package/dist/context-builder/handler.js.map +1 -1
  459. package/dist/context-builder/invocation-sidecar.d.ts +41 -0
  460. package/dist/context-builder/invocation-sidecar.js +189 -0
  461. package/dist/context-builder/invocation-sidecar.js.map +1 -0
  462. package/dist/context-builder/lifecycle-contract.d.ts +424 -0
  463. package/dist/context-builder/lifecycle-contract.js +523 -0
  464. package/dist/context-builder/lifecycle-contract.js.map +1 -0
  465. package/dist/context-builder/lifecycle-journal.d.ts +62 -0
  466. package/dist/context-builder/lifecycle-journal.js +88 -0
  467. package/dist/context-builder/lifecycle-journal.js.map +1 -0
  468. package/dist/context-builder/lifecycle-observer.d.ts +102 -0
  469. package/dist/context-builder/lifecycle-observer.js +258 -0
  470. package/dist/context-builder/lifecycle-observer.js.map +1 -0
  471. package/dist/context-builder/lifecycle-reconcile.d.ts +32 -0
  472. package/dist/context-builder/lifecycle-reconcile.js +191 -0
  473. package/dist/context-builder/lifecycle-reconcile.js.map +1 -0
  474. package/dist/context-builder/lifecycle-recovery.d.ts +2 -0
  475. package/dist/context-builder/lifecycle-recovery.js +14 -0
  476. package/dist/context-builder/lifecycle-recovery.js.map +1 -0
  477. package/dist/context-builder/mutation-lock.d.ts +32 -0
  478. package/dist/context-builder/mutation-lock.js +321 -0
  479. package/dist/context-builder/mutation-lock.js.map +1 -0
  480. package/dist/context-builder/path-signals.js +9 -5
  481. package/dist/context-builder/path-signals.js.map +1 -1
  482. package/dist/context-builder/progress.d.ts +3 -1
  483. package/dist/context-builder/progress.js +23 -0
  484. package/dist/context-builder/progress.js.map +1 -1
  485. package/dist/context-builder/receipt.d.ts +6 -4
  486. package/dist/context-builder/receipt.js +12 -1
  487. package/dist/context-builder/receipt.js.map +1 -1
  488. package/dist/context-builder/refine-handler.d.ts +14 -0
  489. package/dist/context-builder/refine-handler.js +790 -0
  490. package/dist/context-builder/refine-handler.js.map +1 -0
  491. package/dist/context-builder/review-coverage.d.ts +116 -0
  492. package/dist/context-builder/review-coverage.js +544 -0
  493. package/dist/context-builder/review-coverage.js.map +1 -0
  494. package/dist/context-builder/schema.d.ts +315 -2
  495. package/dist/context-builder/schema.js +133 -7
  496. package/dist/context-builder/schema.js.map +1 -1
  497. package/dist/context-builder/secrets.d.ts +59 -0
  498. package/dist/context-builder/secrets.js +2255 -44
  499. package/dist/context-builder/secrets.js.map +1 -1
  500. package/dist/context-builder/selection.d.ts +7 -3
  501. package/dist/context-builder/selection.js +200 -738
  502. package/dist/context-builder/selection.js.map +1 -1
  503. package/dist/context-builder/session-log-identity.d.ts +1 -0
  504. package/dist/context-builder/session-log-identity.js +66 -0
  505. package/dist/context-builder/session-log-identity.js.map +1 -0
  506. package/dist/context-builder/slice-range-math.d.ts +16 -0
  507. package/dist/context-builder/slice-range-math.js +137 -0
  508. package/dist/context-builder/slice-range-math.js.map +1 -0
  509. package/dist/context-builder/status.d.ts +23 -2
  510. package/dist/context-builder/status.js +60 -4
  511. package/dist/context-builder/status.js.map +1 -1
  512. package/dist/context-builder/storage.d.ts +59 -2
  513. package/dist/context-builder/storage.js +500 -168
  514. package/dist/context-builder/storage.js.map +1 -1
  515. package/dist/context-builder/token-estimate.d.ts +13 -2
  516. package/dist/context-builder/token-estimate.js +77 -4
  517. package/dist/context-builder/token-estimate.js.map +1 -1
  518. package/dist/context-builder/versions.d.ts +44 -0
  519. package/dist/context-builder/versions.js +45 -0
  520. package/dist/context-builder/versions.js.map +1 -0
  521. package/dist/context-builder/workflow-runner.d.ts +75 -0
  522. package/dist/context-builder/workflow-runner.js +1241 -0
  523. package/dist/context-builder/workflow-runner.js.map +1 -0
  524. package/dist/context-builder/write-watchdog.d.ts +14 -0
  525. package/dist/context-builder/write-watchdog.js +38 -0
  526. package/dist/context-builder/write-watchdog.js.map +1 -0
  527. package/dist/dashboard-adapter-catalog.d.ts +9 -0
  528. package/dist/dashboard-adapter-catalog.js +53 -0
  529. package/dist/dashboard-adapter-catalog.js.map +1 -0
  530. package/dist/dashboard-cli.d.ts +81 -0
  531. package/dist/dashboard-cli.js +623 -0
  532. package/dist/dashboard-cli.js.map +1 -0
  533. package/dist/dashboard-companion/client.d.ts +37 -0
  534. package/dist/dashboard-companion/client.js +229 -0
  535. package/dist/dashboard-companion/client.js.map +1 -0
  536. package/dist/dashboard-companion/config.d.ts +8 -0
  537. package/dist/dashboard-companion/config.js +52 -0
  538. package/dist/dashboard-companion/config.js.map +1 -0
  539. package/dist/dashboard-companion/http-proxy.d.ts +10 -0
  540. package/dist/dashboard-companion/http-proxy.js +234 -0
  541. package/dist/dashboard-companion/http-proxy.js.map +1 -0
  542. package/dist/dashboard-companion/protocol.d.ts +80 -0
  543. package/dist/dashboard-companion/protocol.js +458 -0
  544. package/dist/dashboard-companion/protocol.js.map +1 -0
  545. package/dist/dashboard-companion/standalone-assets.d.ts +12 -0
  546. package/dist/dashboard-companion/standalone-assets.js +72 -0
  547. package/dist/dashboard-companion/standalone-assets.js.map +1 -0
  548. package/dist/dashboard-companion/standalone-entry.d.ts +1 -0
  549. package/dist/dashboard-companion/standalone-entry.js +17 -0
  550. package/dist/dashboard-companion/standalone-entry.js.map +1 -0
  551. package/dist/dashboard-gateway/config.d.ts +9 -0
  552. package/dist/dashboard-gateway/config.js +44 -0
  553. package/dist/dashboard-gateway/config.js.map +1 -0
  554. package/dist/dashboard-gateway/index.d.ts +12 -0
  555. package/dist/dashboard-gateway/index.js +786 -0
  556. package/dist/dashboard-gateway/index.js.map +1 -0
  557. package/dist/dashboard-gateway/main.d.ts +1 -0
  558. package/dist/dashboard-gateway/main.js +25 -0
  559. package/dist/dashboard-gateway/main.js.map +1 -0
  560. package/dist/dashboard-pairing-token.d.ts +1 -0
  561. package/dist/dashboard-pairing-token.js +5 -0
  562. package/dist/dashboard-pairing-token.js.map +1 -0
  563. package/dist/elaris/client.d.ts +73 -0
  564. package/dist/elaris/client.js +825 -0
  565. package/dist/elaris/client.js.map +1 -0
  566. package/dist/elaris/config.d.ts +18 -0
  567. package/dist/elaris/config.js +75 -0
  568. package/dist/elaris/config.js.map +1 -0
  569. package/dist/elaris/errors.d.ts +41 -0
  570. package/dist/elaris/errors.js +205 -0
  571. package/dist/elaris/errors.js.map +1 -0
  572. package/dist/elaris/github-repo.d.ts +18 -0
  573. package/dist/elaris/github-repo.js +89 -0
  574. package/dist/elaris/github-repo.js.map +1 -0
  575. package/dist/elaris/index.d.ts +10 -0
  576. package/dist/elaris/index.js +11 -0
  577. package/dist/elaris/index.js.map +1 -0
  578. package/dist/elaris/redact.d.ts +89 -0
  579. package/dist/elaris/redact.js +423 -0
  580. package/dist/elaris/redact.js.map +1 -0
  581. package/dist/elaris/run-id.d.ts +5 -0
  582. package/dist/elaris/run-id.js +20 -0
  583. package/dist/elaris/run-id.js.map +1 -0
  584. package/dist/elaris/status.d.ts +45 -0
  585. package/dist/elaris/status.js +122 -0
  586. package/dist/elaris/status.js.map +1 -0
  587. package/dist/elaris/tool-schemas.d.ts +314 -0
  588. package/dist/elaris/tool-schemas.js +208 -0
  589. package/dist/elaris/tool-schemas.js.map +1 -0
  590. package/dist/elaris/tools.d.ts +73 -0
  591. package/dist/elaris/tools.js +1065 -0
  592. package/dist/elaris/tools.js.map +1 -0
  593. package/dist/elaris/types.d.ts +1541 -0
  594. package/dist/elaris/types.js +252 -0
  595. package/dist/elaris/types.js.map +1 -0
  596. package/dist/errors.d.ts +16 -0
  597. package/dist/errors.js +19 -0
  598. package/dist/errors.js.map +1 -1
  599. package/dist/handler.d.ts +4 -0
  600. package/dist/handler.js +15 -2
  601. package/dist/handler.js.map +1 -1
  602. package/dist/index.d.ts +20 -2
  603. package/dist/index.js +154 -6
  604. package/dist/index.js.map +1 -1
  605. package/dist/local-clink-backend.d.ts +3 -0
  606. package/dist/local-clink-backend.js +4 -0
  607. package/dist/local-clink-backend.js.map +1 -1
  608. package/dist/logger.d.ts +1 -1
  609. package/dist/logger.js +18 -3
  610. package/dist/logger.js.map +1 -1
  611. package/dist/package-info.d.ts +2 -0
  612. package/dist/package-info.js +18 -0
  613. package/dist/package-info.js.map +1 -0
  614. package/dist/parsers/agy-stream-json.d.ts +14 -0
  615. package/dist/parsers/agy-stream-json.js +172 -0
  616. package/dist/parsers/agy-stream-json.js.map +1 -0
  617. package/dist/parsers/codex-jsonl.js +48 -3
  618. package/dist/parsers/codex-jsonl.js.map +1 -1
  619. package/dist/parsers/extract.d.ts +10 -1
  620. package/dist/parsers/extract.js +16 -4
  621. package/dist/parsers/extract.js.map +1 -1
  622. package/dist/parsers/observed-invocation.d.ts +20 -0
  623. package/dist/parsers/observed-invocation.js +42 -0
  624. package/dist/parsers/observed-invocation.js.map +1 -0
  625. package/dist/pipeline.d.ts +17 -0
  626. package/dist/pipeline.js +181 -10
  627. package/dist/pipeline.js.map +1 -1
  628. package/dist/progress-report/lock.d.ts +74 -0
  629. package/dist/progress-report/lock.js +343 -0
  630. package/dist/progress-report/lock.js.map +1 -0
  631. package/dist/progress-report/schema.d.ts +808 -0
  632. package/dist/progress-report/schema.js +119 -0
  633. package/dist/progress-report/schema.js.map +1 -0
  634. package/dist/progress-report/store.d.ts +66 -0
  635. package/dist/progress-report/store.js +766 -0
  636. package/dist/progress-report/store.js.map +1 -0
  637. package/dist/progress-report/tools.d.ts +20 -0
  638. package/dist/progress-report/tools.js +141 -0
  639. package/dist/progress-report/tools.js.map +1 -0
  640. package/dist/prompt-mode.d.ts +1 -1
  641. package/dist/prompt-mode.js +7 -2
  642. package/dist/prompt-mode.js.map +1 -1
  643. package/dist/run-dir.d.ts +24 -0
  644. package/dist/run-dir.js +201 -2
  645. package/dist/run-dir.js.map +1 -1
  646. package/dist/runner.d.ts +20 -0
  647. package/dist/runner.js +192 -16
  648. package/dist/runner.js.map +1 -1
  649. package/dist/safety.d.ts +54 -4
  650. package/dist/safety.js +186 -5
  651. package/dist/safety.js.map +1 -1
  652. package/dist/schema.d.ts +15 -7
  653. package/dist/schema.js +20 -0
  654. package/dist/schema.js.map +1 -1
  655. package/dist/server.d.ts +7 -1
  656. package/dist/server.js +451 -23
  657. package/dist/server.js.map +1 -1
  658. package/dist/session-log-stream.d.ts +18 -0
  659. package/dist/session-log-stream.js +566 -0
  660. package/dist/session-log-stream.js.map +1 -0
  661. package/dist/stdio-activity.d.ts +28 -0
  662. package/dist/stdio-activity.js +72 -0
  663. package/dist/stdio-activity.js.map +1 -0
  664. package/package.json +47 -5
  665. package/conf/adapters/gemini.json +0 -44
  666. package/conf/adapters/hapi/gemini.json +0 -47
  667. package/dist/parsers/gemini-json.d.ts +0 -2
  668. package/dist/parsers/gemini-json.js +0 -72
  669. package/dist/parsers/gemini-json.js.map +0 -1
@@ -5,10 +5,12 @@ import { isSamePathOrDescendant } from "../allowed-roots.js";
5
5
  import { CancellationError } from "../errors.js";
6
6
  import { CONTEXT_BUILDER_INTERNAL_CAP_DEFAULTS, } from "./config.js";
7
7
  import { CONTEXT_BUILDER_REQUESTED_EVIDENCE_OMISSION_REASON, requestedEvidenceOmission, } from "./diagnostics.js";
8
+ import { CONTEXT_BUILDER_SCAN_PROGRESS_EVERY_FILES } from "./discovery-progress.js";
8
9
  import { compileContextBuilderGlobs, CONTEXT_BUILDER_DEFAULT_EXCLUDE_GLOBS, } from "./globs.js";
9
10
  import { normalizeContextBuilderRootRelativePath, rootRelativePathForAbsolutePath, } from "./paths.js";
10
11
  import { directoryDistance, genericPathKind, isTestPath, normalizedPathStem, } from "./path-signals.js";
11
- import { isBlockingSecretFinding, redactHighConfidenceAssignmentSecrets, scanHighConfidenceSecretContent, scanSecretPath, } from "./secrets.js";
12
+ import { buildContextReviewObligations, planRegressionHeadSliceCandidates, } from "./review-coverage.js";
13
+ import { sanitizeHighConfidenceSecretContent, scanSecretPath, } from "./secrets.js";
12
14
  import { CONTEXT_BUILDER_PUBLIC_BUDGET_HARD_LIMITS, } from "./schema.js";
13
15
  const SEARCH_WINDOW_LINES_BEFORE = 19;
14
16
  const SEARCH_WINDOW_LINES_AFTER = 20;
@@ -16,13 +18,32 @@ const SEARCH_BRIDGE_GAP_LINES = 20;
16
18
  const SEARCH_MAX_MERGED_SPAN_LINES = 160;
17
19
  const DEFAULT_MAX_FULL_FOCUS_SLICE_BYTES = 48_000;
18
20
  const DEFAULT_MAX_FULL_IMPLEMENTATION_FOCUS_SLICE_BYTES = 96_000;
21
+ // Non-silent, material signal for an explicitly-focused file that exceeded the
22
+ // bounded full-file focus size and had no per-file search evidence: instead of
23
+ // dropping it, we include a bounded head slice and record this reason so the
24
+ // receipt reflects a partial inclusion (not a silent omission).
25
+ const CONTEXT_BUILDER_FOCUS_SLICED_REASON = "focus_sliced";
26
+ // Non-silent, material signal for an explicitly-focused file whose FIRST logical
27
+ // line alone exceeds the bounded focus-slice cap. The line-range model cannot
28
+ // express a partial line, so emitting a head slice would blow the byte bound.
29
+ // We omit the file with this explicit material reason instead — honoring both
30
+ // the byte bound and "never silently drop an explicitly-focused file".
31
+ const CONTEXT_BUILDER_FOCUS_OVER_CAP_REASON = "focus_over_cap";
32
+ // Secret sanitization can run multi-second synchronous stretches. The walk
33
+ // yields a macrotask at least this often (and after every sanitize) so timers,
34
+ // cancellation notifications, and lock heartbeats keep running mid-scan.
35
+ const DISCOVERY_YIELD_EVERY_FILES = 32;
19
36
  const IMPORT_EXPANSION_PASSES = 3;
37
+ const MAX_EXPANDED_SEARCH_TERMS = 128;
38
+ const MAX_EXPANDED_SEARCH_TERM_BYTES = 16_384;
39
+ const MAX_DERIVED_SEARCH_TERM_LENGTH = 256;
20
40
  const PROJECT_SUPPORT_FILENAMES = Object.freeze([
21
41
  "package.json",
22
42
  "vitest.config.ts",
23
43
  "vite.config.ts",
24
44
  ]);
25
45
  export async function discoverContextBuilderCandidates(options) {
46
+ const allowSecrets = options.allowSecrets ?? true;
26
47
  const internalCaps = options.internal_caps ?? CONTEXT_BUILDER_INTERNAL_CAP_DEFAULTS;
27
48
  const matcher = compileContextBuilderGlobs({
28
49
  include: [...(options.include_globs ?? [])],
@@ -37,6 +58,8 @@ export async function discoverContextBuilderCandidates(options) {
37
58
  omissions: [],
38
59
  requestedEvidenceOmissionKeys: new Set(),
39
60
  processedFileKeys: new Set(),
61
+ traversedDirectoryKeys: new Set(),
62
+ focusScanExemptFiles: 0,
40
63
  metrics: {
41
64
  files_seen: 0,
42
65
  files_considered: 0,
@@ -48,6 +71,9 @@ export async function discoverContextBuilderCandidates(options) {
48
71
  bytes_read: 0,
49
72
  },
50
73
  stopped: false,
74
+ onProgress: options.onProgress,
75
+ filesSinceYield: 0,
76
+ filesSinceProgress: 0,
51
77
  };
52
78
  for (const root of options.roots) {
53
79
  if (state.stopped) {
@@ -57,6 +83,7 @@ export async function discoverContextBuilderCandidates(options) {
57
83
  await processExactFocusFiles({
58
84
  root,
59
85
  focusPaths: options.focus_paths ?? [],
86
+ allowSecrets,
60
87
  matcher,
61
88
  budget: options.budget,
62
89
  internalCaps,
@@ -70,12 +97,31 @@ export async function discoverContextBuilderCandidates(options) {
70
97
  },
71
98
  state,
72
99
  });
100
+ await processFocusDirectories({
101
+ root,
102
+ focusPaths: options.focus_paths ?? [],
103
+ allowSecrets,
104
+ matcher,
105
+ budget: options.budget,
106
+ internalCaps,
107
+ excludedRealRoots: options.excluded_real_roots ?? [],
108
+ ...(options.signal == null ? {} : { signal: options.signal }),
109
+ fs: {
110
+ readdir: options.fs?.readdir ?? fsReaddir,
111
+ lstat: options.fs?.lstat ?? fsLstat,
112
+ open: options.fs?.open ?? fsOpen,
113
+ realpath: options.fs?.realpath ?? fsRealpath,
114
+ stat: options.fs?.stat ?? fsStat,
115
+ },
116
+ state,
117
+ });
73
118
  await traverseDirectory({
74
119
  root,
75
120
  absoluteDir: root.path,
76
121
  relativeDir: "",
77
122
  matcher,
78
123
  focusPaths: options.focus_paths ?? [],
124
+ allowSecrets,
79
125
  budget: options.budget,
80
126
  internalCaps,
81
127
  excludedRealRoots: options.excluded_real_roots ?? [],
@@ -93,6 +139,7 @@ export async function discoverContextBuilderCandidates(options) {
93
139
  root,
94
140
  matcher,
95
141
  focusPaths: options.focus_paths ?? [],
142
+ allowSecrets,
96
143
  budget: options.budget,
97
144
  internalCaps,
98
145
  ...(options.signal == null ? {} : { signal: options.signal }),
@@ -108,11 +155,12 @@ export async function discoverContextBuilderCandidates(options) {
108
155
  }
109
156
  state.tree.sort(compareTreeFiles);
110
157
  state.contentCandidates.sort(compareContentCandidates);
158
+ const expandedSearchTerms = expandSearchTerms([...(options.search_terms ?? [])]);
111
159
  const search = buildCandidateSearchRecords({
112
160
  candidates: state.contentCandidates,
113
- ...(options.task == null ? {} : { task: options.task }),
114
161
  focusPaths: [...(options.focus_paths ?? [])],
115
- searchTerms: expandSearchTerms([...(options.search_terms ?? [])]),
162
+ searchTerms: expandedSearchTerms.terms,
163
+ callerTermCount: expandedSearchTerms.callerTermCount,
116
164
  maxSearchResults: options.budget.max_search_results,
117
165
  maxPreviewBytes: internalCaps.max_search_preview_bytes,
118
166
  maxCandidateBytes: internalCaps.max_candidate_bytes,
@@ -135,6 +183,50 @@ export async function discoverContextBuilderCandidates(options) {
135
183
  if (slices.capHit) {
136
184
  state.metrics.candidate_cap_hit = true;
137
185
  }
186
+ const reviewFocusPaths = (options.focus_paths ?? []).map((focus) => ({
187
+ root_index: focus.root_index,
188
+ path: focus.root_relative_path,
189
+ kind: focus.kind,
190
+ }));
191
+ let reviewObligations = buildContextReviewObligations({
192
+ candidates: state.contentCandidates,
193
+ focusPaths: reviewFocusPaths,
194
+ searchRecords: search.records,
195
+ slices: slices.records,
196
+ policy: options.coverage_policy,
197
+ });
198
+ if (reviewObligations != null) {
199
+ const headSlices = buildRegressionHeadSliceRecords({
200
+ candidates: state.contentCandidates,
201
+ planned: planRegressionHeadSliceCandidates({
202
+ candidates: state.contentCandidates,
203
+ searchRecords: search.records,
204
+ slices: slices.records,
205
+ obligations: reviewObligations,
206
+ }),
207
+ existingRecords: slices.records,
208
+ maxCandidateSlices: internalCaps.max_candidate_slices,
209
+ maxCandidateBytes: Math.max(0, internalCaps.max_candidate_bytes - search.candidateBytes),
210
+ maxBytesPerFile: options.budget.max_bytes_per_file,
211
+ });
212
+ if (headSlices.length > 0) {
213
+ slices.records.push(...headSlices);
214
+ reviewObligations = buildContextReviewObligations({
215
+ candidates: state.contentCandidates,
216
+ focusPaths: reviewFocusPaths,
217
+ searchRecords: search.records,
218
+ slices: slices.records,
219
+ policy: options.coverage_policy,
220
+ });
221
+ }
222
+ }
223
+ classifyContextEvidenceCandidates({
224
+ candidates: state.contentCandidates,
225
+ focusPaths: options.focus_paths ?? [],
226
+ searchRecords: search.records,
227
+ policy: options.coverage_policy,
228
+ obligations: reviewObligations,
229
+ });
138
230
  auditScanCapFocusedPaths({
139
231
  focusPaths: [...(options.focus_paths ?? [])],
140
232
  state,
@@ -146,30 +238,86 @@ export async function discoverContextBuilderCandidates(options) {
146
238
  slices: slices.records,
147
239
  omissions: state.omissions,
148
240
  metrics: state.metrics,
241
+ search_coverage: search.coverage,
242
+ ...(reviewObligations == null ? {} : { review_obligations: reviewObligations }),
149
243
  };
150
244
  }
151
- function expandSearchTerms(searchTerms) {
245
+ export function expandSearchTerms(searchTerms) {
152
246
  const expanded = [];
153
247
  const seen = new Set();
248
+ let aggregateBytes = 0;
249
+ // Caller terms are admitted first and are never displaced by heuristic
250
+ // expansion. Public post-parse validation owns their individual/aggregate
251
+ // bounds; this function only bounds derived fan-out before stream creation.
252
+ for (const term of searchTerms) {
253
+ const added = addExpandedSearchTerm(expanded, seen, term);
254
+ aggregateBytes += added;
255
+ }
256
+ const callerTermCount = expanded.length;
154
257
  for (const term of searchTerms) {
155
- addExpandedSearchTerm(expanded, seen, term);
156
258
  for (const derived of deriveGenericSearchTerms(term)) {
157
- addExpandedSearchTerm(expanded, seen, derived);
259
+ const normalized = derived.trim();
260
+ if (normalized.length > MAX_DERIVED_SEARCH_TERM_LENGTH ||
261
+ expanded.length >= MAX_EXPANDED_SEARCH_TERMS) {
262
+ continue;
263
+ }
264
+ const bytes = Buffer.byteLength(normalized, "utf8");
265
+ if (aggregateBytes + bytes > MAX_EXPANDED_SEARCH_TERM_BYTES) {
266
+ continue;
267
+ }
268
+ aggregateBytes += addExpandedSearchTerm(expanded, seen, normalized);
158
269
  }
159
270
  }
160
- return expanded;
271
+ return { terms: expanded, callerTermCount };
272
+ }
273
+ function classifyContextEvidenceCandidates(input) {
274
+ if (input.policy?.id == null) {
275
+ return;
276
+ }
277
+ const directSearchKeys = new Set(input.searchRecords.map(candidateKey));
278
+ const focusedFileKeys = new Set(input.focusPaths
279
+ .filter((focus) => focus.kind === "file")
280
+ .map((focus) => candidateKey({
281
+ root_index: focus.root_index,
282
+ path: focus.root_relative_path,
283
+ })));
284
+ const targetCandidateIds = new Set(input.obligations?.targets.map((target) => target.candidate_id) ?? []);
285
+ const regressionCandidateIds = new Set(input.obligations?.targets.flatMap((target) => target.regression_links.map((link) => link.candidate_id)) ?? []);
286
+ for (const candidate of input.candidates) {
287
+ const classes = [];
288
+ const key = candidateKey(candidate);
289
+ const packetCandidateId = `c:${String(candidate.root_index)}:${candidate.path}`;
290
+ const isReviewTarget = targetCandidateIds.has(packetCandidateId);
291
+ if (isReviewTarget) {
292
+ classes.push("review_target");
293
+ }
294
+ if (isTestPath(candidate.path) && regressionCandidateIds.has(packetCandidateId)) {
295
+ classes.push("regression_test");
296
+ }
297
+ const hasDiscoveryEvidence = directSearchKeys.has(key) ||
298
+ focusedFileKeys.has(key) ||
299
+ candidate.selection_hint != null;
300
+ if (genericPathKind(candidate.path) === "config" && hasDiscoveryEvidence) {
301
+ classes.push("configuration");
302
+ }
303
+ if (candidate.selection_hint === "local_dependency") {
304
+ classes.push("dependency");
305
+ }
306
+ candidate.evidence_classes = classes;
307
+ }
161
308
  }
162
309
  function addExpandedSearchTerm(expanded, seen, term) {
163
310
  const normalized = term.trim();
164
311
  if (normalized.length === 0) {
165
- return;
312
+ return 0;
166
313
  }
167
314
  const key = normalized.toLowerCase();
168
315
  if (seen.has(key)) {
169
- return;
316
+ return 0;
170
317
  }
171
318
  expanded.push(normalized);
172
319
  seen.add(key);
320
+ return Buffer.byteLength(normalized, "utf8");
173
321
  }
174
322
  function deriveGenericSearchTerms(term) {
175
323
  const tokens = tokenizeGenericSearchTerm(term);
@@ -238,6 +386,7 @@ async function processImportAndSupportFiles(input) {
238
386
  relativePath,
239
387
  matcher: input.matcher,
240
388
  focusPaths: input.focusPaths,
389
+ allowSecrets: input.allowSecrets,
241
390
  budget: input.budget,
242
391
  internalCaps: input.internalCaps,
243
392
  ignoreIncludeGlob: true,
@@ -264,6 +413,7 @@ async function processImportAndSupportFiles(input) {
264
413
  relativePath,
265
414
  matcher: input.matcher,
266
415
  focusPaths: input.focusPaths,
416
+ allowSecrets: input.allowSecrets,
267
417
  budget: input.budget,
268
418
  internalCaps: input.internalCaps,
269
419
  ignoreIncludeGlob: true,
@@ -477,9 +627,51 @@ async function processExactFocusFiles(input) {
477
627
  relativePath: focus.root_relative_path,
478
628
  matcher: input.matcher,
479
629
  focusPaths: input.focusPaths,
630
+ allowSecrets: input.allowSecrets,
480
631
  budget: input.budget,
481
632
  internalCaps: input.internalCaps,
482
- ignoreScanCap: true,
633
+ focusScanExempt: true,
634
+ ...(input.signal == null ? {} : { signal: input.signal }),
635
+ fs: input.fs,
636
+ state: input.state,
637
+ });
638
+ }
639
+ }
640
+ // Pre-walk explicitly-focused directories before global traversal so a focus
641
+ // directory late in sort order cannot be starved by max_scan_files exhaustion
642
+ // from unrelated trees. Files processed here are focus-scan-exempt (they never
643
+ // erode traversal headroom) but remain bounded by the discovery byte and
644
+ // candidate caps; glob/secret/binary semantics are unchanged because the walk
645
+ // reuses traverseDirectory/processFile verbatim.
646
+ async function processFocusDirectories(input) {
647
+ const focusDirectories = [...input.focusPaths]
648
+ .filter((focus) => focus.root_index === input.root.root_index)
649
+ .filter((focus) => focus.kind === "directory")
650
+ .sort(compareFocusPathsForDiscovery);
651
+ for (const focus of focusDirectories) {
652
+ assertNotAborted(input.signal);
653
+ // A root-level focus gains nothing from a pre-walk (global traversal
654
+ // starts there immediately), and pre-walking it would exempt the entire
655
+ // root from max_scan_files.
656
+ if (focus.root_relative_path === "") {
657
+ continue;
658
+ }
659
+ // Leave include-glob-pruned focus directories to global traversal, which
660
+ // emits the existing requested-evidence omission for them.
661
+ if (!input.matcher.canContainIncludedPath(focus.root_relative_path)) {
662
+ continue;
663
+ }
664
+ await traverseDirectory({
665
+ root: input.root,
666
+ absoluteDir: focus.absolute_path,
667
+ relativeDir: focus.root_relative_path,
668
+ matcher: input.matcher,
669
+ focusPaths: input.focusPaths,
670
+ allowSecrets: input.allowSecrets,
671
+ budget: input.budget,
672
+ internalCaps: input.internalCaps,
673
+ excludedRealRoots: input.excludedRealRoots,
674
+ focusScanExempt: true,
483
675
  ...(input.signal == null ? {} : { signal: input.signal }),
484
676
  fs: input.fs,
485
677
  state: input.state,
@@ -495,14 +687,41 @@ export function buildCandidateSearchRecords(input) {
495
687
  let previewBytes = 0;
496
688
  let candidateBytes = 0;
497
689
  let capHit = false;
498
- if (input.searchTerms.length === 0) {
499
- return { records, capHit, candidateBytes };
500
- }
690
+ const callerTermCount = Math.max(0, Math.min(input.callerTermCount ?? 0, input.searchTerms.length));
501
691
  const searchTerms = input.searchTerms
502
692
  .map((term, index) => ({ term, index }))
503
693
  .filter(({ term }) => term.trim().length > 0);
694
+ const callerTerms = searchTerms.filter(({ index }) => index < callerTermCount);
695
+ const derivedTerms = searchTerms.filter(({ index }) => index >= callerTermCount);
696
+ // Candidates whose content was examined for at least one term before a hard
697
+ // cap ended the walk. Key set is bounded by the candidate pool; only counts
698
+ // are surfaced.
699
+ const searchedCandidateKeys = new Set();
700
+ const callerTermCoverage = callerTerms.map(({ term, index }) => ({
701
+ term,
702
+ search_term_index: index,
703
+ hit_count: 0,
704
+ scan_complete: false,
705
+ }));
706
+ let callerRecordCount = 0;
707
+ const finalize = () => ({
708
+ records,
709
+ capHit,
710
+ candidateBytes,
711
+ coverage: {
712
+ eligible_candidate_count: input.candidates.length,
713
+ searched_candidate_count: searchedCandidateKeys.size,
714
+ unsearched_candidate_count: input.candidates.length - searchedCandidateKeys.size,
715
+ caller_term_count: callerTerms.length,
716
+ derived_term_count: derivedTerms.length,
717
+ caller_record_count: callerRecordCount,
718
+ derived_record_count: records.length - callerRecordCount,
719
+ caller_coverage_complete: callerTermCoverage.every((coverage) => coverage.scan_complete),
720
+ caller_terms: callerTermCoverage,
721
+ },
722
+ });
504
723
  if (searchTerms.length === 0) {
505
- return { records, capHit, candidateBytes };
724
+ return finalize();
506
725
  }
507
726
  const focusRank = new Map();
508
727
  for (const focus of input.focusPaths ?? []) {
@@ -521,70 +740,154 @@ export function buildCandidateSearchRecords(input) {
521
740
  const leftRank = focusRank.get(candidateKey(left)) ?? Number.MAX_SAFE_INTEGER;
522
741
  const rightRank = focusRank.get(candidateKey(right)) ?? Number.MAX_SAFE_INTEGER;
523
742
  return (leftRank - rightRank ||
524
- discoveryTaskClosureRank(left.path, input.task ?? "") -
525
- discoveryTaskClosureRank(right.path, input.task ?? "") ||
526
743
  compareContentCandidates(left, right));
527
744
  });
528
- const streams = [];
745
+ const candidateLines = [];
529
746
  for (const candidate of candidates) {
530
747
  assertNotAborted(input.signal);
531
- const lines = splitTextLines(candidate.content);
532
- for (const searchTerm of searchTerms) {
533
- streams.push({
748
+ candidateLines.push(splitTextLines(candidate.content));
749
+ }
750
+ // Emits one found hit unless a hard cap rejects it. Cap semantics match the
751
+ // pre-phasing scheduler: the record/byte caps are checked after the hit is
752
+ // found, and tripping either one ends the whole search with capHit set.
753
+ const emitSearchHit = (stream, hit) => {
754
+ if (records.length >= input.maxSearchResults) {
755
+ capHit = true;
756
+ return false;
757
+ }
758
+ const preview = boundedPreview(hit.line, hit.columnIndex, stream.searchTerm.term.length);
759
+ const previewSize = Buffer.byteLength(preview, "utf8");
760
+ const bounded = previewBytes + previewSize <= maxPreviewBytes ? preview : "";
761
+ const record = {
762
+ root_index: stream.candidate.root_index,
763
+ path: stream.candidate.path,
764
+ line: hit.lineIndex + 1,
765
+ column: hit.columnIndex + 1,
766
+ search_term: stream.searchTerm.term,
767
+ search_term_index: stream.searchTerm.index,
768
+ preview: bounded,
769
+ };
770
+ const recordBytes = Buffer.byteLength(`${JSON.stringify(record)}\n`, "utf8");
771
+ if (candidateBytes + recordBytes > maxCandidateBytes) {
772
+ capHit = true;
773
+ return false;
774
+ }
775
+ previewBytes += Buffer.byteLength(bounded, "utf8");
776
+ candidateBytes += recordBytes;
777
+ records.push(record);
778
+ return true;
779
+ };
780
+ if (callerTerms.length > 0) {
781
+ // Phase 1 — exact caller terms get first claim on the record budget. One
782
+ // cursor per caller term walks the complete candidate list (focus rank
783
+ // first, one hit per candidate per pass), and the scheduler round-robins
784
+ // across the term cursors, so neither a common sibling term nor an early
785
+ // alphabetical candidate prefix can starve a rare late-path caller hit.
786
+ const cursors = callerTermCoverage.map((coverage) => ({
787
+ coverage,
788
+ streams: candidates.map((candidate, candidateIndex) => ({
534
789
  candidate,
535
- searchTerm,
536
- lines,
790
+ searchTerm: { term: coverage.term, index: coverage.search_term_index },
791
+ lines: candidateLines[candidateIndex] ?? [],
537
792
  lineIndex: 0,
538
793
  fromIndex: 0,
539
794
  done: false,
540
- });
795
+ })),
796
+ cursor: 0,
797
+ active: candidates.length,
798
+ exhausted: false,
799
+ }));
800
+ let liveCursors = cursors.length;
801
+ while (liveCursors > 0) {
802
+ for (const cursor of cursors) {
803
+ assertNotAborted(input.signal);
804
+ if (cursor.exhausted) {
805
+ continue;
806
+ }
807
+ const next = nextCallerTermHit(cursor, searchedCandidateKeys);
808
+ if (next == null) {
809
+ // Natural exhaustion: this term's cursor examined every candidate.
810
+ cursor.exhausted = true;
811
+ cursor.coverage.scan_complete = true;
812
+ liveCursors--;
813
+ continue;
814
+ }
815
+ if (!emitSearchHit(next.stream, next.hit)) {
816
+ return finalize();
817
+ }
818
+ cursor.coverage.hit_count++;
819
+ callerRecordCount++;
820
+ }
541
821
  }
542
822
  }
543
- let activeStreams = streams.length;
544
- while (activeStreams > 0) {
545
- let foundInRound = false;
546
- for (const stream of streams) {
823
+ if (derivedTerms.length > 0) {
824
+ // Phase 2 — derived/heuristic terms spend whatever budget remains, using
825
+ // the pre-existing candidate-major one-hit-per-stream round-robin.
826
+ const streams = [];
827
+ for (const [candidateIndex, candidate] of candidates.entries()) {
547
828
  assertNotAborted(input.signal);
548
- if (stream.done) {
549
- continue;
550
- }
551
- const hit = nextSearchHit(stream);
552
- if (hit == null) {
553
- stream.done = true;
554
- activeStreams--;
555
- continue;
829
+ const lines = candidateLines[candidateIndex] ?? [];
830
+ for (const searchTerm of derivedTerms) {
831
+ streams.push({
832
+ candidate,
833
+ searchTerm,
834
+ lines,
835
+ lineIndex: 0,
836
+ fromIndex: 0,
837
+ done: false,
838
+ });
556
839
  }
557
- foundInRound = true;
558
- if (records.length >= input.maxSearchResults) {
559
- capHit = true;
560
- return { records, capHit, candidateBytes };
840
+ }
841
+ let activeStreams = streams.length;
842
+ while (activeStreams > 0) {
843
+ let foundInRound = false;
844
+ for (const stream of streams) {
845
+ assertNotAborted(input.signal);
846
+ if (stream.done) {
847
+ continue;
848
+ }
849
+ searchedCandidateKeys.add(candidateKey(stream.candidate));
850
+ const hit = nextSearchHit(stream);
851
+ if (hit == null) {
852
+ stream.done = true;
853
+ activeStreams--;
854
+ continue;
855
+ }
856
+ foundInRound = true;
857
+ if (!emitSearchHit(stream, hit)) {
858
+ return finalize();
859
+ }
561
860
  }
562
- const preview = boundedPreview(hit.line, hit.columnIndex, stream.searchTerm.term.length);
563
- const previewSize = Buffer.byteLength(preview, "utf8");
564
- const bounded = previewBytes + previewSize <= maxPreviewBytes ? preview : "";
565
- const record = {
566
- root_index: stream.candidate.root_index,
567
- path: stream.candidate.path,
568
- line: hit.lineIndex + 1,
569
- column: hit.columnIndex + 1,
570
- search_term: stream.searchTerm.term,
571
- search_term_index: stream.searchTerm.index,
572
- preview: bounded,
573
- };
574
- const recordBytes = Buffer.byteLength(`${JSON.stringify(record)}\n`, "utf8");
575
- if (candidateBytes + recordBytes > maxCandidateBytes) {
576
- capHit = true;
577
- return { records, capHit, candidateBytes };
861
+ if (!foundInRound) {
862
+ break;
578
863
  }
579
- previewBytes += Buffer.byteLength(bounded, "utf8");
580
- candidateBytes += recordBytes;
581
- records.push(record);
582
864
  }
583
- if (!foundInRound) {
584
- break;
865
+ }
866
+ return finalize();
867
+ }
868
+ // Advances one caller term's cursor to its next hit, cycling the candidate
869
+ // list one hit per candidate per pass. Scanning is free — only emitted records
870
+ // consume the budget — so a rare term reaches late-sorting candidates even
871
+ // when earlier candidates are saturated with other terms' hits. Returns
872
+ // undefined exactly when every candidate stream is exhausted.
873
+ function nextCallerTermHit(cursor, searchedCandidateKeys) {
874
+ const total = cursor.streams.length;
875
+ for (let visited = 0; visited < total && cursor.active > 0; visited++) {
876
+ const stream = cursor.streams[cursor.cursor];
877
+ cursor.cursor = (cursor.cursor + 1) % total;
878
+ if (stream == null || stream.done) {
879
+ continue;
880
+ }
881
+ searchedCandidateKeys.add(candidateKey(stream.candidate));
882
+ const hit = nextSearchHit(stream);
883
+ if (hit == null) {
884
+ stream.done = true;
885
+ cursor.active--;
886
+ continue;
585
887
  }
888
+ return { stream, hit };
586
889
  }
587
- return { records, capHit, candidateBytes };
890
+ return undefined;
588
891
  }
589
892
  export function buildCandidateSliceRecords(input) {
590
893
  const maxCandidateSlices = input.maxCandidateSlices ??
@@ -603,7 +906,7 @@ export function buildCandidateSliceRecords(input) {
603
906
  const expectedFocusedSearchRanges = new Map();
604
907
  const survivedFocusedSearchRanges = new Map();
605
908
  const focusSliceSurvivors = new Set();
606
- const omittedLargeFocusedCandidates = new Set();
909
+ const slicedLargeFocusedCandidates = new Set();
607
910
  const omittedRequestedCandidates = new Set();
608
911
  const pushRequestedCandidateOmission = (candidate, kind, message) => {
609
912
  const key = candidateKey(candidate);
@@ -701,12 +1004,8 @@ export function buildCandidateSliceRecords(input) {
701
1004
  (focus.kind === "directory" &&
702
1005
  isRootRelativeDescendant(candidate.path, focus.root_relative_path)))) {
703
1006
  const key = candidateKey(candidate);
704
- if (candidate.byte_length > fullFocusSliceByteLimit(candidate.path, maxFullFocusSliceBytes)) {
705
- if (!searchRanges.has(key) && !omittedLargeFocusedCandidates.has(key)) {
706
- pushRequestedCandidateOmission(candidate, "too_large", "focused file exceeded bounded full-file focus size and had no per-file search evidence");
707
- omittedLargeFocusedCandidates.add(key);
708
- }
709
- else if (searchRanges.has(key)) {
1007
+ if (candidate.byte_length > maxFullFocusSliceBytes) {
1008
+ if (searchRanges.has(key)) {
710
1009
  focusedLargeSearchCandidates.set(key, candidate);
711
1010
  expectedFocusedSearchRanges.set(key, mergeLineRanges(searchRanges.get(key) ?? [], {
712
1011
  bridgeGapLines: SEARCH_BRIDGE_GAP_LINES,
@@ -714,6 +1013,27 @@ export function buildCandidateSliceRecords(input) {
714
1013
  }));
715
1014
  survivedFocusedSearchRanges.set(key, []);
716
1015
  }
1016
+ else if (!slicedLargeFocusedCandidates.has(key)) {
1017
+ // Never silently drop an explicitly-focused file. With no per-file
1018
+ // search evidence, include a bounded head slice up to the focus
1019
+ // byte cap and record a material, non-silent partial-focus signal
1020
+ // instead of a too_large omission.
1021
+ if (firstLineExceedsCap(candidate.content, maxFullFocusSliceBytes)) {
1022
+ // The first logical line alone exceeds the cap (e.g. a minified
1023
+ // single-line file). The line-range model cannot express a partial
1024
+ // line, so a head slice would blow the byte bound. Omit the file
1025
+ // with an explicit material reason rather than exceeding the bound.
1026
+ omissions.push(focusOverCapNotice(candidate, maxFullFocusSliceBytes));
1027
+ slicedLargeFocusedCandidates.add(key);
1028
+ continue;
1029
+ }
1030
+ const headEndLine = headSliceEndLine(candidate.content, maxFullFocusSliceBytes);
1031
+ const ranges = focusRanges.get(key) ?? [];
1032
+ ranges.push({ start_line: 1, end_line: headEndLine });
1033
+ focusRanges.set(key, ranges);
1034
+ omissions.push(focusSlicedNotice(candidate, headEndLine));
1035
+ slicedLargeFocusedCandidates.add(key);
1036
+ }
717
1037
  continue;
718
1038
  }
719
1039
  const ranges = focusRanges.get(candidateKey(candidate)) ?? [];
@@ -735,6 +1055,30 @@ export function buildCandidateSliceRecords(input) {
735
1055
  { start_line: 1, end_line: Math.max(1, candidate.line_count) },
736
1056
  ]);
737
1057
  }
1058
+ // Focus slices are appended FIRST so max_candidate_slices/max_candidate_bytes
1059
+ // pressure prunes search and dependency material before explicitly-focused
1060
+ // ranges — never the other way around.
1061
+ for (const [key, ranges] of [...focusRanges.entries()].sort(([a], [b]) => a.localeCompare(b))) {
1062
+ assertNotAborted(input.signal);
1063
+ const candidate = candidateByIdentity.get(key);
1064
+ if (candidate == null) {
1065
+ continue;
1066
+ }
1067
+ for (const range of mergeLineRanges(ranges)) {
1068
+ if (!append({
1069
+ root_index: candidate.root_index,
1070
+ path: candidate.path,
1071
+ start_line: range.start_line,
1072
+ end_line: range.end_line,
1073
+ source: "focus",
1074
+ content: sliceContent(candidate.content, range.start_line, range.end_line),
1075
+ })) {
1076
+ pushMissingFocusedRangeOmissions(focusRanges.keys());
1077
+ pushMissingFocusedSearchOmissions(focusedLargeSearchCandidates.keys());
1078
+ return { records, capHit, omissions };
1079
+ }
1080
+ }
1081
+ }
738
1082
  for (const [key, ranges] of [...searchRanges.entries()].sort(([a], [b]) => a.localeCompare(b))) {
739
1083
  assertNotAborted(input.signal);
740
1084
  const candidate = candidateByIdentity.get(key);
@@ -787,27 +1131,52 @@ export function buildCandidateSliceRecords(input) {
787
1131
  }
788
1132
  }
789
1133
  }
790
- for (const [key, ranges] of [...focusRanges.entries()].sort(([a], [b]) => a.localeCompare(b))) {
791
- assertNotAborted(input.signal);
792
- const candidate = candidateByIdentity.get(key);
793
- if (candidate == null) {
1134
+ return { records, capHit, omissions };
1135
+ }
1136
+ // Head-slice line bound for synthesized regression evidence: enough to show a
1137
+ // test's imports and first cases without competing with real search windows.
1138
+ const REGRESSION_HEAD_SLICE_MAX_LINES = 60;
1139
+ /**
1140
+ * Materializes the tests chosen by `planRegressionHeadSliceCandidates` as real
1141
+ * slice records so selection, reconstruction, and rendering can carry them.
1142
+ * Source is `search` WITHOUT `search_term_index`: every slice consumer already
1143
+ * defaults a missing index to the lowest rank, and `focus` would wrongly mark
1144
+ * the test as caller-requested evidence. Content comes from the already
1145
+ * sanitized content candidate, so `allow_secrets:false` redaction applies
1146
+ * exactly as for other slices. Candidate slice/byte caps still bound the
1147
+ * total; a slice that does not fit is simply not synthesized.
1148
+ */
1149
+ function buildRegressionHeadSliceRecords(input) {
1150
+ const candidateByIdentity = new Map(input.candidates.map((candidate) => [candidateKey(candidate), candidate]));
1151
+ let count = input.existingRecords.length;
1152
+ let bytes = input.existingRecords.reduce((total, record) => total + Buffer.byteLength(`${JSON.stringify(record)}\n`, "utf8"), 0);
1153
+ const records = [];
1154
+ for (const planned of input.planned) {
1155
+ const candidate = candidateByIdentity.get(candidateKey(planned));
1156
+ if (candidate == null ||
1157
+ candidate.line_count === 0 ||
1158
+ firstLineExceedsCap(candidate.content, input.maxBytesPerFile)) {
794
1159
  continue;
795
1160
  }
796
- for (const range of mergeLineRanges(ranges)) {
797
- if (!append({
798
- root_index: candidate.root_index,
799
- path: candidate.path,
800
- start_line: range.start_line,
801
- end_line: range.end_line,
802
- source: "focus",
803
- content: sliceContent(candidate.content, range.start_line, range.end_line),
804
- })) {
805
- pushMissingFocusedRangeOmissions(focusRanges.keys());
806
- return { records, capHit, omissions };
807
- }
1161
+ const endLine = Math.min(candidate.line_count, REGRESSION_HEAD_SLICE_MAX_LINES, headSliceEndLine(candidate.content, input.maxBytesPerFile));
1162
+ const record = {
1163
+ root_index: candidate.root_index,
1164
+ path: candidate.path,
1165
+ start_line: 1,
1166
+ end_line: endLine,
1167
+ source: "search",
1168
+ content: sliceContent(candidate.content, 1, endLine),
1169
+ };
1170
+ const recordBytes = Buffer.byteLength(`${JSON.stringify(record)}\n`, "utf8");
1171
+ if (count >= input.maxCandidateSlices ||
1172
+ bytes + recordBytes > input.maxCandidateBytes) {
1173
+ continue;
808
1174
  }
1175
+ records.push(record);
1176
+ count++;
1177
+ bytes += recordBytes;
809
1178
  }
810
- return { records, capHit, omissions };
1179
+ return records;
811
1180
  }
812
1181
  export function splitTextLines(text) {
813
1182
  if (text.length === 0) {
@@ -859,11 +1228,55 @@ export function mergeLineRanges(ranges, options = {}) {
859
1228
  }
860
1229
  return merged;
861
1230
  }
862
- function fullFocusSliceByteLimit(path, maxFullFocusSliceBytes) {
863
- if (isTestPath(path)) {
864
- return Math.min(maxFullFocusSliceBytes, DEFAULT_MAX_FULL_FOCUS_SLICE_BYTES);
1231
+ // Largest 1-based line count whose cumulative UTF-8 bytes (lines joined by
1232
+ // "\n", matching sliceContent) stay within capBytes. Always returns >= 1 so an
1233
+ // explicitly-focused file is never reduced to nothing.
1234
+ // CALLER COUPLING: line 1 is admitted unconditionally (the `count > 0 &&` guard
1235
+ // skips the cap check for the first line), so callers MUST pre-screen with
1236
+ // firstLineExceedsCap — otherwise an over-cap first line silently breaks the
1237
+ // byte bound.
1238
+ function headSliceEndLine(content, capBytes) {
1239
+ const lines = splitTextLines(content);
1240
+ let bytes = 0;
1241
+ let count = 0;
1242
+ for (const line of lines) {
1243
+ const next = bytes + (count === 0 ? 0 : 1) + Buffer.byteLength(line, "utf8");
1244
+ if (count > 0 && next > capBytes) {
1245
+ break;
1246
+ }
1247
+ bytes = next;
1248
+ count++;
1249
+ }
1250
+ return Math.max(1, count);
1251
+ }
1252
+ // True when even the first logical line's own UTF-8 byte length exceeds capBytes,
1253
+ // i.e. no head slice (which always covers at least line 1) can fit within the cap.
1254
+ function firstLineExceedsCap(content, capBytes) {
1255
+ const lines = splitTextLines(content);
1256
+ const first = lines[0];
1257
+ if (first == null) {
1258
+ return false;
865
1259
  }
866
- return maxFullFocusSliceBytes;
1260
+ return Buffer.byteLength(first, "utf8") > capBytes;
1261
+ }
1262
+ function focusOverCapNotice(candidate, capBytes) {
1263
+ return {
1264
+ root_index: candidate.root_index,
1265
+ reason: CONTEXT_BUILDER_FOCUS_OVER_CAP_REASON,
1266
+ message: "focused file's first line alone exceeded the bounded focus-slice cap " +
1267
+ `(${capBytes} bytes); omitted rather than exceeding the byte bound`,
1268
+ paths: [candidate.path],
1269
+ };
1270
+ }
1271
+ function focusSlicedNotice(candidate, headEndLine) {
1272
+ return {
1273
+ root_index: candidate.root_index,
1274
+ reason: CONTEXT_BUILDER_FOCUS_SLICED_REASON,
1275
+ message: "focused file exceeded bounded full-file focus size and had no per-file " +
1276
+ `search evidence; included a bounded head slice (lines 1-${headEndLine}) ` +
1277
+ "instead of dropping it",
1278
+ paths: [candidate.path],
1279
+ };
867
1280
  }
868
1281
  function focusedSearchRangesCovered(expected, survived) {
869
1282
  return expected.every((range) => rangeCoveredByRanges(range, survived));
@@ -889,6 +1302,14 @@ async function traverseDirectory(input) {
889
1302
  if (input.state.stopped) {
890
1303
  return;
891
1304
  }
1305
+ const directoryKey = candidateKey({
1306
+ root_index: input.root.root_index,
1307
+ path: input.relativeDir,
1308
+ });
1309
+ if (input.state.traversedDirectoryKeys.has(directoryKey)) {
1310
+ return;
1311
+ }
1312
+ input.state.traversedDirectoryKeys.add(directoryKey);
892
1313
  if (input.relativeDir !== "" &&
893
1314
  (input.matcher.excludes(input.relativeDir) ||
894
1315
  input.matcher.excludes(`${input.relativeDir}/__dir__`))) {
@@ -1025,6 +1446,35 @@ function pushDirectoryOmission(input, omission) {
1025
1446
  });
1026
1447
  }
1027
1448
  async function processFile(input) {
1449
+ await processFileEntry(input);
1450
+ await settleDiscoveryFileBoundary(input.state, input.signal);
1451
+ }
1452
+ async function settleDiscoveryFileBoundary(state, signal) {
1453
+ state.filesSinceProgress++;
1454
+ if (state.onProgress != null &&
1455
+ state.filesSinceProgress >= CONTEXT_BUILDER_SCAN_PROGRESS_EVERY_FILES) {
1456
+ state.filesSinceProgress = 0;
1457
+ try {
1458
+ state.onProgress(Object.freeze({ ...state.metrics }));
1459
+ }
1460
+ catch {
1461
+ // Progress is observability only; a failing sink must never stop the walk.
1462
+ }
1463
+ }
1464
+ assertNotAborted(signal);
1465
+ state.filesSinceYield++;
1466
+ if (state.filesSinceYield >= DISCOVERY_YIELD_EVERY_FILES) {
1467
+ await yieldDiscoveryToEventLoop(state, signal);
1468
+ }
1469
+ }
1470
+ async function yieldDiscoveryToEventLoop(state, signal) {
1471
+ state.filesSinceYield = 0;
1472
+ await new Promise((resolve) => {
1473
+ setImmediate(resolve);
1474
+ });
1475
+ assertNotAborted(signal);
1476
+ }
1477
+ async function processFileEntry(input) {
1028
1478
  const fileKey = candidateKey({
1029
1479
  root_index: input.root.root_index,
1030
1480
  path: input.relativePath,
@@ -1038,7 +1488,7 @@ async function processFile(input) {
1038
1488
  if (!alreadyProcessed) {
1039
1489
  input.state.processedFileKeys.add(fileKey);
1040
1490
  }
1041
- const omitted = (reason, message) => {
1491
+ const omitted = (reason, message, secretFindings) => {
1042
1492
  input.state.omissions.push({
1043
1493
  root_index: input.root.root_index,
1044
1494
  reason,
@@ -1051,7 +1501,7 @@ async function processFile(input) {
1051
1501
  focusPaths: input.focusPaths,
1052
1502
  state: input.state,
1053
1503
  kind: requestedOmissionKindForDiscoveryReason(reason),
1054
- message: sanitizedFocusedOmissionMessage(reason),
1504
+ message: sanitizedFocusedOmissionMessage(reason, secretFindings),
1055
1505
  });
1056
1506
  };
1057
1507
  const requestedOmitted = (kind, message) => {
@@ -1103,8 +1553,13 @@ async function processFile(input) {
1103
1553
  });
1104
1554
  return;
1105
1555
  }
1556
+ // files_seen stays accurate for observability, but focus-processed files are
1557
+ // subtracted from the cap check so explicit focus never consumes the
1558
+ // max_scan_files headroom reserved for global traversal.
1106
1559
  if (input.ignoreScanCap !== true &&
1107
- input.state.metrics.files_seen >= input.budget.max_scan_files) {
1560
+ input.focusScanExempt !== true &&
1561
+ input.state.metrics.files_seen - input.state.focusScanExemptFiles >=
1562
+ input.budget.max_scan_files) {
1108
1563
  input.state.metrics.scan_cap_hit = true;
1109
1564
  pushRequestedFocusOmission({
1110
1565
  root_index: input.root.root_index,
@@ -1118,9 +1573,12 @@ async function processFile(input) {
1118
1573
  return;
1119
1574
  }
1120
1575
  input.state.metrics.files_seen++;
1121
- const pathSecrets = scanSecretPath(input.relativePath);
1576
+ if (input.focusScanExempt === true) {
1577
+ input.state.focusScanExemptFiles++;
1578
+ }
1579
+ const pathSecrets = input.allowSecrets ? [] : scanSecretPath(input.relativePath);
1122
1580
  if (pathSecrets.length > 0) {
1123
- omitted("secret_path", `Secret-looking path omitted (${pathSecrets[0]?.provenance})`);
1581
+ omitted("secret_path", `Secret-looking path omitted (${pathSecrets[0]?.provenance})`, pathSecrets);
1124
1582
  pushTree({
1125
1583
  eligible: false,
1126
1584
  content_eligible: false,
@@ -1235,10 +1693,15 @@ async function processFile(input) {
1235
1693
  }
1236
1694
  const rawContent = contentBuffer.toString("utf8");
1237
1695
  input.state.metrics.bytes_read += contentBuffer.byteLength;
1238
- const contentSecrets = scanHighConfidenceSecretContent(rawContent);
1239
- const blockingSecrets = contentSecrets.filter(isBlockingSecretFinding);
1240
- if (blockingSecrets.length > 0) {
1241
- omitted("content_secret", `Content omitted due to high-confidence secret (${summarizeSecretFindings(blockingSecrets)})`);
1696
+ const sanitized = input.allowSecrets
1697
+ ? { status: "unchanged", content: rawContent, findings: [] }
1698
+ : sanitizeHighConfidenceSecretContent(rawContent);
1699
+ if (!input.allowSecrets) {
1700
+ assertNotAborted(input.signal);
1701
+ await yieldDiscoveryToEventLoop(input.state, input.signal);
1702
+ }
1703
+ if (sanitized.status === "blocked") {
1704
+ omitted("content_secret", `Content omitted due to high-confidence secret (${summarizeSecretFindings(sanitized.findings)})`, sanitized.findings);
1242
1705
  pushTree({
1243
1706
  size_bytes: read.sizeBytes,
1244
1707
  eligible: true,
@@ -1247,9 +1710,7 @@ async function processFile(input) {
1247
1710
  });
1248
1711
  return;
1249
1712
  }
1250
- const content = contentSecrets.length > 0
1251
- ? redactHighConfidenceAssignmentSecrets(rawContent)
1252
- : rawContent;
1713
+ const content = sanitized.content;
1253
1714
  const contentBytes = Buffer.byteLength(content, "utf8");
1254
1715
  if (input.state.contentCandidates.length >= input.internalCaps.max_discovery_candidates) {
1255
1716
  input.state.metrics.discovery_candidate_cap_hit = true;
@@ -1403,74 +1864,6 @@ function compareTreeFiles(left, right) {
1403
1864
  function compareContentCandidates(left, right) {
1404
1865
  return left.root_index - right.root_index || left.path.localeCompare(right.path);
1405
1866
  }
1406
- function discoveryTaskClosureRank(path, task) {
1407
- const normalizedTask = task.toLowerCase();
1408
- if (normalizedTask.length === 0) {
1409
- return 0;
1410
- }
1411
- const taskTokens = new Set(tokenizeGenericSearchTerm(normalizedTask));
1412
- const normalizedPath = path.toLowerCase();
1413
- if (/\b(discover|discovery)\b.*\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b|\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b.*\b(discover|discovery)\b/.test(normalizedTask) &&
1414
- hasAnyToken(taskTokens, ["provider", "runtime", "claude", "agent", "symmetry"]) &&
1415
- [/\/claude_agent\.py$/, /\/runtime\/base\.py$/].some((pattern) => pattern.test(normalizedPath))) {
1416
- return -30;
1417
- }
1418
- if (/\b(discover|discovery)\b/.test(normalizedTask) &&
1419
- hasAnyToken(taskTokens, ["queue", "migration", "runtime", "schema", "setting", "selector"]) &&
1420
- [
1421
- /\/tasks\/chat_processor\.py$/,
1422
- /\/hooks\/usemessageactions\.ts$/,
1423
- /\/hooks\/usechatstreaming\.ts$/,
1424
- /\/hooks\/usechatruntimesettings\.ts$/,
1425
- /\/components\/chat\/chat-window\/chat\.tsx$/,
1426
- /\/components\/chat\/message-input\/input\.tsx$/,
1427
- /\/components\/chat\/message-input\/inputsettingspopover\.tsx$/,
1428
- /\/pages\/chatpage\.tsx$/,
1429
- /\/landingpage\.tsx$/,
1430
- /\/models\/db_models\/chat\.py$/,
1431
- /\/[^/]*(permission|thinking).*selector[^/]*\.(ts|tsx)$/,
1432
- /\/tests\/test_chat\.py$/,
1433
- /\/tests?\/.*runtime.*\.(py|ts|tsx)$/,
1434
- ].some((pattern) => pattern.test(normalizedPath))) {
1435
- return -24;
1436
- }
1437
- if (/\breview\b/.test(normalizedTask) &&
1438
- hasAnyToken(taskTokens, ["codex", "approval", "permission", "session", "runtime"]) &&
1439
- [
1440
- /\/api\/endpoints\/permissions\.py$/,
1441
- /\/services\/runtime\/codex_approval\.py$/,
1442
- /\/services\/permission_manager\.py$/,
1443
- /\/services\/chat\.py$/,
1444
- /\/api\/endpoints\/chat\.py$/,
1445
- /\/models\/db_models\/ai_model\.py$/,
1446
- /\/services\/chatservice\.ts$/,
1447
- /\/types\/chat\.types\.ts$/,
1448
- /\/core\/config\.py$/,
1449
- /\/constants\.py$/,
1450
- /\/hooks\/usepermissionrequest\.ts$/,
1451
- /\/tests\/test_permissions\.py$/,
1452
- /(^|\/)docs?\/.*(codex|approval|permission|session|runtime).*\.md$/,
1453
- ].some((pattern) => pattern.test(normalizedPath))) {
1454
- return -24;
1455
- }
1456
- if (/\b(debug|debugging|diagnose|diagnosis|diagnostic)\b/.test(normalizedTask) &&
1457
- hasAnyToken(taskTokens, ["devtool", "trace", "archive", "message"]) &&
1458
- [
1459
- /\/api\/endpoints\/devtools\.py$/,
1460
- /\/services\/session_trace_archive\.py$/,
1461
- /\/models\/db_models\/session_trace_archive\.py$/,
1462
- /\/.*trace.*archive.*\.test\.(ts|tsx|py)$/,
1463
- /\/tests?\/.*trace.*archive.*\.(py|ts|tsx)$/,
1464
- /\/messagerenderer\.tsx$/,
1465
- /\/devtools\.types\.ts$/,
1466
- ].some((pattern) => pattern.test(normalizedPath))) {
1467
- return -24;
1468
- }
1469
- return 0;
1470
- }
1471
- function hasAnyToken(tokens, candidates) {
1472
- return candidates.some((candidate) => tokens.has(candidate));
1473
- }
1474
1867
  function compareSearchRecords(left, right) {
1475
1868
  return (left.root_index - right.root_index ||
1476
1869
  left.path.localeCompare(right.path) ||
@@ -1569,14 +1962,14 @@ function requestedEvidenceOmissionKey(rootIndex, relativePath) {
1569
1962
  function requestedOmissionKindForDiscoveryReason(reason) {
1570
1963
  return reason === "file_too_large" ? "too_large" : "unavailable";
1571
1964
  }
1572
- function sanitizedFocusedOmissionMessage(reason) {
1965
+ function sanitizedFocusedOmissionMessage(reason, secretFindings) {
1573
1966
  switch (reason) {
1574
1967
  case "caller_include_glob":
1575
1968
  return "focused path was outside include globs";
1576
1969
  case "exclude_glob":
1577
1970
  return "focused path was omitted by exclude globs";
1578
1971
  case "secret_path":
1579
- return "focused path was omitted because it matched a secret-path rule";
1972
+ return withSecretFindingProvenance("focused path was omitted because it matched a secret-path rule", secretFindings);
1580
1973
  case "symlink_omitted":
1581
1974
  return "focused path was omitted because symlinks are not followed";
1582
1975
  case "path_escape":
@@ -1591,13 +1984,32 @@ function sanitizedFocusedOmissionMessage(reason) {
1591
1984
  case "binary_file":
1592
1985
  return "focused binary file cannot be represented as text";
1593
1986
  case "content_secret":
1594
- return "focused file content was omitted because secret-like content was detected";
1987
+ return withSecretFindingProvenance("focused file content was omitted because secret-like content was detected", secretFindings);
1595
1988
  case "file_too_large":
1596
1989
  return "focused file exceeded max_bytes_per_file";
1597
1990
  default:
1598
1991
  return "focused path could not be represented as local evidence";
1599
1992
  }
1600
1993
  }
1994
+ const MAX_SECRET_FINDING_PROVENANCE_DETAILS = 3;
1995
+ // Appends detector provenance labels and line numbers (never matched secret
1996
+ // text or values) to a sanitized focused-omission message, e.g.
1997
+ // "... (aws_access_key_id at line 12)".
1998
+ function withSecretFindingProvenance(base, secretFindings) {
1999
+ const details = [];
2000
+ for (const finding of secretFindings ?? []) {
2001
+ const detail = finding.line == null
2002
+ ? finding.provenance
2003
+ : `${finding.provenance} at line ${finding.line}`;
2004
+ if (!details.includes(detail)) {
2005
+ details.push(detail);
2006
+ }
2007
+ if (details.length >= MAX_SECRET_FINDING_PROVENANCE_DETAILS) {
2008
+ break;
2009
+ }
2010
+ }
2011
+ return details.length === 0 ? base : `${base} (${details.join(", ")})`;
2012
+ }
1601
2013
  function candidateKey(candidate) {
1602
2014
  return `${candidate.root_index}\u0000${candidate.path}`;
1603
2015
  }