@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
|
@@ -164,6 +164,22 @@ export const LENS_FLAGS = [
|
|
|
164
164
|
default: false,
|
|
165
165
|
scope: "global",
|
|
166
166
|
},
|
|
167
|
+
{
|
|
168
|
+
name: "no-lazy-tools",
|
|
169
|
+
description: "Keep all pi-lens tools active to avoid tool-list cache changes. Also via tools.lazy=false in ~/.pi-lens/config.json.",
|
|
170
|
+
configKey: "tools.lazy",
|
|
171
|
+
negated: true,
|
|
172
|
+
default: false,
|
|
173
|
+
scope: "global",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "lens-turn-end-madge",
|
|
177
|
+
description: "Run the per-turn-end madge circular-dependency check on import-changed files. Off by default: the pass only writes debug output, and user-facing madge diagnostics come from the session-start scan cache + lens_diagnostics. Also via turnEnd.madge.enabled=true in ~/.pi-lens/config.json.",
|
|
178
|
+
configKey: "turnEnd.madge.enabled",
|
|
179
|
+
negated: false,
|
|
180
|
+
default: false,
|
|
181
|
+
scope: "global",
|
|
182
|
+
},
|
|
167
183
|
];
|
|
168
184
|
const byName = new Map(LENS_FLAGS.map((spec) => [spec.name, spec]));
|
|
169
185
|
export function getLensFlagSpec(name) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { recordDegradation } from "./degradation-ledger.js";
|
|
2
|
+
import { probeCtxActive } from "./session-lifecycle.js";
|
|
3
|
+
import { logBusEvent, } from "./bus-events-logger.js";
|
|
2
4
|
const STALE_CTX_MESSAGE = "This extension ctx is stale after session replacement";
|
|
3
5
|
/** Ledger a dead activation once, at the publisher's occurrence-window guard. */
|
|
4
6
|
export function recordStaleBusFailure(subject, error) {
|
|
@@ -19,8 +21,26 @@ export function createLiveBusEmitter() {
|
|
|
19
21
|
getter = next;
|
|
20
22
|
emit = undefined;
|
|
21
23
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
resolve() {
|
|
25
|
+
// Invoke the getter for every delivery so session_start rewiring can
|
|
26
|
+
// replace a captured pre-await activation with the current primary. When
|
|
27
|
+
// the current target is nevertheless confirmed stale, never invoke it.
|
|
28
|
+
const target = getter?.() ?? emit;
|
|
29
|
+
if (!target)
|
|
30
|
+
return { outcome: "unwired", ctxSource: "unwired" };
|
|
31
|
+
if (typeof target === "function") {
|
|
32
|
+
return { outcome: "ready", emit: target, ctxSource: "global-fallback" };
|
|
33
|
+
}
|
|
34
|
+
// Object targets are always "own"-sourced (only `wire(fn)`'s bare
|
|
35
|
+
// function arm is "global-fallback", and it never reaches this
|
|
36
|
+
// branch) — compute it once so the ready/stale-session outcomes
|
|
37
|
+
// below both carry the same value instead of restating the
|
|
38
|
+
// literal independently.
|
|
39
|
+
const ctxSource = "own";
|
|
40
|
+
if (probeCtxActive(target.ctx) === false) {
|
|
41
|
+
return { outcome: "stale-session", ctxSource };
|
|
42
|
+
}
|
|
43
|
+
return { outcome: "ready", emit: target.emit, ctxSource };
|
|
24
44
|
},
|
|
25
45
|
reset() {
|
|
26
46
|
emit = undefined;
|
|
@@ -28,3 +48,26 @@ export function createLiveBusEmitter() {
|
|
|
28
48
|
},
|
|
29
49
|
};
|
|
30
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve through the shared stale-session guard and record a declined
|
|
53
|
+
* target.
|
|
54
|
+
*
|
|
55
|
+
* `entry` is a THUNK, not a value (M1, #1415 review): building the log entry
|
|
56
|
+
* (every producer's version normalizes `cwd` via `normalizeFilePath`, a sync
|
|
57
|
+
* `realpathSync.native` call on Windows) is real per-publish cost that used
|
|
58
|
+
* to be paid on EVERY call regardless of outcome, even though it is only
|
|
59
|
+
* consumed on the `stale-session` branch. Invoking the thunk only there means
|
|
60
|
+
* the common `ready` path pays nothing for it.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveLiveBusEmitter(liveEmitter, entry) {
|
|
63
|
+
const resolution = liveEmitter.resolve();
|
|
64
|
+
if (resolution.outcome === "stale-session") {
|
|
65
|
+
logBusEvent({
|
|
66
|
+
...entry(),
|
|
67
|
+
outcome: "skipped_stale_session",
|
|
68
|
+
level: "info",
|
|
69
|
+
ctxSource: resolution.ctxSource,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return resolution;
|
|
73
|
+
}
|
|
@@ -26,9 +26,12 @@
|
|
|
26
26
|
* receive `options.auxGraceMs` before the race finalises. Aux results within
|
|
27
27
|
* that window are included; later arrivals are dropped. When no descriptors
|
|
28
28
|
* carry `role:"auxiliary"` the aux-grace path is never entered.
|
|
29
|
-
* @param options.auxGraceMs -
|
|
30
|
-
* primary promises have settled. Only relevant when at
|
|
31
|
-
* carries `role:"auxiliary"`. Defaults to 500ms.
|
|
29
|
+
* @param options.auxGraceMs - Ceiling on the grace period given to auxiliary
|
|
30
|
+
* promises after all primary promises have settled. Only relevant when at
|
|
31
|
+
* least one descriptor carries `role:"auxiliary"`. Defaults to 500ms. When a
|
|
32
|
+
* still-pending auxiliary's descriptor carries `budgetMs`, the actual window
|
|
33
|
+
* is `min(auxGraceMs, max(budgetMs of still-pending auxiliaries))` — see
|
|
34
|
+
* `PromiseDescriptor.budgetMs`.
|
|
32
35
|
*/
|
|
33
36
|
export async function raceToCompletion(promises, shouldComplete, options = { timeoutMs: 1500 }) {
|
|
34
37
|
const results = new Array(promises.length).fill(undefined);
|
|
@@ -76,7 +79,30 @@ export async function raceToCompletion(promises, shouldComplete, options = { tim
|
|
|
76
79
|
if (auxGraceStarted || completed)
|
|
77
80
|
return;
|
|
78
81
|
auxGraceStarted = true;
|
|
79
|
-
const
|
|
82
|
+
const ceilingMs = options.auxGraceMs ?? 500;
|
|
83
|
+
// #1458 S2: cap the grace window by the still-pending auxiliaries' own
|
|
84
|
+
// declared budgets, not just the flat ceiling — mirrors touchFile's
|
|
85
|
+
// per-server `min(declared, ceiling)`.
|
|
86
|
+
//
|
|
87
|
+
// This is ONE shared timer, not a deadline per promise, so it grants
|
|
88
|
+
// every pending auxiliary the window of its slowest pending sibling.
|
|
89
|
+
// That is safe here only because of an invariant the caller upholds,
|
|
90
|
+
// not because of anything this function enforces: every promise
|
|
91
|
+
// `getDiagnostics` passes in is already self-bounded by the same
|
|
92
|
+
// `strategy.aggregateWaitMs` it declares as `budgetMs`, so a fast
|
|
93
|
+
// auxiliary resolves on its own deadline long before a slow sibling's
|
|
94
|
+
// window expires. A caller that passes a promise NOT self-bounded by
|
|
95
|
+
// its descriptor's `budgetMs` — or one that outlives it, the way
|
|
96
|
+
// `expectSemanticSecondPush` extends a primary — would get a window
|
|
97
|
+
// wider than it declared. `PromiseDescriptor` is public, so treat that
|
|
98
|
+
// as a real constraint on new callers rather than a theoretical one.
|
|
99
|
+
const pendingAuxBudgets = [...auxIndices]
|
|
100
|
+
.filter((i) => results[i] === undefined)
|
|
101
|
+
.map((i) => descriptors[i]?.budgetMs)
|
|
102
|
+
.filter((b) => typeof b === "number" && b >= 0);
|
|
103
|
+
const graceMs = pendingAuxBudgets.length > 0
|
|
104
|
+
? Math.min(ceilingMs, Math.max(...pendingAuxBudgets))
|
|
105
|
+
: ceilingMs;
|
|
80
106
|
if (graceMs <= 0) {
|
|
81
107
|
finalize();
|
|
82
108
|
return;
|
|
@@ -32,6 +32,12 @@
|
|
|
32
32
|
* NOT tier-3 — the caller keeps today's full in-lane wait. Fail-safe is
|
|
33
33
|
* always "wait like before".
|
|
34
34
|
*
|
|
35
|
+
* Native TS7 is the cascade-only exception. It is not silent on clean, but
|
|
36
|
+
* its publication does not settle inside the cold-snapshot budget. Cascade
|
|
37
|
+
* classifies it as `collect-later`, sends the same no-wait touch, and
|
|
38
|
+
* reconciles its later per-file push or pull publication. The shared server
|
|
39
|
+
* policy remains `waits`, so main-lane behavior does not change.
|
|
40
|
+
*
|
|
35
41
|
* #524/#529/#541/#558: a server id can now be backed by more than one actual
|
|
36
42
|
* binary — "typescript" is classic typescript-language-server OR TS7's
|
|
37
43
|
* native `tsc --lsp --stdio` (PR #526). PR #526 originally routed the
|
|
@@ -46,18 +52,46 @@
|
|
|
46
52
|
* confirmed still silent (`cleanPubs=0(v:0)`) in the same run. This is
|
|
47
53
|
* therefore an EVIDENCE-BASED revert, not the original unverified caution:
|
|
48
54
|
* native-ts7's clean-signal behavior IS known, and it is "publishes, not
|
|
49
|
-
* silent". The
|
|
50
|
-
*
|
|
51
|
-
*
|
|
55
|
+
* silent". The shared classifier still routes a native-ts7 snapshot through
|
|
56
|
+
* `waits`. The cascade-only wrapper routes it through `collect-later` because
|
|
57
|
+
* the measured publication arrives after the in-lane budget. The shared
|
|
58
|
+
* `silentOnClean` flag stays `true` for classic.
|
|
59
|
+
* `scripts/probe-clean-signal.mjs`'s drift check no
|
|
52
60
|
* longer compares native-ts7 rows against the shared marker (it now expects
|
|
53
61
|
* `false` for them explicitly) — see that file's header for the regression
|
|
54
62
|
* watch this sets up for a future TS7 build that becomes silent again.
|
|
55
63
|
*/
|
|
56
64
|
import { logCascade } from "../cascade-logger.js";
|
|
65
|
+
import { incrementDegradationCount } from "../degradation-ledger.js";
|
|
57
66
|
import { logLatency } from "../latency-logger.js";
|
|
58
67
|
import { normalizeMapKey } from "../path-utils.js";
|
|
59
68
|
import { registerQuietWindowTask } from "../quiet-window.js";
|
|
60
|
-
|
|
69
|
+
import { classifyCascadeWaitTier as classifySharedCascadeWaitTier, classifyServerWaitTier, resolvePrimaryServerForWaitPolicy, } from "./wait-policy/classification.js";
|
|
70
|
+
export { classifyServerWaitTier };
|
|
71
|
+
/**
|
|
72
|
+
* The cascade lane's wait tier for `filePath`. DELEGATES to the shared
|
|
73
|
+
* `wait-policy/classification.ts` rule — this wrapper adds exactly one
|
|
74
|
+
* cascade-only override on top of it (native TS7's push-only snapshot →
|
|
75
|
+
* `collect-later`) and never re-implements the classification itself.
|
|
76
|
+
*
|
|
77
|
+
* #1444 coverage tradeoff: the no-wait touch this tier selects is
|
|
78
|
+
* `clientScope: "primary"`, and the tier itself is decided from the PRIMARY
|
|
79
|
+
* (non-auxiliary) server alone. That tradeoff already existed for
|
|
80
|
+
* `tier3-silent`; the override enlarges the population it applies to — every
|
|
81
|
+
* native-TS7 TypeScript neighbour now takes the no-wait path too, so an
|
|
82
|
+
* auxiliary server configured for those files no longer gets touched in-lane
|
|
83
|
+
* for them (its findings arrive via the next per-edit dispatch, as they
|
|
84
|
+
* already did for classic tier-3 files).
|
|
85
|
+
*/
|
|
86
|
+
export function classifyCascadeWaitTier(lspService, filePath, snapshots) {
|
|
87
|
+
const primary = resolvePrimaryServerForWaitPolicy(filePath, snapshots);
|
|
88
|
+
if (primary?.serverId === "typescript" &&
|
|
89
|
+
primary.snapshot?.launchVariant === "native-ts7" &&
|
|
90
|
+
primary.snapshot.workspaceDiagnosticsSupport?.mode === "push-only") {
|
|
91
|
+
return "collect-later";
|
|
92
|
+
}
|
|
93
|
+
return classifySharedCascadeWaitTier(lspService, filePath, snapshots);
|
|
94
|
+
}
|
|
61
95
|
// --- Kill switch (lazy, memoized — house style per clients/runtime-config.ts /
|
|
62
96
|
// clients/quiet-window.ts's isQuietWindowEnabled) ---
|
|
63
97
|
let _enabledCache;
|
|
@@ -78,20 +112,88 @@ export function _resetTierAwareCascadeEnabledForTests() {
|
|
|
78
112
|
// replaces the earlier entry (only the most recent touch matters — an
|
|
79
113
|
// older touch's diagnostics, if they ever arrive, are still a strict superset
|
|
80
114
|
// concern the newer touch already re-supersedes via didOpen/didChange).
|
|
115
|
+
//
|
|
116
|
+
// #1899: the registry is drained in full by every reconcile sweep, but nothing
|
|
117
|
+
// bounded it BETWEEN sweeps. The sweep runs on pi's `agent_settled` quiet
|
|
118
|
+
// window, and a session can go a long time without one — dogfood logs show
|
|
119
|
+
// sweeps up to 52 minutes apart. So the two bounds below are the registry's
|
|
120
|
+
// own, independent of when a sweep arrives:
|
|
121
|
+
//
|
|
122
|
+
// - `MAX_OUTSTANDING_TOUCHES` caps the entry count. Entries are held in
|
|
123
|
+
// touch order (see `recordOutstandingCascadeTouch`), so eviction takes the
|
|
124
|
+
// oldest touch at O(1).
|
|
125
|
+
// - `OUTSTANDING_TOUCH_MAX_AGE_MS` caps how long a touch stays reconcilable.
|
|
126
|
+
// Past it, the touch is discarded rather than answered: re-injecting a
|
|
127
|
+
// neighbour error, or clearing a footer entry, from a touch fired that
|
|
128
|
+
// long ago reports a state the agent has already moved past.
|
|
129
|
+
//
|
|
130
|
+
// Both constants are sized from the 2026-08-09..20 dogfood window (cascade.log,
|
|
131
|
+
// 67 sweeps / 756 entries): the largest single sweep held 53 entries, and a
|
|
132
|
+
// 15-minute age bound retains 72 of the 80 outcomes that ever resolved (90%)
|
|
133
|
+
// while discarding the tail that resolved after ~26-52 minutes.
|
|
134
|
+
const MAX_OUTSTANDING_TOUCHES = 256;
|
|
135
|
+
const OUTSTANDING_TOUCH_MAX_AGE_MS = 15 * 60_000;
|
|
81
136
|
const _outstandingTouches = new Map();
|
|
137
|
+
/** Entries dropped by the age bound since the last sweep reported. */
|
|
138
|
+
let _expiredSinceLastSweep = 0;
|
|
139
|
+
/** Entries dropped by the size cap since the last sweep reported. */
|
|
140
|
+
let _evictedSinceLastSweep = 0;
|
|
141
|
+
/**
|
|
142
|
+
* Drop every entry older than `OUTSTANDING_TOUCH_MAX_AGE_MS`. The map is held
|
|
143
|
+
* in touch order, so the expired entries are a prefix and the walk stops at
|
|
144
|
+
* the first live one.
|
|
145
|
+
*/
|
|
146
|
+
function pruneExpiredOutstandingTouches(now) {
|
|
147
|
+
for (const [key, touch] of _outstandingTouches) {
|
|
148
|
+
if (now - touch.touchedAt <= OUTSTANDING_TOUCH_MAX_AGE_MS)
|
|
149
|
+
break;
|
|
150
|
+
_outstandingTouches.delete(key);
|
|
151
|
+
_expiredSinceLastSweep++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
82
154
|
/**
|
|
83
155
|
* Record a Tier-3 cascade touch that skipped its in-lane wait. Called right
|
|
84
156
|
* after the (still-performed) didOpen/didChange notify, before returning
|
|
85
157
|
* without waiting. `touchedAt` must be sampled BEFORE the notify (see the
|
|
86
158
|
* field doc) so the reconcile comparison can never misread a publish that
|
|
87
159
|
* raced the record as pre-touch.
|
|
160
|
+
*
|
|
161
|
+
* #1899: also enforces the registry's two bounds. The `delete` before the
|
|
162
|
+
* `set` is load-bearing — `Map.set` on an existing key keeps the key's
|
|
163
|
+
* ORIGINAL insertion position, so without it a re-touched file would keep a
|
|
164
|
+
* stale position and both the age prefix walk and the oldest-first eviction
|
|
165
|
+
* would pick the wrong entry.
|
|
88
166
|
*/
|
|
89
167
|
export function recordOutstandingCascadeTouch(entry) {
|
|
90
|
-
|
|
168
|
+
const key = normalizeMapKey(entry.filePath);
|
|
169
|
+
_outstandingTouches.delete(key);
|
|
170
|
+
// `Date.now()`, not `entry.touchedAt`: the caller samples `touchedAt` before
|
|
171
|
+
// its notify, so it trails real time, and the age bound is a statement about
|
|
172
|
+
// the clock rather than about the newest touch's own stamp.
|
|
173
|
+
pruneExpiredOutstandingTouches(Date.now());
|
|
174
|
+
_outstandingTouches.set(key, entry);
|
|
175
|
+
while (_outstandingTouches.size > MAX_OUTSTANDING_TOUCHES) {
|
|
176
|
+
const oldest = _outstandingTouches.keys().next();
|
|
177
|
+
if (oldest.done)
|
|
178
|
+
break;
|
|
179
|
+
_outstandingTouches.delete(oldest.value);
|
|
180
|
+
_evictedSinceLastSweep++;
|
|
181
|
+
// Bounded by construction: one ledger tally per session, not per
|
|
182
|
+
// eviction event. The subject is the cap itself rather than the evicted
|
|
183
|
+
// path — the discriminating fact is "this session overflowed the tier-3
|
|
184
|
+
// backlog", and per-path subjects would unbound the ledger group.
|
|
185
|
+
incrementDegradationCount({
|
|
186
|
+
kind: "cascade-tier3-backlog-evicted",
|
|
187
|
+
subject: `cap=${MAX_OUTSTANDING_TOUCHES}`,
|
|
188
|
+
reason: "tier-3 outstanding-touch registry hit its cap before a quiet-window reconcile drained it; the oldest touch was dropped unanswered",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
91
191
|
}
|
|
92
192
|
/** Test-only: clear the outstanding-touch registry between test cases. */
|
|
93
193
|
export function _resetOutstandingCascadeTouchesForTests() {
|
|
94
194
|
_outstandingTouches.clear();
|
|
195
|
+
_expiredSinceLastSweep = 0;
|
|
196
|
+
_evictedSinceLastSweep = 0;
|
|
95
197
|
}
|
|
96
198
|
/** Test-only: peek at the registry without mutating it. */
|
|
97
199
|
export function _getOutstandingCascadeTouchesForTests() {
|
|
@@ -122,6 +224,10 @@ export function _getOutstandingCascadeTouchesForTests() {
|
|
|
122
224
|
*/
|
|
123
225
|
export async function reconcileOutstandingCascadeTouches(lspService) {
|
|
124
226
|
const outcomes = [];
|
|
227
|
+
// #1899: the age bound applies at sweep time too, not only at record time —
|
|
228
|
+
// a registry that received no further touches would otherwise hand the sweep
|
|
229
|
+
// entries of unbounded age.
|
|
230
|
+
pruneExpiredOutstandingTouches(Date.now());
|
|
125
231
|
const entries = [..._outstandingTouches.entries()];
|
|
126
232
|
_outstandingTouches.clear();
|
|
127
233
|
for (const [key, touch] of entries) {
|
|
@@ -133,6 +239,7 @@ export async function reconcileOutstandingCascadeTouches(lspService) {
|
|
|
133
239
|
filePath: touch.filePath,
|
|
134
240
|
serverId: touch.serverId,
|
|
135
241
|
outcome: "unresolved",
|
|
242
|
+
unresolvedReason: spawned ? "server-mismatch" : "warm-miss",
|
|
136
243
|
ageMs,
|
|
137
244
|
});
|
|
138
245
|
continue;
|
|
@@ -147,6 +254,7 @@ export async function reconcileOutstandingCascadeTouches(lspService) {
|
|
|
147
254
|
filePath: touch.filePath,
|
|
148
255
|
serverId: touch.serverId,
|
|
149
256
|
outcome: "unresolved",
|
|
257
|
+
unresolvedReason: entry ? "no-publish-since-touch" : "no-publish",
|
|
150
258
|
ageMs,
|
|
151
259
|
});
|
|
152
260
|
continue;
|
|
@@ -158,6 +266,7 @@ export async function reconcileOutstandingCascadeTouches(lspService) {
|
|
|
158
266
|
outcome: found ? "resolved-found" : "resolved-clean",
|
|
159
267
|
ageMs,
|
|
160
268
|
diagnosticCount: entry.diags.length,
|
|
269
|
+
publishedAt: entry.ts,
|
|
161
270
|
// #1023: carry the diagnostics so the task can re-surface them.
|
|
162
271
|
...(found && { diagnostics: entry.diags }),
|
|
163
272
|
});
|
|
@@ -167,6 +276,7 @@ export async function reconcileOutstandingCascadeTouches(lspService) {
|
|
|
167
276
|
filePath: touch.filePath,
|
|
168
277
|
serverId: touch.serverId,
|
|
169
278
|
outcome: "unresolved",
|
|
279
|
+
unresolvedReason: "error",
|
|
170
280
|
ageMs,
|
|
171
281
|
});
|
|
172
282
|
logLatency({
|
|
@@ -193,23 +303,30 @@ export function registerCascadeTierReconcileTask(getLspService, options = {}) {
|
|
|
193
303
|
registerQuietWindowTask("cascade_tier3_reconcile", async () => {
|
|
194
304
|
if (!isTierAwareCascadeEnabled())
|
|
195
305
|
return;
|
|
196
|
-
if (_outstandingTouches.size === 0)
|
|
197
|
-
return;
|
|
198
306
|
const outcomes = await reconcileOutstandingCascadeTouches(getLspService());
|
|
199
|
-
if (outcomes.length === 0)
|
|
200
|
-
return;
|
|
201
307
|
// #1023: re-inject each resolved-found neighbor error so it reaches the
|
|
202
|
-
// agent (previously logs-only).
|
|
203
|
-
//
|
|
308
|
+
// agent (previously logs-only). #1444: hand each resolved-CLEAN outcome to
|
|
309
|
+
// the footer reconcile for the mirror-image case. Isolated per-outcome — a
|
|
310
|
+
// throwing callback must not drop the log line or the sibling deliveries.
|
|
204
311
|
for (const o of outcomes) {
|
|
205
|
-
if (o.outcome !== "resolved-found" || !o.diagnostics?.length)
|
|
206
|
-
continue;
|
|
207
312
|
try {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
313
|
+
if (o.outcome === "resolved-found" && o.diagnostics?.length) {
|
|
314
|
+
options.onResolvedFound?.({
|
|
315
|
+
filePath: o.filePath,
|
|
316
|
+
serverId: o.serverId,
|
|
317
|
+
diagnostics: o.diagnostics,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
else if (o.outcome === "resolved-clean" && o.publishedAt != null) {
|
|
321
|
+
// #1444: the stale-footer half of the same honesty problem — the
|
|
322
|
+
// neighbour proved clean, but only after the in-lane wait was
|
|
323
|
+
// skipped, so nothing has cleared its earlier error entries.
|
|
324
|
+
options.onResolvedClean?.({
|
|
325
|
+
filePath: o.filePath,
|
|
326
|
+
serverId: o.serverId,
|
|
327
|
+
publishedAt: o.publishedAt,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
213
330
|
}
|
|
214
331
|
catch {
|
|
215
332
|
// best-effort surfacing; the log below is the durable record.
|
|
@@ -219,16 +336,31 @@ export function registerCascadeTierReconcileTask(getLspService, options = {}) {
|
|
|
219
336
|
let resolvedClean = 0;
|
|
220
337
|
let unresolved = 0;
|
|
221
338
|
let ageSumMs = 0;
|
|
339
|
+
let maxAgeMs = 0;
|
|
340
|
+
const unresolvedByReason = {};
|
|
222
341
|
for (const o of outcomes) {
|
|
223
342
|
if (o.outcome === "resolved-found")
|
|
224
343
|
resolvedFound++;
|
|
225
344
|
else if (o.outcome === "resolved-clean")
|
|
226
345
|
resolvedClean++;
|
|
227
|
-
else
|
|
346
|
+
else {
|
|
228
347
|
unresolved++;
|
|
348
|
+
const reason = o.unresolvedReason ?? "no-publish";
|
|
349
|
+
unresolvedByReason[reason] = (unresolvedByReason[reason] ?? 0) + 1;
|
|
350
|
+
}
|
|
229
351
|
ageSumMs += o.ageMs;
|
|
352
|
+
if (o.ageMs > maxAgeMs)
|
|
353
|
+
maxAgeMs = o.ageMs;
|
|
230
354
|
}
|
|
231
|
-
const avgAgeMs =
|
|
355
|
+
const avgAgeMs = outcomes.length
|
|
356
|
+
? Math.round(ageSumMs / outcomes.length)
|
|
357
|
+
: 0;
|
|
358
|
+
// #1899: emitted on EVERY sweep, including the empty one. The backlog's
|
|
359
|
+
// size was previously observable only when it was non-empty, so "the
|
|
360
|
+
// queue is drained" and "the sweep never ran" read identically in
|
|
361
|
+
// cascade.log. This record is the backlog gauge: what the sweep drained,
|
|
362
|
+
// what the two bounds dropped since the last sweep, and what the bounds
|
|
363
|
+
// are, so a reader never has to know the constants to judge the numbers.
|
|
232
364
|
logCascade({
|
|
233
365
|
phase: "cascade_tier3_reconcile",
|
|
234
366
|
filePath: "<quiet-window>",
|
|
@@ -237,10 +369,18 @@ export function registerCascadeTierReconcileTask(getLspService, options = {}) {
|
|
|
237
369
|
resolvedFound,
|
|
238
370
|
resolvedClean,
|
|
239
371
|
unresolved,
|
|
372
|
+
unresolvedByReason,
|
|
240
373
|
avgAgeMs,
|
|
374
|
+
maxAgeMs,
|
|
375
|
+
expired: _expiredSinceLastSweep,
|
|
376
|
+
evicted: _evictedSinceLastSweep,
|
|
377
|
+
capacity: MAX_OUTSTANDING_TOUCHES,
|
|
378
|
+
maxAgeCapMs: OUTSTANDING_TOUCH_MAX_AGE_MS,
|
|
241
379
|
outcomes,
|
|
242
380
|
},
|
|
243
381
|
});
|
|
382
|
+
_expiredSinceLastSweep = 0;
|
|
383
|
+
_evictedSinceLastSweep = 0;
|
|
244
384
|
});
|
|
245
385
|
}
|
|
246
386
|
/** Test-only: undo registerCascadeTierReconcileTask's idempotency guard. */
|