@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
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import * as nodeCrypto from "node:crypto";
|
|
2
2
|
import * as nodeFs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
|
|
4
|
+
import { extractReadPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
|
|
5
5
|
import { registerSearchReads, } from "./search-read-registration.js";
|
|
6
6
|
import { createFileTime } from "./file-time.js";
|
|
7
7
|
import { publishFormatQueued } from "./format-events-publish.js";
|
|
8
8
|
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
9
9
|
import { getFormatService } from "./format-service.js";
|
|
10
|
-
import { isExternalOrVendorFile } from "./path-utils.js";
|
|
10
|
+
import { isExternalOrVendorFile, normalizeEphemeralMapKey } from "./path-utils.js";
|
|
11
|
+
import { PathKeyedMap } from "./path-keyed-map.js";
|
|
11
12
|
import { resolveLanguageRootForFile } from "./language-profile.js";
|
|
12
13
|
import { logLatency } from "./latency-logger.js";
|
|
14
|
+
import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
|
|
13
15
|
import { runPipeline } from "./pipeline.js";
|
|
14
16
|
import { appendProjectChange, } from "./project-changes.js";
|
|
17
|
+
import { syncGitGuardRecord } from "./git-guard.js";
|
|
15
18
|
import { scheduleWordIndexPersist } from "./word-index.js";
|
|
19
|
+
import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
20
|
+
const AUTHORITATIVE_CONTENT_MAX_BYTES = RUNTIME_CONFIG.pipeline.lspMaxFileBytes;
|
|
16
21
|
function parseDiffRanges(diff) {
|
|
17
22
|
const changedLines = [];
|
|
18
23
|
for (const line of diff.split("\n")) {
|
|
@@ -40,19 +45,23 @@ function parseDiffRanges(diff) {
|
|
|
40
45
|
ranges.push({ start: rangeStart, end: rangeEnd });
|
|
41
46
|
return ranges;
|
|
42
47
|
}
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// Keyed by (normalized) filePath, then by the raw stateHash — the path portion
|
|
49
|
+
// needs normalizing (divergent Windows spellings must collapse to one entry),
|
|
50
|
+
// the stateHash suffix must NOT be folded into the path key (a real content
|
|
51
|
+
// change for the same file has to stay a distinct entry). A flat
|
|
52
|
+
// `PathKeyedMap<InFlightPipeline>` keyed by a composite `${filePath}:${hash}`
|
|
53
|
+
// string can't express that split cleanly (the normalizer only sees the whole
|
|
54
|
+
// composite string, so it can't fold the path half without also mangling the
|
|
55
|
+
// hash half); nesting keeps each axis normalized/compared with its own rules.
|
|
56
|
+
const inFlightPipelines = new PathKeyedMap(normalizeEphemeralMapKey);
|
|
57
|
+
const lastAnalyzedStateByFile = new PathKeyedMap(normalizeEphemeralMapKey);
|
|
49
58
|
// Called at turn_start — entries from the previous turn can never match the new
|
|
50
59
|
// turnIndex so they're dead weight. Clearing here keeps the map bounded to the
|
|
51
60
|
// files touched in the current turn only (typically < 20).
|
|
52
61
|
export function clearLastAnalyzedStateCache() {
|
|
53
62
|
lastAnalyzedStateByFile.clear();
|
|
54
63
|
}
|
|
55
|
-
const debouncedPipelines = new
|
|
64
|
+
const debouncedPipelines = new PathKeyedMap(normalizeEphemeralMapKey);
|
|
56
65
|
const DEFAULT_DEBOUNCE_MS = 0;
|
|
57
66
|
const MAX_DEBOUNCE_MS = 1000;
|
|
58
67
|
function getDebounceMs() {
|
|
@@ -98,7 +107,13 @@ function scheduleDebounced(filePath, debounceMs, deps) {
|
|
|
98
107
|
const existing = debouncedPipelines.get(filePath);
|
|
99
108
|
if (existing) {
|
|
100
109
|
clearTimeout(existing.timer);
|
|
101
|
-
|
|
110
|
+
const incomingId = deps._telemetryParticipantIds?.[0] ?? getReadGuardCorrelationId(deps.event);
|
|
111
|
+
const priorIds = existing.latestDeps._telemetryParticipantIds ?? [];
|
|
112
|
+
existing.latestDeps = {
|
|
113
|
+
...deps,
|
|
114
|
+
_telemetryParticipantIds: [...priorIds, incomingId].slice(0, 100),
|
|
115
|
+
_telemetryParticipantTotal: (existing.latestDeps._telemetryParticipantTotal ?? priorIds.length) + 1,
|
|
116
|
+
};
|
|
102
117
|
existing.coalescedCount += 1;
|
|
103
118
|
existing.timer = setTimeout(() => {
|
|
104
119
|
debouncedPipelines.delete(filePath);
|
|
@@ -114,6 +129,7 @@ function scheduleDebounced(filePath, debounceMs, deps) {
|
|
|
114
129
|
resolveFn = res;
|
|
115
130
|
rejectFn = rej;
|
|
116
131
|
});
|
|
132
|
+
const initialParticipantIds = deps._telemetryParticipantIds ?? [getReadGuardCorrelationId(deps.event)];
|
|
117
133
|
const entry = {
|
|
118
134
|
timer: setTimeout(() => {
|
|
119
135
|
debouncedPipelines.delete(filePath);
|
|
@@ -122,7 +138,11 @@ function scheduleDebounced(filePath, debounceMs, deps) {
|
|
|
122
138
|
promise,
|
|
123
139
|
resolve: resolveFn,
|
|
124
140
|
reject: rejectFn,
|
|
125
|
-
latestDeps:
|
|
141
|
+
latestDeps: {
|
|
142
|
+
...deps,
|
|
143
|
+
_telemetryParticipantIds: initialParticipantIds.slice(0, 100),
|
|
144
|
+
_telemetryParticipantTotal: deps._telemetryParticipantTotal ?? initialParticipantIds.length,
|
|
145
|
+
},
|
|
126
146
|
scheduledAt: Date.now(),
|
|
127
147
|
coalescedCount: 1,
|
|
128
148
|
};
|
|
@@ -139,6 +159,15 @@ function getFileStateHash(filePath) {
|
|
|
139
159
|
return `unreadable:${code}`;
|
|
140
160
|
}
|
|
141
161
|
}
|
|
162
|
+
function getRequestedEditCount(event) {
|
|
163
|
+
if (event.toolName === "write")
|
|
164
|
+
return 1;
|
|
165
|
+
const edits = event.input?.edits;
|
|
166
|
+
return Array.isArray(edits) && edits.length > 0 ? edits.length : 1;
|
|
167
|
+
}
|
|
168
|
+
function getRequestedEditIndexes(event) {
|
|
169
|
+
return boundedIndexesForCount(getRequestedEditCount(event));
|
|
170
|
+
}
|
|
142
171
|
function sourceForToolName(toolName, details) {
|
|
143
172
|
if (details
|
|
144
173
|
?.piLensPartialApply) {
|
|
@@ -180,6 +209,8 @@ export async function handleToolResult(deps) {
|
|
|
180
209
|
: path.resolve(workspaceRoot, rawFilePath)
|
|
181
210
|
: rawFilePath;
|
|
182
211
|
const behaviorWarnings = agentBehaviorRecord(event.toolName, filePath);
|
|
212
|
+
const syntheticWriteContent = [];
|
|
213
|
+
let syntheticAttachmentBytes = 0;
|
|
183
214
|
// Bash writes (redirects, tee, sed -i, cp/mv, touch, git checkout/restore) —
|
|
184
215
|
// these change file content but never go through the edit tool, so bash
|
|
185
216
|
// early-returns before the dispatch pipeline below. For each in-project file
|
|
@@ -191,23 +222,91 @@ export async function handleToolResult(deps) {
|
|
|
191
222
|
if (event.toolName === "bash" &&
|
|
192
223
|
typeof event.input.command === "string") {
|
|
193
224
|
const command = event.input.command;
|
|
194
|
-
const written = extractWrittenPathsFromCommand(command, workspaceRoot).filter((wp) =>
|
|
225
|
+
const written = extractWrittenPathsFromCommand(command, workspaceRoot).filter((wp) => event.isError !== true &&
|
|
226
|
+
!isExternalOrVendorFile(wp, workspaceRoot) &&
|
|
195
227
|
!isPathIgnoredByProject(wp, workspaceRoot, false));
|
|
196
228
|
for (const wp of written) {
|
|
197
229
|
if (!getFlag("no-read-guard"))
|
|
198
230
|
deps.readGuard?.recordWritten(wp);
|
|
199
|
-
|
|
231
|
+
const receipt = runtime.recordMutationToolReceipt;
|
|
232
|
+
const autofixMode = receipt
|
|
233
|
+
? receipt.call(runtime, wp, "write").autofixMode
|
|
234
|
+
: "immediate";
|
|
235
|
+
const syntheticResult = await handleToolResult({
|
|
200
236
|
...deps,
|
|
201
237
|
event: { ...event, toolName: "write", input: { path: wp } },
|
|
202
238
|
_bypassDebounce: true,
|
|
239
|
+
_autofixMode: autofixMode,
|
|
203
240
|
});
|
|
241
|
+
if (syntheticResult) {
|
|
242
|
+
// The per-attachment cap bounds each file, but a multi-file bash
|
|
243
|
+
// write (`sed -i` over globs, `;`-chained rewrites) appends one
|
|
244
|
+
// attachment per path — share ONE authoritative-content budget
|
|
245
|
+
// across the whole command so the aggregate tool result stays
|
|
246
|
+
// bounded too. Past the budget, degrade to the re-read warning.
|
|
247
|
+
for (const block of syntheticResult.content.slice(event.content.length)) {
|
|
248
|
+
const blockBytes = typeof block.text === "string"
|
|
249
|
+
? Buffer.byteLength(block.text, "utf-8")
|
|
250
|
+
: 0;
|
|
251
|
+
const isAuthoritativeAttachment = typeof block.text === "string" &&
|
|
252
|
+
block.text.startsWith("pi-lens applied autofix to ");
|
|
253
|
+
if (isAuthoritativeAttachment &&
|
|
254
|
+
syntheticAttachmentBytes + blockBytes >
|
|
255
|
+
AUTHORITATIVE_CONTENT_MAX_BYTES) {
|
|
256
|
+
// S3e (#1432 review): this is the SECOND
|
|
257
|
+
// `authoritative_content_attachment_decision` row for `wp` —
|
|
258
|
+
// the synthetic `handleToolResult` call above already logged
|
|
259
|
+
// an "attached" row for the same path under its per-file
|
|
260
|
+
// cap. This outer, aggregate-budget row is logged later and
|
|
261
|
+
// is the one that matches what the caller actually sees
|
|
262
|
+
// (the re-read warning below, not the attachment), so it
|
|
263
|
+
// wins for `wp`; the inner "attached" row is a stale
|
|
264
|
+
// per-file view superseded by this shared-budget decision.
|
|
265
|
+
logLatency({
|
|
266
|
+
type: "phase",
|
|
267
|
+
phase: "authoritative_content_attachment_decision",
|
|
268
|
+
filePath: wp,
|
|
269
|
+
durationMs: 0,
|
|
270
|
+
metadata: { path: wp, bytes: blockBytes, decision: "aggregate-budget-degraded" },
|
|
271
|
+
});
|
|
272
|
+
syntheticWriteContent.push({
|
|
273
|
+
type: "text",
|
|
274
|
+
text: `⚠️ **File was modified by auto-format/fix. You MUST re-read ${wp} before making any further edits — the aggregate authoritative content for this command is too large to attach.**`,
|
|
275
|
+
});
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (isAuthoritativeAttachment) {
|
|
279
|
+
syntheticAttachmentBytes += blockBytes;
|
|
280
|
+
}
|
|
281
|
+
syntheticWriteContent.push(block);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (event.isError !== true && !getFlag("no-read-guard")) {
|
|
286
|
+
for (const span of extractReadPathsFromCommand(command, workspaceRoot)) {
|
|
287
|
+
if (isExternalOrVendorFile(span.filePath, workspaceRoot))
|
|
288
|
+
continue;
|
|
289
|
+
if (isPathIgnoredByProject(span.filePath, workspaceRoot, false))
|
|
290
|
+
continue;
|
|
291
|
+
deps.readGuard?.recordRead({
|
|
292
|
+
filePath: span.filePath,
|
|
293
|
+
requestedOffset: span.offset,
|
|
294
|
+
requestedLimit: span.limit,
|
|
295
|
+
effectiveOffset: span.offset,
|
|
296
|
+
effectiveLimit: span.limit,
|
|
297
|
+
expandedByLsp: false,
|
|
298
|
+
turnIndex: runtime.turnIndex,
|
|
299
|
+
writeIndex: runtime.peekWriteIndex(),
|
|
300
|
+
timestamp: Date.now(),
|
|
301
|
+
});
|
|
302
|
+
}
|
|
204
303
|
}
|
|
205
304
|
}
|
|
206
305
|
// Search tools reveal specific lines (file:line) the agent then edits — register
|
|
207
306
|
// those shown lines (± context) as reads so the follow-up edit isn't blocked (#169).
|
|
208
307
|
// Our tools attach locations as `details.searchReads`; bash grep is parsed from
|
|
209
308
|
// `grep -n` output. Only shown lines are registered, never the whole file.
|
|
210
|
-
if (deps.readGuard && !getFlag("no-read-guard")) {
|
|
309
|
+
if (deps.readGuard && event.isError !== true && !getFlag("no-read-guard")) {
|
|
211
310
|
const searchReads = [];
|
|
212
311
|
const detailSearchReads = event.details?.searchReads;
|
|
213
312
|
if (Array.isArray(detailSearchReads))
|
|
@@ -230,7 +329,9 @@ export async function handleToolResult(deps) {
|
|
|
230
329
|
}
|
|
231
330
|
if (event.toolName !== "write" && event.toolName !== "edit") {
|
|
232
331
|
dbg(`tool_result: skipped turn tracking - toolName="${event.toolName}" (not write/edit)`);
|
|
233
|
-
return
|
|
332
|
+
return syntheticWriteContent.length > 0
|
|
333
|
+
? { content: [...event.content, ...syntheticWriteContent] }
|
|
334
|
+
: undefined;
|
|
234
335
|
}
|
|
235
336
|
if (!filePath) {
|
|
236
337
|
dbg(`tool_result: skipped turn tracking - no filePath for toolName="${event.toolName}"`);
|
|
@@ -240,13 +341,65 @@ export async function handleToolResult(deps) {
|
|
|
240
341
|
dbg(`tool_result: skipped pipeline - file outside project root or in node_modules: ${filePath}`);
|
|
241
342
|
return;
|
|
242
343
|
}
|
|
344
|
+
const readGuardCorrelationId = getReadGuardCorrelationId(event);
|
|
345
|
+
const resultDetails = (event.details ?? {});
|
|
346
|
+
const isPartialApplyResult = resultDetails.piLensPartialApply === true;
|
|
347
|
+
const requestedEditIndexes = getRequestedEditIndexes(event);
|
|
348
|
+
const requestedEditTotal = getRequestedEditCount(event);
|
|
349
|
+
const participantIds = [
|
|
350
|
+
...(deps._telemetryParticipantIds ?? []),
|
|
351
|
+
readGuardCorrelationId,
|
|
352
|
+
].slice(0, 100);
|
|
353
|
+
const participantTotal = (deps._telemetryParticipantTotal ?? 0) +
|
|
354
|
+
(deps._telemetryParticipantIds?.includes(readGuardCorrelationId) ? 0 : 1);
|
|
355
|
+
const hostToolResultFailed = event.isError === true || resultDetails.isError === true;
|
|
356
|
+
if (hostToolResultFailed) {
|
|
357
|
+
logReadGuardEvent({
|
|
358
|
+
event: "edit_batch_summary",
|
|
359
|
+
correlationId: readGuardCorrelationId,
|
|
360
|
+
filePath,
|
|
361
|
+
metadata: {
|
|
362
|
+
tool: event.toolName,
|
|
363
|
+
source: "host_tool_result",
|
|
364
|
+
editBatchSummary: createReadGuardEditBatchSummary({
|
|
365
|
+
requestedIndexes: requestedEditIndexes,
|
|
366
|
+
requestedTotal: requestedEditTotal,
|
|
367
|
+
rejectedReasons: requestedEditIndexes.map((index) => ({
|
|
368
|
+
index,
|
|
369
|
+
code: "write_failed",
|
|
370
|
+
})),
|
|
371
|
+
rejectedTotal: requestedEditTotal,
|
|
372
|
+
participantIds: [readGuardCorrelationId],
|
|
373
|
+
participantTotal: 1,
|
|
374
|
+
commitStatus: "failed",
|
|
375
|
+
terminalStatus: "failed",
|
|
376
|
+
}),
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
return { content: event.content, isError: true };
|
|
380
|
+
}
|
|
381
|
+
// Must happen before debounce admission: latestDeps intentionally retains only
|
|
382
|
+
// the latest event, but write -> edit is a sticky turn transition.
|
|
383
|
+
const receipt = runtime.recordMutationToolReceipt;
|
|
384
|
+
const autofixMode = deps._bypassDebounce
|
|
385
|
+
? (deps._autofixMode ?? (event.toolName === "edit" ? "deferred" : "immediate"))
|
|
386
|
+
: receipt
|
|
387
|
+
? receipt.call(runtime, filePath, event.toolName).autofixMode
|
|
388
|
+
: event.toolName === "edit"
|
|
389
|
+
? "deferred"
|
|
390
|
+
: "immediate";
|
|
243
391
|
// Coalesce sequential edits to the same file into one pipeline run against
|
|
244
392
|
// the final state. Only the debounce-fired call (with _bypassDebounce=true)
|
|
245
393
|
// proceeds to the pipeline body; in-window callers share its promise.
|
|
246
394
|
if (!deps._bypassDebounce) {
|
|
247
395
|
const debounceMs = getDebounceMs();
|
|
248
396
|
if (debounceMs > 0) {
|
|
249
|
-
return scheduleDebounced(filePath, debounceMs,
|
|
397
|
+
return scheduleDebounced(filePath, debounceMs, {
|
|
398
|
+
...deps,
|
|
399
|
+
_autofixMode: autofixMode,
|
|
400
|
+
_telemetryParticipantIds: [readGuardCorrelationId],
|
|
401
|
+
_telemetryParticipantTotal: 1,
|
|
402
|
+
});
|
|
250
403
|
}
|
|
251
404
|
}
|
|
252
405
|
// Refresh the read-guard's FileTime stamp so that the model's own write
|
|
@@ -275,13 +428,18 @@ export async function handleToolResult(deps) {
|
|
|
275
428
|
}
|
|
276
429
|
}
|
|
277
430
|
const initialStateHash = getFileStateHash(filePath);
|
|
278
|
-
const pipelineDedupeKey = `${filePath}:${initialStateHash}`;
|
|
279
431
|
// Deduplicate concurrent calls for the same final file state (pi can fire one
|
|
280
432
|
// tool_result per edit hunk). Do not dedupe by file alone: a distinct later
|
|
281
433
|
// same-turn edit to this file must still be analyzed.
|
|
282
|
-
|
|
434
|
+
const inFlight = inFlightPipelines.get(filePath)?.get(initialStateHash);
|
|
435
|
+
if (inFlight) {
|
|
283
436
|
dbg(`tool_result: skipping duplicate concurrent state for ${filePath}`);
|
|
284
|
-
|
|
437
|
+
const duplicateId = readGuardCorrelationId;
|
|
438
|
+
if (inFlight.participantIds.length < 100) {
|
|
439
|
+
inFlight.participantIds.push(duplicateId);
|
|
440
|
+
}
|
|
441
|
+
inFlight.participantTotal += 1;
|
|
442
|
+
await inFlight.promise;
|
|
285
443
|
return;
|
|
286
444
|
}
|
|
287
445
|
// Deduplicate sequential duplicate events for the same post-write state in the
|
|
@@ -319,6 +477,13 @@ export async function handleToolResult(deps) {
|
|
|
319
477
|
const writeIndex = runtime.nextWriteIndex();
|
|
320
478
|
let modifiedRanges;
|
|
321
479
|
try {
|
|
480
|
+
// #1334 S6: the host DECLARES this payload (`EditToolDetails`, a
|
|
481
|
+
// type-only export), so use it instead of re-declaring `{ diff?: string }`
|
|
482
|
+
// here — the ad-hoc shape hid the sibling `patch`/`firstChangedLine`
|
|
483
|
+
// fields. `Partial<>` keeps the defensive posture: the host types mark
|
|
484
|
+
// `diff` required, but this runs against whatever a live host actually
|
|
485
|
+
// sent, and the `details?.diff` truthiness check below is what the code
|
|
486
|
+
// has always relied on.
|
|
322
487
|
const details = event.details;
|
|
323
488
|
dbg(`tool_result: details.diff=${details?.diff ? "present" : "missing"}, details keys: ${Object.keys(event.details || {}).join(", ")}`);
|
|
324
489
|
if (event.toolName === "edit" && details?.diff) {
|
|
@@ -367,13 +532,17 @@ export async function handleToolResult(deps) {
|
|
|
367
532
|
const pipelinePromise = runPipeline({
|
|
368
533
|
filePath,
|
|
369
534
|
cwd: dispatchCwd,
|
|
535
|
+
projectRoot: turnStateCwd,
|
|
370
536
|
toolName: event.toolName,
|
|
537
|
+
autofixMode,
|
|
371
538
|
modifiedRanges,
|
|
372
539
|
telemetry: {
|
|
373
540
|
model: runtime.telemetryModel,
|
|
374
541
|
sessionId: runtime.telemetrySessionId,
|
|
375
542
|
turnIndex: runtime.turnIndex,
|
|
376
543
|
writeIndex,
|
|
544
|
+
modelId: runtime.telemetryModelId,
|
|
545
|
+
provider: runtime.telemetryProviderId,
|
|
377
546
|
},
|
|
378
547
|
getFlag,
|
|
379
548
|
getFlagSource,
|
|
@@ -404,12 +573,57 @@ export async function handleToolResult(deps) {
|
|
|
404
573
|
getFormatService,
|
|
405
574
|
fixedThisTurn: runtime.fixedThisTurn,
|
|
406
575
|
});
|
|
407
|
-
|
|
576
|
+
const pipelineTelemetry = {
|
|
577
|
+
promise: pipelinePromise,
|
|
578
|
+
participantIds: [...new Set(participantIds)].slice(0, 100),
|
|
579
|
+
participantTotal,
|
|
580
|
+
};
|
|
581
|
+
let filePipelines = inFlightPipelines.get(filePath);
|
|
582
|
+
if (!filePipelines) {
|
|
583
|
+
filePipelines = new Map();
|
|
584
|
+
inFlightPipelines.set(filePath, filePipelines);
|
|
585
|
+
}
|
|
586
|
+
filePipelines.set(initialStateHash, pipelineTelemetry);
|
|
408
587
|
try {
|
|
409
588
|
result = await pipelinePromise;
|
|
410
589
|
}
|
|
411
590
|
catch (pipelineErr) {
|
|
591
|
+
if (getFlag("lens-guard")) {
|
|
592
|
+
runtime.markGitGuardCacheUnknown("pipeline_crash");
|
|
593
|
+
}
|
|
412
594
|
dbg(`runPipeline crashed: ${pipelineErr}`);
|
|
595
|
+
logReadGuardEvent({
|
|
596
|
+
event: "edit_post_edit_pipeline_failed",
|
|
597
|
+
correlationId: readGuardCorrelationId,
|
|
598
|
+
filePath,
|
|
599
|
+
metadata: {
|
|
600
|
+
tool: event.toolName,
|
|
601
|
+
commitStatus: "committed",
|
|
602
|
+
reasonCode: "pipeline_failed",
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
logReadGuardEvent({
|
|
606
|
+
event: "edit_batch_summary",
|
|
607
|
+
correlationId: readGuardCorrelationId,
|
|
608
|
+
filePath,
|
|
609
|
+
metadata: {
|
|
610
|
+
tool: event.toolName,
|
|
611
|
+
editBatchSummary: createReadGuardEditBatchSummary({
|
|
612
|
+
requestedIndexes: requestedEditIndexes,
|
|
613
|
+
requestedTotal: requestedEditTotal,
|
|
614
|
+
resolvedIndexes: requestedEditIndexes,
|
|
615
|
+
resolvedTotal: requestedEditTotal,
|
|
616
|
+
appliedIndexes: requestedEditIndexes,
|
|
617
|
+
appliedTotal: requestedEditTotal,
|
|
618
|
+
participantIds: pipelineTelemetry.participantIds,
|
|
619
|
+
participantTotal: pipelineTelemetry.participantTotal,
|
|
620
|
+
commitStatus: "committed",
|
|
621
|
+
postEditStatus: "failed",
|
|
622
|
+
terminalStatus: "failed",
|
|
623
|
+
durationMs: Date.now() - toolResultStart,
|
|
624
|
+
}),
|
|
625
|
+
},
|
|
626
|
+
});
|
|
413
627
|
dbg(`runPipeline crash stack: ${pipelineErr.stack}`);
|
|
414
628
|
if (!getFlag("no-lsp")) {
|
|
415
629
|
resetLSPService({ fast: true, reason: "pipeline_crash" });
|
|
@@ -422,14 +636,57 @@ export async function handleToolResult(deps) {
|
|
|
422
636
|
result: "pipeline_crash",
|
|
423
637
|
});
|
|
424
638
|
const notice = runtime.formatPipelineCrashNotice(filePath, pipelineErr);
|
|
425
|
-
if (!notice)
|
|
426
|
-
return;
|
|
427
639
|
return {
|
|
428
|
-
content:
|
|
640
|
+
content: notice
|
|
641
|
+
? [...event.content, { type: "text", text: notice }]
|
|
642
|
+
: event.content,
|
|
643
|
+
isError: true,
|
|
429
644
|
};
|
|
430
645
|
}
|
|
431
646
|
finally {
|
|
432
|
-
|
|
647
|
+
// Prune the per-file inner map once it's empty so a file touched once
|
|
648
|
+
// this session doesn't leave a permanent empty entry in the outer map.
|
|
649
|
+
filePipelines.delete(initialStateHash);
|
|
650
|
+
if (filePipelines.size === 0) {
|
|
651
|
+
inFlightPipelines.delete(filePath);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (!isPartialApplyResult) {
|
|
655
|
+
const postEditStatus = result.isError ? "failed" : "succeeded";
|
|
656
|
+
if (result.isError) {
|
|
657
|
+
logReadGuardEvent({
|
|
658
|
+
event: "edit_post_edit_pipeline_failed",
|
|
659
|
+
correlationId: readGuardCorrelationId,
|
|
660
|
+
filePath,
|
|
661
|
+
metadata: {
|
|
662
|
+
tool: event.toolName,
|
|
663
|
+
commitStatus: "committed",
|
|
664
|
+
reasonCode: "pipeline_failed",
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
logReadGuardEvent({
|
|
669
|
+
event: "edit_batch_summary",
|
|
670
|
+
correlationId: readGuardCorrelationId,
|
|
671
|
+
filePath,
|
|
672
|
+
metadata: {
|
|
673
|
+
tool: event.toolName,
|
|
674
|
+
editBatchSummary: createReadGuardEditBatchSummary({
|
|
675
|
+
requestedIndexes: requestedEditIndexes,
|
|
676
|
+
requestedTotal: requestedEditTotal,
|
|
677
|
+
resolvedIndexes: requestedEditIndexes,
|
|
678
|
+
resolvedTotal: requestedEditTotal,
|
|
679
|
+
appliedIndexes: requestedEditIndexes,
|
|
680
|
+
appliedTotal: requestedEditTotal,
|
|
681
|
+
participantIds: pipelineTelemetry.participantIds,
|
|
682
|
+
participantTotal: pipelineTelemetry.participantTotal,
|
|
683
|
+
commitStatus: "committed",
|
|
684
|
+
postEditStatus,
|
|
685
|
+
terminalStatus: postEditStatus === "failed" ? "failed" : "success",
|
|
686
|
+
durationMs: Date.now() - toolResultStart,
|
|
687
|
+
}),
|
|
688
|
+
},
|
|
689
|
+
});
|
|
433
690
|
}
|
|
434
691
|
lastAnalyzedStateByFile.set(filePath, {
|
|
435
692
|
turnIndex: runtime.turnIndex,
|
|
@@ -449,11 +706,19 @@ export async function handleToolResult(deps) {
|
|
|
449
706
|
}
|
|
450
707
|
}
|
|
451
708
|
}
|
|
709
|
+
let autofixNewlyQueued = false;
|
|
710
|
+
if (!result.isError && autofixMode === "deferred" && nodeFs.existsSync(filePath)) {
|
|
711
|
+
autofixNewlyQueued =
|
|
712
|
+
runtime.deferMutation?.call(runtime, filePath, dispatchCwd, event.toolName, turnStateCwd, "autofix", deps.sessionId) ?? false;
|
|
713
|
+
dbg(`tool_result: queued deferred autofix for ${filePath}`);
|
|
714
|
+
}
|
|
715
|
+
let formatQueued = false;
|
|
452
716
|
if (!result.isError &&
|
|
453
717
|
!getFlag("no-autoformat", filePath) &&
|
|
454
|
-
!getFlag("immediate-format") &&
|
|
718
|
+
(autofixMode === "deferred" || !getFlag("immediate-format")) &&
|
|
455
719
|
nodeFs.existsSync(filePath)) {
|
|
456
720
|
const isNewlyQueued = runtime.deferFormat(filePath, dispatchCwd, event.toolName, turnStateCwd, deps.sessionId);
|
|
721
|
+
formatQueued = true;
|
|
457
722
|
dbg(`tool_result: queued deferred format for ${filePath}`);
|
|
458
723
|
logLatency({
|
|
459
724
|
type: "phase",
|
|
@@ -463,19 +728,21 @@ export async function handleToolResult(deps) {
|
|
|
463
728
|
durationMs: 0,
|
|
464
729
|
metadata: { cwd: dispatchCwd },
|
|
465
730
|
});
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
// queue", so re-emitting would be spam with zero new information.
|
|
470
|
-
if (isNewlyQueued) {
|
|
731
|
+
// Publish a file's first queue entry and each newly added kind. A same-kind
|
|
732
|
+
// re-touch before agent_end carries no new information and stays silent.
|
|
733
|
+
if (isNewlyQueued || autofixNewlyQueued) {
|
|
471
734
|
publishFormatQueued({
|
|
472
735
|
filePath,
|
|
473
736
|
cwd: dispatchCwd,
|
|
474
737
|
tool: event.toolName,
|
|
475
738
|
dbg,
|
|
739
|
+
kinds: autofixMode === "deferred" ? ["autofix", "format"] : ["format"],
|
|
476
740
|
});
|
|
477
741
|
}
|
|
478
742
|
}
|
|
743
|
+
if (autofixNewlyQueued && !formatQueued) {
|
|
744
|
+
publishFormatQueued({ filePath, cwd: dispatchCwd, tool: event.toolName, kinds: ["autofix"], dbg });
|
|
745
|
+
}
|
|
479
746
|
for (const changedFile of result.changedFiles ?? []) {
|
|
480
747
|
const resolvedChanged = path.resolve(changedFile);
|
|
481
748
|
if (!nodeFs.existsSync(resolvedChanged))
|
|
@@ -549,6 +816,13 @@ export async function handleToolResult(deps) {
|
|
|
549
816
|
else {
|
|
550
817
|
runtime.clearInlineBlockers(filePath);
|
|
551
818
|
}
|
|
819
|
+
runtime.updateGitGuardStatus(result.hasBlockers, result.output);
|
|
820
|
+
if (getFlag("lens-guard")) {
|
|
821
|
+
syncGitGuardRecord(runtime, cacheManager, turnStateCwd, filePath);
|
|
822
|
+
if (result.isError && !result.hasBlockers) {
|
|
823
|
+
runtime.markGitGuardCacheUnknown("pipeline_error");
|
|
824
|
+
}
|
|
825
|
+
}
|
|
552
826
|
if (result.isError) {
|
|
553
827
|
return {
|
|
554
828
|
content: [...event.content, { type: "text", text: result.output }],
|
|
@@ -556,7 +830,6 @@ export async function handleToolResult(deps) {
|
|
|
556
830
|
};
|
|
557
831
|
}
|
|
558
832
|
let output = result.output;
|
|
559
|
-
runtime.updateGitGuardStatus(result.hasBlockers, result.output);
|
|
560
833
|
if (behaviorWarnings.length > 0 && !result.hasBlockers) {
|
|
561
834
|
output += `\n\n${formatBehaviorWarnings(behaviorWarnings)}`;
|
|
562
835
|
}
|
|
@@ -569,9 +842,45 @@ export async function handleToolResult(deps) {
|
|
|
569
842
|
result: output ? "completed" : "no_output",
|
|
570
843
|
});
|
|
571
844
|
runtime.reportedThisTurn.add(filePath);
|
|
572
|
-
|
|
845
|
+
const postMutation = result.postMutation;
|
|
846
|
+
const attachAuthoritativeContent = postMutation !== undefined &&
|
|
847
|
+
Buffer.byteLength(postMutation.content, "utf-8") <= AUTHORITATIVE_CONTENT_MAX_BYTES;
|
|
848
|
+
if (postMutation) {
|
|
849
|
+
const bytes = Buffer.byteLength(postMutation.content, "utf-8");
|
|
850
|
+
// S3e (#1432 review): when this call is the synthetic per-file
|
|
851
|
+
// `handleToolResult` recursion a multi-file bash write drives (see the
|
|
852
|
+
// bash branch above), the OUTER aggregate-budget loop may log a SECOND
|
|
853
|
+
// `authoritative_content_attachment_decision` row for this same
|
|
854
|
+
// `filePath` right after this one, downgrading an "attached" here to
|
|
855
|
+
// "aggregate-budget-degraded" once the shared budget is exhausted.
|
|
856
|
+
// Both rows are intentional (this one reflects the per-file cap
|
|
857
|
+
// decision; the outer one reflects the aggregate-budget decision that
|
|
858
|
+
// can override it) — the outer row, logged later, wins for that path.
|
|
859
|
+
logLatency({
|
|
860
|
+
type: "phase",
|
|
861
|
+
phase: "authoritative_content_attachment_decision",
|
|
862
|
+
filePath: postMutation.filePath,
|
|
863
|
+
durationMs: 0,
|
|
864
|
+
metadata: { path: postMutation.filePath, bytes, decision: attachAuthoritativeContent ? "attached" : "size-capped" },
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
const returnedContent = attachAuthoritativeContent
|
|
868
|
+
? [
|
|
869
|
+
...event.content,
|
|
870
|
+
{
|
|
871
|
+
type: "text",
|
|
872
|
+
text: `pi-lens applied autofix to ${postMutation.filePath}. The following full content is authoritative for subsequent edits:\n\n${postMutation.content}`,
|
|
873
|
+
},
|
|
874
|
+
]
|
|
875
|
+
: event.content;
|
|
876
|
+
if (postMutation && !attachAuthoritativeContent) {
|
|
877
|
+
output = `${output ? `${output}\n\n` : ""}⚠️ **File was modified by auto-format/fix. You MUST re-read ${postMutation.filePath} before making any further edits — the authoritative content is too large to attach.**`;
|
|
878
|
+
}
|
|
879
|
+
if (!output && !result.postMutation)
|
|
573
880
|
return;
|
|
574
881
|
return {
|
|
575
|
-
content:
|
|
882
|
+
content: output
|
|
883
|
+
? [...returnedContent, { type: "text", text: output }]
|
|
884
|
+
: returnedContent,
|
|
576
885
|
};
|
|
577
886
|
}
|