@herbertgao/pi-extensions 2026.8.6 → 2026.8.8
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 +8 -6
- 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 +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -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 +6 -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 +17 -13
- 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 +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- 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 +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -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 +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- 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 +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- 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 +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -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 +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- 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 +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -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 +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- 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/dead-code-client.js +123 -31
- 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 +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- 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/detekt.js +9 -6
- 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/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- 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 +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- 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 +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- 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 +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- 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 +734 -64
- 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 +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- 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 +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- 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 +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- 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-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- 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 +277 -16
- 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 +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- 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/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- 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 +154 -33
- 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 +84 -14
- 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/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- 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 +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -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/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- 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 +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- 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-logger.js +1 -0
- 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/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -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 +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- 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 +15 -1
- 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-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 +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- 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-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 +57 -12
- 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-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 +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- 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 +6 -1
- 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 +53 -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/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- 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/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -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-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- 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 +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- 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/pdf-extract.ts +18 -5
- 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/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- 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/package.json +14 -14
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { resetBoundedTelemetry } from "./bounded-telemetry.js";
|
|
3
4
|
import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
|
|
4
5
|
import { deadCodeIssueCount } from "./dead-code-client.js";
|
|
5
6
|
import { logDeadCodeScan } from "./dead-code-logger.js";
|
|
6
|
-
import { resetDegradationLedger } from "./degradation-ledger.js";
|
|
7
|
+
import { incrementDegradationCount, resetDegradationLedger, } from "./degradation-ledger.js";
|
|
7
8
|
import { getDiagnosticTracker } from "./diagnostic-tracker.js";
|
|
9
|
+
import { resetPsScriptAnalyzerAvailability } from "./dispatch/runners/psscriptanalyzer.js";
|
|
10
|
+
import { resetInstallRetryLatches } from "./dispatch/runners/utils/availability-policy.js";
|
|
11
|
+
import { resetLazyInstallAttempts } from "./dispatch/runners/utils/lazy-installer.js";
|
|
8
12
|
import { resetDispatchAvailabilityState } from "./dispatch/runners/utils/runner-helpers.js";
|
|
9
13
|
import { clearAllSessions as clearFileTimeSessions } from "./file-time.js";
|
|
10
14
|
import { getGlobalPiLensDir, getKnipIgnorePatterns, getProjectDataDir, } from "./file-utils.js";
|
|
@@ -15,12 +19,19 @@ import { canRunStartupHeavyScans } from "./language-policy.js";
|
|
|
15
19
|
import { detectProjectLanguageProfile, getDefaultStartupTools, } from "./language-profile.js";
|
|
16
20
|
import { logLatency } from "./latency-logger.js";
|
|
17
21
|
import { runLogCleanup } from "./log-cleanup.js";
|
|
22
|
+
import { resetCascadeTierSessionState } from "./lsp/cascade-tier.js";
|
|
18
23
|
import { initLSPConfig, loadLSPConfig } from "./lsp/config.js";
|
|
24
|
+
import { resetWorkspaceDiagnosticsCacheSession } from "./lsp/workspace-diagnostics-session.js";
|
|
25
|
+
import { resetDirectLspCommandAvailability } from "./lsp/server.js";
|
|
19
26
|
import { loadLspService } from "./lsp-lazy.js";
|
|
27
|
+
import { resetManagedToolRefreshSession } from "./installer/managed-tool-refresh-session.js";
|
|
28
|
+
import { resetResolvedPathCache } from "./installer/index.js";
|
|
29
|
+
import { _resetPackageManagerCache } from "./package-manager.js";
|
|
30
|
+
import { clearFormatterCache } from "./formatters.js";
|
|
20
31
|
import { isAtOrAboveHomeDir } from "./path-utils.js";
|
|
21
32
|
import { isPrintMode } from "./print-mode.js";
|
|
22
33
|
import { readLatestProjectSequence, readLatestProjectSequenceAsync, } from "./project-changes.js";
|
|
23
|
-
import { getProjectSnapshotPath, hydrateRuntimeFromProjectSnapshot, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
|
|
34
|
+
import { getProjectSnapshotPath, getProjectSnapshotLegacyPath, hydrateRuntimeFromProjectSnapshot, hydrateRuntimeFromProjectSnapshotIfIdle, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, loadProjectSnapshotExportsAndRules, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
|
|
24
35
|
import { clearTsconfigPathsCache } from "./review-graph/tsconfig-paths.js";
|
|
25
36
|
import { scanProjectRules } from "./rules-scanner.js";
|
|
26
37
|
import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
|
|
@@ -33,6 +44,27 @@ import { isWarmAttached } from "./warm-attach.js";
|
|
|
33
44
|
import { setSessionLanguages } from "./widget-state.js";
|
|
34
45
|
import { logWordIndex } from "./word-index-logger.js";
|
|
35
46
|
import { resetWorkspaceTopology } from "./workspace-topology.js";
|
|
47
|
+
import { resetZizmorTokenAvailability } from "./zizmor-config.js";
|
|
48
|
+
const HOST_STALL_THRESHOLD_MS = 30_000;
|
|
49
|
+
function logHostReadyDelay(deps, cwd) {
|
|
50
|
+
if (!deps.emitHostReadyDelay ||
|
|
51
|
+
deps.sessionStartMonotonicAt === undefined ||
|
|
52
|
+
deps.extensionLoadedAt === undefined) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const durationMs = Math.max(0, deps.sessionStartMonotonicAt - deps.extensionLoadedAt);
|
|
56
|
+
logLatency({
|
|
57
|
+
type: "phase",
|
|
58
|
+
filePath: cwd,
|
|
59
|
+
phase: "host_ready_delay",
|
|
60
|
+
durationMs,
|
|
61
|
+
metadata: {
|
|
62
|
+
hostStallSuspected: durationMs > HOST_STALL_THRESHOLD_MS,
|
|
63
|
+
sessionStart: "first-process-session",
|
|
64
|
+
reason: deps.sessionReason,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
36
68
|
function resolveSnapshotRoot(cwd) {
|
|
37
69
|
const resolvedCwd = path.resolve(cwd);
|
|
38
70
|
const nearest = findNearestProjectRoot(resolvedCwd);
|
|
@@ -79,6 +111,91 @@ function snapshotSequenceBase(root) {
|
|
|
79
111
|
sinceSeq: meta.seq,
|
|
80
112
|
};
|
|
81
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* #1785: one bounded ledger record per timed-out sequence read, so a real
|
|
116
|
+
* occurrence is diagnosable from the ledger alone rather than only from a
|
|
117
|
+
* `dbg` line that most hosts never surface. Carries the project root and the
|
|
118
|
+
* on-disk snapshot's age/size (when one exists) — the identity AC1 asks for:
|
|
119
|
+
* which project, how stale/large the snapshot that got skipped was.
|
|
120
|
+
*/
|
|
121
|
+
function recordSnapshotSequenceTimeout(args) {
|
|
122
|
+
let reason = "sequence read timed out; no snapshot on disk";
|
|
123
|
+
try {
|
|
124
|
+
const stat = nodeFs.statSync(args.snapshotPath);
|
|
125
|
+
reason = `sequence read timed out; snapshot age=${Math.round(Date.now() - stat.mtimeMs)}ms size=${stat.size}b`;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// No snapshot on disk yet — the reason above already covers it.
|
|
129
|
+
}
|
|
130
|
+
incrementDegradationCount({
|
|
131
|
+
kind: "snapshot-sequence-read-timeout",
|
|
132
|
+
subject: args.snapshotRoot,
|
|
133
|
+
reason,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* #1785: the synchronous freshness check made a conservative call with the
|
|
138
|
+
* `UNKNOWN_PROJECT_SEQ` sentinel (never hydrate when the real sequence is
|
|
139
|
+
* unknown). Once the deferred read resolves — a deterministic completion
|
|
140
|
+
* signal, not a sleep — this re-checks freshness against the now-known
|
|
141
|
+
* sequence and hydrates late when the snapshot really was current, instead of
|
|
142
|
+
* leaving the runtime without `cachedExports`/`projectRulesScan` for the rest
|
|
143
|
+
* of the session.
|
|
144
|
+
*
|
|
145
|
+
* #1785 review round F5 (design (a), replacing rounds 1-3's synchronous
|
|
146
|
+
* capture entirely): quick mode's own cold-start warmup ALREADY loads the
|
|
147
|
+
* on-disk snapshot for its own purposes — `cachedSnapshot` at the top of the
|
|
148
|
+
* warmup body, used to reuse a still-fresh `startupScan` verdict — strictly
|
|
149
|
+
* BEFORE the warmup's own possible save (`saveRuntimeProjectSnapshot`, only
|
|
150
|
+
* reached when that verdict was NOT fresh). Reusing THAT already-loaded
|
|
151
|
+
* value costs nothing new: the read was always going to happen regardless of
|
|
152
|
+
* this fix, and it is guaranteed to predate any overwrite the SAME warmup
|
|
153
|
+
* invocation might go on to make — a read-before-write invariant of the
|
|
154
|
+
* warmup's own code, not something this function has to defend against with
|
|
155
|
+
* a race window of its own. `getWarmupOwnSnapshotRead` is a closure over a
|
|
156
|
+
* per-`handleSessionStart`-call LOCAL variable (never module-scope — #1785
|
|
157
|
+
* F6 is exactly the class of bug a module-scope holder here would
|
|
158
|
+
* reintroduce) that the warmup publishes into once its own read completes.
|
|
159
|
+
*
|
|
160
|
+
* When the getter still returns `undefined` — the deferred read resolved
|
|
161
|
+
* before the warmup got that far (or no warmup was ever armed by this call:
|
|
162
|
+
* a later quick-mode call in the same process, print mode, full mode) —
|
|
163
|
+
* there is nothing published yet, so this falls back to a live re-load via
|
|
164
|
+
* `loadProjectSnapshotExportsAndRules`. That fallback is exactly as safe as
|
|
165
|
+
* the primary path: if the warmup hasn't reached its own read yet, it
|
|
166
|
+
* certainly hasn't saved yet either (same invariant), so disk still holds
|
|
167
|
+
* whatever was there before any warmup activity.
|
|
168
|
+
*
|
|
169
|
+
* Both the published value and the fallback re-load are the narrow,
|
|
170
|
+
* postings-free `ProjectSnapshotExportsAndRules` shape — never the full
|
|
171
|
+
* `loadProjectSnapshot`. This path only ever hydrates
|
|
172
|
+
* `cachedExports`/`projectRulesScan`; it can NOT hydrate `wordIndex` even
|
|
173
|
+
* when the underlying snapshot would otherwise have one, because the narrow
|
|
174
|
+
* type never carries it. That is intentional, not a regression: F2's hazard
|
|
175
|
+
* was this exact path nulling a `wordIndex` that quick mode's warmup had, in
|
|
176
|
+
* the meantime, built for real — the warmup remains the sole source of a
|
|
177
|
+
* late-arriving `wordIndex` for the interactive path.
|
|
178
|
+
*/
|
|
179
|
+
function retroactivelyHydrateAfterDeferredSequence(args) {
|
|
180
|
+
return (latestSeq) => {
|
|
181
|
+
const published = args.getWarmupOwnSnapshotRead();
|
|
182
|
+
const snapshot = published !== undefined
|
|
183
|
+
? published
|
|
184
|
+
: loadProjectSnapshotExportsAndRules(args.snapshotRoot);
|
|
185
|
+
if (!snapshot ||
|
|
186
|
+
snapshot.version !== PROJECT_SNAPSHOT_VERSION ||
|
|
187
|
+
snapshot.seq !== latestSeq.projectSeq) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const hydrated = hydrateRuntimeFromProjectSnapshotIfIdle(args.runtime, snapshot);
|
|
191
|
+
if (hydrated) {
|
|
192
|
+
args.dbg(`session_start: deferred sequence read confirmed snapshot freshness — hydrating cachedExports/projectRulesScan late (seq=${snapshot.seq})`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
args.dbg(`session_start: deferred sequence read confirmed snapshot freshness (seq=${snapshot.seq}), but the runtime already has live state (warmup or another task got there first) — skipping late hydration to avoid clobbering it`);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
82
199
|
function loadSnapshotBodyUnlessStale(args) {
|
|
83
200
|
const meta = readProjectSnapshotMeta(args.root);
|
|
84
201
|
if (meta && isProjectSnapshotMetaStale(meta, args.currentProjectSeq)) {
|
|
@@ -90,12 +207,17 @@ function loadSnapshotBodyUnlessStale(args) {
|
|
|
90
207
|
skippedStale: false,
|
|
91
208
|
};
|
|
92
209
|
}
|
|
93
|
-
function describeSnapshotMiss(snapshot, currentProjectSeq) {
|
|
210
|
+
function describeSnapshotMiss(snapshot, currentProjectSeq, args) {
|
|
211
|
+
if (args.skippedStale)
|
|
212
|
+
return "stale-meta-gate";
|
|
94
213
|
if (!snapshot)
|
|
95
|
-
return "missing";
|
|
214
|
+
return args.bodyPresent ? "invalid-body" : "missing";
|
|
96
215
|
if (snapshot.seq !== currentProjectSeq) {
|
|
97
216
|
return `stale(seq=${snapshot.seq}, current=${currentProjectSeq})`;
|
|
98
217
|
}
|
|
218
|
+
// Defensive-only arm: parseSnapshot rejects incompatible versions, and a
|
|
219
|
+
// same-sequence parsed snapshot is fresh. Keep this classification explicit
|
|
220
|
+
// so a future loader change cannot collapse it into a generic miss.
|
|
99
221
|
return "incompatible";
|
|
100
222
|
}
|
|
101
223
|
function logProjectSnapshotProbe(args) {
|
|
@@ -104,7 +226,7 @@ function logProjectSnapshotProbe(args) {
|
|
|
104
226
|
args.dbg(`project_snapshot: loaded seq=${args.snapshot.seq} exports=${args.snapshot.cachedExports.length} files=${Object.keys(args.snapshot.files ?? {}).length} reverseDeps=${Object.keys(args.snapshot.reverseDeps ?? {}).length} startupScan=${Boolean(args.snapshot.startupScan)} languageProfile=${Boolean(args.snapshot.languageProfile)}`);
|
|
105
227
|
}
|
|
106
228
|
else {
|
|
107
|
-
args.dbg(`project_snapshot: miss reason=${
|
|
229
|
+
args.dbg(`project_snapshot: miss reason=${args.missReason}`);
|
|
108
230
|
}
|
|
109
231
|
}
|
|
110
232
|
function resolveStartupMode() {
|
|
@@ -171,7 +293,7 @@ const UNKNOWN_PROJECT_SEQ = -1;
|
|
|
171
293
|
* logs its own `session_start_sequence_read_deferred_reseed` phase.
|
|
172
294
|
*/
|
|
173
295
|
async function readSequenceWithBudget(args) {
|
|
174
|
-
const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg } = args;
|
|
296
|
+
const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg, onDeferredSequenceResolved, } = args;
|
|
175
297
|
const readPromise = readLatestProjectSequenceAsync(snapshotRoot, base);
|
|
176
298
|
let timeoutHandle;
|
|
177
299
|
const timeoutPromise = new Promise((resolve) => {
|
|
@@ -224,6 +346,7 @@ async function readSequenceWithBudget(args) {
|
|
|
224
346
|
metadata: { entries: latestSeq.fileSeqByPath.size, deferred: true },
|
|
225
347
|
});
|
|
226
348
|
dbg(`session_start: deferred sequence read completed — reseeded projectSeq=${latestSeq.projectSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
349
|
+
onDeferredSequenceResolved?.(latestSeq);
|
|
227
350
|
})
|
|
228
351
|
.catch((err) => {
|
|
229
352
|
dbg(`session_start: deferred sequence read failed: ${err}`);
|
|
@@ -375,6 +498,47 @@ function firePreinstallDefaults(ensureTool, dbg, startupDefaults) {
|
|
|
375
498
|
});
|
|
376
499
|
}
|
|
377
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Default delay before the managed-tool version refresh runs (#1730). Long
|
|
503
|
+
* enough that `session_start`, the startup scans, and the tool preinstalls have
|
|
504
|
+
* all settled — the refresh may spawn one `npm update`, and that must never
|
|
505
|
+
* compete with the work the user is waiting on.
|
|
506
|
+
*/
|
|
507
|
+
const MANAGED_TOOL_REFRESH_DELAY_MS = 30_000;
|
|
508
|
+
/**
|
|
509
|
+
* Schedule the periodic managed-tool refresh (#1730) on an unref'd background
|
|
510
|
+
* timer.
|
|
511
|
+
*
|
|
512
|
+
* `session_start`'s own cost here is a single `setTimeout` registration: the
|
|
513
|
+
* refresh module is not even imported until the timer fires. The timer is
|
|
514
|
+
* unref'd so a one-shot process exits without waiting for it, matching the
|
|
515
|
+
* warmup timer above. Whether a refresh actually runs is decided inside
|
|
516
|
+
* `runManagedToolRefresh` against a PERSISTED per-tool stamp, so a launch loop
|
|
517
|
+
* cannot escalate the weekly cadence.
|
|
518
|
+
*/
|
|
519
|
+
function scheduleManagedToolRefresh(dbg) {
|
|
520
|
+
const delayMs = Number(process.env.PI_LENS_TOOL_REFRESH_DELAY_MS ?? MANAGED_TOOL_REFRESH_DELAY_MS);
|
|
521
|
+
const timer = setTimeout(() => {
|
|
522
|
+
void (async () => {
|
|
523
|
+
try {
|
|
524
|
+
const refresh = await import("./installer/managed-tool-refresh.js");
|
|
525
|
+
const outcome = await refresh.runManagedToolRefresh();
|
|
526
|
+
if (outcome.skipped) {
|
|
527
|
+
dbg(`session_start tool-refresh: skipped (${outcome.skipped})`);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
for (const result of outcome.refreshed) {
|
|
531
|
+
dbg(`session_start tool-refresh: ${result.toolId} ${result.ok ? "ok" : "failed"}` +
|
|
532
|
+
`${result.changed ? ` ${result.previousVersion ?? "unknown"} → ${result.currentVersion}` : " (unchanged)"}`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
dbg(`session_start tool-refresh: error ${err}`);
|
|
537
|
+
}
|
|
538
|
+
})();
|
|
539
|
+
}, Number.isFinite(delayMs) ? delayMs : MANAGED_TOOL_REFRESH_DELAY_MS);
|
|
540
|
+
timer.unref?.();
|
|
541
|
+
}
|
|
378
542
|
async function probePrettierInstall(ensureTool, dbg, analysisRoot) {
|
|
379
543
|
const pkgPath = path.join(analysisRoot, "package.json");
|
|
380
544
|
try {
|
|
@@ -715,7 +879,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
|
|
|
715
879
|
// KnipClient skips before probing/installing when analysisRoot is not a real
|
|
716
880
|
// JS/Knip project. This avoids running knip from Unity/C#/generic repos.
|
|
717
881
|
const startMs = Date.now();
|
|
718
|
-
const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns());
|
|
882
|
+
const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns(), { projectSeq: runtime.projectSeq });
|
|
719
883
|
if (!runtime.isCurrentSession(sessionGeneration))
|
|
720
884
|
return;
|
|
721
885
|
if (knipResult.success) {
|
|
@@ -1121,6 +1285,12 @@ export const SESSION_START_GUIDANCE = [
|
|
|
1121
1285
|
];
|
|
1122
1286
|
export async function handleSessionStart(deps) {
|
|
1123
1287
|
resetDegradationLedger();
|
|
1288
|
+
// #1743: the bounded-telemetry per-turn counters. The rising-edge state is
|
|
1289
|
+
// NOT here — it is the ledger's own tally, reset on the line above. These
|
|
1290
|
+
// counters are keyed by turn index, and a new session restarts turn
|
|
1291
|
+
// numbering at 0, so without this a stale count could survive a session
|
|
1292
|
+
// boundary that happened to land on the same index.
|
|
1293
|
+
resetBoundedTelemetry();
|
|
1124
1294
|
const handlerEnteredAt = Date.now();
|
|
1125
1295
|
const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
|
|
1126
1296
|
const cwdForTelemetry = deps.ctxCwd ?? process.cwd();
|
|
@@ -1175,6 +1345,11 @@ export async function handleSessionStart(deps) {
|
|
|
1175
1345
|
// (an explicit env var still takes highest precedence).
|
|
1176
1346
|
// Tunable: PI_LENS_WARMUP_DELAY_MS adjusts the warmup delay.
|
|
1177
1347
|
let startupMode = resolveStartupMode();
|
|
1348
|
+
// SAFETY: these two flags are process-lifetime state pi-lens stashes on
|
|
1349
|
+
// `globalThis` so a second extension instance in the same process sees the
|
|
1350
|
+
// first one's warmup. There is no ambient declaration for them, and adding
|
|
1351
|
+
// one would let any module write them. Both are declared OPTIONAL here, so
|
|
1352
|
+
// the reads below are `undefined`-safe on a process where nothing set them.
|
|
1178
1353
|
const processGlobals = globalThis;
|
|
1179
1354
|
const isFirstSessionOfProcess = !processGlobals.__piLensFirstSessionDone;
|
|
1180
1355
|
if (isFirstSessionOfProcess &&
|
|
@@ -1185,6 +1360,20 @@ export async function handleSessionStart(deps) {
|
|
|
1185
1360
|
startupMode = deps.startupModeOverride ?? "quick";
|
|
1186
1361
|
}
|
|
1187
1362
|
processGlobals.__piLensFirstSessionDone = true;
|
|
1363
|
+
// #1785 F5 (round 4, design (a)): the warmup timer body below ALREADY
|
|
1364
|
+
// loads the on-disk snapshot for its own purposes (`cachedSnapshot`,
|
|
1365
|
+
// reused for the `startupScan` verdict cache) strictly BEFORE any save it
|
|
1366
|
+
// might go on to make. This LOCAL variable — per-`handleSessionStart`-call,
|
|
1367
|
+
// deliberately NOT module-scope (see #1785 F6) — lets the warmup publish
|
|
1368
|
+
// that already-loaded read (narrowed to exports+rules, never the full
|
|
1369
|
+
// object with `wordIndex`) for `retroactivelyHydrateAfterDeferredSequence`
|
|
1370
|
+
// to reuse at zero additional cost, instead of this call paying for its
|
|
1371
|
+
// own separate synchronous capture (rounds 1-3's approach, reverted here:
|
|
1372
|
+
// see that function's doc comment for the full history). `undefined`
|
|
1373
|
+
// means the warmup hasn't reached its own read yet (or was never armed by
|
|
1374
|
+
// this call at all) — the quick-mode block's retroactive-hydration
|
|
1375
|
+
// callback then falls back to a live re-load instead.
|
|
1376
|
+
let warmupOwnSnapshotRead;
|
|
1188
1377
|
// #1154: quick mode is entered on BOTH `pi -p`/`--print` (a one-shot that
|
|
1189
1378
|
// exits right after this turn) and an interactive process's first
|
|
1190
1379
|
// session_start (forced quick to protect keystroke latency, then warms
|
|
@@ -1232,6 +1421,23 @@ export async function handleSessionStart(deps) {
|
|
|
1232
1421
|
// reuse it instead of re-walking a possibly huge tree from
|
|
1233
1422
|
// scratch on every single startup.
|
|
1234
1423
|
const cachedSnapshot = loadProjectSnapshot(warmupSnapshotRoot);
|
|
1424
|
+
// #1785 F5 (round 4): publish this ALREADY-loaded read — narrowed
|
|
1425
|
+
// to exports+rules, never a reference to `cachedSnapshot` itself
|
|
1426
|
+
// (which carries `wordIndex`/`files`/`symbols`/`reverseDeps`) — for
|
|
1427
|
+
// `retroactivelyHydrateAfterDeferredSequence` to reuse. This read
|
|
1428
|
+
// strictly precedes the warmup's own possible save a few lines
|
|
1429
|
+
// below, so it is guaranteed to reflect disk as it stood before
|
|
1430
|
+
// THIS warmup could have touched it. Zero marginal cost: this read
|
|
1431
|
+
// already happens unconditionally for the `startupScan` verdict
|
|
1432
|
+
// cache below, with or without this fix.
|
|
1433
|
+
warmupOwnSnapshotRead = cachedSnapshot
|
|
1434
|
+
? {
|
|
1435
|
+
version: cachedSnapshot.version,
|
|
1436
|
+
seq: cachedSnapshot.seq,
|
|
1437
|
+
cachedExports: cachedSnapshot.cachedExports,
|
|
1438
|
+
projectRulesScan: cachedSnapshot.projectRulesScan,
|
|
1439
|
+
}
|
|
1440
|
+
: null;
|
|
1235
1441
|
const cachedVerdict = cachedSnapshot?.startupScan;
|
|
1236
1442
|
let scan;
|
|
1237
1443
|
if (cachedVerdict &&
|
|
@@ -1381,7 +1587,7 @@ export async function handleSessionStart(deps) {
|
|
|
1381
1587
|
}
|
|
1382
1588
|
const allowBootstrapTasks = startupMode === "full";
|
|
1383
1589
|
const quickMode = startupMode === "quick";
|
|
1384
|
-
const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
|
|
1590
|
+
const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, knipClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
|
|
1385
1591
|
// Lightweight phase timer — resets after each call so each log line shows
|
|
1386
1592
|
// the cost of that phase alone, not cumulative time from session start.
|
|
1387
1593
|
let _phaseT = Date.now();
|
|
@@ -1415,9 +1621,74 @@ export async function handleSessionStart(deps) {
|
|
|
1415
1621
|
// the tool for the rest of the process lifetime. Clear it here, same
|
|
1416
1622
|
// boundary as the other per-session caches on this line.
|
|
1417
1623
|
resetDispatchAvailabilityState();
|
|
1624
|
+
// #1895: formatter PATH verdicts are session-scoped, but they live in
|
|
1625
|
+
// formatters.ts and are not covered by the dispatch generation. Re-arm them
|
|
1626
|
+
// here so a formatter installed or removed between sessions is observed by
|
|
1627
|
+
// the next session. `clearFormatterCache` drops the per-cwd selection cache
|
|
1628
|
+
// as well as the which latches, which is what a real re-probe needs: the
|
|
1629
|
+
// selection cache answers a same-cwd lookup before any probe runs, so
|
|
1630
|
+
// clearing the latches alone would leave the stale verdict standing in the
|
|
1631
|
+
// one directory the user is working in.
|
|
1632
|
+
clearFormatterCache();
|
|
1633
|
+
// #1535: same #1266 pattern, one caller earlier — the `gh auth token` latch
|
|
1634
|
+
// zizmor's spawn reads is process-lived storage whose durability contract is
|
|
1635
|
+
// per SESSION, not per process. Without this, a user who runs `gh auth
|
|
1636
|
+
// login` and starts a fresh session still reads the previous session's
|
|
1637
|
+
// stale "no token" verdict until the cooldown (if any) happens to expire.
|
|
1638
|
+
resetZizmorTokenAvailability();
|
|
1639
|
+
// psscriptanalyzer's three latches (interpreter, module, -File exec) are
|
|
1640
|
+
// module-local, so the generation counter above does not reach them
|
|
1641
|
+
// (#1490, #1540).
|
|
1642
|
+
resetPsScriptAnalyzerAvailability();
|
|
1643
|
+
// #1497: the install-class retry ceiling is terminal for a SESSION, but the
|
|
1644
|
+
// latches holding it live on process-lived client instances (bootstrap builds
|
|
1645
|
+
// them once). Same #1266/#1490/#1535 shape — without this line "terminal for
|
|
1646
|
+
// the session" is terminal for the process, and a repaired network never
|
|
1647
|
+
// re-earns its `go install`.
|
|
1648
|
+
resetInstallRetryLatches();
|
|
1649
|
+
// #1537: the lazy-install seam's hold (`gem install rubocop`, `rustup
|
|
1650
|
+
// component add`) is durable for a SESSION. Its map is module-local, so the
|
|
1651
|
+
// generation counter above does not reach it — same #1490/#1497 shape. It
|
|
1652
|
+
// belongs on THIS line and not on the turn_end path: the first cut cleared it
|
|
1653
|
+
// from `clearFormatterRuntimeState()`, which runs every turn, so a failing
|
|
1654
|
+
// install re-spawned every turn instead of once per session.
|
|
1655
|
+
resetLazyInstallAttempts();
|
|
1656
|
+
// #1897: direct-LSP negative availability and bare installer paths are
|
|
1657
|
+
// session facts. A command or PATH entry can appear between sessions.
|
|
1658
|
+
resetDirectLspCommandAvailability();
|
|
1659
|
+
resetResolvedPathCache();
|
|
1660
|
+
// #1653: pnpm/yarn/bun/npm's availability latches (package-manager.ts) are
|
|
1661
|
+
// module-local, same #1490/#1535 shape as the two lines above — the
|
|
1662
|
+
// generation counter above does not reach them. Without this line, a
|
|
1663
|
+
// pnpm/yarn/bun install done mid-day stayed invisible: a genuine "missing"
|
|
1664
|
+
// verdict from one session latched into the next until a process restart.
|
|
1665
|
+
_resetPackageManagerCache();
|
|
1666
|
+
// #1730: the managed-tool refresh budget is a per-SESSION allowance (at most
|
|
1667
|
+
// one `npm update` per session). Left process-lived, one long-running pi
|
|
1668
|
+
// would refresh a single tool at launch and never look at the other 21
|
|
1669
|
+
// again — the same latch shape as the two lines above. The weekly cadence
|
|
1670
|
+
// itself is NOT reset here: it lives in the persisted per-tool stamp, so
|
|
1671
|
+
// re-arming the budget only restores the session's right to ask.
|
|
1672
|
+
resetManagedToolRefreshSession();
|
|
1418
1673
|
// #1123 item 3: a fresh session can re-report smells that a prior session
|
|
1419
1674
|
// already surfaced once (see `checkSmellsAndNoteOnce`'s once-per-session gate).
|
|
1420
1675
|
resetSmellsSessionState();
|
|
1676
|
+
// #1782: re-arm the workspace-diagnostics cache session clock. Entries
|
|
1677
|
+
// written before this instant assert findings from a session that is over,
|
|
1678
|
+
// so they must revalidate before they can be served as current again.
|
|
1679
|
+
resetWorkspaceDiagnosticsCacheSession(sessionStartMs);
|
|
1680
|
+
// Some embedders inject a capability-shaped Knip client rather than the
|
|
1681
|
+
// concrete KnipClient. Session reset is an optional lifecycle capability;
|
|
1682
|
+
// its absence must not make session_start fail.
|
|
1683
|
+
knipClient.resetSessionState?.();
|
|
1684
|
+
// #1910: the tier-3 cascade outstanding-touch registry and its
|
|
1685
|
+
// sweep-scoped expired/evicted counters (clients/lsp/cascade-tier.ts) are
|
|
1686
|
+
// a per-SESSION claim about touches THIS session fired. #1899 bounded the
|
|
1687
|
+
// registry between sweeps but, by its own review, left the session
|
|
1688
|
+
// boundary unwired — a session replacement inherited the prior session's
|
|
1689
|
+
// outstanding touches and misattributed a stray expiry/eviction to the
|
|
1690
|
+
// next session's first reconcile gauge.
|
|
1691
|
+
resetCascadeTierSessionState();
|
|
1421
1692
|
runtime.resetForSession(sessionStartMs);
|
|
1422
1693
|
logLatency({
|
|
1423
1694
|
type: "phase",
|
|
@@ -1471,11 +1742,21 @@ export async function handleSessionStart(deps) {
|
|
|
1471
1742
|
// project data roots and machine-global registry root once per session start;
|
|
1472
1743
|
// this is fire-and-forget and bounded so it never delays startup.
|
|
1473
1744
|
const projectDataDir = getProjectDataDir(cwd);
|
|
1745
|
+
// #1609 review F1: sweepOwnStagingFiles does not recurse, so the installer's
|
|
1746
|
+
// bin/ and tools/ subdirectories (clients/installer/index.ts's
|
|
1747
|
+
// GITHUB_BIN_DIR / TOOLS_DIR, now atomic-write.js writers too) need their
|
|
1748
|
+
// own entries — otherwise an orphaned staging file from a kill mid-install
|
|
1749
|
+
// (this PR's own motivating scenario) never gets reaped, and unique
|
|
1750
|
+
// pid-thread-seq staging names mean repeated kills ACCUMULATE full-size
|
|
1751
|
+
// orphan binaries instead of being cleaned up.
|
|
1752
|
+
const globalDir = getGlobalPiLensDir();
|
|
1474
1753
|
void sweepAtomicWriteStages([
|
|
1475
1754
|
projectDataDir,
|
|
1476
1755
|
path.join(projectDataDir, "cache"),
|
|
1477
1756
|
path.join(projectDataDir, "sessions"),
|
|
1478
|
-
|
|
1757
|
+
globalDir,
|
|
1758
|
+
path.join(globalDir, "bin"),
|
|
1759
|
+
path.join(globalDir, "tools"),
|
|
1479
1760
|
]).catch(() => {
|
|
1480
1761
|
// best-effort lifecycle cleanup — never fail session_start
|
|
1481
1762
|
});
|
|
@@ -1483,6 +1764,12 @@ export async function handleSessionStart(deps) {
|
|
|
1483
1764
|
runtime.projectRoot = cwd;
|
|
1484
1765
|
const sequenceReadStartedAt = Date.now();
|
|
1485
1766
|
const snapshotRoot = resolveSnapshotRoot(cwd);
|
|
1767
|
+
// #1785 F5 (round 4): the getter closes over `warmupOwnSnapshotRead`
|
|
1768
|
+
// directly (a `let` in this same `handleSessionStart` invocation's
|
|
1769
|
+
// scope), so it reads whatever value is current AT DEFERRED-RESOLVE
|
|
1770
|
+
// TIME — not whatever it was at this wiring instant. See
|
|
1771
|
+
// `retroactivelyHydrateAfterDeferredSequence`'s doc comment for the
|
|
1772
|
+
// full design.
|
|
1486
1773
|
const { latestSeq, timedOut } = await readSequenceWithBudget({
|
|
1487
1774
|
snapshotRoot,
|
|
1488
1775
|
base: snapshotSequenceBase(snapshotRoot),
|
|
@@ -1490,6 +1777,12 @@ export async function handleSessionStart(deps) {
|
|
|
1490
1777
|
runtime,
|
|
1491
1778
|
sessionGeneration: runtime.sessionGeneration,
|
|
1492
1779
|
dbg,
|
|
1780
|
+
onDeferredSequenceResolved: retroactivelyHydrateAfterDeferredSequence({
|
|
1781
|
+
getWarmupOwnSnapshotRead: () => warmupOwnSnapshotRead,
|
|
1782
|
+
snapshotRoot,
|
|
1783
|
+
runtime,
|
|
1784
|
+
dbg,
|
|
1785
|
+
}),
|
|
1493
1786
|
});
|
|
1494
1787
|
logLatency({
|
|
1495
1788
|
type: "phase",
|
|
@@ -1499,6 +1792,12 @@ export async function handleSessionStart(deps) {
|
|
|
1499
1792
|
durationMs: Date.now() - sequenceReadStartedAt,
|
|
1500
1793
|
metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
|
|
1501
1794
|
});
|
|
1795
|
+
if (timedOut) {
|
|
1796
|
+
recordSnapshotSequenceTimeout({
|
|
1797
|
+
snapshotRoot,
|
|
1798
|
+
snapshotPath: getProjectSnapshotPath(snapshotRoot),
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1502
1801
|
runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
|
|
1503
1802
|
const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
|
|
1504
1803
|
dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
@@ -1522,6 +1821,8 @@ export async function handleSessionStart(deps) {
|
|
|
1522
1821
|
catch {
|
|
1523
1822
|
// Missing snapshots are the normal cold-start case.
|
|
1524
1823
|
}
|
|
1824
|
+
const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
|
|
1825
|
+
nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
|
|
1525
1826
|
const snapshotGate = loadSnapshotBodyUnlessStale({
|
|
1526
1827
|
root: snapshotRoot,
|
|
1527
1828
|
currentProjectSeq: freshnessSeq,
|
|
@@ -1529,6 +1830,10 @@ export async function handleSessionStart(deps) {
|
|
|
1529
1830
|
});
|
|
1530
1831
|
const snapshot = snapshotGate.snapshot;
|
|
1531
1832
|
const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
|
|
1833
|
+
const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
|
|
1834
|
+
skippedStale: snapshotGate.skippedStale,
|
|
1835
|
+
bodyPresent: snapshotBodyPresent,
|
|
1836
|
+
});
|
|
1532
1837
|
logLatency({
|
|
1533
1838
|
type: "phase",
|
|
1534
1839
|
phase: "session_start_snapshot_load",
|
|
@@ -1539,6 +1844,7 @@ export async function handleSessionStart(deps) {
|
|
|
1539
1844
|
bytes: snapshotBytes,
|
|
1540
1845
|
fresh: snapshotFresh,
|
|
1541
1846
|
seq: snapshot?.seq ?? null,
|
|
1847
|
+
reason: snapshotFresh ? undefined : snapshotMissReason,
|
|
1542
1848
|
...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
|
|
1543
1849
|
...(timedOut ? { sequenceUnknown: true } : {}),
|
|
1544
1850
|
},
|
|
@@ -1548,6 +1854,7 @@ export async function handleSessionStart(deps) {
|
|
|
1548
1854
|
root: snapshotRoot,
|
|
1549
1855
|
currentProjectSeq: freshnessSeq,
|
|
1550
1856
|
snapshot,
|
|
1857
|
+
missReason: snapshotMissReason,
|
|
1551
1858
|
});
|
|
1552
1859
|
if (snapshotFresh) {
|
|
1553
1860
|
hydrateRuntimeFromProjectSnapshot(runtime, snapshot);
|
|
@@ -1559,6 +1866,38 @@ export async function handleSessionStart(deps) {
|
|
|
1559
1866
|
log(`Active tools: ${quickTools.join(", ")}`);
|
|
1560
1867
|
dbg(`session_start tools: ${quickTools.join(", ") || "deferred (quick mode)"}`);
|
|
1561
1868
|
dbg("session_start: quick mode active - skipping slow tool probes, language profiling, preinstall, scans, and error debt baseline");
|
|
1869
|
+
// #1911: the debug line above says WHICH steps were skipped, but nothing
|
|
1870
|
+
// bounded or structured said so — quick mode's absence of work and an
|
|
1871
|
+
// absent LOGGER read identically in latency.log. This record is that
|
|
1872
|
+
// line's structured twin: one bounded gauge per quick-mode session_start,
|
|
1873
|
+
// naming exactly the step set skipped, so a reader can tell "quick mode
|
|
1874
|
+
// correctly skipped these" from "the probes silently never ran".
|
|
1875
|
+
logLatency({
|
|
1876
|
+
type: "phase",
|
|
1877
|
+
phase: "session_start_skipped_steps",
|
|
1878
|
+
filePath: cwd,
|
|
1879
|
+
durationMs: 0,
|
|
1880
|
+
metadata: {
|
|
1881
|
+
mode: startupMode,
|
|
1882
|
+
reason: deps.sessionReason,
|
|
1883
|
+
// #1911 review F3: this `if (quickMode)` branch is an early return —
|
|
1884
|
+
// the whole quick path — so there is no enumerable list of "steps
|
|
1885
|
+
// run vs. skipped" this array could be derived from mechanically. It
|
|
1886
|
+
// is DESCRIPTIVE documentation of what the early return skips,
|
|
1887
|
+
// matching the `dbg()` line above word for word; keep both in sync by
|
|
1888
|
+
// hand if either changes. It also does NOT narrow under
|
|
1889
|
+
// `getFlag("no-lsp")` — quick mode skips the same five steps either
|
|
1890
|
+
// way; the LSP flag instead affects `quickTools` above, a separate
|
|
1891
|
+
// record.
|
|
1892
|
+
steps: [
|
|
1893
|
+
"slow_tool_probes",
|
|
1894
|
+
"language_profiling",
|
|
1895
|
+
"tool_preinstall",
|
|
1896
|
+
"startup_scans",
|
|
1897
|
+
"error_debt_baseline",
|
|
1898
|
+
],
|
|
1899
|
+
},
|
|
1900
|
+
});
|
|
1562
1901
|
const totalDurationMs = Date.now() - sessionStartMs;
|
|
1563
1902
|
dbg(`session_start total: ${totalDurationMs}ms (interactive path)`);
|
|
1564
1903
|
logLatency({
|
|
@@ -1569,6 +1908,7 @@ export async function handleSessionStart(deps) {
|
|
|
1569
1908
|
durationMs: totalDurationMs,
|
|
1570
1909
|
metadata: { mode: startupMode, reason: deps.sessionReason },
|
|
1571
1910
|
});
|
|
1911
|
+
logHostReadyDelay(deps, cwd);
|
|
1572
1912
|
emitSmellsSessionStartLine(dbg, sessionStartMs);
|
|
1573
1913
|
return;
|
|
1574
1914
|
}
|
|
@@ -1605,6 +1945,20 @@ export async function handleSessionStart(deps) {
|
|
|
1605
1945
|
durationMs: Date.now() - sequenceReadStartedAt,
|
|
1606
1946
|
metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
|
|
1607
1947
|
});
|
|
1948
|
+
if (timedOut) {
|
|
1949
|
+
// #1785: instrumentation only here, deliberately no
|
|
1950
|
+
// `onDeferredSequenceResolved` — unlike quick mode's cold path (which
|
|
1951
|
+
// does nothing when the snapshot isn't trusted), full mode's cold path
|
|
1952
|
+
// actively kicks off a real rescan below to rebuild this same state.
|
|
1953
|
+
// Retroactively hydrating from the on-disk snapshot once the deferred
|
|
1954
|
+
// read lands could overwrite that fresher, actively-computed state with
|
|
1955
|
+
// the stale disk copy — a regression, not a fix. See the PR body for the
|
|
1956
|
+
// full reasoning.
|
|
1957
|
+
recordSnapshotSequenceTimeout({
|
|
1958
|
+
snapshotRoot,
|
|
1959
|
+
snapshotPath: getProjectSnapshotPath(snapshotRoot),
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1608
1962
|
runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
|
|
1609
1963
|
const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
|
|
1610
1964
|
dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
@@ -1624,6 +1978,8 @@ export async function handleSessionStart(deps) {
|
|
|
1624
1978
|
catch {
|
|
1625
1979
|
// Missing snapshots are the normal cold-start case.
|
|
1626
1980
|
}
|
|
1981
|
+
const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
|
|
1982
|
+
nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
|
|
1627
1983
|
const snapshotGate = loadSnapshotBodyUnlessStale({
|
|
1628
1984
|
root: snapshotRoot,
|
|
1629
1985
|
currentProjectSeq: freshnessSeq,
|
|
@@ -1631,6 +1987,10 @@ export async function handleSessionStart(deps) {
|
|
|
1631
1987
|
});
|
|
1632
1988
|
const snapshot = snapshotGate.snapshot;
|
|
1633
1989
|
const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
|
|
1990
|
+
const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
|
|
1991
|
+
skippedStale: snapshotGate.skippedStale,
|
|
1992
|
+
bodyPresent: snapshotBodyPresent,
|
|
1993
|
+
});
|
|
1634
1994
|
logLatency({
|
|
1635
1995
|
type: "phase",
|
|
1636
1996
|
phase: "session_start_snapshot_load",
|
|
@@ -1641,6 +2001,7 @@ export async function handleSessionStart(deps) {
|
|
|
1641
2001
|
bytes: snapshotBytes,
|
|
1642
2002
|
fresh: snapshotFresh,
|
|
1643
2003
|
seq: snapshot?.seq ?? null,
|
|
2004
|
+
reason: snapshotFresh ? undefined : snapshotMissReason,
|
|
1644
2005
|
...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
|
|
1645
2006
|
...(timedOut ? { sequenceUnknown: true } : {}),
|
|
1646
2007
|
},
|
|
@@ -1650,6 +2011,7 @@ export async function handleSessionStart(deps) {
|
|
|
1650
2011
|
root: snapshotRoot,
|
|
1651
2012
|
currentProjectSeq: freshnessSeq,
|
|
1652
2013
|
snapshot,
|
|
2014
|
+
missReason: snapshotMissReason,
|
|
1653
2015
|
});
|
|
1654
2016
|
const freshSnapshot = snapshotFresh ? snapshot : null;
|
|
1655
2017
|
if (freshSnapshot) {
|
|
@@ -1777,6 +2139,7 @@ export async function handleSessionStart(deps) {
|
|
|
1777
2139
|
const jstsHeavyScansWillRun = startupScansWillRun && canRunStartupHeavyScans(languageProfile, "jsts");
|
|
1778
2140
|
if (allowBootstrapTasks) {
|
|
1779
2141
|
scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, jstsHeavyScansWillRun, dbg);
|
|
2142
|
+
scheduleManagedToolRefresh(dbg);
|
|
1780
2143
|
}
|
|
1781
2144
|
if (allowBootstrapTasks) {
|
|
1782
2145
|
// Fire-and-forget like other tool probes
|
|
@@ -1889,6 +2252,7 @@ export async function handleSessionStart(deps) {
|
|
|
1889
2252
|
durationMs: totalDurationMs,
|
|
1890
2253
|
metadata: { mode: startupMode, reason: deps.sessionReason },
|
|
1891
2254
|
});
|
|
2255
|
+
logHostReadyDelay(deps, cwd);
|
|
1892
2256
|
emitSmellsSessionStartLine(dbg, sessionStartMs);
|
|
1893
2257
|
}
|
|
1894
2258
|
/**
|