@herbertgao/pi-extensions 2026.8.4 → 2026.8.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 (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -1,8 +1,30 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
+ import { TERRAGRUNT_FILENAMES } from "./file-kinds.js";
3
4
  import { logLatency } from "./latency-logger.js";
5
+ import { resolvePackagePath } from "./package-root.js";
4
6
  import { findNearestContaining, walkUpDirs } from "./path-utils.js";
5
- import { loadProjectSnapshot } from "./project-snapshot.js";
7
+ import { loadProjectSnapshotWithoutWordIndex } from "./project-snapshot.js";
8
+ // Extension → formatter policy. This map, `FORMATTER_POLICY_BY_FILENAME`, and
9
+ // `AUTO_INSTALLABLE_DEFAULT_FORMATTERS` are the inverse of the formatter
10
+ // definitions in `clients/formatters.ts` (formatter → extensions). The two are
11
+ // bound by `tests/clients/formatter-policy-consistency.test.ts` (#1135, the
12
+ // #883/#209 single-source-of-truth class) so they cannot drift silently. All
13
+ // three are re-exported (read-only intent) via a single `export {}` below —
14
+ // deliberately NOT inline on these declarations, to keep the pre-existing,
15
+ // structural lookup-table duplication out of the PR's "new code" (SonarCloud).
16
+ //
17
+ // Two deliberate #1135 decisions live in the entries below, documented here so
18
+ // the rationale sits outside the duplicated run:
19
+ // - `.sass` offers ["biome", "prettier"] only — NOT oxfmt: oxfmt is absent
20
+ // from OXFMT_SUPPORTED_EXTENSIONS (oxfmt/prettier handle .css/.scss/.less,
21
+ // not the indented `.sass` syntax). It was previously hand-listed here,
22
+ // diverging from the oxfmt definition (inert, because `matching` filtered
23
+ // it out); dropped to bind the two.
24
+ // - `.fish` intentionally has NO entry. `fish-indent` is a LINT runner
25
+ // (getLinterPolicyForFile), not a FormatterInfo — a formatter policy naming
26
+ // it was a dead, unsatisfiable entry; fish reformatting runs via the
27
+ // linter/autofix path. Removed to keep extension→formatter consistent.
6
28
  const FORMATTER_POLICY_BY_EXTENSION = new Map([
7
29
  [
8
30
  ".js",
@@ -133,7 +155,8 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
133
155
  [
134
156
  ".sass",
135
157
  {
136
- formatterNames: ["biome", "prettier", "oxfmt"],
158
+ // #1135: no oxfmt (see map header comment).
159
+ formatterNames: ["biome", "prettier"],
137
160
  defaultFormatter: "biome",
138
161
  defaultWhenUnconfigured: true,
139
162
  gate: "smart-default",
@@ -230,7 +253,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
230
253
  {
231
254
  formatterNames: ["ktfmt", "ktlint"],
232
255
  defaultFormatter: "ktlint",
233
- defaultWhenUnconfigured: true,
256
+ defaultWhenUnconfigured: false,
234
257
  gate: "smart-default",
235
258
  },
236
259
  ],
@@ -239,7 +262,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
239
262
  {
240
263
  formatterNames: ["ktfmt", "ktlint"],
241
264
  defaultFormatter: "ktlint",
242
- defaultWhenUnconfigured: true,
265
+ defaultWhenUnconfigured: false,
243
266
  gate: "smart-default",
244
267
  },
245
268
  ],
@@ -248,7 +271,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
248
271
  {
249
272
  formatterNames: ["swiftformat"],
250
273
  defaultFormatter: "swiftformat",
251
- defaultWhenUnconfigured: true,
274
+ defaultWhenUnconfigured: false,
252
275
  gate: "smart-default",
253
276
  },
254
277
  ],
@@ -257,7 +280,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
257
280
  {
258
281
  formatterNames: ["fantomas"],
259
282
  defaultFormatter: "fantomas",
260
- defaultWhenUnconfigured: true,
283
+ defaultWhenUnconfigured: false,
261
284
  gate: "smart-default",
262
285
  },
263
286
  ],
@@ -266,7 +289,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
266
289
  {
267
290
  formatterNames: ["fantomas"],
268
291
  defaultFormatter: "fantomas",
269
- defaultWhenUnconfigured: true,
292
+ defaultWhenUnconfigured: false,
270
293
  gate: "smart-default",
271
294
  },
272
295
  ],
@@ -275,7 +298,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
275
298
  {
276
299
  formatterNames: ["fantomas"],
277
300
  defaultFormatter: "fantomas",
278
- defaultWhenUnconfigured: true,
301
+ defaultWhenUnconfigured: false,
279
302
  gate: "smart-default",
280
303
  },
281
304
  ],
