@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.
- package/README.md +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +32 -24
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/pi-lens/CHANGELOG.md +2535 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
- package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
- package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
- package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
- package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +51785 -36118
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +219 -46
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +40 -15
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +45 -3
- package/node_modules/pi-lens/docs/globalconfig.md +56 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +18 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +41 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
- package/node_modules/pi-mcp-adapter/README.md +38 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/cli.js +25 -4
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/config.ts +4 -4
- package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +4 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +176 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/node_modules/pi-web-access/CHANGELOG.md +14 -0
- package/node_modules/pi-web-access/README.md +18 -12
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +106 -34
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +18 -4
- package/node_modules/pi-web-access/index.ts +120 -48
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/summary-review.ts +11 -5
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +12 -13
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -15,10 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import * as nodeFs from "node:fs";
|
|
17
17
|
import * as path from "node:path";
|
|
18
|
+
import { isReadableSourceFile } from "./file-kinds.js";
|
|
18
19
|
import { countFileLines } from "./read-guard-tool-lines.js";
|
|
19
|
-
// Source-ish extensions worth registering. Anchored end-check → linear (no
|
|
20
|
-
// catastrophic backtracking).
|
|
21
|
-
const READABLE_EXT_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|py|sh|rs|go|cs|java|kt|rb|php|c|cpp|cc|h|hpp|json|jsonc|yaml|yml|toml|md|txt|env|cfg|conf|ini|html|css|scss|less|xml|sql|vue|svelte)$/i;
|
|
22
20
|
function stripQuotes(token) {
|
|
23
21
|
if (token.length >= 2) {
|
|
24
22
|
const first = token[0];
|
|
@@ -32,14 +30,123 @@ function stripQuotes(token) {
|
|
|
32
30
|
function stripAnsi(value) {
|
|
33
31
|
return value.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
34
32
|
}
|
|
35
|
-
function
|
|
36
|
-
const
|
|
37
|
-
|
|
33
|
+
export function tokenizeShellCommand(command) {
|
|
34
|
+
const segments = [];
|
|
35
|
+
let tokens = [];
|
|
36
|
+
let word = "";
|
|
37
|
+
let quote;
|
|
38
|
+
let escaped = false;
|
|
39
|
+
let unsupported = false;
|
|
40
|
+
let atTokenStart = true;
|
|
41
|
+
const flushWord = () => {
|
|
42
|
+
if (word)
|
|
43
|
+
tokens.push(word);
|
|
44
|
+
word = "";
|
|
45
|
+
atTokenStart = true;
|
|
46
|
+
};
|
|
47
|
+
const flushSegment = () => {
|
|
48
|
+
flushWord();
|
|
49
|
+
if (tokens.length > 0 || unsupported)
|
|
50
|
+
segments.push({ tokens, unsupported });
|
|
51
|
+
tokens = [];
|
|
52
|
+
unsupported = false;
|
|
53
|
+
atTokenStart = true;
|
|
54
|
+
};
|
|
55
|
+
for (let i = 0; i < command.length; i++) {
|
|
56
|
+
const ch = command[i];
|
|
57
|
+
const next = command[i + 1];
|
|
58
|
+
if (quote === "single") {
|
|
59
|
+
if (ch === "'")
|
|
60
|
+
quote = undefined;
|
|
61
|
+
else
|
|
62
|
+
word += ch;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (quote === "double") {
|
|
66
|
+
if (escaped) {
|
|
67
|
+
word += ch;
|
|
68
|
+
escaped = false;
|
|
69
|
+
}
|
|
70
|
+
else if (ch === "\\")
|
|
71
|
+
escaped = true;
|
|
72
|
+
else if (ch === '"')
|
|
73
|
+
quote = undefined;
|
|
74
|
+
else
|
|
75
|
+
word += ch;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (escaped) {
|
|
79
|
+
// A backslash-newline is a shell line continuation, not part of the
|
|
80
|
+
// command argument. Keeping the newline here makes a continued git command
|
|
81
|
+
// visible to command guards.
|
|
82
|
+
if (ch !== "\n")
|
|
83
|
+
word += ch;
|
|
84
|
+
escaped = false;
|
|
85
|
+
atTokenStart = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (ch === "\\") {
|
|
89
|
+
// Bash uses backslash as a general escape, but command inputs on
|
|
90
|
+
// Windows routinely contain native paths (C:\\src\\file.ts). Preserve
|
|
91
|
+
// backslashes before ordinary path characters while still honoring
|
|
92
|
+
// shell escapes and line continuations.
|
|
93
|
+
if (next === "\n" || /[\s\\'\";$|&<>]/.test(next ?? "")) {
|
|
94
|
+
escaped = true;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
word += ch;
|
|
98
|
+
atTokenStart = false;
|
|
99
|
+
}
|
|
100
|
+
atTokenStart = false;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (ch === "'") {
|
|
104
|
+
quote = "single";
|
|
105
|
+
atTokenStart = false;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (ch === '"') {
|
|
109
|
+
quote = "double";
|
|
110
|
+
atTokenStart = false;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (ch === "#" && atTokenStart) {
|
|
114
|
+
while (i + 1 < command.length && command[i + 1] !== "\n")
|
|
115
|
+
i++;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (/\s/.test(ch)) {
|
|
119
|
+
flushWord();
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (ch === ";" || ch === "\n" || ch === "|" || ch === "&") {
|
|
123
|
+
flushWord();
|
|
124
|
+
if (ch === "|" && next === "|")
|
|
125
|
+
i++;
|
|
126
|
+
else if (ch === "&" && next === "&")
|
|
127
|
+
i++;
|
|
128
|
+
else if (ch === "|" || ch === "&")
|
|
129
|
+
unsupported = true;
|
|
130
|
+
flushSegment();
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (ch === "<" || ch === ">") {
|
|
134
|
+
flushWord();
|
|
135
|
+
unsupported = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
word += ch;
|
|
139
|
+
atTokenStart = false;
|
|
140
|
+
}
|
|
141
|
+
if (quote || escaped)
|
|
142
|
+
unsupported = true;
|
|
143
|
+
flushSegment();
|
|
144
|
+
return segments;
|
|
38
145
|
}
|
|
39
146
|
/** Resolve a token to an absolute path if it looks like a source file. */
|
|
40
147
|
function resolveCandidate(token, cwd) {
|
|
41
148
|
const cleaned = stripQuotes(token);
|
|
42
|
-
if (!cleaned || cleaned.startsWith("-") || !
|
|
149
|
+
if (!cleaned || cleaned.startsWith("-") || !isReadableSourceFile(cleaned)) {
|
|
43
150
|
return null;
|
|
44
151
|
}
|
|
45
152
|
return path.isAbsolute(cleaned) ? cleaned : path.resolve(cwd, cleaned);
|
|
@@ -52,8 +159,67 @@ function parseCountFlag(token) {
|
|
|
52
159
|
const n = Number.parseInt(digits, 10);
|
|
53
160
|
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
54
161
|
}
|
|
55
|
-
function
|
|
56
|
-
return command.
|
|
162
|
+
function commandSegments(command) {
|
|
163
|
+
return tokenizeShellCommand(command).map((segment) => segment.tokens);
|
|
164
|
+
}
|
|
165
|
+
/** Find redirect targets without treating quoted `>` characters as syntax. */
|
|
166
|
+
function extractRedirectTargets(command) {
|
|
167
|
+
const targets = [];
|
|
168
|
+
let quote;
|
|
169
|
+
let escaped = false;
|
|
170
|
+
for (let i = 0; i < command.length; i += 1) {
|
|
171
|
+
const ch = command[i];
|
|
172
|
+
if (quote === "single") {
|
|
173
|
+
if (ch === "'")
|
|
174
|
+
quote = undefined;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (quote === "double") {
|
|
178
|
+
if (escaped)
|
|
179
|
+
escaped = false;
|
|
180
|
+
else if (ch === "\\")
|
|
181
|
+
escaped = true;
|
|
182
|
+
else if (ch === '"')
|
|
183
|
+
quote = undefined;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (escaped) {
|
|
187
|
+
escaped = false;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (ch === "\\") {
|
|
191
|
+
escaped = true;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (ch === "'") {
|
|
195
|
+
quote = "single";
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (ch === '"') {
|
|
199
|
+
quote = "double";
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (ch !== ">")
|
|
203
|
+
continue;
|
|
204
|
+
while (i + 1 < command.length && /\s/.test(command[i + 1]))
|
|
205
|
+
i += 1;
|
|
206
|
+
if (command[i + 1] === ">")
|
|
207
|
+
i += 1;
|
|
208
|
+
while (i + 1 < command.length && /\s/.test(command[i + 1]))
|
|
209
|
+
i += 1;
|
|
210
|
+
let target = "";
|
|
211
|
+
for (i += 1; i < command.length; i += 1) {
|
|
212
|
+
const next = command[i];
|
|
213
|
+
if (/\s/.test(next) || next === ";" || next === "|" || next === "&") {
|
|
214
|
+
i -= 1;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
target += next;
|
|
218
|
+
}
|
|
219
|
+
if (target)
|
|
220
|
+
targets.push(target);
|
|
221
|
+
}
|
|
222
|
+
return targets;
|
|
57
223
|
}
|
|
58
224
|
/**
|
|
59
225
|
* Extract the line ranges a bash command explicitly showed the agent.
|
|
@@ -93,11 +259,9 @@ export function extractReadPathsFromCommand(command, cwd) {
|
|
|
93
259
|
seen.add(key);
|
|
94
260
|
spans.push({ filePath: file.abs, offset, limit });
|
|
95
261
|
};
|
|
96
|
-
for (const
|
|
97
|
-
|
|
98
|
-
if (!segment)
|
|
262
|
+
for (const tokens of commandSegments(command)) {
|
|
263
|
+
if (tokens.length === 0)
|
|
99
264
|
continue;
|
|
100
|
-
const tokens = segment.split(/\s+/);
|
|
101
265
|
const verb = path.basename(tokens[0] ?? "");
|
|
102
266
|
const args = tokens.slice(1);
|
|
103
267
|
if (["cat", "bat", "less", "more", "nl"].includes(verb)) {
|
|
@@ -247,8 +411,7 @@ function parseGrepLineWithoutFile(line, file) {
|
|
|
247
411
|
function collectGrepCommandFiles(command, cwd) {
|
|
248
412
|
const files = new Set();
|
|
249
413
|
let hasLineNumberGrep = false;
|
|
250
|
-
for (const
|
|
251
|
-
const tokens = tokenizeSegment(rawSegment.trim());
|
|
414
|
+
for (const tokens of commandSegments(command)) {
|
|
252
415
|
const verb = path.basename(stripQuotes(tokens[0] ?? ""));
|
|
253
416
|
if (verb !== "grep" && verb !== "egrep" && verb !== "fgrep")
|
|
254
417
|
continue;
|
|
@@ -311,15 +474,22 @@ export function extractWrittenPathsFromCommand(command, cwd) {
|
|
|
311
474
|
if (abs)
|
|
312
475
|
out.add(abs);
|
|
313
476
|
};
|
|
314
|
-
for (const
|
|
315
|
-
|
|
316
|
-
|
|
477
|
+
for (const tokens of commandSegments(command)) {
|
|
478
|
+
if (tokens.length === 0)
|
|
479
|
+
continue;
|
|
480
|
+
// Redirect targets are collected by a quote-aware scanner. The shared
|
|
481
|
+
// tokenizer supplies the normalized command arguments; it deliberately
|
|
482
|
+
// does not expose shell redirection operators as arguments.
|
|
483
|
+
for (const target of extractRedirectTargets(command))
|
|
484
|
+
add(target);
|
|
485
|
+
// A command may contain multiple segments; only the first pass should
|
|
486
|
+
// attach redirects, otherwise targets would be duplicated harmlessly but
|
|
487
|
+
// needlessly rescanned.
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
for (const tokens of commandSegments(command)) {
|
|
491
|
+
if (tokens.length === 0)
|
|
317
492
|
continue;
|
|
318
|
-
// Redirect targets: the token after `>` / `>>` (optionally prefixed by a
|
|
319
|
-
// file descriptor like `2>` or `&>`, with or without a space).
|
|
320
|
-
for (const m of segment.matchAll(/>>?\s*([^\s>|&]+)/g))
|
|
321
|
-
add(m[1]);
|
|
322
|
-
const tokens = segment.split(/\s+/);
|
|
323
493
|
const verb = path.basename(tokens[0] ?? "");
|
|
324
494
|
const args = tokens.slice(1);
|
|
325
495
|
if (verb === "tee" || verb === "touch") {
|
|
@@ -7,15 +7,38 @@
|
|
|
7
7
|
* Requires: npm install @biomejs/biome (or npx @biomejs/biome)
|
|
8
8
|
* Docs: https://biomejs.dev/
|
|
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";
|
|
12
13
|
import { isFileKind } from "./file-kinds.js";
|
|
13
14
|
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
14
15
|
import { findGlobalBinary } from "./package-manager.js";
|
|
15
16
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
17
|
+
import { biomeConfigArgs } from "./tool-policy.js";
|
|
18
|
+
import { resolveManagedToolClient, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
19
|
+
import { classifyProbeFailure, createAvailabilityLatch, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
|
|
16
20
|
// --- Client ---
|
|
21
|
+
const PROBE_TIMEOUT_MS = 10_000;
|
|
17
22
|
export class BiomeClient {
|
|
18
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Availability memo, backed by the shared transient-aware latch (#1476).
|
|
25
|
+
*
|
|
26
|
+
* Biome is the hot-path formatter: before this, ANY probe failure — a
|
|
27
|
+
* timeout included — collapsed to `{ outcome: "missing" }`, which both
|
|
28
|
+
* triggered an install and latched `false` for the life of the process. One
|
|
29
|
+
* slow first format then disabled formatting until restart.
|
|
30
|
+
*/
|
|
31
|
+
availabilityLatch = createAvailabilityLatch();
|
|
32
|
+
/** Cause of the last probe, read when the resolution comes back. */
|
|
33
|
+
lastProbeCause = null;
|
|
34
|
+
/**
|
|
35
|
+
* Measurements of the last failed probe, held until the latch decides how
|
|
36
|
+
* long the verdict lasts. The decision record is emitted after that, so it
|
|
37
|
+
* can carry `retryAfterMs` — a latch you can see is worth little if the
|
|
38
|
+
* retry schedule is not greppable beside it (#1474).
|
|
39
|
+
*/
|
|
40
|
+
lastProbeElapsedMs = 0;
|
|
41
|
+
lastProbeHostStallMs = 0;
|
|
19
42
|
// Per-cwd cache of the resolved biome binary. Keying by cwd matters in
|
|
20
43
|
// monorepos where different sub-packages each ship their own biome
|
|
21
44
|
// installation; sharing one slot across the whole client would cause
|
|
@@ -29,7 +52,7 @@ export class BiomeClient {
|
|
|
29
52
|
log;
|
|
30
53
|
constructor(verbose = false) {
|
|
31
54
|
this.log = verbose
|
|
32
|
-
? (
|
|
55
|
+
? createSubsystemLogger("biome")
|
|
33
56
|
: () => { };
|
|
34
57
|
}
|
|
35
58
|
/**
|
|
@@ -87,7 +110,7 @@ export class BiomeClient {
|
|
|
87
110
|
}
|
|
88
111
|
async spawnBiomeAsync(args, timeout = 15000, cwd) {
|
|
89
112
|
const { cmd, args: prefix } = await this.getBiomeBinary(cwd);
|
|
90
|
-
return safeSpawnAsync(cmd, [...prefix, ...args], { timeout });
|
|
113
|
+
return safeSpawnAsync(cmd, [...prefix, ...args], { timeout, cwd });
|
|
91
114
|
}
|
|
92
115
|
/**
|
|
93
116
|
* Ensure Biome is available, auto-installing if necessary.
|
|
@@ -97,10 +120,15 @@ export class BiomeClient {
|
|
|
97
120
|
* `ensureInFlight` promise so probing/auto-install isn't duplicated.
|
|
98
121
|
* Mirrors the dedupe pattern in `SgRunner` / `KnipClient` /
|
|
99
122
|
* `DependencyChecker`.
|
|
123
|
+
*
|
|
124
|
+
* The memo returns `null` when the last verdict was transient and its
|
|
125
|
+
* cooldown expired, which re-enters the probe: "biome is not installed" is a
|
|
126
|
+
* fact worth caching, "the probe timed out" is a moment worth retrying.
|
|
100
127
|
*/
|
|
101
128
|
async ensureAvailable() {
|
|
102
|
-
|
|
103
|
-
|
|
129
|
+
const memo = this.availabilityLatch.read();
|
|
130
|
+
if (memo !== null)
|
|
131
|
+
return memo;
|
|
104
132
|
if (this.ensureInFlight)
|
|
105
133
|
return this.ensureInFlight;
|
|
106
134
|
this.ensureInFlight = this.doEnsureAvailable();
|
|
@@ -111,27 +139,105 @@ export class BiomeClient {
|
|
|
111
139
|
this.ensureInFlight = null;
|
|
112
140
|
}
|
|
113
141
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Probe `biome --version` and classify the failure through the shared
|
|
144
|
+
* policy. Only a durable verdict (`missing` / `non-installable`) may reach
|
|
145
|
+
* the install branch of `resolveManagedToolClient`; a transient one returns
|
|
146
|
+
* as `transient`, which that seam passes straight back without installing.
|
|
147
|
+
*/
|
|
148
|
+
async probeBiome() {
|
|
149
|
+
// The probe budget is enforced by a HOST-side timer, so a stalled event
|
|
150
|
+
// loop expires it while the child is still healthy. Measure the stall
|
|
151
|
+
// that overlapped the window and let the classifier see it (#1467).
|
|
152
|
+
const sampler = startHostStallSampler();
|
|
153
|
+
const startedAt = Date.now();
|
|
154
|
+
let result;
|
|
155
|
+
let hostStallMs;
|
|
156
|
+
try {
|
|
157
|
+
result = await this.spawnBiomeAsync(["--version"], PROBE_TIMEOUT_MS);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
hostStallMs = sampler.stop();
|
|
161
|
+
}
|
|
162
|
+
const elapsedMs = Date.now() - startedAt;
|
|
117
163
|
if (!result.error && result.status === 0) {
|
|
118
|
-
this.
|
|
119
|
-
|
|
164
|
+
this.lastProbeCause = "ok";
|
|
165
|
+
logAvailabilityDecision({
|
|
166
|
+
tool: "biome",
|
|
167
|
+
verdict: "available",
|
|
168
|
+
outcome: "success",
|
|
169
|
+
cause: "ok",
|
|
170
|
+
elapsedMs,
|
|
171
|
+
latched: true,
|
|
172
|
+
hostStallMs,
|
|
173
|
+
budgetMs: PROBE_TIMEOUT_MS,
|
|
174
|
+
});
|
|
175
|
+
return { outcome: "success", value: true };
|
|
120
176
|
}
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
177
|
+
// `unclassifiedFailureOutcome: "missing"` preserves the pre-#1476
|
|
178
|
+
// meaning of a plain non-zero exit (npx reporting no biome package):
|
|
179
|
+
// still "missing", still installable. Only the timeout/abort arm changes.
|
|
180
|
+
const { outcome, cause } = classifyProbeFailure(result, {
|
|
181
|
+
hostStallMs,
|
|
182
|
+
unclassifiedFailureOutcome: "missing",
|
|
183
|
+
});
|
|
184
|
+
// `classifyProbeFailure` is typed over the full outcome union but never
|
|
185
|
+
// returns "success" for a failed probe; narrow it for the seam's type.
|
|
186
|
+
const failureOutcome = outcome === "success" ? "non-installable" : outcome;
|
|
187
|
+
this.lastProbeCause = cause;
|
|
188
|
+
this.lastProbeElapsedMs = elapsedMs;
|
|
189
|
+
this.lastProbeHostStallMs = hostStallMs;
|
|
190
|
+
// The record is emitted by `doEnsureAvailable`, once the latch has said how
|
|
191
|
+
// long this verdict holds.
|
|
192
|
+
return { outcome: failureOutcome };
|
|
193
|
+
}
|
|
194
|
+
async doEnsureAvailable() {
|
|
195
|
+
const resolved = await resolveManagedToolClient({
|
|
196
|
+
toolId: "biome",
|
|
197
|
+
cwd: process.cwd(),
|
|
198
|
+
probe: () => this.probeBiome(),
|
|
199
|
+
acceptInstalled: (installedPath) => {
|
|
200
|
+
this.autoInstalledBinaryPath = installedPath;
|
|
201
|
+
return true;
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
if (resolved.outcome === "success") {
|
|
205
|
+
this.availabilityLatch.noteAvailable();
|
|
206
|
+
// The probe itself logs a clean hit. This arm is the other way to
|
|
207
|
+
// succeed — the install repaired a durable miss — and it needs its own
|
|
208
|
+
// record, or "biome went missing and came back" reads as silence.
|
|
209
|
+
if (this.lastProbeCause !== null && this.lastProbeCause !== "ok") {
|
|
210
|
+
logAvailabilityDecision({
|
|
211
|
+
tool: "biome",
|
|
212
|
+
verdict: "available",
|
|
213
|
+
outcome: "success",
|
|
214
|
+
cause: "ok",
|
|
215
|
+
elapsedMs: this.lastProbeElapsedMs,
|
|
216
|
+
latched: true,
|
|
217
|
+
hostStallMs: this.lastProbeHostStallMs,
|
|
218
|
+
budgetMs: PROBE_TIMEOUT_MS,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
131
221
|
return true;
|
|
132
222
|
}
|
|
133
|
-
|
|
134
|
-
|
|
223
|
+
// A transient probe expires; a durable verdict is remembered for the
|
|
224
|
+
// session exactly as before.
|
|
225
|
+
const cause = this.lastProbeCause ?? "not-found";
|
|
226
|
+
const retryAfterMs = this.availabilityLatch.noteUnavailable(resolved.outcome, cause);
|
|
227
|
+
logAvailabilityDecision({
|
|
228
|
+
tool: "biome",
|
|
229
|
+
verdict: "unavailable",
|
|
230
|
+
outcome: resolved.outcome,
|
|
231
|
+
cause,
|
|
232
|
+
elapsedMs: this.lastProbeElapsedMs,
|
|
233
|
+
latched: resolved.outcome !== "transient",
|
|
234
|
+
hostStallMs: this.lastProbeHostStallMs,
|
|
235
|
+
...(retryAfterMs > 0 && { retryAfterMs }),
|
|
236
|
+
budgetMs: PROBE_TIMEOUT_MS,
|
|
237
|
+
});
|
|
238
|
+
if (resolved.outcome === "transient") {
|
|
239
|
+
this.log("biome availability probe timed out; will retry (not installing)");
|
|
240
|
+
}
|
|
135
241
|
return false;
|
|
136
242
|
}
|
|
137
243
|
/**
|
|
@@ -142,8 +248,10 @@ export class BiomeClient {
|
|
|
142
248
|
}
|
|
143
249
|
/**
|
|
144
250
|
* Async auto-fix variant for pipeline use (non-blocking spawn).
|
|
251
|
+
* `cwd` is the dispatch language root (used for config discovery); when
|
|
252
|
+
* omitted it defaults to the file's directory.
|
|
145
253
|
*/
|
|
146
|
-
async fixFileAsync(filePath) {
|
|
254
|
+
async fixFileAsync(filePath, cwd) {
|
|
147
255
|
if (!(await this.ensureAvailable())) {
|
|
148
256
|
return {
|
|
149
257
|
success: false,
|
|
@@ -163,7 +271,11 @@ export class BiomeClient {
|
|
|
163
271
|
}
|
|
164
272
|
try {
|
|
165
273
|
const before = await fs.promises.readFile(absolutePath, "utf-8");
|
|
166
|
-
const
|
|
274
|
+
const configCwd = cwd ?? path.dirname(absolutePath);
|
|
275
|
+
// Shared config-args seam (#1247): the lint runner consumes the same
|
|
276
|
+
// builder, so `lint --write` can never drift to biome's default
|
|
277
|
+
// config when a user config or the package fallback exists.
|
|
278
|
+
const result = await this.spawnBiomeAsync(["lint", "--write", ...biomeConfigArgs(configCwd), absolutePath], 15000, configCwd);
|
|
167
279
|
if (result.error) {
|
|
168
280
|
return {
|
|
169
281
|
success: false,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logExtension } from "./extension-log.js";
|
|
1
2
|
let bootstrapPromise = null;
|
|
2
3
|
/**
|
|
3
4
|
* A stand-in for an analysis client whose module failed to load (an unresolved
|
|
@@ -28,11 +29,19 @@ export function degradedClient() {
|
|
|
28
29
|
*/
|
|
29
30
|
async function logBootstrapFailures(failures) {
|
|
30
31
|
for (const { name, err } of failures) {
|
|
31
|
-
|
|
32
|
+
logExtension({
|
|
33
|
+
subsystem: "bootstrap",
|
|
34
|
+
message: `analyzer "${name}" disabled (degraded mode): ${err?.message ?? String(err)}`,
|
|
35
|
+
metadata: { analyzer: name },
|
|
36
|
+
});
|
|
32
37
|
}
|
|
33
38
|
try {
|
|
34
39
|
const { collectInstallDiagnostics, formatInstallDiagnostics } = await import("./install-diagnostics.js");
|
|
35
|
-
|
|
40
|
+
logExtension({
|
|
41
|
+
subsystem: "bootstrap",
|
|
42
|
+
message: formatInstallDiagnostics(collectInstallDiagnostics(), failures[0]?.err),
|
|
43
|
+
metadata: { kind: "install_diagnostics" },
|
|
44
|
+
});
|
|
36
45
|
}
|
|
37
46
|
catch {
|
|
38
47
|
// the per-analyzer lines above already named the failures
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Small insertion-ordered LRU used for process-lifetime memo tables. */
|
|
2
|
+
export class BoundedLruCache {
|
|
3
|
+
maxEntries;
|
|
4
|
+
entries = new Map();
|
|
5
|
+
constructor(maxEntries) {
|
|
6
|
+
this.maxEntries = maxEntries;
|
|
7
|
+
}
|
|
8
|
+
get(key) {
|
|
9
|
+
const value = this.entries.get(key);
|
|
10
|
+
if (value !== undefined) {
|
|
11
|
+
this.entries.delete(key);
|
|
12
|
+
this.entries.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
has(key) { return this.entries.has(key); }
|
|
17
|
+
set(key, value) {
|
|
18
|
+
this.entries.delete(key);
|
|
19
|
+
this.entries.set(key, value);
|
|
20
|
+
while (this.entries.size > this.maxEntries) {
|
|
21
|
+
const oldest = this.entries.keys().next().value;
|
|
22
|
+
if (oldest === undefined)
|
|
23
|
+
break;
|
|
24
|
+
this.entries.delete(oldest);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
delete(key) { return this.entries.delete(key); }
|
|
28
|
+
clear() { this.entries.clear(); }
|
|
29
|
+
get size() { return this.entries.size; }
|
|
30
|
+
keys() { return this.entries.keys(); }
|
|
31
|
+
values() { return this.entries.values(); }
|
|
32
|
+
entriesArray() { return [...this.entries.entries()]; }
|
|
33
|
+
[Symbol.iterator]() { return this.entries[Symbol.iterator](); }
|
|
34
|
+
}
|