@descryy/mcp 0.11.5 → 0.11.7

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 (445) hide show
  1. package/dist/action-handshake.d.ts +38 -0
  2. package/dist/action-handshake.d.ts.map +1 -0
  3. package/dist/action-handshake.js +127 -0
  4. package/dist/action-handshake.js.map +1 -0
  5. package/dist/bin/descry-mcp.d.ts +7 -0
  6. package/dist/bin/descry-mcp.d.ts.map +1 -0
  7. package/dist/bin/descry-mcp.js +73 -0
  8. package/dist/bin/descry-mcp.js.map +1 -0
  9. package/dist/browser/auth.d.ts +84 -0
  10. package/dist/browser/auth.d.ts.map +1 -0
  11. package/dist/browser/auth.js +233 -0
  12. package/dist/browser/auth.js.map +1 -0
  13. package/dist/browser/capability-probe.d.ts +109 -0
  14. package/dist/browser/capability-probe.d.ts.map +1 -0
  15. package/dist/browser/capability-probe.js +201 -0
  16. package/dist/browser/capability-probe.js.map +1 -0
  17. package/dist/browser/driver.d.ts +591 -0
  18. package/dist/browser/driver.d.ts.map +1 -0
  19. package/dist/browser/driver.js +116 -0
  20. package/dist/browser/driver.js.map +1 -0
  21. package/dist/browser/evidence.d.ts +28 -0
  22. package/dist/browser/evidence.d.ts.map +1 -0
  23. package/dist/browser/evidence.js +82 -0
  24. package/dist/browser/evidence.js.map +1 -0
  25. package/dist/browser/fake-driver.d.ts +116 -0
  26. package/dist/browser/fake-driver.d.ts.map +1 -0
  27. package/dist/browser/fake-driver.js +416 -0
  28. package/dist/browser/fake-driver.js.map +1 -0
  29. package/dist/browser/fault-attribution.d.ts +178 -0
  30. package/dist/browser/fault-attribution.d.ts.map +1 -0
  31. package/dist/browser/fault-attribution.js +266 -0
  32. package/dist/browser/fault-attribution.js.map +1 -0
  33. package/dist/browser/graph-write.d.ts +45 -0
  34. package/dist/browser/graph-write.d.ts.map +1 -0
  35. package/dist/browser/graph-write.js +103 -0
  36. package/dist/browser/graph-write.js.map +1 -0
  37. package/dist/browser/identity-graph-write.d.ts +55 -0
  38. package/dist/browser/identity-graph-write.d.ts.map +1 -0
  39. package/dist/browser/identity-graph-write.js +45 -0
  40. package/dist/browser/identity-graph-write.js.map +1 -0
  41. package/dist/browser/page-probe.d.ts +81 -0
  42. package/dist/browser/page-probe.d.ts.map +1 -0
  43. package/dist/browser/page-probe.js +202 -0
  44. package/dist/browser/page-probe.js.map +1 -0
  45. package/dist/browser/playwright-driver.d.ts +115 -0
  46. package/dist/browser/playwright-driver.d.ts.map +1 -0
  47. package/dist/browser/playwright-driver.js +1545 -0
  48. package/dist/browser/playwright-driver.js.map +1 -0
  49. package/dist/browser/provider.d.ts +26 -0
  50. package/dist/browser/provider.d.ts.map +1 -0
  51. package/dist/browser/provider.js +14 -0
  52. package/dist/browser/provider.js.map +1 -0
  53. package/dist/browser/reach-recording-session.d.ts +44 -0
  54. package/dist/browser/reach-recording-session.d.ts.map +1 -0
  55. package/dist/browser/reach-recording-session.js +151 -0
  56. package/dist/browser/reach-recording-session.js.map +1 -0
  57. package/dist/browser/reachability.d.ts +168 -0
  58. package/dist/browser/reachability.d.ts.map +1 -0
  59. package/dist/browser/reachability.js +294 -0
  60. package/dist/browser/reachability.js.map +1 -0
  61. package/dist/browser/registry.d.ts +126 -0
  62. package/dist/browser/registry.d.ts.map +1 -0
  63. package/dist/browser/registry.js +177 -0
  64. package/dist/browser/registry.js.map +1 -0
  65. package/dist/browser/scenario-provenance.d.ts +23 -0
  66. package/dist/browser/scenario-provenance.d.ts.map +1 -0
  67. package/dist/browser/scenario-provenance.js +73 -0
  68. package/dist/browser/scenario-provenance.js.map +1 -0
  69. package/dist/browser/scenario-resolve.d.ts +28 -0
  70. package/dist/browser/scenario-resolve.d.ts.map +1 -0
  71. package/dist/browser/scenario-resolve.js +96 -0
  72. package/dist/browser/scenario-resolve.js.map +1 -0
  73. package/dist/browser/scenario-runner.d.ts +72 -0
  74. package/dist/browser/scenario-runner.d.ts.map +1 -0
  75. package/dist/browser/scenario-runner.js +353 -0
  76. package/dist/browser/scenario-runner.js.map +1 -0
  77. package/dist/browser/stack-parser.d.ts +19 -0
  78. package/dist/browser/stack-parser.d.ts.map +1 -0
  79. package/dist/browser/stack-parser.js +85 -0
  80. package/dist/browser/stack-parser.js.map +1 -0
  81. package/dist/browser/tool-support.d.ts +71 -0
  82. package/dist/browser/tool-support.d.ts.map +1 -0
  83. package/dist/browser/tool-support.js +216 -0
  84. package/dist/browser/tool-support.js.map +1 -0
  85. package/dist/browser/url-scheme.d.ts +14 -0
  86. package/dist/browser/url-scheme.d.ts.map +1 -0
  87. package/dist/browser/url-scheme.js +38 -0
  88. package/dist/browser/url-scheme.js.map +1 -0
  89. package/dist/browser/wait-target.d.ts +37 -0
  90. package/dist/browser/wait-target.d.ts.map +1 -0
  91. package/dist/browser/wait-target.js +54 -0
  92. package/dist/browser/wait-target.js.map +1 -0
  93. package/dist/cancellation.d.ts +20 -0
  94. package/dist/cancellation.d.ts.map +1 -0
  95. package/dist/cancellation.js +41 -0
  96. package/dist/cancellation.js.map +1 -0
  97. package/dist/capped.d.ts +39 -0
  98. package/dist/capped.d.ts.map +1 -0
  99. package/dist/capped.js +43 -0
  100. package/dist/capped.js.map +1 -0
  101. package/dist/credential-store.d.ts +22 -0
  102. package/dist/credential-store.d.ts.map +1 -0
  103. package/dist/credential-store.js +33 -0
  104. package/dist/credential-store.js.map +1 -0
  105. package/dist/disclosure-ledger.d.ts +14 -0
  106. package/dist/disclosure-ledger.d.ts.map +1 -0
  107. package/dist/disclosure-ledger.js +18 -0
  108. package/dist/disclosure-ledger.js.map +1 -0
  109. package/dist/evidence/observed-route-evidence.d.ts +25 -0
  110. package/dist/evidence/observed-route-evidence.d.ts.map +1 -0
  111. package/dist/evidence/observed-route-evidence.js +76 -0
  112. package/dist/evidence/observed-route-evidence.js.map +1 -0
  113. package/dist/heap.d.ts +61 -0
  114. package/dist/heap.d.ts.map +1 -0
  115. package/dist/heap.js +82 -0
  116. package/dist/heap.js.map +1 -0
  117. package/dist/heartbeat.d.ts +46 -0
  118. package/dist/heartbeat.d.ts.map +1 -0
  119. package/dist/heartbeat.js +66 -0
  120. package/dist/heartbeat.js.map +1 -0
  121. package/dist/index.d.ts +32 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +19 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/module-trust.d.ts +37 -0
  126. package/dist/module-trust.d.ts.map +1 -0
  127. package/dist/module-trust.js +77 -0
  128. package/dist/module-trust.js.map +1 -0
  129. package/dist/path-confinement.d.ts +31 -0
  130. package/dist/path-confinement.d.ts.map +1 -0
  131. package/dist/path-confinement.js +44 -0
  132. package/dist/path-confinement.js.map +1 -0
  133. package/dist/planner/predict-then-propose.d.ts +134 -0
  134. package/dist/planner/predict-then-propose.d.ts.map +1 -0
  135. package/dist/planner/predict-then-propose.js +138 -0
  136. package/dist/planner/predict-then-propose.js.map +1 -0
  137. package/dist/planner/propose-journey.d.ts +75 -0
  138. package/dist/planner/propose-journey.d.ts.map +1 -0
  139. package/dist/planner/propose-journey.js +96 -0
  140. package/dist/planner/propose-journey.js.map +1 -0
  141. package/dist/protocol.d.ts +57 -0
  142. package/dist/protocol.d.ts.map +1 -0
  143. package/dist/protocol.js +90 -0
  144. package/dist/protocol.js.map +1 -0
  145. package/dist/ready-checks.d.ts +12 -0
  146. package/dist/ready-checks.d.ts.map +1 -0
  147. package/dist/ready-checks.js +43 -0
  148. package/dist/ready-checks.js.map +1 -0
  149. package/dist/registry.d.ts +103 -0
  150. package/dist/registry.d.ts.map +1 -0
  151. package/dist/registry.js +327 -0
  152. package/dist/registry.js.map +1 -0
  153. package/dist/render.d.ts +623 -0
  154. package/dist/render.d.ts.map +1 -0
  155. package/dist/render.js +968 -0
  156. package/dist/render.js.map +1 -0
  157. package/dist/runtime-registry.d.ts +22 -0
  158. package/dist/runtime-registry.d.ts.map +1 -0
  159. package/dist/runtime-registry.js +142 -0
  160. package/dist/runtime-registry.js.map +1 -0
  161. package/dist/sandbox-defaults.d.ts +41 -0
  162. package/dist/sandbox-defaults.d.ts.map +1 -0
  163. package/dist/sandbox-defaults.js +14 -0
  164. package/dist/sandbox-defaults.js.map +1 -0
  165. package/dist/scenarios/browser-run-plan-projection.d.ts +161 -0
  166. package/dist/scenarios/browser-run-plan-projection.d.ts.map +1 -0
  167. package/dist/scenarios/browser-run-plan-projection.js +264 -0
  168. package/dist/scenarios/browser-run-plan-projection.js.map +1 -0
  169. package/dist/scenarios/credential-ref.d.ts +102 -0
  170. package/dist/scenarios/credential-ref.d.ts.map +1 -0
  171. package/dist/scenarios/credential-ref.js +148 -0
  172. package/dist/scenarios/credential-ref.js.map +1 -0
  173. package/dist/scenarios/index.d.ts +7 -0
  174. package/dist/scenarios/index.d.ts.map +1 -0
  175. package/dist/scenarios/index.js +7 -0
  176. package/dist/scenarios/index.js.map +1 -0
  177. package/dist/scenarios/parse.d.ts +18 -0
  178. package/dist/scenarios/parse.d.ts.map +1 -0
  179. package/dist/scenarios/parse.js +212 -0
  180. package/dist/scenarios/parse.js.map +1 -0
  181. package/dist/scenarios/scenario.d.ts +93 -0
  182. package/dist/scenarios/scenario.d.ts.map +1 -0
  183. package/dist/scenarios/scenario.js +27 -0
  184. package/dist/scenarios/scenario.js.map +1 -0
  185. package/dist/scenarios/secret-ref.d.ts +86 -0
  186. package/dist/scenarios/secret-ref.d.ts.map +1 -0
  187. package/dist/scenarios/secret-ref.js +125 -0
  188. package/dist/scenarios/secret-ref.js.map +1 -0
  189. package/dist/scenarios/storage.d.ts +21 -0
  190. package/dist/scenarios/storage.d.ts.map +1 -0
  191. package/dist/scenarios/storage.js +103 -0
  192. package/dist/scenarios/storage.js.map +1 -0
  193. package/dist/server.d.ts +61 -0
  194. package/dist/server.d.ts.map +1 -0
  195. package/dist/server.js +642 -0
  196. package/dist/server.js.map +1 -0
  197. package/dist/session.d.ts +356 -0
  198. package/dist/session.d.ts.map +1 -0
  199. package/dist/session.js +779 -0
  200. package/dist/session.js.map +1 -0
  201. package/dist/tools/alias-kit.d.ts +29 -0
  202. package/dist/tools/alias-kit.d.ts.map +1 -0
  203. package/dist/tools/alias-kit.js +21 -0
  204. package/dist/tools/alias-kit.js.map +1 -0
  205. package/dist/tools/aliases.d.ts +42 -0
  206. package/dist/tools/aliases.d.ts.map +1 -0
  207. package/dist/tools/aliases.js +52 -0
  208. package/dist/tools/aliases.js.map +1 -0
  209. package/dist/tools/analyze-workspace.d.ts +52 -0
  210. package/dist/tools/analyze-workspace.d.ts.map +1 -0
  211. package/dist/tools/analyze-workspace.js +207 -0
  212. package/dist/tools/analyze-workspace.js.map +1 -0
  213. package/dist/tools/analyze.d.ts +163 -0
  214. package/dist/tools/analyze.d.ts.map +1 -0
  215. package/dist/tools/analyze.js +724 -0
  216. package/dist/tools/analyze.js.map +1 -0
  217. package/dist/tools/browser-click.d.ts +18 -0
  218. package/dist/tools/browser-click.d.ts.map +1 -0
  219. package/dist/tools/browser-click.js +110 -0
  220. package/dist/tools/browser-click.js.map +1 -0
  221. package/dist/tools/browser-close-session.d.ts +39 -0
  222. package/dist/tools/browser-close-session.d.ts.map +1 -0
  223. package/dist/tools/browser-close-session.js +120 -0
  224. package/dist/tools/browser-close-session.js.map +1 -0
  225. package/dist/tools/browser-fill.d.ts +18 -0
  226. package/dist/tools/browser-fill.d.ts.map +1 -0
  227. package/dist/tools/browser-fill.js +117 -0
  228. package/dist/tools/browser-fill.js.map +1 -0
  229. package/dist/tools/browser-navigate.d.ts +15 -0
  230. package/dist/tools/browser-navigate.d.ts.map +1 -0
  231. package/dist/tools/browser-navigate.js +106 -0
  232. package/dist/tools/browser-navigate.js.map +1 -0
  233. package/dist/tools/browser-read.d.ts +33 -0
  234. package/dist/tools/browser-read.d.ts.map +1 -0
  235. package/dist/tools/browser-read.js +105 -0
  236. package/dist/tools/browser-read.js.map +1 -0
  237. package/dist/tools/browser-run-scenario.d.ts +28 -0
  238. package/dist/tools/browser-run-scenario.d.ts.map +1 -0
  239. package/dist/tools/browser-run-scenario.js +238 -0
  240. package/dist/tools/browser-run-scenario.js.map +1 -0
  241. package/dist/tools/browser-save-scenario.d.ts +19 -0
  242. package/dist/tools/browser-save-scenario.d.ts.map +1 -0
  243. package/dist/tools/browser-save-scenario.js +447 -0
  244. package/dist/tools/browser-save-scenario.js.map +1 -0
  245. package/dist/tools/browser-select.d.ts +20 -0
  246. package/dist/tools/browser-select.d.ts.map +1 -0
  247. package/dist/tools/browser-select.js +120 -0
  248. package/dist/tools/browser-select.js.map +1 -0
  249. package/dist/tools/browser-snapshot.d.ts +46 -0
  250. package/dist/tools/browser-snapshot.d.ts.map +1 -0
  251. package/dist/tools/browser-snapshot.js +127 -0
  252. package/dist/tools/browser-snapshot.js.map +1 -0
  253. package/dist/tools/browser-start-session.d.ts +24 -0
  254. package/dist/tools/browser-start-session.d.ts.map +1 -0
  255. package/dist/tools/browser-start-session.js +653 -0
  256. package/dist/tools/browser-start-session.js.map +1 -0
  257. package/dist/tools/browser-submit.d.ts +18 -0
  258. package/dist/tools/browser-submit.d.ts.map +1 -0
  259. package/dist/tools/browser-submit.js +106 -0
  260. package/dist/tools/browser-submit.js.map +1 -0
  261. package/dist/tools/browser-type.d.ts +18 -0
  262. package/dist/tools/browser-type.d.ts.map +1 -0
  263. package/dist/tools/browser-type.js +115 -0
  264. package/dist/tools/browser-type.js.map +1 -0
  265. package/dist/tools/browser-wait-for.d.ts +45 -0
  266. package/dist/tools/browser-wait-for.d.ts.map +1 -0
  267. package/dist/tools/browser-wait-for.js +164 -0
  268. package/dist/tools/browser-wait-for.js.map +1 -0
  269. package/dist/tools/browser.d.ts +69 -0
  270. package/dist/tools/browser.d.ts.map +1 -0
  271. package/dist/tools/browser.js +326 -0
  272. package/dist/tools/browser.js.map +1 -0
  273. package/dist/tools/chain.d.ts +41 -0
  274. package/dist/tools/chain.d.ts.map +1 -0
  275. package/dist/tools/chain.js +101 -0
  276. package/dist/tools/chain.js.map +1 -0
  277. package/dist/tools/change-scope.d.ts +25 -0
  278. package/dist/tools/change-scope.d.ts.map +1 -0
  279. package/dist/tools/change-scope.js +103 -0
  280. package/dist/tools/change-scope.js.map +1 -0
  281. package/dist/tools/code-context.d.ts +83 -0
  282. package/dist/tools/code-context.d.ts.map +1 -0
  283. package/dist/tools/code-context.js +432 -0
  284. package/dist/tools/code-context.js.map +1 -0
  285. package/dist/tools/contracts.d.ts +74 -0
  286. package/dist/tools/contracts.d.ts.map +1 -0
  287. package/dist/tools/contracts.js +214 -0
  288. package/dist/tools/contracts.js.map +1 -0
  289. package/dist/tools/cross-pr.d.ts +178 -0
  290. package/dist/tools/cross-pr.d.ts.map +1 -0
  291. package/dist/tools/cross-pr.js +362 -0
  292. package/dist/tools/cross-pr.js.map +1 -0
  293. package/dist/tools/disclosure.d.ts +75 -0
  294. package/dist/tools/disclosure.d.ts.map +1 -0
  295. package/dist/tools/disclosure.js +325 -0
  296. package/dist/tools/disclosure.js.map +1 -0
  297. package/dist/tools/draw-conclusion.d.ts +55 -0
  298. package/dist/tools/draw-conclusion.d.ts.map +1 -0
  299. package/dist/tools/draw-conclusion.js +243 -0
  300. package/dist/tools/draw-conclusion.js.map +1 -0
  301. package/dist/tools/git-context.d.ts +39 -0
  302. package/dist/tools/git-context.d.ts.map +1 -0
  303. package/dist/tools/git-context.js +374 -0
  304. package/dist/tools/git-context.js.map +1 -0
  305. package/dist/tools/git-diff.d.ts +45 -0
  306. package/dist/tools/git-diff.d.ts.map +1 -0
  307. package/dist/tools/git-diff.js +338 -0
  308. package/dist/tools/git-diff.js.map +1 -0
  309. package/dist/tools/git-history.d.ts +16 -0
  310. package/dist/tools/git-history.d.ts.map +1 -0
  311. package/dist/tools/git-history.js +106 -0
  312. package/dist/tools/git-history.js.map +1 -0
  313. package/dist/tools/history.d.ts +34 -0
  314. package/dist/tools/history.d.ts.map +1 -0
  315. package/dist/tools/history.js +121 -0
  316. package/dist/tools/history.js.map +1 -0
  317. package/dist/tools/impact.d.ts +46 -0
  318. package/dist/tools/impact.d.ts.map +1 -0
  319. package/dist/tools/impact.js +225 -0
  320. package/dist/tools/impact.js.map +1 -0
  321. package/dist/tools/index.d.ts +59 -0
  322. package/dist/tools/index.d.ts.map +1 -0
  323. package/dist/tools/index.js +70 -0
  324. package/dist/tools/index.js.map +1 -0
  325. package/dist/tools/kit.d.ts +165 -0
  326. package/dist/tools/kit.d.ts.map +1 -0
  327. package/dist/tools/kit.js +153 -0
  328. package/dist/tools/kit.js.map +1 -0
  329. package/dist/tools/link-workspace.d.ts +24 -0
  330. package/dist/tools/link-workspace.d.ts.map +1 -0
  331. package/dist/tools/link-workspace.js +131 -0
  332. package/dist/tools/link-workspace.js.map +1 -0
  333. package/dist/tools/lookup.d.ts +19 -0
  334. package/dist/tools/lookup.d.ts.map +1 -0
  335. package/dist/tools/lookup.js +63 -0
  336. package/dist/tools/lookup.js.map +1 -0
  337. package/dist/tools/mark-incident.d.ts +28 -0
  338. package/dist/tools/mark-incident.d.ts.map +1 -0
  339. package/dist/tools/mark-incident.js +171 -0
  340. package/dist/tools/mark-incident.js.map +1 -0
  341. package/dist/tools/merged-browser.d.ts +11 -0
  342. package/dist/tools/merged-browser.d.ts.map +1 -0
  343. package/dist/tools/merged-browser.js +20 -0
  344. package/dist/tools/merged-browser.js.map +1 -0
  345. package/dist/tools/merged-context.d.ts +11 -0
  346. package/dist/tools/merged-context.d.ts.map +1 -0
  347. package/dist/tools/merged-context.js +21 -0
  348. package/dist/tools/merged-context.js.map +1 -0
  349. package/dist/tools/merged-observe.d.ts +13 -0
  350. package/dist/tools/merged-observe.d.ts.map +1 -0
  351. package/dist/tools/merged-observe.js +21 -0
  352. package/dist/tools/merged-observe.js.map +1 -0
  353. package/dist/tools/merged-workspace.d.ts +14 -0
  354. package/dist/tools/merged-workspace.d.ts.map +1 -0
  355. package/dist/tools/merged-workspace.js +21 -0
  356. package/dist/tools/merged-workspace.js.map +1 -0
  357. package/dist/tools/observe-runtime.d.ts +262 -0
  358. package/dist/tools/observe-runtime.d.ts.map +1 -0
  359. package/dist/tools/observe-runtime.js +1966 -0
  360. package/dist/tools/observe-runtime.js.map +1 -0
  361. package/dist/tools/observe-tests.d.ts +57 -0
  362. package/dist/tools/observe-tests.d.ts.map +1 -0
  363. package/dist/tools/observe-tests.js +391 -0
  364. package/dist/tools/observe-tests.js.map +1 -0
  365. package/dist/tools/observe.d.ts +28 -0
  366. package/dist/tools/observe.d.ts.map +1 -0
  367. package/dist/tools/observe.js +291 -0
  368. package/dist/tools/observe.js.map +1 -0
  369. package/dist/tools/pr-analysis.d.ts +189 -0
  370. package/dist/tools/pr-analysis.d.ts.map +1 -0
  371. package/dist/tools/pr-analysis.js +365 -0
  372. package/dist/tools/pr-analysis.js.map +1 -0
  373. package/dist/tools/pre-push.d.ts +168 -0
  374. package/dist/tools/pre-push.d.ts.map +1 -0
  375. package/dist/tools/pre-push.js +416 -0
  376. package/dist/tools/pre-push.js.map +1 -0
  377. package/dist/tools/predict-reach.d.ts +57 -0
  378. package/dist/tools/predict-reach.d.ts.map +1 -0
  379. package/dist/tools/predict-reach.js +183 -0
  380. package/dist/tools/predict-reach.js.map +1 -0
  381. package/dist/tools/propagation.d.ts +37 -0
  382. package/dist/tools/propagation.d.ts.map +1 -0
  383. package/dist/tools/propagation.js +162 -0
  384. package/dist/tools/propagation.js.map +1 -0
  385. package/dist/tools/propose-journey.d.ts +16 -0
  386. package/dist/tools/propose-journey.d.ts.map +1 -0
  387. package/dist/tools/propose-journey.js +132 -0
  388. package/dist/tools/propose-journey.js.map +1 -0
  389. package/dist/tools/prove-reach.d.ts +74 -0
  390. package/dist/tools/prove-reach.d.ts.map +1 -0
  391. package/dist/tools/prove-reach.js +274 -0
  392. package/dist/tools/prove-reach.js.map +1 -0
  393. package/dist/tools/questions.d.ts +30 -0
  394. package/dist/tools/questions.d.ts.map +1 -0
  395. package/dist/tools/questions.js +230 -0
  396. package/dist/tools/questions.js.map +1 -0
  397. package/dist/tools/refusal-fetch.d.ts +35 -0
  398. package/dist/tools/refusal-fetch.d.ts.map +1 -0
  399. package/dist/tools/refusal-fetch.js +123 -0
  400. package/dist/tools/refusal-fetch.js.map +1 -0
  401. package/dist/tools/runtime-incident.d.ts +33 -0
  402. package/dist/tools/runtime-incident.d.ts.map +1 -0
  403. package/dist/tools/runtime-incident.js +67 -0
  404. package/dist/tools/runtime-incident.js.map +1 -0
  405. package/dist/tools/runtime-journey-drive.d.ts +102 -0
  406. package/dist/tools/runtime-journey-drive.d.ts.map +1 -0
  407. package/dist/tools/runtime-journey-drive.js +247 -0
  408. package/dist/tools/runtime-journey-drive.js.map +1 -0
  409. package/dist/tools/scope.d.ts +45 -0
  410. package/dist/tools/scope.d.ts.map +1 -0
  411. package/dist/tools/scope.js +217 -0
  412. package/dist/tools/scope.js.map +1 -0
  413. package/dist/tools/similar-incidents.d.ts +43 -0
  414. package/dist/tools/similar-incidents.d.ts.map +1 -0
  415. package/dist/tools/similar-incidents.js +190 -0
  416. package/dist/tools/similar-incidents.js.map +1 -0
  417. package/dist/tools/validate.d.ts +133 -0
  418. package/dist/tools/validate.d.ts.map +1 -0
  419. package/dist/tools/validate.js +488 -0
  420. package/dist/tools/validate.js.map +1 -0
  421. package/dist/tools/verb.d.ts +46 -0
  422. package/dist/tools/verb.d.ts.map +1 -0
  423. package/dist/tools/verb.js +78 -0
  424. package/dist/tools/verb.js.map +1 -0
  425. package/dist/tools/verification-status.d.ts +38 -0
  426. package/dist/tools/verification-status.d.ts.map +1 -0
  427. package/dist/tools/verification-status.js +203 -0
  428. package/dist/tools/verification-status.js.map +1 -0
  429. package/dist/tools/verify-claim.d.ts +29 -0
  430. package/dist/tools/verify-claim.d.ts.map +1 -0
  431. package/dist/tools/verify-claim.js +218 -0
  432. package/dist/tools/verify-claim.js.map +1 -0
  433. package/dist/tools/workspace.d.ts +28 -0
  434. package/dist/tools/workspace.d.ts.map +1 -0
  435. package/dist/tools/workspace.js +94 -0
  436. package/dist/tools/workspace.js.map +1 -0
  437. package/dist/transport.d.ts +32 -0
  438. package/dist/transport.d.ts.map +1 -0
  439. package/dist/transport.js +85 -0
  440. package/dist/transport.js.map +1 -0
  441. package/dist/workspace-index.d.ts +164 -0
  442. package/dist/workspace-index.d.ts.map +1 -0
  443. package/dist/workspace-index.js +381 -0
  444. package/dist/workspace-index.js.map +1 -0
  445. package/package.json +5 -5
