@herbertgao/pi-extensions 2026.8.11 → 2026.8.13

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 (476) hide show
  1. package/README.md +23 -10
  2. package/{node_modules/@herbertgao/pi-mermaid-open/LICENSE → THIRD_PARTY_NOTICES.md} +19 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +15 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -3
  5. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +2 -0
  6. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +60 -0
  7. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +1 -0
  8. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +4 -4
  9. package/node_modules/@czottmann/pi-automode/docs/configuration.md +20 -4
  10. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +1 -1
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +692 -0
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +181 -3
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +4 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +143 -36
  15. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +103 -148
  16. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +32 -6
  17. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +344 -22
  18. package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +1 -0
  19. package/node_modules/@czottmann/pi-automode/package.json +4 -1
  20. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -1
  21. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -1
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +4 -0
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +21 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +1 -1
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +19 -19
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +4 -2
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +2 -1
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +10 -2
  29. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  30. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +10 -0
  31. package/node_modules/@herbertgao/pi-subagents/README.md +21 -15
  32. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  33. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +11 -8
  34. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +184 -106
  35. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +31 -11
  36. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +9 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/index.ts +156 -31
  38. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +17 -0
  39. package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +14 -0
  40. package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +8 -0
  41. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +32 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/types.ts +17 -2
  43. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +23 -2
  44. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +259 -24
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  46. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
  47. package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
  48. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
  49. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
  50. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
  51. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
  52. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
  53. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  54. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  55. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
  56. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
  57. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
  58. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
  59. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
  60. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
  61. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
  62. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
  63. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
  64. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
  65. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
  66. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
  67. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
  68. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
  69. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
  70. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
  71. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
  72. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
  73. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
  74. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
  75. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
  76. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
  77. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
  78. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
  79. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
  80. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
  81. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
  82. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
  83. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
  84. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
  85. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
  86. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
  87. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
  88. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
  89. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
  90. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
  91. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
  92. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
  93. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
  94. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
  95. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
  96. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
  97. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
  98. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
  99. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
  100. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
  101. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
  102. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
  103. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
  104. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
  105. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
  106. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
  107. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
  108. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
  109. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
  110. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
  111. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
  112. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
  113. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
  114. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
  115. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
  116. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
  117. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
  118. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
  119. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
  120. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
  121. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
  122. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
  123. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
  124. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
  125. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
  126. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
  127. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
  128. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
  129. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
  130. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
  131. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
  132. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
  133. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
  134. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
  135. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
  136. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
  137. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
  138. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
  139. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
  140. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
  141. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
  142. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
  143. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
  144. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
  145. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
  146. package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
  147. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
  148. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -46
  149. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  150. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  151. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +136 -22
  152. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/README.md +2 -4
  153. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/package.json +5 -15
  154. package/node_modules/{@herbertgao → @tifan}/pi-handoff/README.md +4 -6
  155. package/node_modules/@tifan/pi-handoff/package.json +43 -0
  156. package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/index.ts +1 -1
  157. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/README.md +2 -4
  158. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/package.json +5 -15
  159. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/README.md +5 -7
  160. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/package.json +5 -19
  161. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/README.md +4 -6
  162. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/package.json +6 -16
  163. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/src/index.ts +1 -6
  164. package/node_modules/{@herbertgao → @tifan}/pi-recap/README.md +4 -6
  165. package/node_modules/@tifan/pi-recap/package.json +42 -0
  166. package/node_modules/{@herbertgao → @tifan}/pi-recap/src/models.ts +1 -6
  167. package/node_modules/{@herbertgao → @tifan}/pi-rename/README.md +13 -8
  168. package/node_modules/@tifan/pi-rename/package.json +47 -0
  169. package/node_modules/@tifan/pi-rename/src/herdr-label.ts +4 -0
  170. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/index.ts +4 -16
  171. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/models.ts +1 -6
  172. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/README.md +2 -4
  173. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/package.json +5 -15
  174. package/node_modules/pi-lens/CHANGELOG.md +96 -1
  175. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +14 -5
  177. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +48 -18
  178. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -3
  179. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +16 -4
  180. package/node_modules/pi-lens/dist/clients/bash-file-access.js +3 -1
  181. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -3
  182. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +21 -8
  183. package/node_modules/pi-lens/dist/clients/bounded-cache.js +24 -8
  184. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +4 -3
  185. package/node_modules/pi-lens/dist/clients/cache-manager.js +6 -7
  186. package/node_modules/pi-lens/dist/clients/cache-observability.js +461 -66
  187. package/node_modules/pi-lens/dist/clients/call-graph.js +238 -63
  188. package/node_modules/pi-lens/dist/clients/codebase-model.js +13 -5
  189. package/node_modules/pi-lens/dist/clients/complexity-client.js +1 -3
  190. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -8
  191. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +1 -2
  192. package/node_modules/pi-lens/dist/clients/deadline-utils.js +3 -1
  193. package/node_modules/pi-lens/dist/clients/debug-heap.js +8 -1
  194. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +1 -1
  195. package/node_modules/pi-lens/dist/clients/dependency-checker.js +11 -7
  196. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -2
  197. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +5 -1
  198. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +2 -3
  199. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +13 -1
  200. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +3 -1
  201. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +2 -1
  202. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -4
  204. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +3 -1
  205. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
  206. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
  207. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +5 -2
  208. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +10 -14
  209. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +5 -1
  210. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +1 -1
  211. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +3 -1
  212. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +25 -6
  213. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +1 -1
  214. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +1 -1
  215. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +3 -1
  216. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +13 -8
  217. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +4 -1
  218. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +25 -10
  219. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +28 -4
  223. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +6 -8
  224. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +212 -11
  225. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +1 -1
  226. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +8 -4
  227. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
  228. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +23 -14
  229. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -1
  230. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +7 -9
  231. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +7 -7
  233. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +6 -8
  234. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +13 -8
  235. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +13 -8
  236. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +17 -3
  237. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
  238. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
  239. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +35 -0
  240. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
  241. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +6 -8
  242. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +1 -1
  243. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +2 -1
  244. package/node_modules/pi-lens/dist/clients/dispatch/types.js +6 -1
  245. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
  246. package/node_modules/pi-lens/dist/clients/extension-log.js +5 -3
  247. package/node_modules/pi-lens/dist/clients/feature-hints.js +8 -1
  248. package/node_modules/pi-lens/dist/clients/file-kinds.js +34 -129
  249. package/node_modules/pi-lens/dist/clients/file-utils.js +17 -1
  250. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +57 -2
  251. package/node_modules/pi-lens/dist/clients/formatters.js +144 -27
  252. package/node_modules/pi-lens/dist/clients/freshness.js +38 -0
  253. package/node_modules/pi-lens/dist/clients/git-guard.js +43 -13
  254. package/node_modules/pi-lens/dist/clients/go-client.js +1 -3
  255. package/node_modules/pi-lens/dist/clients/grammar-source.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +30 -4
  257. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +1 -3
  258. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +4 -2
  259. package/node_modules/pi-lens/dist/clients/installer/index.js +86 -77
  260. package/node_modules/pi-lens/dist/clients/instance-reaper.js +5 -2
  261. package/node_modules/pi-lens/dist/clients/instance-registry.js +4 -2
  262. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  263. package/node_modules/pi-lens/dist/clients/knip-client.js +29 -15
  264. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -1
  265. package/node_modules/pi-lens/dist/clients/latency-logger.js +13 -2
  266. package/node_modules/pi-lens/dist/clients/lens-config.js +1 -1
  267. package/node_modules/pi-lens/dist/clients/lens-map.js +8 -3
  268. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +1 -1
  269. package/node_modules/pi-lens/dist/clients/lsp/config.js +4 -6
  270. package/node_modules/pi-lens/dist/clients/lsp/edits.js +119 -32
  271. package/node_modules/pi-lens/dist/clients/lsp/index.js +94 -35
  272. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +2 -1
  273. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +4 -1
  274. package/node_modules/pi-lens/dist/clients/lsp/launch.js +11 -3
  275. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +152 -0
  276. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -7
  277. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +10 -2
  278. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
  279. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -3
  280. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +10 -20
  281. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +1 -1
  282. package/node_modules/pi-lens/dist/clients/memory-sampler.js +73 -7
  283. package/node_modules/pi-lens/dist/clients/metrics-client.js +1 -3
  284. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +8 -3
  285. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +7 -1
  286. package/node_modules/pi-lens/dist/clients/module-report.js +14 -17
  287. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +3 -5
  288. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +220 -0
  289. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -1
  290. package/node_modules/pi-lens/dist/clients/pipeline.js +57 -9
  291. package/node_modules/pi-lens/dist/clients/project-conventions.js +2 -8
  292. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +10 -7
  293. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
  294. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
  295. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
  296. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
  297. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -2
  298. package/node_modules/pi-lens/dist/clients/project-lens-config.js +12 -5
  299. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +48 -0
  300. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +15 -1
  301. package/node_modules/pi-lens/dist/clients/project-snapshot.js +472 -66
  302. package/node_modules/pi-lens/dist/clients/read-expansion.js +12 -2
  303. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +5 -4
  304. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +5 -2
  305. package/node_modules/pi-lens/dist/clients/read-guard.js +1 -1
  306. package/node_modules/pi-lens/dist/clients/resource-sampler.js +1 -1
  307. package/node_modules/pi-lens/dist/clients/reverse-deps.js +6 -5
  308. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +42 -17
  309. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +8 -2
  310. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +10 -1
  311. package/node_modules/pi-lens/dist/clients/review-graph/query.js +2 -1
  312. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +4 -2
  313. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +2 -2
  314. package/node_modules/pi-lens/dist/clients/ruff-client.js +6 -5
  315. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +63 -31
  316. package/node_modules/pi-lens/dist/clients/runtime-context.js +12 -4
  317. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +83 -4
  318. package/node_modules/pi-lens/dist/clients/runtime-session.js +14 -0
  319. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +59 -3
  320. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +148 -34
  321. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -6
  322. package/node_modules/pi-lens/dist/clients/rust-client.js +1 -3
  323. package/node_modules/pi-lens/dist/clients/safe-spawn.js +150 -11
  324. package/node_modules/pi-lens/dist/clients/security-scan-client.js +1 -3
  325. package/node_modules/pi-lens/dist/clients/session-summary.js +3 -1
  326. package/node_modules/pi-lens/dist/clients/sg-runner.js +1 -3
  327. package/node_modules/pi-lens/dist/clients/source-filter.js +10 -6
  328. package/node_modules/pi-lens/dist/clients/source-walker.js +1 -1
  329. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +96 -0
  330. package/node_modules/pi-lens/dist/clients/startup-scan.js +4 -1
  331. package/node_modules/pi-lens/dist/clients/tool-definition.js +7 -0
  332. package/node_modules/pi-lens/dist/clients/tool-policy.js +26 -11
  333. package/node_modules/pi-lens/dist/clients/tool-render.js +2 -1
  334. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +10 -4
  335. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  336. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  337. package/node_modules/pi-lens/dist/clients/warm-attach.js +12 -5
  338. package/node_modules/pi-lens/dist/clients/widget-state.js +27 -11
  339. package/node_modules/pi-lens/dist/clients/word-index.js +3 -1
  340. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -2
  341. package/node_modules/pi-lens/dist/clients/zizmor-config.js +9 -1
  342. package/node_modules/pi-lens/dist/i18n.js +13 -5
  343. package/node_modules/pi-lens/dist/index.js +10797 -8627
  344. package/node_modules/pi-lens/dist/mcp/server.js +3 -1
  345. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +68 -12
  346. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +21 -7
  347. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +164 -35
  348. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +24 -7
  349. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  350. package/node_modules/pi-lens/dist/tools/module-report.js +1 -1
  351. package/node_modules/pi-lens/dist/tools/project-report.js +1 -1
  352. package/node_modules/pi-lens/dist/tools/symbol-search.js +5 -2
  353. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +1 -1
  354. package/node_modules/pi-lens/docs/servercapabilities.md +1 -1
  355. package/node_modules/pi-lens/package.json +160 -156
  356. package/node_modules/pi-lens/rules/typos/_typos.toml +2 -2
  357. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +31 -13
  358. package/node_modules/pi-lens/scripts/download-grammars.js +9 -3
  359. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +30 -9
  360. package/node_modules/pi-mcp-adapter/CHANGELOG.md +47 -0
  361. package/node_modules/pi-mcp-adapter/README.md +42 -13
  362. package/node_modules/pi-mcp-adapter/commands.ts +4 -2
  363. package/node_modules/pi-mcp-adapter/config.ts +45 -5
  364. package/node_modules/pi-mcp-adapter/direct-tools.ts +103 -92
  365. package/node_modules/pi-mcp-adapter/dist/agent-dir.d.ts +10 -0
  366. package/node_modules/pi-mcp-adapter/dist/agent-dir.js +63 -0
  367. package/node_modules/pi-mcp-adapter/dist/agent-dir.js.map +1 -0
  368. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.d.ts +8 -0
  369. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js +356 -0
  370. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js.map +1 -0
  371. package/node_modules/pi-mcp-adapter/dist/config.d.ts +123 -0
  372. package/node_modules/pi-mcp-adapter/dist/config.js +1087 -0
  373. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -0
  374. package/node_modules/pi-mcp-adapter/dist/metadata-cache.d.ts +19 -0
  375. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +319 -0
  376. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -0
  377. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.d.ts +2 -0
  378. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js +156 -0
  379. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js.map +1 -0
  380. package/node_modules/pi-mcp-adapter/dist/resource-tools.d.ts +1 -0
  381. package/node_modules/pi-mcp-adapter/dist/resource-tools.js +15 -0
  382. package/node_modules/pi-mcp-adapter/dist/resource-tools.js.map +1 -0
  383. package/node_modules/pi-mcp-adapter/dist/types.d.ts +564 -0
  384. package/node_modules/pi-mcp-adapter/dist/types.js +287 -0
  385. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -0
  386. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.d.ts +6 -0
  387. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js +37 -0
  388. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js.map +1 -0
  389. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.d.ts +104 -0
  390. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js +59 -0
  391. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js.map +1 -0
  392. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.d.ts +4 -0
  393. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js +27 -0
  394. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js.map +1 -0
  395. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +32 -0
  396. package/node_modules/pi-mcp-adapter/dist/utils.js +338 -0
  397. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -0
  398. package/node_modules/pi-mcp-adapter/failure-backoff.ts +23 -0
  399. package/node_modules/pi-mcp-adapter/index.ts +204 -82
  400. package/node_modules/pi-mcp-adapter/init.ts +41 -30
  401. package/node_modules/pi-mcp-adapter/lifecycle.ts +16 -8
  402. package/node_modules/pi-mcp-adapter/mcp-code.ts +2 -0
  403. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +66 -16
  404. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +95 -7
  405. package/node_modules/pi-mcp-adapter/mcp-probe.ts +18 -4
  406. package/node_modules/pi-mcp-adapter/mcp-references.ts +368 -0
  407. package/node_modules/pi-mcp-adapter/mcp-status.ts +8 -19
  408. package/node_modules/pi-mcp-adapter/metadata-cache.ts +20 -12
  409. package/node_modules/pi-mcp-adapter/namespace-tools.ts +276 -0
  410. package/node_modules/pi-mcp-adapter/package.json +24 -6
  411. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -10
  412. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -0
  413. package/node_modules/pi-mcp-adapter/server-manager.ts +63 -12
  414. package/node_modules/pi-mcp-adapter/state.ts +1 -3
  415. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +16 -2
  416. package/node_modules/pi-mcp-adapter/types.ts +48 -1
  417. package/node_modules/pi-mcp-adapter/ui-server.ts +3 -19
  418. package/node_modules/pi-mcp-adapter/ui-session.ts +2 -1
  419. package/node_modules/pi-mcp-adapter/utils.ts +21 -19
  420. package/node_modules/pi-web-access/CHANGELOG.md +26 -0
  421. package/node_modules/pi-web-access/README.md +71 -14
  422. package/node_modules/pi-web-access/chrome-cookies.ts +115 -35
  423. package/node_modules/pi-web-access/credential-source.ts +6 -2
  424. package/node_modules/pi-web-access/curator-page.ts +5 -3
  425. package/node_modules/pi-web-access/curator-server.ts +2 -1
  426. package/node_modules/pi-web-access/extract.ts +89 -9
  427. package/node_modules/pi-web-access/fetch-params.ts +13 -0
  428. package/node_modules/pi-web-access/gemini-adc.ts +298 -0
  429. package/node_modules/pi-web-access/gemini-api.ts +59 -15
  430. package/node_modules/pi-web-access/gemini-search.ts +58 -18
  431. package/node_modules/pi-web-access/gemini-url-context.ts +3 -2
  432. package/node_modules/pi-web-access/gemini-web-config.ts +57 -7
  433. package/node_modules/pi-web-access/gemini-web.ts +9 -3
  434. package/node_modules/pi-web-access/github-api.ts +5 -4
  435. package/node_modules/pi-web-access/github-issue-pr.ts +700 -0
  436. package/node_modules/pi-web-access/index.ts +403 -297
  437. package/node_modules/pi-web-access/kimi-search.ts +234 -0
  438. package/node_modules/pi-web-access/openai-search.ts +118 -21
  439. package/node_modules/pi-web-access/package.json +3 -2
  440. package/node_modules/pi-web-access/ssrf-protection.ts +4 -1
  441. package/node_modules/pi-web-access/utils.ts +307 -1
  442. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  443. package/package.json +46 -37
  444. package/node_modules/@herbertgao/pi-copy-response/CHANGELOG.md +0 -49
  445. package/node_modules/@herbertgao/pi-copy-response/LICENSE +0 -22
  446. package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +0 -83
  447. package/node_modules/@herbertgao/pi-handoff/LICENSE +0 -22
  448. package/node_modules/@herbertgao/pi-handoff/package.json +0 -60
  449. package/node_modules/@herbertgao/pi-inline-skills/CHANGELOG.md +0 -57
  450. package/node_modules/@herbertgao/pi-inline-skills/LICENSE +0 -22
  451. package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +0 -39
  452. package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +0 -63
  453. package/node_modules/@herbertgao/pi-preferred-thinking/LICENSE +0 -22
  454. package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +0 -101
  455. package/node_modules/@herbertgao/pi-recap/LICENSE +0 -22
  456. package/node_modules/@herbertgao/pi-recap/package.json +0 -55
  457. package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +0 -49
  458. package/node_modules/@herbertgao/pi-rename/LICENSE +0 -22
  459. package/node_modules/@herbertgao/pi-rename/package.json +0 -63
  460. package/node_modules/@herbertgao/pi-titlebar-spinner/CHANGELOG.md +0 -25
  461. package/node_modules/@herbertgao/pi-titlebar-spinner/LICENSE +0 -22
  462. /package/node_modules/{@herbertgao → @tifan}/pi-copy-response/src/index.ts +0 -0
  463. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/complete-text.ts +0 -0
  464. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/session-query.ts +0 -0
  465. /package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/src/index.ts +0 -0
  466. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +0 -0
  467. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/viewer.mjs +0 -0
  468. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/src/index.ts +0 -0
  469. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/index.ts +0 -0
  470. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/model-picker.ts +0 -0
  471. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/sanitize.ts +0 -0
  472. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/tui.ts +0 -0
  473. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/model-picker.ts +0 -0
  474. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/naming.ts +0 -0
  475. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/sanitize.ts +0 -0
  476. /package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/src/index.ts +0 -0