@@ -284,7 +307,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
284
307
  {
285
308
  formatterNames: ["nixfmt"],
286
309
  defaultFormatter: "nixfmt",
287
- defaultWhenUnconfigured: true,
310
+ defaultWhenUnconfigured: false,
288
311
  gate: "smart-default",
289
312
  },
290
313
  ],
@@ -293,7 +316,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
293
316
  {
294
317
  formatterNames: ["mix"],
295
318
  defaultFormatter: "mix",
296
- defaultWhenUnconfigured: true,
319
+ defaultWhenUnconfigured: false,
297
320
  gate: "smart-default",
298
321
  },
299
322
  ],
@@ -302,7 +325,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
302
325
  {
303
326
  formatterNames: ["mix"],
304
327
  defaultFormatter: "mix",
305
- defaultWhenUnconfigured: true,
328
+ defaultWhenUnconfigured: false,
306
329
  gate: "smart-default",
307
330
  },
308
331
  ],
@@ -311,7 +334,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
311
334
  {
312
335
  formatterNames: ["mix"],
313
336
  defaultFormatter: "mix",
314
- defaultWhenUnconfigured: true,
337
+ defaultWhenUnconfigured: false,
315
338
  gate: "smart-default",
316
339
  },
317
340
  ],
@@ -320,7 +343,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
320
343
  {
321
344
  formatterNames: ["mix"],
322
345
  defaultFormatter: "mix",
323
- defaultWhenUnconfigured: true,
346
+ defaultWhenUnconfigured: false,
324
347
  gate: "smart-default",
325
348
  },
326
349
  ],
@@ -329,7 +352,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
329
352
  {
330
353
  formatterNames: ["mix"],
331
354
  defaultFormatter: "mix",
332
- defaultWhenUnconfigured: true,
355
+ defaultWhenUnconfigured: false,
333
356
  gate: "smart-default",
334
357
  },
335
358
  ],
@@ -419,7 +442,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
419
442
  {
420
443
  formatterNames: ["csharpier"],
421
444
  defaultFormatter: "csharpier",
422
- defaultWhenUnconfigured: true,
445
+ defaultWhenUnconfigured: false,
423
446
  gate: "smart-default",
424
447
  },
425
448
  ],
@@ -437,7 +460,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
437
460
  {
438
461
  formatterNames: ["ormolu"],
439
462
  defaultFormatter: "ormolu",
440
- defaultWhenUnconfigured: true,
463
+ defaultWhenUnconfigured: false,
441
464
  gate: "smart-default",
442
465
  },
443
466
  ],
@@ -446,7 +469,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
446
469
  {
447
470
  formatterNames: ["ormolu"],
448
471
  defaultFormatter: "ormolu",
449
- defaultWhenUnconfigured: true,
472
+ defaultWhenUnconfigured: false,
450
473
  gate: "smart-default",
451
474
  },
452
475
  ],
@@ -504,21 +527,12 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
504
527
  gate: "smart-default",
505
528
  },
506
529
  ],
507
- [
508
- ".fish",
509
- {
510
- formatterNames: ["fish-indent"],
511
- defaultFormatter: "fish-indent",
512
- defaultWhenUnconfigured: true,
513
- gate: "smart-default",
514
- },
515
- ],
516
530
  [
517
531
  ".toml",
518
532
  {
519
533
  formatterNames: ["taplo"],
520
534
  defaultFormatter: "taplo",
521
- defaultWhenUnconfigured: true,
535
+ defaultWhenUnconfigured: false,
522
536
  gate: "smart-default",
523
537
  },
524
538
  ],
@@ -527,7 +541,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
527
541
  {
528
542
  formatterNames: ["terraform"],
529
543
  defaultFormatter: "terraform",
530
- defaultWhenUnconfigured: true,
544
+ defaultWhenUnconfigured: false,
531
545
  gate: "smart-default",
532
546
  },
533
547
  ],
@@ -536,7 +550,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
536
550
  {
537
551
  formatterNames: ["terraform"],
538
552
  defaultFormatter: "terraform",
539
- defaultWhenUnconfigured: true,
553
+ defaultWhenUnconfigured: false,
540
554
  gate: "smart-default",
541
555
  },
542
556
  ],
@@ -617,7 +631,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
617
631
  {
618
632
  formatterNames: ["psscriptanalyzer-format"],
619
633
  defaultFormatter: "psscriptanalyzer-format",
620
- defaultWhenUnconfigured: true,
634
+ defaultWhenUnconfigured: false,
621
635
  gate: "smart-default",
622
636
  },
623
637
  ],
