@herbertgao/pi-extensions 2026.8.4 → 2026.8.5

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 (288) hide show
  1. package/README.md +4 -4
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  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/index.ts +7 -6
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  13. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  14. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  15. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  16. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
  20. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  21. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  22. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  25. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  30. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  31. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  32. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  33. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  34. package/node_modules/pi-lens/README.md +13 -0
  35. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  36. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  37. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  39. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  40. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  41. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  42. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  43. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  44. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  45. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  46. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  47. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  51. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  52. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  53. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  54. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  56. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  57. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  58. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  59. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  60. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  63. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  64. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  66. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  67. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  68. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  69. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  70. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  71. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  72. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  73. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  75. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  99. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  100. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  101. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  102. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  103. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  104. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  105. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  106. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  107. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  108. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  109. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  110. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  111. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  112. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  113. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  114. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  116. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  117. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  118. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  120. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  121. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  122. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  123. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  124. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  125. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  126. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  127. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  128. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  129. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  130. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  131. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  132. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  134. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  135. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  136. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  137. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  138. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  139. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  140. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  141. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  142. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  143. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  144. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  145. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  146. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  147. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  148. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  149. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  150. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  151. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  152. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  153. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  154. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  155. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  157. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  158. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  159. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  160. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  161. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  162. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  163. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  164. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  165. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  166. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  167. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  168. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  169. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  170. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  171. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  172. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  173. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  174. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  175. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  177. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  178. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  179. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  180. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  181. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  182. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  183. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  184. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  185. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  186. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  187. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  188. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  189. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  190. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  191. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  192. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  193. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  194. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  196. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  197. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  198. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  199. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  200. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  201. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  202. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  203. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  204. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  205. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  210. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  211. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  212. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  213. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  214. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  215. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  216. package/node_modules/pi-lens/dist/index.js +49361 -36888
  217. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  218. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  219. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  220. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  221. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  222. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  223. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  224. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  225. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  226. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  227. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  228. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  229. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  230. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  231. package/node_modules/pi-lens/docs/fable.md +27 -0
  232. package/node_modules/pi-lens/docs/features.md +31 -2
  233. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  234. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  235. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  236. package/node_modules/pi-lens/docs/mcp.md +37 -4
  237. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  238. package/node_modules/pi-lens/docs/settings.md +12 -1
  239. package/node_modules/pi-lens/docs/tools.md +4 -1
  240. package/node_modules/pi-lens/docs/usage.md +18 -0
  241. package/node_modules/pi-lens/package.json +10 -10
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  252. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  253. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  254. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  255. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  256. package/node_modules/pi-mcp-adapter/README.md +34 -3
  257. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  258. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  259. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  260. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  261. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  262. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  263. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  264. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  265. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  266. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  267. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  268. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  269. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  270. package/node_modules/pi-mcp-adapter/package.json +3 -3
  271. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  272. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  273. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  274. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  275. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  276. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  277. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  278. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  279. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  280. package/package.json +11 -12
  281. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  282. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  283. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  284. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  285. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  286. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  287. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  288. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -14,11 +14,12 @@
14
14
  */
15
15
  import * as fs from "node:fs";
16
16
  import * as path from "node:path";
17
+ import { BoundedLruCache } from "../bounded-cache.js";
17
18
  import { normalizeFilePath, walkUpDirs } from "../path-utils.js";
18
19
  // Per-process cache of resolved gitdir location keyed by cwd — the gitdir
19
20
  // location itself is stable for the life of the process; only HEAD's
20
21
  // CONTENT changes (on commit/checkout), so that's re-read fresh every call.
21
- const _gitDirCache = new Map();
22
+ const _gitDirCache = new BoundedLruCache(32);
22
23
  export function _resetGitIdentityCacheForTests() {
23
24
  _gitDirCache.clear();
24
25
  }