@@ -0,0 +1,724 @@
1
+ /** `analyze` — the only tool that writes to the graph. Disclosures matter most: a
2
+ * query can't report a gap it wasn't told about. Discloses: sources that failed or
3
+ * didn't claim the repo (§20.2 — not-analysable ≠ clean), each source's resolution
4
+ * reached (caps reliability, rule 3), id collisions (DEC-024), evicted files, and the
5
+ * cross-repo join count. No config → `repo` defaults to dir name, hashed into every id (DEC-004). */
6
+ import { createHash } from "node:crypto";
7
+ import { readFile } from "node:fs/promises";
8
+ import { join } from "node:path";
9
+ import { isStructuredSkipEntry } from "@descryy/ir";
10
+ import { applyConfirmedFacts, buildGraph, CONFIRMED_INCIDENT_SOURCE_ID, CONFIRMED_INCIDENT_SOURCE_VERSION, counts, createConfirmedIncidentSource, createGitSource, evictStaleConfirmedIncidentNodes, FILELESS_CACHE_KEY, getCachedFiles, listWorkingTreeFiles, mintEdgesFromConfirmedFacts, MINT_PRODUCED_BY, partitionBatchByFile, persistGraph, planIncrementalReuse, replaceCachedFiles, summariseRefusals, } from "@descryy/core";
11
+ import { answer, optionalBoolean, ToolInputError } from "./kit.js";
12
+ import { heapGuard, readHeap } from "../heap.js";
13
+ import { withHeartbeat } from "../heartbeat.js";
14
+ import { detectSources, loadSources } from "../registry.js";
15
+ // Re-exported for `analyze.test.ts`, which covers this pure helper in isolation.
16
+ // The check itself now runs centrally in `server.ts` (13.3.16 / N2 steps 2-3) —
17
+ // every reply discloses a stale config, not only this tool's.
18
+ export { configDriftNote } from "../session.js";
19
+ /** `skippedFiles`/`unresolved`: absent means an adapter compiled against an older
20
+ * `@descryy/ir`, not malformed — a real adapter once crashed here on `.length` of
21
+ * undefined despite returning 1000+ good nodes. Absent ⇒ old producer; wrong type ⇒ broken, never defaulted away. */
22
+ export function optionalBatchLists(batch) {
23
+ const read = (value, field) => {
24
+ if (value === undefined || value === null)
25
+ return [];
26
+ if (!Array.isArray(value)) {
27
+ throw new TypeError(`${field} must be an array when present, got ${typeof value}`);
28
+ }
29
+ return value;
30
+ };
31
+ return {
32
+ skippedFiles: read(batch.skippedFiles, "skippedFiles"),
33
+ unresolved: read(batch.unresolved, "unresolved"),
34
+ };
35
+ }
36
+ /** Distinguishes "the adapter failed" from "Descry's own code broke handling its
37
+ * output" — before this, a `TypeError` thrown in this file was reported as the
38
+ * adapter failing, sending users to debug working code instead of reporting our bug. */
39
+ /**
40
+ * F2 (UAT phase 4 F3 / Part 13 §13.3.2): which build actually ran. A bare
41
+ * specifier can resolve to more than one installed copy with the same
42
+ * name — CJS resolution walks upward through `node_modules`, so a stray
43
+ * install above the repository silently wins over the intended one, and
44
+ * `producedBy` alone cannot tell them apart (it carries the module's own
45
+ * self-declared version, which can drift from what actually shipped).
46
+ * This is the disclosure that makes "why are my results different from
47
+ * yours" answerable instead of a debugging session.
48
+ */
49
+ export function sourceProvenanceNote(entry) {
50
+ const version = entry.packageVersion ?? "unknown version";
51
+ const location = entry.resolvedPath !== null
52
+ ? `resolved from ${entry.resolvedPath} (${entry.via === "repo" ? "the scanned repository" : "this server's own module closure"})`
53
+ : "resolved via this server's own module closure (the exact path could not be determined)";
54
+ // UAT phase 5 §1b: the winning path alone does not explain why a repo whose
55
+ // adapter should be repo-local keeps getting the server's own copy instead —
56
+ // naming the candidate that was found and rejected is what makes that
57
+ // answerable without a debugging session.
58
+ const rejected = entry.rejectedRepoCandidate === null ? "" : ` A repo-local candidate was rejected: ${entry.rejectedRepoCandidate}`;
59
+ return `${entry.source.id} — ${entry.spec.module}@${version}, ${location}.${rejected}`;
60
+ }
61
+ export function sourceFailureNote(sourceId, error, phase) {
62
+ const message = error instanceof Error ? error.message : String(error);
63
+ return phase === "emit"
64
+ ? `${sourceId} failed while reading this repository (${message}). ` +
65
+ "Everything it covers is not analysable."
66
+ : `Descry itself failed while processing ${sourceId}'s output (${message}). This is a ` +
67
+ "defect in Descry, not in that adapter and not in your code — the adapter returned " +
68
+ "successfully and its results were dropped for this run. Everything it covers is not " +
69
+ "analysable until this is fixed.";
70
+ }
71
+ const SCHEMA = {
72
+ type: "object",
73
+ properties: {
74
+ includeHistory: {
75
+ type: "boolean",
76
+ description: "Read git history for co-change coupling (CHANGES_WITH edges). Default true. " +
77
+ "Costs a few seconds on a large repository.",
78
+ },
79
+ maxCommits: {
80
+ type: "integer",
81
+ minimum: 1,
82
+ description: "Cap on commits read from history. Default 2000.",
83
+ },
84
+ reload: {
85
+ type: "boolean",
86
+ description: "Re-read .descry/config.json from disk before this run, rather than using the " +
87
+ "configuration this server started with. Configuration is otherwise read once per " +
88
+ "process — a plain edit to the file, including its \"sources\" list, does nothing until " +
89
+ "either the server restarts or a call passes this. Every trust check on the new " +
90
+ "specifiers (module-trust.ts) runs again as part of loading them, exactly as it would on " +
91
+ "a fresh start; this is not a way around that gate.",
92
+ },
93
+ },
94
+ additionalProperties: false,
95
+ };
96
+ /** §5.4's `refusals` field for this run only, not the graph's whole ledger
97
+ * (`refusal_fetch`'s job) — a fresh population per call, honestly scoped to what
98
+ * this run found. `undefined` on zero rows so `refusals` stays `null`, not an empty summary. */
99
+ async function hashFileContent(absolutePath) {
100
+ try {
101
+ return createHash("sha256").update(await readFile(absolutePath)).digest("hex");
102
+ }
103
+ catch {
104
+ // Deleted, unreadable, or otherwise gone — left absent so the caller's
105
+ // hash lookup mismatches the cached value and correctly reports "changed".
106
+ return null;
107
+ }
108
+ }
109
+ /** Gap 6 step 3: attempts whole-producer cache reuse for one `LanguageAdapter`
110
+ * source, so a repeat `analyze` run can skip `emit()` (and the re-parse inside
111
+ * it) entirely when nothing this producer read has changed. Every failure path
112
+ * here returns `{ reused: false }` rather than throwing — declining to reuse is
113
+ * always safe, and the caller's normal `emit()` path is the fallback. See
114
+ * `planIncrementalReuse`'s doc (`@descryy/core`) for why this is whole-producer,
115
+ * never per-file. */
116
+ export async function attemptIncrementalReuse(params) {
117
+ const cache = getCachedFiles(params.driver, params.producedBy, params.repo);
118
+ const cachedPaths = [...cache.files.keys()].filter((path) => path !== FILELESS_CACHE_KEY);
119
+ const cachedHashes = new Map(cachedPaths.map((path) => [path, cache.files.get(path).contentHash]));
120
+ const currentHashes = new Map();
121
+ for (const path of cachedPaths) {
122
+ const hash = await hashFileContent(join(params.repoPath, path));
123
+ if (hash !== null)
124
+ currentHashes.set(path, hash);
125
+ }
126
+ const decision = planIncrementalReuse({
127
+ cachedPaths,
128
+ repoPaths: params.repoFileListing,
129
+ currentHashes,
130
+ cachedHashes,
131
+ });
132
+ if (!decision.canReuse)
133
+ return { reused: false, reason: decision.reason };
134
+ const nodes = [];
135
+ const edges = [];
136
+ const unresolved = [];
137
+ for (const entry of cache.files.values()) {
138
+ nodes.push(...entry.nodes);
139
+ edges.push(...entry.edges);
140
+ unresolved.push(...entry.unresolved);
141
+ }
142
+ const batch = {
143
+ repo: params.repo,
144
+ ...(params.workspace === undefined ? {} : { workspace: params.workspace }),
145
+ commitSha: params.commitSha,
146
+ producedBy: params.producedBy,
147
+ sourceFiles: cachedPaths,
148
+ skippedFiles: cache.skippedFiles,
149
+ reachedResolution: (cache.reachedResolution ?? 0),
150
+ nodes,
151
+ edges,
152
+ unresolved,
153
+ };
154
+ return { reused: true, batch };
155
+ }
156
+ export function refusalSummaryField(unresolved) {
157
+ const summary = summariseRefusals(unresolved);
158
+ if (summary.count === 0 || summary.exemplar === null || summary.handle === null)
159
+ return undefined;
160
+ return { count: summary.count, exemplar: summary.exemplar, handle: summary.handle };
161
+ }
162
+ /** Single-repo half of the joins disclosure. In the ordinary case — one repo in scope —
163
+ * every join metric's `suppliedByTwoOrMoreRepos: 0` looks like `NO_CROSS_REPO_JOIN`'s
164
+ * failure case; this states outright it's just scope, not a failed join. */
165
+ export function crossRepoJoinNote(joins) {
166
+ const singleRepo = joins.filter((j) => !j.crossRepoJoinPossible);
167
+ if (singleRepo.length === 0)
168
+ return undefined;
169
+ return (`${singleRepo.length} of ${joins.length} join metric(s) — ` +
170
+ `${singleRepo.map((j) => j.type).join(", ")} — reflect one repository in this build's scope. ` +
171
+ "A cross-repo join is not possible here, so 0 is the only value suppliedByTwoOrMoreRepos could " +
172
+ "take for them; this is not the NO_CROSS_REPO_JOIN warning, which is for two or more " +
173
+ "repositories that failed to join.");
174
+ }
175
+ /** Turns one adapter's `DetectionResult.evidence` into the same kind of disclosed note the
176
+ * `skippedFiles` rollup below builds — grouped by `reason` where an entry is a
177
+ * `StructuredSkipEntry`, left under an "other" bucket, verbatim, where it is still the
178
+ * legacy plain-string shape (`isStructuredSkipEntry`, `@descryy/ir`). `null` on an empty
179
+ * list — nothing to disclose, not a note saying so. */
180
+ export function summariseDetectionEvidence(evidence) {
181
+ if (evidence.entries.length === 0)
182
+ return null;
183
+ const byReason = new Map();
184
+ const legacy = [];
185
+ for (const entry of evidence.entries) {
186
+ if (isStructuredSkipEntry(entry)) {
187
+ byReason.set(entry.reason, (byReason.get(entry.reason) ?? 0) + 1);
188
+ }
189
+ else {
190
+ legacy.push(entry);
191
+ }
192
+ }
193
+ const parts = [...byReason.entries()].map(([reason, count]) => `${count} ${reason}`);
194
+ if (legacy.length > 0)
195
+ parts.push(`${legacy.length} other (${legacy.join("; ")})`);
196
+ return (`${evidence.source} reported ${evidence.entries.length} detection note(s) for this ` +
197
+ `repository (${parts.join(", ")}).`);
198
+ }
199
+ async function run(args, ctx) {
200
+ const { session } = ctx;
201
+ const includeHistory = args["includeHistory"] !== false;
202
+ const maxCommits = args["maxCommits"];
203
+ if (maxCommits !== undefined && (typeof maxCommits !== "number" || !Number.isInteger(maxCommits) || maxCommits < 1)) {
204
+ throw new ToolInputError('"maxCommits" must be a positive integer');
205
+ }
206
+ const notes = [];
207
+ // §0 gap 2 (UAT phase 5): configuration is otherwise read once per process.
208
+ // Explicit and caller-initiated, never a file watcher — see `reloadConfig`'s
209
+ // own doc for why. Before `session.root()`, so a changed "repo"/"workspace"
210
+ // is reflected in this very run rather than the one after.
211
+ if (optionalBoolean(args, "reload") === true) {
212
+ const { changed } = await session.reloadConfig();
213
+ notes.push(changed.length > 0
214
+ ? `Reloaded .descry/config.json from disk before this run (changed: ${changed.join(", ")}).`
215
+ : "Reloaded .descry/config.json from disk before this run — nothing had actually changed.");
216
+ }
217
+ const root = await session.root();
218
+ // MK-4: analyze rebuilds from source regardless, so a stale IR schema is repaired
219
+ // here rather than refused — see `Session.repairStaleGraph` for why only this tool does this.
220
+ const { rebuilt } = session.repairStaleGraph();
221
+ if (rebuilt) {
222
+ notes.push("The stored graph was written under an older IR schema version. Its derived tables were " +
223
+ "dropped and are rebuilt by this run; earned data (R4 observations, edge corrections, " +
224
+ "incident links) was not affected.");
225
+ }
226
+ // Config drift is now checked centrally in server.ts for every tool (13.3.16 /
227
+ // N2 steps 2-3), not just this one — see `checkConfigDrift` in session.ts.
228
+ if (session.config.configPath === null) {
229
+ notes.push(`No ${".descry/config.json"} was found, so the repository identity defaults to the ` +
230
+ `directory name ("${session.config.repo}"). Every repo-scoped node id is a hash over that ` +
231
+ "string: cloning into a differently-named folder produces a different graph, and incident " +
232
+ "links and co-change weights do not survive the change. Set \"repo\" explicitly.");
233
+ }
234
+ if (session.config.workspace === undefined) {
235
+ notes.push("No workspace is configured, so this repository is its own contract boundary. Endpoints, " +
236
+ "tables and incidents will not join with any other repository's (DEC-054). If there is a " +
237
+ 'sibling repository this one should join — a frontend to this backend, for example — ask ' +
238
+ 'whether they should share a workspace, and call "link_workspace" once confirmed. Never ' +
239
+ "call it on a guess: a directory sitting next to another is a suggestion, not evidence.");
240
+ }
241
+ // --- sources -------------------------------------------------------------
242
+ const registry = await loadSources(session.config.sources, session.repoPath);
243
+ for (const failure of registry.failed) {
244
+ notes.push(`The source "${failure.spec.module}" could not be loaded (${failure.reason}). Anything it ` +
245
+ "would have read is not analysable — not clean.");
246
+ }
247
+ for (const entry of registry.loaded) {
248
+ notes.push(sourceProvenanceNote(entry));
249
+ }
250
+ if (session.config.sources.length === 0) {
251
+ notes.push(
252
+ // No example package name here — naming one would leak a specific language into
253
+ // this engine, the inversion `registry.ts` exists to prevent (rule 1: IR boundary).
254
+ "No language adapters are configured, so nothing was read from source. Add a \"sources\" " +
255
+ `array to ${".descry/config.json"} listing the adapter packages to load, as module ` +
256
+ "specifiers. This engine does not know the name of any adapter: the IR boundary is a " +
257
+ "dependency direction, so the list has to come from configuration.");
258
+ }
259
+ const { applicable, skipped, evidence } = await detectSources(registry.loaded, root);
260
+ for (const entry of skipped) {
261
+ notes.push(`${entry.source.source.id} did not run: it ${entry.reason}. Any code only that adapter ` +
262
+ "could read is not analysable.");
263
+ }
264
+ for (const item of evidence) {
265
+ const note = summariseDetectionEvidence(item);
266
+ if (note !== null)
267
+ notes.push(note);
268
+ }
269
+ // --- emit ----------------------------------------------------------------
270
+ const context = {
271
+ root,
272
+ prepareTimeoutMs: 300_000,
273
+ signal: ctx.signal,
274
+ };
275
+ const batches = [];
276
+ const perSource = [];
277
+ /** Resolution floor comes from code-reading sources only — git history is always R0
278
+ * by nature, not degradation; folding it in would cap every reply at class C. DEC-058:
279
+ * an edge carries its own evidence's resolution, not the run's; each source still reported individually. */
280
+ const codeResolutions = [];
281
+ const total = applicable.length + (includeHistory ? 1 : 0);
282
+ let done = 0;
283
+ const driver = session.store().driver;
284
+ // Computed once for the whole run, not per source: every `LanguageAdapter`
285
+ // source's Gap 6 reuse check needs the same "what does the working tree have
286
+ // right now" answer, and it is meaningless to ask git for it twice. `null`
287
+ // when it cannot be determined at all (no git, or git unavailable) — every
288
+ // incremental check below then conservatively declines to reuse anything.
289
+ const repoFileListing = await listWorkingTreeFiles(session.repoPath).catch(() => null);
290
+ /**
291
+ * P6-B1. The fence, at the two points where this tool's memory actually
292
+ * peaks: before an adapter is asked to read the repository (its batch is
293
+ * retained for the whole run), and before the merge, which holds every
294
+ * batch and the built graph live at once. A V8 heap abort cannot be caught
295
+ * — this is the only place the failure can be turned into a reply.
296
+ *
297
+ * `sourcesRead` reports what had already emitted, because those batches are
298
+ * discarded unwritten: without it the reply would be silent about work that
299
+ * did happen and produced nothing.
300
+ */
301
+ const halted = (phase) => {
302
+ const reading = readHeap();
303
+ const note = heapGuard(reading, phase);
304
+ if (note === null)
305
+ return null;
306
+ const base = session.provider().baseStamp();
307
+ return answer({
308
+ headline: `Analysis of ${session.config.repo} stopped at the heap ceiling before "${phase}". ` +
309
+ "Nothing was written to the graph.",
310
+ state: "failed",
311
+ nameLevel: true,
312
+ resolutionFloor: 0,
313
+ commitSha: root.commitSha,
314
+ graphBuiltAt: base.graphBuiltAt,
315
+ irSchemaVersion: base.irSchemaVersion,
316
+ commitSpread: base.commitSpread,
317
+ repoCount: base.repoCount,
318
+ notes: [...notes, note],
319
+ data: {
320
+ halted: "heap",
321
+ phase,
322
+ heapUsedMib: Math.round(reading.usedBytes / (1024 * 1024)),
323
+ heapLimitMib: Math.round(reading.limitBytes / (1024 * 1024)),
324
+ sourcesRead: perSource,
325
+ },
326
+ });
327
+ };
328
+ for (const entry of applicable) {
329
+ const fence = halted(`Reading ${entry.source.id}`);
330
+ if (fence !== null)
331
+ return fence;
332
+ ctx.progress(`Reading ${entry.source.id}`, done, total);
333
+ const started = Date.now();
334
+ // Gap 6: only `LanguageAdapter` sources pay the re-parse cost this exists
335
+ // to avoid — the git-history/confirmed-incidents/mint sources below are
336
+ // already cheap and deterministic and are out of scope for this cache.
337
+ if (entry.adapter !== null) {
338
+ const expectedProducedBy = `${entry.source.id}@${entry.source.version}`;
339
+ const reuse = await attemptIncrementalReuse({
340
+ driver,
341
+ producedBy: expectedProducedBy,
342
+ repo: session.config.repo,
343
+ repoPath: session.repoPath,
344
+ repoFileListing,
345
+ commitSha: root.commitSha,
346
+ workspace: session.config.workspace,
347
+ });
348
+ if (reuse.reused) {
349
+ const batch = reuse.batch;
350
+ batches.push(batch);
351
+ perSource.push({
352
+ source: batch.producedBy,
353
+ installedVersion: entry.packageVersion,
354
+ files: batch.sourceFiles.length,
355
+ nodes: batch.nodes.length,
356
+ edges: batch.edges.length,
357
+ unresolved: batch.unresolved.length,
358
+ skippedFiles: batch.skippedFiles.length,
359
+ reachedResolution: batch.reachedResolution,
360
+ ms: 0,
361
+ });
362
+ const ceiling = entry.adapter.capabilities().maxResolution;
363
+ codeResolutions.push(batch.reachedResolution);
364
+ notes.push(`${entry.source.id}: reused ${String(batch.sourceFiles.length)} cached file(s) from the ` +
365
+ "previous run, unchanged since — not re-parsed this run (Gap 6 incremental indexing). " +
366
+ "Cross-file effects (a change in one file altering another file's resolved edges) are " +
367
+ "not re-checked by this cache; see documents/plans/site-claims-closure-production-plan.md Gap 6.");
368
+ if (batch.reachedResolution < ceiling) {
369
+ notes.push(`${entry.source.id} reached R${String(batch.reachedResolution)} where it is capable of ` +
370
+ `R${String(ceiling)} (cached from its last real run). Findings resting on its edges are ` +
371
+ "capped accordingly, and shape-level checks (contract matching, field propagation) need R3.");
372
+ }
373
+ done += 1;
374
+ continue;
375
+ }
376
+ }
377
+ // Adapter's own work and Descry's handling of its output are separate phases with
378
+ // separate blame — folding them into one `try` let a `TypeError` here be blamed on the adapter.
379
+ let batch;
380
+ try {
381
+ // P6-B2. An adapter reading a large repository can hold this await for
382
+ // minutes, and until now that was the whole gap between two progress
383
+ // frames — long enough for the client's timeout to fire on a run that
384
+ // was working. The beat keeps the request visibly alive; it does not
385
+ // claim to know how far through the adapter is, because this side
386
+ // cannot see that and will not invent it.
387
+ batch = await withHeartbeat(`Reading ${entry.source.id}`, (message) => ctx.progress(message, done, total), () => entry.source.emit(context));
388
+ }
389
+ catch (error) {
390
+ notes.push(sourceFailureNote(entry.source.id, error, "emit"));
391
+ await entry.adapter?.dispose();
392
+ done += 1;
393
+ continue;
394
+ }
395
+ try {
396
+ const { skippedFiles, unresolved } = optionalBatchLists(batch);
397
+ batches.push(batch);
398
+ perSource.push({
399
+ source: batch.producedBy,
400
+ installedVersion: entry.packageVersion,
401
+ files: batch.sourceFiles.length,
402
+ nodes: batch.nodes.length,
403
+ edges: batch.edges.length,
404
+ unresolved: unresolved.length,
405
+ skippedFiles: skippedFiles.length,
406
+ reachedResolution: batch.reachedResolution,
407
+ ms: Date.now() - started,
408
+ });
409
+ // Gap 6 step 3: this was a real parse (reuse would have `continue`d above),
410
+ // so refresh the per-file cache from its output — the only place the
411
+ // cache is ever written. A producer whose declared `id@version` drifted
412
+ // from its self-declared `producedBy` (see `sourceProvenanceNote`) simply
413
+ // caches under the real `producedBy`; the next run's reuse check looks
414
+ // for `${id}@${version}` and will not find a mismatched entry, which is
415
+ // the safe direction for this to fail (always falls back to full reparse).
416
+ try {
417
+ const partitioned = partitionBatchByFile(batch);
418
+ const cacheEntries = [];
419
+ for (const [filePath, contribution] of partitioned) {
420
+ const contentHash = filePath === FILELESS_CACHE_KEY
421
+ ? "fileless"
422
+ : (await hashFileContent(join(session.repoPath, filePath))) ?? "unreadable";
423
+ cacheEntries.push({ filePath, contentHash, ...contribution });
424
+ }
425
+ replaceCachedFiles(driver, batch.producedBy, session.config.repo, cacheEntries, batch.reachedResolution, skippedFiles, Date.now());
426
+ }
427
+ catch {
428
+ // Caching is an optimisation, never a correctness requirement — a
429
+ // failure here must not fail the run or lose the batch already pushed
430
+ // above. Worst case: the next run finds no cache and reparses fully.
431
+ }
432
+ // Declared ceiling vs what this run reached — a gap is honest degradation (rule 7):
433
+ // the adapter can do better but something in this repo stopped it.
434
+ const ceiling = entry.adapter?.capabilities().maxResolution;
435
+ if (ceiling !== undefined)
436
+ codeResolutions.push(batch.reachedResolution);
437
+ if (ceiling !== undefined && batch.reachedResolution < ceiling) {
438
+ notes.push(`${entry.source.id} reached R${batch.reachedResolution} where it is capable of ` +
439
+ `R${ceiling}. Findings resting on its edges are capped accordingly, and shape-level ` +
440
+ "checks (contract matching, field propagation) need R3.");
441
+ }
442
+ if (skippedFiles.length > 0) {
443
+ const byReason = new Map();
444
+ for (const skipped of skippedFiles) {
445
+ byReason.set(skipped.reason, (byReason.get(skipped.reason) ?? 0) + 1);
446
+ }
447
+ const summary = [...byReason.entries()].map(([reason, count]) => `${count} ${reason}`).join(", ");
448
+ notes.push(`${entry.source.id} could not analyse ${skippedFiles.length} file(s) it attempted ` +
449
+ `(${summary}). Not analysable — absent from the graph, not confirmed clean.`);
450
+ }
451
+ }
452
+ catch (error) {
453
+ // Reached only when Descry's own handling threw — the adapter already returned successfully.
454
+ notes.push(sourceFailureNote(entry.source.id, error, "engine"));
455
+ }
456
+ finally {
457
+ // `dispose` is a `LanguageAdapter` obligation, not `IRSource`'s — a leaked language
458
+ // server costs hundreds of MB per repo. Sources with none to release (git reader) need no method.
459
+ await entry.adapter?.dispose();
460
+ done += 1;
461
+ }
462
+ }
463
+ if (includeHistory) {
464
+ ctx.progress("Reading git history", done, total);
465
+ const historyStarted = Date.now();
466
+ try {
467
+ // P6-B2, same reason as the adapter read above: `maxCommits` defaults to
468
+ // 2000, and walking that much history on a large repository is its own
469
+ // multi-minute silence.
470
+ const history = await withHeartbeat("Reading git history", (message) => ctx.progress(message, done, total), () => createGitSource({
471
+ repo: root.repo,
472
+ cwd: session.repoPath,
473
+ ...(typeof maxCommits === "number" ? { maxCommits } : {}),
474
+ }).emit(context));
475
+ batches.push(history);
476
+ perSource.push({
477
+ source: history.producedBy,
478
+ // Built into this engine, not a loaded adapter module — there is no separate
479
+ // "installed artifact" to disagree with its own self-declared version.
480
+ installedVersion: null,
481
+ files: history.sourceFiles.length,
482
+ nodes: history.nodes.length,
483
+ edges: history.edges.length,
484
+ unresolved: history.unresolved.length,
485
+ skippedFiles: history.skippedFiles.length,
486
+ reachedResolution: history.reachedResolution,
487
+ ms: Date.now() - historyStarted,
488
+ });
489
+ }
490
+ catch (error) {
491
+ notes.push(`Git history was not read (${error.message}), so co-change coupling is absent ` +
492
+ "and blast radii will not include historically coupled files.");
493
+ }
494
+ done += 1;
495
+ }
496
+ else {
497
+ notes.push("Git history was skipped by request, so no CHANGES_WITH edges were produced and the blast " +
498
+ "radius will miss files that historically change together.");
499
+ }
500
+ // Developer-confirmed incidents, re-projected every analyze run. The record lives in
501
+ // `.descry/config.json` (testimony, DEC-223) — the graph only holds a derived projection,
502
+ // dropped on every schema bump, so re-emitting here is what keeps a rebuild from losing it.
503
+ const confirmedIncidents = session.config.confirmedIncidents ?? [];
504
+ if (confirmedIncidents.length > 0) {
505
+ const projected = await createConfirmedIncidentSource({
506
+ repo: root.repo,
507
+ incidents: confirmedIncidents,
508
+ }).emit(context);
509
+ batches.push(projected);
510
+ perSource.push({
511
+ source: projected.producedBy,
512
+ // Same reasoning as the git-history source above: this is a re-projection of
513
+ // testimony already in .descry/config.json, not a loaded adapter module.
514
+ installedVersion: null,
515
+ files: projected.sourceFiles.length,
516
+ nodes: projected.nodes.length,
517
+ edges: projected.edges.length,
518
+ unresolved: projected.unresolved.length,
519
+ skippedFiles: 0,
520
+ reachedResolution: projected.reachedResolution,
521
+ ms: 0,
522
+ });
523
+ notes.push(`${confirmedIncidents.length} developer-confirmed incident(s) were re-projected into the ` +
524
+ "graph from .descry/config.json. They are testimony, not a reading of this repository — " +
525
+ "an edge resting on one is capped at reliability class B (DEC-223).");
526
+ }
527
+ // --- build and store -----------------------------------------------------
528
+ // The real peak: every batch is live here and `buildGraph` allocates the
529
+ // merged graph beside them. This is the checkpoint the field report needed.
530
+ const mergeFence = halted("Merging into the graph");
531
+ if (mergeFence !== null)
532
+ return mergeFence;
533
+ ctx.progress("Merging into the graph", done, total);
534
+ const built = buildGraph(batches, {
535
+ nodeExists: (id) => session.provider().node(id) !== undefined,
536
+ });
537
+ const persisted = persistGraph(session.store().driver, batches, built);
538
+ // confirmed-incidents' output is a small, fully-specified list re-derived from
539
+ // config every run — a deleted incident whose files aren't referenced by any
540
+ // surviving incident shares no file with the prior run, so the eviction above
541
+ // (file-overlap keyed) never retires its INCIDENT/FIX_PATTERN nodes. This
542
+ // fires unconditionally, even when `confirmedIncidents` is now empty and no
543
+ // `projected` batch was built this run — that emptiness IS the current node
544
+ // set to evict everything else against.
545
+ const confirmedIncidentsProducedBy = `${CONFIRMED_INCIDENT_SOURCE_ID}@${CONFIRMED_INCIDENT_SOURCE_VERSION}`;
546
+ evictStaleConfirmedIncidentNodes(session.store().driver, confirmedIncidentsProducedBy, new Set(built.nodes.filter((n) => n.producedBy === confirmedIncidentsProducedBy).map((n) => n.id)));
547
+ for (const collision of built.collisions) {
548
+ notes.push(`Two different things claimed node id ${collision.nodeId}: a ${collision.kept.type} from ` +
549
+ `${collision.kept.producedBy} and a ${collision.discarded.type} from ` +
550
+ `${collision.discarded.producedBy}. They are not the same symbol and there is no correct ` +
551
+ "merge, so the second was discarded (DEC-024).");
552
+ }
553
+ if (built.droppedEdges > 0) {
554
+ notes.push(`${built.droppedEdges} edge(s) were dropped because an endpoint did not resolve to a real ` +
555
+ "node. They are never stubbed into existence — a name-matched guess belongs in the " +
556
+ "unresolved-reference ledger, not in the graph.");
557
+ }
558
+ if (built.rejections.length > 0) {
559
+ notes.push(`${built.rejections.length} item(s) were turned away at the IR boundary as malformed. They ` +
560
+ "are not in the graph and nothing above will see them.");
561
+ }
562
+ if (persisted.evictedFiles.length > 0) {
563
+ notes.push(`${persisted.evictedFiles.length} file(s) covered by a previous run were not re-supplied by ` +
564
+ "this one; their rows have been removed. A query about them will now find nothing because " +
565
+ "nothing is stored, not because there is nothing there.");
566
+ }
567
+ for (const warning of built.warnings)
568
+ notes.push(warning.detail);
569
+ const joinNote = crossRepoJoinNote(built.crossRepoJoins);
570
+ if (joinNote !== undefined)
571
+ notes.push(joinNote);
572
+ if (built.unresolved.length > 0) {
573
+ notes.push(`${built.unresolved.length} reference(s) could not be resolved to a target and are recorded ` +
574
+ "in the ledger rather than guessed at. They are the measured recall gap, not an error.");
575
+ }
576
+ // --- mint edges from confirmed facts --------------------------------------
577
+ //
578
+ // DEC-223/DEC-138 minting, sequenced after the graph is persisted: a confirmed answer
579
+ // joins against a stored `API_ENDPOINT` row via the SQL-backed `EndpointLookup`, not
580
+ // `built`'s in-memory result, so the row must already exist for the lookup to find it.
581
+ ctx.progress("Minting edges from confirmed facts", done, total);
582
+ const provider = session.provider();
583
+ const { refs: ledgerRefs } = provider.unresolvedRefs();
584
+ const { answered } = applyConfirmedFacts(ledgerRefs, session.config.confirmedFacts, session.config.repo);
585
+ const scope = {
586
+ repo: session.config.repo,
587
+ ...(session.config.workspace === undefined ? {} : { workspace: session.config.workspace }),
588
+ };
589
+ const mintResult = mintEdgesFromConfirmedFacts(answered, provider, scope, MINT_PRODUCED_BY, root.commitSha);
590
+ // Invalidation key (DEC-015: producedBy+sourceFiles), scoped to every *askable* file this
591
+ // run, not just answered ones — else a file dropping its one answer would vanish from
592
+ // sourceFiles and its stale edge could never be found by the writer's self-clean pass to retire.
593
+ const mintFiles = [
594
+ ...new Set(ledgerRefs.flatMap((ref) => ref.attrs?.["refusalClass"] === "value-unknown" && typeof ref.file === "string" ? [ref.file] : [])),
595
+ ].sort();
596
+ const mintBatch = {
597
+ repo: session.config.repo,
598
+ ...(session.config.workspace === undefined ? {} : { workspace: session.config.workspace }),
599
+ commitSha: root.commitSha,
600
+ producedBy: MINT_PRODUCED_BY,
601
+ sourceFiles: mintFiles,
602
+ skippedFiles: [],
603
+ reachedResolution: 2,
604
+ nodes: [],
605
+ edges: mintResult.minted.map((m) => m.edge),
606
+ unresolved: [],
607
+ };
608
+ const mintBuilt = buildGraph([mintBatch], {
609
+ nodeExists: (id) => provider.node(id) !== undefined,
610
+ });
611
+ const mintPersisted = persistGraph(session.store().driver, [mintBatch], mintBuilt);
612
+ const stored = counts(session.store().driver);
613
+ if (mintResult.minted.length > 0) {
614
+ notes.push(`${mintResult.minted.length} human-confirmed answer(s) minted a USES_API edge this run. Every ` +
615
+ "one is capped at reliability class B regardless of the resolution it would otherwise earn " +
616
+ "(DEC-223) — a confirmed value is testimony, not a structural read.");
617
+ const stale = mintResult.minted.filter((m) => m.edge.attrs?.["staleFact"] === true).length;
618
+ if (stale > 0) {
619
+ notes.push(`${stale} of those edge(s) rest on an answer not affirmatively current for this commit — either ` +
620
+ "given against a different commit, or given before this system recorded which commit an answer " +
621
+ "was confirmed against. Not re-verified against live code (there is no live re-verification " +
622
+ "mechanism yet); disclosed on the edge's attrs.confirmedFacts[].staleness so a consumer can see " +
623
+ "it rather than treat an old answer as unconditionally current.");
624
+ }
625
+ }
626
+ if (mintResult.orphaned.length > 0) {
627
+ notes.push(`${mintResult.orphaned.length} confirmed answer(s) named a path/method that matches no known ` +
628
+ "endpoint, so no edge was minted for them — never guessed into existence: " +
629
+ mintResult.orphaned.map((o) => `${o.method} ${o.path}`).join(", ") +
630
+ ".");
631
+ }
632
+ if (mintResult.unjoinable.length > 0) {
633
+ notes.push(`${mintResult.unjoinable.length} confirmed answer(s) apply to a row with no resolved ` +
634
+ "path/method to join against at all, so no edge was minted for those either.");
635
+ }
636
+ if (mintPersisted.evictedFiles.length > 0) {
637
+ notes.push(`${mintPersisted.evictedFiles.length} file(s) that previously grounded a minted edge were not ` +
638
+ "in this run's askable set (their confirmed answer was removed, or the row it answered " +
639
+ "changed) — the edges they previously grounded have been retired, not left to coexist with " +
640
+ "whatever this run minted instead.");
641
+ }
642
+ // No code-reading source ran — R0, not a cheerful default.
643
+ const floor = (codeResolutions.length === 0
644
+ ? 0
645
+ : Math.min(...codeResolutions));
646
+ if (codeResolutions.length > 1 && new Set(codeResolutions).size > 1) {
647
+ notes.push(`Sources reached different resolution levels (R${Math.min(...codeResolutions)}-` +
648
+ `R${Math.max(...codeResolutions)}). The floor quoted here is the lowest of them, but an ` +
649
+ "individual answer computes its own from the edges it actually traversed, so a query " +
650
+ "confined to well-resolved code is not capped by the weakest source in the graph.");
651
+ }
652
+ // Report what THIS run wrote, never the store's whole cumulative total as if it
653
+ // were this call's own output — `stored` is every row the store holds across every
654
+ // past run (and, in a shared workspace, possibly other repos too), so a repo
655
+ // re-analysed many times would otherwise headline a number this call never touched.
656
+ // The cumulative total is still a genuinely useful fact, so it stays in the headline
657
+ // as a second, clearly-labelled clause rather than being dropped (rule 7).
658
+ const headline = batches.length === 0
659
+ ? `Nothing was read from ${session.config.repo}.`
660
+ : `Analysed ${session.config.repo} at ${root.commitSha.slice(0, 12)}: wrote ` +
661
+ `${persisted.nodesWritten} nodes, ${persisted.edgesWritten} edges, ` +
662
+ `${persisted.unresolvedWritten} disclosed gaps this run across ${batches.length} source(s); ` +
663
+ `the graph now holds ${stored.nodes} nodes, ${stored.edges} edges, ` +
664
+ `${stored.unresolvedRefs} disclosed gaps total.`;
665
+ const refusalSummary = refusalSummaryField(built.unresolved);
666
+ return answer({
667
+ headline,
668
+ state: batches.length === 0 ? "refused" : "ok",
669
+ nameLevel: true,
670
+ resolutionFloor: floor,
671
+ commitSha: root.commitSha,
672
+ graphBuiltAt: Date.now(),
673
+ irSchemaVersion: session.provider().baseStamp().irSchemaVersion,
674
+ commitSpread: session.provider().baseStamp().commitSpread,
675
+ repoCount: session.provider().baseStamp().repoCount,
676
+ notes,
677
+ ...(refusalSummary === undefined ? {} : { refusalSummary }),
678
+ data: {
679
+ repo: session.config.repo,
680
+ workspace: session.config.workspace ?? null,
681
+ commitSha: root.commitSha,
682
+ graphPath: session.graphPath,
683
+ sources: perSource,
684
+ sourcesFailed: registry.failed.map((f) => ({ module: f.spec.module, reason: f.reason })),
685
+ sourcesSkipped: skipped.map((s) => ({ source: s.source.source.id, reason: s.reason })),
686
+ stored,
687
+ merge: {
688
+ mergedNodes: built.mergedNodes,
689
+ mergedEdges: built.mergedEdges,
690
+ collisions: built.collisions.length,
691
+ droppedEdges: built.droppedEdges,
692
+ rejections: built.rejections.length,
693
+ },
694
+ crossRepoJoins: built.crossRepoJoins,
695
+ written: {
696
+ nodes: persisted.nodesWritten,
697
+ edges: persisted.edgesWritten,
698
+ unresolved: persisted.unresolvedWritten,
699
+ orphanedEdges: persisted.orphanedEdges,
700
+ evictedFiles: persisted.evictedFiles.length,
701
+ },
702
+ minted: {
703
+ edges: mintResult.minted.length,
704
+ orphaned: mintResult.orphaned.length,
705
+ unjoinable: mintResult.unjoinable.length,
706
+ evictedFiles: mintPersisted.evictedFiles.length,
707
+ },
708
+ },
709
+ });
710
+ }
711
+ export const analyzeTool = {
712
+ name: "analyze",
713
+ class: "stateful-read",
714
+ tier: "evidence",
715
+ version: "1.0.0",
716
+ title: "Analyse a repository into the code graph",
717
+ description: "Read the repository with every configured adapter and store the result as a code graph. " +
718
+ "Run this before any other Descry tool, and again after the working tree changes. Reports " +
719
+ "what it read, what it could not read, and the resolution level each adapter reached — the " +
720
+ "last one caps how strongly anything built on this graph may be stated.",
721
+ inputSchema: SCHEMA,
722
+ run,
723
+ };
724
+ //# sourceMappingURL=analyze.js.map