@herbertgao/pi-extensions 2026.8.4 → 2026.8.5
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 +4 -4
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
- 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/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 +5 -8
- 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 +8 -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 +15 -2
- 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/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -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 +8 -7
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
- package/node_modules/pi-lens/CHANGELOG.md +2440 -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/agent-behavior-client.js +21 -4
- 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 +29 -25
- 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-publish.js +10 -3
- 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/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 +14 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
- 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 +347 -75
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
- 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 +1085 -681
- 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 +14 -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/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -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 +10 -3
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +139 -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/format-events-publish.js +16 -3
- 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 +681 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
- 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 +390 -99
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
- package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
- 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 +23 -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 +27 -4
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
- 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 +196 -32
- 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 +123 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
- 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/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 +47 -13
- 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/runner-adapters/call-graph-impact.js +8 -0
- 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/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/runtime-agent-end.js +107 -73
- package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -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 +218 -23
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
- package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -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 +1 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -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 +33 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +49361 -36888
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +211 -44
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
- 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/docs/agent-guide.md +2 -2
- 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 +5 -2
- 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 +31 -2
- package/node_modules/pi-lens/docs/globalconfig.md +45 -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 +12 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +18 -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-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-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-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-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 +55 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
- package/node_modules/pi-mcp-adapter/README.md +34 -3
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
- 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/metadata-cache.ts +27 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +3 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +36 -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 +42 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +93 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/package.json +11 -12
- 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
|
@@ -4,8 +4,11 @@ import { applyConservativeActionableWarningFixes, checkActionableWarningsReportF
|
|
|
4
4
|
import { publishFilesTouched } from "./bus-publish.js";
|
|
5
5
|
import { publishAutofixStart, publishFormatStart, } from "./format-events-publish.js";
|
|
6
6
|
import { logLatency } from "./latency-logger.js";
|
|
7
|
+
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
8
|
+
import { newLspMutationCorrelationId } from "./lsp-mutation.js";
|
|
7
9
|
import { getGlobalActionableWarningMaxFixes, } from "./lens-config.js";
|
|
8
10
|
import { resyncLspFile, runFormatPhase } from "./pipeline.js";
|
|
11
|
+
import { getAmbientAbortSignal } from "./safe-spawn.js";
|
|
9
12
|
import { appendProjectChange, } from "./project-changes.js";
|
|
10
13
|
/**
|
|
11
14
|
* A queued file is claimed by any flush once it has sat unclaimed by its own
|
|
@@ -16,6 +19,7 @@ import { appendProjectChange, } from "./project-changes.js";
|
|
|
16
19
|
* extra staleness for guaranteed eventual formatting. (#791)
|
|
17
20
|
*/
|
|
18
21
|
export const DEFERRED_FORMAT_STALE_AFTER_MS = 10 * 60_000;
|
|
22
|
+
const DEFERRED_FORMAT_CONCURRENCY = 3;
|
|
19
23
|
function recordProjectChange(args) {
|
|
20
24
|
const bump = args.runtime.bumpFileSeq;
|
|
21
25
|
if (!bump)
|
|
@@ -138,43 +142,63 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
138
142
|
return !disabled;
|
|
139
143
|
});
|
|
140
144
|
if (formatRecords.length > 0) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
145
|
+
const work = new Array(formatRecords.length);
|
|
146
|
+
const started = new Set();
|
|
147
|
+
let nextIndex = 0;
|
|
148
|
+
const ambientSignal = getAmbientAbortSignal();
|
|
149
|
+
const worker = async () => {
|
|
150
|
+
while (nextIndex < formatRecords.length) {
|
|
151
|
+
const index = nextIndex++;
|
|
152
|
+
if (ambientSignal?.aborted)
|
|
153
|
+
return;
|
|
154
|
+
const record = formatRecords[index];
|
|
155
|
+
const fileStart = Date.now();
|
|
156
|
+
const filePath = path.resolve(record.filePath);
|
|
157
|
+
started.add(index);
|
|
158
|
+
if (!nodeFs.existsSync(filePath)) {
|
|
159
|
+
work[index] = { record, filePath, fileStart, missing: true };
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
work[index] = {
|
|
164
|
+
record,
|
|
165
|
+
filePath,
|
|
166
|
+
fileStart,
|
|
167
|
+
result: await runFormatPhase(filePath, getFormatService, dbg),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
work[index] = {
|
|
172
|
+
record,
|
|
173
|
+
filePath,
|
|
174
|
+
fileStart,
|
|
175
|
+
error: err instanceof Error ? err.message : String(err),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
158
178
|
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
};
|
|
180
|
+
await Promise.all(Array.from({ length: Math.min(DEFERRED_FORMAT_CONCURRENCY, formatRecords.length) }, () => worker()));
|
|
181
|
+
if (ambientSignal?.aborted) {
|
|
182
|
+
runtime.requeueDeferredFormatFiles(formatRecords.filter((_, index) => !started.has(index)));
|
|
183
|
+
}
|
|
184
|
+
for (const entry of work) {
|
|
185
|
+
if (!entry)
|
|
186
|
+
continue;
|
|
187
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
188
|
+
const { record, filePath, fileStart } = entry;
|
|
189
|
+
if (entry.missing) {
|
|
190
|
+
dbg(`agent_end deferred_format skipped missing file: ${filePath}`);
|
|
191
|
+
summary.skipped.push({ filePath, reason: "missing" });
|
|
168
192
|
continue;
|
|
169
193
|
}
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
errors: [outcome.message],
|
|
174
|
-
});
|
|
194
|
+
if (entry.error) {
|
|
195
|
+
dbg(`agent_end deferred_format failed for ${filePath}: ${entry.error}`);
|
|
196
|
+
summary.failed.push({ filePath, errors: [entry.error] });
|
|
175
197
|
continue;
|
|
176
198
|
}
|
|
177
|
-
const
|
|
199
|
+
const result = entry.result;
|
|
200
|
+
if (!result)
|
|
201
|
+
continue;
|
|
178
202
|
summary.formatted++;
|
|
179
203
|
if (result.formatFailures.length > 0) {
|
|
180
204
|
summary.failed.push({ filePath, errors: result.formatFailures });
|
|
@@ -202,7 +226,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
202
226
|
const content = nodeFs.readFileSync(filePath, "utf-8");
|
|
203
227
|
const lineCount = content.split("\n").length;
|
|
204
228
|
const hasImports = /^import\s/m.test(content);
|
|
205
|
-
cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, hasImports, bookkeepingCwd);
|
|
229
|
+
cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, hasImports, bookkeepingCwd, currentSessionId ?? runtime.telemetrySessionId, "pi");
|
|
206
230
|
}
|
|
207
231
|
catch (err) {
|
|
208
232
|
dbg(`agent_end deferred_format modified-range tracking failed for ${filePath}: ${err}`);
|
|
@@ -251,6 +275,14 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
251
275
|
}
|
|
252
276
|
else {
|
|
253
277
|
const enabledFiles = actionReport.data.files.filter((file) => {
|
|
278
|
+
// #1247: the per-edit dispatch surface gates ignored files before
|
|
279
|
+
// running; the turn-end autofix must apply the same filter or a
|
|
280
|
+
// `.pi-lens.json` `ignore` entry cannot protect a prose file
|
|
281
|
+
// (CHANGELOG.md / AGENTS.md) from being rewritten here.
|
|
282
|
+
if (isPathIgnoredByProject(file.filePath, ctxCwd ?? runtime.projectRoot)) {
|
|
283
|
+
dbg(`agent_end actionable_warnings_autofix: skipped ${file.filePath} (ignored by project)`);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
254
286
|
const enabled = !!getFlag("lens-actionable-warning-autofix", file.filePath);
|
|
255
287
|
if (!enabled) {
|
|
256
288
|
const source = getFlagSource?.("lens-actionable-warning-autofix", file.filePath);
|
|
@@ -281,49 +313,42 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
281
313
|
if (!freshness.fresh) {
|
|
282
314
|
dbg(`agent_end actionable_warnings_autofix: stale report (${freshness.reason}; reportProjectSeqEnd=${freshness.reportProjectSeqEnd ?? "missing"}; currentProjectSeq=${freshness.currentProjectSeq}${freshness.filePath ? `; file=${freshness.filePath}; reportFileSeq=${freshness.reportFileSeq}; currentFileSeq=${freshness.currentFileSeq}` : ""}), skipping fixes`);
|
|
283
315
|
}
|
|
284
|
-
else {
|
|
316
|
+
else if (eligibleReport.summary.autoFixEligible > 0) {
|
|
285
317
|
// #684: same "genuine work about to happen" gate as
|
|
286
318
|
// publishFormatStart — only fires when the report is fresh AND
|
|
287
319
|
// has at least one autofix-eligible warning, right before
|
|
288
320
|
// applyConservativeActionableWarningFixes actually starts.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
});
|
|
299
|
-
}
|
|
321
|
+
publishAutofixStart({
|
|
322
|
+
cwd: ctxCwd ?? runtime.projectRoot,
|
|
323
|
+
paths: eligibleReport.files
|
|
324
|
+
.filter((file) => file.warnings.some((warning) => !warning.suppressed &&
|
|
325
|
+
warning.actions.some((action) => action.autoFixEligible)))
|
|
326
|
+
.map((file) => file.filePath),
|
|
327
|
+
eligibleCount: eligibleReport.summary.autoFixEligible,
|
|
328
|
+
dbg,
|
|
329
|
+
});
|
|
300
330
|
const fixStart = Date.now();
|
|
331
|
+
const fixCwd = ctxCwd ?? runtime.projectRoot;
|
|
332
|
+
const mutationContext = {
|
|
333
|
+
cwd: fixCwd,
|
|
334
|
+
correlationId: newLspMutationCorrelationId(),
|
|
335
|
+
tool: "lsp-quickfix",
|
|
336
|
+
source: "autofix",
|
|
337
|
+
runtime,
|
|
338
|
+
cacheManager,
|
|
339
|
+
readGuard: getFlag("no-read-guard") ? undefined : runtime.readGuard,
|
|
340
|
+
recordAutofix: getFlag("lens-turn-summary")
|
|
341
|
+
? (filePath) => runtime.turnSummary.recordAutofix(filePath, { tool: "lsp-quickfix" })
|
|
342
|
+
: undefined,
|
|
343
|
+
dbg,
|
|
344
|
+
};
|
|
301
345
|
const fixSummary = await applyConservativeActionableWarningFixes({
|
|
302
|
-
cwd:
|
|
346
|
+
cwd: fixCwd,
|
|
303
347
|
report: eligibleReport,
|
|
304
348
|
maxFixes: getGlobalActionableWarningMaxFixes(),
|
|
305
349
|
dbg,
|
|
350
|
+
mutationContext,
|
|
306
351
|
});
|
|
307
|
-
for (const changedFile of fixSummary.changedFiles) {
|
|
308
|
-
if (!nodeFs.existsSync(changedFile))
|
|
309
|
-
continue;
|
|
310
|
-
recordProjectChange({
|
|
311
|
-
runtime,
|
|
312
|
-
cwd: ctxCwd ?? runtime.projectRoot,
|
|
313
|
-
filePath: changedFile,
|
|
314
|
-
source: "autofix",
|
|
315
|
-
dbg,
|
|
316
|
-
});
|
|
317
|
-
if (!getFlag("no-read-guard"))
|
|
318
|
-
runtime.readGuard.recordWritten(changedFile);
|
|
319
|
-
try {
|
|
320
|
-
const content = nodeFs.readFileSync(changedFile, "utf-8");
|
|
321
|
-
cacheManager.addModifiedRange(changedFile, { start: 1, end: content.split("\n").length }, /^import\s/m.test(content), ctxCwd ?? runtime.projectRoot);
|
|
322
|
-
}
|
|
323
|
-
catch (err) {
|
|
324
|
-
dbg(`agent_end actionable warning changed-file tracking failed for ${changedFile}: ${err}`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
352
|
if (fixSummary.changedFiles.length > 0) {
|
|
328
353
|
publishFilesTouched({
|
|
329
354
|
reason: "autofix",
|
|
@@ -336,13 +361,6 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
336
361
|
kind: "autofix",
|
|
337
362
|
})),
|
|
338
363
|
});
|
|
339
|
-
if (getFlag("lens-turn-summary")) {
|
|
340
|
-
for (const changedFile of fixSummary.changedFiles) {
|
|
341
|
-
runtime.turnSummary.recordAutofix(changedFile, {
|
|
342
|
-
tool: "lsp-quickfix",
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
364
|
}
|
|
347
365
|
logLatency({
|
|
348
366
|
type: "phase",
|
|
@@ -361,6 +379,9 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
361
379
|
notify(`pi-lens applied ${fixSummary.applied} conservative LSP warning quickfix(es)`, "info");
|
|
362
380
|
}
|
|
363
381
|
}
|
|
382
|
+
else {
|
|
383
|
+
dbg("agent_end actionable_warnings_autofix: fresh report, 0 autofix-eligible warnings, skipping");
|
|
384
|
+
}
|
|
364
385
|
}
|
|
365
386
|
}
|
|
366
387
|
logLatency({
|
|
@@ -377,6 +398,19 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
377
398
|
skipped: summary.skipped.length,
|
|
378
399
|
},
|
|
379
400
|
});
|
|
401
|
+
logLatency({
|
|
402
|
+
type: "phase",
|
|
403
|
+
toolName: "agent_end",
|
|
404
|
+
filePath: ctxCwd ?? runtime.projectRoot,
|
|
405
|
+
phase: "agent_end_deferred_format_done",
|
|
406
|
+
durationMs: Date.now() - startedAt,
|
|
407
|
+
metadata: {
|
|
408
|
+
formatted: summary.formatted,
|
|
409
|
+
changed: summary.changed.length,
|
|
410
|
+
failed: summary.failed.length,
|
|
411
|
+
skipped: summary.skipped.length,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
380
414
|
dbg(`agent_end deferred_format complete: formatted=${summary.formatted} changed=${summary.changed.length} failed=${summary.failed.length} skipped=${summary.skipped.length}`);
|
|
381
415
|
if (summary.failed.length > 0) {
|
|
382
416
|
notify(`pi-lens deferred format: ${summary.changed.length} changed, ${summary.failed.length} failed`, "warning");
|
|
@@ -1,30 +1,54 @@
|
|
|
1
|
+
// Exported so the Stop-hook bin strips exactly what these bridges prepend.
|
|
2
|
+
export const AUTOMATION_FRAMING = "[pi-lens automated check — not a user request] ";
|
|
3
|
+
function turnEndMessage(content) {
|
|
4
|
+
return {
|
|
5
|
+
role: "user",
|
|
6
|
+
content: `${AUTOMATION_FRAMING}Address 🔴 blockers before continuing; ℹ️ advisories are informational only.\n\n${content}`,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** Read a turn-end finding without changing its durable delivery state. */
|
|
10
|
+
export function peekTurnEndFindings(cacheManager, cwd) {
|
|
11
|
+
const findings = cacheManager.readCache("turn-end-findings", cwd);
|
|
12
|
+
if (!findings?.data?.content || findings.data.consumed === true)
|
|
13
|
+
return;
|
|
14
|
+
return { messages: [turnEndMessage(findings.data.content)] };
|
|
15
|
+
}
|
|
1
16
|
export function consumeTurnEndFindings(cacheManager, cwd) {
|
|
2
17
|
const findings = cacheManager.readCache("turn-end-findings", cwd);
|
|
18
|
+
if (!findings?.data?.content || findings.data.consumed === true)
|
|
19
|
+
return;
|
|
20
|
+
// A blocker record is also the opt-in commit gate's durable state. Mark the
|
|
21
|
+
// context message consumed without deleting the record; clean/advisory-only
|
|
22
|
+
// records retain the historical consume-and-clear behavior.
|
|
23
|
+
if (findings.data.hasBlockers === true &&
|
|
24
|
+
typeof findings.data.sessionId === "string") {
|
|
25
|
+
cacheManager.writeCache("turn-end-findings", { ...findings.data, consumed: true }, cwd);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
cacheManager.clearCache("turn-end-findings", cwd);
|
|
29
|
+
}
|
|
30
|
+
return { messages: [turnEndMessage(findings.data.content)] };
|
|
31
|
+
}
|
|
32
|
+
/** Read test findings without consuming them; used by acknowledged IPC delivery. */
|
|
33
|
+
export function peekTestFindings(cacheManager, cwd) {
|
|
34
|
+
const findings = cacheManager.readCache("test-runner-findings", cwd);
|
|
3
35
|
if (!findings?.data?.content)
|
|
4
36
|
return;
|
|
5
|
-
cacheManager.writeCache("turn-end-findings", null, cwd);
|
|
6
37
|
return {
|
|
7
38
|
messages: [
|
|
8
39
|
{
|
|
9
40
|
role: "user",
|
|
10
|
-
content:
|
|
41
|
+
content: `${AUTOMATION_FRAMING}Test failures detected last turn — fix before continuing:\n\n${findings.data.content}`,
|
|
11
42
|
},
|
|
12
43
|
],
|
|
13
44
|
};
|
|
14
45
|
}
|
|
15
46
|
export function consumeTestFindings(cacheManager, cwd) {
|
|
16
|
-
const findings = cacheManager
|
|
17
|
-
if (!findings
|
|
47
|
+
const findings = peekTestFindings(cacheManager, cwd);
|
|
48
|
+
if (!findings)
|
|
18
49
|
return;
|
|
19
50
|
cacheManager.writeCache("test-runner-findings", null, cwd);
|
|
20
|
-
return
|
|
21
|
-
messages: [
|
|
22
|
-
{
|
|
23
|
-
role: "user",
|
|
24
|
-
content: `[pi-lens automated check — not a user request] Test failures detected last turn — fix before continuing:\n\n${findings.data.content}`,
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
};
|
|
51
|
+
return findings;
|
|
28
52
|
}
|
|
29
53
|
export function consumeSessionStartGuidance(cacheManager, cwd) {
|
|
30
54
|
const guidance = cacheManager.readCache("session-start-guidance", cwd);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { normalizeMapKey } from "./path-utils.js";
|
|
5
|
+
import { PathKeyedMap } from "./path-keyed-map.js";
|
|
4
6
|
import { ReadGuard } from "./read-guard.js";
|
|
5
7
|
import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
6
8
|
import { TurnSummaryCollector } from "./turn-summary.js";
|
|
@@ -45,12 +47,13 @@ export class RuntimeCoordinator {
|
|
|
45
47
|
_fileLastProjectSeq = new Map();
|
|
46
48
|
_gitGuardHasBlockers = false;
|
|
47
49
|
_gitGuardSummary = "";
|
|
50
|
+
_gitGuardCacheUnknownReason;
|
|
48
51
|
callGraph = null;
|
|
49
52
|
wordIndex = null;
|
|
50
53
|
_readGuard = null;
|
|
51
54
|
_pendingDeferredFormatFiles = new Map();
|
|
52
55
|
_lspReadWarmState = new Map();
|
|
53
|
-
_pendingInlineBlockers = new
|
|
56
|
+
_pendingInlineBlockers = new PathKeyedMap(normalizeMapKey);
|
|
54
57
|
_actionableWarningsThisTurn = new Map();
|
|
55
58
|
_codeQualityWarningsThisTurn = new Map();
|
|
56
59
|
// #484: opt-in per-RUN summary of diagnostics/autofixes/formats,
|
|
@@ -87,6 +90,7 @@ export class RuntimeCoordinator {
|
|
|
87
90
|
this._fileLastProjectSeq.clear();
|
|
88
91
|
this._gitGuardHasBlockers = false;
|
|
89
92
|
this._gitGuardSummary = "";
|
|
93
|
+
this._gitGuardCacheUnknownReason = undefined;
|
|
90
94
|
this._readGuard = null;
|
|
91
95
|
this._pendingDeferredFormatFiles.clear();
|
|
92
96
|
this._lspReadWarmState.clear();
|
|
@@ -107,8 +111,12 @@ export class RuntimeCoordinator {
|
|
|
107
111
|
this._cascadeSessionStats.coldSnapshotTouches += coldSnapshotTouches;
|
|
108
112
|
}
|
|
109
113
|
updateGitGuardStatus(hasBlockers, output) {
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
// The status is an aggregate over the current per-file map. A clean B
|
|
115
|
+
// result must not erase an unresolved A result; the pipeline records/clears
|
|
116
|
+
// the edited file immediately before this method runs.
|
|
117
|
+
this._gitGuardHasBlockers =
|
|
118
|
+
hasBlockers || this.getInlineBlockersSnapshot().length > 0;
|
|
119
|
+
if (!this._gitGuardHasBlockers) {
|
|
112
120
|
this._gitGuardSummary = "";
|
|
113
121
|
return;
|
|
114
122
|
}
|
|
@@ -116,7 +124,10 @@ export class RuntimeCoordinator {
|
|
|
116
124
|
.split("\n")
|
|
117
125
|
.map((line) => line.trim())
|
|
118
126
|
.find((line) => line.length > 0);
|
|
119
|
-
|
|
127
|
+
const summaries = this.getInlineBlockersSnapshot()
|
|
128
|
+
.map((entry) => entry.summary.trim())
|
|
129
|
+
.filter(Boolean);
|
|
130
|
+
this._gitGuardSummary = (summaries[0] ?? firstLine ?? "Unresolved blockers detected").slice(0, 160);
|
|
120
131
|
}
|
|
121
132
|
get gitGuardHasBlockers() {
|
|
122
133
|
return this._gitGuardHasBlockers;
|
|
@@ -124,6 +135,15 @@ export class RuntimeCoordinator {
|
|
|
124
135
|
get gitGuardSummary() {
|
|
125
136
|
return this._gitGuardSummary;
|
|
126
137
|
}
|
|
138
|
+
markGitGuardCacheUnknown(reason) {
|
|
139
|
+
this._gitGuardCacheUnknownReason = reason;
|
|
140
|
+
}
|
|
141
|
+
clearGitGuardCacheUnknown() {
|
|
142
|
+
this._gitGuardCacheUnknownReason = undefined;
|
|
143
|
+
}
|
|
144
|
+
get gitGuardCacheUnknownReason() {
|
|
145
|
+
return this._gitGuardCacheUnknownReason;
|
|
146
|
+
}
|
|
127
147
|
beginTurn() {
|
|
128
148
|
this._cascadeRuns = [];
|
|
129
149
|
// _pendingCascadeRuns is deliberately NOT cleared here: a cascade compute
|
|
@@ -131,7 +151,9 @@ export class RuntimeCoordinator {
|
|
|
131
151
|
// measured up to ~19s) must surface on the NEXT turn_end, not be dropped —
|
|
132
152
|
// pre-#450 those findings were always awaited, never lost. Session reset
|
|
133
153
|
// still clears it.
|
|
134
|
-
|
|
154
|
+
// Inline blockers are session-scoped per-file state. They are cleared only
|
|
155
|
+
// when that file is re-analyzed clean or the session resets; a new turn must
|
|
156
|
+
// not let a clean unrelated file erase an unresolved blocker.
|
|
135
157
|
this._actionableWarningsThisTurn.clear();
|
|
136
158
|
this._codeQualityWarningsThisTurn.clear();
|
|
137
159
|
// _turnSummary is deliberately NOT cleared here (#484 rework): the
|
|
@@ -365,8 +387,45 @@ export class RuntimeCoordinator {
|
|
|
365
387
|
clearInlineBlockers(filePath) {
|
|
366
388
|
this._pendingInlineBlockers.delete(path.resolve(filePath));
|
|
367
389
|
}
|
|
390
|
+
reconcileInlineBlockers() {
|
|
391
|
+
// Rebuild, never delete-in-place: `PathKeyedMap.delete()` re-normalizes
|
|
392
|
+
// the key, and `normalizeMapKey` realpaths a live file but lowercases
|
|
393
|
+
// the tail of a deleted one — so on Windows a mixed-case filename gets
|
|
394
|
+
// a DIFFERENT delete-time key than its set-time key and the delete
|
|
395
|
+
// misses (#1245, verified live: `MyCase.ts` survived reconcile).
|
|
396
|
+
// Existence-checking the display path and rebuilding survivors avoids
|
|
397
|
+
// the key-mismatch entirely; live survivors re-set to identical keys
|
|
398
|
+
// (both realpath), so only the stale entries are dropped.
|
|
399
|
+
const survivors = [];
|
|
400
|
+
for (const [displayPath, value] of this._pendingInlineBlockers.entries()) {
|
|
401
|
+
if (fs.existsSync(displayPath))
|
|
402
|
+
survivors.push([displayPath, value]);
|
|
403
|
+
}
|
|
404
|
+
if (survivors.length !== this._pendingInlineBlockers.size) {
|
|
405
|
+
this._pendingInlineBlockers.clear();
|
|
406
|
+
for (const [displayPath, value] of survivors) {
|
|
407
|
+
this._pendingInlineBlockers.set(displayPath, value);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Stale-entry reconcile (#1245): a blocker recorded for a file that has
|
|
413
|
+
* since been deleted can never be cleared — `clearInlineBlockers` fires
|
|
414
|
+
* only on a LATER dispatch of the same path, which a deleted file never
|
|
415
|
+
* gets. Every read of the blocker map (turn_end injection, git-guard
|
|
416
|
+
* size/summary, `syncGitGuardRecord`) therefore drops entries whose file no
|
|
417
|
+
* longer exists on disk: a blocker for a deleted file is stale by
|
|
418
|
+
* definition (the agent cannot fix it), so it must not re-surface every
|
|
419
|
+
* turn or gate a commit. The map is tiny (per-turn blockers) and reads are
|
|
420
|
+
* bounded (once per turn_end / tool_result), so the probe cost is
|
|
421
|
+
* negligible.
|
|
422
|
+
*/
|
|
423
|
+
getInlineBlockersSnapshot() {
|
|
424
|
+
this.reconcileInlineBlockers();
|
|
425
|
+
return [...this._pendingInlineBlockers.values()];
|
|
426
|
+
}
|
|
368
427
|
consumeInlineBlockers() {
|
|
369
|
-
const entries =
|
|
428
|
+
const entries = this.getInlineBlockersSnapshot();
|
|
370
429
|
this._pendingInlineBlockers.clear();
|
|
371
430
|
return entries;
|
|
372
431
|
}
|
|
@@ -500,6 +559,15 @@ export class RuntimeCoordinator {
|
|
|
500
559
|
}
|
|
501
560
|
return { claimed, staleClaimed, deferredToOwner };
|
|
502
561
|
}
|
|
562
|
+
/** Return claimed records that were never started by an aborted drain. */
|
|
563
|
+
requeueDeferredFormatFiles(records) {
|
|
564
|
+
for (const record of records) {
|
|
565
|
+
const key = path.resolve(record.filePath);
|
|
566
|
+
if (!this._pendingDeferredFormatFiles.has(key)) {
|
|
567
|
+
this._pendingDeferredFormatFiles.set(key, record);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
503
571
|
shouldWarmLspOnRead(filePath, maxAgeMs = 120_000) {
|
|
504
572
|
const state = this._lspReadWarmState.get(path.resolve(filePath));
|
|
505
573
|
if (!state)
|