@@ -90,7 +90,7 @@ function resolveDart(cwd, filePath, source) {
90
90
  // JS/TS extension from the specifier before re-appending candidate extensions
91
91
  // lets that universal pattern resolve to the real source file. Exported so
92
92
  // builder.ts's warm `localImportToFile` shares the exact same regex (#694).
93
- export const JS_TS_EXT_RE = /\.(mjs|cjs|jsx?|tsx?)$/i;
93
+ export const JS_TS_EXT_RE = /\.(mjs|cjs|mts|cts|jsx?|tsx?)$/i;
94
94
  /**
95
95
  * Ordered candidate list for resolving a relative JS/TS import specifier
96
96
  * (already resolved to an absolute base path) to an on-disk file, with
@@ -122,13 +122,18 @@ function jsTsExtensionCandidates(base, strippedBase, ext) {
122
122
  candidates.push(`${strippedBase}.mts`);
123
123
  if (ext === ".cjs")
124
124
  candidates.push(`${strippedBase}.cts`);
125
- candidates.push(`${strippedBase}.ts`, `${strippedBase}.tsx`);
125
+ if (ext === ".mts")
126
+ candidates.push(`${strippedBase}.mts`);
127
+ if (ext === ".cts")
128
+ candidates.push(`${strippedBase}.cts`);
129
+ candidates.push(`${strippedBase}.ts`, `${strippedBase}.tsx`, `${strippedBase}.mts`, `${strippedBase}.cts`);
126
130
  // The literal specifier path (covers both "no extension in the specifier"
127
131
  // — base === strippedBase — and the compiled/as-written extension itself).
128
- candidates.push(base);
129
- candidates.push(`${strippedBase}.js`, `${strippedBase}.jsx`);
130
- candidates.push(path.join(base, "index.ts"), path.join(base, "index.tsx"), path.join(base, "index.js"), path.join(base, "index.jsx"));
131
- return candidates;
132
+ candidates.push(base, `${strippedBase}.js`, `${strippedBase}.jsx`, `${strippedBase}.mjs`, `${strippedBase}.cjs`);
133
+ for (const index of ["index.ts", "index.tsx", "index.mts", "index.cts", "index.js", "index.jsx", "index.mjs", "index.cjs"]) {
134
+ candidates.push(path.join(base, index));
135
+ }
136
+ return [...new Set(candidates)];
132
137
  }
133
138
  export function jsTsCandidatePaths(filePath, source) {
134
139
  const base = path.resolve(path.dirname(filePath), source);
@@ -198,10 +203,16 @@ function workspaceEntryCandidates(pkgRoot) {
198
203
  // missing/unreadable package.json — fall through to index candidates
199
204
  }
200
205
  const candidates = [];
201
- if (main)
202
- candidates.push(path.resolve(pkgRoot, main));
203
- candidates.push(path.join(pkgRoot, "index.ts"), path.join(pkgRoot, "index.tsx"), path.join(pkgRoot, "index.js"), path.join(pkgRoot, "src", "index.ts"), path.join(pkgRoot, "src", "index.js"));
204
- return candidates;
206
+ if (main) {
207
+ const mainPath = path.resolve(pkgRoot, main);
208
+ const ext = path.extname(mainPath).toLowerCase();
209
+ const stripped = mainPath.replace(JS_TS_EXT_RE, "");
210
+ candidates.push(...jsTsExtensionCandidates(mainPath, stripped, ext));
211
+ }
212
+ for (const base of [pkgRoot, path.join(pkgRoot, "src")]) {
213
+ candidates.push(path.join(base, "index.ts"), path.join(base, "index.tsx"), path.join(base, "index.mts"), path.join(base, "index.cts"), path.join(base, "index.js"), path.join(base, "index.jsx"), path.join(base, "index.mjs"), path.join(base, "index.cjs"));
214
+ }
215
+ return [...new Set(candidates)];
205
216
  }
206
217
  /** Candidate paths for a workspace-package SUBPATH import (`@scope/pkg/foo`)
207
218
  * — same source-twin-preferring extension probe as a relative import, rooted
@@ -55,3 +55,49 @@
55
55
  export function buildSymbolId(filePath, name, kind, startLine) {
56
56
  return `${filePath}:${name}:${kind}:${startLine}`;
57
57
  }
58
+ /**
59
+ * Structural shape of a kind token in a canonical symbol id: every kind this
60
+ * repo mints — the fixed `buildSymbolId` vocabulary (`function`, `method`,
61
+ * `class`, ...) AND the open-ended LSP-fallback vocabulary from
62
+ * `lspSymbolKindName` (`enum`, `struct`, `type-parameter`, `enum-member`, the
63
+ * `lsp-symbol-<n>` catch-all for unknown LSP `SymbolKind` numbers, ...) —
64
+ * is a lowercase word optionally hyphen-segmented, never containing a colon.
65
+ * Matching this SHAPE (rather than whitelisting specific kind strings) keeps
66
+ * `parseSymbolKey` in agreement with whatever kind vocabulary either minter
67
+ * uses, present or future, without needing a matching update here.
68
+ */
69
+ const KIND_TOKEN_RE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
70
+ /**
71
+ * Parse both canonical symbol IDs and the legacy `file:name` compatibility
72
+ * shape. Canonical IDs are recognized from their typed line suffix, so drive
73
+ * letters and colons in POSIX filenames are data rather than separators. A
74
+ * known file hint makes the legacy form lossless too; without it, legacy IDs
75
+ * remain inherently ambiguous and use their historical final separator.
76
+ */
77
+ export function parseSymbolKey(key, knownFilePath) {
78
+ if (key.startsWith("file:")) {
79
+ return { filePath: key.slice("file:".length) };
80
+ }
81
+ const canonical = /^(.*):([^:]*):([^:]+):(\d+)$/.exec(key);
82
+ if (canonical && KIND_TOKEN_RE.test(canonical[3])) {
83
+ return {
84
+ filePath: canonical[1],
85
+ symbolName: canonical[2] || undefined,
86
+ kind: canonical[3],
87
+ line: Number(canonical[4]),
88
+ };
89
+ }
90
+ if (knownFilePath && key.startsWith(`${knownFilePath}:`)) {
91
+ return {
92
+ filePath: knownFilePath,
93
+ symbolName: key.slice(knownFilePath.length + 1) || undefined,
94
+ };
95
+ }
96
+ const separator = key.lastIndexOf(":");
97
+ return separator < 0
98
+ ? { filePath: key }
99
+ : {
100
+ filePath: key.slice(0, separator),
101
+ symbolName: key.slice(separator + 1) || undefined,
102
+ };
103
+ }
@@ -1,9 +1,10 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as os from "node:os";
3
+ import { BoundedLruCache } from "../bounded-cache.js";
3
4
  import * as path from "node:path";
4
5
  import { findGoverningTsconfigDir, getDirectoryMarkers, } from "../workspace-topology.js";
5
- const cache = new Map();
6
- const referencesCache = new Map();
6
+ const cache = new BoundedLruCache(64);
7
+ const referencesCache = new BoundedLruCache(64);
7
8
  /** Strip JSONC comments and trailing commas without touching string contents. */
8
9
  function parseJsonc(content) {
9
10
  let output = "";
@@ -44,6 +45,50 @@ function parseJsonc(content) {
44
45
  }
45
46
  return JSON.parse(output.replace(/,\s*([}\]])/g, "$1"));
