@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
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { resetBoundedTelemetry } from "./bounded-telemetry.js";
|
|
4
|
+
import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
|
|
3
5
|
import { deadCodeIssueCount } from "./dead-code-client.js";
|
|
4
6
|
import { logDeadCodeScan } from "./dead-code-logger.js";
|
|
7
|
+
import { incrementDegradationCount, resetDegradationLedger, } from "./degradation-ledger.js";
|
|
5
8
|
import { getDiagnosticTracker } from "./diagnostic-tracker.js";
|
|
6
|
-
import {
|
|
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";
|
|
7
12
|
import { resetDispatchAvailabilityState } from "./dispatch/runners/utils/runner-helpers.js";
|
|
8
13
|
import { clearAllSessions as clearFileTimeSessions } from "./file-time.js";
|
|
9
|
-
import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
|
|
10
14
|
import { getGlobalPiLensDir, getKnipIgnorePatterns, getProjectDataDir, } from "./file-utils.js";
|
|
11
15
|
import { GitleaksClient } from "./gitleaks-client.js";
|
|
12
16
|
import { GovulncheckClient, } from "./govulncheck-client.js";
|
|
17
|
+
import { sweepAtomicWriteStages } from "./instance-reaper.js";
|
|
13
18
|
import { canRunStartupHeavyScans } from "./language-policy.js";
|
|
14
19
|
import { detectProjectLanguageProfile, getDefaultStartupTools, } from "./language-profile.js";
|
|
15
20
|
import { logLatency } from "./latency-logger.js";
|
|
16
21
|
import { runLogCleanup } from "./log-cleanup.js";
|
|
17
22
|
import { initLSPConfig, loadLSPConfig } from "./lsp/config.js";
|
|
23
|
+
import { resetWorkspaceDiagnosticsCacheSession } from "./lsp/workspace-diagnostics-session.js";
|
|
24
|
+
import { resetDirectLspCommandAvailability } from "./lsp/server.js";
|
|
18
25
|
import { loadLspService } from "./lsp-lazy.js";
|
|
26
|
+
import { resetManagedToolRefreshSession } from "./installer/managed-tool-refresh-session.js";
|
|
27
|
+
import { resetResolvedPathCache } from "./installer/index.js";
|
|
28
|
+
import { _resetPackageManagerCache } from "./package-manager.js";
|
|
29
|
+
import { clearFormatterCache } from "./formatters.js";
|
|
19
30
|
import { isAtOrAboveHomeDir } from "./path-utils.js";
|
|
20
31
|
import { isPrintMode } from "./print-mode.js";
|
|
21
32
|
import { readLatestProjectSequence, readLatestProjectSequenceAsync, } from "./project-changes.js";
|
|
22
|
-
import { getProjectSnapshotPath, hydrateRuntimeFromProjectSnapshot, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
|
|
33
|
+
import { getProjectSnapshotPath, getProjectSnapshotLegacyPath, hydrateRuntimeFromProjectSnapshot, hydrateRuntimeFromProjectSnapshotIfIdle, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, loadProjectSnapshotExportsAndRules, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
|
|
23
34
|
import { clearTsconfigPathsCache } from "./review-graph/tsconfig-paths.js";
|
|
24
35
|
import { scanProjectRules } from "./rules-scanner.js";
|
|
25
36
|
import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
|
|
@@ -27,12 +38,32 @@ import { getSlowFsVerdict, isSlowFs, slowFsDegradationNotice, } from "./slow-fs.
|
|
|
27
38
|
import { countRecentSmells, formatSmellsSessionStartLine, resetSmellsSessionState, } from "./smells-rollup.js";
|
|
28
39
|
import { findNearestProjectRoot, getStartupScanMaxEntries, isStartupScanVerdictFresh, resolveStartupScanContext, } from "./startup-scan.js";
|
|
29
40
|
import { getSubagentIdentity, isSubagentSession, subagentLightModeNotice, } from "./subagent-mode.js";
|
|
30
|
-
import { sweepAtomicWriteStages } from "./instance-reaper.js";
|
|
31
41
|
import { TrivyClient } from "./trivy-client.js";
|
|
32
42
|
import { isWarmAttached } from "./warm-attach.js";
|
|
33
43
|
import { setSessionLanguages } from "./widget-state.js";
|
|
34
44
|
import { logWordIndex } from "./word-index-logger.js";
|
|
35
45
|
import { resetWorkspaceTopology } from "./workspace-topology.js";
|
|
46
|
+
import { resetZizmorTokenAvailability } from "./zizmor-config.js";
|
|
47
|
+
const HOST_STALL_THRESHOLD_MS = 30_000;
|
|
48
|
+
function logHostReadyDelay(deps, cwd) {
|
|
49
|
+
if (!deps.emitHostReadyDelay ||
|
|
50
|
+
deps.sessionStartMonotonicAt === undefined ||
|
|
51
|
+
deps.extensionLoadedAt === undefined) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const durationMs = Math.max(0, deps.sessionStartMonotonicAt - deps.extensionLoadedAt);
|
|
55
|
+
logLatency({
|
|
56
|
+
type: "phase",
|
|
57
|
+
filePath: cwd,
|
|
58
|
+
phase: "host_ready_delay",
|
|
59
|
+
durationMs,
|
|
60
|
+
metadata: {
|
|
61
|
+
hostStallSuspected: durationMs > HOST_STALL_THRESHOLD_MS,
|
|
62
|
+
sessionStart: "first-process-session",
|
|
63
|
+
reason: deps.sessionReason,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
36
67
|
function resolveSnapshotRoot(cwd) {
|
|
37
68
|
const resolvedCwd = path.resolve(cwd);
|
|
38
69
|
const nearest = findNearestProjectRoot(resolvedCwd);
|
|
@@ -79,6 +110,91 @@ function snapshotSequenceBase(root) {
|
|
|
79
110
|
sinceSeq: meta.seq,
|
|
80
111
|
};
|
|
81
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* #1785: one bounded ledger record per timed-out sequence read, so a real
|
|
115
|
+
* occurrence is diagnosable from the ledger alone rather than only from a
|
|
116
|
+
* `dbg` line that most hosts never surface. Carries the project root and the
|
|
117
|
+
* on-disk snapshot's age/size (when one exists) — the identity AC1 asks for:
|
|
118
|
+
* which project, how stale/large the snapshot that got skipped was.
|
|
119
|
+
*/
|
|
120
|
+
function recordSnapshotSequenceTimeout(args) {
|
|
121
|
+
let reason = "sequence read timed out; no snapshot on disk";
|
|
122
|
+
try {
|
|
123
|
+
const stat = nodeFs.statSync(args.snapshotPath);
|
|
124
|
+
reason = `sequence read timed out; snapshot age=${Math.round(Date.now() - stat.mtimeMs)}ms size=${stat.size}b`;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// No snapshot on disk yet — the reason above already covers it.
|
|
128
|
+
}
|
|
129
|
+
incrementDegradationCount({
|
|
130
|
+
kind: "snapshot-sequence-read-timeout",
|
|
131
|
+
subject: args.snapshotRoot,
|
|
132
|
+
reason,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* #1785: the synchronous freshness check made a conservative call with the
|
|
137
|
+
* `UNKNOWN_PROJECT_SEQ` sentinel (never hydrate when the real sequence is
|
|
138
|
+
* unknown). Once the deferred read resolves — a deterministic completion
|
|
139
|
+
* signal, not a sleep — this re-checks freshness against the now-known
|
|
140
|
+
* sequence and hydrates late when the snapshot really was current, instead of
|
|
141
|
+
* leaving the runtime without `cachedExports`/`projectRulesScan` for the rest
|
|
142
|
+
* of the session.
|
|
143
|
+
*
|
|
144
|
+
* #1785 review round F5 (design (a), replacing rounds 1-3's synchronous
|
|
145
|
+
* capture entirely): quick mode's own cold-start warmup ALREADY loads the
|
|
146
|
+
* on-disk snapshot for its own purposes — `cachedSnapshot` at the top of the
|
|
147
|
+
* warmup body, used to reuse a still-fresh `startupScan` verdict — strictly
|
|
148
|
+
* BEFORE the warmup's own possible save (`saveRuntimeProjectSnapshot`, only
|
|
149
|
+
* reached when that verdict was NOT fresh). Reusing THAT already-loaded
|
|
150
|
+
* value costs nothing new: the read was always going to happen regardless of
|
|
151
|
+
* this fix, and it is guaranteed to predate any overwrite the SAME warmup
|
|
152
|
+
* invocation might go on to make — a read-before-write invariant of the
|
|
153
|
+
* warmup's own code, not something this function has to defend against with
|
|
154
|
+
* a race window of its own. `getWarmupOwnSnapshotRead` is a closure over a
|
|
155
|
+
* per-`handleSessionStart`-call LOCAL variable (never module-scope — #1785
|
|
156
|
+
* F6 is exactly the class of bug a module-scope holder here would
|
|
157
|
+
* reintroduce) that the warmup publishes into once its own read completes.
|
|
158
|
+
*
|
|
159
|
+
* When the getter still returns `undefined` — the deferred read resolved
|
|
160
|
+
* before the warmup got that far (or no warmup was ever armed by this call:
|
|
161
|
+
* a later quick-mode call in the same process, print mode, full mode) —
|
|
162
|
+
* there is nothing published yet, so this falls back to a live re-load via
|
|
163
|
+
* `loadProjectSnapshotExportsAndRules`. That fallback is exactly as safe as
|
|
164
|
+
* the primary path: if the warmup hasn't reached its own read yet, it
|
|
165
|
+
* certainly hasn't saved yet either (same invariant), so disk still holds
|
|
166
|
+
* whatever was there before any warmup activity.
|
|
167
|
+
*
|
|
168
|
+
* Both the published value and the fallback re-load are the narrow,
|
|
169
|
+
* postings-free `ProjectSnapshotExportsAndRules` shape — never the full
|
|
170
|
+
* `loadProjectSnapshot`. This path only ever hydrates
|
|
171
|
+
* `cachedExports`/`projectRulesScan`; it can NOT hydrate `wordIndex` even
|
|
172
|
+
* when the underlying snapshot would otherwise have one, because the narrow
|
|
173
|
+
* type never carries it. That is intentional, not a regression: F2's hazard
|
|
174
|
+
* was this exact path nulling a `wordIndex` that quick mode's warmup had, in
|
|
175
|
+
* the meantime, built for real — the warmup remains the sole source of a
|
|
176
|
+
* late-arriving `wordIndex` for the interactive path.
|
|
177
|
+
*/
|
|
178
|
+
function retroactivelyHydrateAfterDeferredSequence(args) {
|
|
179
|
+
return (latestSeq) => {
|
|
180
|
+
const published = args.getWarmupOwnSnapshotRead();
|
|
181
|
+
const snapshot = published !== undefined
|
|
182
|
+
? published
|
|
183
|
+
: loadProjectSnapshotExportsAndRules(args.snapshotRoot);
|
|
184
|
+
if (!snapshot ||
|
|
185
|
+
snapshot.version !== PROJECT_SNAPSHOT_VERSION ||
|
|
186
|
+
snapshot.seq !== latestSeq.projectSeq) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const hydrated = hydrateRuntimeFromProjectSnapshotIfIdle(args.runtime, snapshot);
|
|
190
|
+
if (hydrated) {
|
|
191
|
+
args.dbg(`session_start: deferred sequence read confirmed snapshot freshness — hydrating cachedExports/projectRulesScan late (seq=${snapshot.seq})`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
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`);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
82
198
|
function loadSnapshotBodyUnlessStale(args) {
|
|
83
199
|
const meta = readProjectSnapshotMeta(args.root);
|
|
84
200
|
if (meta && isProjectSnapshotMetaStale(meta, args.currentProjectSeq)) {
|
|
@@ -90,12 +206,17 @@ function loadSnapshotBodyUnlessStale(args) {
|
|
|
90
206
|
skippedStale: false,
|
|
91
207
|
};
|
|
92
208
|
}
|
|
93
|
-
function describeSnapshotMiss(snapshot, currentProjectSeq) {
|
|
209
|
+
function describeSnapshotMiss(snapshot, currentProjectSeq, args) {
|
|
210
|
+
if (args.skippedStale)
|
|
211
|
+
return "stale-meta-gate";
|
|
94
212
|
if (!snapshot)
|
|
95
|
-
return "missing";
|
|
213
|
+
return args.bodyPresent ? "invalid-body" : "missing";
|
|
96
214
|
if (snapshot.seq !== currentProjectSeq) {
|
|
97
215
|
return `stale(seq=${snapshot.seq}, current=${currentProjectSeq})`;
|
|
98
216
|
}
|
|
217
|
+
// Defensive-only arm: parseSnapshot rejects incompatible versions, and a
|
|
218
|
+
// same-sequence parsed snapshot is fresh. Keep this classification explicit
|
|
219
|
+
// so a future loader change cannot collapse it into a generic miss.
|
|
99
220
|
return "incompatible";
|
|
100
221
|
}
|
|
101
222
|
function logProjectSnapshotProbe(args) {
|
|
@@ -104,7 +225,7 @@ function logProjectSnapshotProbe(args) {
|
|
|
104
225
|
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
226
|
}
|
|
106
227
|
else {
|
|
107
|
-
args.dbg(`project_snapshot: miss reason=${
|
|
228
|
+
args.dbg(`project_snapshot: miss reason=${args.missReason}`);
|
|
108
229
|
}
|
|
109
230
|
}
|
|
110
231
|
function resolveStartupMode() {
|
|
@@ -171,7 +292,7 @@ const UNKNOWN_PROJECT_SEQ = -1;
|
|
|
171
292
|
* logs its own `session_start_sequence_read_deferred_reseed` phase.
|
|
172
293
|
*/
|
|
173
294
|
async function readSequenceWithBudget(args) {
|
|
174
|
-
const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg } = args;
|
|
295
|
+
const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg, onDeferredSequenceResolved, } = args;
|
|
175
296
|
const readPromise = readLatestProjectSequenceAsync(snapshotRoot, base);
|
|
176
297
|
let timeoutHandle;
|
|
177
298
|
const timeoutPromise = new Promise((resolve) => {
|
|
@@ -224,6 +345,7 @@ async function readSequenceWithBudget(args) {
|
|
|
224
345
|
metadata: { entries: latestSeq.fileSeqByPath.size, deferred: true },
|
|
225
346
|
});
|
|
226
347
|
dbg(`session_start: deferred sequence read completed — reseeded projectSeq=${latestSeq.projectSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
348
|
+
onDeferredSequenceResolved?.(latestSeq);
|
|
227
349
|
})
|
|
228
350
|
.catch((err) => {
|
|
229
351
|
dbg(`session_start: deferred sequence read failed: ${err}`);
|
|
@@ -375,6 +497,47 @@ function firePreinstallDefaults(ensureTool, dbg, startupDefaults) {
|
|
|
375
497
|
});
|
|
376
498
|
}
|
|
377
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* Default delay before the managed-tool version refresh runs (#1730). Long
|
|
502
|
+
* enough that `session_start`, the startup scans, and the tool preinstalls have
|
|
503
|
+
* all settled — the refresh may spawn one `npm update`, and that must never
|
|
504
|
+
* compete with the work the user is waiting on.
|
|
505
|
+
*/
|
|
506
|
+
const MANAGED_TOOL_REFRESH_DELAY_MS = 30_000;
|
|
507
|
+
/**
|
|
508
|
+
* Schedule the periodic managed-tool refresh (#1730) on an unref'd background
|
|
509
|
+
* timer.
|
|
510
|
+
*
|
|
511
|
+
* `session_start`'s own cost here is a single `setTimeout` registration: the
|
|
512
|
+
* refresh module is not even imported until the timer fires. The timer is
|
|
513
|
+
* unref'd so a one-shot process exits without waiting for it, matching the
|
|
514
|
+
* warmup timer above. Whether a refresh actually runs is decided inside
|
|
515
|
+
* `runManagedToolRefresh` against a PERSISTED per-tool stamp, so a launch loop
|
|
516
|
+
* cannot escalate the weekly cadence.
|
|
517
|
+
*/
|
|
518
|
+
function scheduleManagedToolRefresh(dbg) {
|
|
519
|
+
const delayMs = Number(process.env.PI_LENS_TOOL_REFRESH_DELAY_MS ?? MANAGED_TOOL_REFRESH_DELAY_MS);
|
|
520
|
+
const timer = setTimeout(() => {
|
|
521
|
+
void (async () => {
|
|
522
|
+
try {
|
|
523
|
+
const refresh = await import("./installer/managed-tool-refresh.js");
|
|
524
|
+
const outcome = await refresh.runManagedToolRefresh();
|
|
525
|
+
if (outcome.skipped) {
|
|
526
|
+
dbg(`session_start tool-refresh: skipped (${outcome.skipped})`);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
for (const result of outcome.refreshed) {
|
|
530
|
+
dbg(`session_start tool-refresh: ${result.toolId} ${result.ok ? "ok" : "failed"}` +
|
|
531
|
+
`${result.changed ? ` ${result.previousVersion ?? "unknown"} → ${result.currentVersion}` : " (unchanged)"}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
catch (err) {
|
|
535
|
+
dbg(`session_start tool-refresh: error ${err}`);
|
|
536
|
+
}
|
|
537
|
+
})();
|
|
538
|
+
}, Number.isFinite(delayMs) ? delayMs : MANAGED_TOOL_REFRESH_DELAY_MS);
|
|
539
|
+
timer.unref?.();
|
|
540
|
+
}
|
|
378
541
|
async function probePrettierInstall(ensureTool, dbg, analysisRoot) {
|
|
379
542
|
const pkgPath = path.join(analysisRoot, "package.json");
|
|
380
543
|
try {
|
|
@@ -452,10 +615,14 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
452
615
|
let rebuildPreflightFiles;
|
|
453
616
|
const latestSeq = readLatestProjectSequence(snapshotRoot, snapshotSequenceBase(snapshotRoot));
|
|
454
617
|
const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
|
|
618
|
+
const snapshotLoadStartMs = Date.now();
|
|
455
619
|
const snapshot = loadProjectSnapshot(snapshotRoot);
|
|
620
|
+
const snapshotLoadMs = Date.now() - snapshotLoadStartMs;
|
|
456
621
|
if (snapshot?.wordIndex) {
|
|
457
622
|
const { deserializeWordIndex, refreshWordIndexIncrementally } = await import("./word-index.js");
|
|
623
|
+
const deserializeStartMs = Date.now();
|
|
458
624
|
const index = deserializeWordIndex(snapshot.wordIndex);
|
|
625
|
+
const deserializeMs = Date.now() - deserializeStartMs;
|
|
459
626
|
if (index) {
|
|
460
627
|
try {
|
|
461
628
|
const result = await refreshWordIndexIncrementally(index, analysisRoot, () => runtime.isCurrentSession(sessionGeneration));
|
|
@@ -469,10 +636,16 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
469
636
|
cwd: snapshotRoot,
|
|
470
637
|
trigger: "session_start",
|
|
471
638
|
reason: result.reason,
|
|
639
|
+
phaseDurationsMs: {
|
|
640
|
+
snapshotLoadMs,
|
|
641
|
+
deserializeMs,
|
|
642
|
+
...result.timings,
|
|
643
|
+
},
|
|
472
644
|
});
|
|
473
645
|
}
|
|
474
646
|
else {
|
|
475
647
|
runtime.wordIndex = index;
|
|
648
|
+
let snapshotSaveSyncMs = 0;
|
|
476
649
|
// A stale project seq must be advanced even when mtimes prove every
|
|
477
650
|
// indexed document reusable. Fresh snapshots with no changes avoid
|
|
478
651
|
// an unnecessary rewrite of the large shared snapshot.
|
|
@@ -480,9 +653,15 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
480
653
|
result.refreshed > 0 ||
|
|
481
654
|
result.dropped > 0 ||
|
|
482
655
|
snapshot.wordIndex.truncated !== index.truncated) {
|
|
656
|
+
const serializeSaveEnqueueStartMs = Date.now();
|
|
483
657
|
saveRuntimeProjectSnapshot({ cwd: snapshotRoot, runtime, dbg });
|
|
658
|
+
snapshotSaveSyncMs = Date.now() - serializeSaveEnqueueStartMs;
|
|
484
659
|
}
|
|
485
|
-
|
|
660
|
+
const phases = `snapshot-load=${snapshotLoadMs}ms, deserialize=${deserializeMs}ms, ` +
|
|
661
|
+
`source-walk=${result.timings.sourceWalkMs}ms, stat-walk=${result.timings.statWalkMs}ms, ` +
|
|
662
|
+
`refresh-reads=${result.timings.refreshReadsMs}ms, ` +
|
|
663
|
+
`snapshot-save-sync=${snapshotSaveSyncMs}ms`;
|
|
664
|
+
dbg(`session_start word-index: incremental (seq=${effectiveSeq}, refreshed=${result.refreshed}, dropped=${result.dropped}, skipped=${result.skipped}, reused=${result.reused}, ${Date.now() - startMs}ms, phases: ${phases})`);
|
|
486
665
|
// M2, #958: the incremental-vs-full decision + honest coverage
|
|
487
666
|
// (indexedFileCount/truncated/skipped), independent of host `dbg`.
|
|
488
667
|
logWordIndex({
|
|
@@ -493,6 +672,12 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
493
672
|
indexedFileCount: index.docCount,
|
|
494
673
|
tokens: index.postings.size,
|
|
495
674
|
truncated: index.truncated,
|
|
675
|
+
phaseDurationsMs: {
|
|
676
|
+
snapshotLoadMs,
|
|
677
|
+
deserializeMs,
|
|
678
|
+
...result.timings,
|
|
679
|
+
snapshotSaveSyncMs,
|
|
680
|
+
},
|
|
496
681
|
refreshed: result.refreshed,
|
|
497
682
|
dropped: result.dropped,
|
|
498
683
|
skipped: result.skipped,
|
|
@@ -516,6 +701,7 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
516
701
|
cwd: snapshotRoot,
|
|
517
702
|
trigger: "session_start",
|
|
518
703
|
reason: err instanceof Error ? err.message : String(err),
|
|
704
|
+
phaseDurationsMs: { snapshotLoadMs, deserializeMs },
|
|
519
705
|
});
|
|
520
706
|
}
|
|
521
707
|
}
|
|
@@ -692,7 +878,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
|
|
|
692
878
|
// KnipClient skips before probing/installing when analysisRoot is not a real
|
|
693
879
|
// JS/Knip project. This avoids running knip from Unity/C#/generic repos.
|
|
694
880
|
const startMs = Date.now();
|
|
695
|
-
const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns());
|
|
881
|
+
const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns(), { projectSeq: runtime.projectSeq });
|
|
696
882
|
if (!runtime.isCurrentSession(sessionGeneration))
|
|
697
883
|
return;
|
|
698
884
|
if (knipResult.success) {
|
|
@@ -1004,7 +1190,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
|
|
|
1004
1190
|
return;
|
|
1005
1191
|
if (!runtime.callGraph)
|
|
1006
1192
|
return;
|
|
1007
|
-
const { buildCodebaseModel, saveCodebaseModel, DEFAULT_CODEBASE_MODEL_TOKEN_BUDGET } = await import("./codebase-model.js");
|
|
1193
|
+
const { buildCodebaseModel, saveCodebaseModel, DEFAULT_CODEBASE_MODEL_TOKEN_BUDGET, } = await import("./codebase-model.js");
|
|
1008
1194
|
if (!callGraphIdentity)
|
|
1009
1195
|
return;
|
|
1010
1196
|
const model = buildCodebaseModel(runtime.callGraph, analysisRoot, DEFAULT_CODEBASE_MODEL_TOKEN_BUDGET, callGraphIdentity);
|
|
@@ -1098,6 +1284,12 @@ export const SESSION_START_GUIDANCE = [
|
|
|
1098
1284
|
];
|
|
1099
1285
|
export async function handleSessionStart(deps) {
|
|
1100
1286
|
resetDegradationLedger();
|
|
1287
|
+
// #1743: the bounded-telemetry per-turn counters. The rising-edge state is
|
|
1288
|
+
// NOT here — it is the ledger's own tally, reset on the line above. These
|
|
1289
|
+
// counters are keyed by turn index, and a new session restarts turn
|
|
1290
|
+
// numbering at 0, so without this a stale count could survive a session
|
|
1291
|
+
// boundary that happened to land on the same index.
|
|
1292
|
+
resetBoundedTelemetry();
|
|
1101
1293
|
const handlerEnteredAt = Date.now();
|
|
1102
1294
|
const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
|
|
1103
1295
|
const cwdForTelemetry = deps.ctxCwd ?? process.cwd();
|
|
@@ -1152,6 +1344,11 @@ export async function handleSessionStart(deps) {
|
|
|
1152
1344
|
// (an explicit env var still takes highest precedence).
|
|
1153
1345
|
// Tunable: PI_LENS_WARMUP_DELAY_MS adjusts the warmup delay.
|
|
1154
1346
|
let startupMode = resolveStartupMode();
|
|
1347
|
+
// SAFETY: these two flags are process-lifetime state pi-lens stashes on
|
|
1348
|
+
// `globalThis` so a second extension instance in the same process sees the
|
|
1349
|
+
// first one's warmup. There is no ambient declaration for them, and adding
|
|
1350
|
+
// one would let any module write them. Both are declared OPTIONAL here, so
|
|
1351
|
+
// the reads below are `undefined`-safe on a process where nothing set them.
|
|
1155
1352
|
const processGlobals = globalThis;
|
|
1156
1353
|
const isFirstSessionOfProcess = !processGlobals.__piLensFirstSessionDone;
|
|
1157
1354
|
if (isFirstSessionOfProcess &&
|
|
@@ -1162,6 +1359,20 @@ export async function handleSessionStart(deps) {
|
|
|
1162
1359
|
startupMode = deps.startupModeOverride ?? "quick";
|
|
1163
1360
|
}
|
|
1164
1361
|
processGlobals.__piLensFirstSessionDone = true;
|
|
1362
|
+
// #1785 F5 (round 4, design (a)): the warmup timer body below ALREADY
|
|
1363
|
+
// loads the on-disk snapshot for its own purposes (`cachedSnapshot`,
|
|
1364
|
+
// reused for the `startupScan` verdict cache) strictly BEFORE any save it
|
|
1365
|
+
// might go on to make. This LOCAL variable — per-`handleSessionStart`-call,
|
|
1366
|
+
// deliberately NOT module-scope (see #1785 F6) — lets the warmup publish
|
|
1367
|
+
// that already-loaded read (narrowed to exports+rules, never the full
|
|
1368
|
+
// object with `wordIndex`) for `retroactivelyHydrateAfterDeferredSequence`
|
|
1369
|
+
// to reuse at zero additional cost, instead of this call paying for its
|
|
1370
|
+
// own separate synchronous capture (rounds 1-3's approach, reverted here:
|
|
1371
|
+
// see that function's doc comment for the full history). `undefined`
|
|
1372
|
+
// means the warmup hasn't reached its own read yet (or was never armed by
|
|
1373
|
+
// this call at all) — the quick-mode block's retroactive-hydration
|
|
1374
|
+
// callback then falls back to a live re-load instead.
|
|
1375
|
+
let warmupOwnSnapshotRead;
|
|
1165
1376
|
// #1154: quick mode is entered on BOTH `pi -p`/`--print` (a one-shot that
|
|
1166
1377
|
// exits right after this turn) and an interactive process's first
|
|
1167
1378
|
// session_start (forced quick to protect keystroke latency, then warms
|
|
@@ -1209,6 +1420,23 @@ export async function handleSessionStart(deps) {
|
|
|
1209
1420
|
// reuse it instead of re-walking a possibly huge tree from
|
|
1210
1421
|
// scratch on every single startup.
|
|
1211
1422
|
const cachedSnapshot = loadProjectSnapshot(warmupSnapshotRoot);
|
|
1423
|
+
// #1785 F5 (round 4): publish this ALREADY-loaded read — narrowed
|
|
1424
|
+
// to exports+rules, never a reference to `cachedSnapshot` itself
|
|
1425
|
+
// (which carries `wordIndex`/`files`/`symbols`/`reverseDeps`) — for
|
|
1426
|
+
// `retroactivelyHydrateAfterDeferredSequence` to reuse. This read
|
|
1427
|
+
// strictly precedes the warmup's own possible save a few lines
|
|
1428
|
+
// below, so it is guaranteed to reflect disk as it stood before
|
|
1429
|
+
// THIS warmup could have touched it. Zero marginal cost: this read
|
|
1430
|
+
// already happens unconditionally for the `startupScan` verdict
|
|
1431
|
+
// cache below, with or without this fix.
|
|
1432
|
+
warmupOwnSnapshotRead = cachedSnapshot
|
|
1433
|
+
? {
|
|
1434
|
+
version: cachedSnapshot.version,
|
|
1435
|
+
seq: cachedSnapshot.seq,
|
|
1436
|
+
cachedExports: cachedSnapshot.cachedExports,
|
|
1437
|
+
projectRulesScan: cachedSnapshot.projectRulesScan,
|
|
1438
|
+
}
|
|
1439
|
+
: null;
|
|
1212
1440
|
const cachedVerdict = cachedSnapshot?.startupScan;
|
|
1213
1441
|
let scan;
|
|
1214
1442
|
if (cachedVerdict &&
|
|
@@ -1358,7 +1586,7 @@ export async function handleSessionStart(deps) {
|
|
|
1358
1586
|
}
|
|
1359
1587
|
const allowBootstrapTasks = startupMode === "full";
|
|
1360
1588
|
const quickMode = startupMode === "quick";
|
|
1361
|
-
const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
|
|
1589
|
+
const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, knipClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
|
|
1362
1590
|
// Lightweight phase timer — resets after each call so each log line shows
|
|
1363
1591
|
// the cost of that phase alone, not cumulative time from session start.
|
|
1364
1592
|
let _phaseT = Date.now();
|
|
@@ -1392,9 +1620,66 @@ export async function handleSessionStart(deps) {
|
|
|
1392
1620
|
// the tool for the rest of the process lifetime. Clear it here, same
|
|
1393
1621
|
// boundary as the other per-session caches on this line.
|
|
1394
1622
|
resetDispatchAvailabilityState();
|
|
1623
|
+
// #1895: formatter PATH verdicts are session-scoped, but they live in
|
|
1624
|
+
// formatters.ts and are not covered by the dispatch generation. Re-arm them
|
|
1625
|
+
// here so a formatter installed or removed between sessions is observed by
|
|
1626
|
+
// the next session. `clearFormatterCache` drops the per-cwd selection cache
|
|
1627
|
+
// as well as the which latches, which is what a real re-probe needs: the
|
|
1628
|
+
// selection cache answers a same-cwd lookup before any probe runs, so
|
|
1629
|
+
// clearing the latches alone would leave the stale verdict standing in the
|
|
1630
|
+
// one directory the user is working in.
|
|
1631
|
+
clearFormatterCache();
|
|
1632
|
+
// #1535: same #1266 pattern, one caller earlier — the `gh auth token` latch
|
|
1633
|
+
// zizmor's spawn reads is process-lived storage whose durability contract is
|
|
1634
|
+
// per SESSION, not per process. Without this, a user who runs `gh auth
|
|
1635
|
+
// login` and starts a fresh session still reads the previous session's
|
|
1636
|
+
// stale "no token" verdict until the cooldown (if any) happens to expire.
|
|
1637
|
+
resetZizmorTokenAvailability();
|
|
1638
|
+
// psscriptanalyzer's three latches (interpreter, module, -File exec) are
|
|
1639
|
+
// module-local, so the generation counter above does not reach them
|
|
1640
|
+
// (#1490, #1540).
|
|
1641
|
+
resetPsScriptAnalyzerAvailability();
|
|
1642
|
+
// #1497: the install-class retry ceiling is terminal for a SESSION, but the
|
|
1643
|
+
// latches holding it live on process-lived client instances (bootstrap builds
|
|
1644
|
+
// them once). Same #1266/#1490/#1535 shape — without this line "terminal for
|
|
1645
|
+
// the session" is terminal for the process, and a repaired network never
|
|
1646
|
+
// re-earns its `go install`.
|
|
1647
|
+
resetInstallRetryLatches();
|
|
1648
|
+
// #1537: the lazy-install seam's hold (`gem install rubocop`, `rustup
|
|
1649
|
+
// component add`) is durable for a SESSION. Its map is module-local, so the
|
|
1650
|
+
// generation counter above does not reach it — same #1490/#1497 shape. It
|
|
1651
|
+
// belongs on THIS line and not on the turn_end path: the first cut cleared it
|
|
1652
|
+
// from `clearFormatterRuntimeState()`, which runs every turn, so a failing
|
|
1653
|
+
// install re-spawned every turn instead of once per session.
|
|
1654
|
+
resetLazyInstallAttempts();
|
|
1655
|
+
// #1897: direct-LSP negative availability and bare installer paths are
|
|
1656
|
+
// session facts. A command or PATH entry can appear between sessions.
|
|
1657
|
+
resetDirectLspCommandAvailability();
|
|
1658
|
+
resetResolvedPathCache();
|
|
1659
|
+
// #1653: pnpm/yarn/bun/npm's availability latches (package-manager.ts) are
|
|
1660
|
+
// module-local, same #1490/#1535 shape as the two lines above — the
|
|
1661
|
+
// generation counter above does not reach them. Without this line, a
|
|
1662
|
+
// pnpm/yarn/bun install done mid-day stayed invisible: a genuine "missing"
|
|
1663
|
+
// verdict from one session latched into the next until a process restart.
|
|
1664
|
+
_resetPackageManagerCache();
|
|
1665
|
+
// #1730: the managed-tool refresh budget is a per-SESSION allowance (at most
|
|
1666
|
+
// one `npm update` per session). Left process-lived, one long-running pi
|
|
1667
|
+
// would refresh a single tool at launch and never look at the other 21
|
|
1668
|
+
// again — the same latch shape as the two lines above. The weekly cadence
|
|
1669
|
+
// itself is NOT reset here: it lives in the persisted per-tool stamp, so
|
|
1670
|
+
// re-arming the budget only restores the session's right to ask.
|
|
1671
|
+
resetManagedToolRefreshSession();
|
|
1395
1672
|
// #1123 item 3: a fresh session can re-report smells that a prior session
|
|
1396
1673
|
// already surfaced once (see `checkSmellsAndNoteOnce`'s once-per-session gate).
|
|
1397
1674
|
resetSmellsSessionState();
|
|
1675
|
+
// #1782: re-arm the workspace-diagnostics cache session clock. Entries
|
|
1676
|
+
// written before this instant assert findings from a session that is over,
|
|
1677
|
+
// so they must revalidate before they can be served as current again.
|
|
1678
|
+
resetWorkspaceDiagnosticsCacheSession(sessionStartMs);
|
|
1679
|
+
// Some embedders inject a capability-shaped Knip client rather than the
|
|
1680
|
+
// concrete KnipClient. Session reset is an optional lifecycle capability;
|
|
1681
|
+
// its absence must not make session_start fail.
|
|
1682
|
+
knipClient.resetSessionState?.();
|
|
1398
1683
|
runtime.resetForSession(sessionStartMs);
|
|
1399
1684
|
logLatency({
|
|
1400
1685
|
type: "phase",
|
|
@@ -1448,11 +1733,21 @@ export async function handleSessionStart(deps) {
|
|
|
1448
1733
|
// project data roots and machine-global registry root once per session start;
|
|
1449
1734
|
// this is fire-and-forget and bounded so it never delays startup.
|
|
1450
1735
|
const projectDataDir = getProjectDataDir(cwd);
|
|
1736
|
+
// #1609 review F1: sweepOwnStagingFiles does not recurse, so the installer's
|
|
1737
|
+
// bin/ and tools/ subdirectories (clients/installer/index.ts's
|
|
1738
|
+
// GITHUB_BIN_DIR / TOOLS_DIR, now atomic-write.js writers too) need their
|
|
1739
|
+
// own entries — otherwise an orphaned staging file from a kill mid-install
|
|
1740
|
+
// (this PR's own motivating scenario) never gets reaped, and unique
|
|
1741
|
+
// pid-thread-seq staging names mean repeated kills ACCUMULATE full-size
|
|
1742
|
+
// orphan binaries instead of being cleaned up.
|
|
1743
|
+
const globalDir = getGlobalPiLensDir();
|
|
1451
1744
|
void sweepAtomicWriteStages([
|
|
1452
1745
|
projectDataDir,
|
|
1453
1746
|
path.join(projectDataDir, "cache"),
|
|
1454
1747
|
path.join(projectDataDir, "sessions"),
|
|
1455
|
-
|
|
1748
|
+
globalDir,
|
|
1749
|
+
path.join(globalDir, "bin"),
|
|
1750
|
+
path.join(globalDir, "tools"),
|
|
1456
1751
|
]).catch(() => {
|
|
1457
1752
|
// best-effort lifecycle cleanup — never fail session_start
|
|
1458
1753
|
});
|
|
@@ -1460,6 +1755,12 @@ export async function handleSessionStart(deps) {
|
|
|
1460
1755
|
runtime.projectRoot = cwd;
|
|
1461
1756
|
const sequenceReadStartedAt = Date.now();
|
|
1462
1757
|
const snapshotRoot = resolveSnapshotRoot(cwd);
|
|
1758
|
+
// #1785 F5 (round 4): the getter closes over `warmupOwnSnapshotRead`
|
|
1759
|
+
// directly (a `let` in this same `handleSessionStart` invocation's
|
|
1760
|
+
// scope), so it reads whatever value is current AT DEFERRED-RESOLVE
|
|
1761
|
+
// TIME — not whatever it was at this wiring instant. See
|
|
1762
|
+
// `retroactivelyHydrateAfterDeferredSequence`'s doc comment for the
|
|
1763
|
+
// full design.
|
|
1463
1764
|
const { latestSeq, timedOut } = await readSequenceWithBudget({
|
|
1464
1765
|
snapshotRoot,
|
|
1465
1766
|
base: snapshotSequenceBase(snapshotRoot),
|
|
@@ -1467,6 +1768,12 @@ export async function handleSessionStart(deps) {
|
|
|
1467
1768
|
runtime,
|
|
1468
1769
|
sessionGeneration: runtime.sessionGeneration,
|
|
1469
1770
|
dbg,
|
|
1771
|
+
onDeferredSequenceResolved: retroactivelyHydrateAfterDeferredSequence({
|
|
1772
|
+
getWarmupOwnSnapshotRead: () => warmupOwnSnapshotRead,
|
|
1773
|
+
snapshotRoot,
|
|
1774
|
+
runtime,
|
|
1775
|
+
dbg,
|
|
1776
|
+
}),
|
|
1470
1777
|
});
|
|
1471
1778
|
logLatency({
|
|
1472
1779
|
type: "phase",
|
|
@@ -1476,6 +1783,12 @@ export async function handleSessionStart(deps) {
|
|
|
1476
1783
|
durationMs: Date.now() - sequenceReadStartedAt,
|
|
1477
1784
|
metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
|
|
1478
1785
|
});
|
|
1786
|
+
if (timedOut) {
|
|
1787
|
+
recordSnapshotSequenceTimeout({
|
|
1788
|
+
snapshotRoot,
|
|
1789
|
+
snapshotPath: getProjectSnapshotPath(snapshotRoot),
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1479
1792
|
runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
|
|
1480
1793
|
const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
|
|
1481
1794
|
dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
@@ -1499,6 +1812,8 @@ export async function handleSessionStart(deps) {
|
|
|
1499
1812
|
catch {
|
|
1500
1813
|
// Missing snapshots are the normal cold-start case.
|
|
1501
1814
|
}
|
|
1815
|
+
const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
|
|
1816
|
+
nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
|
|
1502
1817
|
const snapshotGate = loadSnapshotBodyUnlessStale({
|
|
1503
1818
|
root: snapshotRoot,
|
|
1504
1819
|
currentProjectSeq: freshnessSeq,
|
|
@@ -1506,6 +1821,10 @@ export async function handleSessionStart(deps) {
|
|
|
1506
1821
|
});
|
|
1507
1822
|
const snapshot = snapshotGate.snapshot;
|
|
1508
1823
|
const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
|
|
1824
|
+
const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
|
|
1825
|
+
skippedStale: snapshotGate.skippedStale,
|
|
1826
|
+
bodyPresent: snapshotBodyPresent,
|
|
1827
|
+
});
|
|
1509
1828
|
logLatency({
|
|
1510
1829
|
type: "phase",
|
|
1511
1830
|
phase: "session_start_snapshot_load",
|
|
@@ -1516,6 +1835,7 @@ export async function handleSessionStart(deps) {
|
|
|
1516
1835
|
bytes: snapshotBytes,
|
|
1517
1836
|
fresh: snapshotFresh,
|
|
1518
1837
|
seq: snapshot?.seq ?? null,
|
|
1838
|
+
reason: snapshotFresh ? undefined : snapshotMissReason,
|
|
1519
1839
|
...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
|
|
1520
1840
|
...(timedOut ? { sequenceUnknown: true } : {}),
|
|
1521
1841
|
},
|
|
@@ -1525,6 +1845,7 @@ export async function handleSessionStart(deps) {
|
|
|
1525
1845
|
root: snapshotRoot,
|
|
1526
1846
|
currentProjectSeq: freshnessSeq,
|
|
1527
1847
|
snapshot,
|
|
1848
|
+
missReason: snapshotMissReason,
|
|
1528
1849
|
});
|
|
1529
1850
|
if (snapshotFresh) {
|
|
1530
1851
|
hydrateRuntimeFromProjectSnapshot(runtime, snapshot);
|
|
@@ -1546,6 +1867,7 @@ export async function handleSessionStart(deps) {
|
|
|
1546
1867
|
durationMs: totalDurationMs,
|
|
1547
1868
|
metadata: { mode: startupMode, reason: deps.sessionReason },
|
|
1548
1869
|
});
|
|
1870
|
+
logHostReadyDelay(deps, cwd);
|
|
1549
1871
|
emitSmellsSessionStartLine(dbg, sessionStartMs);
|
|
1550
1872
|
return;
|
|
1551
1873
|
}
|
|
@@ -1582,6 +1904,20 @@ export async function handleSessionStart(deps) {
|
|
|
1582
1904
|
durationMs: Date.now() - sequenceReadStartedAt,
|
|
1583
1905
|
metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
|
|
1584
1906
|
});
|
|
1907
|
+
if (timedOut) {
|
|
1908
|
+
// #1785: instrumentation only here, deliberately no
|
|
1909
|
+
// `onDeferredSequenceResolved` — unlike quick mode's cold path (which
|
|
1910
|
+
// does nothing when the snapshot isn't trusted), full mode's cold path
|
|
1911
|
+
// actively kicks off a real rescan below to rebuild this same state.
|
|
1912
|
+
// Retroactively hydrating from the on-disk snapshot once the deferred
|
|
1913
|
+
// read lands could overwrite that fresher, actively-computed state with
|
|
1914
|
+
// the stale disk copy — a regression, not a fix. See the PR body for the
|
|
1915
|
+
// full reasoning.
|
|
1916
|
+
recordSnapshotSequenceTimeout({
|
|
1917
|
+
snapshotRoot,
|
|
1918
|
+
snapshotPath: getProjectSnapshotPath(snapshotRoot),
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1585
1921
|
runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
|
|
1586
1922
|
const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
|
|
1587
1923
|
dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
|
|
@@ -1601,6 +1937,8 @@ export async function handleSessionStart(deps) {
|
|
|
1601
1937
|
catch {
|
|
1602
1938
|
// Missing snapshots are the normal cold-start case.
|
|
1603
1939
|
}
|
|
1940
|
+
const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
|
|
1941
|
+
nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
|
|
1604
1942
|
const snapshotGate = loadSnapshotBodyUnlessStale({
|
|
1605
1943
|
root: snapshotRoot,
|
|
1606
1944
|
currentProjectSeq: freshnessSeq,
|
|
@@ -1608,6 +1946,10 @@ export async function handleSessionStart(deps) {
|
|
|
1608
1946
|
});
|
|
1609
1947
|
const snapshot = snapshotGate.snapshot;
|
|
1610
1948
|
const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
|
|
1949
|
+
const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
|
|
1950
|
+
skippedStale: snapshotGate.skippedStale,
|
|
1951
|
+
bodyPresent: snapshotBodyPresent,
|
|
1952
|
+
});
|
|
1611
1953
|
logLatency({
|
|
1612
1954
|
type: "phase",
|
|
1613
1955
|
phase: "session_start_snapshot_load",
|
|
@@ -1618,6 +1960,7 @@ export async function handleSessionStart(deps) {
|
|
|
1618
1960
|
bytes: snapshotBytes,
|
|
1619
1961
|
fresh: snapshotFresh,
|
|
1620
1962
|
seq: snapshot?.seq ?? null,
|
|
1963
|
+
reason: snapshotFresh ? undefined : snapshotMissReason,
|
|
1621
1964
|
...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
|
|
1622
1965
|
...(timedOut ? { sequenceUnknown: true } : {}),
|
|
1623
1966
|
},
|
|
@@ -1627,6 +1970,7 @@ export async function handleSessionStart(deps) {
|
|
|
1627
1970
|
root: snapshotRoot,
|
|
1628
1971
|
currentProjectSeq: freshnessSeq,
|
|
1629
1972
|
snapshot,
|
|
1973
|
+
missReason: snapshotMissReason,
|
|
1630
1974
|
});
|
|
1631
1975
|
const freshSnapshot = snapshotFresh ? snapshot : null;
|
|
1632
1976
|
if (freshSnapshot) {
|
|
@@ -1754,6 +2098,7 @@ export async function handleSessionStart(deps) {
|
|
|
1754
2098
|
const jstsHeavyScansWillRun = startupScansWillRun && canRunStartupHeavyScans(languageProfile, "jsts");
|
|
1755
2099
|
if (allowBootstrapTasks) {
|
|
1756
2100
|
scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, jstsHeavyScansWillRun, dbg);
|
|
2101
|
+
scheduleManagedToolRefresh(dbg);
|
|
1757
2102
|
}
|
|
1758
2103
|
if (allowBootstrapTasks) {
|
|
1759
2104
|
// Fire-and-forget like other tool probes
|
|
@@ -1866,6 +2211,7 @@ export async function handleSessionStart(deps) {
|
|
|
1866
2211
|
durationMs: totalDurationMs,
|
|
1867
2212
|
metadata: { mode: startupMode, reason: deps.sessionReason },
|
|
1868
2213
|
});
|
|
2214
|
+
logHostReadyDelay(deps, cwd);
|
|
1869
2215
|
emitSmellsSessionStartLine(dbg, sessionStartMs);
|
|
1870
2216
|
}
|
|
1871
2217
|
/**
|