@duckmind/dm-darwin-x64 0.66.5 → 0.66.6

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 (1115) hide show
  1. package/README.md +4 -0
  2. package/dm +2 -2
  3. package/extensions/.dm-extensions.json +755 -37
  4. package/extensions/dm-lens/clients/actionable-warnings.js +63 -11
  5. package/extensions/dm-lens/clients/advisory-provenance.js +5 -3
  6. package/extensions/dm-lens/clients/agent-nudge.js +106 -2
  7. package/extensions/dm-lens/clients/analysis-root.js +103 -0
  8. package/extensions/dm-lens/clients/ast-grep-client.js +18 -7
  9. package/extensions/dm-lens/clients/ast-grep-rule-manager.js +35 -12
  10. package/extensions/dm-lens/clients/biome-client.js +18 -12
  11. package/extensions/dm-lens/clients/blocker-freshness.js +1 -9
  12. package/extensions/dm-lens/clients/bounded-pid-file-lock.js +141 -30
  13. package/extensions/dm-lens/clients/bounded-telemetry.js +3 -0
  14. package/extensions/dm-lens/clients/cache/rule-cache.js +2 -17
  15. package/extensions/dm-lens/clients/cache-manager.js +105 -17
  16. package/extensions/dm-lens/clients/cargo-manifest.js +23 -3
  17. package/extensions/dm-lens/clients/complexity-client.js +1 -1
  18. package/extensions/dm-lens/clients/config-core/normalize.js +9 -0
  19. package/extensions/dm-lens/clients/config-core/schema.js +3 -0
  20. package/extensions/dm-lens/clients/config-schema.js +105 -2
  21. package/extensions/dm-lens/clients/confirmed-delete.js +11 -0
  22. package/extensions/dm-lens/clients/custom-rule-locations.js +28 -0
  23. package/extensions/dm-lens/clients/dead-code-client.js +81 -12
  24. package/extensions/dm-lens/clients/deferred-runner-blockers.js +108 -0
  25. package/extensions/dm-lens/clients/deferred-test-targets.js +31 -0
  26. package/extensions/dm-lens/clients/degradation-ledger.js +21 -3
  27. package/extensions/dm-lens/clients/demoted-finding-render.js +5 -2
  28. package/extensions/dm-lens/clients/dependency-checker.js +13 -4
  29. package/extensions/dm-lens/clients/diagnostic-line-freshness.js +3 -5
  30. package/extensions/dm-lens/clients/dispatch/adopted-root-runners.js +22 -0
  31. package/extensions/dm-lens/clients/dispatch/dispatcher.js +105 -27
  32. package/extensions/dm-lens/clients/dispatch/facts/comment-facts.js +5 -2
  33. package/extensions/dm-lens/clients/dispatch/facts/function-facts.js +1 -1
  34. package/extensions/dm-lens/clients/dispatch/facts/import-facts.js +2 -2
  35. package/extensions/dm-lens/clients/dispatch/facts/tree-sitter-facts.js +2 -2
  36. package/extensions/dm-lens/clients/dispatch/facts/try-catch-facts.js +1 -1
  37. package/extensions/dm-lens/clients/dispatch/finding-policy.js +12 -4
  38. package/extensions/dm-lens/clients/dispatch/integration.js +60 -15
  39. package/extensions/dm-lens/clients/dispatch/known-runner-ids.js +13 -0
  40. package/extensions/dm-lens/clients/dispatch/pending-runner-findings.js +66 -11
  41. package/extensions/dm-lens/clients/dispatch/plan.js +6 -0
  42. package/extensions/dm-lens/clients/dispatch/rule-id-normalize.js +9 -2
  43. package/extensions/dm-lens/clients/dispatch/rule-policy.js +33 -4
  44. package/extensions/dm-lens/clients/dispatch/runners/ast-grep-napi.js +9 -5
  45. package/extensions/dm-lens/clients/dispatch/runners/biome-check.js +5 -2
  46. package/extensions/dm-lens/clients/dispatch/runners/cue-vet.js +7 -3
  47. package/extensions/dm-lens/clients/dispatch/runners/detekt.js +3 -3
  48. package/extensions/dm-lens/clients/dispatch/runners/fact-rules.js +3 -3
  49. package/extensions/dm-lens/clients/dispatch/runners/fish-indent.js +10 -6
  50. package/extensions/dm-lens/clients/dispatch/runners/gleam-check.js +8 -5
  51. package/extensions/dm-lens/clients/dispatch/runners/go-vet.js +2 -1
  52. package/extensions/dm-lens/clients/dispatch/runners/lsp.js +28 -8
  53. package/extensions/dm-lens/clients/dispatch/runners/oxlint.js +2 -2
  54. package/extensions/dm-lens/clients/dispatch/runners/php-lint.js +6 -7
  55. package/extensions/dm-lens/clients/dispatch/runners/prisma-validate.js +18 -8
  56. package/extensions/dm-lens/clients/dispatch/runners/psscriptanalyzer.js +3 -3
  57. package/extensions/dm-lens/clients/dispatch/runners/pyright.js +1 -1
  58. package/extensions/dm-lens/clients/dispatch/runners/rust-clippy.js +25 -6
  59. package/extensions/dm-lens/clients/dispatch/runners/shellcheck.js +71 -4
  60. package/extensions/dm-lens/clients/dispatch/runners/shfmt.js +5 -1
  61. package/extensions/dm-lens/clients/dispatch/runners/spellcheck.js +3 -3
  62. package/extensions/dm-lens/clients/dispatch/runners/swiftlint.js +3 -3
  63. package/extensions/dm-lens/clients/dispatch/runners/taplo.js +17 -5
  64. package/extensions/dm-lens/clients/dispatch/runners/tree-sitter.js +12 -5
  65. package/extensions/dm-lens/clients/dispatch/runners/trivy-config.js +3 -3
  66. package/extensions/dm-lens/clients/dispatch/runners/utils/runner-helpers.js +127 -46
  67. package/extensions/dm-lens/clients/dispatch/runners/utils/tool-failure.js +11 -6
  68. package/extensions/dm-lens/clients/dispatch/runners/vale.js +3 -3
  69. package/extensions/dm-lens/clients/dispatch/runners/yaml-rule-parser.js +8 -1
  70. package/extensions/dm-lens/clients/dispatch/types.js +21 -1
  71. package/extensions/dm-lens/clients/dispatch/utils/format-utils.js +13 -0
  72. package/extensions/dm-lens/clients/effective-config.js +14 -3
  73. package/extensions/dm-lens/clients/ephemeral-root.js +71 -0
  74. package/extensions/dm-lens/clients/file-kinds.js +9 -0
  75. package/extensions/dm-lens/clients/file-mutation-queue.js +95 -0
  76. package/extensions/dm-lens/clients/file-utils.js +87 -8
  77. package/extensions/dm-lens/clients/finding-delivery-gate.js +5 -2
  78. package/extensions/dm-lens/clients/fix-run-restore.js +416 -0
  79. package/extensions/dm-lens/clients/format-events-publish.js +82 -2
  80. package/extensions/dm-lens/clients/format-service.js +10 -5
  81. package/extensions/dm-lens/clients/formatters.js +29 -12
  82. package/extensions/dm-lens/clients/generation-guard.js +50 -8
  83. package/extensions/dm-lens/clients/generation-lock.js +184 -0
  84. package/extensions/dm-lens/clients/git-guard.js +19 -1
  85. package/extensions/dm-lens/clients/gitleaks-client.js +13 -4
  86. package/extensions/dm-lens/clients/grammar-source.js +5 -0
  87. package/extensions/dm-lens/clients/grammar-wasm-imports.js +48 -0
  88. package/extensions/dm-lens/clients/gzip-stage-write.js +15 -7
  89. package/extensions/dm-lens/clients/hard-failure-summary.js +28 -0
  90. package/extensions/dm-lens/clients/hook-budgets.js +1 -0
  91. package/extensions/dm-lens/clients/inline-blocker-fields.js +8 -0
  92. package/extensions/dm-lens/clients/install-diagnostics.js +31 -16
  93. package/extensions/dm-lens/clients/installer/index.js +238 -58
  94. package/extensions/dm-lens/clients/instance-reaper.js +164 -52
  95. package/extensions/dm-lens/clients/instance-registry-lock.js +117 -76
  96. package/extensions/dm-lens/clients/instance-registry-tail.js +17 -0
  97. package/extensions/dm-lens/clients/instance-registry.js +248 -91
  98. package/extensions/dm-lens/clients/io-bridge-contract.js +7 -0
  99. package/extensions/dm-lens/clients/io-bridge.js +372 -0
  100. package/extensions/dm-lens/clients/jscpd-client.js +83 -35
  101. package/extensions/dm-lens/clients/knip-client.js +75 -6
  102. package/extensions/dm-lens/clients/knip-scan-roots.js +29 -0
  103. package/extensions/dm-lens/clients/language-policy.js +2 -0
  104. package/extensions/dm-lens/clients/language-profile.js +4 -1
  105. package/extensions/dm-lens/clients/language-registry.js +4 -1
  106. package/extensions/dm-lens/clients/latency-logger.js +11 -1
  107. package/extensions/dm-lens/clients/lens-config.js +10 -1
  108. package/extensions/dm-lens/clients/lens-engine.js +1 -1
  109. package/extensions/dm-lens/clients/lens-flag-registry.js +14 -24
  110. package/extensions/dm-lens/clients/lsp/aggregation.js +9 -8
  111. package/extensions/dm-lens/clients/lsp/auxiliary-lifecycle.js +23 -0
  112. package/extensions/dm-lens/clients/lsp/capabilities.js +98 -0
  113. package/extensions/dm-lens/clients/lsp/cascade-tier.js +8 -3
  114. package/extensions/dm-lens/clients/lsp/client.js +282 -48
  115. package/extensions/dm-lens/clients/lsp/config.js +247 -15
  116. package/extensions/dm-lens/clients/lsp/document-drift.js +23 -11
  117. package/extensions/dm-lens/clients/lsp/edits.js +137 -85
  118. package/extensions/dm-lens/clients/lsp/grouping.js +38 -0
  119. package/extensions/dm-lens/clients/lsp/index.js +484 -275
  120. package/extensions/dm-lens/clients/lsp/launch.js +106 -6
  121. package/extensions/dm-lens/clients/lsp/pending-aux-coverage.js +37 -7
  122. package/extensions/dm-lens/clients/lsp/resolved-config.js +188 -0
  123. package/extensions/dm-lens/clients/lsp/server-covers.js +8 -0
  124. package/extensions/dm-lens/clients/lsp/server-traits.js +39 -0
  125. package/extensions/dm-lens/clients/lsp/server.js +259 -34
  126. package/extensions/dm-lens/clients/lsp/service-singleton.js +59 -0
  127. package/extensions/dm-lens/clients/lsp/session-roots.js +1 -1
  128. package/extensions/dm-lens/clients/lsp/wait-policy/classification.js +2 -1
  129. package/extensions/dm-lens/clients/lsp/wait-policy/strategies.js +25 -4
  130. package/extensions/dm-lens/clients/lsp/workspace-diagnostics-cache.js +6 -3
  131. package/extensions/dm-lens/clients/lsp-budget.js +9 -5
  132. package/extensions/dm-lens/clients/lsp-document-symbols.js +1 -1
  133. package/extensions/dm-lens/clients/lsp-lazy.js +1 -1
  134. package/extensions/dm-lens/clients/lsp-mutation.js +44 -8
  135. package/extensions/dm-lens/clients/lsp-status.js +5 -7
  136. package/extensions/dm-lens/clients/mcp/analyze.js +24 -11
  137. package/extensions/dm-lens/clients/mcp/ipc.js +26 -7
  138. package/extensions/dm-lens/clients/mcp/session.js +1 -1
  139. package/extensions/dm-lens/clients/memory-sampler.js +48 -3
  140. package/extensions/dm-lens/clients/module-report-lsp.js +1 -1
  141. package/extensions/dm-lens/clients/module-report.js +9 -3
  142. package/extensions/dm-lens/clients/mutating-tool.js +12 -3
  143. package/extensions/dm-lens/clients/mutation-attribution.js +8 -0
  144. package/extensions/dm-lens/clients/mutation-bridge.js +181 -48
  145. package/extensions/dm-lens/clients/ndjson-logger.js +33 -0
  146. package/extensions/dm-lens/clients/observed-mutation-sources.js +1 -1
  147. package/extensions/dm-lens/clients/observed-mutation.js +40 -20
  148. package/extensions/dm-lens/clients/opaque-mutation-scan.js +40 -13
  149. package/extensions/dm-lens/clients/opengrep-client.js +6 -3
  150. package/extensions/dm-lens/clients/package-manager.js +61 -6
  151. package/extensions/dm-lens/clients/path-utils.js +77 -18
  152. package/extensions/dm-lens/clients/performance-report.js +1 -1
  153. package/extensions/dm-lens/clients/persist-worker-stats.js +8 -0
  154. package/extensions/dm-lens/clients/persistent-reverify.js +5 -1
  155. package/extensions/dm-lens/clients/pipeline.js +310 -114
  156. package/extensions/dm-lens/clients/probe-home-state.js +6 -1
  157. package/extensions/dm-lens/clients/process-bridge.js +28 -0
  158. package/extensions/dm-lens/clients/process-snapshot.js +115 -2
  159. package/extensions/dm-lens/clients/project-changes.js +81 -19
  160. package/extensions/dm-lens/clients/project-diagnostics/fresh-fetch.js +18 -13
  161. package/extensions/dm-lens/clients/project-lens-config.js +32 -5
  162. package/extensions/dm-lens/clients/project-scale.js +1 -1
  163. package/extensions/dm-lens/clients/project-snapshot-fingerprint.js +17 -12
  164. package/extensions/dm-lens/clients/project-snapshot-persist-worker.js +2 -3
  165. package/extensions/dm-lens/clients/project-snapshot.js +229 -64
  166. package/extensions/dm-lens/clients/python-environment.js +44 -2
  167. package/extensions/dm-lens/clients/quiet-window.js +6 -3
  168. package/extensions/dm-lens/clients/read-bridge.js +28 -20
  169. package/extensions/dm-lens/clients/read-expansion.js +1 -1
  170. package/extensions/dm-lens/clients/read-guard-branch.js +129 -0
  171. package/extensions/dm-lens/clients/read-guard-logger.js +11 -3
  172. package/extensions/dm-lens/clients/read-guard-tool-lines.js +16 -8
  173. package/extensions/dm-lens/clients/read-guard.js +516 -176
  174. package/extensions/dm-lens/clients/review-graph/builder.js +132 -54
  175. package/extensions/dm-lens/clients/review-graph/git-identity.js +59 -1
  176. package/extensions/dm-lens/clients/review-graph/import-resolvers.js +6 -8
  177. package/extensions/dm-lens/clients/runtime-agent-end.js +271 -68
  178. package/extensions/dm-lens/clients/runtime-coordinator.js +386 -74
  179. package/extensions/dm-lens/clients/runtime-session.js +174 -31
  180. package/extensions/dm-lens/clients/runtime-tool-call.js +92 -17
  181. package/extensions/dm-lens/clients/runtime-tool-result.js +477 -137
  182. package/extensions/dm-lens/clients/runtime-turn.js +949 -355
  183. package/extensions/dm-lens/clients/safe-spawn.js +12 -4
  184. package/extensions/dm-lens/clients/scanner-temp-root.js +8 -0
  185. package/extensions/dm-lens/clients/scratch-tree-policy.js +9 -0
  186. package/extensions/dm-lens/clients/search-read-registration.js +2 -1
  187. package/extensions/dm-lens/clients/session-lifecycle.js +120 -18
  188. package/extensions/dm-lens/clients/session-scope.js +456 -0
  189. package/extensions/dm-lens/clients/session-state-store.js +23 -20
  190. package/extensions/dm-lens/clients/sg-runner.js +24 -6
  191. package/extensions/dm-lens/clients/sgconfig.js +35 -5
  192. package/extensions/dm-lens/clients/startup-scan.js +10 -2
  193. package/extensions/dm-lens/clients/test-runner-client.js +258 -48
  194. package/extensions/dm-lens/clients/test-runner-delivery.js +46 -9
  195. package/extensions/dm-lens/clients/test-target-roots.js +20 -0
  196. package/extensions/dm-lens/clients/tool-agreement.js +282 -19
  197. package/extensions/dm-lens/clients/tool-config.js +1 -0
  198. package/extensions/dm-lens/clients/tool-event.js +6 -0
  199. package/extensions/dm-lens/clients/tool-probe.js +8 -0
  200. package/extensions/dm-lens/clients/tool-set-policy.js +36 -26
  201. package/extensions/dm-lens/clients/tree-sitter-client.js +304 -34
  202. package/extensions/dm-lens/clients/tree-sitter-query-loader.js +76 -2
  203. package/extensions/dm-lens/clients/tree-sitter-shared.js +2 -2
  204. package/extensions/dm-lens/clients/tree-sitter-symbol-extractor.js +3 -1
  205. package/extensions/dm-lens/clients/trivy-client.js +40 -7
  206. package/extensions/dm-lens/clients/turn-end/delivery-holds.js +59 -0
  207. package/extensions/dm-lens/clients/widget-state.js +36 -2
  208. package/extensions/dm-lens/clients/word-index.js +73 -5
  209. package/extensions/dm-lens/clients/workspace-topology.js +11 -4
  210. package/extensions/dm-lens/clients/write-ordering-guard.js +4 -0
  211. package/extensions/dm-lens/config/dependency-cruiser-eager-allowlist.json +9 -3
  212. package/extensions/dm-lens/dist/clients/actionable-warnings-logger.js +24 -0
  213. package/extensions/dm-lens/dist/clients/actionable-warnings.js +1062 -0
  214. package/extensions/dm-lens/dist/clients/advisory-provenance.js +387 -0
  215. package/extensions/dm-lens/dist/clients/agent-behavior-client.js +94 -0
  216. package/extensions/dm-lens/dist/clients/agent-nudge.js +253 -0
  217. package/extensions/dm-lens/dist/clients/analysed-root.js +1 -0
  218. package/extensions/dm-lens/dist/clients/analysis-root.js +100 -0
  219. package/extensions/dm-lens/dist/clients/ast-grep-client.js +587 -0
  220. package/extensions/dm-lens/dist/clients/ast-grep-rule-manager.js +137 -0
  221. package/extensions/dm-lens/dist/clients/ast-grep-tool-logger.js +85 -0
  222. package/extensions/dm-lens/dist/clients/ast-grep-types.js +1 -0
  223. package/extensions/dm-lens/dist/clients/ast-grep-yaml-synth.js +109 -0
  224. package/extensions/dm-lens/dist/clients/atomic-write-staging.js +66 -0
  225. package/extensions/dm-lens/dist/clients/atomic-write.js +37 -0
  226. package/extensions/dm-lens/dist/clients/availability-probe-flight.js +11 -0
  227. package/extensions/dm-lens/dist/clients/bash-file-access.js +830 -0
  228. package/extensions/dm-lens/dist/clients/biome-client.js +223 -0
  229. package/extensions/dm-lens/dist/clients/blocker-freshness.js +377 -0
  230. package/extensions/dm-lens/dist/clients/blocker-past-eof.js +49 -0
  231. package/extensions/dm-lens/dist/clients/bootstrap.js +246 -0
  232. package/extensions/dm-lens/dist/clients/bounded-cache.js +105 -0
  233. package/extensions/dm-lens/dist/clients/bounded-pid-file-lock.js +275 -0
  234. package/extensions/dm-lens/dist/clients/bounded-telemetry.js +107 -0
  235. package/extensions/dm-lens/dist/clients/build-identity.js +45 -0
  236. package/extensions/dm-lens/dist/clients/bundled-resource-health.js +41 -0
  237. package/extensions/dm-lens/dist/clients/bus-events-logger.js +48 -0
  238. package/extensions/dm-lens/dist/clients/bus-publish.js +117 -0
  239. package/extensions/dm-lens/dist/clients/cache/rule-cache.js +87 -0
  240. package/extensions/dm-lens/dist/clients/cache-manager.js +428 -0
  241. package/extensions/dm-lens/dist/clients/cache-observability.js +847 -0
  242. package/extensions/dm-lens/dist/clients/call-graph.js +628 -0
  243. package/extensions/dm-lens/dist/clients/cargo-manifest.js +171 -0
  244. package/extensions/dm-lens/dist/clients/cascade-budget.js +52 -0
  245. package/extensions/dm-lens/dist/clients/cascade-format.js +160 -0
  246. package/extensions/dm-lens/dist/clients/cascade-logger.js +22 -0
  247. package/extensions/dm-lens/dist/clients/cascade-types.js +1 -0
  248. package/extensions/dm-lens/dist/clients/child-unref.js +59 -0
  249. package/extensions/dm-lens/dist/clients/code-quality-warnings.js +192 -0
  250. package/extensions/dm-lens/dist/clients/codebase-model.js +110 -0
  251. package/extensions/dm-lens/dist/clients/collateral-test-role.js +8 -0
  252. package/extensions/dm-lens/dist/clients/complexity-client.js +398 -0
  253. package/extensions/dm-lens/dist/clients/config-core/deny.js +117 -0
  254. package/extensions/dm-lens/dist/clients/config-core/index.js +2 -0
  255. package/extensions/dm-lens/dist/clients/config-core/merge.js +228 -0
  256. package/extensions/dm-lens/dist/clients/config-core/normalize.js +226 -0
  257. package/extensions/dm-lens/dist/clients/config-core/process-spec.js +147 -0
  258. package/extensions/dm-lens/dist/clients/config-core/provenance.js +54 -0
  259. package/extensions/dm-lens/dist/clients/config-core/records.js +79 -0
  260. package/extensions/dm-lens/dist/clients/config-core/resolve.js +48 -0
  261. package/extensions/dm-lens/dist/clients/config-core/safe-object.js +22 -0
  262. package/extensions/dm-lens/dist/clients/config-core/schema.js +93 -0
  263. package/extensions/dm-lens/dist/clients/config-diagnostic-codes.js +90 -0
  264. package/extensions/dm-lens/dist/clients/config-locations.js +175 -0
  265. package/extensions/dm-lens/dist/clients/config-resolve.js +359 -0
  266. package/extensions/dm-lens/dist/clients/config-schema.js +230 -0
  267. package/extensions/dm-lens/dist/clients/config-warn.js +146 -0
  268. package/extensions/dm-lens/dist/clients/confirmed-delete.js +11 -0
  269. package/extensions/dm-lens/dist/clients/console-guard-install.js +4 -0
  270. package/extensions/dm-lens/dist/clients/cooperative-budget.js +36 -0
  271. package/extensions/dm-lens/dist/clients/custom-rule-locations.js +28 -0
  272. package/extensions/dm-lens/dist/clients/dead-code-client.js +408 -0
  273. package/extensions/dm-lens/dist/clients/dead-code-logger.js +18 -0
  274. package/extensions/dm-lens/dist/clients/deadline-utils.js +117 -0
  275. package/extensions/dm-lens/dist/clients/debug-handles.js +121 -0
  276. package/extensions/dm-lens/dist/clients/debug-heap.js +80 -0
  277. package/extensions/dm-lens/dist/clients/deferred-lsp-work.js +33 -0
  278. package/extensions/dm-lens/dist/clients/deferred-runner-blockers.js +106 -0
  279. package/extensions/dm-lens/dist/clients/deferred-test-targets.js +31 -0
  280. package/extensions/dm-lens/dist/clients/degradation-ledger.js +289 -0
  281. package/extensions/dm-lens/dist/clients/demoted-finding-render.js +64 -0
  282. package/extensions/dm-lens/dist/clients/dependency-checker.js +534 -0
  283. package/extensions/dm-lens/dist/clients/deps/ast-grep-napi.js +17 -0
  284. package/extensions/dm-lens/dist/clients/deps/dm-host-deps.js +10 -0
  285. package/extensions/dm-lens/dist/clients/deps/dm-tui-compat.js +58 -0
  286. package/extensions/dm-lens/dist/clients/deps/js-yaml.js +7 -0
  287. package/extensions/dm-lens/dist/clients/deps/minimatch.js +6 -0
  288. package/extensions/dm-lens/dist/clients/deps/pidusage.js +5 -0
  289. package/extensions/dm-lens/dist/clients/deps/typebox.js +5 -0
  290. package/extensions/dm-lens/dist/clients/deps/vscode-jsonrpc.js +8 -0
  291. package/extensions/dm-lens/dist/clients/deps/web-tree-sitter.js +11 -0
  292. package/extensions/dm-lens/dist/clients/diagnostic-dispositions.js +318 -0
  293. package/extensions/dm-lens/dist/clients/diagnostic-line-freshness.js +142 -0
  294. package/extensions/dm-lens/dist/clients/diagnostic-logger.js +60 -0
  295. package/extensions/dm-lens/dist/clients/diagnostic-tracker.js +89 -0
  296. package/extensions/dm-lens/dist/clients/diagnostics-publish.js +134 -0
  297. package/extensions/dm-lens/dist/clients/dispatch/adopted-root-runners.js +22 -0
  298. package/extensions/dm-lens/dist/clients/dispatch/ast-grep-catalog.js +16 -0
  299. package/extensions/dm-lens/dist/clients/dispatch/auxiliary-lsp.js +158 -0
  300. package/extensions/dm-lens/dist/clients/dispatch/collect-later-tier.js +25 -0
  301. package/extensions/dm-lens/dist/clients/dispatch/diagnostic-taxonomy.js +58 -0
  302. package/extensions/dm-lens/dist/clients/dispatch/dispatcher.js +1017 -0
  303. package/extensions/dm-lens/dist/clients/dispatch/fact-provider-types.js +1 -0
  304. package/extensions/dm-lens/dist/clients/dispatch/fact-rule-runner.js +17 -0
  305. package/extensions/dm-lens/dist/clients/dispatch/fact-runner.js +18 -0
  306. package/extensions/dm-lens/dist/clients/dispatch/fact-scheduler.js +52 -0
  307. package/extensions/dm-lens/dist/clients/dispatch/fact-store.js +199 -0
  308. package/extensions/dm-lens/dist/clients/dispatch/facts/comment-facts.js +23 -0
  309. package/extensions/dm-lens/dist/clients/dispatch/facts/file-content.js +18 -0
  310. package/extensions/dm-lens/dist/clients/dispatch/facts/function-facts.js +281 -0
  311. package/extensions/dm-lens/dist/clients/dispatch/facts/import-facts.js +169 -0
  312. package/extensions/dm-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +19 -0
  313. package/extensions/dm-lens/dist/clients/dispatch/facts/try-catch-facts.js +95 -0
  314. package/extensions/dm-lens/dist/clients/dispatch/finding-policy.js +164 -0
  315. package/extensions/dm-lens/dist/clients/dispatch/indent-detect.js +227 -0
  316. package/extensions/dm-lens/dist/clients/dispatch/inline-suppressions.js +52 -0
  317. package/extensions/dm-lens/dist/clients/dispatch/integration.js +1502 -0
  318. package/extensions/dm-lens/dist/clients/dispatch/known-runner-ids.js +13 -0
  319. package/extensions/dm-lens/dist/clients/dispatch/lazy.js +8 -0
  320. package/extensions/dm-lens/dist/clients/dispatch/pending-runner-findings.js +130 -0
  321. package/extensions/dm-lens/dist/clients/dispatch/plan.js +284 -0
  322. package/extensions/dm-lens/dist/clients/dispatch/priorities.js +14 -0
  323. package/extensions/dm-lens/dist/clients/dispatch/rule-id-normalize.js +49 -0
  324. package/extensions/dm-lens/dist/clients/dispatch/rule-ignores.js +21 -0
  325. package/extensions/dm-lens/dist/clients/dispatch/rule-policy.js +102 -0
  326. package/extensions/dm-lens/dist/clients/dispatch/rules/async-noise.js +31 -0
  327. package/extensions/dm-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +27 -0
  328. package/extensions/dm-lens/dist/clients/dispatch/rules/cors-wildcard.js +35 -0
  329. package/extensions/dm-lens/dist/clients/dispatch/rules/error-obscuring.js +29 -0
  330. package/extensions/dm-lens/dist/clients/dispatch/rules/error-swallowing.js +29 -0
  331. package/extensions/dm-lens/dist/clients/dispatch/rules/framework-call-noise.js +31 -0
  332. package/extensions/dm-lens/dist/clients/dispatch/rules/high-complexity.js +56 -0
  333. package/extensions/dm-lens/dist/clients/dispatch/rules/high-fan-out.js +45 -0
  334. package/extensions/dm-lens/dist/clients/dispatch/rules/high-import-coupling.js +31 -0
  335. package/extensions/dm-lens/dist/clients/dispatch/rules/missing-error-propagation.js +45 -0
  336. package/extensions/dm-lens/dist/clients/dispatch/rules/no-commented-credentials.js +46 -0
  337. package/extensions/dm-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +38 -0
  338. package/extensions/dm-lens/dist/clients/dispatch/rules/placeholder-comments.js +40 -0
  339. package/extensions/dm-lens/dist/clients/dispatch/rules/unsafe-boundary.js +101 -0
  340. package/extensions/dm-lens/dist/clients/dispatch/runner-context.js +46 -0
  341. package/extensions/dm-lens/dist/clients/dispatch/runners/actionlint.js +98 -0
  342. package/extensions/dm-lens/dist/clients/dispatch/runners/ast-grep-napi.js +694 -0
  343. package/extensions/dm-lens/dist/clients/dispatch/runners/biome-check.js +205 -0
  344. package/extensions/dm-lens/dist/clients/dispatch/runners/cpp-check.js +190 -0
  345. package/extensions/dm-lens/dist/clients/dispatch/runners/credo.js +66 -0
  346. package/extensions/dm-lens/dist/clients/dispatch/runners/cue-vet.js +171 -0
  347. package/extensions/dm-lens/dist/clients/dispatch/runners/dart-analyze.js +151 -0
  348. package/extensions/dm-lens/dist/clients/dispatch/runners/detekt.js +157 -0
  349. package/extensions/dm-lens/dist/clients/dispatch/runners/dotnet-build.js +157 -0
  350. package/extensions/dm-lens/dist/clients/dispatch/runners/elixir-check.js +153 -0
  351. package/extensions/dm-lens/dist/clients/dispatch/runners/eslint.js +99 -0
  352. package/extensions/dm-lens/dist/clients/dispatch/runners/fact-rules.js +20 -0
  353. package/extensions/dm-lens/dist/clients/dispatch/runners/fish-indent.js +66 -0
  354. package/extensions/dm-lens/dist/clients/dispatch/runners/gleam-check.js +110 -0
  355. package/extensions/dm-lens/dist/clients/dispatch/runners/go-vet.js +52 -0
  356. package/extensions/dm-lens/dist/clients/dispatch/runners/golangci-lint.js +89 -0
  357. package/extensions/dm-lens/dist/clients/dispatch/runners/hadolint.js +83 -0
  358. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-lint.js +144 -0
  359. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-render.js +593 -0
  360. package/extensions/dm-lens/dist/clients/dispatch/runners/htmlhint.js +103 -0
  361. package/extensions/dm-lens/dist/clients/dispatch/runners/index.js +100 -0
  362. package/extensions/dm-lens/dist/clients/dispatch/runners/javac.js +82 -0
  363. package/extensions/dm-lens/dist/clients/dispatch/runners/ktlint.js +93 -0
  364. package/extensions/dm-lens/dist/clients/dispatch/runners/lsp.js +226 -0
  365. package/extensions/dm-lens/dist/clients/dispatch/runners/markdownlint.js +129 -0
  366. package/extensions/dm-lens/dist/clients/dispatch/runners/mypy.js +70 -0
  367. package/extensions/dm-lens/dist/clients/dispatch/runners/oxlint.js +305 -0
  368. package/extensions/dm-lens/dist/clients/dispatch/runners/php-lint.js +66 -0
  369. package/extensions/dm-lens/dist/clients/dispatch/runners/phpstan.js +90 -0
  370. package/extensions/dm-lens/dist/clients/dispatch/runners/prisma-validate.js +66 -0
  371. package/extensions/dm-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +307 -0
  372. package/extensions/dm-lens/dist/clients/dispatch/runners/pyright.js +118 -0
  373. package/extensions/dm-lens/dist/clients/dispatch/runners/rubocop.js +79 -0
  374. package/extensions/dm-lens/dist/clients/dispatch/runners/ruff.js +69 -0
  375. package/extensions/dm-lens/dist/clients/dispatch/runners/rust-clippy.js +166 -0
  376. package/extensions/dm-lens/dist/clients/dispatch/runners/shellcheck.js +177 -0
  377. package/extensions/dm-lens/dist/clients/dispatch/runners/shfmt.js +85 -0
  378. package/extensions/dm-lens/dist/clients/dispatch/runners/spellcheck.js +74 -0
  379. package/extensions/dm-lens/dist/clients/dispatch/runners/spotbugs.js +208 -0
  380. package/extensions/dm-lens/dist/clients/dispatch/runners/sqlfluff.js +136 -0
  381. package/extensions/dm-lens/dist/clients/dispatch/runners/stylelint.js +118 -0
  382. package/extensions/dm-lens/dist/clients/dispatch/runners/swiftlint.js +143 -0
  383. package/extensions/dm-lens/dist/clients/dispatch/runners/taplo.js +108 -0
  384. package/extensions/dm-lens/dist/clients/dispatch/runners/terragrunt.js +110 -0
  385. package/extensions/dm-lens/dist/clients/dispatch/runners/tflint.js +104 -0
  386. package/extensions/dm-lens/dist/clients/dispatch/runners/tree-sitter.js +521 -0
  387. package/extensions/dm-lens/dist/clients/dispatch/runners/trivy-config.js +155 -0
  388. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/availability-policy.js +285 -0
  389. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +61 -0
  390. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +61 -0
  391. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +130 -0
  392. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +1143 -0
  393. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +40 -0
  394. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/tool-failure.js +120 -0
  395. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +88 -0
  396. package/extensions/dm-lens/dist/clients/dispatch/runners/utils.js +8 -0
  397. package/extensions/dm-lens/dist/clients/dispatch/runners/vale.js +106 -0
  398. package/extensions/dm-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +170 -0
  399. package/extensions/dm-lens/dist/clients/dispatch/runners/yamllint.js +83 -0
  400. package/extensions/dm-lens/dist/clients/dispatch/runners/zig-check.js +72 -0
  401. package/extensions/dm-lens/dist/clients/dispatch/suppress-writer.js +57 -0
  402. package/extensions/dm-lens/dist/clients/dispatch/tool-profile.js +30 -0
  403. package/extensions/dm-lens/dist/clients/dispatch/types.js +27 -0
  404. package/extensions/dm-lens/dist/clients/dispatch/utils/format-utils.js +58 -0
  405. package/extensions/dm-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +31 -0
  406. package/extensions/dm-lens/dist/clients/disposition-logger.js +19 -0
  407. package/extensions/dm-lens/dist/clients/disposition-publish.js +88 -0
  408. package/extensions/dm-lens/dist/clients/durable-store.js +77 -0
  409. package/extensions/dm-lens/dist/clients/effective-config.js +170 -0
  410. package/extensions/dm-lens/dist/clients/env-utils.js +26 -0
  411. package/extensions/dm-lens/dist/clients/ephemeral-root.js +67 -0
  412. package/extensions/dm-lens/dist/clients/error-class.js +3 -0
  413. package/extensions/dm-lens/dist/clients/eval-timestamp.js +2 -0
  414. package/extensions/dm-lens/dist/clients/event-loop-hold.js +119 -0
  415. package/extensions/dm-lens/dist/clients/event-loop-monitor.js +84 -0
  416. package/extensions/dm-lens/dist/clients/extension-log.js +230 -0
  417. package/extensions/dm-lens/dist/clients/extension-mode.js +20 -0
  418. package/extensions/dm-lens/dist/clients/feature-hints.js +88 -0
  419. package/extensions/dm-lens/dist/clients/file-kinds.js +313 -0
  420. package/extensions/dm-lens/dist/clients/file-mutation-queue.js +95 -0
  421. package/extensions/dm-lens/dist/clients/file-role.js +50 -0
  422. package/extensions/dm-lens/dist/clients/file-time.js +112 -0
  423. package/extensions/dm-lens/dist/clients/file-utils.js +706 -0
  424. package/extensions/dm-lens/dist/clients/finding-delivery-gate.js +132 -0
  425. package/extensions/dm-lens/dist/clients/finding-identity.js +23 -0
  426. package/extensions/dm-lens/dist/clients/fix-run-restore.js +413 -0
  427. package/extensions/dm-lens/dist/clients/fix-worklog.js +75 -0
  428. package/extensions/dm-lens/dist/clients/format-events-publish.js +310 -0
  429. package/extensions/dm-lens/dist/clients/format-service.js +159 -0
  430. package/extensions/dm-lens/dist/clients/formatters-lazy.js +8 -0
  431. package/extensions/dm-lens/dist/clients/formatters.js +1367 -0
  432. package/extensions/dm-lens/dist/clients/freshness-cadence.js +1 -0
  433. package/extensions/dm-lens/dist/clients/freshness.js +8 -0
  434. package/extensions/dm-lens/dist/clients/generated-artifacts.js +209 -0
  435. package/extensions/dm-lens/dist/clients/generation-guard.js +147 -0
  436. package/extensions/dm-lens/dist/clients/generation-lock.js +181 -0
  437. package/extensions/dm-lens/dist/clients/git-guard.js +786 -0
  438. package/extensions/dm-lens/dist/clients/git-tracked-ignore.js +120 -0
  439. package/extensions/dm-lens/dist/clients/gitleaks-client.js +290 -0
  440. package/extensions/dm-lens/dist/clients/go-client.js +47 -0
  441. package/extensions/dm-lens/dist/clients/govulncheck-client.js +411 -0
  442. package/extensions/dm-lens/dist/clients/gradle-ktfmt-style.js +177 -0
  443. package/extensions/dm-lens/dist/clients/grammar-source.js +229 -0
  444. package/extensions/dm-lens/dist/clients/grammar-wasm-imports.js +48 -0
  445. package/extensions/dm-lens/dist/clients/gzip-stage-write.js +93 -0
  446. package/extensions/dm-lens/dist/clients/hard-failure-summary.js +28 -0
  447. package/extensions/dm-lens/dist/clients/hashline-anchor.js +222 -0
  448. package/extensions/dm-lens/dist/clients/hook-budgets.js +17 -0
  449. package/extensions/dm-lens/dist/clients/host-edit-normalize.js +87 -0
  450. package/extensions/dm-lens/dist/clients/host-ports.js +35 -0
  451. package/extensions/dm-lens/dist/clients/indent-retarget.js +102 -0
  452. package/extensions/dm-lens/dist/clients/inline-blocker-dispositions.js +103 -0
  453. package/extensions/dm-lens/dist/clients/inline-blocker-fields.js +8 -0
  454. package/extensions/dm-lens/dist/clients/install-diagnostics.js +135 -0
  455. package/extensions/dm-lens/dist/clients/installer/index.js +3935 -0
  456. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh-session.js +17 -0
  457. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh.js +522 -0
  458. package/extensions/dm-lens/dist/clients/instance-reaper-state.js +3 -0
  459. package/extensions/dm-lens/dist/clients/instance-reaper.js +682 -0
  460. package/extensions/dm-lens/dist/clients/instance-registry-lock.js +166 -0
  461. package/extensions/dm-lens/dist/clients/instance-registry-tail.js +17 -0
  462. package/extensions/dm-lens/dist/clients/instance-registry.js +595 -0
  463. package/extensions/dm-lens/dist/clients/io-bridge-contract.js +7 -0
  464. package/extensions/dm-lens/dist/clients/io-bridge.js +357 -0
  465. package/extensions/dm-lens/dist/clients/jscpd-client.js +300 -0
  466. package/extensions/dm-lens/dist/clients/json-cache-read.js +25 -0
  467. package/extensions/dm-lens/dist/clients/knip-client.js +534 -0
  468. package/extensions/dm-lens/dist/clients/knip-scan-roots.js +26 -0
  469. package/extensions/dm-lens/dist/clients/language-policy.js +244 -0
  470. package/extensions/dm-lens/dist/clients/language-profile.js +263 -0
  471. package/extensions/dm-lens/dist/clients/language-registry.js +427 -0
  472. package/extensions/dm-lens/dist/clients/latency-logger.js +202 -0
  473. package/extensions/dm-lens/dist/clients/lazy-import.js +14 -0
  474. package/extensions/dm-lens/dist/clients/ledger-bounds.js +21 -0
  475. package/extensions/dm-lens/dist/clients/lens-config.js +246 -0
  476. package/extensions/dm-lens/dist/clients/lens-engine.js +181 -0
  477. package/extensions/dm-lens/dist/clients/lens-events.js +105 -0
  478. package/extensions/dm-lens/dist/clients/lens-flag-registry.js +292 -0
  479. package/extensions/dm-lens/dist/clients/lens-map.js +980 -0
  480. package/extensions/dm-lens/dist/clients/live-bus-emitter.js +53 -0
  481. package/extensions/dm-lens/dist/clients/log-cleanup.js +138 -0
  482. package/extensions/dm-lens/dist/clients/lsp/aggregation.js +89 -0
  483. package/extensions/dm-lens/dist/clients/lsp/auxiliary-lifecycle.js +23 -0
  484. package/extensions/dm-lens/dist/clients/lsp/capabilities.js +94 -0
  485. package/extensions/dm-lens/dist/clients/lsp/cascade-tier.js +208 -0
  486. package/extensions/dm-lens/dist/clients/lsp/client.js +2943 -0
  487. package/extensions/dm-lens/dist/clients/lsp/config.js +471 -0
  488. package/extensions/dm-lens/dist/clients/lsp/content-limits.js +21 -0
  489. package/extensions/dm-lens/dist/clients/lsp/diagnostic-binding.js +79 -0
  490. package/extensions/dm-lens/dist/clients/lsp/document-drift.js +324 -0
  491. package/extensions/dm-lens/dist/clients/lsp/edits.js +982 -0
  492. package/extensions/dm-lens/dist/clients/lsp/grouping.js +38 -0
  493. package/extensions/dm-lens/dist/clients/lsp/index.js +4639 -0
  494. package/extensions/dm-lens/dist/clients/lsp/inferred-project.js +121 -0
  495. package/extensions/dm-lens/dist/clients/lsp/jvm-runtime.js +194 -0
  496. package/extensions/dm-lens/dist/clients/lsp/language.js +23 -0
  497. package/extensions/dm-lens/dist/clients/lsp/launch.js +564 -0
  498. package/extensions/dm-lens/dist/clients/lsp/lombok.js +146 -0
  499. package/extensions/dm-lens/dist/clients/lsp/path-utils.js +1 -0
  500. package/extensions/dm-lens/dist/clients/lsp/pending-aux-coverage.js +120 -0
  501. package/extensions/dm-lens/dist/clients/lsp/position-encoding.js +28 -0
  502. package/extensions/dm-lens/dist/clients/lsp/resolved-config.js +183 -0
  503. package/extensions/dm-lens/dist/clients/lsp/ruby-drive-dirs.js +42 -0
  504. package/extensions/dm-lens/dist/clients/lsp/server-covers.js +8 -0
  505. package/extensions/dm-lens/dist/clients/lsp/server-traits.js +39 -0
  506. package/extensions/dm-lens/dist/clients/lsp/server.js +2640 -0
  507. package/extensions/dm-lens/dist/clients/lsp/service-singleton.js +59 -0
  508. package/extensions/dm-lens/dist/clients/lsp/session-roots.js +52 -0
  509. package/extensions/dm-lens/dist/clients/lsp/spawn-history.js +15 -0
  510. package/extensions/dm-lens/dist/clients/lsp/sync-kind.js +30 -0
  511. package/extensions/dm-lens/dist/clients/lsp/tsserver-sync.js +156 -0
  512. package/extensions/dm-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +1 -0
  513. package/extensions/dm-lens/dist/clients/lsp/wait-policy/classification.js +37 -0
  514. package/extensions/dm-lens/dist/clients/lsp/wait-policy/index.js +3 -0
  515. package/extensions/dm-lens/dist/clients/lsp/wait-policy/strategies.js +196 -0
  516. package/extensions/dm-lens/dist/clients/lsp/watch-queue.js +40 -0
  517. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-cache.js +270 -0
  518. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-session.js +7 -0
  519. package/extensions/dm-lens/dist/clients/lsp/workspace-sweep-hold.js +93 -0
  520. package/extensions/dm-lens/dist/clients/lsp-budget.js +87 -0
  521. package/extensions/dm-lens/dist/clients/lsp-document-symbols.js +93 -0
  522. package/extensions/dm-lens/dist/clients/lsp-lazy.js +8 -0
  523. package/extensions/dm-lens/dist/clients/lsp-mutation.js +309 -0
  524. package/extensions/dm-lens/dist/clients/lsp-status.js +35 -0
  525. package/extensions/dm-lens/dist/clients/map-with-concurrency.js +20 -0
  526. package/extensions/dm-lens/dist/clients/mcp/analyze.js +265 -0
  527. package/extensions/dm-lens/dist/clients/mcp/host-shim.js +14 -0
  528. package/extensions/dm-lens/dist/clients/mcp/ipc.js +321 -0
  529. package/extensions/dm-lens/dist/clients/mcp/review.js +137 -0
  530. package/extensions/dm-lens/dist/clients/mcp/session.js +305 -0
  531. package/extensions/dm-lens/dist/clients/memory-sampler.js +145 -0
  532. package/extensions/dm-lens/dist/clients/message-end-attribution.js +18 -0
  533. package/extensions/dm-lens/dist/clients/metrics-client.js +80 -0
  534. package/extensions/dm-lens/dist/clients/metrics-history.js +255 -0
  535. package/extensions/dm-lens/dist/clients/middle-man-analysis.js +161 -0
  536. package/extensions/dm-lens/dist/clients/model-provider.js +31 -0
  537. package/extensions/dm-lens/dist/clients/module-report-lsp.js +140 -0
  538. package/extensions/dm-lens/dist/clients/module-report.js +1648 -0
  539. package/extensions/dm-lens/dist/clients/mutating-tool.js +386 -0
  540. package/extensions/dm-lens/dist/clients/mutation-attribution.js +176 -0
  541. package/extensions/dm-lens/dist/clients/mutation-bridge.js +231 -0
  542. package/extensions/dm-lens/dist/clients/ndjson-logger.js +504 -0
  543. package/extensions/dm-lens/dist/clients/observed-mutation-sources.js +43 -0
  544. package/extensions/dm-lens/dist/clients/observed-mutation.js +729 -0
  545. package/extensions/dm-lens/dist/clients/oldtext-autopatch.js +100 -0
  546. package/extensions/dm-lens/dist/clients/opaque-mutation-scan.js +340 -0
  547. package/extensions/dm-lens/dist/clients/opengrep-client.js +219 -0
  548. package/extensions/dm-lens/dist/clients/opengrep-config.js +52 -0
  549. package/extensions/dm-lens/dist/clients/package-manager.js +358 -0
  550. package/extensions/dm-lens/dist/clients/package-root.js +25 -0
  551. package/extensions/dm-lens/dist/clients/partial-edit-apply.js +337 -0
  552. package/extensions/dm-lens/dist/clients/path-attribution-telemetry.js +31 -0
  553. package/extensions/dm-lens/dist/clients/path-keyed-map.js +57 -0
  554. package/extensions/dm-lens/dist/clients/path-utils.js +535 -0
  555. package/extensions/dm-lens/dist/clients/performance-report.js +291 -0
  556. package/extensions/dm-lens/dist/clients/persist-debounce.js +37 -0
  557. package/extensions/dm-lens/dist/clients/persist-worker-stats.js +8 -0
  558. package/extensions/dm-lens/dist/clients/persistent-reverify.js +166 -0
  559. package/extensions/dm-lens/dist/clients/php-cs-fixer-config.js +15 -0
  560. package/extensions/dm-lens/dist/clients/pipeline.js +1279 -0
  561. package/extensions/dm-lens/dist/clients/post-autofix-notice.js +19 -0
  562. package/extensions/dm-lens/dist/clients/print-mode.js +3 -0
  563. package/extensions/dm-lens/dist/clients/probe-home-state.js +67 -0
  564. package/extensions/dm-lens/dist/clients/process-bridge.js +48 -0
  565. package/extensions/dm-lens/dist/clients/process-singletons.js +69 -0
  566. package/extensions/dm-lens/dist/clients/process-snapshot.js +130 -0
  567. package/extensions/dm-lens/dist/clients/project-changes.js +174 -0
  568. package/extensions/dm-lens/dist/clients/project-conventions.js +152 -0
  569. package/extensions/dm-lens/dist/clients/project-diagnostics/cache.js +91 -0
  570. package/extensions/dm-lens/dist/clients/project-diagnostics/extractors.js +53 -0
  571. package/extensions/dm-lens/dist/clients/project-diagnostics/fresh-fetch.js +413 -0
  572. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +64 -0
  573. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +38 -0
  574. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +21 -0
  575. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +23 -0
  576. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +28 -0
  577. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +45 -0
  578. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +34 -0
  579. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +32 -0
  580. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +79 -0
  581. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +41 -0
  582. package/extensions/dm-lens/dist/clients/project-diagnostics/scanner.js +349 -0
  583. package/extensions/dm-lens/dist/clients/project-diagnostics/types.js +1 -0
  584. package/extensions/dm-lens/dist/clients/project-lens-config.js +464 -0
  585. package/extensions/dm-lens/dist/clients/project-report.js +527 -0
  586. package/extensions/dm-lens/dist/clients/project-scale.js +60 -0
  587. package/extensions/dm-lens/dist/clients/project-scan-policy.js +4 -0
  588. package/extensions/dm-lens/dist/clients/project-snapshot-fingerprint.js +44 -0
  589. package/extensions/dm-lens/dist/clients/project-snapshot-persist-worker.js +13 -0
  590. package/extensions/dm-lens/dist/clients/project-snapshot.js +1333 -0
  591. package/extensions/dm-lens/dist/clients/project-trust.js +104 -0
  592. package/extensions/dm-lens/dist/clients/python-environment.js +162 -0
  593. package/extensions/dm-lens/dist/clients/python-provenance.js +551 -0
  594. package/extensions/dm-lens/dist/clients/quiet-window-config.js +16 -0
  595. package/extensions/dm-lens/dist/clients/quiet-window.js +129 -0
  596. package/extensions/dm-lens/dist/clients/read-bridge.js +53 -0
  597. package/extensions/dm-lens/dist/clients/read-expansion.js +218 -0
  598. package/extensions/dm-lens/dist/clients/read-guard-branch.js +126 -0
  599. package/extensions/dm-lens/dist/clients/read-guard-logger.js +186 -0
  600. package/extensions/dm-lens/dist/clients/read-guard-tool-lines.js +1050 -0
  601. package/extensions/dm-lens/dist/clients/read-guard.js +1429 -0
  602. package/extensions/dm-lens/dist/clients/recent-touches.js +126 -0
  603. package/extensions/dm-lens/dist/clients/redact/secrets.js +386 -0
  604. package/extensions/dm-lens/dist/clients/resource-sampler.js +344 -0
  605. package/extensions/dm-lens/dist/clients/reverse-deps.js +227 -0
  606. package/extensions/dm-lens/dist/clients/review-graph/builder.js +3708 -0
  607. package/extensions/dm-lens/dist/clients/review-graph/format.js +30 -0
  608. package/extensions/dm-lens/dist/clients/review-graph/git-identity.js +168 -0
  609. package/extensions/dm-lens/dist/clients/review-graph/import-resolvers.js +323 -0
  610. package/extensions/dm-lens/dist/clients/review-graph/persist-worker.js +8 -0
  611. package/extensions/dm-lens/dist/clients/review-graph/query.js +195 -0
  612. package/extensions/dm-lens/dist/clients/review-graph/revision-drift.js +3 -0
  613. package/extensions/dm-lens/dist/clients/review-graph/service.js +60 -0
  614. package/extensions/dm-lens/dist/clients/review-graph/shared-extraction-ir.js +54 -0
  615. package/extensions/dm-lens/dist/clients/review-graph/symbol-id.js +29 -0
  616. package/extensions/dm-lens/dist/clients/review-graph/tsconfig-paths.js +253 -0
  617. package/extensions/dm-lens/dist/clients/review-graph/types.js +1 -0
  618. package/extensions/dm-lens/dist/clients/review-graph/workspace-modules.js +374 -0
  619. package/extensions/dm-lens/dist/clients/review-graph-logger.js +51 -0
  620. package/extensions/dm-lens/dist/clients/ruff-client.js +109 -0
  621. package/extensions/dm-lens/dist/clients/rules-scanner.js +113 -0
  622. package/extensions/dm-lens/dist/clients/run-duration.js +9 -0
  623. package/extensions/dm-lens/dist/clients/runtime-agent-end.js +800 -0
  624. package/extensions/dm-lens/dist/clients/runtime-config.js +39 -0
  625. package/extensions/dm-lens/dist/clients/runtime-context.js +155 -0
  626. package/extensions/dm-lens/dist/clients/runtime-coordinator.js +1117 -0
  627. package/extensions/dm-lens/dist/clients/runtime-session.js +1768 -0
  628. package/extensions/dm-lens/dist/clients/runtime-tool-call.js +935 -0
  629. package/extensions/dm-lens/dist/clients/runtime-tool-result.js +1630 -0
  630. package/extensions/dm-lens/dist/clients/runtime-turn.js +2900 -0
  631. package/extensions/dm-lens/dist/clients/rust-client.js +48 -0
  632. package/extensions/dm-lens/dist/clients/safe-spawn.js +1275 -0
  633. package/extensions/dm-lens/dist/clients/sanitize.js +174 -0
  634. package/extensions/dm-lens/dist/clients/scan-utils.js +7 -0
  635. package/extensions/dm-lens/dist/clients/scanner-temp-root.js +8 -0
  636. package/extensions/dm-lens/dist/clients/scratch-tree-policy.js +63 -0
  637. package/extensions/dm-lens/dist/clients/search-read-registration.js +60 -0
  638. package/extensions/dm-lens/dist/clients/secret-findings.js +69 -0
  639. package/extensions/dm-lens/dist/clients/security-scan-client.js +208 -0
  640. package/extensions/dm-lens/dist/clients/session-event-guard.js +111 -0
  641. package/extensions/dm-lens/dist/clients/session-lifecycle.js +269 -0
  642. package/extensions/dm-lens/dist/clients/session-scope.js +451 -0
  643. package/extensions/dm-lens/dist/clients/session-start-observability.js +47 -0
  644. package/extensions/dm-lens/dist/clients/session-state-store.js +66 -0
  645. package/extensions/dm-lens/dist/clients/session-summary.js +8 -0
  646. package/extensions/dm-lens/dist/clients/sessionstart-logger.js +22 -0
  647. package/extensions/dm-lens/dist/clients/sg-runner.js +645 -0
  648. package/extensions/dm-lens/dist/clients/sgconfig.js +306 -0
  649. package/extensions/dm-lens/dist/clients/shared-checkout-guard.js +177 -0
  650. package/extensions/dm-lens/dist/clients/single-flight.js +52 -0
  651. package/extensions/dm-lens/dist/clients/situational-tool-telemetry.js +85 -0
  652. package/extensions/dm-lens/dist/clients/skills-resolver.js +38 -0
  653. package/extensions/dm-lens/dist/clients/slow-fs.js +77 -0
  654. package/extensions/dm-lens/dist/clients/smells-rollup.js +118 -0
  655. package/extensions/dm-lens/dist/clients/source-filter.js +320 -0
  656. package/extensions/dm-lens/dist/clients/source-walker.js +96 -0
  657. package/extensions/dm-lens/dist/clients/spawn-output-cap.js +35 -0
  658. package/extensions/dm-lens/dist/clients/spawn-timeout-cooldown.js +51 -0
  659. package/extensions/dm-lens/dist/clients/stale-marker.js +1 -0
  660. package/extensions/dm-lens/dist/clients/startup-scan.js +230 -0
  661. package/extensions/dm-lens/dist/clients/startup-timing.js +67 -0
  662. package/extensions/dm-lens/dist/clients/string-utils.js +6 -0
  663. package/extensions/dm-lens/dist/clients/subagent-mode.js +40 -0
  664. package/extensions/dm-lens/dist/clients/symbol-containment.js +16 -0
  665. package/extensions/dm-lens/dist/clients/symbol-types.js +1 -0
  666. package/extensions/dm-lens/dist/clients/test-runner-client.js +1697 -0
  667. package/extensions/dm-lens/dist/clients/test-runner-delivery.js +293 -0
  668. package/extensions/dm-lens/dist/clients/test-target-roots.js +17 -0
  669. package/extensions/dm-lens/dist/clients/todo-scanner.js +164 -0
  670. package/extensions/dm-lens/dist/clients/tool-agreement.js +640 -0
  671. package/extensions/dm-lens/dist/clients/tool-config.js +219 -0
  672. package/extensions/dm-lens/dist/clients/tool-cwd.js +235 -0
  673. package/extensions/dm-lens/dist/clients/tool-definition.js +22 -0
  674. package/extensions/dm-lens/dist/clients/tool-event.js +24 -0
  675. package/extensions/dm-lens/dist/clients/tool-policy.js +2393 -0
  676. package/extensions/dm-lens/dist/clients/tool-probe.js +13 -0
  677. package/extensions/dm-lens/dist/clients/tool-render.js +79 -0
  678. package/extensions/dm-lens/dist/clients/tool-set-policy.js +77 -0
  679. package/extensions/dm-lens/dist/clients/tree-sitter-cache.js +206 -0
  680. package/extensions/dm-lens/dist/clients/tree-sitter-client.js +3057 -0
  681. package/extensions/dm-lens/dist/clients/tree-sitter-logger.js +77 -0
  682. package/extensions/dm-lens/dist/clients/tree-sitter-navigator.js +198 -0
  683. package/extensions/dm-lens/dist/clients/tree-sitter-query-loader.js +389 -0
  684. package/extensions/dm-lens/dist/clients/tree-sitter-shared.js +87 -0
  685. package/extensions/dm-lens/dist/clients/tree-sitter-symbol-extractor.js +959 -0
  686. package/extensions/dm-lens/dist/clients/trivy-client.js +335 -0
  687. package/extensions/dm-lens/dist/clients/tui-fit.js +26 -0
  688. package/extensions/dm-lens/dist/clients/turn-context.js +48 -0
  689. package/extensions/dm-lens/dist/clients/turn-end/delivery-holds.js +59 -0
  690. package/extensions/dm-lens/dist/clients/turn-end/lane.js +1 -0
  691. package/extensions/dm-lens/dist/clients/turn-end/lanes/govulncheck.js +54 -0
  692. package/extensions/dm-lens/dist/clients/turn-end/lanes/secrets.js +131 -0
  693. package/extensions/dm-lens/dist/clients/turn-summary-render.js +56 -0
  694. package/extensions/dm-lens/dist/clients/turn-summary.js +84 -0
  695. package/extensions/dm-lens/dist/clients/typos-config.js +9 -0
  696. package/extensions/dm-lens/dist/clients/user-notify.js +15 -0
  697. package/extensions/dm-lens/dist/clients/vanished-instance-marker.js +18 -0
  698. package/extensions/dm-lens/dist/clients/warm-attach.js +210 -0
  699. package/extensions/dm-lens/dist/clients/widget-state.js +997 -0
  700. package/extensions/dm-lens/dist/clients/word-index-logger.js +21 -0
  701. package/extensions/dm-lens/dist/clients/word-index-store.js +222 -0
  702. package/extensions/dm-lens/dist/clients/word-index.js +1494 -0
  703. package/extensions/dm-lens/dist/clients/workspace-topology.js +268 -0
  704. package/extensions/dm-lens/dist/clients/write-ordering-guard.js +28 -0
  705. package/extensions/dm-lens/dist/clients/zizmor-config.js +160 -0
  706. package/extensions/dm-lens/dist/i18n.js +67 -0
  707. package/extensions/dm-lens/dist/index.js +1973 -0
  708. package/extensions/dm-lens/dist/mcp/analyze-cli.js +205 -0
  709. package/extensions/dm-lens/dist/mcp/build-staleness.js +55 -0
  710. package/extensions/dm-lens/dist/mcp/cli.js +96 -0
  711. package/extensions/dm-lens/dist/mcp/server.js +1239 -0
  712. package/extensions/dm-lens/dist/mcp/tool-arguments.js +134 -0
  713. package/extensions/dm-lens/dist/mcp/worker.js +41 -0
  714. package/extensions/dm-lens/dist/scripts/lib/process-scan.mjs +375 -0
  715. package/extensions/dm-lens/dist/scripts/lib/skills-predicate.mjs +53 -0
  716. package/extensions/dm-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +51 -0
  717. package/extensions/dm-lens/dist/tools/activate-tools.js +62 -0
  718. package/extensions/dm-lens/dist/tools/ast-grep-outline.js +126 -0
  719. package/extensions/dm-lens/dist/tools/ast-grep-replace.js +227 -0
  720. package/extensions/dm-lens/dist/tools/ast-grep-search.js +687 -0
  721. package/extensions/dm-lens/dist/tools/effective-config.js +59 -0
  722. package/extensions/dm-lens/dist/tools/lens-diagnostic-mark.js +251 -0
  723. package/extensions/dm-lens/dist/tools/lens-diagnostics.js +1518 -0
  724. package/extensions/dm-lens/dist/tools/lsp-diagnostics.js +1198 -0
  725. package/extensions/dm-lens/dist/tools/lsp-navigation.js +1249 -0
  726. package/extensions/dm-lens/dist/tools/lsp-structured-output.js +277 -0
  727. package/extensions/dm-lens/dist/tools/module-report.js +332 -0
  728. package/extensions/dm-lens/dist/tools/project-report.js +72 -0
  729. package/extensions/dm-lens/dist/tools/render-compact.js +272 -0
  730. package/extensions/dm-lens/dist/tools/scan-progress.js +31 -0
  731. package/extensions/dm-lens/dist/tools/shared.js +32 -0
  732. package/extensions/dm-lens/dist/tools/symbol-search.js +133 -0
  733. package/extensions/dm-lens/i18n.js +3 -3
  734. package/extensions/dm-lens/index.js +431 -214
  735. package/extensions/dm-lens/mcp/analyze-cli.js +63 -36
  736. package/extensions/dm-lens/mcp/cli.js +20 -0
  737. package/extensions/dm-lens/mcp/server.js +40 -3
  738. package/extensions/dm-lens/mcp/tool-arguments.js +134 -0
  739. package/extensions/dm-lens/mcp/worker.js +8 -0
  740. package/extensions/dm-lens/package.json +1 -1
  741. package/extensions/dm-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  742. package/extensions/dm-lens/rules/ast-grep-rules/rule-tests/no-identity-operator-on-literals-test.yml +12 -2
  743. package/extensions/dm-lens/rules/ast-grep-rules/rule-tests/throw-new-error-js-test.yml +2 -0
  744. package/extensions/dm-lens/rules/ast-grep-rules/rule-tests/throw-new-error-test.yml +2 -0
  745. package/extensions/dm-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  746. package/extensions/dm-lens/rules/ast-grep-rules/rules/no-identity-operator-on-literals.yml +20 -12
  747. package/extensions/dm-lens/rules/ast-grep-rules/rules/throw-new-error-js.yml +2 -2
  748. package/extensions/dm-lens/rules/ast-grep-rules/rules/throw-new-error.yml +2 -2
  749. package/extensions/dm-lens/scripts/lib/process-scan.mjs +126 -7
  750. package/extensions/dm-lens/scripts/lib/web-tree-sitter-dir.mjs +6 -0
  751. package/extensions/dm-lens/tools/activate-tools.js +3 -2
  752. package/extensions/dm-lens/tools/ast-grep-outline.js +2 -3
  753. package/extensions/dm-lens/tools/ast-grep-replace.js +6 -5
  754. package/extensions/dm-lens/tools/ast-grep-search.js +2 -2
  755. package/extensions/dm-lens/tools/lens-diagnostic-mark.js +12 -1
  756. package/extensions/dm-lens/tools/lens-diagnostics.js +74 -37
  757. package/extensions/dm-lens/tools/lsp-diagnostics.js +140 -25
  758. package/extensions/dm-lens/tools/lsp-navigation.js +64 -7
  759. package/extensions/dm-lens/tools/module-report.js +6 -6
  760. package/extensions/dm-lens/tools/shared.js +6 -0
  761. package/extensions/dm-mcp-adapter/THIRD_PARTY_NOTICES.md +1 -1
  762. package/extensions/dm-mcp-adapter/cli.js +265 -23
  763. package/extensions/dm-mcp-adapter/commands.js +83 -17
  764. package/extensions/dm-mcp-adapter/config.js +517 -92
  765. package/extensions/dm-mcp-adapter/direct-tool-surface.js +10 -8
  766. package/extensions/dm-mcp-adapter/direct-tools.js +54 -36
  767. package/extensions/dm-mcp-adapter/dist/abort.js +35 -0
  768. package/extensions/dm-mcp-adapter/dist/agent-dir.js +45 -0
  769. package/extensions/dm-mcp-adapter/dist/agent-plugin-loader.js +392 -0
  770. package/extensions/dm-mcp-adapter/dist/agent-plugin-provenance.js +26 -0
  771. package/extensions/dm-mcp-adapter/dist/bearer-command-resolver.js +182 -0
  772. package/extensions/dm-mcp-adapter/dist/claude-plugin-loader.js +350 -0
  773. package/extensions/dm-mcp-adapter/dist/config.js +1735 -0
  774. package/extensions/dm-mcp-adapter/dist/consent-manager.js +84 -0
  775. package/extensions/dm-mcp-adapter/dist/elicitation-handler.js +370 -0
  776. package/extensions/dm-mcp-adapter/dist/errors.js +225 -0
  777. package/extensions/dm-mcp-adapter/dist/http-ca.js +75 -0
  778. package/extensions/dm-mcp-adapter/dist/jev-client.js +359 -0
  779. package/extensions/dm-mcp-adapter/dist/jev-contracts.js +1 -0
  780. package/extensions/dm-mcp-adapter/dist/jev-key-store.js +189 -0
  781. package/extensions/dm-mcp-adapter/dist/json-schema-validator.js +70 -0
  782. package/extensions/dm-mcp-adapter/dist/lifecycle.js +387 -0
  783. package/extensions/dm-mcp-adapter/dist/logger.js +115 -0
  784. package/extensions/dm-mcp-adapter/dist/mcp-auth-fetch.js +86 -0
  785. package/extensions/dm-mcp-adapter/dist/mcp-auth-flow.js +956 -0
  786. package/extensions/dm-mcp-adapter/dist/mcp-auth.js +998 -0
  787. package/extensions/dm-mcp-adapter/dist/mcp-bearer-store.js +182 -0
  788. package/extensions/dm-mcp-adapter/dist/mcp-callback-server.js +380 -0
  789. package/extensions/dm-mcp-adapter/dist/mcp-oauth-provider.js +525 -0
  790. package/extensions/dm-mcp-adapter/dist/mcp-probe.js +151 -0
  791. package/extensions/dm-mcp-adapter/dist/mcp-tasks.js +300 -0
  792. package/extensions/dm-mcp-adapter/dist/mcp-trace.js +220 -0
  793. package/extensions/dm-mcp-adapter/dist/metadata-cache.js +323 -0
  794. package/extensions/dm-mcp-adapter/dist/npx-resolver.js +465 -0
  795. package/extensions/dm-mcp-adapter/dist/output-shape.js +312 -0
  796. package/extensions/dm-mcp-adapter/dist/package-mcp-loader.js +144 -0
  797. package/extensions/dm-mcp-adapter/dist/project-server-trust.js +186 -0
  798. package/extensions/dm-mcp-adapter/dist/request-headers-command.js +294 -0
  799. package/extensions/dm-mcp-adapter/dist/resource-tools.js +7 -0
  800. package/extensions/dm-mcp-adapter/dist/runtime-owner.js +94 -0
  801. package/extensions/dm-mcp-adapter/dist/sampling-handler.js +213 -0
  802. package/extensions/dm-mcp-adapter/dist/secure-keyring.js +191 -0
  803. package/extensions/dm-mcp-adapter/dist/server-manager.js +1594 -0
  804. package/extensions/dm-mcp-adapter/dist/session-approvals.js +127 -0
  805. package/extensions/dm-mcp-adapter/dist/session-recovery.js +83 -0
  806. package/extensions/dm-mcp-adapter/dist/state.js +1 -0
  807. package/extensions/dm-mcp-adapter/dist/ts-shape.js +157 -0
  808. package/extensions/dm-mcp-adapter/dist/types.js +286 -0
  809. package/extensions/dm-mcp-adapter/dist/ui-app-bridge-helpers.js +36 -0
  810. package/extensions/dm-mcp-adapter/dist/ui-resource-handler.js +204 -0
  811. package/extensions/dm-mcp-adapter/dist/ui-stream-types.js +58 -0
  812. package/extensions/dm-mcp-adapter/dist/ui-tool-visibility.js +26 -0
  813. package/extensions/dm-mcp-adapter/dist/unix-socket-transport.js +83 -0
  814. package/extensions/dm-mcp-adapter/dist/utils.js +418 -0
  815. package/extensions/dm-mcp-adapter/elicitation-handler.js +67 -2
  816. package/extensions/dm-mcp-adapter/failure-backoff.js +9 -0
  817. package/extensions/dm-mcp-adapter/host-managed.js +400 -0
  818. package/extensions/dm-mcp-adapter/http-ca.js +4 -0
  819. package/extensions/dm-mcp-adapter/index.js +347 -57
  820. package/extensions/dm-mcp-adapter/init.js +92 -44
  821. package/extensions/dm-mcp-adapter/jev-client.js +5 -5
  822. package/extensions/dm-mcp-adapter/jev-key-store.js +15 -2
  823. package/extensions/dm-mcp-adapter/mcp-auth-flow.js +10 -2
  824. package/extensions/dm-mcp-adapter/mcp-auth.js +2 -1
  825. package/extensions/dm-mcp-adapter/mcp-callback-server.js +1 -1
  826. package/extensions/dm-mcp-adapter/mcp-code.js +174 -87
  827. package/extensions/dm-mcp-adapter/mcp-keyring-helper.cjs +1 -1
  828. package/extensions/dm-mcp-adapter/mcp-oauth-provider.js +3 -2
  829. package/extensions/dm-mcp-adapter/mcp-output-guard.js +19 -5
  830. package/extensions/dm-mcp-adapter/mcp-panel.js +59 -12
  831. package/extensions/dm-mcp-adapter/mcp-script-wasm.js +22 -0
  832. package/extensions/dm-mcp-adapter/mcp-script-worker.mjs +227 -111
  833. package/extensions/dm-mcp-adapter/mcp-setup-panel.js +500 -258
  834. package/extensions/dm-mcp-adapter/mcp-status.js +9 -2
  835. package/extensions/dm-mcp-adapter/mcp-trace.js +5 -0
  836. package/extensions/dm-mcp-adapter/metadata-cache.js +68 -11
  837. package/extensions/dm-mcp-adapter/namespace-tools.js +20 -5
  838. package/extensions/dm-mcp-adapter/onboarding-state.js +11 -1
  839. package/extensions/dm-mcp-adapter/output-shape.js +312 -0
  840. package/extensions/dm-mcp-adapter/package-mcp-loader.js +15 -6
  841. package/extensions/dm-mcp-adapter/package.json +6 -15
  842. package/extensions/dm-mcp-adapter/panel-keys.js +13 -0
  843. package/extensions/dm-mcp-adapter/pi-builtin-mcp.js +26 -0
  844. package/extensions/dm-mcp-adapter/pi-signin-import.js +121 -0
  845. package/extensions/dm-mcp-adapter/project-server-trust.js +186 -0
  846. package/extensions/dm-mcp-adapter/prompts.js +80 -7
  847. package/extensions/dm-mcp-adapter/proxy-modes.js +219 -158
  848. package/extensions/dm-mcp-adapter/runtime-protocol.js +342 -0
  849. package/extensions/dm-mcp-adapter/search-ranking.js +8 -6
  850. package/extensions/dm-mcp-adapter/semantic-search.js +5 -4
  851. package/extensions/dm-mcp-adapter/server-manager.js +108 -26
  852. package/extensions/dm-mcp-adapter/session-recovery.js +3 -2
  853. package/extensions/dm-mcp-adapter/skills/mcp-scripting/SKILL.md +24 -28
  854. package/extensions/dm-mcp-adapter/skills/mcp-scripting/references/jev.md +3 -0
  855. package/extensions/dm-mcp-adapter/test-runner.mjs +1 -1
  856. package/extensions/dm-mcp-adapter/tool-approval.js +17 -7
  857. package/extensions/dm-mcp-adapter/tool-metadata.js +4 -2
  858. package/extensions/dm-mcp-adapter/tool-parameters.js +4 -0
  859. package/extensions/dm-mcp-adapter/tool-result-renderer.js +68 -7
  860. package/extensions/dm-mcp-adapter/ts-shape.js +1 -1
  861. package/extensions/dm-mcp-adapter/ui-server.js +24 -20
  862. package/extensions/dm-mcp-adapter/unix-socket-transport.js +1 -1
  863. package/extensions/dm-mcp-adapter/utils.js +37 -1
  864. package/extensions/dm-ponytail/extensions/ponytail.mjs +37 -17
  865. package/extensions/dm-ponytail/hooks/claude-codex-hooks.json +3 -3
  866. package/extensions/dm-ponytail/hooks/copilot-hooks.json +4 -4
  867. package/extensions/dm-ponytail/hooks/ponytail-activate.js +46 -13
  868. package/extensions/dm-ponytail/hooks/ponytail-config.js +6 -5
  869. package/extensions/dm-ponytail/hooks/ponytail-instructions.js +29 -33
  870. package/extensions/dm-ponytail/hooks/ponytail-map.js +116 -0
  871. package/extensions/dm-ponytail/hooks/ponytail-mode-tracker.js +26 -13
  872. package/extensions/dm-ponytail/hooks/ponytail-runtime.js +23 -9
  873. package/extensions/dm-ponytail/hooks/ponytail-subagent.js +15 -3
  874. package/extensions/dm-ponytail/hooks/qoder-hooks.json +3 -3
  875. package/extensions/dm-ponytail/package.json +1 -1
  876. package/extensions/dm-ponytail/pi-extension/index.js +37 -17
  877. package/extensions/dm-ponytail/pi-extension/package.json +1 -1
  878. package/extensions/dm-ponytail/skills/plugin.json +5 -0
  879. package/extensions/dm-ponytail/skills/ponytail/SKILL.md +33 -101
  880. package/extensions/dm-ponytail/skills/ponytail-audit/SKILL.md +89 -27
  881. package/extensions/dm-ponytail/skills/ponytail-debt/SKILL.md +13 -12
  882. package/extensions/dm-ponytail/skills/ponytail-gain/SKILL.md +21 -18
  883. package/extensions/dm-ponytail/skills/ponytail-help/SKILL.md +13 -14
  884. package/extensions/dm-ponytail/skills/ponytail-review/SKILL.md +96 -52
  885. package/extensions/dm-subagents/agents/oracle.md +8 -19
  886. package/extensions/dm-subagents/agents/researcher.md +0 -3
  887. package/extensions/dm-subagents/agents/reviewer.md +17 -61
  888. package/extensions/dm-subagents/agents/scout.md +1 -4
  889. package/extensions/dm-subagents/agents/worker.md +8 -25
  890. package/extensions/dm-subagents/index.js +5 -0
  891. package/extensions/dm-subagents/install.mjs +47 -62
  892. package/extensions/dm-subagents/package.json +6 -5
  893. package/extensions/dm-subagents/prompts/council.md +1 -1
  894. package/extensions/dm-subagents/prompts/review-loop.md +1 -1
  895. package/extensions/dm-subagents/skills/council-mode/SKILL.md +1 -1
  896. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +13 -6
  897. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +3 -3
  898. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +79 -78
  899. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +18 -14
  900. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +1 -1
  901. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +46 -49
  902. package/extensions/dm-subagents/src/agents/advertised-agent-prompt.js +18 -32
  903. package/extensions/dm-subagents/src/agents/agent-management.js +7 -2
  904. package/extensions/dm-subagents/src/agents/agent-memory.js +3 -3
  905. package/extensions/dm-subagents/src/agents/agent-scope.js +3 -0
  906. package/extensions/dm-subagents/src/agents/agent-serializer.js +12 -1
  907. package/extensions/dm-subagents/src/agents/agents.js +217 -120
  908. package/extensions/dm-subagents/src/api/inspectors.js +10 -0
  909. package/extensions/dm-subagents/src/api/preflight.js +43 -6
  910. package/extensions/dm-subagents/src/extension/config.js +35 -2
  911. package/extensions/dm-subagents/src/extension/control-notices.js +3 -7
  912. package/extensions/dm-subagents/src/extension/declaration-pinning.js +127 -0
  913. package/extensions/dm-subagents/src/extension/doctor.js +4 -7
  914. package/extensions/dm-subagents/src/extension/fanout-child.js +15 -7
  915. package/extensions/dm-subagents/src/extension/herdr-dm-bridge.js +2 -0
  916. package/extensions/dm-subagents/src/extension/index.js +231 -332
  917. package/extensions/dm-subagents/src/extension/public-execution.js +63 -33
  918. package/extensions/dm-subagents/src/extension/reply-workflow-script.js +65 -0
  919. package/extensions/dm-subagents/src/extension/rpc.js +42 -16
  920. package/extensions/dm-subagents/src/extension/schemas.js +73 -152
  921. package/extensions/dm-subagents/src/extension/subagent-guide.js +92 -7
  922. package/extensions/dm-subagents/src/extension/subagent-options.js +47 -0
  923. package/extensions/dm-subagents/src/extension/tool-activation.js +57 -89
  924. package/extensions/dm-subagents/src/extension/tool-description.js +56 -47
  925. package/extensions/dm-subagents/src/extension/upgrade-notice.js +36 -0
  926. package/extensions/dm-subagents/src/inspectors/actions.js +34 -11
  927. package/extensions/dm-subagents/src/inspectors/plugins.js +71 -2
  928. package/extensions/dm-subagents/src/inspectors/tmux/actions.js +173 -0
  929. package/extensions/dm-subagents/src/inspectors/tmux/client.js +63 -0
  930. package/extensions/dm-subagents/src/inspectors/tmux/plugin.js +14 -0
  931. package/extensions/dm-subagents/src/integrations/herdr-status.js +26 -49
  932. package/extensions/dm-subagents/src/integrations/program-status.js +179 -0
  933. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +77 -4
  934. package/extensions/dm-subagents/src/intercom/result-intercom.js +3 -2
  935. package/extensions/dm-subagents/src/intercom/supervisor-ui.js +2 -152
  936. package/extensions/dm-subagents/src/missions/goal-driver.js +47 -34
  937. package/extensions/dm-subagents/src/missions/store.js +33 -4
  938. package/extensions/dm-subagents/src/profiles/profiles.js +22 -15
  939. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +49 -6
  940. package/extensions/dm-subagents/src/runs/background/async-execution.js +301 -139
  941. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +65 -24
  942. package/extensions/dm-subagents/src/runs/background/async-resume.js +9 -3
  943. package/extensions/dm-subagents/src/runs/background/async-retention.js +40 -15
  944. package/extensions/dm-subagents/src/runs/background/await-async-run.js +68 -0
  945. package/extensions/dm-subagents/src/runs/background/binary-bootstrap.js +2 -1
  946. package/extensions/dm-subagents/src/runs/background/calendar-schedule.js +90 -0
  947. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +11 -8
  948. package/extensions/dm-subagents/src/runs/background/control-channel.js +89 -5
  949. package/extensions/dm-subagents/src/runs/background/fleet-view.js +5 -5
  950. package/extensions/dm-subagents/src/runs/background/notify.js +170 -11
  951. package/extensions/dm-subagents/src/runs/background/pid-namespace.js +17 -0
  952. package/extensions/dm-subagents/src/runs/background/result-files.js +80 -6
  953. package/extensions/dm-subagents/src/runs/background/result-watcher.js +92 -65
  954. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +2 -2
  955. package/extensions/dm-subagents/src/runs/background/run-child-session.js +34 -10
  956. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +8 -6
  957. package/extensions/dm-subagents/src/runs/background/run-status.js +25 -15
  958. package/extensions/dm-subagents/src/runs/background/runner-aliases.js +4 -2
  959. package/extensions/dm-subagents/src/runs/background/runner-child-launch.js +3 -0
  960. package/extensions/dm-subagents/src/runs/background/runner-http-dispatcher.js +2 -1
  961. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +270 -79
  962. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +18 -3
  963. package/extensions/dm-subagents/src/runs/background/subagent-runner-bootstrap.js +4 -1
  964. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +123 -33
  965. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +33 -20
  966. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +42 -1
  967. package/extensions/dm-subagents/src/runs/background/wait-completions.js +1 -0
  968. package/extensions/dm-subagents/src/runs/background/wait-tool.js +36 -26
  969. package/extensions/dm-subagents/src/runs/background/workflow-terminal-proof.js +39 -26
  970. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +58 -26
  971. package/extensions/dm-subagents/src/runs/foreground/command-action.js +37 -0
  972. package/extensions/dm-subagents/src/runs/foreground/execution.js +132 -32
  973. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +1 -0
  974. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +5 -5
  975. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +683 -325
  976. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +3 -0
  977. package/extensions/dm-subagents/src/runs/shared/child-commands.js +252 -0
  978. package/extensions/dm-subagents/src/runs/shared/child-hooks.js +6 -5
  979. package/extensions/dm-subagents/src/runs/shared/child-launch.js +13 -1
  980. package/extensions/dm-subagents/src/runs/shared/child-session.js +183 -34
  981. package/extensions/dm-subagents/src/runs/shared/child-tool-plan.js +17 -14
  982. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +87 -1
  983. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +11 -85
  984. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +3 -0
  985. package/extensions/dm-subagents/src/runs/shared/effective-system-prompt.js +1 -2
  986. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +57 -6
  987. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +6 -3
  988. package/extensions/dm-subagents/src/runs/shared/herdr-placed-run.js +13 -6
  989. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +1 -1
  990. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +66 -14
  991. package/extensions/dm-subagents/src/runs/shared/model-resolution-diagnostic.js +25 -5
  992. package/extensions/dm-subagents/src/runs/shared/model-resolution.js +55 -11
  993. package/extensions/dm-subagents/src/runs/shared/model-scope.js +23 -10
  994. package/extensions/dm-subagents/src/runs/shared/nested-events.js +3 -0
  995. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +55 -7
  996. package/extensions/dm-subagents/src/runs/shared/partial-output.js +26 -0
  997. package/extensions/dm-subagents/src/runs/shared/run-history.js +41 -0
  998. package/extensions/dm-subagents/src/runs/shared/runner-launcher.js +21 -0
  999. package/extensions/dm-subagents/src/runs/shared/single-output.js +67 -26
  1000. package/extensions/dm-subagents/src/runs/shared/structured-output.js +24 -7
  1001. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +32 -20
  1002. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +68 -29
  1003. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +1 -1
  1004. package/extensions/dm-subagents/src/runs/shared/workflow-async-child-guidance.js +1 -1
  1005. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-apply.js +169 -0
  1006. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +41 -20
  1007. package/extensions/dm-subagents/src/runs/shared/worktree-lock.js +38 -0
  1008. package/extensions/dm-subagents/src/runs/shared/worktree.js +10 -1
  1009. package/extensions/dm-subagents/src/shared/atomic-json.js +2 -1
  1010. package/extensions/dm-subagents/src/shared/disabled-features.js +101 -0
  1011. package/extensions/dm-subagents/src/shared/dm-declarations.js +14 -0
  1012. package/extensions/dm-subagents/src/shared/dm-safeguards.js +41 -0
  1013. package/extensions/dm-subagents/src/shared/dm-settlement.js +48 -0
  1014. package/extensions/dm-subagents/src/shared/edit-distance.js +23 -0
  1015. package/extensions/dm-subagents/src/shared/extension-context.js +4 -0
  1016. package/extensions/dm-subagents/src/shared/file-lease.js +89 -0
  1017. package/extensions/dm-subagents/src/shared/fork-context.js +0 -1
  1018. package/extensions/dm-subagents/src/shared/formatters.js +1 -6
  1019. package/extensions/dm-subagents/src/shared/model-info.js +23 -0
  1020. package/extensions/dm-subagents/src/shared/package-version.js +12 -0
  1021. package/extensions/dm-subagents/src/shared/parent-wake.js +67 -0
  1022. package/extensions/dm-subagents/src/shared/pruned-fork.js +6 -2
  1023. package/extensions/dm-subagents/src/shared/required-child-extensions.js +35 -5
  1024. package/extensions/dm-subagents/src/shared/runtime-module-path.js +9 -0
  1025. package/extensions/dm-subagents/src/shared/settings-file-lease.js +31 -0
  1026. package/extensions/dm-subagents/src/shared/types.js +3 -1
  1027. package/extensions/dm-subagents/src/shared/utils.js +7 -7
  1028. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +2 -2
  1029. package/extensions/dm-subagents/src/slash/slash-commands.js +25 -15
  1030. package/extensions/dm-subagents/src/slash/subagent-cost.js +38 -7
  1031. package/extensions/dm-subagents/src/slash/subagents-admin.js +1 -1
  1032. package/extensions/dm-subagents/src/tui/dm-mouse-region.js +12 -0
  1033. package/extensions/dm-subagents/src/tui/fleet-status.js +12 -6
  1034. package/extensions/dm-subagents/src/tui/fleet-transcript.js +6 -2
  1035. package/extensions/dm-subagents/src/tui/fleet.js +20 -6
  1036. package/extensions/dm-subagents/src/tui/render.js +126 -72
  1037. package/extensions/dm-subagents/src/tui/running-tone.js +20 -0
  1038. package/extensions/dm-subagents/src/tui/subagent-messages.js +249 -0
  1039. package/extensions/dm-subagents/src/watchdog/diff-tool.js +19 -11
  1040. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +2 -2
  1041. package/extensions/dm-subagents/src/watchdog/register-child.js +2 -2
  1042. package/extensions/dm-subagents/src/watchdog/register-main.js +4 -24
  1043. package/extensions/dm-subagents/src/watchdog/render.js +1 -19
  1044. package/extensions/dm-subagents/src/watchdog/review.js +3 -3
  1045. package/extensions/dm-subagents/src/watchdog/runtime.js +6 -2
  1046. package/extensions/dm-subagents/src/watchdog/settings.js +22 -17
  1047. package/extensions/dm-subagents/src/watchdog/tool-actions.js +2 -2
  1048. package/extensions/dm-subagents/src/watchdog/turn-delta.js +1 -1
  1049. package/extensions/dm-subagents/src/workflows/chat-progress.js +2 -2
  1050. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +116 -45
  1051. package/extensions/dm-subagents/src/workflows/structured-workflow-scripts.js +154 -0
  1052. package/extensions/dm-subagents/src/workflows/workflow-checklist.js +3 -0
  1053. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +7 -4
  1054. package/extensions/dm-subagents/src/workflows/workflow-resources.js +52 -17
  1055. package/extensions/dm-subagents/src/workflows/workflow-reuse.js +87 -0
  1056. package/extensions/dm-subagents/src/workflows/workflow-revival.js +80 -0
  1057. package/extensions/dm-tty/control.js +150 -0
  1058. package/extensions/dm-tty/index.js +122 -0
  1059. package/extensions/dm-tty/package.json +20 -0
  1060. package/extensions/dm-tty/pty.js +213 -0
  1061. package/extensions/dm-tty/pty_bridge.py +266 -0
  1062. package/extensions/dm-tty/server.js +438 -0
  1063. package/extensions/dm-tty/sessions.js +97 -0
  1064. package/extensions/dm-tty/standalone.js +75 -0
  1065. package/extensions/dm-tty/web/client.js +1141 -0
  1066. package/extensions/dm-tty/web/index.html +117 -0
  1067. package/extensions/dm-tty/web/style.css +73 -0
  1068. package/extensions/dm-web-access/brave-rate-limit.js +160 -0
  1069. package/extensions/dm-web-access/brave.js +62 -11
  1070. package/extensions/dm-web-access/ceramic.js +197 -0
  1071. package/extensions/dm-web-access/chrome-cookies.js +69 -21
  1072. package/extensions/dm-web-access/curator-page.js +12 -2
  1073. package/extensions/dm-web-access/curator-server.js +10 -0
  1074. package/extensions/dm-web-access/declared-web-links.js +1 -1
  1075. package/extensions/dm-web-access/degoog.js +288 -0
  1076. package/extensions/dm-web-access/dist/index.js +28404 -0
  1077. package/extensions/dm-web-access/dist/mcp-cli.js +28186 -0
  1078. package/extensions/dm-web-access/duckduckgo.js +6 -3
  1079. package/extensions/dm-web-access/endpoint-pdf-extract.js +210 -0
  1080. package/extensions/dm-web-access/exa.js +17 -35
  1081. package/extensions/dm-web-access/extract.js +63 -10
  1082. package/extensions/dm-web-access/firecrawl.js +30 -4
  1083. package/extensions/dm-web-access/gemini-search.js +117 -37
  1084. package/extensions/dm-web-access/gemini-web.js +7 -7
  1085. package/extensions/dm-web-access/github-extract.js +28 -2
  1086. package/extensions/dm-web-access/github-issue-pr.js +88 -73
  1087. package/extensions/dm-web-access/index.js +230 -1161
  1088. package/extensions/dm-web-access/keenable.js +197 -0
  1089. package/extensions/dm-web-access/mcp-cli.js +30 -0
  1090. package/extensions/dm-web-access/mcp-server.js +51 -0
  1091. package/extensions/dm-web-access/mcp-tool-definitions.js +93 -0
  1092. package/extensions/dm-web-access/openai-search.js +70 -20
  1093. package/extensions/dm-web-access/opencode-session-headers.js +1 -1
  1094. package/extensions/dm-web-access/package.json +4 -1
  1095. package/extensions/dm-web-access/page-query.js +5 -10
  1096. package/extensions/dm-web-access/parallel-mcp.js +2 -1
  1097. package/extensions/dm-web-access/pdf-extract.js +34 -1
  1098. package/extensions/dm-web-access/perplexity.js +68 -51
  1099. package/extensions/dm-web-access/query-rewrite.js +3 -4
  1100. package/extensions/dm-web-access/scripts/build.js +8 -0
  1101. package/extensions/dm-web-access/ssrf-protection.js +10 -8
  1102. package/extensions/dm-web-access/storage.js +79 -76
  1103. package/extensions/dm-web-access/summary-model-scope.js +5 -64
  1104. package/extensions/dm-web-access/summary-review.js +35 -9
  1105. package/extensions/dm-web-access/tavily.js +69 -22
  1106. package/extensions/dm-web-access/tool-activation.js +44 -26
  1107. package/extensions/dm-web-access/tool-arguments.js +21 -0
  1108. package/extensions/dm-web-access/utils.js +17 -7
  1109. package/extensions/dm-web-access/video-extract.js +1 -1
  1110. package/extensions/dm-web-access/web-tool-contract.js +0 -0
  1111. package/extensions/dm-web-access/web-tool-core.js +1312 -0
  1112. package/extensions/dm-web-access/you.js +155 -0
  1113. package/extensions/dm-web-access/youtube-extract.js +2 -2
  1114. package/extensions/dm-web-access/zai.js +159 -0
  1115. package/package.json +13 -9