@@ -54,7 +54,7 @@ const javacRunner = {
54
54
  ctx.log?.("javac: skipped — file is inside a Maven/Gradle project; a classpath-less compile would emit false positives");
55
55
  return { status: "skipped", diagnostics: [], semantic: "none" };
56
56
  }
57
- if (!(await (javac.isAvailableAsync(cwd)))) {
57
+ if (!(await javac.isAvailableAsync(cwd))) {
58
58
  return { status: "skipped", diagnostics: [], semantic: "none" };
59
59
  }
60
60
  const cmd = javac.getCommand(cwd);
@@ -65,7 +65,7 @@ const ktlintRunner = {
65
65
  return { status: "skipped", diagnostics: [], semantic: "none" };
66
66
  }
67
67
  let cmd = null;
68
- if (await (ktlint.isAvailableAsync(cwd))) {
68
+ if (await ktlint.isAvailableAsync(cwd)) {
69
69
  cmd = ktlint.getCommand(cwd);
70
70
  }
71
71
  else {
@@ -23,7 +23,7 @@ import { demoteInferredProjectDiagnostics } from "../../lsp/inferred-project.js"
23
23
  import { enabledAuxiliaryLspServerIds, retagAuxiliaryDiagnostics, } from "../auxiliary-lsp.js";
24
24
  import { readFileContent } from "./utils.js";
25
25
  import { tryWarmAttachedCodeActions, tryWarmAttachedDiagnostics, } from "../../warm-attach.js";
26
- import { contentHash, WARM_CODE_ACTION_LOOKUP_LIMIT, } from "../../mcp/ipc.js";
26
+ import { contentHash, WARM_CODE_ACTION_LOOKUP_LIMIT } from "../../mcp/ipc.js";
27
27
  const LSP_MAX_FILE_BYTES = RUNTIME_CONFIG.pipeline.lspMaxFileBytes;
28
28
  const LSP_MAX_FILE_LINES = RUNTIME_CONFIG.pipeline.lspMaxFileLines;
29
29
  const LSP_SPAWN_BUDGET_MS = RUNTIME_CONFIG.pipeline.lspSpawnBudgetMs;
@@ -3,6 +3,8 @@ import { getLinterPolicyForCwd, markdownlintConfigArgs, } from "../../tool-polic
3
3
  import { PRIORITY } from "../priorities.js";
4
4
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
5
  import { parseToolRun } from "./utils/tool-failure.js";
6
+ import { isInSpawnTimeoutCooldown, noteSpawnTimeout, } from "../../spawn-timeout-cooldown.js";
7
+ import { finishParsedRun } from "./utils/tool-failure.js";
6
8
  const markdownlint = createAvailabilityChecker("markdownlint-cli2", ".cmd");
7
9
  // markdownlint-cli2 exit codes (its README's "Exit Codes" section): 0 = no
8
10
  // findings, 1 = lint findings, 2 = unexpected error (unreadable config, bad
@@ -106,6 +108,13 @@ const markdownlintRunner = {
106
108
  }
107
109
  if (!cmd)
108
110
  return { status: "skipped", diagnostics: [], semantic: "none" };
111
+ // #1995: a command cooling down after a spawn timeout already consumed
112
+ // its budget in another lane (availability verify, autofix --fix). Skip
113
+ // without spawning — "not checked", never re-reported as clean.
114
+ if (isInSpawnTimeoutCooldown(cmd)) {
115
+ ctx.log(`markdownlint: ${cmd} is cooling down after a spawn timeout — skipping (one bounded failure budget per edit)`);
116
+ return { status: "skipped", diagnostics: [], semantic: "none" };
117
+ }
109
118
  // Shared config-args seam (#1247): the autofix path consumes the same
110
119
  // builder, so the package-owned fallback config can never drift.
111
120
  const configArgs = markdownlintConfigArgs(cwd);
@@ -113,6 +122,18 @@ const markdownlintRunner = {
113
122
  timeout: 15000,
114
123
  cwd,
115
124
  });
125
+ // #1995: a timeout is negative runtime evidence. Arm the cooldown so
126
+ // the autofix and availability lanes cannot hand this command a second
127
+ // budget within the same session.
128
+ if (result.failure === "timeout") {
129
+ noteSpawnTimeout({
130
+ tool: "markdownlint",
131
+ command: cmd,
132
+ phase: "lint",
133
+ durationMs: 15000,
134
+ teardown: result.timeoutTeardown,
135
+ });
136
+ }
116
137
  // #1816: this runner read `result.status` zero times, so an exit-2
117
138
  // config error with an empty stdout parsed to zero diagnostics and was
118
139
  // reported as a clean Markdown file. An empty result must distinguish
@@ -124,10 +145,13 @@ const markdownlintRunner = {
124
145
  if (run.skipped)
125
146
  return run.skipped;
126
147
  const diagnostics = run.diagnostics;
127
- if (diagnostics.length === 0) {
128
- return { status: "succeeded", diagnostics: [], semantic: "none" };
129
- }
130
- return { status: "succeeded", diagnostics, semantic: "warning" };
148
+ return finishParsedRun({
149
+ tool: "markdownlint",
150
+ ctx,
151
+ result,
152
+ diagnostics,
153
+ classify: () => ({ status: "succeeded", semantic: "warning" }),
154
+ });
131
155
  },
132
156
  };
133
157
  export default markdownlintRunner;
@@ -4,6 +4,7 @@ import { hasMypyConfig } from "../../tool-policy.js";
4
4
  import { PRIORITY } from "../priorities.js";
5
5
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
6
  import { parseToolRun } from "./utils/tool-failure.js";
7
+ import { finishParsedRun } from "./utils/tool-failure.js";
7
8
  const mypy = createAvailabilityChecker("mypy", "");
8
9
  // mypy exit codes: 0 = no type errors, 1 = type errors found, 2 = a blocking
9
10
  // error. 2 is NOT a rejected invocation on its own — mypy reports a source
@@ -89,15 +90,12 @@ const mypyRunner = {
89
90
  if (run.skipped)
90
91
  return run.skipped;
91
92
  const diagnostics = run.diagnostics;
92
- if (diagnostics.length === 0) {
93
- return { status: "succeeded", diagnostics: [], semantic: "none" };
94
- }
95
- const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
96
- return {
97
- status: hasBlocking ? "failed" : "succeeded",
93
+ return finishParsedRun({
94
+ tool: "mypy",
95
+ ctx,
96
+ result,
98
97
  diagnostics,
99
- semantic: hasBlocking ? "blocking" : "warning",
100
- };
98
+ });
101
99
  },
102
100
  };
