@herbertgao/pi-extensions 2026.9.2 → 2026.9.4

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 (255) hide show
  1. package/README.md +4 -2
  2. package/THIRD_PARTY_NOTICES.md +49 -0
  3. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
  8. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  9. package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
  10. package/node_modules/@herbertgao/sol-pi/README.md +159 -0
  11. package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
  12. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
  13. package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
  14. package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
  15. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
  16. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
  17. package/node_modules/@herbertgao/sol-pi/package.json +76 -0
  18. package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
  19. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
  20. package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
  21. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
  22. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
  23. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
  24. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
  25. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
  26. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
  27. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
  28. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
  29. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
  30. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
  31. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
  32. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
  33. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
  34. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
  35. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
  36. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
  37. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
  38. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
  39. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
  40. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
  41. package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
  42. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
  43. package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
  44. package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -2
  45. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
  46. package/node_modules/@narumitw/pi-btw/package.json +1 -1
  47. package/node_modules/@narumitw/pi-btw/src/btw.ts +13 -2
  48. package/node_modules/pi-antigravity/LICENSE +21 -0
  49. package/node_modules/pi-antigravity/README.md +194 -0
  50. package/node_modules/pi-antigravity/package.json +67 -0
  51. package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
  52. package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
  53. package/node_modules/pi-antigravity/src/client/client.ts +561 -0
  54. package/node_modules/pi-antigravity/src/client/index.ts +1 -0
  55. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
  56. package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
  57. package/node_modules/pi-antigravity/src/image/image.ts +336 -0
  58. package/node_modules/pi-antigravity/src/image/index.ts +1 -0
  59. package/node_modules/pi-antigravity/src/index.ts +280 -0
  60. package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
  61. package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
  62. package/node_modules/pi-antigravity/src/models/index.ts +3 -0
  63. package/node_modules/pi-antigravity/src/models/models.ts +500 -0
  64. package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
  65. package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
  66. package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
  67. package/node_modules/pi-antigravity/src/types/index.ts +2 -0
  68. package/node_modules/pi-antigravity/src/types/types.ts +292 -0
  69. package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
  70. package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
  71. package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
  72. package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
  73. package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
  74. package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
  75. package/node_modules/pi-antigravity/tsconfig.json +21 -0
  76. package/node_modules/pi-lens/CHANGELOG.md +176 -0
  77. package/node_modules/pi-lens/README.md +13 -8
  78. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
  79. package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
  80. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -1
  81. package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
  82. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -0
  83. package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -1
  84. package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
  85. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
  86. package/node_modules/pi-lens/dist/clients/config-resolve.js +6 -3
  87. package/node_modules/pi-lens/dist/clients/config-schema.js +17 -0
  88. package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
  89. package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
  90. package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -15
  92. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
  93. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -3
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +2 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +2 -1
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +2 -2
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -1
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +2 -2
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +4 -3
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
  143. package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
  144. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
  145. package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
  146. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
  147. package/node_modules/pi-lens/dist/clients/formatters.js +54 -188
  148. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
  149. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
  150. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
  151. package/node_modules/pi-lens/dist/clients/installer/index.js +196 -52
  152. package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
  153. package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
  154. package/node_modules/pi-lens/dist/clients/language-profile.js +12 -2
  155. package/node_modules/pi-lens/dist/clients/latency-logger.js +2 -0
  156. package/node_modules/pi-lens/dist/clients/lens-config.js +4 -0
  157. package/node_modules/pi-lens/dist/clients/lsp/config.js +36 -7
  158. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +78 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/index.js +281 -45
  161. package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
  162. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
  163. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
  164. package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
  165. package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
  166. package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
  167. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +8 -3
  168. package/node_modules/pi-lens/dist/clients/pipeline.js +3 -2
  169. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
  170. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
  171. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  172. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +2 -0
  173. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
  174. package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
  175. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +9 -0
  176. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
  177. package/node_modules/pi-lens/dist/clients/runtime-session.js +13 -4
  178. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
  179. package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
  180. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
  181. package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
  182. package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
  183. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
  184. package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
  185. package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
  186. package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
  187. package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
  188. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
  189. package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
  190. package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
  191. package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
  192. package/node_modules/pi-lens/dist/index.js +21969 -20005
  193. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
  194. package/node_modules/pi-lens/dist/mcp/server.js +135 -159
  195. package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
  196. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
  197. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
  198. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
  199. package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
  200. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
  201. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +353 -85
  202. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +21 -110
  203. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
  204. package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
  205. package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
  206. package/node_modules/pi-lens/dist/tools/render-compact.js +280 -1
  207. package/node_modules/pi-lens/dist/tools/symbol-search.js +2 -2
  208. package/node_modules/pi-lens/docs/agent-guide.md +3 -4
  209. package/node_modules/pi-lens/docs/agent-tools.md +46 -22
  210. package/node_modules/pi-lens/docs/configuration.md +9 -0
  211. package/node_modules/pi-lens/docs/environment-variables.md +0 -5
  212. package/node_modules/pi-lens/docs/features.md +5 -5
  213. package/node_modules/pi-lens/docs/globalconfig.md +11 -1
  214. package/node_modules/pi-lens/docs/mcp.md +13 -1
  215. package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
  216. package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
  217. package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
  218. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +35 -0
  219. package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -4
  220. package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
  221. package/node_modules/pi-lens/docs/real-harness.md +46 -0
  222. package/node_modules/pi-lens/docs/release-qa-baseline.md +5 -1
  223. package/node_modules/pi-lens/docs/servercapabilities.md +1 -6
  224. package/node_modules/pi-lens/docs/settings.md +37 -2
  225. package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
  226. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  227. package/node_modules/pi-lens/docs/usage.md +13 -3
  228. package/node_modules/pi-lens/package.json +10 -1
  229. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
  230. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
  231. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
  232. package/node_modules/pi-web-access/CHANGELOG.md +29 -0
  233. package/node_modules/pi-web-access/README.md +33 -22
  234. package/node_modules/pi-web-access/abortable.ts +17 -0
  235. package/node_modules/pi-web-access/crawl4ai.ts +204 -0
  236. package/node_modules/pi-web-access/credential-source.ts +1 -0
  237. package/node_modules/pi-web-access/curator-page.ts +20 -2
  238. package/node_modules/pi-web-access/curator-run.ts +44 -0
  239. package/node_modules/pi-web-access/curator-server.ts +3 -1
  240. package/node_modules/pi-web-access/duckduckgo.ts +1 -1
  241. package/node_modules/pi-web-access/extract.ts +57 -12
  242. package/node_modules/pi-web-access/fetch-params.ts +1 -1
  243. package/node_modules/pi-web-access/gemini-search.ts +9 -5
  244. package/node_modules/pi-web-access/index.ts +25 -18
  245. package/node_modules/pi-web-access/openai-search.ts +35 -13
  246. package/node_modules/pi-web-access/package.json +2 -2
  247. package/node_modules/pi-web-access/page-query.ts +5 -2
  248. package/node_modules/pi-web-access/query-rewrite.ts +5 -2
  249. package/node_modules/pi-web-access/serpapi.ts +220 -0
  250. package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
  251. package/node_modules/pi-web-access/storage.ts +10 -0
  252. package/node_modules/pi-web-access/summary-review.ts +34 -21
  253. package/node_modules/pi-web-access/utils.ts +6 -4
  254. package/package.json +11 -5
  255. package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