@@ -22,13 +22,23 @@ import {
22
22
  import { cascadeSettleWaitMs } from "./cascade-budget.js";
23
23
  import { logCascade } from "./cascade-logger.js";
24
24
  import { normalizeMapKey } from "./path-utils.js";
25
+ import {
26
+ boundDeferredTargets,
27
+ mergeDeferredTargets,
28
+ TEST_RUNNER_MAX_PERSISTED_TARGETS
29
+ } from "./deferred-test-targets.js";
25
30
  import { compareOrdinal } from "./string-utils.js";
31
+
32
+ export { TEST_RUNNER_MAX_PERSISTED_TARGETS };
26
33
  import {
27
34
  resolveRunnerPath,
28
35
  toRunnerDisplayPath
29
36
  } from "./dispatch/runner-context.js";
30
37
  import { getKnipIgnorePatterns } from "./file-utils.js";
31
- import { formatCacheAgeLabel } from "./finding-delivery-gate.js";
38
+ import {
39
+ admitsProjectWideFindings,
40
+ formatCacheAgeLabel
41
+ } from "./finding-delivery-gate.js";
32
42
  import {
33
43
  getFullScanWallClockMs,
34
44
  isWorkspaceSweepActive,
@@ -40,12 +50,23 @@ import { isSecretWarning, secretLocationKey } from "./secret-findings.js";
40
50
  import { govulncheckLane } from "./turn-end/lanes/govulncheck.js";
41
51
  import { secretsLane } from "./turn-end/lanes/secrets.js";
42
52
  import {
53
+ planDeliveryHolds,
54
+ stillReportedParked
55
+ } from "./turn-end/delivery-holds.js";
56
+ import { isHardFailureSummary } from "./hard-failure-summary.js";
57
+ import {
58
+ MAX_KNIP_ROOTS_PER_TURN,
59
+ resolveKnipScanRoots
60
+ } from "./knip-scan-roots.js";
61
+ import {
62
+ DEAD_CODE_DELTA_MAX_SHOWN,
43
63
  deadCodeIssueKey,
44
64
  deadCodeIssues,
45
65
  formatDeadCodeDelta,
46
66
  stableFindingKey
47
67
  } from "./dead-code-client.js";
48
68
  import { logDeadCodeScan } from "./dead-code-logger.js";
69
+ import { scopeCell } from "./session-scope.js";
49
70
  import {
50
71
  PROJECT_DIAGNOSTICS_CACHE_VERSION,
51
72
  writeProjectDiagnosticsDeltaReport
@@ -53,6 +74,7 @@ import {
53
74
  import { deadCodeIssueToProjectDiagnostic } from "./project-diagnostics/runner-adapters/dead-code.js";
54
75
  import { trivyFindingToProjectDiagnostic } from "./project-diagnostics/runner-adapters/trivy.js";
55
76
  import { knipIssuesToProjectDiagnostics } from "./project-diagnostics/runner-adapters/knip.js";
77
+ import { hasAmbientPythonEnvironment } from "./python-environment.js";
56
78
  import { logLatency } from "./latency-logger.js";
57
79
  import {
58
80
  getLspBudgetIdleTimeoutMs,
@@ -68,6 +90,7 @@ import {
68
90
  isRunnerErrorResult,
69
91
  RUNNERS
70
92
  } from "./test-runner-client.js";
93
+ import { createTurnEndTestRoots } from "./test-target-roots.js";
71
94
  import {
72
95
  MAX_ADVISORY_AFFECTED_FILES,
73
96
  gateFindingsByPathFreshness,
@@ -78,17 +101,20 @@ import {
78
101
  sweepInlineBlockerFreshness
79
102
  } from "./blocker-freshness.js";
80
103
  import { sweepInlineBlockerPastEof } from "./blocker-past-eof.js";
81
- import { getLSPService } from "./lsp/index.js";
104
+ import { getLSPService } from "./lsp/capabilities.js";
82
105
  import {
83
106
  drainPendingAuxCapEvictedCount,
84
107
  drainPendingAuxiliaryCoverage,
108
+ isAuxBacklogPublished,
85
109
  isPendingAuxiliaryPastRearmTtl,
86
110
  rearmPendingAuxiliaryCoverage,
87
111
  MAX_LATE_AUX_REARMS,
88
- pendingAuxiliaryCoverageSize
112
+ pendingAuxiliaryCoverageSize,
113
+ canRearmPendingAuxiliary
89
114
  } from "./lsp/pending-aux-coverage.js";
90
115
  import { convertLspDiagnostics } from "./dispatch/utils/lsp-diagnostics.js";
91
116
  import { retagAuxiliaryDiagnostics } from "./dispatch/auxiliary-lsp.js";
117
+ import { findingsResult, hasUsableResult } from "./dispatch/types.js";
92
118
  import {
93
119
  runPersistentReverify
94
120
  } from "./persistent-reverify.js";
@@ -98,6 +124,10 @@ import {
98
124
  filterFindingsByDisposition
99
125
  } from "./dispatch/finding-policy.js";
100
126
  import { detectFileRole } from "./file-role.js";
127
+ import {
128
+ judgeDeferredRunnerFindings,
129
+ recordDeferredRunnerBlockers
130
+ } from "./deferred-runner-blockers.js";
101
131
  import {
102
132
  applyInlineBlockerPolicy,
103
133
  summarizeInlineBlockerPolicy
@@ -105,7 +135,8 @@ import {
105
135
  import {
106
136
  drainPendingRunnerFindings,
107
137
  dropStaleRunnerFindings,
108
- pendingRunnerFindingsSize
138
+ pendingRunnerFindingsSize,
139
+ requeueRunnerFindings
109
140
  } from "./dispatch/pending-runner-findings.js";
110
141
  import {
111
142
  incrementDegradationCount,
@@ -134,23 +165,9 @@ import {
134
165
  const LATE_AUX_COVERAGE_GAP_DETAIL_CAP_PER_TURN = 20;
135
166
  export const TEST_RUNNER_BATCH_CONCURRENCY = 4;
136
167
  export const TEST_RUNNER_MAX_TARGETS = 12;
168
+ const TURN_END_SELECTION_ROOT_ROWS = 8;
137
169
  export const TEST_RUNNER_BATCH_BUDGET_MS = 20000;
138
170
  export const TEST_RUNNER_MAX_DEFERRALS = 2;
139
- export const TEST_RUNNER_MAX_PERSISTED_TARGETS = 64;
140
- function deferralEntryKey(entry) {
141
- return `${entry.sessionId ?? ""}\x00${normalizeMapKey(path.resolve(entry.testFile))}`;
142
- }
143
- function mergeDeferredTargets(existing, incoming) {
144
- const byKey = new Map;
145
- for (const entry of [...existing, ...incoming]) {
146
- const key = deferralEntryKey(entry);
147
- const prior = byKey.get(key);
148
- if (prior && (prior.attempts ?? 0) >= (entry.attempts ?? 0))
149
- continue;
150
- byKey.set(key, entry);
151
- }
152
- return [...byKey.values()];
153
- }
154
171
  export async function runTestTargetsBounded(args) {
155
172
  const results = [];
156
173
  if (args.targets.length === 0)
@@ -224,6 +241,79 @@ export async function runTestTargetsBounded(args) {
224
241
  function wouldPoisonCache(prev, next) {
225
242
  return !next.success && prev?.data.success === true;
226
243
  }
244
+ const LATE_DEAD_CODE_SCANS = "dead-code-late-scans";
245
+ function lateDeadCodeScansOf(scope) {
246
+ return scopeCell(scope, LATE_DEAD_CODE_SCANS, () => new Map);
247
+ }
248
+ function joinedEarlierScan(result, askedAt) {
249
+ return result.scannedAt !== undefined && Date.parse(result.scannedAt) < askedAt;
250
+ }
251
+ function withRowForFailureWrite(scan, cacheManager, cacheKey, cwd, startRow) {
252
+ return scan.then((result) => result.success || startRow?.data.success === true ? { result, row: startRow } : cacheManager.readCacheAsync(cacheKey, cwd).then((row) => ({ result, row })));
253
+ }
254
+ function lateDeadCodeScanKey(client, cwd) {
255
+ return `${client.id}\x00${cwd}`;
256
+ }
257
+ function deadCodeScanEvent(client, cwd, result, durationMs) {
258
+ return {
259
+ language: client.language,
260
+ root: cwd,
261
+ success: result.success,
262
+ cached: false,
263
+ unusedExports: result.unusedExports.length,
264
+ unusedFiles: result.unusedFiles.length,
265
+ unusedDeps: result.unusedDeps.length,
266
+ unlistedDeps: result.unlistedDeps.length,
267
+ durationMs: result.durationMs ?? durationMs,
268
+ ...result.excludedWorktrees !== undefined && {
269
+ excludedWorktrees: result.excludedWorktrees
270
+ },
271
+ ...!result.success && { reason: result.summary }
272
+ };
273
+ }
274
+ function dropLateDeadCodeScan(scans, key, client, reason) {
275
+ scans.delete(key);
276
+ incrementDegradationCount({
277
+ kind: "dead-code-late-scan-dropped",
278
+ subject: client.id,
279
+ reason
280
+ });
281
+ }
282
+ function parkLateDeadCodeScan(args) {
283
+ const { scope, cacheManager, client, cwd, cacheKey, startedAt } = args;
284
+ const scans = lateDeadCodeScansOf(scope);
285
+ const key = lateDeadCodeScanKey(client, cwd);
286
+ const entry = {
287
+ files: args.files,
288
+ previousScan: args.previousScan,
289
+ carry: new Set,
290
+ settled: null,
291
+ askedAt: startedAt
292
+ };
293
+ scans.set(key, entry);
294
+ withRowForFailureWrite(args.scan, cacheManager, cacheKey, cwd, entry.previousScan ? { data: entry.previousScan } : null).then(({ result, row }) => {
295
+ if (!scope.isLive()) {
296
+ dropLateDeadCodeScan(scans, key, client, "session-ended");
297
+ return;
298
+ }
299
+ const durationMs = Date.now() - startedAt;
300
+ const cacheKept = wouldPoisonCache(row, result);
301
+ if (!cacheKept) {
302
+ cacheManager.writeCache(cacheKey, result, cwd, {
303
+ scanDurationMs: durationMs
304
+ });
305
+ }
306
+ logDeadCodeScan({
307
+ ...deadCodeScanEvent(client, cwd, result, durationMs),
308
+ ...cacheKept && { cacheKept }
309
+ });
310
+ if (!result.success) {
311
+ dropLateDeadCodeScan(scans, key, client, `scan-failed: ${result.summary}`);
312
+ return;
313
+ }
314
+ entry.settled = result;
315
+ }, (err) => dropLateDeadCodeScan(scans, key, client, `scan-threw: ${err}`));
316
+ }
227
317
  let lspIdleResetTimeout = null;
228
318
  let pendingSweepRearm = null;
229
319
  function emitIdleResetReporterWarning(reportErr) {
@@ -297,22 +387,66 @@ export function cancelLSPIdleReset() {
297
387
  pendingSweepRearm = null;
298
388
  }
299
389
  }
300
- function capTurnEndMessage(content) {
390
+ function capTurnEndMessage(content, held = 0) {
301
391
  const maxLines = RUNTIME_CONFIG.turnEnd.maxLines;
302
392
  const maxChars = RUNTIME_CONFIG.turnEnd.maxChars;
303
- let out = content;
304
- const lines = out.split(`
393
+ const marker = held > 0 ? `... (truncated; ${held} held for the next turn)` : "... (truncated)";
394
+ let kept = content;
395
+ let cut = false;
396
+ const lines = kept.split(`
305
397
  `);
306
398
  if (lines.length > maxLines) {
307
- out = `${lines.slice(0, maxLines).join(`
308
- `)}
309
- ... (truncated)`;
399
+ kept = lines.slice(0, maxLines).join(`
400
+ `);
401
+ cut = true;
402
+ }
403
+ if (kept.length > maxChars) {
404
+ kept = sliceAtCodePointBoundaries(kept, 0, maxChars);
405
+ cut = true;
310
406
  }
311
- if (out.length > maxChars) {
312
- out = `${out.slice(0, maxChars)}
313
- ... (truncated)`;
407
+ return cut ? `${kept}
408
+ ${marker}` : content;
409
+ }
410
+ function turnEndKeptChars(content) {
411
+ const maxLines = RUNTIME_CONFIG.turnEnd.maxLines;
412
+ const maxChars = RUNTIME_CONFIG.turnEnd.maxChars;
413
+ const lines = content.split(`
414
+ `);
415
+ const kept = lines.length > maxLines ? lines.slice(0, maxLines).join(`
416
+ `).length : content.length;
417
+ return Math.min(kept, sliceAtCodePointBoundaries(content, 0, maxChars).length);
418
+ }
419
+ function sliceAtCodePointBoundaries(value, start, end) {
420
+ if (start > 0 && start < value.length && isLowSurrogate(value.charCodeAt(start)) && isHighSurrogate(value.charCodeAt(start - 1))) {
421
+ start += 1;
422
+ }
423
+ if (end > 0 && end < value.length && isLowSurrogate(value.charCodeAt(end)) && isHighSurrogate(value.charCodeAt(end - 1))) {
424
+ end -= 1;
425
+ }
426
+ return value.slice(start, end);
427
+ }
428
+ function isHighSurrogate(codeUnit) {
429
+ return codeUnit >= 55296 && codeUnit <= 56319;
430
+ }
431
+ function isLowSurrogate(codeUnit) {
432
+ return codeUnit >= 56320 && codeUnit <= 57343;
433
+ }
434
+ const RESOLVED_SHARE_OF_CHARS = 0.4;
435
+ const RESOLVED_MAX_LINES = 5;
436
+ function formatWriteOrdinal(n) {
437
+ const mod100 = n % 100;
438
+ if (mod100 >= 11 && mod100 <= 13)
439
+ return `${n}th`;
440
+ switch (n % 10) {
441
+ case 1:
442
+ return `${n}st`;
443
+ case 2:
444
+ return `${n}nd`;
445
+ case 3:
446
+ return `${n}rd`;
447
+ default:
448
+ return `${n}th`;
314
449
  }
315
- return out;
316
450
  }
317
451
  export async function handleTurnEnd(deps) {
318
452
  const {
@@ -337,21 +471,25 @@ export async function handleTurnEnd(deps) {
337
471
  dbg(`turn_end: retaining newer turn state (dispatch=${turnIndexAtDispatch}, current=${runtime.turnIndex})`);
338
472
  return;
339
473
  }
340
- cacheManager.clearTurnState(cwd, currentOwner);
474
+ cacheManager.clearTurnState(cwd, currentOwner, isSecondarySession ? sessionId : undefined);
341
475
  };
342
476
  updateHeartbeat().catch(() => {});
343
477
  const cwd = ctxCwd ?? process.cwd();
344
- let turnState = cacheManager.readTurnState(cwd);
478
+ const isSecondarySession = deps.sessionScope?.role === "secondary";
479
+ const sessionRole = isSecondarySession ? "secondary" : "primary";
480
+ const allowProjectWideFindings = admitsProjectWideFindings(sessionRole);
481
+ const turnStateSessionId = isSecondarySession ? sessionId : undefined;
482
+ let turnState = cacheManager.readTurnState(cwd, turnStateSessionId);
345
483
  const currentOwner = {
346
484
  ...owner ?? {
347
485
  kind: "pi",
348
- id: runtime.telemetrySessionId,
486
+ id: sessionId ?? runtime.telemetrySessionId,
349
487
  pid: process.pid,
350
488
  lastSeen: new Date().toISOString()
351
489
  },
352
490
  sessionStartedAt: owner?.sessionStartedAt ?? runtime.sessionStartedAt
353
491
  };
354
- const access = cacheManager.getTurnStateAccess(cwd, currentOwner);
492
+ const access = isSecondarySession ? "owned" : cacheManager.getTurnStateAccess(cwd, currentOwner);
355
493
  const gateOwnerLabel = turnState.owner ? `${turnState.owner.kind}:${turnState.owner.id}` : turnState.sessionId ? `legacy:${turnState.sessionId}` : "none";
356
494
  const sameProcessPiSessionHandoff = access === "foreign-live" && currentOwner.kind === "pi" && turnState.owner?.kind === "pi" && turnState.owner.pid === process.pid && turnState.owner.id !== currentOwner.id;
357
495
  if (access === "foreign-live" && !sameProcessPiSessionHandoff) {
@@ -361,9 +499,10 @@ export async function handleTurnEnd(deps) {
361
499
  if (access === "available" && (turnState.files || turnState.owner || turnState.sessionId)) {
362
500
  dbg("turn_end: evicting stale turn-state owner");
363
501
  clearOwnedTurnState();
364
- turnState = cacheManager.readTurnState(cwd);
502
+ turnState = cacheManager.readTurnState(cwd, turnStateSessionId);
365
503
  }
366
- const files = Object.keys(turnState.files);
504
+ const ownFiles = Object.keys(turnState.files);
505
+ const files = ownFiles;
367
506
  let widgetDemotedFindingsRetired = 0;
368
507
  for (const wPath of drainRenderedDependencyDriftFilePaths()) {
369
508
  const deliveryCount = incrementWidgetDependencyDriftDelivery(wPath);
@@ -379,7 +518,7 @@ export async function handleTurnEnd(deps) {
379
518
  }
380
519
  }
381
520
  }
382
- if (files.length === 0 && !runtime.hasCascadeRuns()) {
521
+ if (files.length === 0 && !runtime.hasCascadeRuns() && !isSecondarySession) {
383
522
  if (getFlag("lens-guard") && !runtime.gitGuardHasBlockers) {
384
523
  const guardRecord = cacheManager.readCache("turn-end-findings", cwd)?.data;
385
524
  if (guardRecord?.sessionId === runtime.telemetrySessionId && guardRecord.testFailures !== true) {
@@ -400,7 +539,7 @@ export async function handleTurnEnd(deps) {
400
539
  });
401
540
  }
402
541
  resetFormatService();
403
- if (pendingRunnerFindingsSize() === 0)
542
+ if (pendingRunnerFindingsSize() === 0 && !runtime.hasResolvedBlockerFiles())
404
543
  return;
405
544
  }
406
545
  if (files.length > 0 && (lspIdleResetTimeout || pendingSweepRearm)) {
@@ -408,7 +547,7 @@ export async function handleTurnEnd(deps) {
408
547
  dbg("turn_end: cancelled pending LSP idle reset (active editing)");
409
548
  }
410
549
  dbg(`turn_end: ${files.length} file(s) modified, cycles: ${turnState.turnCycles}/${turnState.maxCycles}, access: ${access}, owner: ${gateOwnerLabel}`);
411
- if (cacheManager.isMaxCyclesExceeded(cwd)) {
550
+ if (cacheManager.isMaxCyclesExceeded(cwd, turnStateSessionId)) {
412
551
  dbg("turn_end: max cycles exceeded, clearing state and forcing through");
413
552
  clearOwnedTurnState();
414
553
  runtime.fixedThisTurn.clear();
@@ -419,8 +558,131 @@ export async function handleTurnEnd(deps) {
419
558
  const blockerParts = [];
420
559
  const staleSecretParts = [];
421
560
  const advisoryParts = [];
561
+ const deliveryHolds = [];
562
+ const turnScope = deps.sessionScope ?? runtime.sessionScope;
563
+ const holdScope = runtime.captureSessionGeneration();
564
+ const carryScope = sessionId ?? runtime.telemetrySessionId;
565
+ const carryLane = (...parts) => [carryScope, ...parts].join(":");
566
+ const takeParked = (lane) => holdScope.guardedWrite(`turn-end:${lane}`, () => runtime.takeCutAdvisoryItems(lane)) ?? [];
567
+ const cutAdvisoryHold = (family, lane, part, shown, isReOffer) => {
568
+ const fresh = shown.filter((item) => !isReOffer(item));
569
+ const recordDropped = (reason) => {
570
+ incrementDegradationCount({
571
+ kind: "turn-end-advisory-carry-dropped",
572
+ subject: family,
573
+ reason
574
+ });
575
+ };
576
+ return {
577
+ part,
578
+ canHold: () => fresh.length > 0,
579
+ onHeld: () => {
580
+ for (const evicted of runtime.parkCutAdvisoryItems(lane, fresh)) {
581
+ recordDropped(`${evicted} evicted: more lanes had cut items parked than the carry bound keeps`);
582
+ }
583
+ if (fresh.length < shown.length) {
584
+ recordDropped("the cap cut items this lane had already re-offered once");
585
+ }
586
+ },
587
+ onDropped: () => recordDropped("the cap cut a part that showed only items it had already re-offered once")
588
+ };
589
+ };
422
590
  const projectDiagnosticsDelta = [];
423
591
  const projectDiagnosticsSources = new Set;
592
+ const runnerFindingsStart = Date.now();
593
+ const runnerDrainSignal = deps.signal;
594
+ const deliverySessionId = sessionId ?? runtime.telemetrySessionId;
595
+ const pendingRunnerFindings = await bounded(drainPendingRunnerFindings(0, runtime.sessionScope.capture(), deliverySessionId), {
596
+ ms: HOOK_WALL_BUDGET_MS.turn_end,
597
+ signal: runnerDrainSignal,
598
+ hook: "turn_end",
599
+ label: "drainPendingRunnerFindings"
600
+ }) ?? [];
601
+ let runnerFindingsDelivered = 0;
602
+ let runnerFindingsStale = 0;
603
+ let runnerFindingsFailed = 0;
604
+ let runnerFindingsDropped = 0;
605
+ let runnerBlockersRecorded = 0;
606
+ let runnerFindingsDispositionSuppressed = 0;
607
+ const runnerFindingsDeliveredIds = [];
608
+ for (const pending of pendingRunnerFindings) {
609
+ const result = pending.result;
610
+ if (!result)
611
+ continue;
612
+ recordRunner(pending.filePath, pending.runnerId, result.status, result.diagnostics.length, Date.now() - pending.markedAtMs, pending.writeIndex);
613
+ if (result.status === "failed" && !hasUsableResult(result)) {
614
+ runnerFindingsFailed += 1;
615
+ const detail = result.failureMessage ? `: ${result.failureMessage}` : "";
616
+ const failedNote = `❌ Deferred runner ${pending.runnerId} failed (${result.failureKind ?? "unknown"})${detail}`;
617
+ deliveryHolds.push({
618
+ part: failedNote,
619
+ onHeld: () => requeueRunnerFindings({
620
+ ...pending,
621
+ result: { ...result, diagnostics: [] }
622
+ })
623
+ });
624
+ advisoryParts.push(failedNote);
625
+ }
626
+ const verdict = judgeDeferredRunnerFindings(pending, cwd);
627
+ runnerFindingsStale += verdict.stale;
628
+ if (verdict.stale > 0) {
629
+ dropStaleRunnerFindings(pending);
630
+ runnerFindingsDropped += 1;
631
+ }
632
+ if (verdict.live === 0)
633
+ continue;
634
+ const displayPath = toRunnerDisplayPath(cwd, pending.filePath);
635
+ const runnerKept = verdict.kept;
636
+ runnerFindingsDispositionSuppressed += verdict.suppressed;
637
+ if (runnerKept.length === 0) {
638
+ continue;
639
+ }
640
+ runnerFindingsDelivered += runnerKept.length;
641
+ runnerBlockersRecorded += recordDeferredRunnerBlockers(runtime, pending, runnerKept, verdict.bytes);
642
+ for (const finding of runnerKept) {
643
+ if (runnerFindingsDeliveredIds.length < 50) {
644
+ runnerFindingsDeliveredIds.push(finding.id);
645
+ }
646
+ }
647
+ const advisoryKept = runnerKept.flatMap((finding) => finding.semantic === "blocking" ? [] : [finding]);
648
+ if (advisoryKept.length === 0)
649
+ continue;
650
+ const lines = advisoryKept.map((finding) => ` ${displayPath}:${finding.line ?? 1}:${finding.column ?? 1} [${finding.rule ?? finding.id}] ${finding.message}`);
651
+ const runnerSuppressedNote = verdict.suppressed > 0 ? `; suppressed by disposition: ${verdict.suppressed} finding(s)` : "";
652
+ const lateRunnerPart = `⏱️ Late runner diagnostics (${pending.runnerId} completed after the edit${runnerSuppressedNote}):
653
+ ${lines.join(`
654
+ `)}`;
655
+ const {
656
+ failureKind: _kind,
657
+ failureMessage: _message,
658
+ ...findingsOnly
659
+ } = result;
660
+ deliveryHolds.push({
661
+ part: lateRunnerPart,
662
+ onHeld: () => requeueRunnerFindings({
663
+ ...pending,
664
+ result: findingsResult(advisoryKept, findingsOnly)
665
+ })
666
+ });
667
+ advisoryParts.push(lateRunnerPart);
668
+ }
669
+ logLatency({
670
+ type: "phase",
671
+ toolName: "turn_end",
672
+ filePath: cwd,
673
+ phase: "late_runner_findings",
674
+ durationMs: Date.now() - runnerFindingsStart,
675
+ metadata: {
676
+ pending: pendingRunnerFindings.length,
677
+ delivered: runnerFindingsDelivered,
678
+ stale: runnerFindingsStale,
679
+ failed: runnerFindingsFailed,
680
+ dropped: runnerFindingsDropped,
681
+ blockersRecorded: runnerBlockersRecorded,
682
+ dispositionSuppressed: runnerFindingsDispositionSuppressed,
683
+ deliveredIds: runnerFindingsDeliveredIds
684
+ }
685
+ });
424
686
  const blockerPastEofStart = Date.now();
425
687
  const blockerPastEof = sweepInlineBlockerPastEof(runtime, cwd);
426
688
  logLatency({
@@ -435,6 +697,32 @@ export async function handleTurnEnd(deps) {
435
697
  demoted: blockerPastEof.demoted
436
698
  }
437
699
  });
700
+ let demotedFindingsRetired = 0;
701
+ const retirePastEofOnDelivery = (bPath, deadLines, displayPath) => () => {
702
+ if (!runtime.retireDemotedPastEofBlocker(bPath, deadLines))
703
+ return;
704
+ runtime.updateGitGuardStatus(false, "");
705
+ demotedFindingsRetired += 1;
706
+ incrementDegradationCount({
707
+ kind: "demoted-finding-retired",
708
+ subject: `inline-blocker:${displayPath}`,
709
+ reason: `file shrank past cited line(s) ${deadLines.join(", ")}; retired after one degraded delivery`
710
+ });
711
+ };
712
+ const countDriftDeliveryOnDelivery = (bPath, displayPath) => () => {
713
+ const deliveryCount = runtime.incrementInlineBlockerStaleDelivery(bPath);
714
+ if (deliveryCount < DEPENDENCY_DRIFT_MAX_DELIVERIES)
715
+ return;
716
+ if (!runtime.retireDemotedDependencyDriftBlocker(bPath))
717
+ return;
718
+ runtime.updateGitGuardStatus(false, "");
719
+ demotedFindingsRetired += 1;
720
+ incrementDegradationCount({
721
+ kind: "demoted-finding-retired",
722
+ subject: `inline-blocker:${displayPath}`,
723
+ reason: `capped after ${deliveryCount} deliveries with no re-run; re-run can still confirm`
724
+ });
725
+ };
438
726
  const blockerFreshnessStart = Date.now();
439
727
  const blockerFreshness = await sweepInlineBlockerFreshness(runtime, cwd, {
440
728
  ...deps.signal === undefined ? {} : { signal: deps.signal },
@@ -462,8 +750,6 @@ export async function handleTurnEnd(deps) {
462
750
  }
463
751
  });
464
752
  const unresolvedBlockers = runtime.getInlineBlockersSnapshot();
465
- let demotedFindingsRetired = 0;
466
- const pendingDependencyDriftDeliveries = [];
467
753
  const inlinePolicyEntries = [];
468
754
  const policySuppressedPaths = [];
469
755
  const inlinePolicyStart = Date.now();
@@ -475,39 +761,32 @@ export async function handleTurnEnd(deps) {
475
761
  inlinePolicyEntries.push({ ...tally, stale: true });
476
762
  const deadLines = blockerPastEof.deadLinesByPath.get(bPath) ?? [];
477
763
  const degraded = degradeDemotedFindingBody(summary, { deadLines });
478
- const retired = runtime.retireDemotedPastEofBlocker(bPath, deadLines);
764
+ const retires = runtime.wouldRetireDemotedPastEofBlocker(bPath, deadLines);
479
765
  let retirementNote;
480
- if (retired) {
481
- demotedFindingsRetired += 1;
482
- incrementDegradationCount({
483
- kind: "demoted-finding-retired",
484
- subject: `inline-blocker:${displayPath}`,
485
- reason: `file shrank past cited line(s) ${deadLines.join(", ")}; retired after one degraded delivery`
486
- });
766
+ if (retires) {
487
767
  retirementNote = formatRetirementNote(deadLines);
488
768
  } else if (staleReason === "dependency-drift") {
489
769
  const tentativeCount = runtime.peekInlineBlockerStaleDeliveryCount(bPath) + 1;
490
770
  if (tentativeCount >= DEPENDENCY_DRIFT_MAX_DELIVERIES) {
491
771
  retirementNote = formatDeliveryCapNote(tentativeCount);
492
772
  }
493
- pendingDependencyDriftDeliveries.push(() => {
494
- const deliveryCount = runtime.incrementInlineBlockerStaleDelivery(bPath);
495
- if (deliveryCount >= DEPENDENCY_DRIFT_MAX_DELIVERIES) {
496
- const capRetired = runtime.retireDemotedDependencyDriftBlocker(bPath);
497
- if (capRetired) {
498
- demotedFindingsRetired += 1;
499
- incrementDegradationCount({
500
- kind: "demoted-finding-retired",
501
- subject: `inline-blocker:${displayPath}`,
502
- reason: `capped after ${deliveryCount} deliveries with no re-run; re-run can still confirm`
503
- });
504
- }
505
- }
506
- });
507
773
  }
508
- advisoryParts.push(`${STALE_LINE_MARKER} ${displayPath}:
774
+ const advisoryPart = `${STALE_LINE_MARKER} ${displayPath}:
509
775
  ${degraded.body}` + (retirementNote ? `
510
- ${retirementNote}` : ""));
776
+ ${retirementNote}` : "");
777
+ advisoryParts.push(advisoryPart);
778
+ if (retires) {
779
+ deliveryHolds.push({
780
+ part: advisoryPart,
781
+ onDelivered: retirePastEofOnDelivery(bPath, deadLines, displayPath)
782
+ });
783
+ } else if (staleReason === "dependency-drift") {
784
+ deliveryHolds.push({
785
+ part: advisoryPart,
786
+ onDelivered: countDriftDeliveryOnDelivery(bPath, displayPath),
787
+ skipOnSuppressed: true
788
+ });
789
+ }
511
790
  } else {
512
791
  const policy = applyInlineBlockerPolicy(record, cwd);
513
792
  inlinePolicyEntries.push({ ...tally, stale: false, outcome: policy });
@@ -540,7 +819,16 @@ ${policy.body}`);
540
819
  });
541
820
  }
542
821
  const cascadeSettleStart = Date.now();
543
- const { settled, timedOut } = await runtime.settleCascadeRuns(cascadeSettleWaitMs(), { trackTurnEndClock: true });
822
+ const cascadeSettleSignal = deps.signal;
823
+ const { settled, timedOut } = await bounded(runtime.settleCascadeRuns(cascadeSettleWaitMs(), {
824
+ trackTurnEndClock: true,
825
+ generation: holdScope
826
+ }), {
827
+ ms: HOOK_WALL_BUDGET_MS.turn_end,
828
+ signal: cascadeSettleSignal,
829
+ hook: "turn_end",
830
+ label: "settleCascadeRuns"
831
+ }) ?? { settled: 0, timedOut: 0 };
544
832
  logLatency({
545
833
  type: "phase",
546
834
  toolName: "turn_end",
@@ -550,7 +838,7 @@ ${policy.body}`);
550
838
  metadata: { settled, timedOut }
551
839
  });
552
840
  const t0 = Date.now();
553
- const cascadeRuns = runtime.consumeCascadeRuns().filter((run) => {
841
+ const cascadeRuns = (holdScope.guardedWrite("turn-end:cascade-runs", () => runtime.consumeCascadeRuns()) ?? []).filter((run) => {
554
842
  const originSeq = run.origin?.projectSeq;
555
843
  const originTurn = run.origin?.turnSeq;
556
844
  if (originSeq !== undefined) {
@@ -589,7 +877,10 @@ ${policy.body}`);
589
877
  let carriedRunsRendered = 0;
590
878
  let labeledAdvisories = 0;
591
879
  const carriedMetaByResult = new Map;
880
+ const runByResult = new Map;
592
881
  for (const r of cascadeRuns) {
882
+ if (r.result)
883
+ runByResult.set(r.result, r);
593
884
  if (r.result && (r.carriedTurns ?? 0) > 0 && r.carriedTurns !== undefined) {
594
885
  carriedMetaByResult.set(r.result, {
595
886
  carriedTurns: r.carriedTurns,
@@ -613,6 +904,7 @@ ${policy.body}`);
613
904
  }
614
905
  }
615
906
  const parts = [];
907
+ const sectionRuns = [];
616
908
  let injectedNeighborCount = 0;
617
909
  let injectedDiagnosticCount = 0;
618
910
  let suppressedByOwnership = 0;
@@ -626,6 +918,9 @@ ${policy.body}`);
626
918
  ${carrySuffix}` : result.formatted);
627
919
  if (carrySuffix)
628
920
  carriedRunsRendered += 1;
921
+ const sectionRun = runByResult.get(result);
922
+ if (sectionRun)
923
+ sectionRuns.push(sectionRun);
629
924
  injectedNeighborCount += result.neighbors.length;
630
925
  injectedDiagnosticCount += result.neighbors.reduce((s, n) => s + n.diagnostics.length, 0);
631
926
  } else if (!ownsAny && result.formatted) {
@@ -667,6 +962,13 @@ ${testLines.join(`
667
962
 
668
963
  `);
669
964
  blockerParts.push(section);
965
+ deliveryHolds.push({
966
+ part: section,
967
+ onHeld: () => {
968
+ for (const run of sectionRuns)
969
+ runtime.appendCascadeRun(run);
970
+ }
971
+ });
670
972
  logCascade({
671
973
  phase: "cascade_injected",
672
974
  filePath: cascadeLogFilePath,
@@ -734,18 +1036,31 @@ ${lines.join(`
734
1036
  return `${advisory}
735
1037
  ${suffix}`;
736
1038
  };
1039
+ const holdAdvisory = (advisory, runs) => {
1040
+ if (advisory === undefined)
1041
+ return;
1042
+ deliveryHolds.push({
1043
+ part: advisory,
1044
+ onHeld: () => {
1045
+ for (const run of runs)
1046
+ runtime.appendCascadeRun({ ...run, result: undefined });
1047
+ }
1048
+ });
1049
+ };
737
1050
  const graphAdvisory = withCarryLabel(buildAdvisory(graphRuns, {
738
1051
  lead: (fileCount, reasons) => `Cascade could not compute downstream impact for ${fileCount} edited file(s) this turn — ` + `the review graph was unavailable (${reasons}), so their dependents were not ` + `cascade-checked and a clean cascade result does not cover them.`,
739
1052
  fallbackDetail: (r) => r.indeterminate?.reason === "missing_node" ? "changed file not in the review graph" : "review graph unavailable"
740
1053
  }), graphRuns);
741
1054
  if (graphAdvisory)
742
1055
  advisoryParts.push(graphAdvisory);
1056
+ holdAdvisory(graphAdvisory, graphRuns);
743
1057
  const bindingAdvisory = withCarryLabel(buildAdvisory(bindingRuns, {
744
1058
  lead: (fileCount, reasons) => `Cascade identified dependents for ${fileCount} edited file(s) this turn, but their ` + `diagnostics could not be freshly confirmed (${reasons}) and were withheld — a clean ` + `cascade result does not cover them.`,
745
1059
  fallbackDetail: () => "cascade diagnostics withheld (binding rejected)"
746
1060
  }), bindingRuns);
747
1061
  if (bindingAdvisory)
748
1062
  advisoryParts.push(bindingAdvisory);
1063
+ holdAdvisory(bindingAdvisory, bindingRuns);
749
1064
  const budgetAdvisory = withCarryLabel(buildAdvisory(budgetRuns, {
750
1065
  lead: (fileCount, reasons) => `Cascade checked the selected neighbors for ${fileCount} edited file(s) this turn, ` + `but some eligible dependents were not checked because the cascade budget ` + `was exhausted (${reasons}); a clean cascade result does not cover them.`,
751
1066
  fallbackDetail: (r) => {
@@ -758,6 +1073,7 @@ ${suffix}`;
758
1073
  }), budgetRuns);
759
1074
  if (budgetAdvisory)
760
1075
  advisoryParts.push(budgetAdvisory);
1076
+ holdAdvisory(budgetAdvisory, budgetRuns);
761
1077
  const fileCount = new Set(indeterminateRuns.map((r) => normalizeMapKey(r.filePath))).size;
762
1078
  const byFile = indeterminateRuns.map((r) => ({
763
1079
  file: toRunnerDisplayPath(cwd, r.filePath),
@@ -812,106 +1128,182 @@ ${suffix}`;
812
1128
  skipped: cascadeSkipped
813
1129
  }
814
1130
  });
815
- const t2 = Date.now();
816
- let knipMeta = {};
817
- if (runtime.isStartupScanInFlight("knip")) {
818
- dbg("turn_end: skipping knip (startup scan still in flight)");
819
- knipMeta = { skipped: true };
820
- } else {
821
- const prevKnip = cacheManager.readCache("knip", cwd);
822
- const previousFailedHard = prevKnip && !prevKnip.data.success && !prevKnip.data.failureKind && /(timed out|killed|SIGTERM|SIGKILL|SIGABRT)/i.test(prevKnip.data.summary);
823
- if (previousFailedHard) {
824
- dbg(`turn_end: skipping knip after recent failure: ${prevKnip.data.summary}`);
825
- knipMeta = { skipped: true, reason: prevKnip.data.summary };
1131
+ const knipScan = resolveKnipScanRoots(cwd, files);
1132
+ for (const root of knipScan.overCap) {
1133
+ incrementDegradationCount({
1134
+ kind: "turn-end-knip-root-skipped",
1135
+ subject: "root-cap",
1136
+ reason: `${toRunnerDisplayPath(cwd, root)} not scanned: more than ${MAX_KNIP_ROOTS_PER_TURN} checkouts edited this turn`
1137
+ });
1138
+ }
1139
+ const KNOWN_SLOW_KNIP_GRACE_MS = 1;
1140
+ const KNIP_MAX_SHOWN = 5;
1141
+ const applyKnipResult = (scanRoot, prevKnip, knipResult, rowNow) => {
1142
+ const knipWouldPoison = wouldPoisonCache(rowNow, knipResult);
1143
+ if (knipWouldPoison) {
1144
+ dbg(`turn_end: keeping last good knip cache; this run failed: ${knipResult.summary}`);
826
1145
  } else {
827
- const knipResult = await knipClient.analyze(cwd, getKnipIgnorePatterns(), {
828
- projectSeq: runtime.projectSeq
1146
+ cacheManager.writeCache("knip", knipResult, scanRoot);
1147
+ }
1148
+ const knipMeta = {
1149
+ execution: knipResult.execution ?? "executed",
1150
+ success: knipResult.success,
1151
+ totalIssues: knipResult.issues.length,
1152
+ newIssues: 0,
1153
+ blockerIssues: 0,
1154
+ dispositionSuppressed: 0,
1155
+ ...!knipResult.success && { reason: knipResult.summary },
1156
+ ...knipResult.failureKind && { failureKind: knipResult.failureKind },
1157
+ ...knipResult.nestedWorktrees !== undefined && {
1158
+ nestedWorktrees: knipResult.nestedWorktrees,
1159
+ nestedFilesDropped: knipResult.nestedFilesDropped
1160
+ },
1161
+ ...knipWouldPoison && { cacheKept: true }
1162
+ };
1163
+ const knipBlockerLane = carryLane("knip", scanRoot, "blocker");
1164
+ const knipAdvisoryLane = carryLane("knip", scanRoot, "advisory");
1165
+ const parkedKnip = knipResult.success ? [
1166
+ ...takeParked(knipBlockerLane),
1167
+ ...takeParked(knipAdvisoryLane)
1168
+ ] : [];
1169
+ if (knipResult.success && knipResult.issues.length > 0) {
1170
+ const issueKey = (i) => stableFindingKey(i.type, i.file, i.name, i.package);
1171
+ const prevKeys = new Set((prevKnip?.data?.issues ?? []).map(issueKey));
1172
+ const modifiedSet = new Set(files.map((f) => resolveRunnerPath(cwd, f)));
1173
+ const newIssues = knipResult.issues.filter((issue) => {
1174
+ if (prevKeys.has(issueKey(issue)))
1175
+ return false;
1176
+ if (!issue.file)
1177
+ return false;
1178
+ const abs = resolveRunnerPath(scanRoot, issue.file);
1179
+ return modifiedSet.has(abs);
829
1180
  });
830
- const knipWouldPoison = wouldPoisonCache(prevKnip, knipResult);
831
- if (knipWouldPoison) {
832
- dbg(`turn_end: keeping last good knip cache; this run failed: ${knipResult.summary}`);
833
- } else {
834
- cacheManager.writeCache("knip", knipResult, cwd);
1181
+ knipMeta.newIssues = newIssues.length;
1182
+ const reOffered = stillReportedParked(parkedKnip, knipResult.issues, issueKey, new Set(newIssues.map(issueKey)));
1183
+ const reOfferedKeys = new Set(reOffered.map(issueKey));
1184
+ if (reOffered.length > 0)
1185
+ knipMeta.reOffered = reOffered.length;
1186
+ if (newIssues.length > 0) {
1187
+ projectDiagnosticsDelta.push(...knipIssuesToProjectDiagnostics(scanRoot, newIssues));
1188
+ projectDiagnosticsSources.add("knip");
835
1189
  }
836
- knipMeta = {
837
- execution: knipResult.execution ?? "executed",
838
- success: knipResult.success,
839
- totalIssues: knipResult.issues.length,
840
- newIssues: 0,
841
- blockerIssues: 0,
842
- dispositionSuppressed: 0,
843
- ...!knipResult.success && { reason: knipResult.summary },
844
- ...knipResult.failureKind && { failureKind: knipResult.failureKind },
845
- ...knipWouldPoison && { cacheKept: true }
1190
+ const knipPaired = [...newIssues, ...reOffered].flatMap((issue) => knipIssuesToProjectDiagnostics(scanRoot, [issue]).map((diagnostic) => ({
1191
+ issue,
1192
+ diagnostic
1193
+ })));
1194
+ const knipFiltered = filterFindingsByDisposition(knipPaired, cwd, (pair) => pair.diagnostic);
1195
+ const knipDeliverable = {
1196
+ kept: knipFiltered.kept.map((pair) => pair.issue),
1197
+ suppressed: knipFiltered.suppressed
846
1198
  };
847
- if (knipResult.success && knipResult.issues.length > 0) {
848
- const issueKey = (i) => stableFindingKey(i.type, i.file, i.name, i.package);
849
- const prevKeys = new Set((prevKnip?.data?.issues ?? []).map(issueKey));
850
- const modifiedSet = new Set(files.map((f) => resolveRunnerPath(cwd, f)));
851
- const newIssues = knipResult.issues.filter((issue) => {
852
- if (prevKeys.has(issueKey(issue)))
853
- return false;
854
- if (!issue.file)
855
- return false;
856
- const abs = resolveRunnerPath(cwd, issue.file);
857
- return modifiedSet.has(abs);
858
- });
859
- knipMeta.newIssues = newIssues.length;
860
- if (newIssues.length > 0) {
861
- projectDiagnosticsDelta.push(...knipIssuesToProjectDiagnostics(cwd, newIssues));
862
- projectDiagnosticsSources.add("knip");
863
- }
864
- const knipPaired = newIssues.flatMap((issue) => knipIssuesToProjectDiagnostics(cwd, [issue]).map((diagnostic) => ({
865
- issue,
866
- diagnostic
867
- })));
868
- const knipFiltered = filterFindingsByDisposition(knipPaired, cwd, (pair) => pair.diagnostic);
869
- const knipDeliverable = {
870
- kept: knipFiltered.kept.map((pair) => pair.issue),
871
- suppressed: knipFiltered.suppressed
872
- };
873
- knipMeta.dispositionSuppressed = knipDeliverable.suppressed;
874
- const blockerIssues = knipDeliverable.kept.filter((i) => i.type === "unlisted" || i.type === "bin");
875
- knipMeta.blockerIssues = blockerIssues.length;
876
- if (blockerIssues.length > 0) {
877
- let report = `\uD83D\uDD34 New unresolved imports/deps in modified code (Knip):
1199
+ knipMeta.dispositionSuppressed = knipDeliverable.suppressed;
1200
+ const displayPath = (issue) => issue.file ? toRunnerDisplayPath(cwd, resolveRunnerPath(scanRoot, issue.file)) : "(unknown)";
1201
+ const blockerIssues = knipDeliverable.kept.filter((i) => i.type === "unlisted" || i.type === "bin");
1202
+ knipMeta.blockerIssues = blockerIssues.length;
1203
+ if (blockerIssues.length > 0) {
1204
+ let report = `\uD83D\uDD34 New unresolved imports/deps in modified code (Knip):
878
1205
  `;
879
- let firstPath = null;
880
- for (const issue of blockerIssues.slice(0, 5)) {
881
- const display = issue.file ? toRunnerDisplayPath(cwd, issue.file) : "(unknown)";
882
- if (!firstPath && display !== "(unknown)")
883
- firstPath = display;
884
- report += ` ${display}${issue.line ? `:${issue.line}` : ""} — ${issue.type}: ${issue.name}
1206
+ let firstPath = null;
1207
+ for (const issue of blockerIssues.slice(0, KNIP_MAX_SHOWN)) {
1208
+ const display = displayPath(issue);
1209
+ if (!firstPath && display !== "(unknown)")
1210
+ firstPath = display;
1211
+ report += ` ${display}${issue.line ? `:${issue.line}` : ""} — ${issue.type}: ${issue.name}
885
1212
  `;
886
- }
887
- if (firstPath) {
888
- report += ` First location: ${firstPath}
1213
+ }
1214
+ if (firstPath) {
1215
+ report += ` First location: ${firstPath}
889
1216
  `;
890
- }
891
- blockerParts.push(report);
892
1217
  }
893
- const unusedExportDelta = knipDeliverable.kept.filter((i) => i.type === "export" || i.type === "enumMember");
894
- if (unusedExportDelta.length > 0) {
895
- let report = `⚠️ Newly unused exports in files you edited — check if callers need updating (Knip):
1218
+ blockerParts.push(report);
1219
+ deliveryHolds.push(cutAdvisoryHold("knip", knipBlockerLane, report, blockerIssues.slice(0, KNIP_MAX_SHOWN), (issue) => reOfferedKeys.has(issueKey(issue))));
1220
+ }
1221
+ const unusedExportDelta = knipDeliverable.kept.filter((i) => i.type === "export" || i.type === "enumMember");
1222
+ if (unusedExportDelta.length > 0) {
1223
+ let report = `⚠️ Newly unused exports in files you edited — check if callers need updating (Knip):
896
1224
  `;
897
- for (const issue of unusedExportDelta.slice(0, 5)) {
898
- const display = issue.file ? toRunnerDisplayPath(cwd, issue.file) : "(unknown)";
899
- report += ` ${display}${issue.line ? `:${issue.line}` : ""} — ${issue.name}
1225
+ for (const issue of unusedExportDelta.slice(0, KNIP_MAX_SHOWN)) {
1226
+ const display = displayPath(issue);
1227
+ report += ` ${display}${issue.line ? `:${issue.line}` : ""} — ${issue.name}
900
1228
  `;
901
- }
902
- advisoryParts.push(report);
903
1229
  }
1230
+ advisoryParts.push(report);
1231
+ deliveryHolds.push(cutAdvisoryHold("knip", knipAdvisoryLane, report, unusedExportDelta.slice(0, KNIP_MAX_SHOWN), (issue) => reOfferedKeys.has(issueKey(issue))));
904
1232
  }
905
1233
  }
906
- }
907
- logLatency({
1234
+ return knipMeta;
1235
+ };
1236
+ const logKnipRow = (root, startedAt, metadata) => logLatency({
908
1237
  type: "phase",
909
1238
  toolName: "turn_end",
910
- filePath: cwd,
1239
+ filePath: root,
911
1240
  phase: "knip",
912
- durationMs: Date.now() - t2,
913
- metadata: knipMeta
1241
+ durationMs: Date.now() - startedAt,
1242
+ metadata
914
1243
  });
1244
+ if (runtime.isStartupScanInFlight("knip")) {
1245
+ dbg("turn_end: skipping knip (startup scan still in flight)");
1246
+ logKnipRow(cwd, Date.now(), { skipped: true });
1247
+ } else {
1248
+ let budgetSpent = false;
1249
+ for (const scanRoot of knipScan.roots) {
1250
+ if (budgetSpent) {
1251
+ incrementDegradationCount({
1252
+ kind: "turn-end-knip-root-skipped",
1253
+ subject: "budget",
1254
+ reason: `${toRunnerDisplayPath(cwd, scanRoot)} not scanned: an earlier knip scan spent the turn_end budget`
1255
+ });
1256
+ continue;
1257
+ }
1258
+ const startedAt = Date.now();
1259
+ const prevKnip = cacheManager.readCache("knip", scanRoot);
1260
+ const previousFailedHard = prevKnip && !prevKnip.data.success && !prevKnip.data.failureKind && isHardFailureSummary(prevKnip.data.summary);
1261
+ const abandonedFailure = previousFailedHard ? null : knipClient.recentHardFailure?.(scanRoot) ?? null;
1262
+ let metadata;
1263
+ if (previousFailedHard || abandonedFailure !== null) {
1264
+ const reason = previousFailedHard ? prevKnip.data.summary : abandonedFailure ?? "";
1265
+ dbg(`turn_end: skipping knip after recent failure: ${reason}`);
1266
+ metadata = { skipped: true, reason };
1267
+ } else {
1268
+ const remainingMs = Math.max(0, HOOK_WALL_BUDGET_MS.turn_end - (Date.now() - turnEndStart));
1269
+ const scanFloorMs = knipClient.scanFloorMs?.(scanRoot);
1270
+ const knownSlow = scanFloorMs !== undefined && scanFloorMs > remainingMs;
1271
+ const scanned = await bounded(withRowForFailureWrite(knipClient.analyze(scanRoot, getKnipIgnorePatterns(), {
1272
+ projectSeq: runtime.projectSeq
1273
+ }), cacheManager, "knip", scanRoot, prevKnip), {
1274
+ ms: knownSlow ? KNOWN_SLOW_KNIP_GRACE_MS : remainingMs,
1275
+ signal: deps.signal,
1276
+ hook: "turn_end",
1277
+ label: "knip"
1278
+ });
1279
+ if (scanned === undefined) {
1280
+ dbg(`turn_end: knip for ${scanRoot} outlived the turn_end budget`);
1281
+ const aborted = deps.signal?.aborted === true;
1282
+ const nestedWorktrees = knipClient.nestedWorktrees?.(scanRoot) ?? 0;
1283
+ metadata = {
1284
+ execution: "deferred",
1285
+ aborted,
1286
+ ...knownSlow && {
1287
+ reason: "scan-exceeds-budget",
1288
+ scanFloorMs
1289
+ },
1290
+ ...nestedWorktrees > 0 && { nestedWorktrees }
1291
+ };
1292
+ if (nestedWorktrees > 0 && !aborted) {
1293
+ incrementDegradationCount({
1294
+ kind: "turn-end-knip-nested-worktrees",
1295
+ subject: toRunnerDisplayPath(cwd, scanRoot),
1296
+ reason: `${nestedWorktrees} linked worktree(s) nested under the scan root: knip walks them as project files and the scan did not fit the turn_end budget; add their directory (for example /.worktrees/) to .gitignore to drop the cost`
1297
+ });
1298
+ }
1299
+ } else {
1300
+ metadata = applyKnipResult(scanRoot, prevKnip, scanned.result, scanned.row);
1301
+ }
1302
+ }
1303
+ budgetSpent = metadata.execution === "deferred" && (metadata.scanFloorMs === undefined || metadata.aborted === true);
1304
+ logKnipRow(scanRoot, startedAt, metadata);
1305
+ }
1306
+ }
915
1307
  const tDeadCode = Date.now();
916
1308
  const deadCodeMeta = {};
917
1309
  if (runtime.isStartupScanInFlight("dead-code")) {
@@ -926,29 +1318,136 @@ ${suffix}`;
926
1318
  let newIssueTotal = 0;
927
1319
  let deadCodeDispositionSuppressed = 0;
928
1320
  const reasons = [];
1321
+ const deliverDeadCodeDelta = (client, sources) => {
1322
+ const latest = sources.at(-1);
1323
+ if (latest === undefined)
1324
+ return;
1325
+ const result = latest.result;
1326
+ const deadCodeLane = carryLane("dead-code", client.id);
1327
+ const parkedDeadCode = takeParked(deadCodeLane);
1328
+ deadCodeMeta.totalIssues = (deadCodeMeta.totalIssues ?? 0) + deadCodeIssues(result).length;
1329
+ if (!sources.some((source) => source.previousScan?.success)) {
1330
+ reasons.push(`${client.id}:no_previous_scan`);
1331
+ return;
1332
+ }
1333
+ const newIssues = [];
1334
+ for (const source of sources) {
1335
+ if (!source.previousScan?.success)
1336
+ continue;
1337
+ const prevKeys = new Set(deadCodeIssues(source.previousScan).map(deadCodeIssueKey));
1338
+ for (const issue of deadCodeIssues(source.result)) {
1339
+ if (prevKeys.has(deadCodeIssueKey(issue)) || !issue.file)
1340
+ continue;
1341
+ if (source.modified.has(resolveRunnerPath(cwd, issue.file))) {
1342
+ newIssues.push(issue);
1343
+ }
1344
+ }
1345
+ }
1346
+ const reOffered = stillReportedParked(parkedDeadCode, deadCodeIssues(result), deadCodeIssueKey, new Set(newIssues.map(deadCodeIssueKey)));
1347
+ if (newIssues.length === 0 && reOffered.length === 0) {
1348
+ reasons.push(`${client.id}:clean`);
1349
+ return;
1350
+ }
1351
+ newIssueTotal += newIssues.length;
1352
+ if (newIssues.length > 0) {
1353
+ projectDiagnosticsDelta.push(...newIssues.map((issue) => deadCodeIssueToProjectDiagnostic(cwd, issue, result.language)));
1354
+ projectDiagnosticsSources.add("dead-code");
1355
+ }
1356
+ const deadCodeDeliverable = filterFindingsByDisposition([...newIssues, ...reOffered], cwd, (issue) => deadCodeIssueToProjectDiagnostic(cwd, issue, result.language));
1357
+ deadCodeDispositionSuppressed += deadCodeDeliverable.suppressed;
1358
+ if (deadCodeDeliverable.kept.length === 0) {
1359
+ reasons.push(`${client.id}:all_disposed`);
1360
+ return;
1361
+ }
1362
+ const deadCodePart = formatDeadCodeDelta(deadCodeDeliverable.kept, result.language);
1363
+ advisoryParts.push(deadCodePart);
1364
+ const reOfferedKeys = new Set(reOffered.map(deadCodeIssueKey));
1365
+ deliveryHolds.push(cutAdvisoryHold("dead-code", deadCodeLane, deadCodePart, deadCodeDeliverable.kept.slice(0, DEAD_CODE_DELTA_MAX_SHOWN), (issue) => reOfferedKeys.has(deadCodeIssueKey(issue))));
1366
+ };
929
1367
  try {
1368
+ const lateScans = lateDeadCodeScansOf(turnScope);
930
1369
  for (const client of deadCodeClients) {
931
1370
  if (!client.detect(cwd)) {
932
1371
  reasons.push(`${client.id}:not_detected`);
933
1372
  continue;
934
1373
  }
935
- if (![...modifiedFiles()].some((f) => client.owns(f))) {
936
- reasons.push(`${client.id}:no_owned_files`);
937
- continue;
938
- }
939
1374
  const cacheKey = `dead-code-${client.id}`;
940
- const prev = cacheManager.readCache(cacheKey, cwd);
941
- if (prev && !prev.data.success && /(timed out|killed|SIGTERM|SIGKILL|SIGABRT)/i.test(prev.data.summary)) {
942
- dbg(`turn_end: skipping dead-code after failure: ${prev.data.summary}`);
943
- deadCodeMeta.skipped = true;
944
- reasons.push(`${client.id}:backoff:${prev.data.summary}`);
945
- continue;
1375
+ const lateKey = lateDeadCodeScanKey(client, cwd);
1376
+ const sources = [];
1377
+ const late = lateScans.get(lateKey);
1378
+ let carried = new Set;
1379
+ if (late?.settled) {
1380
+ lateScans.delete(lateKey);
1381
+ sources.push({
1382
+ result: late.settled,
1383
+ previousScan: late.previousScan,
1384
+ modified: late.files
1385
+ });
1386
+ carried = late.carry;
1387
+ reasons.push(`${client.id}:late_scan`);
1388
+ if (joinedEarlierScan(late.settled, late.askedAt)) {
1389
+ carried = new Set([...late.carry, ...late.files]);
1390
+ reasons.push(`${client.id}:joined`);
1391
+ }
946
1392
  }
947
- const startMs = Date.now();
948
1393
  try {
949
- const result = await client.analyze(cwd);
1394
+ if (late && !late.settled) {
1395
+ for (const file of modifiedFiles())
1396
+ late.carry.add(file);
1397
+ reasons.push(`${client.id}:in_flight`);
1398
+ continue;
1399
+ }
1400
+ const scanFiles = new Set([...modifiedFiles(), ...carried]);
1401
+ if (![...scanFiles].some((f) => client.owns(f))) {
1402
+ reasons.push(`${client.id}:no_owned_files`);
1403
+ continue;
1404
+ }
1405
+ const prev = cacheManager.readCache(cacheKey, cwd);
1406
+ const previousFailedHard = prev && !prev.data.success && isHardFailureSummary(prev.data.summary);
1407
+ const abandonedFailure = previousFailedHard ? null : client.recentHardFailure?.(cwd) ?? null;
1408
+ if (previousFailedHard || abandonedFailure !== null) {
1409
+ const failure = previousFailedHard ? prev.data.summary : abandonedFailure ?? "";
1410
+ dbg(`turn_end: skipping dead-code after failure: ${failure}`);
1411
+ deadCodeMeta.skipped = true;
1412
+ reasons.push(`${client.id}:backoff:${failure}`);
1413
+ continue;
1414
+ }
1415
+ const startMs = Date.now();
1416
+ const scan = client.analyze(cwd);
1417
+ const settled = await bounded(withRowForFailureWrite(scan, cacheManager, cacheKey, cwd, prev), {
1418
+ signal: deps.signal,
1419
+ hook: "turn_end",
1420
+ label: "dead-code",
1421
+ ms: Math.max(0, HOOK_WALL_BUDGET_MS.turn_end - (Date.now() - turnEndStart))
1422
+ });
1423
+ const joined = settled !== undefined && joinedEarlierScan(settled.result, startMs);
1424
+ if (settled === undefined || joined) {
1425
+ if (joined) {
1426
+ reasons.push(`${client.id}:joined`);
1427
+ } else {
1428
+ dbg(`turn_end: dead-code(${client.id}) outlived the budget`);
1429
+ deadCodeMeta.execution = "deferred";
1430
+ deadCodeMeta.aborted = deps.signal?.aborted === true;
1431
+ reasons.push(`${client.id}:deferred`);
1432
+ }
1433
+ parkLateDeadCodeScan({
1434
+ scope: turnScope,
1435
+ cacheManager,
1436
+ client,
1437
+ cwd,
1438
+ cacheKey,
1439
+ scan,
1440
+ startedAt: startMs,
1441
+ files: scanFiles,
1442
+ previousScan: prev?.data
1443
+ });
1444
+ if (joined)
1445
+ continue;
1446
+ break;
1447
+ }
1448
+ const { result } = settled;
950
1449
  const durationMs = Date.now() - startMs;
951
- if (wouldPoisonCache(prev, result)) {
1450
+ if (wouldPoisonCache(settled.row, result)) {
952
1451
  dbg(`turn_end: keeping last good dead-code(${client.id}) cache; this run failed: ${result.summary}`);
953
1452
  deadCodeMeta.cacheKept = true;
954
1453
  } else {
@@ -956,53 +1455,30 @@ ${suffix}`;
956
1455
  scanDurationMs: durationMs
957
1456
  });
958
1457
  }
959
- logDeadCodeScan({
960
- language: client.language,
961
- success: result.success,
962
- cached: false,
963
- unusedExports: result.unusedExports.length,
964
- unusedFiles: result.unusedFiles.length,
965
- unusedDeps: result.unusedDeps.length,
966
- unlistedDeps: result.unlistedDeps.length,
967
- durationMs: result.durationMs ?? durationMs,
968
- ...!result.success && { reason: result.summary }
969
- });
1458
+ logDeadCodeScan(deadCodeScanEvent(client, cwd, result, durationMs));
970
1459
  deadCodeMeta.success = result.success;
1460
+ if (result.excludedWorktrees !== undefined) {
1461
+ deadCodeMeta.excludedWorktrees = (deadCodeMeta.excludedWorktrees ?? 0) + result.excludedWorktrees;
1462
+ }
971
1463
  if (!result.success) {
972
1464
  reasons.push(`${client.id}:scan_failed:${result.summary}`);
973
1465
  continue;
974
1466
  }
975
- deadCodeMeta.totalIssues = (deadCodeMeta.totalIssues ?? 0) + deadCodeIssues(result).length;
976
- if (!prev?.data.success) {
977
- reasons.push(`${client.id}:no_previous_scan`);
978
- continue;
979
- }
980
- const prevKeys = new Set(deadCodeIssues(prev.data).map(deadCodeIssueKey));
981
- const modified = modifiedFiles();
982
- const newIssues = deadCodeIssues(result).filter((issue) => {
983
- if (prevKeys.has(deadCodeIssueKey(issue)))
984
- return false;
985
- if (!issue.file)
986
- return false;
987
- return modified.has(resolveRunnerPath(cwd, issue.file));
1467
+ sources.push({
1468
+ result,
1469
+ previousScan: prev?.data,
1470
+ modified: scanFiles
988
1471
  });
989
- if (newIssues.length === 0) {
990
- reasons.push(`${client.id}:clean`);
991
- continue;
992
- }
993
- newIssueTotal += newIssues.length;
994
- projectDiagnosticsDelta.push(...newIssues.map((issue) => deadCodeIssueToProjectDiagnostic(cwd, issue, result.language)));
995
- projectDiagnosticsSources.add("dead-code");
996
- const deadCodeDeliverable = filterFindingsByDisposition(newIssues, cwd, (issue) => deadCodeIssueToProjectDiagnostic(cwd, issue, result.language));
997
- deadCodeDispositionSuppressed += deadCodeDeliverable.suppressed;
998
- if (deadCodeDeliverable.kept.length === 0) {
999
- reasons.push(`${client.id}:all_disposed`);
1000
- continue;
1001
- }
1002
- advisoryParts.push(formatDeadCodeDelta(deadCodeDeliverable.kept, result.language));
1003
1472
  } catch (err) {
1004
1473
  dbg(`turn_end: dead-code(${client.id}) failed: ${err}`);
1005
1474
  reasons.push(`${client.id}:threw`);
1475
+ } finally {
1476
+ try {
1477
+ deliverDeadCodeDelta(client, sources);
1478
+ } catch (err) {
1479
+ dbg(`turn_end: dead-code(${client.id}) delivery failed: ${err}`);
1480
+ reasons.push(`${client.id}:threw`);
1481
+ }
1006
1482
  }
1007
1483
  }
1008
1484
  } catch (err) {
@@ -1053,7 +1529,7 @@ ${suffix}`;
1053
1529
  cwd,
1054
1530
  signal: deps.signal,
1055
1531
  readScannerCache,
1056
- peekActionableWarnings: () => runtime.peekActionableWarnings()
1532
+ peekActionableWarnings: () => runtime.peekActionableWarnings(sessionId)
1057
1533
  };
1058
1534
  const govSources = await govulncheckLane.collect(laneCtx);
1059
1535
  const trivyCacheEntry = await readScannerCache("trivy");
@@ -1081,15 +1557,15 @@ ${suffix}`;
1081
1557
  const govGate = scannerGates.govulncheck;
1082
1558
  const gitleaksGate = scannerGates.gitleaks;
1083
1559
  const trivySecretsGate = scannerGates["trivy-secrets"];
1084
- const govDelivery = govulncheckLane.render(govulncheckLane.gate({ govulncheck: govGate }, laneCtx), laneCtx);
1560
+ const govDelivery = allowProjectWideFindings ? govulncheckLane.render(govulncheckLane.gate({ govulncheck: govGate }, laneCtx), laneCtx) : {};
1085
1561
  for (const [store, count] of Object.entries(govDelivery.dispositionSuppressed ?? {})) {
1086
1562
  recordDispositionSuppressed(store, count);
1087
1563
  }
1088
1564
  advisoryParts.push(...govDelivery.advisoryParts ?? []);
1089
- const secretsDelivery = secretsLane.render(secretsLane.gate({
1565
+ const secretsDelivery = allowProjectWideFindings ? secretsLane.render(secretsLane.gate({
1090
1566
  gitleaks: gitleaksGate,
1091
1567
  "trivy-secrets": trivySecretsGate
1092
- }, laneCtx), laneCtx);
1568
+ }, laneCtx), laneCtx) : {};
1093
1569
  for (const [store, count] of Object.entries(secretsDelivery.dispositionSuppressed ?? {})) {
1094
1570
  recordDispositionSuppressed(store, count);
1095
1571
  }
@@ -1156,8 +1632,14 @@ ${suffix}`;
1156
1632
  }
1157
1633
  const t3 = Date.now();
1158
1634
  let madgeStats;
1159
- if (getFlag("lens-turn-end-madge") && await depChecker.ensureAvailable()) {
1160
- const madgeFiles = cacheManager.getFilesForMadge(cwd);
1635
+ const madgeAvailabilitySignal = deps.signal;
1636
+ if (getFlag("lens-turn-end-madge") && await bounded(depChecker.ensureAvailable(), {
1637
+ ms: HOOK_WALL_BUDGET_MS.turn_end,
1638
+ signal: madgeAvailabilitySignal,
1639
+ hook: "turn_end",
1640
+ label: "madge.ensureAvailable"
1641
+ })) {
1642
+ const madgeFiles = cacheManager.getFilesForMadge(cwd, turnStateSessionId);
1161
1643
  if (madgeFiles.length > 0) {
1162
1644
  dbg(`turn_end: madge checking ${madgeFiles.length} file(s) for circular deps`);
1163
1645
  const absFiles = madgeFiles.map((file) => path.resolve(cwd, file));
@@ -1186,6 +1668,7 @@ ${suffix}`;
1186
1668
  if (!getFlag("no-tests") && files.length > 0) {
1187
1669
  const seen = new Set;
1188
1670
  const targets = [];
1671
+ const testRootFor = createTurnEndTestRoots(cwd);
1189
1672
  const candidates = [];
1190
1673
  const seenCandidateKeys = new Set;
1191
1674
  for (const file of files) {
@@ -1216,14 +1699,11 @@ ${suffix}`;
1216
1699
  const resolvedDeferralKeys = new Set;
1217
1700
  const heldDeferred = [];
1218
1701
  const boundPersisted = (entries, label) => {
1219
- const ordered = [
1220
- ...entries.filter((entry) => !isThisSession(entry)),
1221
- ...entries.filter(isThisSession)
1222
- ];
1223
- if (ordered.length <= TEST_RUNNER_MAX_PERSISTED_TARGETS)
1224
- return ordered;
1225
- dbg(`turn_end: ${label} test target list held ${ordered.length} entries, bounded to the newest ${TEST_RUNNER_MAX_PERSISTED_TARGETS} (oldest foreign-session rows dropped)`);
1226
- return ordered.slice(-TEST_RUNNER_MAX_PERSISTED_TARGETS);
1702
+ const bounded = boundDeferredTargets(entries, TEST_RUNNER_MAX_PERSISTED_TARGETS, isThisSession);
1703
+ if (bounded.length !== entries.length) {
1704
+ dbg(`turn_end: ${label} test target list held ${entries.length} entries, bounded to the newest ${TEST_RUNNER_MAX_PERSISTED_TARGETS} (oldest foreign-session rows dropped)`);
1705
+ }
1706
+ return bounded;
1227
1707
  };
1228
1708
  const writeTestFindings = (record, ownDeferred) => {
1229
1709
  const live = cacheManager.readCache("test-runner-findings", cwd)?.data;
@@ -1272,14 +1752,15 @@ ${suffix}`;
1272
1752
  incrementDegradationCount({
1273
1753
  kind: "test-runner-batch-capped",
1274
1754
  subject: `${cwd}:deferral-exhausted`,
1275
- reason: `test target ${path.relative(cwd, testFile)} was cut at the turn-end batch budget ${attempts} turn(s) running and is retired from turn-end selection for the rest of this session — too slow for a per-turn batch, run it explicitly`
1755
+ reason: `test target was cut after ${attempts} turn(s) at the turn-end budget and is retired for this session — too slow for a per-turn batch; run it explicitly (target: ${path.relative(cwd, testFile)})`
1276
1756
  });
1277
1757
  dbg(`turn_end: retiring deferred test target ${path.relative(cwd, testFile)} after ${attempts} cut batch(es) — too slow for the turn-end budget, run it explicitly`);
1278
1758
  }
1279
1759
  continue;
1280
1760
  }
1281
1761
  const config = RUNNERS[carried.runner];
1282
- if (!config || isExcludedTestTarget(testFile, cwd) || !fs.existsSync(testFile)) {
1762
+ const carriedRoot = testRootFor(testFile);
1763
+ if (!config || isExcludedTestTarget(testFile, carriedRoot) || !fs.existsSync(testFile)) {
1283
1764
  resolvedDeferralKeys.add(carriedKey);
1284
1765
  deadDeferred++;
1285
1766
  continue;
@@ -1304,6 +1785,7 @@ ${suffix}`;
1304
1785
  runner: carried.runner,
1305
1786
  config,
1306
1787
  strategy: "deferred",
1788
+ testRoot: carriedRoot,
1307
1789
  deferralAttempts: attempts
1308
1790
  });
1309
1791
  dbg(`turn_end: re-running deferred test target ${path.relative(cwd, testFile)} (${carried.runner}) from the previous turn's cut batch`);
@@ -1339,8 +1821,12 @@ ${suffix}`;
1339
1821
  let missingTargetFiles = 0;
1340
1822
  let excludedTargets = 0;
1341
1823
  let retiredSkips = 0;
1824
+ let noTestFile = 0;
1825
+ const candidatesByRoot = new Map;
1342
1826
  for (const { display, abs, isNeighbor } of candidates) {
1343
- const target = testRunnerClient.getTestRunTarget(abs, cwd, runtime.turnIndex);
1827
+ const testRoot = testRootFor(abs);
1828
+ candidatesByRoot.set(testRoot, (candidatesByRoot.get(testRoot) ?? 0) + 1);
1829
+ const target = testRunnerClient.getTestRunTarget(abs, testRoot, runtime.turnIndex);
1344
1830
  const targetKey = target ? normalizeMapKey(target.testFile) : "";
1345
1831
  if (target && !seen.has(targetKey)) {
1346
1832
  seen.add(targetKey);
@@ -1349,9 +1835,9 @@ ${suffix}`;
1349
1835
  dbg(`turn_end: ${display} → test target retired earlier this session (outran the turn-end batch budget), skipping spawn (${path.relative(cwd, target.testFile)})`);
1350
1836
  continue;
1351
1837
  }
1352
- if (isExcludedTestTarget(target.testFile, cwd)) {
1838
+ if (isExcludedTestTarget(target.testFile, testRoot)) {
1353
1839
  excludedTargets++;
1354
- dbg(`turn_end: ${display} → test target excluded (integration/e2e), skipping spawn (${path.relative(cwd, target.testFile)})`);
1840
+ dbg(`turn_end: ${display} → test target excluded by the built-in turn-end policy, skipping spawn (${path.relative(cwd, target.testFile)})`);
1355
1841
  continue;
1356
1842
  }
1357
1843
  if (!fs.existsSync(target.testFile)) {
@@ -1363,14 +1849,15 @@ ${suffix}`;
1363
1849
  overCapTargets++;
1364
1850
  continue;
1365
1851
  }
1366
- targets.push({ ...target, sourceFile: abs });
1852
+ targets.push({ ...target, sourceFile: abs, testRoot });
1367
1853
  dbg(`turn_end: ${display} → test ${target.runner} ${path.relative(cwd, target.testFile)} (${target.strategy}${isNeighbor ? ", cascade-neighbor" : ""})`);
1368
1854
  } else if (!target) {
1855
+ noTestFile++;
1369
1856
  dbg(`turn_end: ${display} → no test file found${isNeighbor ? " (cascade-neighbor)" : ""}`);
1370
1857
  }
1371
1858
  }
1372
1859
  if (excludedTargets > 0) {
1373
- dbg(`turn_end: excluded ${excludedTargets} test target(s) under the built-in integration/e2e exclusion list`);
1860
+ dbg(`turn_end: excluded ${excludedTargets} test target(s) by the built-in turn-end policy`);
1374
1861
  }
1375
1862
  if (retiredSkips > 0) {
1376
1863
  dbg(`turn_end: skipped ${retiredSkips} test target(s) retired earlier this session for outrunning the turn-end batch budget`);
@@ -1386,6 +1873,33 @@ ${suffix}`;
1386
1873
  });
1387
1874
  dbg(`turn_end: test target count capped at ${TEST_RUNNER_MAX_TARGETS}, ${overCapTargets} skipped`);
1388
1875
  }
1876
+ if (candidates.length > 0) {
1877
+ const selectedByRoot = new Map;
1878
+ for (const target of targets) {
1879
+ selectedByRoot.set(target.testRoot, (selectedByRoot.get(target.testRoot) ?? 0) + 1);
1880
+ }
1881
+ const roots = [...candidatesByRoot.entries()].map(([root, candidateCount]) => ({
1882
+ root: root === cwd ? "." : toRunnerDisplayPath(cwd, root),
1883
+ candidates: candidateCount,
1884
+ selected: selectedByRoot.get(root) ?? 0
1885
+ }));
1886
+ emitBounded("turn_end_test_selection", `${cwd}:turn:${runtime.turnIndex}`, {
1887
+ filePath: cwd,
1888
+ durationMs: 0,
1889
+ metadata: {
1890
+ sessionId: turnSessionId,
1891
+ candidates: candidates.length,
1892
+ selected: targets.length,
1893
+ noTestFile,
1894
+ excluded: excludedTargets,
1895
+ missing: missingTargetFiles,
1896
+ overCap: overCapTargets,
1897
+ retired: retiredSkips,
1898
+ roots: roots.slice(0, TURN_END_SELECTION_ROOT_ROWS),
1899
+ rootsOmitted: Math.max(0, roots.length - TURN_END_SELECTION_ROOT_ROWS)
1900
+ }
1901
+ });
1902
+ }
1389
1903
  if (targets.length > 0) {
1390
1904
  for (const target of targets) {
1391
1905
  target.fileSeqAtRun = runtime.getFileSeq(target.sourceFile);
@@ -1419,15 +1933,32 @@ ${suffix}`;
1419
1933
  concurrency: TEST_RUNNER_BATCH_CONCURRENCY,
1420
1934
  budgetMs: TEST_RUNNER_BATCH_BUDGET_MS,
1421
1935
  signal: getAmbientAbortSignal(),
1422
- run: (t, batchSignal) => testRunnerClient.runTestFileAsync(t.testFile, cwd, {
1936
+ run: (t, batchSignal) => testRunnerClient.runTestFileAsync(t.testFile, t.testRoot, {
1423
1937
  runner: t.runner,
1424
1938
  config: t.config,
1425
1939
  turnIndex: firedAtTurn,
1426
- signal: batchSignal
1940
+ signal: batchSignal,
1941
+ displayRoot: cwd,
1942
+ requireOwnInstall: t.testRoot !== cwd
1427
1943
  })
1428
- }).then(({ results, deferred, stopReason }) => {
1429
- const settledResults = results;
1430
- const verdicts = settledResults.flatMap((result) => {
1944
+ }).then(({ results: batchResults, deferred, stopReason }) => {
1945
+ const settledResults = batchResults;
1946
+ const results = [];
1947
+ for (const result of settledResults) {
1948
+ if (!("value" in result) || !result.value.notRun) {
1949
+ results.push(result);
1950
+ continue;
1951
+ }
1952
+ const skippedRoot = targets.find((candidate) => candidate.testFile === result.value.file)?.testRoot ?? cwd;
1953
+ const ambientNote = result.value.runner === "pytest" && hasAmbientPythonEnvironment() ? "; ambient Python environments outside this checkout were not borrowed" : "";
1954
+ incrementDegradationCount({
1955
+ kind: "turn-end-test-root-skipped",
1956
+ subject: result.value.notRun,
1957
+ reason: `${toRunnerDisplayPath(cwd, skippedRoot)} has no ${result.value.runner} install of its own${ambientNote}; its tests were skipped rather than fetched through npx or run in another environment`
1958
+ });
1959
+ dbg(`turn_end: skipped ${toRunnerDisplayPath(cwd, result.value.file)}: ${result.value.notRun} in ${toRunnerDisplayPath(cwd, skippedRoot)}`);
1960
+ }
1961
+ const verdicts = results.flatMap((result) => {
1431
1962
  if (result.status === "rejected")
1432
1963
  return [];
1433
1964
  const target = targets.find((candidate) => candidate.testFile === result.value.file);
@@ -1435,6 +1966,7 @@ ${suffix}`;
1435
1966
  {
1436
1967
  file: result.value.file,
1437
1968
  sourceFile: target.sourceFile,
1969
+ runner: target.runner,
1438
1970
  fileSeq: target.fileSeqAtRun === undefined ? {
1439
1971
  state: "unknown",
1440
1972
  reason: "sequence-unavailable"
@@ -1672,7 +2204,12 @@ ${suffix}`;
1672
2204
  const impactLines = [];
1673
2205
  let callGraphDispositionSuppressed = 0;
1674
2206
  const impactFindings = [];
1675
- for (const filePath of files.slice(0, 5)) {
2207
+ const impactFiles = files.slice(0, 5);
2208
+ const impactFileKeys = new Set(impactFiles.map((file) => normalizeMapKey(resolveRunnerPath(cwd, file))));
2209
+ const reOfferedImpactFiles = takeParked(carryLane("call-graph")).filter((file) => !impactFileKeys.has(normalizeMapKey(resolveRunnerPath(cwd, file))));
2210
+ const shownImpactFiles = [];
2211
+ for (const filePath of [...impactFiles, ...reOfferedImpactFiles]) {
2212
+ const linesBefore = impactLines.length;
1676
2213
  const changedFileKey = normalizeMapKey(resolveRunnerPath(cwd, filePath));
1677
2214
  const fileCallerKeys = [...runtime.callGraph.callers.keys()].filter((k) => {
1678
2215
  const graphFilePath = parseSymbolKey(k).filePath;
@@ -1698,11 +2235,15 @@ ${suffix}`;
1698
2235
  impactLines.push(` ${parseSymbolKey(calleeKey).symbolName ?? calleeKey}: ${summary}`);
1699
2236
  }
1700
2237
  }
2238
+ if (impactLines.length > linesBefore)
2239
+ shownImpactFiles.push(filePath);
1701
2240
  }
1702
2241
  if (impactLines.length > 0) {
1703
- advisoryParts.push(`\uD83D\uDCCA Call-graph impact (changed symbols have callers):
2242
+ const impactPart = `\uD83D\uDCCA Call-graph impact (changed symbols have callers):
1704
2243
  ${impactLines.join(`
1705
- `)}`);
2244
+ `)}`;
2245
+ advisoryParts.push(impactPart);
2246
+ deliveryHolds.push(cutAdvisoryHold("call-graph", carryLane("call-graph"), impactPart, shownImpactFiles, (file) => !impactFiles.includes(file)));
1706
2247
  }
1707
2248
  if (impactFindings.length > 0) {
1708
2249
  const impactDiagnostics = callGraphImpactToProjectDiagnostics(cwd, impactFindings);
@@ -1780,10 +2321,12 @@ ${impactLines.join(`
1780
2321
  turnIndex: runtime.turnIndex,
1781
2322
  files,
1782
2323
  modifiedRangesByFile,
1783
- dispatchWarnings: runtime.peekActionableWarnings(),
2324
+ dispatchWarnings: runtime.peekActionableWarnings(sessionId),
1784
2325
  includeLspCodeActions: !!getFlag("lens-actionable-warning-actions"),
1785
2326
  projectSeqStart: runtime.turnStartProjectSeq,
1786
2327
  projectSeqEnd: runtime.projectSeq,
2328
+ branchEpoch: runtime.readGuard.currentBranchEpoch,
2329
+ branchScope: runtime.readGuard.lineageKey,
1787
2330
  fileSeqByPath,
1788
2331
  deltaOnly: !getFlag("lens-actionable-warning-all"),
1789
2332
  dbg,
@@ -1882,7 +2425,7 @@ ${impactLines.join(`
1882
2425
  const t5 = Date.now();
1883
2426
  try {
1884
2427
  const qualityWarningsByFile = new Map;
1885
- for (const warning of runtime.peekCodeQualityWarnings()) {
2428
+ for (const warning of runtime.peekCodeQualityWarnings(sessionId)) {
1886
2429
  const group = qualityWarningsByFile.get(warning.filePath);
1887
2430
  if (group)
1888
2431
  group.push(warning);
@@ -1946,97 +2489,25 @@ ${impactLines.join(`
1946
2489
  }
1947
2490
  });
1948
2491
  }
1949
- cacheManager.incrementTurnCycle(cwd, currentOwner);
1950
- const runnerFindingsStart = Date.now();
1951
- const pendingRunnerFindings = await drainPendingRunnerFindings(0);
1952
- let runnerFindingsDelivered = 0;
1953
- let runnerFindingsStale = 0;
1954
- let runnerFindingsFailed = 0;
1955
- let runnerFindingsDropped = 0;
1956
- let runnerFindingsDispositionSuppressed = 0;
1957
- const runnerFindingsDeliveredIds = [];
1958
- for (const pending of pendingRunnerFindings) {
1959
- const result = pending.result;
1960
- if (!result)
1961
- continue;
1962
- recordRunner(pending.filePath, pending.runnerId, result.status, result.diagnostics.length, Date.now() - pending.markedAtMs, pending.writeIndex);
1963
- if (result.status === "failed") {
1964
- runnerFindingsFailed += 1;
1965
- const detail = result.failureMessage ? `: ${result.failureMessage}` : "";
1966
- advisoryParts.push(`❌ Deferred runner ${pending.runnerId} failed (${result.failureKind ?? "unknown"})${detail}`);
1967
- continue;
1968
- }
1969
- const findings = result.diagnostics;
1970
- if (findings.length === 0)
1971
- continue;
1972
- const { "late-runner-findings": gate } = gateFindingsByPathFreshness({
1973
- cwd,
1974
- sources: {
1975
- "late-runner-findings": {
1976
- findings,
1977
- scannedAt: pending.markedAtMs,
1978
- citedPath: (finding) => finding.filePath
1979
- }
1980
- }
1981
- });
1982
- runnerFindingsStale += gate.stale.length;
1983
- if (gate.stale.length > 0) {
1984
- dropStaleRunnerFindings(pending);
1985
- runnerFindingsDropped += 1;
1986
- }
1987
- if (gate.live.length === 0)
1988
- continue;
1989
- const displayPath = toRunnerDisplayPath(cwd, pending.filePath);
1990
- let runnerContent;
1991
- try {
1992
- runnerContent = fs.readFileSync(pending.filePath, "utf-8");
1993
- } catch {
1994
- runnerContent = undefined;
1995
- }
1996
- const { kept: runnerKept, suppressed: runnerSuppressedHere } = applyPushedFindingPolicy(gate.live, {
1997
- cwd,
1998
- filePath: pending.filePath,
1999
- content: runnerContent
2000
- });
2001
- runnerFindingsDispositionSuppressed += runnerSuppressedHere;
2002
- if (runnerKept.length === 0) {
2003
- continue;
2004
- }
2005
- const lines = runnerKept.map((finding) => ` ${displayPath}:${finding.line ?? 1}:${finding.column ?? 1} [${finding.rule ?? finding.id}] ${finding.message}`);
2006
- runnerFindingsDelivered += runnerKept.length;
2007
- for (const finding of runnerKept) {
2008
- if (runnerFindingsDeliveredIds.length < 50) {
2009
- runnerFindingsDeliveredIds.push(finding.id);
2010
- }
2011
- }
2012
- const runnerSuppressedNote = runnerSuppressedHere > 0 ? `; suppressed by disposition: ${runnerSuppressedHere} finding(s)` : "";
2013
- advisoryParts.push(`⏱️ Late runner diagnostics (${pending.runnerId} completed after the edit${runnerSuppressedNote}):
2014
- ${lines.join(`
2015
- `)}`);
2016
- }
2017
- logLatency({
2018
- type: "phase",
2019
- toolName: "turn_end",
2020
- filePath: cwd,
2021
- phase: "late_runner_findings",
2022
- durationMs: Date.now() - runnerFindingsStart,
2023
- metadata: {
2024
- pending: pendingRunnerFindings.length,
2025
- delivered: runnerFindingsDelivered,
2026
- stale: runnerFindingsStale,
2027
- failed: runnerFindingsFailed,
2028
- dropped: runnerFindingsDropped,
2029
- dispositionSuppressed: runnerFindingsDispositionSuppressed,
2030
- deliveredIds: runnerFindingsDeliveredIds
2031
- }
2032
- });
2492
+ cacheManager.incrementTurnCycle(cwd, currentOwner, turnStateSessionId);
2033
2493
  const lateAuxStart = Date.now();
2034
- const drainedPairs = drainPendingAuxiliaryCoverage();
2035
- const lateAuxCapEvicted = drainPendingAuxCapEvictedCount();
2494
+ const lateAuxDrain = isSecondarySession ? {
2495
+ drainedPairs: drainPendingAuxiliaryCoverage(),
2496
+ lateAuxCapEvicted: drainPendingAuxCapEvictedCount()
2497
+ } : holdScope.guardedWrite("turn-end:late-aux", () => ({
2498
+ drainedPairs: drainPendingAuxiliaryCoverage(),
2499
+ lateAuxCapEvicted: drainPendingAuxCapEvictedCount()
2500
+ })) ?? { drainedPairs: [], lateAuxCapEvicted: 0 };
2501
+ const { drainedPairs, lateAuxCapEvicted } = lateAuxDrain;
2502
+ const rearmLateAux = (pair) => isSecondarySession ? (rearmPendingAuxiliaryCoverage(pair), true) : holdScope.guardedWrite("turn-end:late-aux-rearm", () => {
2503
+ rearmPendingAuxiliaryCoverage(pair);
2504
+ return true;
2505
+ }) === true;
2036
2506
  let lateAuxDelivered = 0;
2037
2507
  let lateAuxStale = 0;
2038
2508
  let lateAuxMissing = 0;
2039
2509
  let lateAuxRearmed = 0;
2510
+ let lateAuxBacklogPending = 0;
2040
2511
  let lateAuxClientGone = 0;
2041
2512
  let lateAuxProbeFailed = 0;
2042
2513
  let lateAuxCleanConfirmed = 0;
@@ -2044,6 +2515,9 @@ ${lines.join(`
2044
2515
  let lateAuxCeilingExhausted = 0;
2045
2516
  let lateAuxAnswered = 0;
2046
2517
  let lateAuxNotifyStallDemoted = 0;
2518
+ let lateAuxHoldRearmed = 0;
2519
+ let lateAuxHoldExpired = 0;
2520
+ let lateAuxHoldCeiling = 0;
2047
2521
  let lateAuxDispositionSuppressed = 0;
2048
2522
  let lateAuxAuxSuppressed = 0;
2049
2523
  const lateAuxCoverageGapPairs = [];
@@ -2069,9 +2543,9 @@ ${lines.join(`
2069
2543
  } catch {
2070
2544
  lateAuxProbeFailed += pairs.length;
2071
2545
  for (const pair of pairs) {
2072
- if (!isPendingAuxiliaryPastRearmTtl(pair) && (pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
2073
- rearmPendingAuxiliaryCoverage(pair);
2074
- lateAuxRearmed += 1;
2546
+ if (canRearmPendingAuxiliary(pair)) {
2547
+ if (rearmLateAux(pair))
2548
+ lateAuxRearmed += 1;
2075
2549
  } else if (isPendingAuxiliaryPastRearmTtl(pair)) {
2076
2550
  lateAuxExpired += 1;
2077
2551
  } else {
@@ -2109,13 +2583,14 @@ ${lines.join(`
2109
2583
  const pastTtl = isPendingAuxiliaryPastRearmTtl(pair);
2110
2584
  const atCeiling = (pair.rearmCount ?? 0) >= MAX_LATE_AUX_REARMS;
2111
2585
  if (!pastTtl && !atCeiling) {
2112
- rearmPendingAuxiliaryCoverage(pair);
2113
- lateAuxRearmed += 1;
2114
- if (lateAuxStuckPairs.length < 20)
2115
- lateAuxStuckPairs.push({
2116
- filePath: pair.filePath,
2117
- serverId: pair.serverId
2118
- });
2586
+ if (rearmLateAux(pair)) {
2587
+ lateAuxRearmed += 1;
2588
+ if (lateAuxStuckPairs.length < 20)
2589
+ lateAuxStuckPairs.push({
2590
+ filePath: pair.filePath,
2591
+ serverId: pair.serverId
2592
+ });
2593
+ }
2119
2594
  } else {
2120
2595
  if (pastTtl)
2121
2596
  lateAuxExpired += 1;
@@ -2129,15 +2604,19 @@ ${lines.join(`
2129
2604
  continue;
2130
2605
  }
2131
2606
  const rawDiags = cachedEntry.diags;
2132
- if (cachedEntry.publishedAt === undefined || cachedEntry.publishedAt <= pair.markedAtMs) {
2133
- if (!isPendingAuxiliaryPastRearmTtl(pair) && (pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
2134
- rearmPendingAuxiliaryCoverage(pair);
2135
- lateAuxRearmed += 1;
2136
- if (lateAuxStuckPairs.length < 20)
2137
- lateAuxStuckPairs.push({
2138
- filePath: pair.filePath,
2139
- serverId: pair.serverId
2140
- });
2607
+ const backlogPending = !isAuxBacklogPublished(pair);
2608
+ if (backlogPending)
2609
+ lateAuxBacklogPending += 1;
2610
+ if (cachedEntry.publishedAt === undefined || cachedEntry.publishedAt <= pair.markedAtMs || backlogPending) {
2611
+ if (canRearmPendingAuxiliary(pair)) {
2612
+ if (rearmLateAux(pair)) {
2613
+ lateAuxRearmed += 1;
2614
+ if (lateAuxStuckPairs.length < 20)
2615
+ lateAuxStuckPairs.push({
2616
+ filePath: pair.filePath,
2617
+ serverId: pair.serverId
2618
+ });
2619
+ }
2141
2620
  } else {
2142
2621
  if (isPendingAuxiliaryPastRearmTtl(pair))
2143
2622
  lateAuxExpired += 1;
@@ -2186,9 +2665,9 @@ ${lines.join(`
2186
2665
  lateAuxMissing += retained.length - gate.live.length - gate.stale.length;
2187
2666
  if (gate.live.length === 0) {
2188
2667
  if (gate.stale.length > 0) {
2189
- if (!isPendingAuxiliaryPastRearmTtl(pair) && (pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
2190
- rearmPendingAuxiliaryCoverage(pair, Date.now(), true);
2191
- lateAuxRearmed += 1;
2668
+ if (canRearmPendingAuxiliary(pair)) {
2669
+ if (rearmLateAux(pair))
2670
+ lateAuxRearmed += 1;
2192
2671
  } else if (isPendingAuxiliaryPastRearmTtl(pair)) {
2193
2672
  lateAuxExpired += 1;
2194
2673
  } else {
@@ -2213,9 +2692,29 @@ ${lines.join(`
2213
2692
  lateAuxDelivered += lateAuxKept.length;
2214
2693
  lateAuxAnswered += 1;
2215
2694
  const lateAuxSuppressedNote = lateAuxSuppressedHere > 0 ? `; suppressed by disposition: ${lateAuxSuppressedHere} finding(s)` : "";
2216
- advisoryParts.push(`\uD83D\uDD50 Late auxiliary diagnostics (${pair.serverId} answered after its grace window${lateAuxSuppressedNote}):
2695
+ const lateAuxPart = `\uD83D\uDD50 Late auxiliary diagnostics (${pair.serverId} answered after its grace window${lateAuxSuppressedNote}):
2217
2696
  ${lines.join(`
2218
- `)}`);
2697
+ `)}`;
2698
+ advisoryParts.push(lateAuxPart);
2699
+ deliveryHolds.push({
2700
+ part: lateAuxPart,
2701
+ canHold: () => canRearmPendingAuxiliary(pair),
2702
+ onHeld: () => {
2703
+ rearmPendingAuxiliaryCoverage(pair);
2704
+ lateAuxHoldRearmed += 1;
2705
+ },
2706
+ onDropped: () => {
2707
+ if (isPendingAuxiliaryPastRearmTtl(pair))
2708
+ lateAuxHoldExpired += 1;
2709
+ else
2710
+ lateAuxHoldCeiling += 1;
2711
+ incrementDegradationCount({
2712
+ kind: "late-auxiliary-held-dropped",
2713
+ subject: `late-auxiliary:${pair.serverId}`,
2714
+ reason: "cut by the turn-end cap and past its re-arm bound, so not re-armed"
2715
+ });
2716
+ }
2717
+ });
2219
2718
  }
2220
2719
  }
2221
2720
  } catch (err) {
@@ -2259,6 +2758,7 @@ ${lines.join(`
2259
2758
  stale: lateAuxStale,
2260
2759
  missing: lateAuxMissing,
2261
2760
  rearmed: lateAuxRearmed,
2761
+ backlogPending: lateAuxBacklogPending,
2262
2762
  clientGone: lateAuxClientGone,
2263
2763
  probeFailed: lateAuxProbeFailed,
2264
2764
  cleanConfirmed: lateAuxCleanConfirmed,
@@ -2276,21 +2776,112 @@ ${lines.join(`
2276
2776
  }
2277
2777
  });
2278
2778
  }
2279
- const labeledAdvisoryParts = advisoryParts.map((p) => `ℹ️ Advisory — no action required this turn:
2280
- ${p}`);
2281
- const findingParts = [
2282
- ...blockerParts,
2283
- ...staleSecretParts,
2284
- ...labeledAdvisoryParts
2779
+ const unresolvedKeys = new Set(unresolvedBlockers.map((record) => normalizeMapKey(path.resolve(record.filePath))));
2780
+ const formatResolvedTail = (dropped) => `… and ${dropped} more`;
2781
+ const resolvedTailMax = formatResolvedTail(Number.MAX_SAFE_INTEGER).length;
2782
+ const resolvedShareChars = Math.floor(RUNTIME_CONFIG.turnEnd.maxChars * RESOLVED_SHARE_OF_CHARS) - resolvedTailMax;
2783
+ const formatResolvedLine = (entry) => {
2784
+ const clause = entry.confirmedClean ? " confirmed clean" : entry.writeIndex === undefined ? "" : ` cleared by the ${formatWriteOrdinal(entry.writeIndex)} write`;
2785
+ const label = entry.turnIndex === runtime.turnIndex ? "Resolved this turn" : "Resolved since the last report";
2786
+ const head = `${label}: `;
2787
+ const tail = ` (${entry.blockerCount} blocker(s)${clause})`;
2788
+ let display = toRunnerDisplayPath(cwd, entry.filePath);
2789
+ const room = resolvedShareChars - 1 - head.length - tail.length;
2790
+ if (display.length > room) {
2791
+ const keepHead = Math.ceil((room - 1) / 2);
2792
+ display = `${sliceAtCodePointBoundaries(display, 0, keepHead)}…${sliceAtCodePointBoundaries(display, display.length - (room - 1 - keepHead), display.length)}`;
2793
+ }
2794
+ return `${head}${display}${tail}`;
2795
+ };
2796
+ const blockerText = blockerParts.join(`
2797
+
2798
+ `);
2799
+ const blockerChars = blockerParts.length > 0 ? blockerText.length + 2 : 0;
2800
+ const blockerLines = blockerParts.length > 0 ? blockerText.split(`
2801
+ `).length + 1 : 0;
2802
+ const resolvedCharBudget = Math.min(resolvedShareChars, RUNTIME_CONFIG.turnEnd.maxChars - blockerChars - resolvedTailMax);
2803
+ const resolvedLineBudget = Math.min(RESOLVED_MAX_LINES, RUNTIME_CONFIG.turnEnd.maxLines - blockerLines) - 1;
2804
+ let resolvedChars = 0;
2805
+ let resolvedCount = 0;
2806
+ const {
2807
+ files: resolvedBlockerFileList,
2808
+ dropped: resolvedBlockerFilesDropped
2809
+ } = runtime.consumeResolvedBlockerFiles((entry) => {
2810
+ if (unresolvedKeys.has(normalizeMapKey(path.resolve(entry.filePath))))
2811
+ return true;
2812
+ const cost = formatResolvedLine(entry).length + 1;
2813
+ if (resolvedCount > 0 && (resolvedCount >= resolvedLineBudget || resolvedChars + cost > resolvedCharBudget))
2814
+ return true;
2815
+ resolvedChars += cost;
2816
+ resolvedCount += 1;
2817
+ return false;
2818
+ });
2819
+ const resolvedLines = resolvedBlockerFileList.map(formatResolvedLine);
2820
+ if (resolvedBlockerFilesDropped > 0) {
2821
+ resolvedLines.push(formatResolvedTail(resolvedBlockerFilesDropped));
2822
+ }
2823
+ const resolvedParts = resolvedLines.length > 0 ? [resolvedLines.join(`
2824
+ `)] : [];
2825
+ const asIs = (raw) => ({ raw, text: raw });
2826
+ const composedParts = [
2827
+ ...resolvedParts.map(asIs),
2828
+ ...blockerParts.map(asIs),
2829
+ ...staleSecretParts.map(asIs),
2830
+ ...advisoryParts.map((raw) => ({
2831
+ raw,
2832
+ text: `ℹ️ Advisory — no action required this turn:
2833
+ ${raw}`
2834
+ }))
2285
2835
  ];
2836
+ const findingParts = composedParts.map((part) => part.text);
2837
+ let heldSections = 0;
2286
2838
  if (findingParts.length > 0) {
2287
2839
  dbg(`turn_end: ${blockerParts.length} blocker section(s), ${advisoryParts.length} advisory section(s) found, persisting for next context`);
2288
- const content = capTurnEndMessage(findingParts.join(`
2840
+ const joined = findingParts.join(`
2841
+
2842
+ `);
2843
+ const holdPlan = planDeliveryHolds({
2844
+ holds: deliveryHolds,
2845
+ parts: composedParts,
2846
+ keptChars: turnEndKeptChars(joined),
2847
+ separatorLength: `
2289
2848
 
2290
- `));
2849
+ `.length
2850
+ });
2851
+ const settleHolds = (suppressed) => {
2852
+ const outcome = holdPlan.settle({
2853
+ suppressed,
2854
+ isCurrentSession: () => holdScope.isCurrent(),
2855
+ onFault: (cause) => dbg(`turn_end: delivery hold failed: ${cause}`)
2856
+ });
2857
+ heldSections = outcome.held;
2858
+ if (lateAuxHoldRearmed + lateAuxHoldExpired + lateAuxHoldCeiling > 0) {
2859
+ logLatency({
2860
+ type: "phase",
2861
+ toolName: "turn_end",
2862
+ filePath: cwd,
2863
+ phase: "late_auxiliary_holds",
2864
+ durationMs: 0,
2865
+ metadata: {
2866
+ rearmed: lateAuxHoldRearmed,
2867
+ expired: lateAuxHoldExpired,
2868
+ ceilingExhausted: lateAuxHoldCeiling,
2869
+ pendingAfter: pendingAuxiliaryCoverageSize()
2870
+ }
2871
+ });
2872
+ }
2873
+ if (outcome.held > 0) {
2874
+ incrementDegradationCount({
2875
+ kind: "turn-end-sections-held",
2876
+ subject: "turn-end",
2877
+ reason: `${outcome.held} one-shot section(s) cut by the turn-end cap, kept pending for the next turn`
2878
+ });
2879
+ }
2880
+ };
2881
+ const content = capTurnEndMessage(joined, holdPlan.heldCount);
2291
2882
  const signature = `${files.slice().sort((a, b) => compareOrdinal(a, b)).join("|")}::${content}`;
2292
2883
  const last = cacheManager.readCache("turn-end-findings-last", cwd);
2293
- if (last?.data?.signature === signature && last?.data?.sessionId === runtime.telemetrySessionId) {
2884
+ if (last?.data?.signature === signature && last?.data?.sessionId === runtime.telemetrySessionId && resolvedBlockerFileList.length === 0) {
2294
2885
  dbg("turn_end: duplicate findings detected (same session), suppressing re-prompt");
2295
2886
  if (getFlag("lens-guard")) {
2296
2887
  const existingGuard = cacheManager.readCache("turn-end-findings", cwd)?.data;
@@ -2314,13 +2905,13 @@ ${p}`);
2314
2905
  });
2315
2906
  }
2316
2907
  }
2908
+ settleHolds(true);
2317
2909
  clearOwnedTurnState();
2318
2910
  runtime.fixedThisTurn.clear();
2319
2911
  resetFormatService();
2320
2912
  return;
2321
2913
  }
2322
- for (const commit of pendingDependencyDriftDeliveries)
2323
- commit();
2914
+ settleHolds(false);
2324
2915
  const fileSeqByPath = {};
2325
2916
  for (const [filePath, seq] of runtime.getFileSeqEntries()) {
2326
2917
  fileSeqByPath[normalizeMapKey(path.resolve(filePath))] = seq;
@@ -2394,7 +2985,7 @@ ${p}`);
2394
2985
  }
2395
2986
  if (blockerParts.length === 0) {
2396
2987
  clearOwnedTurnState();
2397
- if (getFlag("lens-guard") && advisoryParts.length === 0 && staleSecretParts.length === 0 && !runtime.gitGuardHasBlockers) {
2988
+ if (getFlag("lens-guard") && advisoryParts.length === 0 && staleSecretParts.length === 0 && resolvedParts.length === 0 && !runtime.gitGuardHasBlockers) {
2398
2989
  const guardRecord = cacheManager.readCache("turn-end-findings", cwd)?.data;
2399
2990
  if (guardRecord?.sessionId === runtime.telemetrySessionId && guardRecord.testFailures !== true) {
2400
2991
  cacheManager.clearCache("turn-end-findings", cwd);
@@ -2402,8 +2993,8 @@ ${p}`);
2402
2993
  }
2403
2994
  }
2404
2995
  runtime.fixedThisTurn.clear();
2405
- runtime.clearActionableWarnings();
2406
- runtime.clearCodeQualityWarnings();
2996
+ runtime.clearActionableWarnings(sessionId);
2997
+ runtime.clearCodeQualityWarnings(sessionId);
2407
2998
  if (demotedFindingsRetired > 0) {
2408
2999
  cacheManager.clearCache("turn-end-findings-last", cwd);
2409
3000
  }
@@ -2418,6 +3009,9 @@ ${p}`);
2418
3009
  blockerSections: blockerParts.length,
2419
3010
  staleSecretSections: staleSecretParts.length,
2420
3011
  advisorySections: advisoryParts.length,
3012
+ resolvedBlockerFiles: resolvedBlockerFileList.length,
3013
+ resolvedBlockerFilesDropped,
3014
+ heldSections,
2421
3015
  demotedFindingsRetired,
2422
3016
  widgetDemotedFindingsRetired
2423
3017
  }