103
101
  export default mypyRunner;
@@ -13,6 +13,17 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
13
13
  import { getJstsLintPolicyForCwd, hasVitePlusConfig, } from "../../tool-policy.js";
14
14
  import { PRIORITY } from "../priorities.js";
15
15
  import { resolveToolCommand, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
16
+ import { finishParsedRun, parseToolRun } from "./utils/tool-failure.js";
17
+ const OXLINT_NO_FILES = Symbol("oxlint-no-files");
18
+ const OXLINT_NO_FILES_UNCONFIRMED = Symbol("oxlint-no-files-unconfirmed");
19
+ const OXLINT_NO_FILES_BANNER = "No files found to lint. Please check your paths and ignore patterns.";
20
+ const OXLINT_NO_FILES_REPORT_KEYS = new Set([
21
+ "diagnostics",
22
+ "number_of_files",
23
+ "number_of_rules",
24
+ "threads_count",
25
+ "start_time",
26
+ ]);
16
27
  function resolveLocalVp(cwd) {
17
28
  const isWin = process.platform === "win32";
18
29
  for (const dir of walkUpDirs(cwd)) {
@@ -89,14 +100,71 @@ const oxlintRunner = {
89
100
  // unavailable.
90
101
  const stdout = result.stdout ?? "";
91
102
  const stderr = result.stderr ?? "";
92
- let diagnostics = parseOxlintJson(stdout, ctx.filePath);
93
- if (diagnostics.length === 0 && stdout.length > 0) {
94
- diagnostics = parseOxlintUnix(stdout + stderr, ctx.filePath);
103
+ const parsedOutput = stdout + stderr;
104
+ const noFilesDecision = decideOxlintNoFiles(result, stdout, stderr);
105
+ // #1994's shared gate classifies invocation and parsed-output failures.
106
+ // The private markers preserve one legitimate nonzero/empty shape and
107
+ // force a status-0 lookalike away from clean. Neither escapes this runner.
108
+ // parseToolRun checks process failures before invoking this parser, so
109
+ // spawn/timeout/killed/signal precedence remains owned by #1994.
110
+ const parsedRun = parseToolRun("oxlint", { result, output: parsedOutput }, () => {
111
+ if (noFilesDecision.kind === "expected-no-files") {
112
+ return [OXLINT_NO_FILES];
113
+ }
114
+ if (noFilesDecision.kind === "unconfirmed-no-files" &&
115
+ result.status === 0) {
116
+ return [OXLINT_NO_FILES_UNCONFIRMED];
117
+ }
118
+ let parsed = parseOxlintJson(stdout, ctx.filePath);
119
+ if (parsed.length === 0 && stdout.length > 0) {
120
+ parsed = parseOxlintUnix(parsedOutput, ctx.filePath);
121
+ }
122
+ return parsed;
123
+ }, { parseOutput: parsedOutput });
124
+ if (parsedRun.skipped)
125
+ return parsedRun.skipped;
126
+ if (parsedRun.diagnostics.includes(OXLINT_NO_FILES)) {
127
+ // Real captured bytes show oxlint exits
128
+ // 1 with "No files found" + number_of_files: 0 when a config excludes
129
+ // the target, so "nonzero exit" alone cannot mean "unreadable report
130
+ // of problems" until the no-files shape is ruled out.
131
+ // Read BEFORE reporting "succeeded" — a config (root's or a nested
132
+ // one nearer the file, per oxlint's own discovery) that ignores this
133
+ // file reports the same empty diagnostics array a clean file does.
134
+ // "succeeded"/"none" would say "we checked, it's clean"; this file
135
+ // was never checked at all.
136
+ return {
137
+ status: "skipped",
138
+ diagnostics: [],
139
+ semantic: "none",
140
+ skipReason: "no-files-matched",
141
+ };
95
142
  }
96
- if (diagnostics.length === 0) {
97
- return { status: "succeeded", diagnostics: [], semantic: "none" };
143
+ if (parsedRun.diagnostics.includes(OXLINT_NO_FILES_UNCONFIRMED)) {
144
+ const reason = noFilesDecision.kind === "unconfirmed-no-files"
145
+ ? noFilesDecision.reason
146
+ : "status-zero";
147
+ return {
148
+ status: "failed",
149
+ diagnostics: [
150
+ {
151
+ id: `oxlint:no-files-unconfirmed:${reason}`,
152
+ message: `oxlint no-files report was not canonical (${reason})`,
153
+ filePath: ctx.filePath,
154
+ line: 1,
155
+ column: 1,
156
+ severity: "warning",
157
+ semantic: "warning",
158
+ tool: "oxlint",
159
+ },
160
+ ],
161
+ semantic: "warning",
162
+ failureKind: "unconfirmed_output",
163
+ failureMessage: `no-files-${reason}`,
164
+ };
98
165
  }
99
- const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
166
+ const diagnostics = parsedRun.diagnostics.filter((diagnostic) => diagnostic !== OXLINT_NO_FILES &&
167
+ diagnostic !== OXLINT_NO_FILES_UNCONFIRMED);
100
168
  // A warning-only result on exit 0 is oxlint's normal outcome, not a
101
169
  // failure: exit 0 means nothing hit ERROR severity. `status: "failed"`
102
170
  // here would stop this arm from reporting "succeeded", which breaks two
@@ -109,13 +177,144 @@ const oxlintRunner = {
109
177
  // off the tool's raw exit code. The findings themselves still reach the
110
178
  // delivery pipeline regardless of `status` — dispatcher.ts buckets by
111
179
  // each diagnostic's own `semantic`, so a warning stays a warning.
112
- return {
113
- status: !hasBlocking && result.status === 0 ? "succeeded" : "failed",
180
+ return finishParsedRun({
181
+ tool: "oxlint",
182
+ ctx,
183
+ result,
114
184
  diagnostics,
115
- semantic: hasBlocking ? "blocking" : "warning",
116
- };
185
+ classify: (diagnostics) => {
186
+ const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
187
+ return {
188
+ status: !hasBlocking && result.status === 0 ? "succeeded" : "failed",
189
+ semantic: hasBlocking ? "blocking" : "warning",
190
+ };
191
+ },
192
+ });
117
193
  },
118
194
  };
195
+ function oxlintProcessState(result) {
196
+ const failureKind = result.spawnFailure?.kind;
197
+ if (result.signal || result.failure === "signal")
198
+ return "signal";
199
+ if (result.failure === "timeout" || failureKind === "timeout")
200
+ return "timeout";
201
+ if (result.failure === "aborted" || failureKind === "killed")
202
+ return "killed";
203
+ if (result.failure === "spawn" || result.error)
204
+ return "spawn";
205
+ if (result.outputTruncated)
206
+ return "truncated";
207
+ return "normal";
208
+ }
209
+ function isNonnegativeInteger(value) {
210
+ return Number.isInteger(value) && value >= 0;
211
+ }
212
+ function isPositiveInteger(value) {
213
+ return Number.isInteger(value) && value >= 1;
214
+ }
215
+ function isNonnegativeFinite(value) {
216
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
217
+ }
218
+ /**
219
+ * One decision seam for every oxlint no-files axis (#1998).
220
+ *
221
+ * Real oxlint 1.79.0 establishes the only expected shape: a normal completed
222
+ * process, exit 1, empty stderr, the exact no-files banner, and a JSON object
223
+ * containing exactly the five captured summary fields with canonical types
224
+ * and ranges. Diagnostics must be empty and `number_of_files` must be zero.
225
+ *
226
+ * Any process-control evidence wins before report bytes. Any no-files
227
+ * lookalike that differs on status, stderr, banner, JSON syntax/schema,
228
+ * diagnostics, or file count is unconfirmed rather than clean. A report with
229
+ * no no-files evidence remains an ordinary oxlint report for the normal parser.
230
+ */
231
+ export function decideOxlintNoFiles(result, stdout, stderr) {
232
+ const processState = oxlintProcessState(result);
233
+ if (processState !== "normal") {
234
+ return {
235
+ kind: "unconfirmed-no-files",
236
+ reason: `process-${processState}`,
237
+ };
238
+ }
239
+ const jsonStart = stdout.indexOf("{");
240
+ const bannerText = (jsonStart === -1 ? stdout : stdout.slice(0, jsonStart)).trim();
241
+ const banner = bannerText === OXLINT_NO_FILES_BANNER
242
+ ? "exact"
243
+ : /no files found.+lint/i.test(bannerText)
244
+ ? "near"
245
+ : "missing";
246
+ let report;
247
+ let jsonMalformed = jsonStart === -1;
248
+ if (jsonStart !== -1) {
249
+ try {
250
+ const parsed = JSON.parse(stdout.slice(jsonStart));
251
+ if (typeof parsed === "object" &&
252
+ parsed !== null &&
253
+ !Array.isArray(parsed)) {
254
+ report = parsed;
255
+ }
256
+ else {
257
+ jsonMalformed = true;
258
+ }
259
+ }
260
+ catch {
261
+ jsonMalformed = true;
262
+ }
263
+ }
264
+ const hasFileCount = report !== undefined &&
265
+ Object.prototype.hasOwnProperty.call(report, "number_of_files");
266
+ const fileCount = report?.number_of_files;
267
+ const hasNoFilesEvidence = banner !== "missing" ||
268
+ (hasFileCount && (fileCount === 0 || !isNonnegativeInteger(fileCount)));
269
+ if (!hasNoFilesEvidence)
270
+ return { kind: "ordinary-report" };
271
+ if (result.status == null) {
272
+ return { kind: "unconfirmed-no-files", reason: "status-null" };
273
+ }
274
+ if (result.status === 0) {
275
+ return { kind: "unconfirmed-no-files", reason: "status-zero" };
276
+ }
277
+ if (result.status !== 1) {
278
+ return { kind: "unconfirmed-no-files", reason: "status-other" };
279
+ }
280
+ if (stderr.trim().length > 0) {
281
+ return { kind: "unconfirmed-no-files", reason: "stderr-nonempty" };
282
+ }
283
+ if (banner === "near") {
284
+ return { kind: "unconfirmed-no-files", reason: "banner-near" };
285
+ }
286
+ if (banner === "missing") {
287
+ return { kind: "unconfirmed-no-files", reason: "banner-missing" };
288
+ }
289
+ if (jsonMalformed || !report) {
290
+ return { kind: "unconfirmed-no-files", reason: "json-malformed" };
291
+ }
292
+ const keys = Object.keys(report);
293
+ if (keys.some((key) => !OXLINT_NO_FILES_REPORT_KEYS.has(key))) {
294
+ return { kind: "unconfirmed-no-files", reason: "json-unknown-key" };
295
+ }
296
+ if (OXLINT_NO_FILES_REPORT_KEYS.size !== keys.length ||
297
+ [...OXLINT_NO_FILES_REPORT_KEYS].some((key) => !Object.prototype.hasOwnProperty.call(report, key))) {
298
+ return { kind: "unconfirmed-no-files", reason: "json-missing-key" };
299
+ }
300
+ if (!Array.isArray(report.diagnostics) ||
301
+ !isNonnegativeInteger(report.number_of_files) ||
302
+ !isNonnegativeInteger(report.number_of_rules) ||
303
+ !isPositiveInteger(report.threads_count) ||
304
+ !isNonnegativeFinite(report.start_time)) {
305
+ return {
306
+ kind: "unconfirmed-no-files",
307
+ reason: "json-known-field-invalid",
308
+ };
309
+ }
310
+ if (report.diagnostics.length > 0) {
311
+ return { kind: "unconfirmed-no-files", reason: "diagnostics-nonempty" };
312
+ }
313
+ if (report.number_of_files !== 0) {
314
+ return { kind: "unconfirmed-no-files", reason: "files-nonzero" };
315
+ }
316
+ return { kind: "expected-no-files" };
317
+ }
119
318
  // Oxlint codes look like "eslint(no-debugger)" or "oxc(approx-constant)".
120
319
  // Strip the plugin prefix so the rule lines up with what users expect.
121
320
  // indexOf-based extraction avoids a regex hot-spot Sonar flagged for
@@ -142,8 +341,10 @@ function parseOxlintJson(raw, filePath) {
142
341
  catch {
143
342
  return [];
144
343
  }
344
+ if (!Array.isArray(parsed.diagnostics))
345
+ return [];
145
346
  const diagnostics = [];
146
- for (const d of parsed.diagnostics ?? []) {
347
+ for (const d of parsed.diagnostics) {
147
348
  const rule = extractOxlintRule(d.code);
148
349
  const label = d.labels?.[0]?.span;
149
350
  const lineNum = label?.line ?? 1;
@@ -33,7 +33,7 @@ const phpLintRunner = {
33
33
  skipTestFiles: false,
34
34
  async run(ctx) {
35
35
  const cwd = ctx.cwd || process.cwd();
36
- if (!(await (php.isAvailableAsync(cwd)))) {
36
+ if (!(await php.isAvailableAsync(cwd))) {
37
37
  return { status: "skipped", diagnostics: [], semantic: "none" };
38
38
  }
39
39
  const cmd = php.getCommand(cwd);
@@ -4,6 +4,7 @@ import { getLinterPolicyForCwd, hasPhpstanConfig } from "../../tool-policy.js";
4
4
  import { PRIORITY } from "../priorities.js";
5
5
  import { createAvailabilityChecker, resolveVendorToolCommand, } from "./utils/runner-helpers.js";
6
6
  import { parseToolRun } from "./utils/tool-failure.js";
7
+ import { finishParsedRun } from "./utils/tool-failure.js";
7
8
  // phpstan's documented exit codes: 0 = no errors, 1 = errors found, 2 = a
8
9
  // fatal/internal error that stopped the analysis. Only 1 is a run that carries
9
10
  // findings.
@@ -107,10 +108,13 @@ const phpstanRunner = {
107
108
  if (run.skipped)
108
109
  return run.skipped;
109
110
  const diagnostics = run.diagnostics;
110
- if (diagnostics.length === 0) {
111
- return { status: "succeeded", diagnostics: [], semantic: "none" };
112
- }
113
- return { status: "failed", diagnostics, semantic: "blocking" };
111
+ return finishParsedRun({
112
+ tool: "phpstan",
113
+ ctx,
114
+ result,
115
+ diagnostics,
116
+ classify: () => ({ status: "failed", semantic: "blocking" }),
117
+ });
114
118
  },
115
119
  };
116
120
  export default phpstanRunner;
@@ -244,7 +244,11 @@ function parsePSAnalyzerOutput(raw, filePath) {
244
244
  .filter((item) => item.Message && item.Line)
245
245
  .map((item) => {
246
246
  const sev = (item.Severity ?? "Warning").toLowerCase();
247
- const severity = (sev === "error" || sev === "parseerror") ? "error" : (sev === "information" ? "info" : "warning");
247
+ const severity = sev === "error" || sev === "parseerror"
248
+ ? "error"
249
+ : sev === "information"
250
+ ? "info"
251
+ : "warning";
248
252
  const rule = item.RuleName ?? "PSScriptAnalyzer";
249
253
  return {
250
254
  id: `psscriptanalyzer-${rule}-${item.Line}`,
@@ -295,8 +299,10 @@ const psScriptAnalyzerRunner = {
295
299
  const result = await spawnPs(cmd, [
296
300
  "-NoProfile",
297
301
  "-NonInteractive",
298
- "-File", tmpScript,
299
- "-FilePath", absPath,
302
+ "-File",
303
+ tmpScript,
304
+ "-FilePath",
305
+ absPath,
300
306
  ]);
301
307
  const hostStallMs = sampler.stop();
302
308
  const elapsedMs = Date.now() - startedAt;
@@ -396,9 +402,7 @@ const psScriptAnalyzerRunner = {
396
402
  // than latched. It must still never be read as a clean file
397
403
  // (#1598): empty/malformed stdout on a successful exit is a lost
398
404
  // or truncated write, not evidence of zero diagnostics.
399
- const unreadableReason = result.stdout.trim()
400
- ? "unparseable"
401
- : "empty";
405
+ const unreadableReason = result.stdout.trim() ? "unparseable" : "empty";
402
406
  logAvailabilityDecision({
403
407
  tool: "psscriptanalyzer-stdout",
404
408
  verdict: "unavailable",
@@ -11,6 +11,7 @@ import { getLSPService } from "../../lsp/index.js";
11
11
  import { safeSpawnAsync } from "../../safe-spawn.js";
12
12
  import { PRIORITY } from "../priorities.js";
13
13
  import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
14
+ import { finishParsedRun } from "./utils/tool-failure.js";
14
15
  const pyright = createAvailabilityChecker("pyright", ".exe");
15
16
  const pyrightRunner = {
16
17
  id: "pyright",
@@ -31,7 +32,7 @@ const pyrightRunner = {
31
32
  // Get pyright command - try multiple strategies
32
33
  let cmd = null;
33
34
  // Strategy 1: Check cached availability (fast path)
34
- if (await (pyright.isAvailableAsync(cwd))) {
35
+ if (await pyright.isAvailableAsync(cwd)) {
35
36
  cmd = pyright.getCommand(cwd);
36
37
  }
37
38
  // Strategy 2: use the shared availability taxonomy and install suppression.
@@ -64,24 +65,32 @@ const pyrightRunner = {
64
65
  }
65
66
  const output = (result.stdout || "").trim();
66
67
  if (!output) {
67
- return { status: "succeeded", diagnostics: [], semantic: "none" };
68
+ // Empty stdout with a nonzero exit and stderr chatter is an unreadable
69
+ // report of problems, never clean (#1839). The helper turns that into
70
+ // failed + parse-error; exit 0 stays clean.
71
+ return finishParsedRun({
72
+ tool: "pyright",
73
+ ctx,
74
+ result,
75
+ diagnostics: [],
76
+ });
68
77
  }
69
78
  try {
70
79
  const data = JSON.parse(output);
71
80
  const diagnostics = parsePyrightOutput(data, ctx.filePath);
72
- if (diagnostics.length === 0) {
73
- return { status: "succeeded", diagnostics: [], semantic: "none" };
74
- }
75
- const hasErrors = diagnostics.some((d) => d.severity === "error");
76
- return {
77
- status: hasErrors ? "failed" : "succeeded",
81
+ return finishParsedRun({
82
+ tool: "pyright",
83
+ ctx,
84
+ result,
78
85
  diagnostics,
79
- semantic: hasErrors
80
- ? "blocking"
81
- : diagnostics.length > 0
82
- ? "warning"
83
- : "none",
84
- };
86
+ classify: (diagnostics) => {
87
+ const hasErrors = diagnostics.some((d) => d.severity === "error");
88
+ return {
89
+ status: hasErrors ? "failed" : "succeeded",
90
+ semantic: hasErrors ? "blocking" : "warning",
91
+ };
92
+ },
93
+ });
85
94
  // pi-lens-ignore: missing-error-propagation
86
95
  }
87
96
  catch {
@@ -32,7 +32,7 @@ const makeClippyProbe = (cargoExe) => createCwdCachedProbe((cwd) => safeSpawnAsy
32
32
  }), { tool: "clippy", budgetMs: CLIPPY_PROBE_BUDGET_MS });
33
33
  const clippyAvailabilityByCargo = new Map();
34
34
  function getClippyProbe(cargoExe) {
35
- return clippyAvailabilityByCargo.get(cargoExe) ?? refreshClippyProbe(cargoExe);
35
+ return (clippyAvailabilityByCargo.get(cargoExe) ?? refreshClippyProbe(cargoExe));
36
36
  }
37
37
  /** Replace the cached probe so a post-install state is observed. */
38
38
  function refreshClippyProbe(cargoExe) {
@@ -24,6 +24,7 @@ import * as path from "node:path";
24
24
  import { safeSpawnAsync } from "../../safe-spawn.js";
25
25
  import { PRIORITY } from "../priorities.js";
26
26
  import { createAvailabilityChecker, lspPrimaryCoversFile, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
27
+ import { finishParsedRun } from "./utils/tool-failure.js";
27
28
  const shellcheck = createAvailabilityChecker("shellcheck", ".exe");
28
29
  function findShellcheckConfig(cwd) {
29
30
  const local = path.join(cwd, ".shellcheckrc");
@@ -122,7 +123,7 @@ const shellcheckRunner = {
122
123
  return { status: "skipped", diagnostics: [], semantic: "none" };
123
124
  }
124
125
  let cmd = null;
125
- if (await (shellcheck.isAvailableAsync(cwd))) {
126
+ if (await shellcheck.isAvailableAsync(cwd)) {
126
127
  cmd = shellcheck.getCommand(cwd);
127
128
  }
128
129
  else {
@@ -157,15 +158,12 @@ const shellcheckRunner = {
157
158
  // Parse diagnostics
158
159
  const raw = result.stdout + result.stderr;
159
160
  const diagnostics = parseShellcheckOutput(raw, ctx.filePath);
160
- if (diagnostics.length === 0) {
161
- return { status: "succeeded", diagnostics: [], semantic: "none" };
162
- }
163
- const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
164
- return {
165
- status: hasBlocking ? "failed" : "succeeded",
161
+ return finishParsedRun({
162
+ tool: "shellcheck",
163
+ ctx,
164
+ result,
166
165
  diagnostics,
167
- semantic: hasBlocking ? "blocking" : "warning",
168
- };
166
+ });
169
167
  },
170
168
  };
171
169
  export default shellcheckRunner;
@@ -34,7 +34,7 @@ const shfmtRunner = {
34
34
  async run(ctx) {
35
35
  const cwd = ctx.cwd || process.cwd();
36
36
  let cmd = null;
37
- if (await (shfmt.isAvailableAsync(cwd))) {
37
+ if (await shfmt.isAvailableAsync(cwd)) {
38
38
  cmd = shfmt.getCommand(cwd);
39
39
  }
40
40
  else {
@@ -79,7 +79,10 @@ const shfmtRunner = {
79
79
  // .editorconfig — otherwise this nags on every shell write against shfmt's
80
80
  // defaults (#211). Parse errors (above) are always reported.
81
81
  if (!hasEditorConfig(cwd)) {
82
- return { status: "succeeded", diagnostics: [], semantic: "none" };
82
+ // #211: without project opt-in, do not nag about formatting. But
83
+ // shfmt DID exit 1 — differences exist — so this is "chose not to
84
+ // check", reported as skipped, never as a clean result (#1839).
85
+ return { status: "skipped", diagnostics: [], semantic: "none" };
83
86
  }
84
87
  // Extract first changed line from diff if possible
85
88
  const diffOutput = result.stdout ?? result.stderr ?? "";
@@ -3,6 +3,7 @@ import { getLinterPolicyForCwd, hasSqlfluffConfig } from "../../tool-policy.js";
3
3
  import { PRIORITY } from "../priorities.js";
4
4
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
5
  import { parseToolRun } from "./utils/tool-failure.js";
6
+ import { finishParsedRun } from "./utils/tool-failure.js";
6
7
  const sqlfluff = createAvailabilityChecker("sqlfluff", ".exe");
7
8
  // sqlfluff exit codes (its CLI docs): 0 = clean, 1 = violations found, 2 = a
8
9
  // user error that stopped the lint (unknown dialect, unreadable config).
@@ -161,14 +162,13 @@ const sqlfluffRunner = {
161
162
  if (run.skipped)
162
163
  return run.skipped;
163
164
  const diagnostics = run.diagnostics;
164
- if (diagnostics.length === 0) {
165
- return { status: "succeeded", diagnostics: [], semantic: "none" };
166
- }
167
- return {
168
- status: "failed",
165
+ return finishParsedRun({
166
+ tool: "sqlfluff",
167
+ ctx,
168
+ result,
169
169
  diagnostics,
170
- semantic: "warning",
171
- };
170
+ classify: () => ({ status: "failed", semantic: "warning" }),
171
+ });
172
172
  },
173
173
  };
174
174
  export default sqlfluffRunner;
@@ -4,6 +4,7 @@ import { getLinterPolicyForCwd, hasStylelintConfig, } from "../../tool-policy.js
4
4
  import { PRIORITY } from "../priorities.js";
5
5
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
6
  import { parseToolRun } from "./utils/tool-failure.js";
7
+ import { finishParsedRun } from "./utils/tool-failure.js";
7
8
  const stylelint = createAvailabilityChecker("stylelint", ".cmd");
8
9
  // stylelint exit codes (its "Exit codes" docs page): 0 = no problems, 1 = a
9
10
  // fatal error, 2 = lint problems found, 78 = a configuration error.
@@ -146,15 +147,12 @@ const stylelintRunner = {
146
147
  if (run.skipped)
147
148
  return run.skipped;
148
149
  const diagnostics = run.diagnostics;
149
- if (diagnostics.length === 0) {
150
- return { status: "succeeded", diagnostics: [], semantic: "none" };
151
- }
152
- const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
153
- return {
154
- status: hasBlocking ? "failed" : "succeeded",
150
+ return finishParsedRun({
151
+ tool: "stylelint",
152
+ ctx,
153
+ result,
155
154
  diagnostics,
156
- semantic: hasBlocking ? "blocking" : "warning",
157
- };
155
+ });
158
156
  },
159
157
  };
160
158
  export default stylelintRunner;