@@ -1,4 +1,5 @@
1
1
  import { safeSpawnAsync } from "../../safe-spawn.js";
2
+ import { logRunnerAdvisoryOnce, resolveRunnerCwd } from "../../tool-cwd.js";
2
3
  import { getLinterPolicyForCwd, hasSqlfluffConfig } from "../../tool-policy.js";
3
4
  import { PRIORITY } from "../priorities.js";
4
5
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
@@ -117,14 +118,14 @@ const sqlfluffRunner = {
117
118
  priority: PRIORITY.SQL_LINT,
118
119
  skipTestFiles: false,
119
120
  async run(ctx) {
120
- const cwd = ctx.cwd || process.cwd();
121
+ const cwd = resolveRunnerCwd(ctx, "sqlfluff");
121
122
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
122
123
  if (policy && !policy.preferredRunners.includes("sqlfluff")) {
123
124
  return { status: "skipped", diagnostics: [], semantic: "none" };
124
125
  }
125
126
  const hasConfig = hasSqlfluffConfig(cwd);
126
127
  if (!hasConfig) {
127
- ctx.log("sqlfluff: no config detected, using ANSI dialect defaults");
128
+ logRunnerAdvisoryOnce(ctx, "sqlfluff", cwd, "sqlfluff: no config detected, using ANSI dialect defaults");
128
129
  }
129
130
  let cmd = null;
130
131
  if (await sqlfluff.isAvailableAsync(cwd)) {
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { logRunnerAdvisoryOnce, resolveRunnerCwd } from "../../tool-cwd.js";
3
4
  import { getLinterPolicyForCwd, hasStylelintConfig, } from "../../tool-policy.js";
4
5
  import { PRIORITY } from "../priorities.js";
5
6
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
@@ -116,7 +117,7 @@ const stylelintRunner = {
116
117
  priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
117
118
  skipTestFiles: false,
118
119
  async run(ctx) {
119
- const cwd = ctx.cwd || process.cwd();
120
+ const cwd = resolveRunnerCwd(ctx, "stylelint");
120
121
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
121
122
  if (policy && !policy.preferredRunners.includes("stylelint")) {
122
123
  return { status: "skipped", diagnostics: [], semantic: "none" };
@@ -124,7 +125,7 @@ const stylelintRunner = {
124
125
  const fileDir = path.dirname(path.resolve(cwd, ctx.filePath));
125
126
  const hasConfig = hasStylelintConfig(fileDir) || hasStylelintConfig(cwd);
126
127
  if (!hasConfig) {
127
- ctx.log("stylelint: no config detected, running with default rules");
128
+ logRunnerAdvisoryOnce(ctx, "stylelint", cwd, "stylelint: no config detected, running with default rules");
128
129
  }
129
130
  let cmd = null;
130
131
  if (await stylelint.isAvailableAsync(cwd)) {
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
3
4
  import { PRIORITY } from "../priorities.js";
4
5
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
6
  import { parseToolRun } from "./utils/tool-failure.js";
@@ -115,7 +116,7 @@ const swiftlintRunner = {
115
116
  priority: PRIORITY.GENERAL_ANALYSIS,
116
117
  skipTestFiles: false,
117
118
  async run(ctx) {
118
- const cwd = ctx.cwd || process.cwd();
119
+ const cwd = resolveRunnerCwd(ctx, "swiftlint");
119
120
  let cmd = null;
120
121
  if (await swiftlint.isAvailableAsync(cwd)) {
121
122
  cmd = swiftlint.getCommand(cwd);
@@ -1,6 +1,7 @@
1
1
  import * as path from "node:path";
2
2
  import { findLocalBinUpwards } from "../../package-manager.js";
3
3
  import { safeSpawnAsync } from "../../safe-spawn.js";
4
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
4
5
  import { getLinterPolicyForCwd } from "../../tool-policy.js";
5
6
  import { PRIORITY } from "../priorities.js";
6
7
  import { createAvailabilityChecker, lspPrimaryCoversFile, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
@@ -106,7 +107,7 @@ const taploRunner = {
106
107
  priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
107
108
  skipTestFiles: false,
108
109
  async run(ctx) {
109
- const cwd = ctx.cwd || process.cwd();
110
+ const cwd = resolveRunnerCwd(ctx, "taplo");
110
111
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
111
112
  if (policy && !policy.preferredRunners.includes("taplo")) {
112
113
  return { status: "skipped", diagnostics: [], semantic: "none" };
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
3
4
  import { pathsEqual } from "../../path-utils.js";
4
5
  import { getLinterPolicyForCwd } from "../../tool-policy.js";
5
6
  import { PRIORITY } from "../priorities.js";
@@ -128,7 +129,7 @@ const terragruntRunner = {
128
129
  priority: PRIORITY.GENERAL_ANALYSIS,
129
130
  skipTestFiles: false,
130
131
  async run(ctx) {
131
- const cwd = ctx.cwd || process.cwd();
132
+ const cwd = resolveRunnerCwd(ctx, "terragrunt");
132
133
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
133
134
  if (policy && !policy.preferredRunners.includes("terragrunt"))
134
135
  return SKIPPED;
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
3
4
  import { getLinterPolicyForCwd } from "../../tool-policy.js";
4
5
  import { findNearestDirWithAnyBasename } from "../../workspace-topology.js";
5
6
  import { PRIORITY } from "../priorities.js";
@@ -52,7 +53,7 @@ const tflintRunner = {
52
53
  priority: PRIORITY.GENERAL_ANALYSIS,
53
54
  skipTestFiles: false,
54
55
  async run(ctx) {
55
- const cwd = ctx.cwd || process.cwd();
56
+ const cwd = resolveRunnerCwd(ctx, "tflint");
56
57
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
57
58
  if (policy && !policy.preferredRunners.includes("tflint")) {
58
59
  return { status: "skipped", diagnostics: [], semantic: "none" };
@@ -40,6 +40,7 @@ import * as fs from "node:fs";
40
40
  import * as path from "node:path";
41
41
  import { incrementDegradationCount } from "../../degradation-ledger.js";
42
42
  import { safeSpawnAsync } from "../../safe-spawn.js";
43
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
43
44
  import { isTrivyEnabled, resolveSeverityFloor, } from "../../trivy-client.js";
44
45
  import { PRIORITY } from "../priorities.js";
45
46
  import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
@@ -148,7 +149,7 @@ const trivyConfigRunner = {
148
149
  priority: PRIORITY.GENERAL_ANALYSIS,
149
150
  skipTestFiles: false,
150
151
  async run(ctx) {
151
- const cwd = ctx.cwd || process.cwd();
152
+ const cwd = resolveRunnerCwd(ctx, "trivy-config");
152
153
  // Single opt-in switch — trivy is opt-in across all modes.
153
154
  if (!isTrivyEnabled(cwd)) {
154
155
  return { status: "skipped", diagnostics: [], semantic: "none" };
@@ -75,6 +75,11 @@ export function describeInstallAttempt(attempt, options = {}) {
75
75
  return { install: "succeeded", ...(reason && { installReason: reason }) };
76
76
  case "failed":
77
77
  return { install: "failed", ...(reason && { installReason: reason }) };
78
+ case "unavailable":
79
+ return {
80
+ install: "unavailable",
81
+ ...(reason && { installReason: reason }),
82
+ };
78
83
  default:
79
84
  return {
80
85
  install: "not-attempted",
@@ -11,7 +11,7 @@
11
11
  * Complexity limit. This is that sweep, written once.
12
12
  */
13
13
  import * as fs from "node:fs";
14
- import { safeSpawnAsync } from "../../../safe-spawn.js";
14
+ import { probeToolAsync } from "../../../tool-probe.js";
15
15
  import { classifyProbeFailure, startHostStallSampler, } from "./availability-policy.js";
16
16
  /**
17
17
  * Walk `candidates` in order. A candidate containing a path separator is
@@ -45,7 +45,7 @@ export async function probeAvailabilityCandidates(candidates, probeArgs, timeout
45
45
  let result;
46
46
  let stallMs;
47
47
  try {
48
- result = await safeSpawnAsync(candidate, [...probeArgs], {
48
+ result = await probeToolAsync(candidate, probeArgs, {
49
49
  timeout: timeoutMs,
50
50
  });
51
51
  }
@@ -20,9 +20,11 @@ import { getServersForFileWithConfig, isServerDisabled, } from "../../../lsp/con
20
20
  import { findGlobalBinary, findLocalBinAt, findLocalBinsUpwards, findLocalBinUpwards, VENDOR_BIN_DIRS, VENV_BIN_DIRS, } from "../../../package-manager.js";
21
21
  import { logLatency } from "../../../latency-logger.js";
22
22
  import { safeSpawnAsync } from "../../../safe-spawn.js";
23
+ import { probeToolAsync } from "../../../tool-probe.js";
23
24
  import { compareOrdinal } from "../../../string-utils.js";
24
25
  import { getToolCommandSpec, shouldAutoInstallTool, } from "../../../tool-policy.js";
25
26
  import { isInSpawnTimeoutCooldown } from "../../../spawn-timeout-cooldown.js";
27
+ import { resolveToolCwd } from "../../../tool-cwd.js";
26
28
  import { createAvailabilityProbeFlight } from "../../../availability-probe-flight.js";
27
29
  import { classifyProbeFailure, createAvailabilityLatch, describeInstallAttempt, describeProbeEvidence, isLatchingOutcome, logAvailabilityDecision, startHostStallSampler, transientRetryDelayMs, } from "./availability-policy.js";
28
30
  export { createAvailabilityLatch, classifyProbeFailure, describeProbeEvidence, describeUnavailability, isTransientDecision, logAvailabilityDecision, startHostStallSampler, } from "./availability-policy.js";
@@ -1390,7 +1392,7 @@ async function probeAstGrepCommandAsync(cmd, argsPrefix = []) {
1390
1392
  let check;
1391
1393
  let hostStallMs;
1392
1394
  try {
1393
- check = await safeSpawnAsync(cmd, [...argsPrefix, "--version"], {
1395
+ check = await probeToolAsync(cmd, [...argsPrefix, "--version"], {
1394
1396
  timeout: 5000,
1395
1397
  });
1396
1398
  }
@@ -1674,7 +1676,7 @@ export async function resolveLocalFirstAsync(toolName, cwd, windowsExt = ".cmd")
1674
1676
  if (globalBin)
1675
1677
  return { cmd: globalBin, args: [] };
1676
1678
  // 3. Global PATH (already installed system-wide, on PATH)
1677
- const globalCheck = await safeSpawnAsync(toolName, ["--version"], {
1679
+ const globalCheck = await probeToolAsync(toolName, ["--version"], {
1678
1680
  timeout: 3000,
1679
1681
  });
1680
1682
  if (!globalCheck.error && globalCheck.status === 0) {
@@ -1693,3 +1695,7 @@ export const sg = {
1693
1695
  isAvailableAsync: isSgAvailableAsync,
1694
1696
  getCommand: getSgCommand,
1695
1697
  };
1698
+ /** Shared cwd seam for runner probes and analysis children (#2777). */
1699
+ export function resolveRunnerCwd(ctx, tool) {
1700
+ return resolveToolCwd("runner", tool, ctx.filePath, ctx);
1701
+ }
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { safeSpawnAsync } from "../../safe-spawn.js";
4
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
4
5
  import { PRIORITY } from "../priorities.js";
5
6
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
7
  import { parseToolRun } from "./utils/tool-failure.js";
@@ -72,7 +73,7 @@ const valeRunner = {
72
73
  priority: PRIORITY.DOC_QUALITY,
73
74
  skipTestFiles: false,
74
75
  async run(ctx) {
75
- const cwd = ctx.cwd || process.cwd();
76
+ const cwd = resolveRunnerCwd(ctx, "vale");
76
77
  // Config-gated: skip unless a .vale.ini is found
77
78
  if (!findValeConfig(cwd)) {
78
79
  return { status: "skipped", diagnostics: [], semantic: "none" };
@@ -1,7 +1,8 @@
1
1
  import { safeSpawnAsync } from "../../safe-spawn.js";
2
+ import { logRunnerAdvisoryOnce } from "../../tool-cwd.js";
2
3
  import { getLinterPolicyForCwd, hasYamllintConfig } from "../../tool-policy.js";
3
4
  import { PRIORITY } from "../priorities.js";
4
- import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
+ import { createAvailabilityChecker, resolveRunnerCwd, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
6
  import { parseToolRun } from "./utils/tool-failure.js";
6
7
  import { finishParsedRun } from "./utils/tool-failure.js";
7
8
  const yamllint = createAvailabilityChecker("yamllint", ".exe");
@@ -35,14 +36,14 @@ const yamllintRunner = {
35
36
  priority: PRIORITY.YAML_LINT,
36
37
  skipTestFiles: false,
37
38
  async run(ctx) {
38
- const cwd = ctx.cwd || process.cwd();
39
+ const cwd = resolveRunnerCwd(ctx, "yamllint");
39
40
  const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
40
41
  if (policy && !policy.preferredRunners.includes("yamllint")) {
41
42
  return { status: "skipped", diagnostics: [], semantic: "none" };
42
43
  }
43
44
  const hasConfig = hasYamllintConfig(cwd);
44
45
  if (!hasConfig) {
45
- ctx.log("yamllint: no config detected, running with default rules");
46
+ logRunnerAdvisoryOnce(ctx, "yamllint", cwd, "yamllint: no config detected, running with default rules");
46
47
  }
47
48
  let cmd = null;
48
49
  if (await yamllint.isAvailableAsync(cwd)) {
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { resolveRunnerCwd } from "../../tool-cwd.js";
3
4
  import { createAvailabilityChecker } from "./utils/runner-helpers.js";
4
5
  import { PRIORITY } from "../priorities.js";
5
6
  // zig rejects `--version`; the version subcommand is `zig version`. Using the
@@ -46,7 +47,7 @@ const zigCheckRunner = {
46
47
  priority: PRIORITY.GENERAL_ANALYSIS,
47
48
  skipTestFiles: false,
48
49
  async run(ctx) {
49
- const cwd = ctx.cwd || process.cwd();
50
+ const cwd = resolveRunnerCwd(ctx, "zig-check");
50
51
  if (!(await zig.isAvailableAsync(cwd))) {
51
52
  return { status: "skipped", diagnostics: [], semantic: "none" };
52
53
  }
@@ -47,7 +47,9 @@ import { explainServersForFile, lspConfigOf, registerLSPConfig, } from "./lsp/co
47
47
  // apart on a Windows-shaped path (AGENTS.md defect shape 2).
48
48
  import { isSameOrWithin } from "./lsp/server.js";
49
49
  import { homeRelativePath } from "./path-utils.js";
50
+ import { resolveToolCwd } from "./tool-cwd.js";
50
51
  import { compareOrdinal } from "./string-utils.js";
52
+ import { LENS_TOOL_NAMES, resolveLensToolEnabled } from "./tool-config.js";
51
53
  /** True when a `file` half is the rejection shape, not a resolved view. */
52
54
  export function isEffectiveFileViewError(file) {
53
55
  return "error" in file;
@@ -289,6 +291,10 @@ export async function effectiveConfig(options = {}) {
289
291
  provenance: provenanceView(resolved, homeDir).entries,
290
292
  provenanceCounts: summary.countsByTier,
291
293
  recordCounts: countBy(resolution.records, (record) => record.code),
294
+ tools: LENS_TOOL_NAMES.map((name) => ({
295
+ name,
296
+ enabled: resolveLensToolEnabled(name, resolved.value, undefined, options.noTools),
297
+ })),
292
298
  ...(fileOutsideCwd
293
299
  ? {
294
300
  file: {
@@ -299,7 +305,7 @@ export async function effectiveConfig(options = {}) {
299
305
  : absolute === undefined
300
306
  ? {}
301
307
  : {
302
- file: await fileView(absolute, resolved, homeDir,
308
+ file: await fileView(absolute, resolved, homeDir, cwd,
303
309
  // The gates read the LSP slice of that SAME resolution, through
304
310
  // the same `registerLSPConfig` conversion `initLSPConfig` uses —
305
311
  // no session-root registration, no per-root config-store write
@@ -325,7 +331,7 @@ function toolReason(selected, kind) {
325
331
  return "selected";
326
332
  return kind === undefined ? "no-dispatch-plan" : "not-registered-for-kind";
327
333
  }
328
- async function fileView(absolute, resolved, homeDir, lspConfig) {
334
+ async function fileView(absolute, resolved, homeDir, workspaceCwd, lspConfig) {
329
335
  const language = resolveLanguage(absolute);
330
336
  const kind = detectFileKind(absolute);
331
337
  const section = lspSectionOf(resolved.value);
@@ -392,6 +398,10 @@ async function fileView(absolute, resolved, homeDir, lspConfig) {
392
398
  id,
393
399
  selected: available.has(id),
394
400
  reason: toolReason(available.has(id), kind),
401
+ resolvedCwd: homeRelativePath(resolveToolCwd("runner", id, absolute, {
402
+ cwd: workspaceCwd,
403
+ suppressTelemetry: true,
404
+ }), homeDir),
395
405
  }));
396
406
  return {
397
407
  path: homeRelativePath(absolute, homeDir),
@@ -26,6 +26,7 @@ import { isTestMode } from "./env-utils.js";
26
26
  import { getGlobalPiLensLogDir } from "./probe-home-state.js";
27
27
  import { getMaxLogSizeMB } from "./log-cleanup.js";
28
28
  import { createNdjsonLogger } from "./ndjson-logger.js";
29
+ import { getTurnId } from "./turn-context.js";
29
30
  export const EXTENSION_LOG_FILE = path.join(getGlobalPiLensLogDir(), "extension.log");
30
31
  const writer = createNdjsonLogger({
31
32
  filePath: EXTENSION_LOG_FILE,
@@ -37,6 +38,7 @@ export function logExtension(entry) {
37
38
  writer.log({
38
39
  ts: new Date().toISOString(),
39
40
  pid: process.pid,
41
+ turnId: getTurnId(),
40
42
  level: entry.level ?? "error",
41
43
  subsystem: entry.subsystem,
42
44
  message: entry.message,
@@ -51,15 +51,32 @@ function isTypeStub(content) {
51
51
  */
52
52
  export function detectFileRole(filePath, content) {
53
53
  const windowsShaped = isWindowsPath(filePath);
54
- const base = (windowsShaped ? win32.basename(filePath) : basename(filePath)).toLowerCase();
54
+ const rawBase = windowsShaped ? win32.basename(filePath) : basename(filePath);
55
+ const base = rawBase.toLowerCase();
55
56
  const dir = (windowsShaped ? win32.dirname(filePath) : dirname(filePath))
56
57
  .replace(/\\/g, "/")
57
58
  .toLowerCase();
58
59
  // --- Test ---
60
+ // Suffix conventions informed by the test-runner table
61
+ // (SOURCE_TO_TEST_PATTERNS + RUNNERS kinds in
62
+ // clients/test-runner-client.ts); hand-written, not iterated from it —
63
+ // see #2928 for the single-classifier fold:
64
+ // - `_test.` infix: Go (`*_test.go`), pytest (`*_test.py`), ExUnit
65
+ // (`*_test.exs`), Dart (`*_test.dart`). The underscore anchor keeps
66
+ // this precise: `contest.py` and `latest.ts` do not match.
67
+ // - `_spec.` infix: RSpec (`*_spec.rb`).
68
+ // - CamelCase `*Test(s).<ext>` suffix, matched case-SENSITIVELY on the
69
+ // raw basename: JUnit/Surefire (`*Test.java`, `*TestCase.java`),
70
+ // Kotlin (`*Test.kt`), dotnet (`*Test.cs`/`*Tests.cs`), PHPUnit
71
+ // (`*Test.php`). Case matters: Surefire's `*Test.java` does not match
72
+ // `contest.java`, so neither do we.
59
73
  if (base.includes(".test.") ||
60
74
  base.includes(".spec.") ||
75
+ base.includes("_test.") ||
76
+ base.includes("_spec.") ||
61
77
  base.startsWith("test_") ||
62
78
  base.startsWith("spec_") ||
79
+ /(Test|Tests|TestCase)\.(java|kt|kts|cs|fs|php)$/.test(rawBase) ||
63
80
  dir.includes("/__tests__/") ||
64
81
  dir.includes("/test/") ||
65
82
  dir.includes("/tests/") ||
@@ -139,6 +139,10 @@
139
139
  * agent-facing surface is EITHER gated OR explicitly labeled — never neither.
140
140
  */
141
141
  const MS_PER_MINUTE = 60_000;
142
+ /** Mark retained findings whose replacement result could not be reconciled. */
143
+ export function markUnreconciledFindings(findings) {
144
+ return findings.map((finding) => ({ ...finding, stale: true }));
145
+ }
142
146
  /**
143
147
  * Render a short, honest age suffix for a store that cannot be freshness-
144
148
  * gated per-path (see module doc). `undefined`/unparseable `scannedAt`