@herbertgao/pi-extensions 2026.8.5 â 2026.8.7
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 +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +16 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +22 -15
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +34 -10
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +8 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
- package/node_modules/@narumitw/pi-btw/README.md +119 -103
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +13 -9
- package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +78 -15
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/pi-lens/CHANGELOG.md +1004 -0
- package/node_modules/pi-lens/README.md +11 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +427 -0
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
- package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.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 +11 -3
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +16 -4
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +81 -41
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +488 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +943 -93
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +49 -21
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
- package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +86 -15
- package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-events.js +56 -25
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +517 -69
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +172 -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 +61 -3
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +4 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +178 -30
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +85 -15
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- 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/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +76 -4
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +248 -13
- package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
- package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
- package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +224 -8
- package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/warm-attach.js +17 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +64677 -49484
- package/node_modules/pi-lens/dist/mcp/server.js +8 -2
- 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/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +44 -14
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +33 -6
- package/node_modules/pi-lens/docs/globalconfig.md +14 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +25 -1
- package/node_modules/pi-lens/docs/usage.md +24 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -6
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +22 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- 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-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- 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-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +66 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- 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-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +132 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +12 -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 +87 -116
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
- package/node_modules/pi-mcp-adapter/README.md +51 -6
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/cli.js +188 -5
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +28 -10
- package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +4 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +145 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +38 -18
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +95 -10
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +38 -14
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +8 -3
- package/node_modules/pi-web-access/curator-server.ts +5 -1
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +134 -37
- 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 +33 -7
- package/node_modules/pi-web-access/index.ts +160 -104
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +51 -23
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +13 -13
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1479/#1480: one place decides whether a test run was actually timed, and
|
|
3
|
+
* one place renders the answer.
|
|
4
|
+
*
|
|
5
|
+
* `TestResult.duration` is optional, and the two states are different facts.
|
|
6
|
+
* A present number is a MEASUREMENT â including `0`, because pytest really
|
|
7
|
+
* does print `in 0.00s` and a suite whose `startTime` equals its `endTime`
|
|
8
|
+
* really did run in under a millisecond. An absent value means no
|
|
9
|
+
* runner-reported figure was found at all.
|
|
10
|
+
*
|
|
11
|
+
* That contract was written down once, in the doc comment on
|
|
12
|
+
* `TestResult.duration`, and then re-derived at every site that reads or
|
|
13
|
+
* produces a duration. A reader of any one of those sites cannot see the
|
|
14
|
+
* contract, and a producer that reaches for `0` when it means "did not
|
|
15
|
+
* measure" reintroduces exactly the defect #1479 removed. These three
|
|
16
|
+
* functions are the contract in executable form: `isMeasuredDuration`
|
|
17
|
+
* classifies, `toMeasuredDurationMs` normalises a freshly parsed figure into
|
|
18
|
+
* it, and `formatRunDurationMs` renders it.
|
|
19
|
+
*
|
|
20
|
+
* NOTE FOR ANYONE EDITING `isMeasuredDuration`: the predicate is `>= 0`, not
|
|
21
|
+
* `> 0`. A measured zero is real. `> 0` looks like a harmless tightening and
|
|
22
|
+
* is the single change that would silently restore the bug.
|
|
23
|
+
*
|
|
24
|
+
* Kept in its own module rather than exported from `test-runner-client.ts`:
|
|
25
|
+
* `runtime-turn.ts` needs it on the hot turn-end path, and the client is
|
|
26
|
+
* deliberately loaded lazily (`bootstrap.ts` dynamic-imports it), so a value
|
|
27
|
+
* import from there would drag the whole runner into startup.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* True only for a value that represents a real measurement.
|
|
31
|
+
*
|
|
32
|
+
* `0` is measured. `undefined`, `null`, `NaN`, the infinities, and a negative
|
|
33
|
+
* figure are not: the last three can only come from a garbled parse, and a
|
|
34
|
+
* garbled parse must degrade to "we did not measure this", never to a wrong
|
|
35
|
+
* number.
|
|
36
|
+
*/
|
|
37
|
+
export function isMeasuredDuration(duration) {
|
|
38
|
+
return (typeof duration === "number" && Number.isFinite(duration) && duration >= 0);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Normalise a parsed elapsed time to the `TestResult.duration` contract.
|
|
42
|
+
*
|
|
43
|
+
* Returns whole milliseconds for a real reading â `0` included â and
|
|
44
|
+
* `undefined` for anything that is not one, so a producer never has to spell
|
|
45
|
+
* out the absent case itself.
|
|
46
|
+
*/
|
|
47
|
+
export function toMeasuredDurationMs(duration) {
|
|
48
|
+
return isMeasuredDuration(duration) ? Math.round(duration) : undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Render a duration for a log line: `123ms`, or `unmeasured` when absent. */
|
|
51
|
+
export function formatRunDurationMs(duration) {
|
|
52
|
+
return isMeasuredDuration(duration)
|
|
53
|
+
? `${Math.round(duration)}ms`
|
|
54
|
+
: "unmeasured";
|
|
55
|
+
}
|
|
@@ -5,11 +5,13 @@ 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
7
|
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
8
|
+
import { admitBounded, emitBounded } from "./bounded-telemetry.js";
|
|
8
9
|
import { newLspMutationCorrelationId } from "./lsp-mutation.js";
|
|
9
10
|
import { getGlobalActionableWarningMaxFixes, } from "./lens-config.js";
|
|
10
|
-
import { resyncLspFile, runFormatPhase } from "./pipeline.js";
|
|
11
|
+
import { resyncLspFile, runAutofix, runFormatPhase } from "./pipeline.js";
|
|
11
12
|
import { getAmbientAbortSignal } from "./safe-spawn.js";
|
|
12
13
|
import { appendProjectChange, } from "./project-changes.js";
|
|
14
|
+
import { getAutofixPolicyForFile, hasBiomeConfig, hasDetektConfig, hasEslintConfig, hasGolangciConfig, hasKtfmtConfig, hasKtlintConfig, hasOxlintConfig, hasRubocopConfig, hasSqlfluffConfig, hasStylelintConfig, } from "./tool-policy.js";
|
|
13
15
|
/**
|
|
14
16
|
* A queued file is claimed by any flush once it has sat unclaimed by its own
|
|
15
17
|
* owning session for this long â recovery for an orphaned record whose
|
|
@@ -40,21 +42,128 @@ function recordProjectChange(args) {
|
|
|
40
42
|
args.dbg(`project change log append failed for ${args.filePath}: ${err}`);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, dbg, runtime, cacheManager, getFormatService, currentSessionId, staleAfterMs = DEFERRED_FORMAT_STALE_AFTER_MS, }) {
|
|
45
|
+
export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, dbg, runtime, cacheManager, getFormatService, biomeClient, ruffClient, getAutofixClients, currentSessionId, staleAfterMs = DEFERRED_FORMAT_STALE_AFTER_MS, }) {
|
|
44
46
|
// #791: ownership-filtered drain â records queued by a DIFFERENT known
|
|
45
47
|
// session (e.g. a concurrent in-process secondary/subagent) stay queued
|
|
46
48
|
// for their owner's own agent_end, unless they've been stale long enough
|
|
47
49
|
// to fall back to "claim as orphaned" (see claimDeferredFormatFiles).
|
|
48
|
-
const { claimed, staleClaimed, deferredToOwner } = runtime.
|
|
50
|
+
const { claimed, staleClaimed, deferredToOwner, droppedOrphans } = runtime.claimDeferredMutations(currentSessionId, Date.now(), staleAfterMs, ctxCwd ?? runtime.projectRoot);
|
|
49
51
|
const records = [...claimed, ...staleClaimed];
|
|
52
|
+
const requeuedKinds = new Set();
|
|
53
|
+
// S2d (gap 4, #1432 review): the aggregate `agent_end_deferred_mutation_drain`
|
|
54
|
+
// row only carried a coalesced `requeuedKinds` set with no reason, per-call
|
|
55
|
+
// file count, or tool provenance â every requeue (abort mid-drain, missing
|
|
56
|
+
// autofix clients, an autofix/format failure) collapsed into one
|
|
57
|
+
// indistinguishable bucket. Log one bounded record PER requeue call instead,
|
|
58
|
+
// so a real incident can tell "aborted with N files still queued" apart
|
|
59
|
+
// from "M files failed to format".
|
|
60
|
+
const requeue = (pending, reason) => {
|
|
61
|
+
if (pending.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
const kinds = new Set();
|
|
64
|
+
const toolNames = new Set();
|
|
65
|
+
for (const record of pending) {
|
|
66
|
+
for (const kind of record.kinds) {
|
|
67
|
+
requeuedKinds.add(kind);
|
|
68
|
+
kinds.add(kind);
|
|
69
|
+
}
|
|
70
|
+
for (const toolName of record.toolNames)
|
|
71
|
+
toolNames.add(toolName);
|
|
72
|
+
}
|
|
73
|
+
logLatency({
|
|
74
|
+
type: "phase",
|
|
75
|
+
toolName: "agent_end",
|
|
76
|
+
filePath: ctxCwd ?? runtime.projectRoot,
|
|
77
|
+
phase: "agent_end_deferred_mutation_requeue",
|
|
78
|
+
durationMs: 0,
|
|
79
|
+
metadata: {
|
|
80
|
+
reason,
|
|
81
|
+
kinds: [...kinds].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
|
|
82
|
+
fileCount: pending.length,
|
|
83
|
+
toolNames: [...toolNames].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
runtime.requeueDeferredMutations(pending);
|
|
87
|
+
};
|
|
50
88
|
const rootActionableAutofixEnabled = !!getFlag("lens-actionable-warning-autofix");
|
|
89
|
+
// The actionable-warnings cache is only ever written when the
|
|
90
|
+
// "lens-actionable-warnings" writer flag is on (clients/runtime-turn.ts).
|
|
91
|
+
// A reader that ignores this gate always misses in a host where the
|
|
92
|
+
// writer is off and logs "cache missing or expired" at every agent_end,
|
|
93
|
+
// misdirecting the debug log toward a bogus cache problem instead of the
|
|
94
|
+
// real cause: the feature that populates the cache is disabled (#1607).
|
|
95
|
+
const actionableWarningsWriterEnabled = !!getFlag("lens-actionable-warnings");
|
|
51
96
|
// A path-aware source resolver signals that nested configs may re-enable
|
|
52
97
|
// actionable autofix even when the root default is off. Legacy/test hosts
|
|
53
98
|
// without that resolver keep the old fast exit and avoid a cache read.
|
|
54
|
-
const inspectActionableReport =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
const inspectActionableReport = actionableWarningsWriterEnabled &&
|
|
100
|
+
typeof cacheManager.readCache === "function" &&
|
|
101
|
+
(rootActionableAutofixEnabled || getFlagSource !== undefined);
|
|
102
|
+
if (droppedOrphans.length > 0) {
|
|
103
|
+
// #1642 F3: a stale/foreign record whose origin (the cwd/worktree it
|
|
104
|
+
// was actually queued under) does NOT match this flush's own
|
|
105
|
+
// workspace/worktree is left queued and NEVER formatted by this
|
|
106
|
+
// flush â claiming it would be the same worktreeâparent
|
|
107
|
+
// re-attribution the reported incident hit, just via the orphan
|
|
108
|
+
// fallback instead of tool_result's path resolution. It stays in
|
|
109
|
+
// `_pendingDeferredMutations` (not deleted) so a flush whose origin
|
|
110
|
+
// actually matches can still claim it later; a genuinely abandoned
|
|
111
|
+
// origin will keep surfacing this record on every subsequent
|
|
112
|
+
// agent_end, which is the deliberately safer trade-off over silently
|
|
113
|
+
// losing it forever.
|
|
114
|
+
dbg(`agent_end deferred_format: left ${droppedOrphans.length} orphaned file(s) queued due to a mismatched origin (unclaimed >${staleAfterMs}ms, not formatted by this flush): ${droppedOrphans
|
|
115
|
+
.map((r) => `${r.filePath} origin=${r.originCwd}`)
|
|
116
|
+
.join(", ")}`);
|
|
117
|
+
// #1678 item 1: a genuinely abandoned origin re-surfaces the SAME
|
|
118
|
+
// record on every subsequent agent_end for as long as the queued
|
|
119
|
+
// entry lives â by design (see the comment above), but the repo
|
|
120
|
+
// invariant is that a repeated degradation goes through the ledger's
|
|
121
|
+
// counting path instead of accumulating as unbounded raw log lines.
|
|
122
|
+
// The ledger is the single source of truth for whether THIS is a
|
|
123
|
+
// record's first appearance (its return value): the detailed forensic
|
|
124
|
+
// record below names only the orphans on that rising edge, with file
|
|
125
|
+
// identity/origin/age. Every later repeat of
|
|
126
|
+
// the same record is counted ONLY by the ledger's running count â
|
|
127
|
+
// no second raw event, no parallel "already logged" latch to
|
|
128
|
+
// maintain here.
|
|
129
|
+
// #1743: `admitBounded` IS that ledger call, plus the registry
|
|
130
|
+
// membership the bounded-telemetry sweep checks. This site admits PER
|
|
131
|
+
// ORPHAN and then writes ONE batched record naming the admitted ones,
|
|
132
|
+
// which is why it uses `admitBounded` directly instead of a per-record
|
|
133
|
+
// `emitBounded` â the per-call form would turn one log line into N.
|
|
134
|
+
const firstSeenOrphans = [];
|
|
135
|
+
for (const record of droppedOrphans) {
|
|
136
|
+
const isFirstOccurrence = admitBounded("agent_end_deferred_format_orphan_origin_mismatch", record.filePath, {
|
|
137
|
+
ledgerKind: "path-attribution-orphan-unresolved",
|
|
138
|
+
risingEdgePer: "identity",
|
|
139
|
+
reason: `origin=${record.originCwd} unclaimed >${staleAfterMs}ms`,
|
|
140
|
+
});
|
|
141
|
+
if (isFirstOccurrence)
|
|
142
|
+
firstSeenOrphans.push(record);
|
|
143
|
+
}
|
|
144
|
+
if (firstSeenOrphans.length > 0) {
|
|
145
|
+
// Already admitted above, one orphan at a time â hence no bounding
|
|
146
|
+
// options here. The batch's own identity is the origin this flush ran
|
|
147
|
+
// under; per-file identity rides in `metadata.files`.
|
|
148
|
+
emitBounded("agent_end_deferred_format_orphan_origin_mismatch", ctxCwd ?? runtime.projectRoot, {
|
|
149
|
+
type: "phase",
|
|
150
|
+
toolName: "agent_end",
|
|
151
|
+
durationMs: 0,
|
|
152
|
+
metadata: {
|
|
153
|
+
fileCount: firstSeenOrphans.length,
|
|
154
|
+
staleAfterMs,
|
|
155
|
+
currentOriginCwd: ctxCwd ?? runtime.projectRoot,
|
|
156
|
+
files: firstSeenOrphans.map((r) => ({
|
|
157
|
+
filePath: r.filePath,
|
|
158
|
+
originCwd: r.originCwd,
|
|
159
|
+
ownerSessionId: r.ownerSessionId,
|
|
160
|
+
queuedTurnIndex: r.queuedTurnIndex,
|
|
161
|
+
ageMs: Date.now() - r.lastTouchedAt,
|
|
162
|
+
})),
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
58
167
|
if (records.length === 0 && !inspectActionableReport)
|
|
59
168
|
return undefined;
|
|
60
169
|
if (deferredToOwner.length > 0) {
|
|
@@ -97,6 +206,86 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
97
206
|
// publishFilesTouched call so consumers can tell "pi-lens formatted this"
|
|
98
207
|
// from an agent edit.
|
|
99
208
|
const deferredFormatFixes = [];
|
|
209
|
+
const deferredAutofixFixes = [];
|
|
210
|
+
const deferredAutofixChanged = new Set();
|
|
211
|
+
// Mutation ordering is intentional: lint --write may disturb wrapping, so
|
|
212
|
+
// autofix reaches the final edited state first and formatting stabilizes it.
|
|
213
|
+
const ambientSignal = getAmbientAbortSignal();
|
|
214
|
+
const executedAutofixScopes = new Set();
|
|
215
|
+
const autofixRecords = records.filter((candidate) => candidate.kinds.has("autofix"));
|
|
216
|
+
if (autofixRecords.length > 0 && (!biomeClient || !ruffClient) && getAutofixClients) {
|
|
217
|
+
({ biomeClient, ruffClient } = await getAutofixClients());
|
|
218
|
+
}
|
|
219
|
+
for (let autofixIndex = 0; autofixIndex < autofixRecords.length; autofixIndex++) {
|
|
220
|
+
const record = autofixRecords[autofixIndex];
|
|
221
|
+
if (ambientSignal?.aborted) {
|
|
222
|
+
requeue(autofixRecords.slice(autofixIndex).map((pending) => ({
|
|
223
|
+
...pending,
|
|
224
|
+
kinds: new Set(["autofix"]),
|
|
225
|
+
toolNames: new Set(pending.toolNames),
|
|
226
|
+
})), "abort");
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
const filePath = path.resolve(record.filePath);
|
|
230
|
+
if (!nodeFs.existsSync(filePath)) {
|
|
231
|
+
summary.skipped.push({ filePath, reason: "missing" });
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (!biomeClient || !ruffClient) {
|
|
235
|
+
dbg(`agent_end deferred_autofix: clients unavailable for ${filePath}`);
|
|
236
|
+
requeue([{ ...record, kinds: new Set(["autofix"]), toolNames: new Set(record.toolNames) }], "clients-unavailable");
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const policy = getAutofixPolicyForFile(filePath, {
|
|
240
|
+
hasEslintConfig: hasEslintConfig(record.cwd),
|
|
241
|
+
hasStylelintConfig: hasStylelintConfig(record.cwd),
|
|
242
|
+
hasSqlfluffConfig: hasSqlfluffConfig(record.cwd),
|
|
243
|
+
hasRubocopConfig: hasRubocopConfig(record.cwd),
|
|
244
|
+
hasBiomeConfig: hasBiomeConfig(record.cwd),
|
|
245
|
+
hasGolangciConfig: hasGolangciConfig(record.cwd),
|
|
246
|
+
hasDetektConfig: hasDetektConfig(record.cwd),
|
|
247
|
+
hasOxlintConfig: hasOxlintConfig(record.cwd),
|
|
248
|
+
hasKtfmtConfig: hasKtfmtConfig(record.cwd),
|
|
249
|
+
hasKtlintConfig: hasKtlintConfig(record.cwd),
|
|
250
|
+
});
|
|
251
|
+
const scopeKey = policy?.scope && policy.scope !== "file"
|
|
252
|
+
? `${policy.defaultTool ?? "unknown"}:${path.resolve(record.cwd)}`
|
|
253
|
+
: `${policy?.defaultTool ?? "unknown"}:${filePath}`;
|
|
254
|
+
if (executedAutofixScopes.has(scopeKey))
|
|
255
|
+
continue;
|
|
256
|
+
executedAutofixScopes.add(scopeKey);
|
|
257
|
+
try {
|
|
258
|
+
const result = await runAutofix(filePath, record.cwd, getFlag, dbg, { biomeClient, ruffClient, fixedThisTurn: runtime.fixedThisTurn }, getFlagSource);
|
|
259
|
+
const tools = result.autofixTools.map((label) => label.split(":")[0]);
|
|
260
|
+
for (const changed of result.changedFiles) {
|
|
261
|
+
const changedPath = path.resolve(changed);
|
|
262
|
+
deferredAutofixChanged.add(changedPath);
|
|
263
|
+
for (const tool of tools)
|
|
264
|
+
deferredAutofixFixes.push({ path: changedPath, tool, kind: "autofix" });
|
|
265
|
+
if (!nodeFs.existsSync(changedPath))
|
|
266
|
+
continue;
|
|
267
|
+
recordProjectChange({ runtime, cwd: record.turnStateCwd, filePath: changedPath, source: "autofix", dbg });
|
|
268
|
+
if (!getFlag("no-read-guard"))
|
|
269
|
+
runtime.readGuard.recordWritten(changedPath);
|
|
270
|
+
const content = nodeFs.readFileSync(changedPath, "utf-8");
|
|
271
|
+
cacheManager.addModifiedRange(changedPath, { start: 1, end: content.split("\n").length }, /^import\s/m.test(content), record.turnStateCwd, currentSessionId ?? runtime.telemetrySessionId, "pi");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
276
|
+
summary.failed.push({ filePath, errors: [message] });
|
|
277
|
+
requeue([{ ...record, kinds: new Set(["autofix"]), toolNames: new Set(record.toolNames) }], "autofix-failed");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (deferredAutofixFixes.length > 0) {
|
|
281
|
+
publishFilesTouched({
|
|
282
|
+
reason: "autofix",
|
|
283
|
+
paths: [...new Set(deferredAutofixFixes.map((fix) => fix.path))],
|
|
284
|
+
cwd: ctxCwd ?? runtime.projectRoot,
|
|
285
|
+
dbg,
|
|
286
|
+
fixes: deferredAutofixFixes,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
100
289
|
dbg(`agent_end deferred_format: ${records.length} file(s)`);
|
|
101
290
|
logLatency({
|
|
102
291
|
type: "phase",
|
|
@@ -127,9 +316,10 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
127
316
|
cwd: ctxCwd ?? runtime.projectRoot,
|
|
128
317
|
paths: records.map((r) => r.filePath),
|
|
129
318
|
dbg,
|
|
319
|
+
kinds: [...new Set(records.flatMap((record) => [...record.kinds]))],
|
|
130
320
|
});
|
|
131
321
|
}
|
|
132
|
-
const formatRecords = records.filter((record) => {
|
|
322
|
+
const formatRecords = records.filter((record) => record.kinds.has("format")).filter((record) => {
|
|
133
323
|
const disabled = !!getFlag("no-autoformat", record.filePath);
|
|
134
324
|
if (disabled) {
|
|
135
325
|
const source = getFlagSource?.("no-autoformat", record.filePath);
|
|
@@ -145,7 +335,6 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
145
335
|
const work = new Array(formatRecords.length);
|
|
146
336
|
const started = new Set();
|
|
147
337
|
let nextIndex = 0;
|
|
148
|
-
const ambientSignal = getAmbientAbortSignal();
|
|
149
338
|
const worker = async () => {
|
|
150
339
|
while (nextIndex < formatRecords.length) {
|
|
151
340
|
const index = nextIndex++;
|
|
@@ -179,7 +368,11 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
179
368
|
};
|
|
180
369
|
await Promise.all(Array.from({ length: Math.min(DEFERRED_FORMAT_CONCURRENCY, formatRecords.length) }, () => worker()));
|
|
181
370
|
if (ambientSignal?.aborted) {
|
|
182
|
-
|
|
371
|
+
requeue(formatRecords.filter((_, index) => !started.has(index)).map((record) => ({
|
|
372
|
+
...record,
|
|
373
|
+
kinds: new Set(["format"]),
|
|
374
|
+
toolNames: new Set(record.toolNames),
|
|
375
|
+
})), "abort");
|
|
183
376
|
}
|
|
184
377
|
for (const entry of work) {
|
|
185
378
|
if (!entry)
|
|
@@ -188,12 +381,15 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
188
381
|
const { record, filePath, fileStart } = entry;
|
|
189
382
|
if (entry.missing) {
|
|
190
383
|
dbg(`agent_end deferred_format skipped missing file: ${filePath}`);
|
|
191
|
-
summary.skipped.
|
|
384
|
+
if (!summary.skipped.some((item) => item.filePath === filePath && item.reason === "missing")) {
|
|
385
|
+
summary.skipped.push({ filePath, reason: "missing" });
|
|
386
|
+
}
|
|
192
387
|
continue;
|
|
193
388
|
}
|
|
194
389
|
if (entry.error) {
|
|
195
390
|
dbg(`agent_end deferred_format failed for ${filePath}: ${entry.error}`);
|
|
196
391
|
summary.failed.push({ filePath, errors: [entry.error] });
|
|
392
|
+
requeue([{ ...record, kinds: new Set(["format"]), toolNames: new Set(record.toolNames) }], "format-failed");
|
|
197
393
|
continue;
|
|
198
394
|
}
|
|
199
395
|
const result = entry.result;
|
|
@@ -202,6 +398,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
202
398
|
summary.formatted++;
|
|
203
399
|
if (result.formatFailures.length > 0) {
|
|
204
400
|
summary.failed.push({ filePath, errors: result.formatFailures });
|
|
401
|
+
requeue([{ ...record, kinds: new Set(["format"]), toolNames: new Set(record.toolNames) }], "format-failed");
|
|
205
402
|
}
|
|
206
403
|
if (result.formatChanged) {
|
|
207
404
|
summary.changed.push(filePath);
|
|
@@ -268,10 +465,35 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
268
465
|
});
|
|
269
466
|
}
|
|
270
467
|
}
|
|
468
|
+
// LSP sees only authoritative content after both mutation phases. In
|
|
469
|
+
// particular, never publish the autofix intermediate state before format.
|
|
470
|
+
for (const changedPath of deferredAutofixChanged) {
|
|
471
|
+
if (!nodeFs.existsSync(changedPath))
|
|
472
|
+
continue;
|
|
473
|
+
const content = nodeFs.readFileSync(changedPath, "utf-8");
|
|
474
|
+
await resyncLspFile(changedPath, content, true, false, getFlag, dbg);
|
|
475
|
+
}
|
|
271
476
|
if (inspectActionableReport) {
|
|
272
|
-
const
|
|
477
|
+
const actionCwd = ctxCwd ?? runtime.projectRoot;
|
|
478
|
+
const actionableWarningsMaxAgeMs = 10 * 60_000;
|
|
479
|
+
const actionReport = cacheManager.readCache("actionable-warnings", actionCwd, actionableWarningsMaxAgeMs);
|
|
273
480
|
if (!actionReport?.data) {
|
|
274
|
-
|
|
481
|
+
// Distinguish "no cache file was ever written" from "a cache file
|
|
482
|
+
// exists but its TTL elapsed" (#1607) â both used to collapse into
|
|
483
|
+
// one "cache missing or expired" line, which doesn't tell a reader
|
|
484
|
+
// whether the writer ran and produced a stale file, or never ran.
|
|
485
|
+
const inspection = typeof cacheManager.inspectCache === "function"
|
|
486
|
+
? cacheManager.inspectCache("actionable-warnings", actionCwd, actionableWarningsMaxAgeMs)
|
|
487
|
+
: undefined;
|
|
488
|
+
if (inspection === "missing") {
|
|
489
|
+
dbg("agent_end actionable_warnings_autofix: cache absent, skipping fixes");
|
|
490
|
+
}
|
|
491
|
+
else if (inspection === "stale") {
|
|
492
|
+
dbg("agent_end actionable_warnings_autofix: cache expired, skipping fixes");
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
dbg(`agent_end actionable_warnings_autofix: cache missing or expired${inspection ? ` (${inspection})` : ""}, skipping fixes`);
|
|
496
|
+
}
|
|
275
497
|
}
|
|
276
498
|
else {
|
|
277
499
|
const enabledFiles = actionReport.data.files.filter((file) => {
|
|
@@ -384,6 +606,19 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
|
|
|
384
606
|
}
|
|
385
607
|
}
|
|
386
608
|
}
|
|
609
|
+
logLatency({
|
|
610
|
+
type: "phase",
|
|
611
|
+
toolName: "agent_end",
|
|
612
|
+
filePath: ctxCwd ?? runtime.projectRoot,
|
|
613
|
+
phase: "agent_end_deferred_mutation_drain",
|
|
614
|
+
durationMs: Date.now() - startedAt,
|
|
615
|
+
metadata: {
|
|
616
|
+
autofixRecords: autofixRecords.length,
|
|
617
|
+
formatRecords: formatRecords.length,
|
|
618
|
+
coalescedPaths: records.length,
|
|
619
|
+
requeuedKinds: [...requeuedKinds].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
|
|
620
|
+
},
|
|
621
|
+
});
|
|
387
622
|
logLatency({
|
|
388
623
|
type: "tool_result",
|
|
389
624
|
toolName: "agent_end",
|
|
@@ -1,22 +1,72 @@
|
|
|
1
|
+
import { provenanceStamp, validateAdvisoryProvenance, } from "./advisory-provenance.js";
|
|
2
|
+
import { logLatency } from "./latency-logger.js";
|
|
1
3
|
// Exported so the Stop-hook bin strips exactly what these bridges prepend.
|
|
2
4
|
export const AUTOMATION_FRAMING = "[pi-lens automated check â not a user request] ";
|
|
3
|
-
|
|
5
|
+
// #1432 review (S3b): a multi-file bash write can carry hundreds of changed
|
|
6
|
+
// paths, one `reasons` entry apiece â logging all of them shrinks the
|
|
7
|
+
// smells-rollup tail window (a fixed-size ring) to a handful of these
|
|
8
|
+
// records. Cap what this decision row carries; the full list is never
|
|
9
|
+
// needed for triage, only "how many and roughly what kind".
|
|
10
|
+
const MAX_LOGGED_REASONS = 8;
|
|
11
|
+
function boundedReasons(reasons) {
|
|
12
|
+
if (reasons.length <= MAX_LOGGED_REASONS)
|
|
13
|
+
return reasons;
|
|
14
|
+
return [
|
|
15
|
+
...reasons.slice(0, MAX_LOGGED_REASONS),
|
|
16
|
+
`+${reasons.length - MAX_LOGGED_REASONS} more`,
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
function logProvenanceDecision(validation, provenance, advisoryKind, cwd) {
|
|
20
|
+
logLatency({
|
|
21
|
+
type: "phase",
|
|
22
|
+
phase: "advisory_provenance_decision",
|
|
23
|
+
filePath: cwd,
|
|
24
|
+
durationMs: 0,
|
|
25
|
+
metadata: {
|
|
26
|
+
decision: validation.status === "current" ? "current" : "historical",
|
|
27
|
+
reasons: boundedReasons(validation.reasons),
|
|
28
|
+
changedPathCount: validation.changedPathCount,
|
|
29
|
+
provenanceStamp: provenanceStamp(provenance),
|
|
30
|
+
advisoryKind,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function historicalPrefix(provenance) {
|
|
35
|
+
return `Historical finding; workspace changed since capture; re-run to confirm. (${provenanceStamp(provenance)})`;
|
|
36
|
+
}
|
|
37
|
+
function historicalTestContent(content, provenance) {
|
|
38
|
+
return content.startsWith("[from a prior turn")
|
|
39
|
+
? content
|
|
40
|
+
: `${historicalPrefix(provenance)}\n\n${content}`;
|
|
41
|
+
}
|
|
42
|
+
function turnEndMessage(content, current, provenance) {
|
|
4
43
|
return {
|
|
5
44
|
role: "user",
|
|
6
|
-
content:
|
|
45
|
+
content: current
|
|
46
|
+
? `${AUTOMATION_FRAMING}Address đ´ blockers before continuing; âšī¸ advisories are informational only.\n\n${content}`
|
|
47
|
+
: `${AUTOMATION_FRAMING}${historicalPrefix(provenance)}\n\n${content}`,
|
|
7
48
|
};
|
|
8
49
|
}
|
|
9
50
|
/** Read a turn-end finding without changing its durable delivery state. */
|
|
10
|
-
export function peekTurnEndFindings(cacheManager, cwd) {
|
|
51
|
+
export function peekTurnEndFindings(cacheManager, cwd, runtime, logDelivery = false) {
|
|
11
52
|
const findings = cacheManager.readCache("turn-end-findings", cwd);
|
|
12
53
|
if (!findings?.data?.content || findings.data.consumed === true)
|
|
13
54
|
return;
|
|
14
|
-
|
|
55
|
+
const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
|
|
56
|
+
if (logDelivery)
|
|
57
|
+
logProvenanceDecision(validation, findings.data.provenance, "turn-end", cwd);
|
|
58
|
+
if (validation.allFilesDeleted)
|
|
59
|
+
return;
|
|
60
|
+
return {
|
|
61
|
+
messages: [turnEndMessage(findings.data.content, validation.status === "current", findings.data.provenance)],
|
|
62
|
+
};
|
|
15
63
|
}
|
|
16
|
-
export function consumeTurnEndFindings(cacheManager, cwd) {
|
|
64
|
+
export function consumeTurnEndFindings(cacheManager, cwd, runtime) {
|
|
17
65
|
const findings = cacheManager.readCache("turn-end-findings", cwd);
|
|
18
66
|
if (!findings?.data?.content || findings.data.consumed === true)
|
|
19
67
|
return;
|
|
68
|
+
const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
|
|
69
|
+
logProvenanceDecision(validation, findings.data.provenance, "turn-end", cwd);
|
|
20
70
|
// A blocker record is also the opt-in commit gate's durable state. Mark the
|
|
21
71
|
// context message consumed without deleting the record; clean/advisory-only
|
|
22
72
|
// records retain the historical consume-and-clear behavior.
|
|
@@ -27,34 +77,84 @@ export function consumeTurnEndFindings(cacheManager, cwd) {
|
|
|
27
77
|
else {
|
|
28
78
|
cacheManager.clearCache("turn-end-findings", cwd);
|
|
29
79
|
}
|
|
30
|
-
|
|
80
|
+
if (validation.allFilesDeleted)
|
|
81
|
+
return;
|
|
82
|
+
return {
|
|
83
|
+
messages: [turnEndMessage(findings.data.content, validation.status === "current", findings.data.provenance)],
|
|
84
|
+
};
|
|
31
85
|
}
|
|
32
86
|
/** Read test findings without consuming them; used by acknowledged IPC delivery. */
|
|
33
|
-
export function peekTestFindings(cacheManager, cwd) {
|
|
87
|
+
export function peekTestFindings(cacheManager, cwd, runtime, logDelivery = false) {
|
|
34
88
|
const findings = cacheManager.readCache("test-runner-findings", cwd);
|
|
35
89
|
if (!findings?.data?.content)
|
|
36
90
|
return;
|
|
91
|
+
const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
|
|
92
|
+
if (logDelivery)
|
|
93
|
+
logProvenanceDecision(validation, findings.data.provenance, "test-findings", cwd);
|
|
94
|
+
if (validation.allFilesDeleted)
|
|
95
|
+
return;
|
|
96
|
+
const current = validation.status === "current";
|
|
37
97
|
return {
|
|
38
98
|
messages: [
|
|
39
99
|
{
|
|
40
100
|
role: "user",
|
|
41
|
-
content:
|
|
101
|
+
content: current
|
|
102
|
+
? `${AUTOMATION_FRAMING}Test failures detected last turn â fix before continuing:\n\n${findings.data.content}`
|
|
103
|
+
: `${AUTOMATION_FRAMING}${historicalTestContent(findings.data.content, findings.data.provenance)}`,
|
|
42
104
|
},
|
|
43
105
|
],
|
|
44
106
|
};
|
|
45
107
|
}
|
|
46
|
-
export function consumeTestFindings(cacheManager, cwd) {
|
|
47
|
-
const
|
|
108
|
+
export function consumeTestFindings(cacheManager, cwd, runtime) {
|
|
109
|
+
const record = cacheManager.readCache("test-runner-findings", cwd);
|
|
110
|
+
if (!record?.data?.content)
|
|
111
|
+
return;
|
|
112
|
+
const findings = peekTestFindings(cacheManager, cwd, runtime, true);
|
|
48
113
|
if (!findings)
|
|
49
114
|
return;
|
|
50
|
-
|
|
115
|
+
// Retire the content but PRESERVE the generation high-water mark: nulling
|
|
116
|
+
// the whole slot would let a still-in-flight OLDER batch see `undefined`,
|
|
117
|
+
// pass the strictly-greater suppression check, and resurrect a consumed
|
|
118
|
+
// one-shot advisory with stale results. An empty-content record peeks as
|
|
119
|
+
// undelivered while keeping late-generation ordering intact.
|
|
120
|
+
const priorGeneration = cacheManager.readCache("test-runner-findings", cwd)?.data?.testRunGeneration;
|
|
121
|
+
cacheManager.writeCache("test-runner-findings", { content: "", testRunGeneration: priorGeneration }, cwd);
|
|
51
122
|
return findings;
|
|
52
123
|
}
|
|
124
|
+
/** Complete an acknowledged MCP delivery without re-validating or re-rendering it. */
|
|
125
|
+
export function acknowledgeTurnEndFindings(cacheManager, cwd) {
|
|
126
|
+
const findings = cacheManager.readCache("turn-end-findings", cwd);
|
|
127
|
+
if (!findings?.data?.content || findings.data.consumed === true)
|
|
128
|
+
return;
|
|
129
|
+
if (findings.data.hasBlockers === true && typeof findings.data.sessionId === "string") {
|
|
130
|
+
cacheManager.writeCache("turn-end-findings", { ...findings.data, consumed: true }, cwd);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
cacheManager.clearCache("turn-end-findings", cwd);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function acknowledgeTestFindings(cacheManager, cwd) {
|
|
137
|
+
const findings = cacheManager.readCache("test-runner-findings", cwd);
|
|
138
|
+
if (!findings?.data?.content)
|
|
139
|
+
return;
|
|
140
|
+
// Same high-water-mark preservation as consumeTestFindings.
|
|
141
|
+
cacheManager.writeCache("test-runner-findings", {
|
|
142
|
+
content: "",
|
|
143
|
+
testRunGeneration: findings.data.testRunGeneration,
|
|
144
|
+
}, cwd);
|
|
145
|
+
}
|
|
53
146
|
export function consumeSessionStartGuidance(cacheManager, cwd) {
|
|
54
147
|
const guidance = cacheManager.readCache("session-start-guidance", cwd);
|
|
55
148
|
if (!guidance?.data?.content)
|
|
56
149
|
return;
|
|
57
|
-
|
|
150
|
+
// Consume by writing empty guidance, not by casting `null` into the entry's
|
|
151
|
+
// own type. `writeCache` infers its type parameter from `data`, so the cast
|
|
152
|
+
// bought nothing and claimed the file held a `{ content: string }` when it
|
|
153
|
+
// held JSON `null`. The producer (`runtime-session.ts`) always writes
|
|
154
|
+
// `{ content }`, and this reader gates on `data?.content` being non-empty,
|
|
155
|
+
// so an empty string is the same "already consumed" signal with the type
|
|
156
|
+
// the entry actually has. Same idiom as `acknowledgeTestFindings` above.
|
|
157
|
+
cacheManager.writeCache("session-start-guidance", { content: "" }, cwd);
|
|
58
158
|
return {
|
|
59
159
|
messages: [
|
|
60
160
|
{
|