@herbertgao/pi-extensions 2026.9.1 → 2026.9.3
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 +3 -2
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- package/node_modules/pi-lens/CHANGELOG.md +260 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
- package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
- package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
- package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
- package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- 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 +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.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 +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
- package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
- package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
- package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
- package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
- package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
- package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
- package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
- package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
- package/node_modules/pi-lens/dist/index.js +19969 -17481
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
- package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +31 -1
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
- package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +15 -15
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +7 -4
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import { Type } from "../clients/deps/typebox.js";
|
|
10
9
|
import { getProjectIgnoreMatcher, isExcludedDirName, } from "../clients/file-utils.js";
|
|
11
10
|
import { getLSPService, groupFilesByPrimaryServer, runPerServerGroups, } from "../clients/lsp/index.js";
|
|
12
11
|
import { buildScopeKey, createWorkspaceDiagnosticsCacheContext, } from "../clients/lsp/workspace-diagnostics-cache.js";
|
|
@@ -20,23 +19,26 @@ import { attemptTsserverSyncDiagnostics } from "../clients/lsp/tsserver-sync.js"
|
|
|
20
19
|
import { convertLspDiagnostics } from "../clients/dispatch/utils/lsp-diagnostics.js";
|
|
21
20
|
import { demoteInferredProjectDiagnostics } from "../clients/lsp/inferred-project.js";
|
|
22
21
|
import { isBlocking, reconcileScanDiagnostics, } from "../clients/widget-state.js";
|
|
23
|
-
import {
|
|
24
|
-
import { makeProgressReporter, scanningSummaryLine } from "./scan-progress.js";
|
|
22
|
+
import { makeProgressReporter } from "./scan-progress.js";
|
|
25
23
|
import { isWarmAttached, tryWarmAttachedDiagnostics, } from "../clients/warm-attach.js";
|
|
26
24
|
import { extensionsForLanguage, SCAN_LANGUAGE_PRIORITY, } from "../clients/language-registry.js";
|
|
27
25
|
const MAX_FILES = 100;
|
|
28
|
-
const MAX_BATCH_FILES = 100;
|
|
26
|
+
export const MAX_BATCH_FILES = 100;
|
|
29
27
|
const MAX_DIAGNOSTICS = 200;
|
|
30
28
|
const DEFAULT_BATCH_CONCURRENCY = 8;
|
|
31
29
|
const MAX_BATCH_CONCURRENCY = 16;
|
|
32
30
|
const DEFAULT_BATCH_FILE_DEADLINE_MS = 15_000;
|
|
33
31
|
// LSP severities: 1=Error, 2=Warning, 3=Information, 4=Hint
|
|
34
|
-
const SEVERITY_NAMES = {
|
|
32
|
+
export const SEVERITY_NAMES = {
|
|
35
33
|
1: "error",
|
|
36
34
|
2: "warning",
|
|
37
35
|
3: "information",
|
|
38
36
|
4: "hint",
|
|
39
37
|
};
|
|
38
|
+
export const LSP_SEVERITY_FILTERS = [
|
|
39
|
+
...Object.values(SEVERITY_NAMES),
|
|
40
|
+
"all",
|
|
41
|
+
];
|
|
40
42
|
function batchFileDeadlineMs() {
|
|
41
43
|
const raw = Number(process.env.PI_LENS_LSP_BATCH_FILE_MS);
|
|
42
44
|
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_BATCH_FILE_DEADLINE_MS;
|
|
@@ -216,98 +218,8 @@ nextWriteIndex,
|
|
|
216
218
|
// injecting "Unresolved from this turn" for three more turns after answering
|
|
217
219
|
// "confirmed clean" for the same file. index.ts injects
|
|
218
220
|
// `runtime.retireInlineBlockerOnConfirmedClean`. Optional/undefined in tests.
|
|
219
|
-
onConfirmedNoBlockers) {
|
|
221
|
+
onConfirmedNoBlockers, getService = getLSPService) {
|
|
220
222
|
return {
|
|
221
|
-
name: "lsp_diagnostics",
|
|
222
|
-
label: "LSP Diagnostics",
|
|
223
|
-
description: "Get errors, warnings, and hints from language servers for a file or directory. " +
|
|
224
|
-
"Use BEFORE running builds to proactively check for issues. " +
|
|
225
|
-
"Works on directories by auto-detecting file extensions and scanning all matching files.",
|
|
226
|
-
promptSnippet: "Get LSP diagnostics for a file or directory (use before builds)",
|
|
227
|
-
renderResult: compactRenderResult(({ details, args, isError, text }) => {
|
|
228
|
-
// Streaming progress partials render the live bar (see scanningSummaryLine).
|
|
229
|
-
const scanning = scanningSummaryLine(details, text);
|
|
230
|
-
if (scanning)
|
|
231
|
-
return scanning;
|
|
232
|
-
if (isError) {
|
|
233
|
-
return `lsp_diagnostics — ${text.split("\n")[0] ?? "error"}`;
|
|
234
|
-
}
|
|
235
|
-
const count = details?.totalDiagnostics ?? details?.diagnostics?.length ?? 0;
|
|
236
|
-
const target = baseName(details?.filePath ?? args.path) || "workspace";
|
|
237
|
-
const files = details?.filesChecked ?? details?.filesScanned;
|
|
238
|
-
const scope = typeof files === "number" && files > 1
|
|
239
|
-
? ` across ${files} files`
|
|
240
|
-
: target
|
|
241
|
-
? ` ${target}`
|
|
242
|
-
: "";
|
|
243
|
-
const noun = count === 1 ? "diagnostic" : "diagnostics";
|
|
244
|
-
// #533: a batch/directory result with any unconfirmed files must NEVER
|
|
245
|
-
// compact-render as a bare "N diagnostics" — that erases the fact some
|
|
246
|
-
// files' clean status was never actually confirmed by the server.
|
|
247
|
-
const unconfirmedFiles = details?.unconfirmedFiles ?? 0;
|
|
248
|
-
if (unconfirmedFiles > 0) {
|
|
249
|
-
const cleanFiles = details?.cleanFiles ?? 0;
|
|
250
|
-
const timedOutFiles = details?.timedOutFiles ?? 0;
|
|
251
|
-
const suffix = timedOutFiles > 0 ? ` (${timedOutFiles} timed out)` : "";
|
|
252
|
-
return `lsp_diagnostics${scope} — ${count} ${noun} · ${cleanFiles} clean · ${unconfirmedFiles} unconfirmed${suffix}`;
|
|
253
|
-
}
|
|
254
|
-
const outcomeCounts = details?.outcomeCounts;
|
|
255
|
-
const notConfirmed = outcomeCounts
|
|
256
|
-
? (outcomeCounts.inconclusive ?? 0) +
|
|
257
|
-
(outcomeCounts.unavailable ?? 0) +
|
|
258
|
-
(outcomeCounts.unsupported ?? 0) +
|
|
259
|
-
(outcomeCounts.failed ?? 0)
|
|
260
|
-
: 0;
|
|
261
|
-
if (notConfirmed > 0) {
|
|
262
|
-
return `lsp_diagnostics${scope} — ${count} ${noun} · ${notConfirmed} checks not confirmed`;
|
|
263
|
-
}
|
|
264
|
-
if ((details?.incompleteFiles ?? 0) > 0) {
|
|
265
|
-
return `lsp_diagnostics${scope} — incomplete (${details?.incompleteFiles} files not confirmed)`;
|
|
266
|
-
}
|
|
267
|
-
// Single-file mode: 0 diagnostics from an unconfirmed result — either a
|
|
268
|
-
// silent-on-clean server or (#570) a timed-out check — is not a clean
|
|
269
|
-
// render either.
|
|
270
|
-
if (count === 0 && details?.unconfirmed) {
|
|
271
|
-
return details?.timedOut
|
|
272
|
-
? `lsp_diagnostics${scope} — timed out (result may be incomplete)`
|
|
273
|
-
: `lsp_diagnostics${scope} — unconfirmed (server cannot confirm clean)`;
|
|
274
|
-
}
|
|
275
|
-
return `lsp_diagnostics${scope} — ${count} ${noun}`;
|
|
276
|
-
}),
|
|
277
|
-
parameters: Type.Object({
|
|
278
|
-
path: Type.Optional(Type.String({
|
|
279
|
-
description: "File or directory path to check. For directories, all matching source files are scanned.",
|
|
280
|
-
})),
|
|
281
|
-
paths: Type.Optional(Type.Array(Type.String(), {
|
|
282
|
-
minItems: 1,
|
|
283
|
-
maxItems: MAX_BATCH_FILES,
|
|
284
|
-
description: "Explicit files to check as a bounded-concurrency batch. When provided, path is ignored.",
|
|
285
|
-
})),
|
|
286
|
-
severity: Type.Optional(Type.String({
|
|
287
|
-
enum: ["error", "warning", "information", "hint", "all"],
|
|
288
|
-
description: "Filter by severity level (default: all)",
|
|
289
|
-
})),
|
|
290
|
-
concurrency: Type.Optional(Type.Number({
|
|
291
|
-
description: "Batch/directory concurrency, in distinct LSP server groups run in parallel " +
|
|
292
|
-
"(default 8, max 16) — not individual files. Files sharing one server " +
|
|
293
|
-
"(e.g. a same-language batch) are always processed one at a time against " +
|
|
294
|
-
"that server regardless of this value; this caps how many DIFFERENT " +
|
|
295
|
-
"servers run concurrently.",
|
|
296
|
-
})),
|
|
297
|
-
waitMs: Type.Optional(Type.Number({
|
|
298
|
-
description: "Optional per-file LSP wait budget for batch diagnostics. Uses server defaults when omitted.",
|
|
299
|
-
})),
|
|
300
|
-
serverScope: Type.Optional(Type.String({
|
|
301
|
-
enum: ["primary", "all"],
|
|
302
|
-
description: "'primary' (fast, low-noise): only the file's actual language " +
|
|
303
|
-
"server (e.g. typescript) — for 'does this have real type " +
|
|
304
|
-
"errors'. 'all' (default): also touches cross-cutting auxiliary " +
|
|
305
|
-
"scanners (ast-grep, opengrep, zizmor, typos, marksman) attached " +
|
|
306
|
-
"to this file, including findings for files not yet dispatched " +
|
|
307
|
-
"this session. Primary confirmation is always reported " +
|
|
308
|
-
"separately from auxiliary findings regardless of this setting.",
|
|
309
|
-
})),
|
|
310
|
-
}),
|
|
311
223
|
async execute(_toolCallId, params, _signal, onUpdate, ctx) {
|
|
312
224
|
// Escape aborts the turn via ctx.signal; honor both it and the tool-call
|
|
313
225
|
// signal so a batch/directory scan cancels rather than grinding on.
|
|
@@ -323,7 +235,7 @@ onConfirmedNoBlockers) {
|
|
|
323
235
|
? Math.floor(typedParams.waitMs)
|
|
324
236
|
: undefined;
|
|
325
237
|
const serverScope = typedParams.serverScope === "primary" ? "primary" : "all";
|
|
326
|
-
const lspService =
|
|
238
|
+
const lspService = getService();
|
|
327
239
|
if (!lspService) {
|
|
328
240
|
return {
|
|
329
241
|
content: [
|
|
@@ -446,7 +358,7 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
446
358
|
const attached = await tryWarmAttachedDiagnostics(absPath, content, attachedBudgetMs, "sweep");
|
|
447
359
|
if (attached?.available) {
|
|
448
360
|
const scopedDiagnostics = serverScope === "primary"
|
|
449
|
-
? attached.response.diagnostics.filter((item) => item.
|
|
361
|
+
? attached.response.diagnostics.filter((item) => item.serverId === primaryServerId(absPath))
|
|
450
362
|
: attached.response.diagnostics;
|
|
451
363
|
const filtered = applyAuxiliarySuppressions(scopedDiagnostics, content, { fileRole: detectFileRole(absPath, content) });
|
|
452
364
|
return {
|
|
@@ -470,6 +382,7 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
470
382
|
// field across the socket. An older incumbent omits it → empty → the
|
|
471
383
|
// pre-#1470 handling, unchanged.
|
|
472
384
|
unconfirmedServerIds: attached.response.unconfirmedServerIds ?? [],
|
|
385
|
+
diagnosticsUnsupportedServerIds: [],
|
|
473
386
|
content,
|
|
474
387
|
};
|
|
475
388
|
}
|
|
@@ -528,6 +441,7 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
528
441
|
// the getDiagnostics fallback never reports one, which is honest — that
|
|
529
442
|
// path claims no confirmation at all.
|
|
530
443
|
unconfirmedServerIds: touchCoverageGap(touched),
|
|
444
|
+
diagnosticsUnsupportedServerIds: touched?.diagnosticsUnsupportedServerIds ?? [],
|
|
531
445
|
content,
|
|
532
446
|
binding,
|
|
533
447
|
};
|
|
@@ -540,6 +454,7 @@ function diagnosticsToFileDiags(file, diagnostics) {
|
|
|
540
454
|
severity: d.severity,
|
|
541
455
|
message: d.message,
|
|
542
456
|
source: d.source,
|
|
457
|
+
serverId: d.serverId,
|
|
543
458
|
code: d.code,
|
|
544
459
|
}));
|
|
545
460
|
}
|
|
@@ -698,7 +613,9 @@ observedAt) {
|
|
|
698
613
|
scanOrigin: "lsp_diagnostics",
|
|
699
614
|
});
|
|
700
615
|
const retagged = retagAuxiliaryDiagnostics(diagnostics, rawDiags, content ?? "", { cwd, fileRole: detectFileRole(file, content) });
|
|
701
|
-
reconcileScanDiagnostics(file, retagged, true, writeIndex, observedAt);
|
|
616
|
+
const reconciled = reconcileScanDiagnostics(file, retagged, true, writeIndex, observedAt);
|
|
617
|
+
if (!reconciled)
|
|
618
|
+
return { confirmed: false, blocking: true };
|
|
702
619
|
// #1561: the blocking tally comes from the SAME `isBlocking` predicate the
|
|
703
620
|
// footer counts with — no second severity rule for the blocker-retire
|
|
704
621
|
// decision to drift away from.
|
|
@@ -777,7 +694,7 @@ onConfirmedNoBlockers) {
|
|
|
777
694
|
};
|
|
778
695
|
}
|
|
779
696
|
}
|
|
780
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
697
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
781
698
|
const health = lspService.getDiagnosticsHealth?.(file);
|
|
782
699
|
// #570: a timed-out priming check is never a confirmed "clean" — treat it
|
|
783
700
|
// as unconfirmed without consulting the (unrelated) silent-tier
|
|
@@ -788,7 +705,12 @@ onConfirmedNoBlockers) {
|
|
|
788
705
|
// be merged in rather than discarded.
|
|
789
706
|
let effectiveRawDiags = rawDiags;
|
|
790
707
|
let confirmation;
|
|
791
|
-
if (
|
|
708
|
+
if (diagnosticsUnsupportedServerIds.length > 0) {
|
|
709
|
+
// No diagnostic provider and no push evidence is a capability boundary,
|
|
710
|
+
// not a clean result and not a timeout.
|
|
711
|
+
confirmation = undefined;
|
|
712
|
+
}
|
|
713
|
+
else if (skipReason !== undefined) {
|
|
792
714
|
confirmation = "unconfirmed";
|
|
793
715
|
}
|
|
794
716
|
else if (timedOut) {
|
|
@@ -851,6 +773,7 @@ onConfirmedNoBlockers) {
|
|
|
851
773
|
if (cacheCtx &&
|
|
852
774
|
scopeKey !== undefined &&
|
|
853
775
|
confirmation !== "unconfirmed" &&
|
|
776
|
+
diagnosticsUnsupportedServerIds.length === 0 &&
|
|
854
777
|
unconfirmedServerIds.length === 0) {
|
|
855
778
|
cacheCtx.record(file, scopeKey, effectiveRawDiags, stat.mtimeMs, collectedContent !== undefined
|
|
856
779
|
? hashDiagnosticContent(collectedContent)
|
|
@@ -864,6 +787,7 @@ onConfirmedNoBlockers) {
|
|
|
864
787
|
timedOut: confirmation === "unconfirmed" ? timedOut : undefined,
|
|
865
788
|
...(skipReason !== undefined && { skipReason }),
|
|
866
789
|
primaryServerId: primaryServerId(file),
|
|
790
|
+
diagnosticsUnsupported: diagnosticsUnsupportedServerIds.length > 0,
|
|
867
791
|
};
|
|
868
792
|
}
|
|
869
793
|
async function runFileDiagnostics(absPath, severity, lspService, waitMs, nextWriteIndex, serverScope = "all", cwd = process.cwd(),
|
|
@@ -873,7 +797,7 @@ onConfirmedNoBlockers) {
|
|
|
873
797
|
// Reserve the token before awaiting this file's LSP result. The direct-file
|
|
874
798
|
// path performs its own confirmation/reconciliation below (#1198).
|
|
875
799
|
const writeIndex = nextWriteIndex?.();
|
|
876
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
800
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, diagnosticsUnsupportedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
877
801
|
const lspHealth = lspService.getDiagnosticsHealth?.(absPath);
|
|
878
802
|
const unavailable = lspUnavailableMessage(absPath, lspHealth);
|
|
879
803
|
// #533: an empty result needs a confirmed/unconfirmed verdict — a push-only,
|
|
@@ -887,7 +811,10 @@ onConfirmedNoBlockers) {
|
|
|
887
811
|
// diagnostics it surfaces are merged in, not discarded.
|
|
888
812
|
let effectiveRawDiags = rawDiags;
|
|
889
813
|
let confirmation;
|
|
890
|
-
if (
|
|
814
|
+
if (diagnosticsUnsupportedServerIds.length > 0) {
|
|
815
|
+
confirmation = undefined;
|
|
816
|
+
}
|
|
817
|
+
else if (skipReason !== undefined) {
|
|
891
818
|
confirmation = "unconfirmed";
|
|
892
819
|
}
|
|
893
820
|
else if (timedOut) {
|
|
@@ -949,12 +876,15 @@ onConfirmedNoBlockers) {
|
|
|
949
876
|
});
|
|
950
877
|
}
|
|
951
878
|
const primaryId = primaryServerId(absPath);
|
|
952
|
-
const primaryDiags = limited.filter((d) => d.
|
|
953
|
-
const auxiliaryDiags = limited.filter((d) => d.
|
|
879
|
+
const primaryDiags = limited.filter((d) => d.serverId === primaryId);
|
|
880
|
+
const auxiliaryDiags = limited.filter((d) => d.serverId !== primaryId);
|
|
954
881
|
// Primary confirmation is always its own line, independent of how many
|
|
955
882
|
// auxiliary findings exist — a wall of ast-grep/opengrep noise must never
|
|
956
883
|
// bury whether the actual language server confirmed the file clean.
|
|
957
884
|
const primaryLine = (() => {
|
|
885
|
+
if (diagnosticsUnsupportedServerIds.length > 0) {
|
|
886
|
+
return `Primary LSP${primaryId ? ` (${primaryId})` : ""}: navigation-only — diagnostics unsupported (no pull provider or publish evidence).`;
|
|
887
|
+
}
|
|
958
888
|
if (timedOut) {
|
|
959
889
|
return ("Primary LSP: check timed out — NOT the same as 0 diagnostics; the " +
|
|
960
890
|
"file may still have errors that just hadn't been reported yet. " +
|
|
@@ -980,7 +910,7 @@ onConfirmedNoBlockers) {
|
|
|
980
910
|
// this result does NOT speak for, so "no auxiliary findings" can never be read
|
|
981
911
|
// as "the security scanners found nothing".
|
|
982
912
|
const coverageLine = unconfirmedServerIds.length > 0
|
|
983
|
-
? `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
|
|
913
|
+
? `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. waitMs can extend an ordinary wait, but it cannot override a session-demoted scanner.`
|
|
984
914
|
: undefined;
|
|
985
915
|
let text;
|
|
986
916
|
if (total === 0) {
|
|
@@ -1031,6 +961,7 @@ onConfirmedNoBlockers) {
|
|
|
1031
961
|
truncated,
|
|
1032
962
|
unconfirmed,
|
|
1033
963
|
timedOut: unconfirmed ? timedOut : undefined,
|
|
964
|
+
navigationOnlyFiles: diagnosticsUnsupportedServerIds.length > 0 ? 1 : undefined,
|
|
1034
965
|
...(skipReason !== undefined && { skipReason }),
|
|
1035
966
|
// #1470: which servers this result does NOT speak for. Absent when it
|
|
1036
967
|
// speaks for all of them.
|
|
@@ -1054,7 +985,12 @@ function tallyConfirmation(results) {
|
|
|
1054
985
|
let clean = 0;
|
|
1055
986
|
let unconfirmed = 0;
|
|
1056
987
|
let timedOut = 0;
|
|
988
|
+
let navigationOnly = 0;
|
|
1057
989
|
for (const result of results) {
|
|
990
|
+
if (result.diagnosticsUnsupported) {
|
|
991
|
+
navigationOnly += 1;
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
1058
994
|
if (result.diagnostics.length > 0)
|
|
1059
995
|
continue;
|
|
1060
996
|
if (result.confirmation === "unconfirmed") {
|
|
@@ -1068,11 +1004,13 @@ function tallyConfirmation(results) {
|
|
|
1068
1004
|
clean += 1;
|
|
1069
1005
|
}
|
|
1070
1006
|
}
|
|
1071
|
-
return { clean, unconfirmed, timedOut };
|
|
1007
|
+
return { clean, unconfirmed, timedOut, navigationOnly };
|
|
1072
1008
|
}
|
|
1073
1009
|
function classifyBatchFileOutcome(result) {
|
|
1074
1010
|
if (result.error)
|
|
1075
1011
|
return "failed";
|
|
1012
|
+
if (result.diagnosticsUnsupported)
|
|
1013
|
+
return "unsupported";
|
|
1076
1014
|
// A timed-out/unconfirmed answer may contain partial findings, but it cannot
|
|
1077
1015
|
// honestly be called a complete findings result. Keep the raw findings for
|
|
1078
1016
|
// investigation while making the aggregate incomplete.
|
|
@@ -1201,8 +1139,8 @@ async function collectBatchDiagnostics(files, severity, lspService, options) {
|
|
|
1201
1139
|
// `clean`/`unconfirmed` above already reflect ONLY the primary server's
|
|
1202
1140
|
// confirmation; this split does the same job for the listed diagnostics.
|
|
1203
1141
|
const primaryIdByFile = new Map(results.map((r) => [r.file, r.primaryServerId]));
|
|
1204
|
-
const primaryDisplay = display.filter((d) => d.
|
|
1205
|
-
const auxiliaryDisplay = display.filter((d) => d.
|
|
1142
|
+
const primaryDisplay = display.filter((d) => d.serverId === primaryIdByFile.get(d.file));
|
|
1143
|
+
const auxiliaryDisplay = display.filter((d) => d.serverId !== primaryIdByFile.get(d.file));
|
|
1206
1144
|
return {
|
|
1207
1145
|
results,
|
|
1208
1146
|
fileErrors,
|
|
@@ -1228,6 +1166,7 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1228
1166
|
};
|
|
1229
1167
|
}
|
|
1230
1168
|
const { results, fileErrors, lspHealthWarnings, total, truncated, display, primaryDisplay, auxiliaryDisplay, clean, unconfirmed, timedOut, outcomeCounts, incompleteFiles, } = await collectBatchDiagnostics(absPaths, severity, lspService, options);
|
|
1169
|
+
const navigationOnly = results.filter((result) => result.diagnosticsUnsupported).length;
|
|
1231
1170
|
const lines = [
|
|
1232
1171
|
`Files checked: ${results.length}`,
|
|
1233
1172
|
`Total diagnostics: ${total}`,
|
|
@@ -1298,13 +1237,14 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1298
1237
|
truncated,
|
|
1299
1238
|
cleanFiles: clean,
|
|
1300
1239
|
unconfirmedFiles: unconfirmed,
|
|
1240
|
+
navigationOnlyFiles: navigationOnly > 0 ? navigationOnly : undefined,
|
|
1301
1241
|
timedOutFiles: timedOut > 0 ? timedOut : undefined,
|
|
1302
1242
|
outcomes: results.map((result) => ({
|
|
1303
1243
|
file: result.file,
|
|
1304
1244
|
outcome: result.outcome,
|
|
1305
1245
|
reason: result.inconclusiveReason ?? result.error ?? result.unavailable,
|
|
1306
|
-
primaryDiagnosticsCount: result.diagnostics.filter((diagnostic) => diagnostic.
|
|
1307
|
-
auxiliaryDiagnosticsCount: result.diagnostics.filter((diagnostic) => diagnostic.
|
|
1246
|
+
primaryDiagnosticsCount: result.diagnostics.filter((diagnostic) => diagnostic.serverId === result.primaryServerId).length,
|
|
1247
|
+
auxiliaryDiagnosticsCount: result.diagnostics.filter((diagnostic) => diagnostic.serverId !== result.primaryServerId).length,
|
|
1308
1248
|
})),
|
|
1309
1249
|
outcomeCounts,
|
|
1310
1250
|
incompleteFiles: incompleteFiles > 0 ? incompleteFiles : undefined,
|
|
@@ -1366,7 +1306,8 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1366
1306
|
}
|
|
1367
1307
|
const wasCapped = collectedFiles.length > MAX_FILES;
|
|
1368
1308
|
const filesToProcess = collectedFiles.slice(0, MAX_FILES);
|
|
1369
|
-
const { fileErrors, lspHealthWarnings, total, truncated, display, primaryDisplay, auxiliaryDisplay, clean, unconfirmed, timedOut, } = await collectBatchDiagnostics(filesToProcess, severity, lspService, options);
|
|
1309
|
+
const { results, fileErrors, lspHealthWarnings, total, truncated, display, primaryDisplay, auxiliaryDisplay, clean, unconfirmed, timedOut, } = await collectBatchDiagnostics(filesToProcess, severity, lspService, options);
|
|
1310
|
+
const navigationOnly = results.filter((result) => result.diagnosticsUnsupported).length;
|
|
1370
1311
|
let text;
|
|
1371
1312
|
if (total === 0) {
|
|
1372
1313
|
// #533/#570: an unconfirmed-containing directory result must never
|
|
@@ -1450,6 +1391,7 @@ async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
|
1450
1391
|
truncated,
|
|
1451
1392
|
cleanFiles: clean,
|
|
1452
1393
|
unconfirmedFiles: unconfirmed,
|
|
1394
|
+
navigationOnlyFiles: navigationOnly > 0 ? navigationOnly : undefined,
|
|
1453
1395
|
timedOutFiles: timedOut > 0 ? timedOut : undefined,
|
|
1454
1396
|
fileErrors: fileErrors.length > 0 ? fileErrors : undefined,
|
|
1455
1397
|
lspHealthWarnings: lspHealthWarnings.length > 0 ? lspHealthWarnings : undefined,
|
|
@@ -557,29 +557,8 @@ getFlag, mutationDeps) {
|
|
|
557
557
|
return {
|
|
558
558
|
name: "lsp_navigation",
|
|
559
559
|
label: "LSP Navigate",
|
|
560
|
-
description:
|
|
561
|
-
|
|
562
|
-
"- definition: Jump to where a symbol is defined\n" +
|
|
563
|
-
"- typeDefinition: Jump to the definition of a symbol's TYPE (e.g. the class/interface of a variable)\n" +
|
|
564
|
-
"- declaration: Jump to a symbol's declaration (e.g. an extern/forward decl, distinct from its definition)\n" +
|
|
565
|
-
"- references: Find all usages of a symbol\n" +
|
|
566
|
-
"- hover: Get type/doc info at a position\n" +
|
|
567
|
-
"- signatureHelp: Show callable signatures at cursor\n" +
|
|
568
|
-
"- documentSymbol: List all symbols (functions/classes/vars) in a file\n" +
|
|
569
|
-
"- findSymbol: Search document symbols in a file by name/detail with optional kind/top-level/exact filters\n" +
|
|
570
|
-
"- workspaceSymbol: Search symbols across the whole project (best with path context)\n" +
|
|
571
|
-
"- codeAction: Find available quick fixes/refactors at a range\n" +
|
|
572
|
-
"- rename: Compute or apply workspace edits for renaming a symbol\n" +
|
|
573
|
-
"- rename_file: Preview/apply LSP-aware source file rename notifications\n" +
|
|
574
|
-
"- implementation: Jump to interface implementations\n" +
|
|
575
|
-
"- prepareCallHierarchy: Get callable item at position (for incoming/outgoing)\n" +
|
|
576
|
-
"- incomingCalls: Find all functions/methods that CALL this function\n" +
|
|
577
|
-
"- outgoingCalls: Find all functions/methods CALLED by this function\n" +
|
|
578
|
-
"- executeCommand: Run a server-advertised command via workspace/executeCommand. HARDENED: allowlisted to commands the server advertised; dry-run by default (reports whether advertised) — set apply:true to actually run. Pass command (+ optional commandArguments).\n" +
|
|
579
|
-
"- workspaceDiagnostics: List all diagnostics tracked by active LSP clients\n" +
|
|
580
|
-
"- capabilities: Show cached operation support for active LSP servers\n\n" +
|
|
581
|
-
"Line and character are 1-based (as shown in editors). For position-based operations, prefer passing symbol when you know the line but not the exact character; character can be omitted or -1 and pi-lens will resolve the symbol column. Use symbol#N for repeated symbols on the same line (1-based occurrence).",
|
|
582
|
-
promptSnippet: "Find definitions, references, and hover info via LSP",
|
|
560
|
+
description: 'Navigate source with language-server operations such as definition, references, hover, and rename. Example: use `{operation: "references", path: "src/app.ts", line: 12}`.',
|
|
561
|
+
promptSnippet: "Navigate definitions and references with LSP",
|
|
583
562
|
renderResult: compactRenderResult(({ details, args, isError, text }) => {
|
|
584
563
|
const op = details?.operation ??
|
|
585
564
|
(typeof args.operation === "string" ? args.operation : "lsp");
|
|
@@ -594,56 +573,55 @@ getFlag, mutationDeps) {
|
|
|
594
573
|
}),
|
|
595
574
|
parameters: Type.Object({
|
|
596
575
|
operation: Type.String({
|
|
597
|
-
description: "LSP operation to perform. Valid values: "
|
|
598
|
-
VALID_OPERATIONS.join(", "),
|
|
576
|
+
description: "LSP operation to perform. Valid values: definition, typeDefinition, declaration, references, hover, signatureHelp, documentSymbol, findSymbol, workspaceSymbol, codeAction, rename, rename_file, implementation, prepareCallHierarchy, incomingCalls, outgoingCalls, executeCommand, workspaceDiagnostics, capabilities.",
|
|
599
577
|
}),
|
|
600
578
|
path: Type.Optional(Type.String({
|
|
601
|
-
description: "
|
|
579
|
+
description: "Target file path.",
|
|
602
580
|
})),
|
|
603
581
|
line: Type.Optional(Type.Number({
|
|
604
|
-
description: "
|
|
582
|
+
description: "1-based line number.",
|
|
605
583
|
})),
|
|
606
584
|
character: Type.Optional(Type.Number({
|
|
607
|
-
description: "
|
|
585
|
+
description: "1-based character offset.",
|
|
608
586
|
})),
|
|
609
587
|
symbol: Type.Optional(Type.String({
|
|
610
|
-
description: "Symbol
|
|
588
|
+
description: "Symbol for automatic character resolution.",
|
|
611
589
|
})),
|
|
612
590
|
endLine: Type.Optional(Type.Number({
|
|
613
|
-
description: "
|
|
591
|
+
description: "1-based range end line.",
|
|
614
592
|
})),
|
|
615
593
|
endCharacter: Type.Optional(Type.Number({
|
|
616
|
-
description: "
|
|
594
|
+
description: "1-based range end character.",
|
|
617
595
|
})),
|
|
618
596
|
newName: Type.Optional(Type.String({
|
|
619
|
-
description: "
|
|
597
|
+
description: "New symbol name.",
|
|
620
598
|
})),
|
|
621
599
|
newFilePath: Type.Optional(Type.String({
|
|
622
|
-
description: "
|
|
600
|
+
description: "New file path.",
|
|
623
601
|
})),
|
|
624
602
|
apply: Type.Optional(Type.Boolean({
|
|
625
|
-
description: "
|
|
603
|
+
description: "Apply a mutation instead of previewing it.",
|
|
626
604
|
})),
|
|
627
605
|
command: Type.Optional(Type.String({
|
|
628
|
-
description: "
|
|
606
|
+
description: "Server command identifier.",
|
|
629
607
|
})),
|
|
630
608
|
commandArguments: Type.Optional(Type.Array(Type.Unknown(), {
|
|
631
|
-
description: "
|
|
609
|
+
description: "Arguments for the server command.",
|
|
632
610
|
})),
|
|
633
611
|
query: Type.Optional(Type.String({
|
|
634
|
-
description: "Symbol
|
|
612
|
+
description: "Symbol search query.",
|
|
635
613
|
})),
|
|
636
614
|
kinds: Type.Optional(Type.Array(Type.String(), {
|
|
637
|
-
description: "
|
|
615
|
+
description: "Symbol-kind filters.",
|
|
638
616
|
})),
|
|
639
617
|
exactMatch: Type.Optional(Type.Boolean({
|
|
640
|
-
description: "
|
|
618
|
+
description: "Require an exact symbol match.",
|
|
641
619
|
})),
|
|
642
620
|
topLevelOnly: Type.Optional(Type.Boolean({
|
|
643
|
-
description: "
|
|
621
|
+
description: "Exclude nested symbols.",
|
|
644
622
|
})),
|
|
645
623
|
maxResults: Type.Optional(Type.Number({
|
|
646
|
-
description: "
|
|
624
|
+
description: "Maximum symbol matches.",
|
|
647
625
|
})),
|
|
648
626
|
callHierarchyItem: Type.Optional(Type.Object({
|
|
649
627
|
name: Type.String(),
|
|
@@ -669,9 +647,7 @@ getFlag, mutationDeps) {
|
|
|
669
647
|
character: Type.Number(),
|
|
670
648
|
}),
|
|
671
649
|
}),
|
|
672
|
-
}, {
|
|
673
|
-
description: "Call hierarchy item. Required for incomingCalls/outgoingCalls",
|
|
674
|
-
})),
|
|
650
|
+
}, {})),
|
|
675
651
|
}),
|
|
676
652
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
677
653
|
const startedAt = Date.now();
|
|
@@ -9,7 +9,7 @@ function finiteNumber(value) {
|
|
|
9
9
|
? value
|
|
10
10
|
: undefined;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
function lspStatusFromFailureKind(failureKind) {
|
|
13
13
|
if (failureKind === "success" || failureKind === "fallback_success") {
|
|
14
14
|
return "success";
|
|
15
15
|
}
|
|
@@ -145,7 +145,7 @@ function collectCallHierarchyLocationSummaries(result, operation) {
|
|
|
145
145
|
}
|
|
146
146
|
return out;
|
|
147
147
|
}
|
|
148
|
-
|
|
148
|
+
function collectLspToolLocationsForOperation(operation, result, filePath) {
|
|
149
149
|
if ([
|
|
150
150
|
"definition",
|
|
151
151
|
"typeDefinition",
|
|
@@ -210,7 +210,7 @@ function parseBalancedJsonPrefix(text) {
|
|
|
210
210
|
}
|
|
211
211
|
return undefined;
|
|
212
212
|
}
|
|
213
|
-
|
|
213
|
+
function parseLspNavigationTextPayload(text) {
|
|
214
214
|
const notes = [];
|
|
215
215
|
const hints = [];
|
|
216
216
|
const errors = [];
|
|
@@ -26,12 +26,8 @@ export function createModuleReportTool(getProjectRoot) {
|
|
|
26
26
|
return {
|
|
27
27
|
name: "module_report",
|
|
28
28
|
label: "Module Report",
|
|
29
|
-
description: "
|
|
30
|
-
|
|
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" +
|
|
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.',
|
|
34
|
-
promptSnippet: "Navigable file outline — a cheap substitute for reading a whole file",
|
|
29
|
+
description: "Return a navigable source-module outline with symbols, references, and read handles. An outline shows shape, not bodies, and does not satisfy read-before-edit; `read_symbol` and `read_enclosing` return body text and record read coverage. On a cold cache, project_report and symbol_search return available: false with a retry hint and start a non-blocking background build; module_report degrades to outline-only with cache freshness explicit. Example: use module_report on `src/app.ts` before read_symbol.",
|
|
30
|
+
promptSnippet: "Outline a source module before reading a body",
|
|
35
31
|
renderResult: compactRenderResult(({ details, args, isError }) => {
|
|
36
32
|
const base = baseName(args.path) || "module";
|
|
37
33
|
if (isError || details?.available === false) {
|
|
@@ -48,7 +44,7 @@ export function createModuleReportTool(getProjectRoot) {
|
|
|
48
44
|
}),
|
|
49
45
|
parameters: Type.Object({
|
|
50
46
|
path: Type.String({
|
|
51
|
-
description: "
|
|
47
|
+
description: "Source file, e.g. `src/app.ts`.",
|
|
52
48
|
}),
|
|
53
49
|
maxRefsPerSymbol: Type.Optional(Type.Number({
|
|
54
50
|
description: "Cap on who-uses-this entries per symbol (default 10).",
|
|
@@ -157,7 +153,7 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
|
|
|
157
153
|
return {
|
|
158
154
|
name: "read_symbol",
|
|
159
155
|
label: "Read Symbol",
|
|
160
|
-
description: "Return
|
|
156
|
+
description: "Return one symbol's verbatim source. An outline shows shape, not bodies, and does not satisfy read-before-edit; `read_symbol` and `read_enclosing` return body text and record read coverage. Example: use read_symbol after module_report identifies `parseConfig`.",
|
|
161
157
|
promptSnippet: "Read one symbol's body instead of the whole file",
|
|
162
158
|
renderResult: compactRenderResult(({ details, args, isError, lineCount }) => {
|
|
163
159
|
const base = baseName(args.path);
|
|
@@ -259,7 +255,7 @@ export function createReadEnclosingTool(getProjectRoot, recordSymbolRead) {
|
|
|
259
255
|
return {
|
|
260
256
|
name: "read_enclosing",
|
|
261
257
|
label: "Read Enclosing",
|
|
262
|
-
description: "Return the
|
|
258
|
+
description: "Return the smallest symbol or callback enclosing a line. An outline shows shape, not bodies, and does not satisfy read-before-edit; `read_symbol` and `read_enclosing` return body text and record read coverage. Example: use read_enclosing after a diagnostic points to line 42.",
|
|
263
259
|
promptSnippet: "Read the enclosing symbol or callback body for a line",
|
|
264
260
|
renderResult: compactRenderResult(({ details, args, isError }) => {
|
|
265
261
|
const base = baseName(args.path);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { Type } from "../clients/deps/typebox.js";
|
|
11
11
|
import { projectReport, renderCompactProjectReport, } from "../clients/lens-engine.js";
|
|
12
|
-
import { compactRenderResult } from "./render-compact.js";
|
|
12
|
+
import { compactRenderResult, renderToolText, } from "./render-compact.js";
|
|
13
13
|
function errorMessage(err) {
|
|
14
14
|
return err instanceof Error ? err.message : String(err);
|
|
15
15
|
}
|
|
@@ -17,9 +17,8 @@ export function createProjectReportTool(getProjectRoot) {
|
|
|
17
17
|
return {
|
|
18
18
|
name: "project_report",
|
|
19
19
|
label: "Project Report",
|
|
20
|
-
description: "
|
|
21
|
-
|
|
22
|
-
promptSnippet: "Project-level orientation from the review graph",
|
|
20
|
+
description: "Orient in a project from its review graph, with ranked hubs and entry points. On a cold cache, project_report and symbol_search return available: false with a retry hint and start a non-blocking background build; module_report degrades to outline-only with cache freshness explicit. Example: use project_report before module_report when the target file is unknown.",
|
|
21
|
+
promptSnippet: "Orient in a project before choosing a file",
|
|
23
22
|
renderResult: compactRenderResult(({ details, isError }) => {
|
|
24
23
|
if (isError || details?.available === false) {
|
|
25
24
|
return `project_report — unavailable${details?.hint ? `: ${details.hint}` : ""}`;
|
|
@@ -28,7 +27,9 @@ export function createProjectReportTool(getProjectRoot) {
|
|
|
28
27
|
`${details?.hubs ?? 0} hub(s)`,
|
|
29
28
|
`${details?.entryPoints ?? 0} entry point(s)`,
|
|
30
29
|
];
|
|
31
|
-
const view = details?.view && details.view !== "default"
|
|
30
|
+
const view = details?.view && details.view !== "default"
|
|
31
|
+
? ` [${details.view}]`
|
|
32
|
+
: "";
|
|
32
33
|
return `project_report ${parts.join(" · ")}${view}`;
|
|
33
34
|
}),
|
|
34
35
|
parameters: Type.Object({
|
|
@@ -55,24 +56,14 @@ export function createProjectReportTool(getProjectRoot) {
|
|
|
55
56
|
}
|
|
56
57
|
catch (err) {
|
|
57
58
|
return {
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
type: "text",
|
|
61
|
-
text: `Project report failed: ${errorMessage(err)}`,
|
|
62
|
-
},
|
|
63
|
-
],
|
|
59
|
+
...renderToolText(`Project report failed: ${errorMessage(err)}`),
|
|
64
60
|
isError: true,
|
|
65
61
|
details: { available: false },
|
|
66
62
|
};
|
|
67
63
|
}
|
|
68
64
|
if (!report.available) {
|
|
69
65
|
return {
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
type: "text",
|
|
73
|
-
text: report.hint ?? "No review graph cached for this workspace yet.",
|
|
74
|
-
},
|
|
75
|
-
],
|
|
66
|
+
...renderToolText(report.hint ?? "No review graph cached for this workspace yet.", report),
|
|
76
67
|
isError: true,
|
|
77
68
|
details: { available: false, hint: report.hint },
|
|
78
69
|
};
|
|
@@ -82,6 +73,7 @@ export function createProjectReportTool(getProjectRoot) {
|
|
|
82
73
|
: JSON.stringify(report);
|
|
83
74
|
return {
|
|
84
75
|
content: [{ type: "text", text }],
|
|
76
|
+
isError: false,
|
|
85
77
|
details: {
|
|
86
78
|
available: true,
|
|
87
79
|
hubs: report.hubs?.length ?? 0,
|