@@ -626,7 +640,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
626
640
  {
627
641
  formatterNames: ["psscriptanalyzer-format"],
628
642
  defaultFormatter: "psscriptanalyzer-format",
629
- defaultWhenUnconfigured: true,
643
+ defaultWhenUnconfigured: false,
630
644
  gate: "smart-default",
631
645
  },
632
646
  ],
@@ -635,7 +649,7 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
635
649
  {
636
650
  formatterNames: ["psscriptanalyzer-format"],
637
651
  defaultFormatter: "psscriptanalyzer-format",
638
- defaultWhenUnconfigured: true,
652
+ defaultWhenUnconfigured: false,
639
653
  gate: "smart-default",
640
654
  },
641
655
  ],
@@ -643,10 +657,15 @@ const FORMATTER_POLICY_BY_EXTENSION = new Map([
643
657
  // oxfmt supports these extensions — registered as a candidate formatter for each.
644
658
  // Using a post-processing pass avoids repeating the same modification across
645
659
  // many map entries (and keeps SonarCloud's duplication gate happy).
646
- const OXFMT_SUPPORTED_EXTENSIONS = new Set([
660
+ // This is the SINGLE SOURCE OF TRUTH for oxfmt's supported extensions — do not
661
+ // hand-maintain a second copy; `clients/formatters.ts`'s `oxfmtFormatter.extensions`
662
+ // imports and spreads this same Set (#1134; previously two parallel hand-maintained
663
+ // lists, the #883 single-source-of-truth class).
664
+ export const OXFMT_SUPPORTED_EXTENSIONS = new Set([
647
665
  ".js", ".jsx", ".mjs", ".cjs",
648
666
  ".ts", ".tsx", ".mts", ".cts",
649
667
  ".vue",
668
+ ".svelte",
650
669
  ".css", ".scss", ".less",
651
670
  ".html", ".htm",
652
671
  ".json", ".jsonc",
@@ -662,6 +681,22 @@ FORMATTER_POLICY_BY_EXTENSION.set(".vue", {
662
681
  defaultWhenUnconfigured: false,
663
682
  gate: "config-first",
664
683
  });
684
+ // Add .svelte entry (no prior formatter policy existed for this extension —
685
+ // docs/language-coverage.md previously listed no formatter). oxfmt is the only
686
+ // candidate; the loop below appends it since ".svelte" is in
687
+ // OXFMT_SUPPORTED_EXTENSIONS. Unlike the other oxfmt extensions, oxfmt's
688
+ // .svelte support is conditional on more than "a config file exists" — see
689
+ // `hasOxfmtSvelteConfig` below, gated in `formatters.ts`'s
690
+ // `hasExplicitFormatterConfig` (verified empirically against the real oxfmt
691
+ // npm binary; oxfmt exits non-zero on .svelte without BOTH the `svelte`
692
+ // package installed and the config's `svelte` flag enabled — an unconditional
693
+ // offer would guarantee a formatter failure, not a no-op).
694
+ FORMATTER_POLICY_BY_EXTENSION.set(".svelte", {
695
+ formatterNames: [],
696
+ defaultFormatter: "oxfmt",
697
+ defaultWhenUnconfigured: false,
698
+ gate: "config-first",
699
+ });
665
700
  for (const [ext, policy] of FORMATTER_POLICY_BY_EXTENSION) {
666
701
  if (OXFMT_SUPPORTED_EXTENSIONS.has(ext) && !policy.formatterNames.includes("oxfmt")) {
667
702
  policy.formatterNames.push("oxfmt");
@@ -675,10 +710,30 @@ const AUTO_INSTALLABLE_DEFAULT_FORMATTERS = new Map([
675
710
  ["taplo", "taplo"],
676
711
  ["ktlint", "ktlint"],
677
712
  ]);
713
+ // `gate: "smart-default"` so a matched file is formatted only when nothing else
714
+ // claims it. Misdetection edge: `root.hcl` is filename-detected as terragrunt, so
715
+ // a non-terragrunt `root.hcl` gets smart-default formatted with `terragrunt hcl
716
+ // fmt`'s generic HCL canonicalization — a soft outcome (canonical HCL, no config
717
+ // semantics assumed), not a hard failure.
718
+ const TERRAGRUNT_FORMATTER_POLICY = {
719
+ formatterNames: ["terragrunt-hcl"],
720
+ defaultFormatter: "terragrunt-hcl",
721
+ defaultWhenUnconfigured: true,
722
+ gate: "smart-default",
723
+ };
724
+ const FORMATTER_POLICY_BY_FILENAME = new Map(TERRAGRUNT_FILENAMES.map((name) => [name, TERRAGRUNT_FORMATTER_POLICY]));
725
+ // Re-exported (read-only intent) for the #1135 drift guard. Kept as a single
726
+ // separate statement — NOT inline on the declarations above — so the touched
727
+ // lines don't fall at the head of the pre-existing lookup-table duplication and
728
+ // get counted as new duplicated code. Bindings are live, so position is safe.
729
+ export { AUTO_INSTALLABLE_DEFAULT_FORMATTERS, FORMATTER_POLICY_BY_EXTENSION, FORMATTER_POLICY_BY_FILENAME, };
678
730
  export function getFormatterPolicyForExtension(ext) {
679
731
  return FORMATTER_POLICY_BY_EXTENSION.get(ext.toLowerCase());
680
732
  }
681
733
  export function getFormatterPolicyForFile(filePath) {
734
+ const byFilename = FORMATTER_POLICY_BY_FILENAME.get(path.basename(filePath).toLowerCase());
735
+ if (byFilename)
736
+ return byFilename;
682
737
  return getFormatterPolicyForExtension(path.extname(filePath));
683
738
  }
684
739
  export function getSmartDefaultFormatterName(filePath) {
@@ -773,8 +828,21 @@ const AUTOFIX_CAPABILITIES = new Map([
773
828
  ],
774
829
  ]);
775
830
  const TOOL_EXECUTION_POLICY = new Map([
831
+ // Dispatch/LSP runners use the shared availability/install seam. These
832
+ // managed tools are missing-command repair candidates; probe failures still
833
+ // fail closed before this policy is consulted.
834
+ ["pyright", { gate: "smart-default", autoInstall: true }],
835
+ ["shellcheck", { gate: "smart-default", autoInstall: true }],
836
+ ["shfmt", { gate: "smart-default", autoInstall: true }],
837
+ ["tflint", { gate: "smart-default", autoInstall: true }],
838
+ ["terragrunt", { gate: "smart-default", autoInstall: true }],
839
+ ["trivy", { gate: "config-first", autoInstall: true }],
776
840
  ["biome", { gate: "smart-default", autoInstall: true }],
777
841
  ["ruff", { gate: "smart-default", autoInstall: true }],
842
+ ["jscpd", { gate: "smart-default", autoInstall: true }],
843
+ ["madge", { gate: "smart-default", autoInstall: true }],
844
+ ["knip", { gate: "smart-default", autoInstall: true }],
845
+ ["ast-grep", { gate: "smart-default", autoInstall: true }],
778
846
  ["oxlint", { gate: "smart-default", autoInstall: true }],
779
847
  ["stylelint", { gate: "smart-default", autoInstall: true }],
780
848
  ["sqlfluff", { gate: "smart-default", autoInstall: true }],
@@ -785,6 +853,7 @@ const TOOL_EXECUTION_POLICY = new Map([
785
853
  ["mypy", { gate: "config-first", autoInstall: true }],
786
854
  ["taplo", { gate: "smart-default", autoInstall: true }],
787
855
  ["hadolint", { gate: "smart-default", autoInstall: true }],
856
+ ["helm", { gate: "smart-default", autoInstall: true }],
788
857
  ["htmlhint", { gate: "smart-default", autoInstall: true }],
789
858
  ["ktlint", { gate: "smart-default", autoInstall: true }],
790
859
  // ktfmt is opt-in (a project's explicit formatting choice), so it only runs
@@ -1096,8 +1165,8 @@ export function getLinterPolicyForFile(filePath, context = {}) {
1096
1165
  runnerNames: ["sqlfluff"],
1097
1166
  preferredRunners: ["sqlfluff"],
1098
1167
  defaultRunner: "sqlfluff",
1099
- defaultWhenUnconfigured: true,
1100
- gate: "smart-default",
1168
+ defaultWhenUnconfigured: false,
1169
+ gate: "config-first",
1101
1170
  };
1102
1171
  }
1103
1172
  if ([".rb", ".rake", ".gemspec", ".ru"].includes(ext)) {
@@ -1145,6 +1214,15 @@ export function getLinterPolicyForFile(filePath, context = {}) {
1145
1214
  gate: "smart-default",
1146
1215
  };
1147
1216
  }
1217
+ if (TERRAGRUNT_FILENAMES.includes(path.basename(filePath).toLowerCase())) {
1218
+ return {
1219
+ runnerNames: ["terragrunt"],
1220
+ preferredRunners: ["terragrunt"],
1221
+ defaultRunner: "terragrunt",
1222
+ defaultWhenUnconfigured: true,
1223
+ gate: "smart-default",
1224
+ };
1225
+ }
1148
1226
  if ([".kt", ".kts"].includes(ext)) {
1149
1227
  // When the project opts into ktfmt, ktfmt (a pure formatter wired as a safe
1150
1228
  // autofix) owns Kotlin formatting; ktlint's lint steps aside so its style
@@ -1227,7 +1305,7 @@ export function getLinterPolicyForFile(filePath, context = {}) {
1227
1305
  preferredRunners: ["tflint"],
1228
1306
  defaultRunner: "tflint",
1229
1307
  defaultWhenUnconfigured: true,
1230
- gate: "smart-default",
1308
+ gate: context.hasTflintConfig ? "config-first" : "smart-default",
1231
1309
  };
1232
1310
  }
1233
1311
  if ([".ex", ".exs", ".eex", ".heex", ".leex"].includes(ext)) {
@@ -1296,7 +1374,7 @@ export function getLinterPolicyForFile(filePath, context = {}) {
1296
1374
  * start / project-seq bumps rather than on every read.
1297
1375
  */
1298
1376
  export function getCachedProjectConventions(cwd) {
1299
- const snapshot = loadProjectSnapshot(cwd);
1377
+ const snapshot = loadProjectSnapshotWithoutWordIndex(cwd);
1300
1378
  return snapshot?.conventions;
1301
1379
  }
1302
1380
  export function getLinterPolicyForCwd(filePath, cwd) {
@@ -1314,6 +1392,9 @@ export function getLinterPolicyForCwd(filePath, cwd) {
1314
1392
  hasMypyConfig: hasMypyConfig(cwd),
1315
1393
  hasDetektConfig: hasDetektConfig(cwd),
1316
1394
  hasKtfmtConfig: hasKtfmtConfig(cwd),
1395
+ // From the file's directory, not cwd: a `.tflint.hcl` in a terraform
1396
+ // subdirectory is invisible to an upward walk that starts at the repo root.
1397
+ hasTflintConfig: hasTflintConfig(path.dirname(path.resolve(cwd, filePath))),
1317
1398
  };
1318
1399
  const policy = getLinterPolicyForFile(filePath, context);
1319
1400
  if (policy) {
@@ -1372,6 +1453,7 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
1372
1453
  defaultWhenUnconfigured: true,
1373
1454
  gate: "smart-default",
1374
1455
  safe: true,
1456
+ scope: "cargo-project",
1375
1457
  };
1376
1458
  }
1377
1459
  if ([".json", ".jsonc"].includes(ext)) {
@@ -1412,8 +1494,8 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
1412
1494
  toolNames: ["sqlfluff"],
1413
1495
  preferredTools: ["sqlfluff"],
1414
1496
  defaultTool: "sqlfluff",
1415
- defaultWhenUnconfigured: true,
1416
- gate: "smart-default",
1497
+ defaultWhenUnconfigured: false,
1498
+ gate: "config-first",
1417
1499
  safe: true,
1418
1500
  };
1419
1501
  }
@@ -1428,6 +1510,16 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
1428
1510
  };
1429
1511
  }
1430
1512
  if ([".kt", ".kts"].includes(ext)) {
1513
+ if (context.hasKtlintConfig) {
1514
+ return {
1515
+ toolNames: ["ktlint", "ktfmt", "detekt"],
1516
+ preferredTools: ["ktlint"],
1517
+ defaultTool: "ktlint",
1518
+ defaultWhenUnconfigured: false,
1519
+ gate: "config-first",
1520
+ safe: true,
1521
+ };
1522
+ }
1431
1523
  // ktfmt is config-first and the project's explicit formatting choice, so it
1432
1524
  // wins over both detekt and the ktlint smart-default when opted in (#129).
1433
1525
  if (context.hasKtfmtConfig) {
@@ -1504,6 +1596,7 @@ export function getAutofixPolicyForFile(filePath, context = {}) {
1504
1596
  defaultWhenUnconfigured: true,
1505
1597
  gate: "smart-default",
1506
1598
  safe: true,
1599
+ scope: "dart-project",
1507
1600
  };
1508
1601
  }
1509
1602
  return undefined;
@@ -1625,6 +1718,69 @@ export function hasOxfmtConfig(cwd) {
1625
1718
  }
1626
1719
  return false;
1627
1720
  }
1721
+ // Empirically verified against the real `oxfmt` npm package (0.62.0), a
1722
+ // scratch fixture, and a plain `Component.svelte` — see PR body for the full
1723
+ // four-cell matrix. Both conditions are required; either alone always fails:
1724
+ // - no `svelte` package, no config flag -> exit 2 ("excluded by ignore rules")
1725
+ // - no `svelte` package, config flag on -> exit 2 ("Cannot find module 'svelte/compiler'")
1726
+ // - `svelte` package installed, no flag -> exit 2 ("excluded by ignore rules")
1727
+ // - `svelte` package installed, flag on -> exit 0, formats the file
1728
+ // Per https://oxc.rs/docs/guide/usage/formatter/language-support.html, oxfmt
1729
+ // also requires the npm-distributed binary (not the standalone GitHub-release
1730
+ // binary) for `.svelte` — pi-lens already resolves oxfmt via `findInNodeModules`/
1731
+ // `which`, which favors the npm-installed binary, so that requirement is not
1732
+ // separately re-checked here.
1733
+ //
1734
+ // Known limits of this line-match heuristic (#1134 P3 tail 1): it tolerates a
1735
+ // trailing `#`-comment after the value (`svelte = true # enable`), but it is
1736
+ // NOT a real TOML parser — a `svelte = true` occurrence nested under a
1737
+ // `[table]` section, or one embedded inside a multi-line/triple-quoted string
1738
+ // value, would still match and false-positive. Both are considered acceptable
1739
+ // risk: an oxfmt.toml sectioning `svelte` under a table is not a realistic
1740
+ // config shape for this single top-level boolean key, and a false positive
1741
+ // here only causes oxfmt to be OFFERED (still gated by oxfmt actually running
1742
+ // and the `svelte` package check above), never a silent formatter failure.
1743
+ const OXFMT_SVELTE_TOML_TRUE = /(^|\n)\s*svelte\s*=\s*true\s*(\s*#.*)?(\r?\n|$)/;
1744
+ export function hasOxfmtSvelteConfig(cwd) {
1745
+ // Monorepo asymmetry (#1134 P3 tail 2): this dependency check stops at the
1746
+ // NEAREST package.json (`hasNearestPackageJsonDependency`), while the
1747
+ // config walk below (`walkUpDirs`) continues all the way to the repo root.
1748
+ // A root-level `svelte` dependency combined with an oxfmt config at the
1749
+ // root, but invoked with a sub-package `cwd` that has its own
1750
+ // (svelte-less) package.json, under-offers oxfmt for that sub-package —
1751
+ // the same nearest-vs-root-walk asymmetry as the `.tflint.hcl` note in
1752
+ // `getLinterPolicyForCwd` above. This is untested/deliberately unfixed:
1753
+ // failing to offer a valid formatter is safe (never mis-offers one that
1754
+ // then fails at runtime), unlike the inverse.
1755
+ if (!hasNearestPackageJsonDependency(cwd, "svelte"))
1756
+ return false;
1757
+ for (const dir of walkUpDirs(cwd)) {
1758
+ const rcPath = path.join(dir, ".oxfmtrc.json");
1759
+ if (fs.existsSync(rcPath)) {
1760
+ try {
1761
+ const cfg = JSON.parse(fs.readFileSync(rcPath, "utf-8"));
1762
+ if (cfg.svelte === true)
1763
+ return true;
1764
+ }
1765
+ catch { }
1766
+ }
1767
+ // oxfmt.toml is TOML; pi-lens has no TOML parser dependency, so this is
1768
+ // a targeted line match for the single boolean key rather than a full
1769
+ // parse (same pragmatic style as hasVitePlusConfig's content.includes
1770
+ // check above) — presence of the file alone is NOT sufficient, since a
1771
+ // TOML config can omit `svelte` or set it false.
1772
+ const tomlPath = path.join(dir, "oxfmt.toml");
1773
+ if (fs.existsSync(tomlPath)) {
1774
+ try {
1775
+ const content = fs.readFileSync(tomlPath, "utf-8");
1776
+ if (OXFMT_SVELTE_TOML_TRUE.test(content))
1777
+ return true;
1778
+ }
1779
+ catch { }
1780
+ }
1781
+ }
1782
+ return false;
1783
+ }
1628
1784
  export function hasStylelintConfig(cwd) {
1629
1785
  for (const dir of walkUpDirs(cwd)) {
1630
1786
  if (STYLELINT_CONFIGS.some((cfg) => fs.existsSync(path.join(dir, cfg)))) {
@@ -1832,9 +1988,61 @@ export function hasRuffConfig(cwd) {
1832
1988
  }
1833
1989
  return false;
1834
1990
  }
1991
+ /**
1992
+ * Shared config-args seam for the markdownlint lint AND autofix surfaces
1993
+ * (#1247). The lint runner (`markdownlint.ts`) and the autofix path
1994
+ * (`pipeline.ts` `tryMarkdownlintFix`) MUST both consume this builder so the
1995
+ * package-owned sensible-defaults config (`config/markdownlint/core.json`) can
1996
+ * never drift apart from the bare `--fix` invocation again.
1997
+ */
1998
+ /**
1999
+ * Shared fallback shape for the config-args builders (#1247): when the
2000
+ * project has its own config the lint/autofix surfaces pass NO args (the
2001
+ * tool discovers it); otherwise both surfaces point at the package-owned
2002
+ * fallback so the tool never silently runs its default ruleset. One shape
2003
+ * here means the per-tool builders cannot drift from each other.
2004
+ */
2005
+ function configArgsWithFallback(hasConfig, toolArgs, packageConfigPath) {
2006
+ return hasConfig
2007
+ ? []
2008
+ : [...toolArgs, resolvePackagePath(import.meta.url, packageConfigPath)];
2009
+ }
2010
+ export function markdownlintConfigArgs(cwd) {
2011
+ return configArgsWithFallback(hasMarkdownlintConfig(cwd), ["--config"], "config/markdownlint/core.json");
2012
+ }
2013
+ /**
2014
+ * Shared config-args seam for the ruff lint AND autofix surfaces (#1247).
2015
+ * The lint runner (`ruff.ts`) and `ruffClient.fixFileAsync` MUST both consume
2016
+ * this builder so `config/ruff/core.toml` applies on `--fix` too.
2017
+ */
2018
+ export function ruffConfigArgs(cwd) {
2019
+ return configArgsWithFallback(hasRuffConfig(cwd), ["--config"], "config/ruff/core.toml");
2020
+ }
2021
+ /**
2022
+ * Shared config-args seam for the biome lint AND autofix surfaces (#1247).
2023
+ * The lint runner (`biome-check.ts`) and `biomeClient.fixFileAsync` MUST both
2024
+ * consume this builder so the user's `biome.json(c)` — or the package-owned
2025
+ * `config/biome/core.jsonc` fallback — applies on `lint --write` too.
2026
+ */
2027
+ export function biomeConfigArgs(cwd) {
2028
+ return [
2029
+ "--config-path=" +
2030
+ (getBiomeConfigPath(cwd) ??
2031
+ resolvePackagePath(import.meta.url, "config/biome/core.jsonc")),
2032
+ ];
2033
+ }
1835
2034
  export function hasGolangciConfig(cwd) {
1836
2035
  return findNearestContaining(cwd, GOLANGCI_CONFIGS) !== undefined;
1837
2036
  }
2037
+ // tflint ships built-in rules and runs without config, so `.tflint.hcl` is not
2038
+ // a prerequisite — it is the project electing tflint as its terraform linter,
2039
+ // which promotes the policy from smart-default to config-first. Takes a start
2040
+ // directory rather than the project cwd because tflint resolves config
2041
+ // per-directory: callers pass the EDITED FILE's directory so this agrees with
2042
+ // what the runner will actually hand tflint via `--config`.
2043
+ export function hasTflintConfig(startDir) {
2044
+ return findNearestContaining(startDir, [".tflint.hcl"]) !== undefined;
2045
+ }
1838
2046
  export function hasClangFormatConfig(cwd) {
1839
2047
  return (findNearestContaining(cwd, [".clang-format", "_clang-format"]) !== undefined);
1840
2048
  }
@@ -1897,7 +2105,150 @@ const KTFMT_GRADLE_FILES = [
1897
2105
  "settings.gradle.kts",
1898
2106
  "settings.gradle",
1899
2107
  ];
2108
+ const KOTLIN_GRADLE_FILES = [
2109
+ "build.gradle.kts",
2110
+ "build.gradle",
2111
+ "settings.gradle.kts",
2112
+ "settings.gradle",
2113
+ ];
2114
+ const spotlessKotlinConfigCache = new Map();
2115
+ let spotlessGradleReadCount = 0;
2116
+ /** Test-only observability for asserting the hot-path I/O bound. */
2117
+ export function _getSpotlessGradleReadCountForTests() {
2118
+ return spotlessGradleReadCount;
2119
+ }
2120
+ /**
2121
+ * Blank comments and quoted strings while preserving braces and newlines in
2122
+ * executable Gradle source. This is deliberately a small lexical pre-pass,
2123
+ * not a Groovy/Kotlin parser. In particular, statically disabled constructs
2124
+ * such as `if (false) { ktlint() }` remain a documented false-positive.
2125
+ */
2126
+ function stripGradleCommentsAndStrings(source) {
2127
+ let result = "";
2128
+ let state = "code";
2129
+ let quote = "";
2130
+ for (let index = 0; index < source.length; index += 1) {
2131
+ const char = source[index];
2132
+ const next = source[index + 1];
2133
+ if (state === "code") {
2134
+ if (char === "/" && next === "/") {
2135
+ result += " ";
2136
+ index += 1;
2137
+ state = "line-comment";
2138
+ }
2139
+ else if (char === "/" && next === "*") {
2140
+ result += " ";
2141
+ index += 1;
2142
+ state = "block-comment";
2143
+ }
2144
+ else if (char === '"' || char === "'") {
2145
+ result += " ";
2146
+ quote = char;
2147
+ state = "string";
2148
+ }
2149
+ else {
2150
+ result += char;
2151
+ }
2152
+ continue;
2153
+ }
2154
+ if (state === "line-comment") {
2155
+ if (char === "\n" || char === "\r") {
2156
+ result += char;
2157
+ state = "code";
2158
+ }
2159
+ else {
2160
+ result += " ";
2161
+ }
2162
+ continue;
2163
+ }
2164
+ if (state === "block-comment") {
2165
+ if (char === "*" && next === "/") {
2166
+ result += " ";
2167
+ index += 1;
2168
+ state = "code";
2169
+ }
2170
+ else {
2171
+ result += char === "\n" || char === "\r" ? char : " ";
2172
+ }
2173
+ continue;
2174
+ }
2175
+ if (char === "\\") {
2176
+ result += " ";
2177
+ if (index + 1 < source.length) {
2178
+ result += source[index + 1] === "\n" ? "\n" : " ";
2179
+ index += 1;
2180
+ }
2181
+ }
2182
+ else if (char === quote) {
2183
+ result += " ";
2184
+ state = "code";
2185
+ }
2186
+ else {
2187
+ result += char === "\n" || char === "\r" ? char : " ";
2188
+ }
2189
+ }
2190
+ return result;
2191
+ }
2192
+ function namedGradleBlockBodies(source, name) {
2193
+ const bodies = [];
2194
+ const startPattern = new RegExp(`\\b${name}\\s*\\{`, "g");
2195
+ for (const match of source.matchAll(startPattern)) {
2196
+ const open = source.indexOf("{", match.index);
2197
+ let depth = 1;
2198
+ for (let index = open + 1; index < source.length; index += 1) {
2199
+ if (source[index] === "{")
2200
+ depth += 1;
2201
+ if (source[index] === "}")
2202
+ depth -= 1;
2203
+ if (depth === 0) {
2204
+ bodies.push(source.slice(open + 1, index));
2205
+ break;
2206
+ }
2207
+ }
2208
+ }
2209
+ return bodies;
2210
+ }
2211
+ /**
2212
+ * Resolve the formatter elected by a Spotless `kotlin { ... }` block.
2213
+ * ktlint is the deterministic tie-break if a malformed project names both.
2214
+ */
2215
+ export function getSpotlessKotlinFormatter(cwd) {
2216
+ for (const dir of walkUpDirs(cwd)) {
2217
+ for (const gradle of KOTLIN_GRADLE_FILES) {
2218
+ const filePath = path.join(dir, gradle);
2219
+ if (!fs.existsSync(filePath))
2220
+ continue;
2221
+ try {
2222
+ const mtime = fs.statSync(filePath).mtimeMs;
2223
+ let config = spotlessKotlinConfigCache.get(filePath);
2224
+ if (!config || config.mtime !== mtime) {
2225
+ const source = stripGradleCommentsAndStrings(fs.readFileSync(filePath, "utf-8"));
2226
+ spotlessGradleReadCount += 1;
2227
+ const kotlinBodies = namedGradleBlockBodies(source, "spotless").flatMap((spotless) => namedGradleBlockBodies(spotless, "kotlin"));
2228
+ config = {
2229
+ mtime,
2230
+ ktlintConfig: kotlinBodies.some((body) => /\bktlint\s*\(/.test(body)),
2231
+ ktfmtConfig: kotlinBodies.some((body) => /\bktfmt\s*\(/.test(body)),
2232
+ };
2233
+ spotlessKotlinConfigCache.set(filePath, config);
2234
+ }
2235
+ if (config.ktlintConfig)
2236
+ return "ktlint";
2237
+ if (config.ktfmtConfig)
2238
+ return "ktfmt";
2239
+ }
2240
+ catch { }
2241
+ }
2242
+ }
2243
+ return undefined;
2244
+ }
2245
+ export function hasKtlintConfig(cwd) {
2246
+ return getSpotlessKotlinFormatter(cwd) === "ktlint";
2247
+ }
1900
2248
  export function hasKtfmtConfig(cwd) {
2249
+ const spotlessFormatter = getSpotlessKotlinFormatter(cwd);
2250
+ if (spotlessFormatter)
2251
+ return spotlessFormatter === "ktfmt";
1901
2252
  for (const dir of walkUpDirs(cwd)) {
1902
2253
  if (KTFMT_CONFIG_FILES.some((cfg) => fs.existsSync(path.join(dir, cfg))))
1903
2254
  return true;