@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
|
@@ -32,10 +32,106 @@
|
|
|
32
32
|
* `undefined`). The caller must handle `undefined` as "sync path unavailable,
|
|
33
33
|
* fall back to existing unconfirmed/timed-out behavior".
|
|
34
34
|
*/
|
|
35
|
+
import { logLatency } from "../latency-logger.js";
|
|
36
|
+
import { normalizeMapKey } from "../path-utils.js";
|
|
35
37
|
// ---------------------------------------------------------------------------
|
|
36
38
|
// Constants
|
|
37
39
|
// ---------------------------------------------------------------------------
|
|
38
40
|
export const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
|
|
41
|
+
function classifyProjectInfo(body) {
|
|
42
|
+
if (!body || typeof body !== "object") {
|
|
43
|
+
return { projectKind: "unassociated", association: "unassociated" };
|
|
44
|
+
}
|
|
45
|
+
const info = body;
|
|
46
|
+
const configFile = typeof info.configFileName === "string" && info.configFileName.length > 0
|
|
47
|
+
? info.configFileName
|
|
48
|
+
: undefined;
|
|
49
|
+
const inferred = configFile
|
|
50
|
+
? /(?:^|[/\\])inferredProject\d*\*?$/i.test(configFile) ||
|
|
51
|
+
/inferred[-_ ]?project/i.test(configFile)
|
|
52
|
+
: false;
|
|
53
|
+
const projectKind = configFile
|
|
54
|
+
? inferred
|
|
55
|
+
? "inferred"
|
|
56
|
+
: /(?:^|[/\\])(?:tsconfig|jsconfig)\.json$/i.test(configFile)
|
|
57
|
+
? "configured"
|
|
58
|
+
: "unassociated"
|
|
59
|
+
: "unassociated";
|
|
60
|
+
return {
|
|
61
|
+
projectKind,
|
|
62
|
+
...(configFile ? { configFile } : {}),
|
|
63
|
+
association: info.languageServiceDisabled === true
|
|
64
|
+
? "language-service-disabled"
|
|
65
|
+
: projectKind === "unassociated"
|
|
66
|
+
? "unassociated"
|
|
67
|
+
: "associated",
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* #1412: after classic TypeScript's first successful didOpen, sample the
|
|
72
|
+
* tsserver project association without delaying diagnostics. The supplied
|
|
73
|
+
* executeCommand channel owns the existing bounded anti-deadlock backstop.
|
|
74
|
+
*/
|
|
75
|
+
export async function probeTsserverProjectIdentity(options) {
|
|
76
|
+
const normalizedFile = options.normalizedFile ?? normalizeMapKey(options.file);
|
|
77
|
+
const startedAt = Date.now();
|
|
78
|
+
// Logging starts only once a probe is actually eligible and attempted:
|
|
79
|
+
// ineligible servers (wrong serverId/launchVariant, no command channel) and
|
|
80
|
+
// already-probed dedupe are both routine, high-volume, and per-server — a
|
|
81
|
+
// bare return keeps them out of the telemetry stream entirely instead of
|
|
82
|
+
// writing an `lsp_typescript_project_identity` row per didOpen on every
|
|
83
|
+
// server (python, go, opengrep, ...).
|
|
84
|
+
const logOutcome = (outcome, metadata = {}) => logLatency({
|
|
85
|
+
type: "phase", phase: "lsp_typescript_project_identity", filePath: normalizedFile,
|
|
86
|
+
durationMs: Date.now() - startedAt,
|
|
87
|
+
metadata: { serverId: options.serverId, launchVariant: options.launchVariant, clientRoot: options.clientRoot, outcome, ...metadata },
|
|
88
|
+
});
|
|
89
|
+
if (options.serverId !== "typescript" ||
|
|
90
|
+
options.launchVariant !== "classic" ||
|
|
91
|
+
typeof options.commandChannel.executeCommand !== "function") {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (options.probedFiles.has(normalizedFile))
|
|
95
|
+
return;
|
|
96
|
+
// Claim before yielding so concurrent opens cannot issue duplicate probes.
|
|
97
|
+
options.probedFiles.add(normalizedFile);
|
|
98
|
+
try {
|
|
99
|
+
const outcome = await options.commandChannel.executeCommand(TSSERVER_REQUEST_COMMAND, ["projectInfo", { file: options.file, needFileNameList: false }]);
|
|
100
|
+
if (!outcome.executed) {
|
|
101
|
+
logOutcome("not-executed");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const response = outcome.result;
|
|
105
|
+
if (!response) {
|
|
106
|
+
logOutcome("no-response");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (response.success !== true) {
|
|
110
|
+
logOutcome("unsuccessful");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const identity = classifyProjectInfo(response.body);
|
|
114
|
+
logLatency({
|
|
115
|
+
type: "phase",
|
|
116
|
+
phase: "lsp_typescript_project_identity",
|
|
117
|
+
filePath: normalizedFile,
|
|
118
|
+
durationMs: Date.now() - startedAt,
|
|
119
|
+
metadata: {
|
|
120
|
+
outcome: "ok",
|
|
121
|
+
serverId: options.serverId,
|
|
122
|
+
launchVariant: options.launchVariant,
|
|
123
|
+
clientRoot: options.clientRoot,
|
|
124
|
+
projectKind: identity.projectKind,
|
|
125
|
+
configFile: identity.configFile,
|
|
126
|
+
association: identity.association,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
logOutcome("threw");
|
|
132
|
+
// Best-effort telemetry: command errors/timeouts never reach diagnostics.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
39
135
|
// ---------------------------------------------------------------------------
|
|
40
136
|
// Helpers
|
|
41
137
|
// ---------------------------------------------------------------------------
|
|
@@ -26,7 +26,7 @@ export function classifyServerWaitTier(serverId, snapshot) {
|
|
|
26
26
|
return "pull-capable";
|
|
27
27
|
if (mode !== "push-only")
|
|
28
28
|
return "waits";
|
|
29
|
-
const strategy = getStrategy(serverId);
|
|
29
|
+
const strategy = getStrategy(serverId, snapshot.launchVariant);
|
|
30
30
|
if (strategy.silentOnClean !== true)
|
|
31
31
|
return "waits"; // 2*/unknown push-only
|
|
32
32
|
// #524/#529/#541/#558: `silentOnClean` on a server-id-keyed strategy is
|
|
@@ -44,6 +44,24 @@ export function classifyServerWaitTier(serverId, snapshot) {
|
|
|
44
44
|
return "waits";
|
|
45
45
|
return "tier3-silent";
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve `filePath`'s PRIMARY (non-auxiliary) server id and its live
|
|
49
|
+
* capability snapshot, or `undefined` when the file has no primary server
|
|
50
|
+
* configured. The single place that decides what "this file's server" means
|
|
51
|
+
* for wait-policy purposes — shared by {@link classifyCascadeWaitTier} and the
|
|
52
|
+
* cascade-lane wrapper in `clients/lsp/cascade-tier.ts`, which needs the same
|
|
53
|
+
* id/snapshot pair to apply its one cascade-only override.
|
|
54
|
+
*/
|
|
55
|
+
export function resolvePrimaryServerForWaitPolicy(filePath, snapshots) {
|
|
56
|
+
const servers = getServersForFileWithConfig(filePath).filter((s) => s.role !== "auxiliary");
|
|
57
|
+
const primary = servers[0];
|
|
58
|
+
if (!primary)
|
|
59
|
+
return undefined;
|
|
60
|
+
return {
|
|
61
|
+
serverId: primary.id,
|
|
62
|
+
snapshot: snapshots.find((s) => s.serverId === primary.id),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
47
65
|
/**
|
|
48
66
|
* Classify whether `filePath`'s PRIMARY language server is a cascade-lane
|
|
49
67
|
* Tier-3 (push-only, silent-on-clean) server. Ambiguous or missing capability
|
|
@@ -54,10 +72,8 @@ export function classifyServerWaitTier(serverId, snapshot) {
|
|
|
54
72
|
*/
|
|
55
73
|
export function classifyCascadeWaitTier(lspService, filePath, snapshots) {
|
|
56
74
|
void lspService; // kept in the signature for call-site clarity/typing only
|
|
57
|
-
const
|
|
58
|
-
const primary = servers[0];
|
|
75
|
+
const primary = resolvePrimaryServerForWaitPolicy(filePath, snapshots);
|
|
59
76
|
if (!primary)
|
|
60
77
|
return "waits";
|
|
61
|
-
|
|
62
|
-
return classifyServerWaitTier(primary.id, snapshot);
|
|
78
|
+
return classifyServerWaitTier(primary.serverId, primary.snapshot);
|
|
63
79
|
}
|
|
@@ -138,7 +138,8 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
|
|
|
138
138
|
// (#242), so on a 2500ms-capped edit opengrep waits min(2500, 3500)=2500
|
|
139
139
|
// and on uncapped paths it gets its full 3500. 3500 covers warm and most
|
|
140
140
|
// cold; a cold scan that overruns isn't lost — late diagnostics are cached
|
|
141
|
-
// and surface on the next
|
|
141
|
+
// and surface on the next unchanged-content read through the content-bound
|
|
142
|
+
// auxiliary carry-over path.
|
|
142
143
|
opengrep: {
|
|
143
144
|
seedFirstPush: false,
|
|
144
145
|
pullRetryBudgetMs: 0,
|
|
@@ -174,7 +175,8 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
|
|
|
174
175
|
// reopen-on-resync. A native single-workflow audit is sub-second offline;
|
|
175
176
|
// online mode may add a GitHub-API round-trip, so 2000ms gives headroom
|
|
176
177
|
// (bounded by the per-edit caller cap as a ceiling, #242), and any late online
|
|
177
|
-
// finding
|
|
178
|
+
// finding can surface on the next unchanged-content read through the
|
|
179
|
+
// content-bound auxiliary carry-over path.
|
|
178
180
|
zizmor: {
|
|
179
181
|
seedFirstPush: true,
|
|
180
182
|
pullRetryBudgetMs: 0,
|
|
@@ -231,6 +233,16 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
|
|
|
231
233
|
silentOnClean: true,
|
|
232
234
|
},
|
|
233
235
|
};
|
|
236
|
+
/** Native TS7 can publish multiple versionless partial-program snapshots for a
|
|
237
|
+
* single open. Its first push is therefore provisional; a quiet window, rather
|
|
238
|
+
* than a protocol-unstable publication count, establishes the settled push. */
|
|
239
|
+
const NATIVE_TS7_DIAGNOSTIC_STRATEGY = {
|
|
240
|
+
...SERVER_DIAGNOSTIC_STRATEGIES.typescript,
|
|
241
|
+
seedFirstPush: false,
|
|
242
|
+
// Native TS7 demonstrably publishes on clean, so the classic-only marker
|
|
243
|
+
// must not leak through the shared server id.
|
|
244
|
+
silentOnClean: false,
|
|
245
|
+
};
|
|
234
246
|
/** Fallback for unknown servers. Conservative defaults. */
|
|
235
247
|
export const DEFAULT_STRATEGY = {
|
|
236
248
|
seedFirstPush: false,
|
|
@@ -239,6 +251,9 @@ export const DEFAULT_STRATEGY = {
|
|
|
239
251
|
aggregateWaitMs: 1500,
|
|
240
252
|
expectSemanticSecondPush: false,
|
|
241
253
|
};
|
|
242
|
-
export function getStrategy(serverId) {
|
|
254
|
+
export function getStrategy(serverId, launchVariant) {
|
|
255
|
+
if (serverId === "typescript" && launchVariant === "native-ts7") {
|
|
256
|
+
return NATIVE_TS7_DIAGNOSTIC_STRATEGY;
|
|
257
|
+
}
|
|
243
258
|
return SERVER_DIAGNOSTIC_STRATEGIES[serverId] ?? DEFAULT_STRATEGY;
|
|
244
259
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getProjectDataDir } from "../file-utils.js";
|
|
4
|
+
import { writeFileAtomic } from "../atomic-write.js";
|
|
4
5
|
import { readJsonCache } from "../json-cache-read.js";
|
|
5
6
|
import { normalizeMapKey } from "../path-utils.js";
|
|
6
7
|
import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
|
|
8
|
+
import { createDiskBindingCache, } from "./diagnostic-binding.js";
|
|
7
9
|
/**
|
|
8
10
|
* #671: per-file cache of the last CONFIRMED `runWorkspaceDiagnostics` sweep
|
|
9
11
|
* result, so a repeat `lens_diagnostics mode=full` with no intervening edits
|
|
@@ -24,7 +26,12 @@ import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
|
|
|
24
26
|
* `LSPWorkspaceDiagnosticResult.timedOut` in `./index.ts`) into
|
|
25
27
|
* `WorkspaceDiagnosticsCacheEntry`.
|
|
26
28
|
*/
|
|
27
|
-
|
|
29
|
+
// v2 (#1095): entries may carry an optional `contentHash` fingerprint of the
|
|
30
|
+
// file bytes the cached diagnostics were computed against, so a `lookup` can
|
|
31
|
+
// surface a content `binding` (boundToCurrentDisk) beyond the mtime proxy.
|
|
32
|
+
// Legacy v1 entries are rejected by the version guard and re-scanned — a
|
|
33
|
+
// deliberately clean break so no entry lacking the field is ever served.
|
|
34
|
+
export const WORKSPACE_DIAGNOSTICS_CACHE_VERSION = 2;
|
|
28
35
|
const CACHE_FILE = "lsp-workspace-diagnostics.json";
|
|
29
36
|
function cachePath(cwd) {
|
|
30
37
|
return path.join(getProjectDataDir(cwd), "cache", CACHE_FILE);
|
|
@@ -48,7 +55,11 @@ export function loadWorkspaceDiagnosticsCache(cwd) {
|
|
|
48
55
|
export function saveWorkspaceDiagnosticsCache(cwd, cache) {
|
|
49
56
|
const filePath = cachePath(cwd);
|
|
50
57
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
51
|
-
|
|
58
|
+
// bestEffort: false — persist()'s catch is the error policy here, and it
|
|
59
|
+
// must observe the failure so `dirty` stays set and the next sweep retries.
|
|
60
|
+
writeFileAtomic(filePath, JSON.stringify(cache, null, 2), {
|
|
61
|
+
bestEffort: false,
|
|
62
|
+
});
|
|
52
63
|
}
|
|
53
64
|
/**
|
|
54
65
|
* True when `filePath`'s cached entry is still trustworthy enough to reuse
|
|
@@ -133,6 +144,8 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
|
|
|
133
144
|
return undefined;
|
|
134
145
|
return reverseDepsIndex.imports[cacheKeyFor(filePath)] ?? [];
|
|
135
146
|
};
|
|
147
|
+
// #1095: per-sweep disk-fingerprint memo (per file+mtime) for binding verify.
|
|
148
|
+
const diskBindingCache = createDiskBindingCache();
|
|
136
149
|
let dirty = false;
|
|
137
150
|
return {
|
|
138
151
|
lookup(filePath, scopeKey) {
|
|
@@ -141,15 +154,26 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
|
|
|
141
154
|
return undefined;
|
|
142
155
|
if (!isEntryFresh(filePath, entry, getImports))
|
|
143
156
|
return undefined;
|
|
144
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
diagnostics: entry.diagnostics,
|
|
159
|
+
count: entry.count,
|
|
160
|
+
binding: {
|
|
161
|
+
contentHash: entry.contentHash,
|
|
162
|
+
boundToCurrentDisk: diskBindingCache.boundToCurrentDisk(filePath, {
|
|
163
|
+
contentHash: entry.contentHash,
|
|
164
|
+
}),
|
|
165
|
+
},
|
|
166
|
+
scannedAt: entry.scannedAt,
|
|
167
|
+
};
|
|
145
168
|
},
|
|
146
|
-
record(filePath, scopeKey, diagnostics, mtimeMs) {
|
|
169
|
+
record(filePath, scopeKey, diagnostics, mtimeMs, contentHash) {
|
|
147
170
|
entries[cacheKeyFor(filePath)] = {
|
|
148
171
|
diagnostics,
|
|
149
172
|
count: diagnostics.length,
|
|
150
173
|
mtimeMs,
|
|
151
174
|
scannedAt: Date.now(),
|
|
152
175
|
scopeKey,
|
|
176
|
+
...(contentHash !== undefined && { contentHash }),
|
|
153
177
|
};
|
|
154
178
|
dirty = true;
|
|
155
179
|
},
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
|
|
3
|
+
import { appendProjectChange, } from "./project-changes.js";
|
|
4
|
+
import { normalizeMapKey } from "./path-utils.js";
|
|
5
|
+
const MAX_SAMPLES = 100;
|
|
6
|
+
const MAX_SUMMARIES_PER_CONTEXT = 100;
|
|
7
|
+
export function newLspMutationCorrelationId(toolCallId) {
|
|
8
|
+
return getReadGuardCorrelationId(toolCallId ? { toolCallId } : {});
|
|
9
|
+
}
|
|
10
|
+
function allResults(options) {
|
|
11
|
+
return options.results ?? [];
|
|
12
|
+
}
|
|
13
|
+
function combineResults(results) {
|
|
14
|
+
const files = new Set();
|
|
15
|
+
const fileDetails = [];
|
|
16
|
+
const appliedIndexes = [];
|
|
17
|
+
const paths = [];
|
|
18
|
+
let requestedTotal = 0;
|
|
19
|
+
let appliedTotal = 0;
|
|
20
|
+
let textEdits = 0;
|
|
21
|
+
let create = 0;
|
|
22
|
+
let rename = 0;
|
|
23
|
+
let deleteCount = 0;
|
|
24
|
+
for (const result of results) {
|
|
25
|
+
requestedTotal += result.operationTotal;
|
|
26
|
+
appliedTotal += result.appliedOperationTotal;
|
|
27
|
+
textEdits += result.operationCounts.textEdits;
|
|
28
|
+
create += result.operationCounts.create;
|
|
29
|
+
rename += result.operationCounts.rename;
|
|
30
|
+
deleteCount += result.operationCounts.delete;
|
|
31
|
+
for (const index of result.appliedOperationIndexes)
|
|
32
|
+
appliedIndexes.push(index);
|
|
33
|
+
for (const file of result.files) {
|
|
34
|
+
if (!files.has(file)) {
|
|
35
|
+
files.add(file);
|
|
36
|
+
paths.push(file);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
fileDetails.push(...result.fileDetails);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
requestedTotal,
|
|
43
|
+
appliedTotal,
|
|
44
|
+
appliedIndexes,
|
|
45
|
+
files: [...files],
|
|
46
|
+
fileDetails,
|
|
47
|
+
textEdits,
|
|
48
|
+
create,
|
|
49
|
+
rename,
|
|
50
|
+
delete: deleteCount,
|
|
51
|
+
paths,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function uniqueDetails(files, fileDetails) {
|
|
55
|
+
const byPath = new Map();
|
|
56
|
+
for (const detail of fileDetails) {
|
|
57
|
+
const key = normalizeMapKey(path.resolve(detail.filePath));
|
|
58
|
+
const previous = byPath.get(key);
|
|
59
|
+
if (!previous) {
|
|
60
|
+
byPath.set(key, detail);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
byPath.set(key, {
|
|
64
|
+
filePath: previous.filePath,
|
|
65
|
+
range: previous.range && detail.range
|
|
66
|
+
? {
|
|
67
|
+
start: Math.min(previous.range.start, detail.range.start),
|
|
68
|
+
end: Math.max(previous.range.end, detail.range.end),
|
|
69
|
+
}
|
|
70
|
+
: previous.range ?? detail.range,
|
|
71
|
+
importsChanged: previous.importsChanged || detail.importsChanged,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return files.map((filePath) => byPath.get(normalizeMapKey(path.resolve(filePath))) ?? {
|
|
75
|
+
filePath,
|
|
76
|
+
// Resource operations have no already-computed text range. A small
|
|
77
|
+
// range is still enough to invalidate the touched-file turn state;
|
|
78
|
+
// never synchronously re-read the whole file here.
|
|
79
|
+
range: { start: 1, end: 1 },
|
|
80
|
+
importsChanged: true,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function bookkeepLspMutation(context, files, fileDetails) {
|
|
84
|
+
const details = uniqueDetails(files, fileDetails);
|
|
85
|
+
for (const detail of details) {
|
|
86
|
+
const filePath = path.resolve(detail.filePath);
|
|
87
|
+
if (context.readGuard) {
|
|
88
|
+
try {
|
|
89
|
+
context.readGuard.recordWritten(filePath);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
context.dbg?.(`lsp mutation read-guard stamp failed for ${filePath}: ${err}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const runtime = context.runtime;
|
|
96
|
+
if (runtime?.bumpFileSeq) {
|
|
97
|
+
const { projectSeq, fileSeq } = runtime.bumpFileSeq(filePath);
|
|
98
|
+
try {
|
|
99
|
+
appendProjectChange(context.cwd, {
|
|
100
|
+
seq: projectSeq,
|
|
101
|
+
timestamp: new Date().toISOString(),
|
|
102
|
+
sessionId: runtime.telemetrySessionId ?? "unknown",
|
|
103
|
+
turnIndex: runtime.turnIndex ?? 0,
|
|
104
|
+
source: context.source,
|
|
105
|
+
filePath,
|
|
106
|
+
fileSeq,
|
|
107
|
+
changedRange: detail.range,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
context.dbg?.(`lsp mutation project change append failed for ${filePath}: ${err}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (context.cacheManager) {
|
|
115
|
+
try {
|
|
116
|
+
context.cacheManager.addModifiedRange(filePath, detail.range ?? { start: 1, end: 1 }, detail.importsChanged ?? true, context.cwd, runtime?.telemetrySessionId);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
context.dbg?.(`lsp mutation modified-range tracking failed for ${filePath}: ${err}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (context.recordAutofix && context.source === "autofix") {
|
|
123
|
+
const key = normalizeMapKey(filePath);
|
|
124
|
+
const seen = context.autofixRecordedPaths ?? new Set();
|
|
125
|
+
context.autofixRecordedPaths = seen;
|
|
126
|
+
if (!seen.has(key)) {
|
|
127
|
+
if (seen.size >= MAX_SAMPLES) {
|
|
128
|
+
const oldest = seen.values().next().value;
|
|
129
|
+
if (oldest)
|
|
130
|
+
seen.delete(oldest);
|
|
131
|
+
}
|
|
132
|
+
seen.add(key);
|
|
133
|
+
context.recordAutofix(filePath);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (context.publishFilesTouched && files.length > 0) {
|
|
138
|
+
context.publishFilesTouched(files);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function telemetryFor(context, options) {
|
|
142
|
+
const combined = combineResults(allResults(options));
|
|
143
|
+
const requestedTotal = options.requestedTotal ?? combined.requestedTotal;
|
|
144
|
+
const appliedTotal = combined.appliedTotal;
|
|
145
|
+
const requestedIndexes = Array.from({ length: Math.min(requestedTotal, MAX_SAMPLES) }, (_, index) => index);
|
|
146
|
+
const rejectedTotal = Math.max(0, requestedTotal - appliedTotal);
|
|
147
|
+
const rejectedReasons = Array.from({ length: Math.min(rejectedTotal, MAX_SAMPLES) }, (_, index) => ({ index, code: "write_failed" }));
|
|
148
|
+
const status = options.status ?? (appliedTotal > 0 ? "success" : "skipped");
|
|
149
|
+
const editBatchSummary = createReadGuardEditBatchSummary({
|
|
150
|
+
requestedIndexes,
|
|
151
|
+
requestedTotal,
|
|
152
|
+
resolvedIndexes: requestedIndexes,
|
|
153
|
+
resolvedTotal: requestedTotal,
|
|
154
|
+
rejectedReasons,
|
|
155
|
+
rejectedTotal,
|
|
156
|
+
appliedIndexes: combined.appliedIndexes,
|
|
157
|
+
appliedTotal,
|
|
158
|
+
participantIds: [context.correlationId],
|
|
159
|
+
participantTotal: 1,
|
|
160
|
+
commitStatus: status === "failed"
|
|
161
|
+
? "failed"
|
|
162
|
+
: appliedTotal > 0
|
|
163
|
+
? "committed"
|
|
164
|
+
: "no_changes",
|
|
165
|
+
terminalStatus: status,
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
editBatchSummary,
|
|
169
|
+
operationCounts: {
|
|
170
|
+
requested: requestedTotal,
|
|
171
|
+
applied: appliedTotal,
|
|
172
|
+
textEdits: combined.textEdits,
|
|
173
|
+
create: combined.create,
|
|
174
|
+
rename: combined.rename,
|
|
175
|
+
delete: combined.delete,
|
|
176
|
+
},
|
|
177
|
+
sampledPaths: combined.paths.slice(0, MAX_SAMPLES),
|
|
178
|
+
sampledPathsTotal: combined.paths.length,
|
|
179
|
+
sampledPathsTruncated: combined.paths.length > MAX_SAMPLES,
|
|
180
|
+
considered: options.considered,
|
|
181
|
+
completed: options.completed,
|
|
182
|
+
failedCount: options.failedCount,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export function recordLspMutation(context, options = {}) {
|
|
186
|
+
const results = allResults(options);
|
|
187
|
+
const combined = combineResults(results);
|
|
188
|
+
if (options.bookkeep !== false && combined.files.length > 0) {
|
|
189
|
+
bookkeepLspMutation(context, combined.files, combined.fileDetails);
|
|
190
|
+
}
|
|
191
|
+
const telemetry = telemetryFor(context, options);
|
|
192
|
+
if (context.emitSummary !== false) {
|
|
193
|
+
const summaryCount = context.summaryCount ?? 0;
|
|
194
|
+
context.summaryEmitted = true;
|
|
195
|
+
if (summaryCount < MAX_SUMMARIES_PER_CONTEXT) {
|
|
196
|
+
context.summaryCount = summaryCount + 1;
|
|
197
|
+
logReadGuardEvent({
|
|
198
|
+
event: "edit_batch_summary",
|
|
199
|
+
correlationId: context.correlationId,
|
|
200
|
+
filePath: combined.files[0] ?? context.cwd,
|
|
201
|
+
metadata: {
|
|
202
|
+
tool: context.tool,
|
|
203
|
+
source: context.source,
|
|
204
|
+
outcome: telemetry.editBatchSummary.terminalStatus,
|
|
205
|
+
// The outer correlation identifies the soliciting tool call; the
|
|
206
|
+
// bounded sequence distinguishes multiple applyEdit requests within it.
|
|
207
|
+
summaryIndex: summaryCount,
|
|
208
|
+
editBatchSummary: telemetry.editBatchSummary,
|
|
209
|
+
operationCounts: telemetry.operationCounts,
|
|
210
|
+
sampledPaths: telemetry.sampledPaths,
|
|
211
|
+
sampledPathsTotal: telemetry.sampledPathsTotal,
|
|
212
|
+
sampledPathsTruncated: telemetry.sampledPathsTruncated,
|
|
213
|
+
considered: telemetry.considered,
|
|
214
|
+
completed: telemetry.completed,
|
|
215
|
+
failedCount: telemetry.failedCount,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else if (!context.summaryOverflowed) {
|
|
220
|
+
context.summaryOverflowed = true;
|
|
221
|
+
logReadGuardEvent({
|
|
222
|
+
event: "edit_batch_summary_overflow",
|
|
223
|
+
correlationId: context.correlationId,
|
|
224
|
+
filePath: combined.files[0] ?? context.cwd,
|
|
225
|
+
metadata: {
|
|
226
|
+
tool: context.tool,
|
|
227
|
+
source: context.source,
|
|
228
|
+
summaryLimit: MAX_SUMMARIES_PER_CONTEXT,
|
|
229
|
+
suppressedSummaries: "one or more",
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return telemetry;
|
|
235
|
+
}
|
|
236
|
+
export function recordLspMutationBatch(context, options) {
|
|
237
|
+
const previous = context.emitSummary;
|
|
238
|
+
context.emitSummary = true;
|
|
239
|
+
try {
|
|
240
|
+
return recordLspMutation(context, options);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
context.emitSummary = previous;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
export function recordLspMutationOutcome(context, status) {
|
|
247
|
+
return recordLspMutation(context, { status, requestedTotal: 0 });
|
|
248
|
+
}
|