@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
|
@@ -2,10 +2,12 @@ import * as path from "node:path";
|
|
|
2
2
|
import { appendActionableWarningsHistory, buildActionableWarningsReport, formatActionableWarningsAdvisory, writeActionableWarningsReport, } from "./actionable-warnings.js";
|
|
3
3
|
import { logActionableWarningsEvent } from "./actionable-warnings-logger.js";
|
|
4
4
|
import { appendCodeQualityWarningsHistory, buildCodeQualityWarningsReport, formatCodeQualityWarningsAdvisory, writeCodeQualityWarningsReport, } from "./code-quality-warnings.js";
|
|
5
|
+
import { clearGitGuardTestFailure, mergeGitGuardTestFailure, writeGitGuardRecord, } from "./git-guard.js";
|
|
5
6
|
import { logCascade } from "./cascade-logger.js";
|
|
6
7
|
import { normalizeMapKey } from "./path-utils.js";
|
|
7
8
|
import { resolveRunnerPath, toRunnerDisplayPath, } from "./dispatch/runner-context.js";
|
|
8
9
|
import { getKnipIgnorePatterns } from "./file-utils.js";
|
|
10
|
+
import { isTestRoleCollateral } from "./collateral-test-role.js";
|
|
9
11
|
import { dedupeSecretFindings, fromAstGrepWarnings, fromGitleaks, fromTrivySecrets, isSecretWarning, secretLocationKey, } from "./secret-findings.js";
|
|
10
12
|
import { formatDeadCodeAdvisory } from "./dead-code-client.js";
|
|
11
13
|
import { PROJECT_DIAGNOSTICS_CACHE_VERSION, writeProjectDiagnosticsDeltaReport, } from "./project-diagnostics/cache.js";
|
|
@@ -86,7 +88,7 @@ function capTurnEndMessage(content) {
|
|
|
86
88
|
return out;
|
|
87
89
|
}
|
|
88
90
|
export async function handleTurnEnd(deps) {
|
|
89
|
-
const { ctxCwd, getFlag, dbg, runtime, cacheManager, knipClient, deadCodeClients, depChecker, testRunnerClient, resetLSPService, resetFormatService, } = deps;
|
|
91
|
+
const { ctxCwd, getFlag, dbg, runtime, cacheManager, knipClient, deadCodeClients, depChecker, testRunnerClient, owner, resetLSPService, resetFormatService, } = deps;
|
|
90
92
|
// #449 slice 1: piggyback the instance-registry heartbeat on this existing
|
|
91
93
|
// per-turn touchpoint rather than adding a new timer/interval. Cheap (reads
|
|
92
94
|
// process.memoryUsage().rss, one read-modify-write of instances.json) and
|
|
@@ -106,16 +108,40 @@ export async function handleTurnEnd(deps) {
|
|
|
106
108
|
});
|
|
107
109
|
const cwd = ctxCwd ?? process.cwd();
|
|
108
110
|
let turnState = cacheManager.readTurnState(cwd);
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
// A live foreign writer owns this worklist. Do not clear or consume another
|
|
112
|
+
// pi/MCP session's files; a dead/aged owner is safely evicted instead.
|
|
113
|
+
const currentOwner = owner ?? {
|
|
114
|
+
kind: "pi",
|
|
115
|
+
id: runtime.telemetrySessionId,
|
|
116
|
+
pid: process.pid,
|
|
117
|
+
lastSeen: new Date().toISOString(),
|
|
118
|
+
};
|
|
119
|
+
const access = cacheManager.getTurnStateAccess(cwd, currentOwner);
|
|
120
|
+
const sameProcessPiSessionHandoff = access === "foreign-live" &&
|
|
121
|
+
currentOwner.kind === "pi" &&
|
|
122
|
+
turnState.owner?.kind === "pi" &&
|
|
123
|
+
turnState.owner.pid === process.pid &&
|
|
124
|
+
turnState.owner.id !== currentOwner.id;
|
|
125
|
+
if (access === "foreign-live" && !sameProcessPiSessionHandoff) {
|
|
126
|
+
dbg(`turn_end: foreign live owner retained (${turnState.owner?.kind ?? "legacy"}:${turnState.owner?.id ?? turnState.sessionId})`);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (access === "available" && (turnState.files || turnState.owner || turnState.sessionId)) {
|
|
130
|
+
dbg("turn_end: evicting stale turn-state owner");
|
|
131
|
+
cacheManager.clearTurnState(cwd, currentOwner);
|
|
115
132
|
turnState = cacheManager.readTurnState(cwd);
|
|
116
133
|
}
|
|
117
134
|
const files = Object.keys(turnState.files);
|
|
118
135
|
if (files.length === 0) {
|
|
136
|
+
// A genuinely clean session must invalidate the persisted guard record.
|
|
137
|
+
// Blocker records are retained only while the runtime still reports one.
|
|
138
|
+
if (getFlag("lens-guard") && !runtime.gitGuardHasBlockers) {
|
|
139
|
+
const guardRecord = cacheManager.readCache("turn-end-findings", cwd)?.data;
|
|
140
|
+
if (guardRecord?.sessionId === runtime.telemetrySessionId &&
|
|
141
|
+
guardRecord.testFailures !== true) {
|
|
142
|
+
cacheManager.clearCache("turn-end-findings", cwd);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
119
145
|
// #713: subagent sessions use a shorter idle reset (60s) â a short-lived
|
|
120
146
|
// task agent holding a warm fleet for 4 minutes after its last turn is
|
|
121
147
|
// pure waste under fan-out. Classify ONCE here so every tick in this call
|
|
@@ -143,7 +169,7 @@ export async function handleTurnEnd(deps) {
|
|
|
143
169
|
dbg(`turn_end: ${files.length} file(s) modified, cycles: ${turnState.turnCycles}/${turnState.maxCycles}`);
|
|
144
170
|
if (cacheManager.isMaxCyclesExceeded(cwd)) {
|
|
145
171
|
dbg("turn_end: max cycles exceeded, clearing state and forcing through");
|
|
146
|
-
cacheManager.clearTurnState(cwd);
|
|
172
|
+
cacheManager.clearTurnState(cwd, currentOwner);
|
|
147
173
|
runtime.fixedThisTurn.clear();
|
|
148
174
|
resetFormatService();
|
|
149
175
|
return;
|
|
@@ -155,7 +181,7 @@ export async function handleTurnEnd(deps) {
|
|
|
155
181
|
const projectDiagnosticsSources = new Set();
|
|
156
182
|
// Re-surface inline blockers from this turn that the agent didn't fix.
|
|
157
183
|
// These were shown inline during write/edit but the agent moved on without resolving them.
|
|
158
|
-
const unresolvedBlockers = runtime.
|
|
184
|
+
const unresolvedBlockers = runtime.getInlineBlockersSnapshot();
|
|
159
185
|
for (const { filePath: bPath, summary } of unresolvedBlockers) {
|
|
160
186
|
const displayPath = toRunnerDisplayPath(cwd, bPath);
|
|
161
187
|
blockerParts.push(`Unresolved from this turn â ${displayPath}:\n${summary}`);
|
|
@@ -180,7 +206,14 @@ export async function handleTurnEnd(deps) {
|
|
|
180
206
|
// 2. Neighbor-level: each neighbor is claimed by the latest cascade result
|
|
181
207
|
// that covers it â suppresses stale neighbor state from earlier writes.
|
|
182
208
|
const t0 = Date.now();
|
|
183
|
-
const cascadeRuns = runtime.consumeCascadeRuns()
|
|
209
|
+
const cascadeRuns = runtime.consumeCascadeRuns().filter((run) => {
|
|
210
|
+
const originSeq = run.origin?.projectSeq;
|
|
211
|
+
const originTurn = run.origin?.turnSeq;
|
|
212
|
+
// A deferred result from before a later write/turn is not current state.
|
|
213
|
+
// Old test fixtures without provenance remain accepted for compatibility.
|
|
214
|
+
return ((originSeq === undefined || originSeq === runtime.projectSeq) &&
|
|
215
|
+
(originTurn === undefined || originTurn === runtime.turnIndex));
|
|
216
|
+
});
|
|
184
217
|
const cascadeResults = cascadeRuns.flatMap((r) => r.result ? [r.result] : []);
|
|
185
218
|
if (cascadeResults.length > 0) {
|
|
186
219
|
const seen = new Map();
|
|
@@ -249,32 +282,62 @@ export async function handleTurnEnd(deps) {
|
|
|
249
282
|
// (over-correction guard).
|
|
250
283
|
const indeterminateRuns = cascadeRuns.filter((r) => r.indeterminate);
|
|
251
284
|
if (indeterminateRuns.length > 0) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
285
|
+
// #1104 (review P3 on PR #1143, rides with the resultId main body): this
|
|
286
|
+
// preamble used to hardcode a graph-unavailability frame for EVERY
|
|
287
|
+
// indeterminate reason. That's accurate for `graph_degraded`/
|
|
288
|
+
// `missing_node`/`error` (the graph really couldn't produce a dependent
|
|
289
|
+
// set), but `lsp_binding_rejected` is a DIFFERENT failure shape â the
|
|
290
|
+
// graph WAS available and dependents WERE derived; only their LSP
|
|
291
|
+
// diagnostics display was withheld because a fallback snapshot's content
|
|
292
|
+
// binding didn't match current disk. Saying "the review graph was
|
|
293
|
+
// unavailable" for that case mis-attributes the cause. Bucket by reason
|
|
294
|
+
// family so each gets its own accurate frame.
|
|
295
|
+
const buildAdvisory = (runs, frame) => {
|
|
296
|
+
if (runs.length === 0)
|
|
297
|
+
return undefined;
|
|
298
|
+
const byDetail = new Map();
|
|
299
|
+
for (const r of runs) {
|
|
300
|
+
const detail = r.indeterminate?.detail ?? frame.fallbackDetail(r);
|
|
301
|
+
const files = byDetail.get(detail) ?? [];
|
|
302
|
+
files.push(toRunnerDisplayPath(cwd, r.filePath));
|
|
303
|
+
byDetail.set(detail, files);
|
|
304
|
+
}
|
|
305
|
+
const lines = [];
|
|
306
|
+
for (const [detail, filesRaw] of byDetail) {
|
|
307
|
+
const files = [...new Set(filesRaw)];
|
|
308
|
+
const shown = files.slice(0, 5).join(", ");
|
|
309
|
+
const more = files.length > 5 ? ` (+${files.length - 5} more)` : "";
|
|
310
|
+
lines.push(` âĸ ${detail}: ${shown}${more}`);
|
|
311
|
+
}
|
|
312
|
+
const fileCount = new Set(runs.map((r) => normalizeMapKey(r.filePath))).size;
|
|
313
|
+
const reasons = [...byDetail.keys()].join("; ");
|
|
314
|
+
return `${frame.lead(fileCount, reasons)}\n${lines.join("\n")}`;
|
|
315
|
+
};
|
|
316
|
+
const graphRuns = indeterminateRuns.filter((r) => r.indeterminate?.reason !== "lsp_binding_rejected");
|
|
317
|
+
const bindingRuns = indeterminateRuns.filter((r) => r.indeterminate?.reason === "lsp_binding_rejected");
|
|
271
318
|
// Factual/informational phrasing â the advisory tier wraps this with an
|
|
272
319
|
// "âšī¸ Advisory â no action required this turn:" label, so an imperative
|
|
273
320
|
// ("review dependents manually") would contradict it. The #533 substance
|
|
274
321
|
// stays: a clean cascade result does NOT cover these files' dependents.
|
|
275
|
-
|
|
276
|
-
`
|
|
277
|
-
|
|
322
|
+
const graphAdvisory = buildAdvisory(graphRuns, {
|
|
323
|
+
lead: (fileCount, reasons) => `Cascade could not compute downstream impact for ${fileCount} edited file(s) this turn â ` +
|
|
324
|
+
`the review graph was unavailable (${reasons}), so their dependents were not ` +
|
|
325
|
+
`cascade-checked and a clean cascade result does not cover them.`,
|
|
326
|
+
fallbackDetail: (r) => r.indeterminate?.reason === "missing_node"
|
|
327
|
+
? "changed file not in the review graph"
|
|
328
|
+
: "review graph unavailable",
|
|
329
|
+
});
|
|
330
|
+
if (graphAdvisory)
|
|
331
|
+
advisoryParts.push(graphAdvisory);
|
|
332
|
+
const bindingAdvisory = buildAdvisory(bindingRuns, {
|
|
333
|
+
lead: (fileCount, reasons) => `Cascade identified dependents for ${fileCount} edited file(s) this turn, but their ` +
|
|
334
|
+
`diagnostics could not be freshly confirmed (${reasons}) and were withheld â a clean ` +
|
|
335
|
+
`cascade result does not cover them.`,
|
|
336
|
+
fallbackDetail: () => "cascade diagnostics withheld (binding rejected)",
|
|
337
|
+
});
|
|
338
|
+
if (bindingAdvisory)
|
|
339
|
+
advisoryParts.push(bindingAdvisory);
|
|
340
|
+
const fileCount = new Set(indeterminateRuns.map((r) => normalizeMapKey(r.filePath))).size;
|
|
278
341
|
logCascade({
|
|
279
342
|
phase: "cascade_indeterminate",
|
|
280
343
|
filePath: files[0] ?? cwd,
|
|
@@ -516,6 +579,7 @@ export async function handleTurnEnd(deps) {
|
|
|
516
579
|
advisoryParts.push(report);
|
|
517
580
|
}
|
|
518
581
|
const t3 = Date.now();
|
|
582
|
+
let madgeStats;
|
|
519
583
|
if (await depChecker.ensureAvailable()) {
|
|
520
584
|
const madgeFiles = cacheManager.getFilesForMadge(cwd);
|
|
521
585
|
if (madgeFiles.length > 0) {
|
|
@@ -524,7 +588,9 @@ export async function handleTurnEnd(deps) {
|
|
|
524
588
|
// the shared circular-dep state update is deferred/folded inside
|
|
525
589
|
// checkFilesBatch so concurrent spawns can't clobber each other (#766).
|
|
526
590
|
const absFiles = madgeFiles.map((file) => path.resolve(cwd, file));
|
|
527
|
-
const
|
|
591
|
+
const batch = await depChecker.checkFilesBatch(absFiles, cwd);
|
|
592
|
+
const depResults = batch.results;
|
|
593
|
+
madgeStats = batch.stats;
|
|
528
594
|
for (const file of madgeFiles) {
|
|
529
595
|
const absPath = path.resolve(cwd, file);
|
|
530
596
|
const depResult = depResults.get(absPath);
|
|
@@ -550,6 +616,7 @@ export async function handleTurnEnd(deps) {
|
|
|
550
616
|
filePath: cwd,
|
|
551
617
|
phase: "madge",
|
|
552
618
|
durationMs: Date.now() - t3,
|
|
619
|
+
...(madgeStats && { metadata: madgeStats }),
|
|
553
620
|
});
|
|
554
621
|
// --- Test runner: fire once per turn after all edits are done ---
|
|
555
622
|
// Runs for each unique test target across modified files; results appear
|
|
@@ -600,6 +667,7 @@ export async function handleTurnEnd(deps) {
|
|
|
600
667
|
if (targets.length > 0) {
|
|
601
668
|
dbg(`turn_end: firing ${targets.length} test target(s) async (non-blocking)`);
|
|
602
669
|
const firedAtTurn = runtime.turnIndex;
|
|
670
|
+
const firedSessionId = runtime.telemetrySessionId;
|
|
603
671
|
Promise.allSettled(targets.map((t) => testRunnerClient.runTestFileAsync(t.testFile, cwd, t.runner, t.config)))
|
|
604
672
|
.then((results) => {
|
|
605
673
|
// #628: the turn advancing while tests ran no longer means the
|
|
@@ -633,9 +701,20 @@ export async function handleTurnEnd(deps) {
|
|
|
633
701
|
? `[from a prior turn â the edit that triggered this run had already been superseded by the time results came back]\n\n${failures.join("\n\n")}`
|
|
634
702
|
: failures.join("\n\n");
|
|
635
703
|
cacheManager.writeCache("test-runner-findings", { content, stale, results: resultValues }, cwd);
|
|
704
|
+
if (getFlag("lens-guard") && firedSessionId === runtime.telemetrySessionId) {
|
|
705
|
+
clearGitGuardTestFailure(cacheManager, cwd, runtime, resultValues
|
|
706
|
+
.filter((value) => value.failed === 0)
|
|
707
|
+
.map((value) => value.file));
|
|
708
|
+
mergeGitGuardTestFailure(cacheManager, cwd, runtime, content, resultValues
|
|
709
|
+
.filter((value) => value.failed > 0)
|
|
710
|
+
.map((value) => value.file));
|
|
711
|
+
}
|
|
636
712
|
dbg(`turn_end: ${failures.length} test failure(s) cached for next context injection${stale ? " (stale â turn advanced while tests ran)" : ""}`);
|
|
637
713
|
}
|
|
638
714
|
else if (results.length > 0) {
|
|
715
|
+
if (getFlag("lens-guard") && firedSessionId === runtime.telemetrySessionId) {
|
|
716
|
+
clearGitGuardTestFailure(cacheManager, cwd, runtime, resultValues.map((value) => value.file));
|
|
717
|
+
}
|
|
639
718
|
dbg(`turn_end: all tests passed${stale ? " (stale â turn advanced while tests ran)" : ""}`);
|
|
640
719
|
}
|
|
641
720
|
})
|
|
@@ -659,37 +738,68 @@ export async function handleTurnEnd(deps) {
|
|
|
659
738
|
// would drop the call-graph entries â so lens_diagnostics (which only reads the
|
|
660
739
|
// persisted report) would never surface the findings (#179/#533).
|
|
661
740
|
if (runtime.callGraph && files.length > 0) {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
741
|
+
const coverage = runtime.callGraph.coverage;
|
|
742
|
+
if (!coverage || coverage.complete !== true) {
|
|
743
|
+
// An incomplete graph can still contain useful edges, but emitting them
|
|
744
|
+
// as ordinary impact findings would turn unsupported/partial extraction
|
|
745
|
+
// into an authoritative-looking clean result for the rest of the file.
|
|
746
|
+
// Keep the limitation visible and require a complete graph for this
|
|
747
|
+
// user-facing impact surface (#1070).
|
|
748
|
+
advisoryParts.push("Call-graph impact was not emitted because call-graph extraction coverage is incomplete; " +
|
|
749
|
+
"the affected files may have unreported callers.");
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
try {
|
|
753
|
+
const { impact, formatImpact, parseSymbolKey } = await import("./call-graph.js");
|
|
754
|
+
const { callGraphImpactToProjectDiagnostics } = await import("./project-diagnostics/runner-adapters/call-graph-impact.js");
|
|
755
|
+
const impactLines = [];
|
|
756
|
+
const impactFindings = [];
|
|
757
|
+
for (const filePath of files.slice(0, 5)) {
|
|
758
|
+
// Turn-state files may be cwd-relative while graph keys are absolute,
|
|
759
|
+
// and persisted graphs can contain either slash style/casing. Compare
|
|
760
|
+
// through the shared normalized path seam; keep the original filePath
|
|
761
|
+
// only for display and diagnostics.
|
|
762
|
+
const changedFileKey = normalizeMapKey(resolveRunnerPath(cwd, filePath));
|
|
763
|
+
const fileCallerKeys = [...runtime.callGraph.callers.keys()].filter((k) => {
|
|
764
|
+
const graphFilePath = parseSymbolKey(k).filePath;
|
|
765
|
+
return normalizeMapKey(resolveRunnerPath(cwd, graphFilePath)) === changedFileKey;
|
|
766
|
+
});
|
|
767
|
+
for (const calleeKey of fileCallerKeys.slice(0, 3)) {
|
|
768
|
+
// #1080: drop KNOWN test-role callers BEFORE both the human advisory
|
|
769
|
+
// (formatImpact below) and the persisted delta (impactFindings â
|
|
770
|
+
// callGraphImpactToProjectDiagnostics) â the advisory is rendered
|
|
771
|
+
// first, so the filter must reach the shared `results` set that feeds
|
|
772
|
+
// both. A test caller supplied by an old/fixture/expanded graph must
|
|
773
|
+
// appear in neither surface. Fail-open: an unparseable/unclassifiable
|
|
774
|
+
// key is retained (the adapter re-applies the same predicate).
|
|
775
|
+
const results = impact(runtime.callGraph, calleeKey).filter((r) => {
|
|
776
|
+
const callerFile = parseSymbolKey(r.symbolKey).filePath;
|
|
777
|
+
return (!callerFile ||
|
|
778
|
+
!isTestRoleCollateral(resolveRunnerPath(cwd, callerFile)));
|
|
779
|
+
});
|
|
780
|
+
if (results.length > 0) {
|
|
781
|
+
impactFindings.push({ calleeKey, results });
|
|
782
|
+
const summary = formatImpact(results, cwd);
|
|
783
|
+
if (summary)
|
|
784
|
+
impactLines.push(` ${parseSymbolKey(calleeKey).symbolName ?? calleeKey}: ${summary}`);
|
|
785
|
+
}
|
|
677
786
|
}
|
|
678
787
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
advisoryParts.push(`đ Call-graph impact (changed symbols have callers):\n${impactLines.join("\n")}`);
|
|
682
|
-
}
|
|
683
|
-
if (impactFindings.length > 0) {
|
|
684
|
-
const impactDiagnostics = callGraphImpactToProjectDiagnostics(cwd, impactFindings);
|
|
685
|
-
if (impactDiagnostics.length > 0) {
|
|
686
|
-
projectDiagnosticsDelta.push(...impactDiagnostics);
|
|
687
|
-
projectDiagnosticsSources.add("call-graph");
|
|
788
|
+
if (impactLines.length > 0) {
|
|
789
|
+
advisoryParts.push(`đ Call-graph impact (changed symbols have callers):\n${impactLines.join("\n")}`);
|
|
688
790
|
}
|
|
791
|
+
if (impactFindings.length > 0) {
|
|
792
|
+
const impactDiagnostics = callGraphImpactToProjectDiagnostics(cwd, impactFindings);
|
|
793
|
+
if (impactDiagnostics.length > 0) {
|
|
794
|
+
projectDiagnosticsDelta.push(...impactDiagnostics);
|
|
795
|
+
projectDiagnosticsSources.add("call-graph");
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
// Non-fatal â call graph is best-effort
|
|
799
|
+
}
|
|
800
|
+
catch {
|
|
801
|
+
// Non-fatal â call graph is best-effort
|
|
689
802
|
}
|
|
690
|
-
}
|
|
691
|
-
catch {
|
|
692
|
-
// Non-fatal â call graph is best-effort
|
|
693
803
|
}
|
|
694
804
|
}
|
|
695
805
|
if (projectDiagnosticsDelta.length > 0) {
|
|
@@ -838,7 +948,7 @@ export async function handleTurnEnd(deps) {
|
|
|
838
948
|
catch (err) {
|
|
839
949
|
dbg(`turn_end: dead-code advisory failed: ${err}`);
|
|
840
950
|
}
|
|
841
|
-
cacheManager.incrementTurnCycle(cwd);
|
|
951
|
+
cacheManager.incrementTurnCycle(cwd, currentOwner);
|
|
842
952
|
const labeledAdvisoryParts = advisoryParts.map((p) => `âšī¸ Advisory â no action required this turn:\n${p}`);
|
|
843
953
|
const findingParts = [...blockerParts, ...labeledAdvisoryParts];
|
|
844
954
|
if (findingParts.length > 0) {
|
|
@@ -852,12 +962,68 @@ export async function handleTurnEnd(deps) {
|
|
|
852
962
|
if (last?.data?.signature === signature &&
|
|
853
963
|
last?.data?.sessionId === runtime.telemetrySessionId) {
|
|
854
964
|
dbg("turn_end: duplicate findings detected (same session), suppressing re-prompt");
|
|
855
|
-
|
|
965
|
+
if (getFlag("lens-guard")) {
|
|
966
|
+
const existingGuard = cacheManager.readCache("turn-end-findings", cwd)?.data;
|
|
967
|
+
if (existingGuard) {
|
|
968
|
+
writeGitGuardRecord(cacheManager, runtime, cwd, {
|
|
969
|
+
...existingGuard,
|
|
970
|
+
content,
|
|
971
|
+
blockerContent: blockerParts.length > 0
|
|
972
|
+
? capTurnEndMessage(blockerParts.join("\n\n"))
|
|
973
|
+
: undefined,
|
|
974
|
+
hasBlockers: blockerParts.length > 0 || existingGuard.testFailures === true,
|
|
975
|
+
blockingFiles: blockerParts.length > 0 ? existingGuard.affectedFiles : undefined,
|
|
976
|
+
projectSeqStart: runtime.turnStartProjectSeq,
|
|
977
|
+
projectSeqEnd: runtime.projectSeq,
|
|
978
|
+
fileSeqByPath: Object.fromEntries(runtime.getFileSeqEntries().map(([filePath, seq]) => [normalizeMapKey(path.resolve(filePath)), seq])),
|
|
979
|
+
fileContentHashes: {},
|
|
980
|
+
consumed: false,
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
cacheManager.clearTurnState(cwd, currentOwner);
|
|
856
985
|
runtime.fixedThisTurn.clear();
|
|
857
986
|
resetFormatService();
|
|
858
987
|
return;
|
|
859
988
|
}
|
|
860
|
-
|
|
989
|
+
const fileSeqByPath = {};
|
|
990
|
+
for (const [filePath, seq] of runtime.getFileSeqEntries()) {
|
|
991
|
+
fileSeqByPath[normalizeMapKey(path.resolve(filePath))] = seq;
|
|
992
|
+
}
|
|
993
|
+
if (getFlag("lens-guard")) {
|
|
994
|
+
const existingGuard = cacheManager.readCache("turn-end-findings", cwd)?.data;
|
|
995
|
+
const blockingContent = blockerParts.length > 0
|
|
996
|
+
? capTurnEndMessage(blockerParts.join("\n\n"))
|
|
997
|
+
: undefined;
|
|
998
|
+
const affectedFiles = [
|
|
999
|
+
...(existingGuard?.affectedFiles ?? []),
|
|
1000
|
+
...files.map((file) => resolveRunnerPath(cwd, file)),
|
|
1001
|
+
...cascadeResults.flatMap((result) => result.neighbors
|
|
1002
|
+
.filter((neighbor) => neighbor.diagnostics.length > 0)
|
|
1003
|
+
.map((neighbor) => resolveRunnerPath(cwd, neighbor.filePath))),
|
|
1004
|
+
];
|
|
1005
|
+
writeGitGuardRecord(cacheManager, runtime, cwd, {
|
|
1006
|
+
content: [content, existingGuard?.testFailureContent]
|
|
1007
|
+
.filter((value) => !!value)
|
|
1008
|
+
.join("\n\n"),
|
|
1009
|
+
blockerContent: blockingContent,
|
|
1010
|
+
blockingFiles: blockerParts.length > 0 ? affectedFiles : undefined,
|
|
1011
|
+
hasBlockers: !!blockingContent || existingGuard?.testFailures === true,
|
|
1012
|
+
affectedFiles,
|
|
1013
|
+
sessionId: runtime.telemetrySessionId,
|
|
1014
|
+
projectSeqStart: runtime.turnStartProjectSeq,
|
|
1015
|
+
projectSeqEnd: runtime.projectSeq,
|
|
1016
|
+
fileSeqByPath,
|
|
1017
|
+
fileContentHashes: {},
|
|
1018
|
+
consumed: false,
|
|
1019
|
+
testFailures: existingGuard?.testFailures,
|
|
1020
|
+
testFailureContent: existingGuard?.testFailureContent,
|
|
1021
|
+
testFailureFiles: existingGuard?.testFailureFiles,
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
cacheManager.writeCache("turn-end-findings", { content }, cwd);
|
|
1026
|
+
}
|
|
861
1027
|
cacheManager.writeCache("turn-end-findings-last", {
|
|
862
1028
|
signature,
|
|
863
1029
|
sessionId: runtime.telemetrySessionId,
|
|
@@ -875,7 +1041,14 @@ export async function handleTurnEnd(deps) {
|
|
|
875
1041
|
});
|
|
876
1042
|
}
|
|
877
1043
|
if (blockerParts.length === 0) {
|
|
878
|
-
cacheManager.clearTurnState(cwd);
|
|
1044
|
+
cacheManager.clearTurnState(cwd, currentOwner);
|
|
1045
|
+
if (getFlag("lens-guard") && advisoryParts.length === 0 && !runtime.gitGuardHasBlockers) {
|
|
1046
|
+
const guardRecord = cacheManager.readCache("turn-end-findings", cwd)?.data;
|
|
1047
|
+
if (guardRecord?.sessionId === runtime.telemetrySessionId &&
|
|
1048
|
+
guardRecord.testFailures !== true) {
|
|
1049
|
+
cacheManager.clearCache("turn-end-findings", cwd);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
879
1052
|
}
|
|
880
1053
|
runtime.fixedThisTurn.clear();
|
|
881
1054
|
runtime.clearActionableWarnings();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Requires: cargo (rustup)
|
|
7
7
|
* Docs: https://doc.rust-lang.org/cargo/
|
|
8
8
|
*/
|
|
9
|
+
import { createSubsystemLogger } from "./extension-log.js";
|
|
9
10
|
import * as fs from "node:fs";
|
|
10
11
|
import * as path from "node:path";
|
|
11
12
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
@@ -28,7 +29,7 @@ export class RustClient {
|
|
|
28
29
|
log;
|
|
29
30
|
constructor(verbose = false) {
|
|
30
31
|
this.log = verbose
|
|
31
|
-
? (
|
|
32
|
+
? createSubsystemLogger("rust")
|
|
32
33
|
: () => { };
|
|
33
34
|
}
|
|
34
35
|
/**
|