@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
|
@@ -14,6 +14,7 @@ import { primaryServerId } from "../clients/lsp/config.js";
|
|
|
14
14
|
import { combineAbortSignals, withDeadline } from "../clients/deadline-utils.js";
|
|
15
15
|
import { applyAuxiliarySuppressions, retagAuxiliaryDiagnostics, } from "../clients/dispatch/auxiliary-lsp.js";
|
|
16
16
|
import { detectFileRole } from "../clients/file-role.js";
|
|
17
|
+
import { hashDiagnosticContent, touchCompletedConfirmationPolicy, touchCoverageGap, } from "../clients/lsp/diagnostic-binding.js";
|
|
17
18
|
import { classifyCascadeWaitTier } from "../clients/lsp/wait-policy/index.js";
|
|
18
19
|
import { attemptTsserverSyncDiagnostics, } from "../clients/lsp/tsserver-sync.js";
|
|
19
20
|
import { convertLspDiagnostics } from "../clients/dispatch/utils/lsp-diagnostics.js";
|
|
@@ -184,14 +185,30 @@ function projectIgnorePredicate(root) {
|
|
|
184
185
|
return () => false;
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
|
-
|
|
188
|
+
/**
|
|
189
|
+
* #1137: async so a directory read never blocks the event loop (and pi's TUI).
|
|
190
|
+
*
|
|
191
|
+
* This walk was fully synchronous with NO yielding of any kind, bounded only by
|
|
192
|
+
* `maxFiles` *kept* — an ignored-heavy or cloud-backed (OneDrive/network) tree
|
|
193
|
+
* could traverse unboundedly many entries, and a single stalled `readdirSync`
|
|
194
|
+
* held the loop for the whole stall. It is also called once PER LANGUAGE in
|
|
195
|
+
* `runDirectoryDiagnostics`'s `LANG_EXTENSIONS` loop, so a directory-mode
|
|
196
|
+
* `lsp_diagnostics` could pay that cost several times over.
|
|
197
|
+
*
|
|
198
|
+
* The traversal is deliberately still **depth-first with immediate descent**
|
|
199
|
+
* (not the shared stack-based `walkTreeStackAsync`): the `maxFiles` cap makes
|
|
200
|
+
* traversal ORDER observable — a stack walk would keep a different subset of
|
|
201
|
+
* files on an over-large tree. Only scheduling changes here; the returned list
|
|
202
|
+
* is identical. Awaiting each directory read is itself the yield point.
|
|
203
|
+
*/
|
|
204
|
+
async function collectFiles(dir, extensions, maxFiles, isIgnored = () => false) {
|
|
188
205
|
const files = [];
|
|
189
|
-
function walk(current) {
|
|
206
|
+
async function walk(current) {
|
|
190
207
|
if (files.length >= maxFiles)
|
|
191
208
|
return;
|
|
192
209
|
let entries;
|
|
193
210
|
try {
|
|
194
|
-
entries = fs.
|
|
211
|
+
entries = await fs.promises.readdir(current, { withFileTypes: true });
|
|
195
212
|
}
|
|
196
213
|
catch {
|
|
197
214
|
return;
|
|
@@ -204,7 +221,7 @@ function collectFiles(dir, extensions, maxFiles, isIgnored = () => false) {
|
|
|
204
221
|
const full = path.join(current, entry.name);
|
|
205
222
|
if (entry.isDirectory()) {
|
|
206
223
|
if (!isExcludedDirName(entry.name) && !isIgnored(full, true))
|
|
207
|
-
walk(full);
|
|
224
|
+
await walk(full);
|
|
208
225
|
}
|
|
209
226
|
else if (entry.isFile() && extensions.includes(path.extname(full))) {
|
|
210
227
|
if (isIgnored(full, false))
|
|
@@ -213,15 +230,15 @@ function collectFiles(dir, extensions, maxFiles, isIgnored = () => false) {
|
|
|
213
230
|
}
|
|
214
231
|
}
|
|
215
232
|
}
|
|
216
|
-
walk(dir);
|
|
233
|
+
await walk(dir);
|
|
217
234
|
return files;
|
|
218
235
|
}
|
|
219
236
|
export function createLspDiagnosticsTool(
|
|
220
|
-
// #571: same shared write-ordering token source `lens_diagnostics`
|
|
221
|
-
// uses (index.ts injects `() => runtime.nextWriteIndex()`)
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
237
|
+
// #571/#1198: same shared write-ordering token source `lens_diagnostics`
|
|
238
|
+
// mode=full uses (index.ts injects `() => runtime.nextWriteIndex()`). A
|
|
239
|
+
// confirmed result reconciled into the footer reserves its token when the
|
|
240
|
+
// per-file check starts, so settlement order cannot make an older result look
|
|
241
|
+
// newer. Optional/undefined in tests.
|
|
225
242
|
nextWriteIndex) {
|
|
226
243
|
return {
|
|
227
244
|
name: "lsp_diagnostics",
|
|
@@ -419,19 +436,14 @@ nextWriteIndex) {
|
|
|
419
436
|
async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope = "all") {
|
|
420
437
|
let timedOut = false;
|
|
421
438
|
let content;
|
|
422
|
-
//
|
|
423
|
-
//
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
// `serverScope: "primary"` never actually skipped the auxiliary scanners
|
|
431
|
-
// (getDiagnostics always queries every registered server for the file).
|
|
432
|
-
// `touched` is only undefined when touchFile itself couldn't produce a
|
|
433
|
-
// result (service destroyed, no clients resolved) — that's the one case
|
|
434
|
-
// that still needs the getDiagnostics() fallback below.
|
|
439
|
+
// `touchFile` is the authoritative collection boundary for every scope: it
|
|
440
|
+
// preserves per-touch timeout, content-binding, and silent-clean confirmation
|
|
441
|
+
// metadata while returning diagnostics from only the requested clients. The
|
|
442
|
+
// legacy openFile/getDiagnostics path remains only for an older/mock service
|
|
443
|
+
// without touchFile, or when touchFile cannot resolve any clients.
|
|
444
|
+
// #1179: the result is an explicit wrapper so side-channel fields survive
|
|
445
|
+
// array copies; confirmation was added when Marksman's lower-level clean verdict
|
|
446
|
+
// proved that a successful empty collection also needs explicit provenance.
|
|
435
447
|
let touched;
|
|
436
448
|
let usedTouch = false;
|
|
437
449
|
try {
|
|
@@ -447,12 +459,33 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
447
459
|
? attached.response.diagnostics.filter((item) => item.source === primaryServerId(absPath))
|
|
448
460
|
: attached.response.diagnostics;
|
|
449
461
|
const filtered = applyAuxiliarySuppressions(scopedDiagnostics, content, { fileRole: detectFileRole(absPath, content) });
|
|
450
|
-
return {
|
|
462
|
+
return {
|
|
463
|
+
diagnostics: filtered,
|
|
464
|
+
timedOut: false,
|
|
465
|
+
// #1253: the incumbent's touch carries the same confirmation
|
|
466
|
+
// provenance a local touch does (an `available: true` answer is
|
|
467
|
+
// already gated on `fresh && !inconclusive`, but that is NOT
|
|
468
|
+
// evidence a silent-on-clean server was confirmed — only the
|
|
469
|
+
// explicit flag is). The incumbent always touches with
|
|
470
|
+
// `clientScope: "with-auxiliary"`, so this is an AGGREGATE
|
|
471
|
+
// confirmation: it carries the same caveat all-scope local
|
|
472
|
+
// touches do, and classic TypeScript still needs the primary-only
|
|
473
|
+
// tsserver sync check below rather than this verdict.
|
|
474
|
+
// #1470: `"partial"` counts, for the same reason the local touch
|
|
475
|
+
// branch below accepts it — the incumbent's primary confirmed; only
|
|
476
|
+
// a named auxiliary did not.
|
|
477
|
+
confirmedByTouch: attached.response.confirmation !== undefined &&
|
|
478
|
+
primaryServerId(absPath) !== "typescript",
|
|
479
|
+
// #1470: the incumbent's narrowed verdict, carried as an explicit DTO
|
|
480
|
+
// field across the socket. An older incumbent omits it → empty → the
|
|
481
|
+
// pre-#1470 handling, unchanged.
|
|
482
|
+
unconfirmedServerIds: attached.response.unconfirmedServerIds ?? [],
|
|
483
|
+
content,
|
|
484
|
+
};
|
|
451
485
|
}
|
|
452
486
|
}
|
|
453
487
|
const serviceWithTouch = lspService;
|
|
454
|
-
if (
|
|
455
|
-
typeof serviceWithTouch.touchFile === "function") {
|
|
488
|
+
if (typeof serviceWithTouch.touchFile === "function") {
|
|
456
489
|
usedTouch = true;
|
|
457
490
|
touched = await serviceWithTouch.touchFile(absPath, content, {
|
|
458
491
|
diagnostics: "document",
|
|
@@ -480,7 +513,7 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
480
513
|
// serverScope:"primary" actually skip auxiliary scanners and drops the
|
|
481
514
|
// common case back to a single LSP round trip instead of two.
|
|
482
515
|
const diagnostics = usedTouch && touched !== undefined
|
|
483
|
-
? touched
|
|
516
|
+
? touched.diags
|
|
484
517
|
: await lspService.getDiagnostics(absPath, waitMs !== undefined ? "document" : "full");
|
|
485
518
|
// #586: honor each auxiliary profile's native inline-suppression comment
|
|
486
519
|
// (e.g. opengrep's `// nosemgrep`, #441) the same way the per-edit dispatch
|
|
@@ -496,7 +529,27 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
496
529
|
fileRole: detectFileRole(absPath, content),
|
|
497
530
|
})
|
|
498
531
|
: diagnostics;
|
|
499
|
-
|
|
532
|
+
// #1095: surface the touch's content binding (only the touch path carries
|
|
533
|
+
// one; the openFile-only / getDiagnostics fallback leaves it undefined →
|
|
534
|
+
// "unknown", no demotion).
|
|
535
|
+
const binding = usedTouch ? touched?.binding : undefined;
|
|
536
|
+
// #1470: `"partial"` counts here. `confirmedByTouch` feeds
|
|
537
|
+
// `canTrustTouchConfirmation`, which asks about the PRIMARY's own verdict —
|
|
538
|
+
// and a partial touch is one whose primary confirmed while an auxiliary was
|
|
539
|
+
// cut off. Excluding it would render "Primary LSP: unconfirmed" for a primary
|
|
540
|
+
// that did confirm. The coverage gap is carried separately, below.
|
|
541
|
+
const confirmedByTouch = usedTouch && touchCompletedConfirmationPolicy(touched);
|
|
542
|
+
return {
|
|
543
|
+
diagnostics: filtered,
|
|
544
|
+
timedOut,
|
|
545
|
+
confirmedByTouch,
|
|
546
|
+
// #1470: only a touch actually contributes a coverage gap; the
|
|
547
|
+
// openFile+getDiagnostics fallback never reports one, which is honest —
|
|
548
|
+
// that path claims no confirmation at all.
|
|
549
|
+
unconfirmedServerIds: usedTouch ? touchCoverageGap(touched) : [],
|
|
550
|
+
content,
|
|
551
|
+
binding,
|
|
552
|
+
};
|
|
500
553
|
}
|
|
501
554
|
function diagnosticsToFileDiags(file, diagnostics) {
|
|
502
555
|
return diagnostics.map((d) => ({
|
|
@@ -567,6 +620,17 @@ async function resolveEmptyResult(file, lspService) {
|
|
|
567
620
|
return { confirmed: true, diagnostics: [] };
|
|
568
621
|
}
|
|
569
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* A primary-scope touch is authoritative because `touchFile` runs that
|
|
625
|
+
* primary's own confirmation path (including TypeScript's sync fallback). For
|
|
626
|
+
* all-scope TypeScript touches, the aggregate silent-clean gate can settle
|
|
627
|
+
* without that primary-only sync request, so preserve `resolveEmptyResult`'s
|
|
628
|
+
* existing tsserver fallback instead of accepting the aggregate verdict.
|
|
629
|
+
*/
|
|
630
|
+
function canTrustTouchConfirmation(file, serverScope, confirmedByTouch) {
|
|
631
|
+
return (confirmedByTouch &&
|
|
632
|
+
(serverScope === "primary" || primaryServerId(file) !== "typescript"));
|
|
633
|
+
}
|
|
570
634
|
/**
|
|
571
635
|
* #571: reconcile this tool's fresh LSP result into the footer cache
|
|
572
636
|
* (`widget-state.ts`'s `allDiagnostics`) — same shared choke point
|
|
@@ -574,6 +638,11 @@ async function resolveEmptyResult(file, lspService) {
|
|
|
574
638
|
* `reconcileScanDiagnostics`). A manual `lsp_diagnostics` check that proves a
|
|
575
639
|
* stale footer error is actually gone (the real-world case that surfaced
|
|
576
640
|
* #571) is exactly the kind of confirmed result that should correct it.
|
|
641
|
+
* Direct `lsp_diagnostics` deliberately does not perform a second disk read at
|
|
642
|
+
* this reconciliation seam: its collecting touch already read the content and
|
|
643
|
+
* supplies the binding verdict. `false` is unconfirmed and is never written;
|
|
644
|
+
* `true` is trusted, while an absent/`unknown` verdict preserves the legacy
|
|
645
|
+
* fail-open policy for servers that cannot bind their diagnostics to content.
|
|
577
646
|
*
|
|
578
647
|
* `rawDiags` (pre-severity-filter) is what gets written — the footer records
|
|
579
648
|
* the true known state, independent of this call's display-only severity
|
|
@@ -592,8 +661,22 @@ async function resolveEmptyResult(file, lspService) {
|
|
|
592
661
|
* /skipTestFiles-filtered at write time — an empty string here is then a safe
|
|
593
662
|
* no-op re-check, not a behavior gap).
|
|
594
663
|
*/
|
|
595
|
-
function reconcileWidgetFromLspResult(file, rawDiags, confirmation,
|
|
596
|
-
|
|
664
|
+
function reconcileWidgetFromLspResult(file, rawDiags, confirmation, writeIndex, cwd, content,
|
|
665
|
+
// #1095: true when the result's content binding demonstrably mismatches disk
|
|
666
|
+
// (boundToCurrentDisk === false). Such a result — even a NON-EMPTY one, which
|
|
667
|
+
// the pre-#1095 "non-empty is definitionally confirmed" doctrine would have
|
|
668
|
+
// written straight through — must NOT re-cement the footer with a stale view
|
|
669
|
+
// (#1092's window-1 transcript: 17 live-looking diagnostics while tsc exits
|
|
670
|
+
// 0). "unknown"/true bindings leave the doctrine unchanged (fallback preserved
|
|
671
|
+
// for servers that never bind a version).
|
|
672
|
+
boundMismatch = false,
|
|
673
|
+
// #1093: when these `rawDiags` were actually OBSERVED. Fresh touches observe
|
|
674
|
+
// now (`undefined` → `Date.now()`); a cache HIT replays diagnostics scanned
|
|
675
|
+
// earlier, so its caller passes the cache entry's `scannedAt` here so the
|
|
676
|
+
// footer's `touchedAt` isn't re-armed to now() and the mtime-staleness gate
|
|
677
|
+
// stays live (the #1092 re-arming defect).
|
|
678
|
+
observedAt) {
|
|
679
|
+
const confirmed = (rawDiags.length > 0 || confirmation !== "unconfirmed") && !boundMismatch;
|
|
597
680
|
if (!confirmed)
|
|
598
681
|
return;
|
|
599
682
|
try {
|
|
@@ -603,7 +686,7 @@ function reconcileWidgetFromLspResult(file, rawDiags, confirmation, nextWriteInd
|
|
|
603
686
|
scanOrigin: "lsp_diagnostics",
|
|
604
687
|
});
|
|
605
688
|
const retagged = retagAuxiliaryDiagnostics(diagnostics, rawDiags, content ?? "", { cwd, fileRole: detectFileRole(file, content) });
|
|
606
|
-
reconcileScanDiagnostics(file, retagged, true,
|
|
689
|
+
reconcileScanDiagnostics(file, retagged, true, writeIndex, observedAt);
|
|
607
690
|
}
|
|
608
691
|
catch {
|
|
609
692
|
// Never let a footer-reconciliation hiccup fail the diagnostics check.
|
|
@@ -621,6 +704,10 @@ cacheCtx, scopeKey,
|
|
|
621
704
|
// `process.cwd()` for any call site that predates this (there are none
|
|
622
705
|
// today besides the two below, both of which now pass it explicitly).
|
|
623
706
|
cwd = process.cwd()) {
|
|
707
|
+
// Reserve the ordering token when this diagnostic operation starts, not when
|
|
708
|
+
// its LSP promise settles. A slower old result must not receive a newer token
|
|
709
|
+
// merely because it completed later (#1198).
|
|
710
|
+
const writeIndex = nextWriteIndex?.();
|
|
624
711
|
let stat;
|
|
625
712
|
try {
|
|
626
713
|
stat = fs.statSync(file);
|
|
@@ -633,14 +720,27 @@ cwd = process.cwd()) {
|
|
|
633
720
|
}
|
|
634
721
|
if (cacheCtx && scopeKey !== undefined) {
|
|
635
722
|
const cached = cacheCtx.lookup(file, scopeKey);
|
|
636
|
-
|
|
723
|
+
// #1095: a cached entry whose content binding demonstrably mismatches disk
|
|
724
|
+
// (bytes changed without the mtime bump the freshness gate would catch) is
|
|
725
|
+
// NOT served — fall through to a fresh touch instead of replaying a stale
|
|
726
|
+
// cached result. "unknown"/true bindings serve as before.
|
|
727
|
+
if (cached && cached.binding.boundToCurrentDisk !== false) {
|
|
637
728
|
const filteredDiags = applySeverityFilter(cached.diagnostics, severity);
|
|
638
729
|
const confirmation = cached.diagnostics.length === 0 ? "clean" : undefined;
|
|
639
730
|
// #692: cached.diagnostics were already suppression-/skipTestFiles-
|
|
640
731
|
// filtered at write time (this same code path); no file content was
|
|
641
732
|
// cached alongside them, so `undefined` here is a safe re-check, not
|
|
642
733
|
// a gap.
|
|
643
|
-
|
|
734
|
+
// #1093: this is a CACHE HIT — a replay of an OLD observation. Stamp the
|
|
735
|
+
// footer's `touchedAt` with the cache entry's original `scannedAt`, NOT
|
|
736
|
+
// now(), or a repeat check that only re-serves the cache would keep
|
|
737
|
+
// re-arming the mtime-staleness gate and a resolved finding would render
|
|
738
|
+
// forever (the #1092 defect).
|
|
739
|
+
reconcileWidgetFromLspResult(file, cached.diagnostics, confirmation, writeIndex, cwd, undefined,
|
|
740
|
+
// This branch only runs when the cache binding is not a mismatch
|
|
741
|
+
// (guarded above), so boundMismatch is false; #1093's observedAt is
|
|
742
|
+
// the cache entry's original scan time.
|
|
743
|
+
false, cached.scannedAt);
|
|
644
744
|
return {
|
|
645
745
|
file,
|
|
646
746
|
diagnostics: diagnosticsToFileDiags(file, filteredDiags),
|
|
@@ -649,7 +749,7 @@ cwd = process.cwd()) {
|
|
|
649
749
|
};
|
|
650
750
|
}
|
|
651
751
|
}
|
|
652
|
-
const { diagnostics: rawDiags, timedOut, content: collectedContent, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
752
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
653
753
|
const health = lspService.getDiagnosticsHealth?.(file);
|
|
654
754
|
// #570: a timed-out priming check is never a confirmed "clean" — treat it
|
|
655
755
|
// as unconfirmed without consulting the (unrelated) silent-tier
|
|
@@ -665,6 +765,11 @@ cwd = process.cwd()) {
|
|
|
665
765
|
confirmation = "unconfirmed";
|
|
666
766
|
}
|
|
667
767
|
}
|
|
768
|
+
else if (canTrustTouchConfirmation(file, serverScope, confirmedByTouch)) {
|
|
769
|
+
if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
770
|
+
confirmation = "clean";
|
|
771
|
+
}
|
|
772
|
+
}
|
|
668
773
|
else if (rawDiags.length === 0) {
|
|
669
774
|
const resolved = await resolveEmptyResult(file, lspService);
|
|
670
775
|
effectiveRawDiags = resolved.diagnostics;
|
|
@@ -677,16 +782,34 @@ cwd = process.cwd()) {
|
|
|
677
782
|
else if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
678
783
|
confirmation = await classifyEmptyResult(file, lspService);
|
|
679
784
|
}
|
|
785
|
+
// #1095: a result whose content binding demonstrably mismatches disk is
|
|
786
|
+
// demoted to "unconfirmed" — it must neither confirm the footer nor be cached
|
|
787
|
+
// as clean, regardless of how many diagnostics it carries (the #1092
|
|
788
|
+
// re-cementing path). "unknown"/true bindings leave the verdict untouched.
|
|
789
|
+
const boundMismatch = binding?.boundToCurrentDisk === false;
|
|
790
|
+
if (boundMismatch)
|
|
791
|
+
confirmation = "unconfirmed";
|
|
792
|
+
// #1470: an auxiliary cut off by the aux grace timer contributed no evidence
|
|
793
|
+
// about this file, so a "clean" verdict computed from the merged result would
|
|
794
|
+
// be claiming coverage this batch does not have. Demote it — that also keeps
|
|
795
|
+
// the entry out of the workspace cache below, which would otherwise replay the
|
|
796
|
+
// partial answer as a confirmed clean on every later sweep.
|
|
797
|
+
if (unconfirmedServerIds.length > 0 && confirmation === "clean") {
|
|
798
|
+
confirmation = "unconfirmed";
|
|
799
|
+
}
|
|
680
800
|
const filteredDiags = applySeverityFilter(effectiveRawDiags, severity);
|
|
681
|
-
reconcileWidgetFromLspResult(file, effectiveRawDiags, confirmation,
|
|
801
|
+
reconcileWidgetFromLspResult(file, effectiveRawDiags, confirmation, writeIndex, cwd, collectedContent, boundMismatch);
|
|
682
802
|
// #671: only a CONFIRMED outcome ("clean", or a non-empty result — either
|
|
683
803
|
// is definitionally confirmed per this function's own doctrine above) is
|
|
684
804
|
// safe to cache; "unconfirmed" (timeout OR a silent-tier server's
|
|
685
805
|
// unescapable empty push) must never be persisted as a cacheable clean
|
|
686
806
|
// result — same false-clean bug class `runWorkspaceDiagnostics`'s cache
|
|
687
|
-
// wiring guards against.
|
|
807
|
+
// wiring guards against. #1095: the entry carries the content fingerprint so a
|
|
808
|
+
// later lookup can verify it against disk beyond the mtime proxy.
|
|
688
809
|
if (cacheCtx && scopeKey !== undefined && confirmation !== "unconfirmed") {
|
|
689
|
-
cacheCtx.record(file, scopeKey, effectiveRawDiags, stat.mtimeMs
|
|
810
|
+
cacheCtx.record(file, scopeKey, effectiveRawDiags, stat.mtimeMs, collectedContent !== undefined
|
|
811
|
+
? hashDiagnosticContent(collectedContent)
|
|
812
|
+
: undefined);
|
|
690
813
|
}
|
|
691
814
|
return {
|
|
692
815
|
file,
|
|
@@ -698,7 +821,10 @@ cwd = process.cwd()) {
|
|
|
698
821
|
};
|
|
699
822
|
}
|
|
700
823
|
async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWriteIndex, serverScope = "all", cwd = process.cwd()) {
|
|
701
|
-
|
|
824
|
+
// Reserve the token before awaiting this file's LSP result. The direct-file
|
|
825
|
+
// path performs its own confirmation/reconciliation below (#1198).
|
|
826
|
+
const writeIndex = nextWriteIndex?.();
|
|
827
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
702
828
|
const lspHealth = lspService.getDiagnosticsHealth?.(absPath);
|
|
703
829
|
const unavailable = lspUnavailableMessage(absPath, lspHealth);
|
|
704
830
|
// #533: an empty result needs a confirmed/unconfirmed verdict — a push-only,
|
|
@@ -717,6 +843,11 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
717
843
|
confirmation = "unconfirmed";
|
|
718
844
|
}
|
|
719
845
|
}
|
|
846
|
+
else if (canTrustTouchConfirmation(absPath, serverScope, confirmedByTouch)) {
|
|
847
|
+
if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
848
|
+
confirmation = "clean";
|
|
849
|
+
}
|
|
850
|
+
}
|
|
720
851
|
else if (rawDiags.length === 0) {
|
|
721
852
|
const resolved = await resolveEmptyResult(absPath, lspService);
|
|
722
853
|
effectiveRawDiags = resolved.diagnostics;
|
|
@@ -729,12 +860,27 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
729
860
|
else if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
730
861
|
confirmation = await classifyEmptyResult(absPath, lspService);
|
|
731
862
|
}
|
|
863
|
+
// #1095: demote a result whose content binding mismatches disk to
|
|
864
|
+
// "unconfirmed" (the #1092 re-cementing path) — a non-empty stale result is no
|
|
865
|
+
// longer "definitionally confirmed". "unknown"/true bindings are unchanged.
|
|
866
|
+
const boundMismatch = binding?.boundToCurrentDisk === false;
|
|
867
|
+
if (boundMismatch)
|
|
868
|
+
confirmation = "unconfirmed";
|
|
869
|
+
// #1470: NARROWED, not collapsed. An auxiliary the aux grace timer cut off makes
|
|
870
|
+
// the FILE-level verdict unconfirmed — the merged result is missing whatever that
|
|
871
|
+
// scanner would have said, and this tool is the security lane's read surface. The
|
|
872
|
+
// PRIMARY's own verdict is untouched (`primaryCoverageGapOnly` below), so a
|
|
873
|
+
// TypeScript answer stays "confirmed clean" on its own line while an explicit
|
|
874
|
+
// line names the scanner whose coverage is absent.
|
|
875
|
+
const primaryCoverageGapOnly = unconfirmedServerIds.length > 0 && confirmation === "clean";
|
|
876
|
+
if (primaryCoverageGapOnly)
|
|
877
|
+
confirmation = "unconfirmed";
|
|
732
878
|
const filtered = applySeverityFilter(effectiveRawDiags, severity);
|
|
733
879
|
const total = filtered.length;
|
|
734
880
|
const truncated = total > MAX_DIAGNOSTICS;
|
|
735
881
|
const limited = truncated ? filtered.slice(0, MAX_DIAGNOSTICS) : filtered;
|
|
736
882
|
const unconfirmed = confirmation === "unconfirmed";
|
|
737
|
-
reconcileWidgetFromLspResult(absPath, effectiveRawDiags, confirmation,
|
|
883
|
+
reconcileWidgetFromLspResult(absPath, effectiveRawDiags, confirmation, writeIndex, cwd, collectedContent, boundMismatch);
|
|
738
884
|
const primaryId = primaryServerId(absPath);
|
|
739
885
|
const primaryDiags = limited.filter((d) => d.source === primaryId);
|
|
740
886
|
const auxiliaryDiags = limited.filter((d) => d.source !== primaryId);
|
|
@@ -747,7 +893,11 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
747
893
|
"file may still have errors that just hadn't been reported yet. " +
|
|
748
894
|
"Re-check after the server settles, or increase waitMs.");
|
|
749
895
|
}
|
|
750
|
-
|
|
896
|
+
// #1470: a file demoted ONLY because an auxiliary was cut off must not render
|
|
897
|
+
// the silent-on-clean text — the primary did confirm, and saying otherwise is
|
|
898
|
+
// the same overclaim in the opposite direction. The coverage line below names
|
|
899
|
+
// what is actually missing.
|
|
900
|
+
if (unconfirmed && !primaryCoverageGapOnly) {
|
|
751
901
|
return (`Primary LSP${primaryId ? ` (${primaryId})` : ""}: unconfirmed — ` +
|
|
752
902
|
"cannot confirm clean (push-only, silent-on-clean, e.g. classic " +
|
|
753
903
|
"typescript-language-server never publishes on a clean re-check). " +
|
|
@@ -759,9 +909,20 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
759
909
|
}
|
|
760
910
|
return `Primary LSP${primaryId ? ` (${primaryId})` : ""}: ${primaryDiags.length} diagnostic${primaryDiags.length === 1 ? "" : "s"}.`;
|
|
761
911
|
})();
|
|
912
|
+
// #1470: this is the narrowing made readable. It states exactly which servers
|
|
913
|
+
// this result does NOT speak for, so "no auxiliary findings" can never be read
|
|
914
|
+
// as "the security scanners found nothing".
|
|
915
|
+
const coverageLine = unconfirmedServerIds.length > 0
|
|
916
|
+
? `Auxiliary coverage INCOMPLETE — ${[...unconfirmedServerIds].join(", ")} did not answer within the wait budget, so ${unconfirmedServerIds.length === 1 ? "its findings are" : "their findings are"} NOT included here. This is not a clean bill of health for ${unconfirmedServerIds.length === 1 ? "that scanner" : "those scanners"}; re-check after the next edit, or use waitMs to wait longer.`
|
|
917
|
+
: undefined;
|
|
762
918
|
let text;
|
|
763
919
|
if (total === 0) {
|
|
764
|
-
text = [
|
|
920
|
+
text = [
|
|
921
|
+
primaryLine,
|
|
922
|
+
"",
|
|
923
|
+
unavailable ?? "No auxiliary findings.",
|
|
924
|
+
...(coverageLine ? [coverageLine] : []),
|
|
925
|
+
].join("\n");
|
|
765
926
|
}
|
|
766
927
|
else {
|
|
767
928
|
const lines = [primaryLine, ""];
|
|
@@ -772,6 +933,8 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
772
933
|
lines.push(`Auxiliary findings (${auxiliaryDiags.length}):`);
|
|
773
934
|
lines.push(...auxiliaryDiags.map(formatDiag));
|
|
774
935
|
}
|
|
936
|
+
if (coverageLine)
|
|
937
|
+
lines.push("", coverageLine);
|
|
775
938
|
if (unavailable)
|
|
776
939
|
lines.unshift(unavailable, "");
|
|
777
940
|
if (truncated) {
|
|
@@ -801,6 +964,11 @@ async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWri
|
|
|
801
964
|
truncated,
|
|
802
965
|
unconfirmed,
|
|
803
966
|
timedOut: unconfirmed ? timedOut : undefined,
|
|
967
|
+
// #1470: which servers this result does NOT speak for. Absent when it
|
|
968
|
+
// speaks for all of them.
|
|
969
|
+
...(unconfirmedServerIds.length > 0 && {
|
|
970
|
+
unconfirmedServerIds: [...unconfirmedServerIds],
|
|
971
|
+
}),
|
|
804
972
|
lspHealth,
|
|
805
973
|
waitMs,
|
|
806
974
|
},
|
|
@@ -1072,7 +1240,7 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1072
1240
|
let collectedFiles = [];
|
|
1073
1241
|
const isIgnored = projectIgnorePredicate(absPath);
|
|
1074
1242
|
for (const [ext, exts] of Object.entries(LANG_EXTENSIONS)) {
|
|
1075
|
-
collectedFiles = collectFiles(absPath, exts, MAX_FILES + 1, isIgnored);
|
|
1243
|
+
collectedFiles = await collectFiles(absPath, exts, MAX_FILES + 1, isIgnored);
|
|
1076
1244
|
if (collectedFiles.length > 0) {
|
|
1077
1245
|
extension = ext;
|
|
1078
1246
|
break;
|
|
@@ -8,6 +8,7 @@ import * as path from "node:path";
|
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
9
|
import { Type } from "../clients/deps/typebox.js";
|
|
10
10
|
import { logLatency } from "../clients/latency-logger.js";
|
|
11
|
+
import { newLspMutationCorrelationId, recordLspMutationOutcome, } from "../clients/lsp-mutation.js";
|
|
11
12
|
import { compactRenderResult } from "./render-compact.js";
|
|
12
13
|
import { applyWorkspaceEdit, summarizeWorkspaceEdit, } from "../clients/lsp/edits.js";
|
|
13
14
|
import { getLSPService } from "../clients/lsp/index.js";
|
|
@@ -550,7 +551,7 @@ export function createLspNavigationTool(
|
|
|
550
551
|
* constructed in; callers that only have a single fixed project root (e.g.
|
|
551
552
|
* pi's own `getLensFlag`) may ignore the second argument.
|
|
552
553
|
*/
|
|
553
|
-
getFlag) {
|
|
554
|
+
getFlag, mutationDeps) {
|
|
554
555
|
return {
|
|
555
556
|
name: "lsp_navigation",
|
|
556
557
|
label: "LSP Navigate",
|
|
@@ -675,7 +676,15 @@ getFlag) {
|
|
|
675
676
|
let supported = null;
|
|
676
677
|
let diagnosticsMode = "unknown";
|
|
677
678
|
let columnResolution;
|
|
679
|
+
let mutationContext;
|
|
680
|
+
let requestedApply = false;
|
|
678
681
|
const finalize = (payload, meta) => {
|
|
682
|
+
if (payload.isError &&
|
|
683
|
+
requestedApply &&
|
|
684
|
+
mutationContext &&
|
|
685
|
+
["rename", "rename_file", "executeCommand"].includes(meta.operation)) {
|
|
686
|
+
recordLspMutationOutcome(mutationContext, "failed");
|
|
687
|
+
}
|
|
679
688
|
const normalizedFilePath = meta.filePath.replace(/\\/g, "/");
|
|
680
689
|
logLatency({
|
|
681
690
|
type: "phase",
|
|
@@ -759,6 +768,21 @@ getFlag) {
|
|
|
759
768
|
});
|
|
760
769
|
}
|
|
761
770
|
const operation = normalizedOperation;
|
|
771
|
+
requestedApply = apply === true;
|
|
772
|
+
if (requestedApply &&
|
|
773
|
+
["rename", "rename_file", "executeCommand"].includes(operation)) {
|
|
774
|
+
const cwd = ctx.cwd || ".";
|
|
775
|
+
mutationContext = {
|
|
776
|
+
cwd,
|
|
777
|
+
correlationId: newLspMutationCorrelationId(_toolCallId),
|
|
778
|
+
tool: "lsp_navigation",
|
|
779
|
+
source: "lsp-edit",
|
|
780
|
+
...mutationDeps,
|
|
781
|
+
readGuard: getFlag("no-read-guard", cwd)
|
|
782
|
+
? undefined
|
|
783
|
+
: mutationDeps?.readGuard,
|
|
784
|
+
};
|
|
785
|
+
}
|
|
762
786
|
const isCallHierarchyTraversal = operation === "incomingCalls" || operation === "outgoingCalls";
|
|
763
787
|
const needsFilePath = operation !== "workspaceDiagnostics" &&
|
|
764
788
|
operation !== "workspaceSymbol" &&
|
|
@@ -1060,7 +1084,7 @@ getFlag) {
|
|
|
1060
1084
|
edit,
|
|
1061
1085
|
};
|
|
1062
1086
|
}
|
|
1063
|
-
const applied = await applyWorkspaceEdit(edit, ctx.cwd || ".");
|
|
1087
|
+
const applied = await applyWorkspaceEdit(edit, ctx.cwd || ".", { mutationContext });
|
|
1064
1088
|
for (const touchedFile of applied.files) {
|
|
1065
1089
|
try {
|
|
1066
1090
|
await openFileBestEffort(lspService, touchedFile, false);
|
|
@@ -1081,6 +1105,7 @@ getFlag) {
|
|
|
1081
1105
|
const result = await lspService.renameFile(filePath, resolvedNewFilePath, {
|
|
1082
1106
|
cwd: ctx.cwd || ".",
|
|
1083
1107
|
apply: apply ?? false,
|
|
1108
|
+
...(mutationContext ? { mutationContext } : {}),
|
|
1084
1109
|
});
|
|
1085
1110
|
if (result.applied) {
|
|
1086
1111
|
for (const touchedFile of result.files ?? []) {
|
|
@@ -1122,7 +1147,7 @@ getFlag) {
|
|
|
1122
1147
|
if (!isAdvertised) {
|
|
1123
1148
|
throw new Error(`__UNSUPPORTED__ command "${command}" is not advertised by the active LSP server (advertised: ${advertised.join(", ") || "none"})`);
|
|
1124
1149
|
}
|
|
1125
|
-
return lspService.executeCommand(rawPath ? filePath : undefined, command, commandArguments);
|
|
1150
|
+
return lspService.executeCommand(rawPath ? filePath : undefined, command, commandArguments, mutationContext);
|
|
1126
1151
|
}
|
|
1127
1152
|
case "incomingCalls": {
|
|
1128
1153
|
if (!callHierarchyItem) {
|
|
@@ -1177,6 +1202,24 @@ getFlag) {
|
|
|
1177
1202
|
}
|
|
1178
1203
|
}
|
|
1179
1204
|
}
|
|
1205
|
+
if (mutationContext &&
|
|
1206
|
+
requestedApply &&
|
|
1207
|
+
!mutationContext.summaryEmitted) {
|
|
1208
|
+
const outcome = operation === "rename_file" &&
|
|
1209
|
+
result &&
|
|
1210
|
+
typeof result === "object" &&
|
|
1211
|
+
"applied" in result &&
|
|
1212
|
+
result.applied === false
|
|
1213
|
+
? "failed"
|
|
1214
|
+
: operation === "executeCommand" &&
|
|
1215
|
+
result &&
|
|
1216
|
+
typeof result === "object" &&
|
|
1217
|
+
"executed" in result &&
|
|
1218
|
+
result.executed === false
|
|
1219
|
+
? "failed"
|
|
1220
|
+
: "skipped";
|
|
1221
|
+
recordLspMutationOutcome(mutationContext, outcome);
|
|
1222
|
+
}
|
|
1180
1223
|
}
|
|
1181
1224
|
catch (err) {
|
|
1182
1225
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -29,6 +29,7 @@ export function createModuleReportTool(getProjectRoot) {
|
|
|
29
29
|
description: "Structured, navigable overview of a source module — a token-efficient substitute for reading the whole file. Returns each symbol's name/kind/signature/line-range (plus a first-line `doc` summary when a doc comment is attached), important inline callbacks/closures/lambdas with stable handles, plus who-uses-this, risk flags, and ranked recommendedReads. To read a symbol's body: call read/read_symbol with offset=startLine, limit=endLine-startLine+1 on THIS report's `path` — those aren't repeated per symbol. Prefer this before a full read; then use read_symbol (or read) for the exact body you need.\n" +
|
|
30
30
|
"Single mode: language-uniform tree-sitter outline + review-graph who-uses-this + inline executable extraction; degrades to outline-only when no cached graph is available. `semantic.source` reports whether graph data was used.\n" +
|
|
31
31
|
'Pass `blastRadius: true` to also get the cross-file blast radius — the transitive dependents of this module aggregated to ranked file `read` args ("if you change this, verify these files"). Read-only over the cached graph; omitted on a cold cache. Supersedes the standalone impact query.\n' +
|
|
32
|
+
'Pass `callGraph: true` to include bounded derived callers/callees from the cached FunctionCallGraph; unavailable cache state is explicit and never reported as zero calls.\n' +
|
|
32
33
|
'`view: "compact"` returns a line-oriented text rendering (one line per symbol/callback, cheapest option) instead of JSON — same data, roughly a quarter of the token cost; use it for a quick skim. Default view returns JSON. An outline shows shape, not bodies — it does NOT count as having read a symbol\'s body for editing; use read_symbol for that.',
|
|
33
34
|
promptSnippet: "Navigable file outline — a cheap substitute for reading a whole file",
|
|
34
35
|
renderResult: compactRenderResult(({ details, args, isError }) => {
|
|
@@ -65,6 +66,12 @@ export function createModuleReportTool(getProjectRoot) {
|
|
|
65
66
|
blastRadiusDepth: Type.Optional(Type.Number({
|
|
66
67
|
description: "Max hops for the blast-radius walk (default 3). Only used with blastRadius.",
|
|
67
68
|
})),
|
|
69
|
+
callGraph: Type.Optional(Type.Boolean({
|
|
70
|
+
description: "Include bounded derived callers/callees from the cached FunctionCallGraph; cold or stale cache state is explicit.",
|
|
71
|
+
})),
|
|
72
|
+
maxCallGraphEntries: Type.Optional(Type.Number({
|
|
73
|
+
description: "Per-direction cap for call-graph relations (default 20).",
|
|
74
|
+
})),
|
|
68
75
|
}),
|
|
69
76
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
70
77
|
// Resolve the file against the agent's cwd (sibling-tool convention); build
|
|
@@ -79,6 +86,8 @@ export function createModuleReportTool(getProjectRoot) {
|
|
|
79
86
|
view: params.view,
|
|
80
87
|
blastRadius: params.blastRadius,
|
|
81
88
|
blastRadiusDepth: params.blastRadiusDepth,
|
|
89
|
+
callGraph: params.callGraph,
|
|
90
|
+
maxCallGraphEntries: params.maxCallGraphEntries,
|
|
82
91
|
});
|
|
83
92
|
}
|
|
84
93
|
catch (err) {
|
|
@@ -33,7 +33,7 @@ export function createSymbolSearchTool(getProjectRoot) {
|
|
|
33
33
|
}),
|
|
34
34
|
parameters: Type.Object({
|
|
35
35
|
query: Type.String({
|
|
36
|
-
description: "Identifier-ish query, e.g. 'authenticate user'.",
|
|
36
|
+
description: "Identifier-ish query, e.g. 'authenticate user'. Mix in composable prefix filters: lang:<kind> (e.g. lang:jsts, lang:python — kinds from file-kinds.ts), file:<substr> (path substring), ext:<ext> (e.g. ext:ts or ext:.ts), each optionally negated with a leading '-' (-file:test). Filters apply before ranking; e.g. 'lang:jsts file:clients/ -file:test rank'. Unknown prefixes/kinds error with the supported list.",
|
|
37
37
|
}),
|
|
38
38
|
limit: Type.Optional(Type.Number({
|
|
39
39
|
description: "Max files to return (default 20).",
|