46
47
  }
48
+ function configSignature(configPath) {
49
+ try {
50
+ const stat = fs.statSync(configPath);
51
+ return `${stat.mtimeMs}:${stat.size}`;
52
+ }
53
+ catch {
54
+ return "missing";
55
+ }
56
+ }
57
+ function configDependencyPaths(configPath) {
58
+ const paths = new Set();
59
+ const visit = (currentPath) => {
60
+ const normalized = path.resolve(currentPath);
61
+ if (paths.has(normalized))
62
+ return;
63
+ paths.add(normalized);
64
+ let json;
65
+ try {
66
+ json = parseJsonc(fs.readFileSync(normalized, "utf8"));
67
+ }
68
+ catch {
69
+ return;
70
+ }
71
+ if (typeof json.extends === "string") {
72
+ const parent = resolveExtends(normalized, json.extends);
73
+ if (parent)
74
+ visit(parent);
75
+ }
76
+ for (const reference of json.references ?? []) {
77
+ if (typeof reference?.path !== "string")
78
+ continue;
79
+ const referenced = resolveReferenceConfig(normalized, reference.path);
80
+ if (referenced)
81
+ visit(referenced);
82
+ }
83
+ };
84
+ visit(configPath);
85
+ return [...paths].sort((a, b) => a.localeCompare(b));
86
+ }
87
+ function dependencySignature(configPath) {
88
+ return configDependencyPaths(configPath)
89
+ .map((dependency) => `${dependency}:${configSignature(dependency)}`)
90
+ .join("|");
91
+ }
47
92
  function resolveExtends(configPath, value) {
48
93
  if (!value.startsWith("."))
49
94
  return undefined;
@@ -180,14 +225,17 @@ function collectReferencedProjects(configPath, result, visited) {
180
225
  }
181
226
  /** Find and parse the nearest governing tsconfig, cached per importer directory. */
182
227
  export function parseTsconfigPaths(cwd, homeDir = os.homedir()) {
183
- const key = path.resolve(cwd);
228
+ const normalizedCwd = path.resolve(cwd);
229
+ const configDir = findGoverningTsconfigDir(normalizedCwd, homeDir);
230
+ const configPath = configDir ? path.join(configDir, "tsconfig.json") : "";
231
+ const signature = configPath ? dependencySignature(configPath) : "missing";
232
+ const key = `${normalizedCwd}|${configPath}|${signature}`;
184
233
  const cached = cache.get(key);
185
234
  if (cached)
186
235
  return cached;
187
236
  // Home-guarding is enforced inside findGoverningTsconfigDir's walk itself
188
237
  // (via workspace-topology's shared isAtOrAboveHomeDir ceiling), so a hit
189
238
  // here is never at/above homeDir.
190
- const configDir = findGoverningTsconfigDir(key, homeDir);
191
239
  if (!configDir) {
192
240
  cache.set(key, []);
193
241
  return [];
@@ -224,11 +272,14 @@ export function aliasedImportTargets(specifier, importerDir) {
224
272
  }
225
273
  /** Resolve an exact package-name import through the governing config's project references. */
226
274
  export function referencedProjectImportTarget(specifier, importerDir) {
227
- const key = path.resolve(importerDir);
275
+ const normalizedImporterDir = path.resolve(importerDir);
276
+ const governingDir = findGoverningTsconfigDir(normalizedImporterDir);
277
+ const governingPath = governingDir ? path.join(governingDir, "tsconfig.json") : "";
278
+ const key = `${normalizedImporterDir}|${governingPath}|${governingPath ? dependencySignature(governingPath) : "missing"}`;
228
279
  let projects = referencesCache.get(key);
229
280
  if (!projects) {
230
281
  projects = new Map();
231
- const configDir = findGoverningTsconfigDir(key);
282
+ const configDir = governingDir;
232
283
  if (configDir) {
233
284
  collectReferencedProjects(path.join(configDir, "tsconfig.json"), projects, new Set());
234
285
  }
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import * as fs from "node:fs";
8
8
  import * as path from "node:path";
9
- import { getProjectIgnoreMatcher, isExcludedDirName } from "../file-utils.js";
9
+ import { getProjectIgnoreMatcher, isExcludedDirName, } from "../file-utils.js";
10
10
  import { normalizeMapKey } from "../path-utils.js";
11
11
  import { getWorkspaceManifestMarkers } from "../workspace-topology.js";
12
12
  // Cap on candidate sub-directories probed per workspace glob level (#262).
@@ -387,6 +387,7 @@ export function buildModuleGraph(cwd) {
387
387
  }
388
388
  export function clearModuleGraphCache() {
389
389
  _moduleGraphCache = null;
390
+ _moduleSourceFilesMemo.clear();
390
391
  }
391
392
  /**
392
393
  * Find the module that owns a given file path.
@@ -419,13 +420,40 @@ export function getDownstreamModules(graph, moduleName) {
419
420
  }
420
421
  return [...downstream];
421
422
  }
423
+ const _moduleSourceFilesMemo = new Map();
424
+ const MTIME_GRANULARITY_GUARD_MS = 2_000;
425
+ function isMemoEntryFresh(entry) {
426
+ const validatedAt = Date.now();
427
+ for (const { dir, mtimeMs, stampedAt } of entry.dirs) {
428
+ if (validatedAt - stampedAt < MTIME_GRANULARITY_GUARD_MS)
429
+ return false;
430
+ try {
431
+ if (fs.statSync(dir).mtimeMs !== mtimeMs)
432
+ return false;
433
+ }
434
+ catch {
435
+ return false;
436
+ }
437
+ }
438
+ return true;
439
+ }
422
440
  /**
423
- * Get representative source files in a module.
441
+ * Get representative source files in a module. Memoized per module root (see
442
+ * above) — the returned array is a copy; mutating it does not affect the memo.
424
443
  */
425
444
  export function getModuleSourceFiles(moduleRoot, maxFiles = 20) {
426
- const files = [];
427
445
  const root = normalizeMapKey(moduleRoot);
428
446
  const ignoreMatcher = getProjectIgnoreMatcher(root);
447
+ const cached = _moduleSourceFilesMemo.get(root);
448
+ if (cached &&
449
+ cached.maxFiles === maxFiles &&
450
+ cached.matcher === ignoreMatcher &&
451
+ isMemoEntryFresh(cached)) {
452
+ return [...cached.files];
453
+ }
454
+ const files = [];
455
+ const dirs = [];
456
+ let allDirsStamped = true;
429
457
  const visit = (dir, depth) => {
430
458
  if (files.length >= maxFiles || depth > 4)
431
459
  return;
@@ -436,6 +464,18 @@ export function getModuleSourceFiles(moduleRoot, maxFiles = 20) {
436
464
  catch {
437
465
  return;
438
466
  }
467
+ // Stamp AFTER the readdir: a change landing between readdir and stat
468
+ // records the newer mtime, so validation re-walks (fail-safe direction).
469
+ try {
470
+ dirs.push({
471
+ dir,
472
+ mtimeMs: fs.statSync(dir).mtimeMs,
473
+ stampedAt: Date.now(),
474
+ });
475
+ }
476
+ catch {
477
+ allDirsStamped = false;
478
+ }
439
479
  entries.sort((a, b) => a.name.localeCompare(b.name));
440
480
  for (const entry of entries) {
441
481
  if (files.length >= maxFiles)
@@ -458,5 +498,13 @@ export function getModuleSourceFiles(moduleRoot, maxFiles = 20) {
458
498
  }
459
499
  };
460
500
  visit(root, 0);
501
+ if (allDirsStamped) {
502
+ _moduleSourceFilesMemo.set(root, {
503
+ files: [...files],
504
+ maxFiles,
505
+ dirs,
506
+ matcher: ignoreMatcher,
507
+ });
508
+ }
461
509
  return files;
462
510
  }
@@ -5,11 +5,40 @@ import { createNdjsonLogger } from "./ndjson-logger.js";
5
5
  const REVIEW_GRAPH_LOG_DIR = getGlobalPiLensDir();
6
6
  const REVIEW_GRAPH_LOG_FILE = path.join(REVIEW_GRAPH_LOG_DIR, "review-graph.log");
7
7
  const writer = createNdjsonLogger({ filePath: REVIEW_GRAPH_LOG_FILE });
8
+ /**
9
+ * Build the one canonical graph metadata shape used by build and persist logs.
10
+ * Counts come from the graph instance; source-file count may use the exact
11
+ * signature-map count when the build has one, otherwise the graph file index.
12
+ */
13
+ export function makeReviewGraphBuildMetadata(graph, options = {}) {
14
+ return {
15
+ ...(options.buildId === undefined ? {} : { buildId: options.buildId }),
16
+ ...(graph.buildGeneration === undefined
17
+ ? {}
18
+ : { graphGeneration: graph.buildGeneration }),
19
+ builtAt: graph.builtAt,
20
+ ...(options.projectSeq === undefined
21
+ ? {}
22
+ : { projectSeq: options.projectSeq }),
23
+ ...(options.seqHint === undefined ? {} : { seqHint: options.seqHint }),
24
+ ...(options.mode === undefined ? {} : { mode: options.mode }),
25
+ sourceFiles: options.sourceFileCount ?? graph.fileNodes.size,
26
+ ...(options.sourceFileCountTruncated ||
27
+ graph.persistCoverage?.sourceFilesTruncated
28
+ ? { sourceFilesTruncated: true }
29
+ : {}),
30
+ nodes: graph.nodes.size,
31
+ edges: graph.edges.length,
32
+ ...(graph.persistCoverage
33
+ ? { persistCoverage: graph.persistCoverage }
34
+ : {}),
35
+ };
36
+ }
8
37
  export function logReviewGraph(entry) {
9
38
  if (isTestMode()) {
10
39
  return;
11
40
  }
12
- writer.log({ ts: new Date().toISOString(), ...entry });
41
+ writer.log({ ts: new Date().toISOString(), ...entry, pid: process.pid });
13
42
  }
14
43
  export function getReviewGraphLogPath() {
15
44
  return REVIEW_GRAPH_LOG_FILE;
@@ -7,62 +7,36 @@
7
7
  * Requires: pip install ruff
8
8
  * Docs: https://docs.astral.sh/ruff/
9
9
  */
10
+ import { createSubsystemLogger } from "./extension-log.js";
10
11
  import * as fs from "node:fs";
11
12
  import * as path from "node:path";
13
+ import { createAvailabilityChecker, resolveAvailableOrInstall } from "./dispatch/runners/utils/runner-helpers.js";
12
14
  import { isFileKind } from "./file-kinds.js";
13
15
  import { safeSpawnAsync } from "./safe-spawn.js";
16
+ import { ruffConfigArgs } from "./tool-policy.js";
14
17
  // --- Client ---
18
+ const ruffAvailability = createAvailabilityChecker("ruff", ".exe");
15
19
  export class RuffClient {
16
- ruffAvailable = null;
17
- ensureInFlight = null;
20
+ ruffCommand = "ruff";
18
21
  log;
19
22
  constructor(verbose = false) {
20
23
  this.log = verbose
21
- ? (msg) => console.error(`[ruff] ${msg}`)
24
+ ? createSubsystemLogger("ruff")
22
25
  : () => { };
23
26
  }
24
27
  /**
25
28
  * Check if ruff CLI is available, auto-install if not.
26
29
  *
27
- * Re-entrancy safe: concurrent first-time callers share a single
28
- * `ensureInFlight` promise so probing/auto-install isn't duplicated.
29
- * Mirrors the dedupe pattern in `SgRunner` / `KnipClient` /
30
- * `DependencyChecker`.
30
+ * Re-entrancy safe: the shared availability seam deduplicates the complete
31
+ * probe/auto-install transaction per cwd and tool, so concurrent callers do
32
+ * not duplicate installation attempts.
31
33
  */
32
34
  async ensureAvailable() {
33
- if (this.ruffAvailable !== null)
34
- return this.ruffAvailable;
35
- if (this.ensureInFlight)
36
- return this.ensureInFlight;
37
- this.ensureInFlight = this.doEnsureAvailable();
38
- try {
39
- return await this.ensureInFlight;
40
- }
41
- finally {
42
- this.ensureInFlight = null;
43
- }
44
- }
45
- async doEnsureAvailable() {
46
- // Check if available in PATH
47
- const result = await safeSpawnAsync("ruff", ["--version"], {
48
- timeout: 5000,
49
- });
50
- this.ruffAvailable = !result.error && result.status === 0;
51
- if (this.ruffAvailable) {
52
- this.log(`Ruff found: ${result.stdout.trim()}`);
53
- return true;
54
- }
55
- // Auto-install via pi-lens installer
56
- this.log("Ruff not found, attempting auto-install...");
57
- const { ensureTool } = await import("./installer/index.js");
58
- const installedPath = await ensureTool("ruff");
59
- if (installedPath) {
60
- this.log(`Ruff auto-installed: ${installedPath}`);
61
- this.ruffAvailable = true;
62
- return true;
63
- }
64
- this.log("Ruff auto-install failed");
65
- return false;
35
+ const resolved = await resolveAvailableOrInstall(ruffAvailability, "ruff", process.cwd());
36
+ if (!resolved)
37
+ return false;
38
+ this.ruffCommand = resolved;
39
+ return true;
66
40
  }
67
41
  /**
68
42
  * Check if a file is a Python file
@@ -72,8 +46,10 @@ export class RuffClient {
72
46
  }
73
47
  /**
74
48
  * Async auto-fix variant for pipeline use (non-blocking spawn).
49
+ * `cwd` is the dispatch language root (used for config discovery); when
50
+ * omitted it defaults to the file's directory.
75
51
  */
76
- async fixFileAsync(filePath) {
52
+ async fixFileAsync(filePath, cwd) {
77
53
  if (!(await this.ensureAvailable())) {
78
54
  return {
79
55
  success: false,
@@ -93,19 +69,26 @@ export class RuffClient {
93
69
  }
94
70
  try {
95
71
  const before = await fs.promises.readFile(absolutePath, "utf-8");
96
- const pre = await safeSpawnAsync("ruff", [
72
+ // Shared config-args seam (#1247): the lint runner consumes the same
73
+ // builder, so `check --fix` can never drift to ruff's default rule
74
+ // set when the project lacks its own config and the package-owned
75
+ // core.toml fallback applies.
76
+ const configArgs = ruffConfigArgs(cwd ?? path.dirname(absolutePath));
77
+ const spawnOpts = { timeout: 10000, cwd: cwd ?? path.dirname(absolutePath) };
78
+ const pre = await safeSpawnAsync(this.ruffCommand, [
97
79
  "check",
98
80
  "--output-format",
99
81
  "json",
100
82
  "--target-version",
101
83
  "py310",
84
+ ...configArgs,
102
85
  absolutePath,
103
- ], { timeout: 10000 });
86
+ ], spawnOpts);
104
87
  const beforeDiags = pre.stdout?.trim()
105
88
  ? this.parseOutput(pre.stdout, absolutePath)
106
89
  : [];
107
90
  const fixableCount = beforeDiags.filter((d) => d.fixable).length;
108
- const fix = await safeSpawnAsync("ruff", ["check", "--fix", absolutePath], { timeout: 15000 });
91
+ const fix = await safeSpawnAsync(this.ruffCommand, ["check", "--fix", ...configArgs, absolutePath], { timeout: 15000, cwd: cwd ?? path.dirname(absolutePath) });
109
92
  if (fix.error) {
110
93
  return {
111
94
  success: false,