@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
|
@@ -13,7 +13,7 @@ import path from "node:path";
|
|
|
13
13
|
import { getGlobalPiLensDir, getProjectIgnoreGlobs, isPathIgnoredByProject, } from "../file-utils.js";
|
|
14
14
|
import { STAGE_TMP_PATTERN } from "../atomic-write-staging.js";
|
|
15
15
|
import { DOTNET_CSHARP_ROOT_MARKERS, DOTNET_FSHARP_ROOT_MARKERS, KIND_EXTENSIONS, } from "../file-kinds.js";
|
|
16
|
-
import { direntsHaveMarkerGlobMatch, isAtOrAboveHomeDir, isFullyQualified, isWindowsPath, } from "../path-utils.js";
|
|
16
|
+
import { direntsHaveMarkerGlobMatch, isAtOrAboveHomeDir, isFullyQualified, isWindowsPath, pathsEqual, } from "../path-utils.js";
|
|
17
17
|
import { ensureTool, getToolEnvironment, getToolPath, } from "../installer/index.js";
|
|
18
18
|
import { resolveOpengrepConfig } from "../opengrep-config.js";
|
|
19
19
|
import { isZizmorAuditTarget, resolveZizmorGitHubToken } from "../zizmor-config.js";
|
|
@@ -192,6 +192,15 @@ function canInstall(allowInstall) {
|
|
|
192
192
|
const DIRECT_LSP_NEGATIVE_TTL_MS = Math.max(30_000, Number.parseInt(process.env.PI_LENS_DIRECT_LSP_NEGATIVE_TTL_MS ?? "600000", 10) || 600_000);
|
|
193
193
|
const directLspCommandUnavailableUntil = new Map();
|
|
194
194
|
const directLspCommandSkipLoggedUntil = new Map();
|
|
195
|
+
/** Re-arm direct-command availability for the next session. */
|
|
196
|
+
export function resetDirectLspCommandAvailability() {
|
|
197
|
+
directLspCommandUnavailableUntil.clear();
|
|
198
|
+
directLspCommandSkipLoggedUntil.clear();
|
|
199
|
+
}
|
|
200
|
+
/** Test seam for seeding the real negative-cache path. */
|
|
201
|
+
export function _markDirectLspCommandUnavailableForTests(command) {
|
|
202
|
+
markDirectLspCommandUnavailable(command);
|
|
203
|
+
}
|
|
195
204
|
function pruneExpiredDirectLspNegativeEntries(now = Date.now()) {
|
|
196
205
|
for (const [command, until] of directLspCommandUnavailableUntil) {
|
|
197
206
|
if (until <= now) {
|
|
@@ -712,7 +721,10 @@ async function markerExists(dir, pattern) {
|
|
|
712
721
|
* NearestRoot(includePatterns, excludePatterns?) → RootFunction
|
|
713
722
|
*
|
|
714
723
|
* - includePatterns: file/dir names that signal the project root (e.g. ["package.json"])
|
|
715
|
-
* - excludePatterns: if any of these exist in a directory,
|
|
724
|
+
* - excludePatterns: if any of these exist in a directory, SKIP that directory and
|
|
725
|
+
* keep walking up toward stopDir — it does not abort resolution. A directory that
|
|
726
|
+
* matches an exclude pattern is simply never returned as a root; the walk still
|
|
727
|
+
* continues past it looking for an include-pattern hit higher up (#1671).
|
|
716
728
|
* - stopDir: walk stops here (defaults to filesystem root; set to project cwd for safety)
|
|
717
729
|
*
|
|
718
730
|
* Equivalent to createRootDetector; exported under both names for clarity.
|
|
@@ -877,16 +889,28 @@ async function findAncestorFileAmong(startDir, candidateSegmentLists) {
|
|
|
877
889
|
return undefined;
|
|
878
890
|
}
|
|
879
891
|
/**
|
|
880
|
-
* A failed classic-compiler repair must not repeat
|
|
881
|
-
* successful installs, so a repair that works
|
|
882
|
-
* its own. A repair that fails leaves nothing
|
|
883
|
-
* has three call sites (TypeScript, Vue,
|
|
884
|
-
* offline or partial install re-runs a 120 s
|
|
892
|
+
* A failed classic-compiler repair must not repeat within a session.
|
|
893
|
+
* `ensureTool` caches successful installs, so a repair that works
|
|
894
|
+
* short-circuits later calls on its own. A repair that fails leaves nothing
|
|
895
|
+
* behind, and `findTsserverPath` has three call sites (TypeScript, Vue,
|
|
896
|
+
* Svelte). Without this guard an offline or partial install re-runs a 120 s
|
|
897
|
+
* forced reinstall on every spawn.
|
|
898
|
+
*
|
|
899
|
+
* The guard is a plain module-level flag, so without an explicit re-arm it
|
|
900
|
+
* would latch for the whole extension-host process — a repair that failed
|
|
901
|
+
* once (transient registry hiccup) would stay unrepairable for every later
|
|
902
|
+
* session in that process. `resetClassicTsRepairGuard` re-arms it; callers
|
|
903
|
+
* wire that into `session_start` alongside the other per-session resets
|
|
904
|
+
* (#1570).
|
|
885
905
|
*/
|
|
886
906
|
let classicTsRepairAttempted = false;
|
|
907
|
+
/** Re-arm the classic-repair guard so a new session gets its own attempt. */
|
|
908
|
+
export function resetClassicTsRepairGuard() {
|
|
909
|
+
classicTsRepairAttempted = false;
|
|
910
|
+
}
|
|
887
911
|
/** Test hook — clears the per-process classic-repair guard. */
|
|
888
912
|
export function _resetClassicTsRepairForTests() {
|
|
889
|
-
|
|
913
|
+
resetClassicTsRepairGuard();
|
|
890
914
|
}
|
|
891
915
|
/**
|
|
892
916
|
* Directories that may hold the TypeScript package next to a resolved `tsc`
|
|
@@ -1559,15 +1583,120 @@ export const GoServer = {
|
|
|
1559
1583
|
return { ...result, initialization: { ui: { semanticTokens: true } } };
|
|
1560
1584
|
},
|
|
1561
1585
|
};
|
|
1562
|
-
async function
|
|
1586
|
+
async function readTextFileOrUndefined(filePath) {
|
|
1563
1587
|
try {
|
|
1564
|
-
|
|
1565
|
-
const content = await readFile(cargoPath, "utf-8");
|
|
1566
|
-
return /^\s*\[workspace\]/m.test(content);
|
|
1588
|
+
return await readFile(filePath, "utf-8");
|
|
1567
1589
|
}
|
|
1568
1590
|
catch {
|
|
1591
|
+
return undefined;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Slice out ONE top-level TOML table's raw body — from its `[name]` heading
|
|
1596
|
+
* to the next top-level `[...]`/`[[...]]` heading or EOF. `members`/`exclude`
|
|
1597
|
+
* must be read from the `[workspace]` table specifically: `[package]` has its
|
|
1598
|
+
* OWN `exclude` key (the standard cargo-publish exclude list, conventionally
|
|
1599
|
+
* written above `[workspace]` in a virtual-manifest-less root crate), and a
|
|
1600
|
+
* whole-file regex would misread it as workspace membership (#1671 F4).
|
|
1601
|
+
*/
|
|
1602
|
+
function extractTomlTableSection(content, tableName) {
|
|
1603
|
+
const heading = new RegExp(`^\\[${tableName}\\][ \\t]*(?:#.*)?$`, "m");
|
|
1604
|
+
const match = heading.exec(content);
|
|
1605
|
+
if (!match)
|
|
1606
|
+
return "";
|
|
1607
|
+
const rest = content.slice(match.index + match[0].length);
|
|
1608
|
+
const nextHeading = rest.match(/^\[{1,2}[^\]]+\]{1,2}[ \t]*(?:#.*)?$/m);
|
|
1609
|
+
return nextHeading?.index !== undefined ? rest.slice(0, nextHeading.index) : rest;
|
|
1610
|
+
}
|
|
1611
|
+
function parseTomlStringArray(content, key) {
|
|
1612
|
+
const match = content.match(new RegExp(`^[ \\t]*${key}[ \\t]*=[ \\t]*\\[([\\s\\S]*?)\\]`, "m"));
|
|
1613
|
+
if (!match)
|
|
1614
|
+
return [];
|
|
1615
|
+
return [...match[1].matchAll(/"([^"]*)"|'([^']*)'/g)].map((m) => (m[1] ?? m[2] ?? "").trim());
|
|
1616
|
+
}
|
|
1617
|
+
/** Turn one `/`-delimited glob SEGMENT into a regex source: `*` matches any
|
|
1618
|
+
* run of characters within the segment, `?` matches exactly one character,
|
|
1619
|
+
* everything else is escaped and literal. */
|
|
1620
|
+
function segmentGlobToRegExpSource(segment) {
|
|
1621
|
+
let out = "";
|
|
1622
|
+
for (const ch of segment) {
|
|
1623
|
+
if (ch === "*")
|
|
1624
|
+
out += "[^/]*";
|
|
1625
|
+
else if (ch === "?")
|
|
1626
|
+
out += "[^/]";
|
|
1627
|
+
else
|
|
1628
|
+
out += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
1629
|
+
}
|
|
1630
|
+
return out;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* A `members`/`exclude` entry names a path exactly, or globs it segment by
|
|
1634
|
+
* segment: `*` and `?` inside a segment work at any depth — one wildcard
|
|
1635
|
+
* segment (`crates/*`), a bare `*`, or several chained together for a
|
|
1636
|
+
* deeper fixed-depth layout — matching cargo's own `glob`-crate semantics
|
|
1637
|
+
* for a fixed number of path components.
|
|
1638
|
+
*
|
|
1639
|
+
* KNOWN LIMITATION (#1671 F6, documented rather than implemented): a
|
|
1640
|
+
* recursive `**` segment (matching a variable number of path components) is
|
|
1641
|
+
* NOT supported and never matches — cargo workspaces that rely on `**` to
|
|
1642
|
+
* pull in an arbitrarily-nested crate tree will under-hoist (the crate stays
|
|
1643
|
+
* independently rooted instead of joining the workspace). This is
|
|
1644
|
+
* deliberately out of #1671's scope: the common, and the issue's fixture,
|
|
1645
|
+
* shape is an explicit fixed-depth `members` list.
|
|
1646
|
+
*/
|
|
1647
|
+
function matchesCargoWorkspacePattern(pattern, relativePath) {
|
|
1648
|
+
const normalized = pattern.replace(/\/+$/, "");
|
|
1649
|
+
if (normalized.includes("**"))
|
|
1650
|
+
return false;
|
|
1651
|
+
const patternSegments = normalized.split("/");
|
|
1652
|
+
const pathSegments = relativePath.split("/");
|
|
1653
|
+
if (patternSegments.length !== pathSegments.length)
|
|
1654
|
+
return false;
|
|
1655
|
+
return patternSegments.every((segment, i) => new RegExp(`^${segmentGlobToRegExpSource(segment)}$`).test(pathSegments[i]));
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Given an ancestor Cargo.toml's raw contents that already contains a
|
|
1659
|
+
* `[workspace]` table, decide whether it actually claims `childDir` as a
|
|
1660
|
+
* member. Cargo's own default is that a bare `[workspace]` with no `members`
|
|
1661
|
+
* key claims only the manifest's own package — a nested crate is NOT
|
|
1662
|
+
* implicitly swept in just because it sits underneath the workspace root on
|
|
1663
|
+
* disk. Without this check any Cargo.toml with a `[workspace]` table would
|
|
1664
|
+
* hoist every crate below it, including ones the workspace never declared
|
|
1665
|
+
* (#1671) — the same defect shape as an undeclared Maven sibling module.
|
|
1666
|
+
*
|
|
1667
|
+
* KNOWN LIMITATION (#1671 F7, documented rather than implemented): cargo also
|
|
1668
|
+
* treats a crate as an implicit workspace member when the workspace root's
|
|
1669
|
+
* OWN `[package]` has a `path = "..."` dependency on it and no explicit
|
|
1670
|
+
* `members` key is present at all. That dependency-graph inference is not
|
|
1671
|
+
* evaluated here — a workspace relying on it alone (no `members` key) reads
|
|
1672
|
+
* as claiming nothing, so its crates stay independently rooted rather than
|
|
1673
|
+
* being (correctly, per cargo) swept in. An explicit `members` list — the
|
|
1674
|
+
* common case and the one #1671's fixtures exercise — is unaffected.
|
|
1675
|
+
*/
|
|
1676
|
+
function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
|
|
1677
|
+
const relativePath = path.relative(parentDir, childDir).split(path.sep).join("/");
|
|
1678
|
+
if (relativePath === "" || relativePath.startsWith(".."))
|
|
1679
|
+
return false;
|
|
1680
|
+
const workspaceSection = extractTomlTableSection(workspaceContent, "workspace");
|
|
1681
|
+
const excluded = parseTomlStringArray(workspaceSection, "exclude");
|
|
1682
|
+
if (excluded.some((pattern) => matchesCargoWorkspacePattern(pattern, relativePath))) {
|
|
1569
1683
|
return false;
|
|
1570
1684
|
}
|
|
1685
|
+
const members = parseTomlStringArray(workspaceSection, "members");
|
|
1686
|
+
return members.some((pattern) => matchesCargoWorkspacePattern(pattern, relativePath));
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Bound a monorepo-hoist walk-up by the session ceiling: when `file` is inside
|
|
1690
|
+
* the session cwd, the walk must stop AT the cwd rather than climb past it —
|
|
1691
|
+
* matching enforceLspRootCeiling's clamp semantics but avoiding the wasted stat
|
|
1692
|
+
* calls of walking past a boundary we would clamp back down anyway. When
|
|
1693
|
+
* `file` is outside the session (isolated tests, out-of-session API callers),
|
|
1694
|
+
* enforceLspRootCeiling is a no-op, so the walk is left unbounded (`undefined`).
|
|
1695
|
+
*/
|
|
1696
|
+
function sessionHoistCeiling(sessionCwd, file) {
|
|
1697
|
+
return isSameOrWithin(path.resolve(sessionCwd), path.resolve(file))
|
|
1698
|
+
? path.resolve(sessionCwd)
|
|
1699
|
+
: undefined;
|
|
1571
1700
|
}
|
|
1572
1701
|
function RustWorkspaceRoot() {
|
|
1573
1702
|
const crateRoot = createRootDetector(["Cargo.toml", "Cargo.lock"]);
|
|
@@ -1575,21 +1704,131 @@ function RustWorkspaceRoot() {
|
|
|
1575
1704
|
const root = await crateRoot(file);
|
|
1576
1705
|
if (!root)
|
|
1577
1706
|
return undefined;
|
|
1707
|
+
const sessionCwd = process.cwd();
|
|
1708
|
+
// The walk-up for an ancestor Cargo.toml with a [workspace] table stays
|
|
1709
|
+
// bounded by the same session ceiling the crate-root lookup above already
|
|
1710
|
+
// enforces (enforceLspRootCeiling) — a monorepo hoist must never cross the
|
|
1711
|
+
// session boundary just because a workspace manifest happens to sit above
|
|
1712
|
+
// it (#1671).
|
|
1713
|
+
const stop = sessionHoistCeiling(sessionCwd, file);
|
|
1578
1714
|
let current = root;
|
|
1579
1715
|
const fsRoot = path.parse(current).root;
|
|
1580
1716
|
while (true) {
|
|
1717
|
+
if (stop !== undefined && current === stop)
|
|
1718
|
+
break;
|
|
1581
1719
|
const parent = path.dirname(current);
|
|
1582
1720
|
if (parent === current || parent === fsRoot)
|
|
1583
1721
|
break;
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1586
|
-
|
|
1722
|
+
const parentCargoPath = path.join(parent, "Cargo.toml");
|
|
1723
|
+
const parentCargoContent = await readTextFileOrUndefined(parentCargoPath);
|
|
1724
|
+
if (parentCargoContent !== undefined && /^\s*\[workspace\]/m.test(parentCargoContent)) {
|
|
1725
|
+
// Test membership against the ORIGINAL crate dir (`root`), never the
|
|
1726
|
+
// walk cursor (`current`, which may already have climbed through
|
|
1727
|
+
// gap directories that have no Cargo.toml of their own) — a
|
|
1728
|
+
// `members = ["crates/foo"]` or `["crates/*"]` entry is relative to
|
|
1729
|
+
// the workspace root, spanning the whole gap in one hop (#1671 F1).
|
|
1730
|
+
if (cargoWorkspaceDeclaresMember(parentCargoContent, parent, root)) {
|
|
1731
|
+
return enforceLspRootCeiling(parent, sessionCwd, file);
|
|
1732
|
+
}
|
|
1733
|
+
// A workspace root exists here but its `members`/`exclude` tables do
|
|
1734
|
+
// not claim this crate — stop climbing; the crate stays independently
|
|
1735
|
+
// rooted rather than being swept into a workspace it opted out of.
|
|
1736
|
+
break;
|
|
1587
1737
|
}
|
|
1588
1738
|
current = parent;
|
|
1589
1739
|
}
|
|
1590
1740
|
return root;
|
|
1591
1741
|
};
|
|
1592
1742
|
}
|
|
1743
|
+
/**
|
|
1744
|
+
* Resolve whether `parentPomPath`'s <modules> block declares `childDir` as one
|
|
1745
|
+
* of its member modules. Maven multi-module hoisting must only chain through
|
|
1746
|
+
* poms that actually declare the child (an undeclared sibling directory that
|
|
1747
|
+
* merely happens to sit next to a parent pom stays independently rooted) —
|
|
1748
|
+
* this is the "Maven module-chain verification" #1671 asks for, as opposed to
|
|
1749
|
+
* rust-analyzer's simpler "any ancestor [workspace] wins" hoist.
|
|
1750
|
+
*/
|
|
1751
|
+
/**
|
|
1752
|
+
* Strip XML comments to a fixed point rather than in one pass: a single
|
|
1753
|
+
* `.replace()` can leave a residual `<!--` behind on adversarially-nested
|
|
1754
|
+
* input (CodeQL flags this class as "incomplete multi-character
|
|
1755
|
+
* sanitization" — the removal of one comment can expose a delimiter that
|
|
1756
|
+
* was itself inside another). Looping until nothing changes closes that gap.
|
|
1757
|
+
*/
|
|
1758
|
+
function stripXmlComments(content) {
|
|
1759
|
+
let result = content;
|
|
1760
|
+
let previous;
|
|
1761
|
+
do {
|
|
1762
|
+
previous = result;
|
|
1763
|
+
result = result.replace(/<!--[\s\S]*?-->/g, "");
|
|
1764
|
+
} while (result !== previous);
|
|
1765
|
+
return result;
|
|
1766
|
+
}
|
|
1767
|
+
async function declaresMavenModule(parentDir, parentPomPath, childDir) {
|
|
1768
|
+
try {
|
|
1769
|
+
const content = stripXmlComments(await readFile(parentPomPath, "utf-8"));
|
|
1770
|
+
const modulesBlock = content.match(/<modules>([\s\S]*?)<\/modules>/);
|
|
1771
|
+
if (!modulesBlock)
|
|
1772
|
+
return false;
|
|
1773
|
+
const resolvedChild = path.resolve(childDir);
|
|
1774
|
+
for (const match of modulesBlock[1].matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
|
|
1775
|
+
// Case-insensitive / realpath-aware compare (#1671 F8): a declared
|
|
1776
|
+
// `<module>Foo</module>` must still match a directory actually named
|
|
1777
|
+
// `foo` on a case-insensitive filesystem, the same class of check the
|
|
1778
|
+
// rest of this codebase does via `pathsEqual` (#1139/#1150).
|
|
1779
|
+
if (pathsEqual(path.resolve(parentDir, match[1]), resolvedChild))
|
|
1780
|
+
return true;
|
|
1781
|
+
}
|
|
1782
|
+
return false;
|
|
1783
|
+
}
|
|
1784
|
+
catch {
|
|
1785
|
+
return false;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
function JavaWorkspaceRoot() {
|
|
1789
|
+
const moduleRoot = createRootDetector(["pom.xml", "build.gradle", ".classpath"]);
|
|
1790
|
+
return async (file) => {
|
|
1791
|
+
const root = await moduleRoot(file);
|
|
1792
|
+
if (!root)
|
|
1793
|
+
return undefined;
|
|
1794
|
+
// Only a Maven (pom.xml) module chain-hoists here — Gradle/.classpath module
|
|
1795
|
+
// roots are returned as found; multi-module Gradle wiring (settings.gradle)
|
|
1796
|
+
// is a different shape and out of scope for #1671.
|
|
1797
|
+
if (!(await markerExists(root, "pom.xml")))
|
|
1798
|
+
return root;
|
|
1799
|
+
const sessionCwd = process.cwd();
|
|
1800
|
+
const stop = sessionHoistCeiling(sessionCwd, file);
|
|
1801
|
+
// `current` is the walk CURSOR — it climbs over gap directories (ones
|
|
1802
|
+
// with no pom.xml of their own, e.g. a `<module>sub/dir</module>` entry
|
|
1803
|
+
// spanning more than one filesystem level). `lastHop` is the last
|
|
1804
|
+
// CONFIRMED module boundary; it is what the next ancestor pom's
|
|
1805
|
+
// <modules> must declare, and it is what actually gets returned — never
|
|
1806
|
+
// the cursor, which can land on a bare gap directory that is not itself
|
|
1807
|
+
// a valid module root (#1671 F2).
|
|
1808
|
+
let current = root;
|
|
1809
|
+
let lastHop = root;
|
|
1810
|
+
const fsRoot = path.parse(current).root;
|
|
1811
|
+
while (true) {
|
|
1812
|
+
if (stop !== undefined && current === stop)
|
|
1813
|
+
break;
|
|
1814
|
+
const parent = path.dirname(current);
|
|
1815
|
+
if (parent === current || parent === fsRoot)
|
|
1816
|
+
break;
|
|
1817
|
+
if (await markerExists(parent, "pom.xml")) {
|
|
1818
|
+
const parentPom = path.join(parent, "pom.xml");
|
|
1819
|
+
if (!(await declaresMavenModule(parent, parentPom, lastHop)))
|
|
1820
|
+
break;
|
|
1821
|
+
current = parent;
|
|
1822
|
+
lastHop = parent;
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
// No pom.xml here — a gap directory, not a module boundary. Keep
|
|
1826
|
+
// climbing without advancing `lastHop`.
|
|
1827
|
+
current = parent;
|
|
1828
|
+
}
|
|
1829
|
+
return enforceLspRootCeiling(lastHop, sessionCwd, file);
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1593
1832
|
export const RustServer = {
|
|
1594
1833
|
id: "rust",
|
|
1595
1834
|
name: "rust-analyzer",
|
|
@@ -1819,7 +2058,7 @@ export const JavaServer = createInteractiveServer({
|
|
|
1819
2058
|
id: "java",
|
|
1820
2059
|
name: "JDT Language Server",
|
|
1821
2060
|
extensions: KIND_EXTENSIONS["java"],
|
|
1822
|
-
root: RootWithFallback(
|
|
2061
|
+
root: RootWithFallback(JavaWorkspaceRoot()),
|
|
1823
2062
|
language: "java",
|
|
1824
2063
|
command: () => process.env.JDTLS_PATH || "jdtls",
|
|
1825
2064
|
args: (root) => createLombokJdtlsArgs(root),
|
|
@@ -2024,6 +2263,20 @@ export const ClojureServer = {
|
|
|
2024
2263
|
}, options?.allowInstall);
|
|
2025
2264
|
},
|
|
2026
2265
|
};
|
|
2266
|
+
export const CueServer = {
|
|
2267
|
+
id: "cue",
|
|
2268
|
+
name: "CUE Language Server",
|
|
2269
|
+
extensions: KIND_EXTENSIONS["cue"],
|
|
2270
|
+
root: RootWithFallback(createRootDetector(["cue.mod", ".git"])),
|
|
2271
|
+
async spawn(root, options) {
|
|
2272
|
+
return resolveAndLaunch({
|
|
2273
|
+
candidates: ["cue"],
|
|
2274
|
+
args: ["lsp", "serve"],
|
|
2275
|
+
cwd: root,
|
|
2276
|
+
managedToolId: "cue",
|
|
2277
|
+
}, options?.allowInstall);
|
|
2278
|
+
},
|
|
2279
|
+
};
|
|
2027
2280
|
export const TerraformServer = {
|
|
2028
2281
|
id: "terraform",
|
|
2029
2282
|
name: "Terraform LSP",
|
|
@@ -2402,6 +2655,13 @@ export const AstGrepServer = {
|
|
|
2402
2655
|
// (it falls back to napi when the ast-grep binary is absent — Gate B).
|
|
2403
2656
|
root: RootWithFallback(createRootDetector(["sgconfig.yml", "sgconfig.yaml"]), RootWithFallback(NearestRoot([".git"]), async () => process.cwd())),
|
|
2404
2657
|
availabilityKey: "ast-grep",
|
|
2658
|
+
// #1714: the one auxiliary with a measured wedge ceiling. A `lens_diagnostics
|
|
2659
|
+
// mode=full` sweep of 225 files drove this server into an unrecoverable stall
|
|
2660
|
+
// twice in two exposures (writes outstanding 5.9 s and 9.4 s, then a forced
|
|
2661
|
+
// shutdown that timed out both the request and the exit notify). It re-parses
|
|
2662
|
+
// the whole file on every didOpen, so it absorbs a sweep more slowly than the
|
|
2663
|
+
// other scanners — hold it to half the shared default.
|
|
2664
|
+
notifyInflightLimit: 4,
|
|
2405
2665
|
// First scan of a session compiles the rules.
|
|
2406
2666
|
initializeTimeoutMs: 15000,
|
|
2407
2667
|
async spawn(root, options) {
|
|
@@ -2564,6 +2824,7 @@ export const LSP_SERVERS = [
|
|
|
2564
2824
|
MarksmanServer,
|
|
2565
2825
|
OCamlServer,
|
|
2566
2826
|
ClojureServer,
|
|
2827
|
+
CueServer,
|
|
2567
2828
|
TerraformServer,
|
|
2568
2829
|
NixServer,
|
|
2569
2830
|
BashServer,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Process-lifetime history of successful LSP spawn plus initialize durations. */
|
|
2
|
+
const MAX_SERVER_HISTORIES = 64;
|
|
3
|
+
const successfulSpawnDurationMs = new Map();
|
|
4
|
+
export function recordSuccessfulLspSpawn(serverId, durationMs) {
|
|
5
|
+
if (!Number.isFinite(durationMs) || durationMs < 0)
|
|
6
|
+
return;
|
|
7
|
+
successfulSpawnDurationMs.delete(serverId);
|
|
8
|
+
successfulSpawnDurationMs.set(serverId, durationMs);
|
|
9
|
+
while (successfulSpawnDurationMs.size > MAX_SERVER_HISTORIES) {
|
|
10
|
+
const oldest = successfulSpawnDurationMs.keys().next().value;
|
|
11
|
+
if (oldest === undefined)
|
|
12
|
+
break;
|
|
13
|
+
successfulSpawnDurationMs.delete(oldest);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function getSuccessfulLspSpawnDurationMs(serverId) {
|
|
17
|
+
return successfulSpawnDurationMs.get(serverId);
|
|
18
|
+
}
|
|
19
|
+
/** Test-only: isolate process-lifetime history between cases. */
|
|
20
|
+
export function _clearSuccessfulLspSpawnHistoryForTests() {
|
|
21
|
+
successfulSpawnDurationMs.clear();
|
|
22
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP `textDocument/didChange` sync-kind negotiation (#1669).
|
|
3
|
+
*
|
|
4
|
+
* A server advertises how it wants document changes described via
|
|
5
|
+
* `ServerCapabilities.textDocumentSync`, either as a bare
|
|
6
|
+
* `TextDocumentSyncKind` number (the legacy pre-3.0 shape) or as a
|
|
7
|
+
* `TextDocumentSyncOptions` object whose `change` field carries the kind.
|
|
8
|
+
* pi-lens always sent a single whole-document `{ text }` change event — valid
|
|
9
|
+
* for `Full` (1) and harmless for `None` (0, since the server ignores content
|
|
10
|
+
* changes entirely), but out of spec for `Incremental` (2): an
|
|
11
|
+
* Incremental-only server expects every change event to carry a `range`.
|
|
12
|
+
*
|
|
13
|
+
* This module is the pure negotiation core, mirroring `position-encoding.ts`'s
|
|
14
|
+
* shape: read the kind from the server's `initialize` reply, defaulting to
|
|
15
|
+
* `Full` when the server doesn't advertise one — the same shape pi-lens has
|
|
16
|
+
* always sent, so an unrecognized/absent value never regresses `Full`/`None`
|
|
17
|
+
* behavior.
|
|
18
|
+
*/
|
|
19
|
+
export const TEXT_DOCUMENT_SYNC_KIND_NONE = 0;
|
|
20
|
+
export const TEXT_DOCUMENT_SYNC_KIND_FULL = 1;
|
|
21
|
+
export const TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL = 2;
|
|
22
|
+
function isSyncKind(value) {
|
|
23
|
+
return value === 0 || value === 1 || value === 2;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The `change` sync kind the server negotiated, read from its `initialize`
|
|
27
|
+
* reply. Defaults to `Full` (pi-lens's historical always-whole-document
|
|
28
|
+
* behavior) when the server omits `textDocumentSync` entirely, or advertises
|
|
29
|
+
* a shape/value this function doesn't recognize.
|
|
30
|
+
*/
|
|
31
|
+
export function negotiateSyncKind(serverCapabilities) {
|
|
32
|
+
const sync = serverCapabilities?.textDocumentSync;
|
|
33
|
+
// Legacy shape: the whole field IS the kind.
|
|
34
|
+
if (isSyncKind(sync))
|
|
35
|
+
return sync;
|
|
36
|
+
// 3.0+ shape: `TextDocumentSyncOptions.change`.
|
|
37
|
+
if (sync && typeof sync === "object") {
|
|
38
|
+
const change = sync.change;
|
|
39
|
+
if (isSyncKind(change))
|
|
40
|
+
return change;
|
|
41
|
+
}
|
|
42
|
+
return TEXT_DOCUMENT_SYNC_KIND_FULL;
|
|
43
|
+
}
|
|
@@ -38,7 +38,40 @@ import { normalizeMapKey } from "../path-utils.js";
|
|
|
38
38
|
// Constants
|
|
39
39
|
// ---------------------------------------------------------------------------
|
|
40
40
|
export const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* tsserver's synthetic inferred-project name, as its own source builds it:
|
|
43
|
+
* `"/dev/null/inferredProject" + counter + "*"`. `/dev/null` is a deliberate
|
|
44
|
+
* sentinel prefix — no real config file can live there — and matching the WHOLE
|
|
45
|
+
* string against it is the only safe test.
|
|
46
|
+
*
|
|
47
|
+
* #1645 review F4: an earlier version also matched an UNANCHORED
|
|
48
|
+
* `/inferred[-_ ]?project/i` anywhere in the string. That inverted the verdict
|
|
49
|
+
* for a real project in a directory a human happened to name that way —
|
|
50
|
+
* `/repo/inferred-project/tsconfig.json` classified as INFERRED, which demoted
|
|
51
|
+
* its genuine blocking errors. A classifier that gates authority must never key
|
|
52
|
+
* off user-controlled directory names.
|
|
53
|
+
*
|
|
54
|
+
* The optional drive-letter/backslash arm covers a host that normalizes the
|
|
55
|
+
* sentinel through win32 path handling before it reaches us; the `/dev/null`
|
|
56
|
+
* prefix is still required.
|
|
57
|
+
*/
|
|
58
|
+
const INFERRED_PROJECT_SENTINEL = /^(?:[A-Za-z]:)?[/\\]dev[/\\]null[/\\]inferredProject\d*\*?$/i;
|
|
59
|
+
/**
|
|
60
|
+
* Classify one tsserver `projectInfo` response body.
|
|
61
|
+
*
|
|
62
|
+
* `configFileName` is tsserver's own answer to "which project owns this file".
|
|
63
|
+
* A real project answers with a `tsconfig.json`/`jsconfig.json` path; a file
|
|
64
|
+
* that matches no project's `include`/`files` lands in tsserver's synthetic
|
|
65
|
+
* inferred project, whose `configFileName` is a `/dev/null/inferredProject1*`
|
|
66
|
+
* placeholder. The two are the same field, so the placeholder shape is the only
|
|
67
|
+
* thing that separates "checked against the project's real compiler options"
|
|
68
|
+
* from "checked against defaults nobody configured" (#1640).
|
|
69
|
+
*
|
|
70
|
+
* Exported so the diagnostic-demotion seam (`inferred-project.ts`) and the
|
|
71
|
+
* #1412 telemetry probe share ONE classifier — a second hand-rolled
|
|
72
|
+
* configFileName test would be a parallel source of truth for the same verdict.
|
|
73
|
+
*/
|
|
74
|
+
export function classifyProjectInfo(body) {
|
|
42
75
|
if (!body || typeof body !== "object") {
|
|
43
76
|
return { projectKind: "unassociated", association: "unassociated" };
|
|
44
77
|
}
|
|
@@ -47,8 +80,7 @@ function classifyProjectInfo(body) {
|
|
|
47
80
|
? info.configFileName
|
|
48
81
|
: undefined;
|
|
49
82
|
const inferred = configFile
|
|
50
|
-
?
|
|
51
|
-
/inferred[-_ ]?project/i.test(configFile)
|
|
83
|
+
? INFERRED_PROJECT_SENTINEL.test(configFile)
|
|
52
84
|
: false;
|
|
53
85
|
const projectKind = configFile
|
|
54
86
|
? inferred
|
|
@@ -132,6 +164,50 @@ export async function probeTsserverProjectIdentity(options) {
|
|
|
132
164
|
// Best-effort telemetry: command errors/timeouts never reach diagnostics.
|
|
133
165
|
}
|
|
134
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* #1640: ask tsserver which project owns `file`, on demand, through the same
|
|
169
|
+
* `typescript.tsserverRequest` escape hatch the sync-diagnostics helpers use.
|
|
170
|
+
*
|
|
171
|
+
* Unlike {@link probeTsserverProjectIdentity} — fire-and-forget telemetry
|
|
172
|
+
* sampled once per didOpen — this is a request/response call a caller awaits
|
|
173
|
+
* because it needs the answer to decide how to RENDER a diagnostic.
|
|
174
|
+
*
|
|
175
|
+
* Routed through `executeReadOnlyCommandOnLiveClient` ONLY, never
|
|
176
|
+
* `executeCommand` (#1645 review F1/F2). The mutation channel would open the
|
|
177
|
+
* `workspace/applyEdit` acceptance window, clobber a concurrent command's
|
|
178
|
+
* `activeMutationContext`, carry the 30s mutation backstop instead of the short
|
|
179
|
+
* probe one, and spawn a language-server fleet to answer. All four are wrong for
|
|
180
|
+
* a passive render-path question. A service without the read-only channel is
|
|
181
|
+
* UNKNOWN, not a reason to fall back.
|
|
182
|
+
*
|
|
183
|
+
* Returns `undefined` for every "we do not know" path: no read-only channel, no
|
|
184
|
+
* live server for the file, the command is not advertised (non-classic server,
|
|
185
|
+
* older typescript-language-server), the command was not executed, the response
|
|
186
|
+
* envelope is not `{success:true}`, or the call threw/timed out. `undefined`
|
|
187
|
+
* must never be treated as "inferred" — an unanswered probe is not a verdict
|
|
188
|
+
* (AGENTS.md shape 10: an empty result must distinguish clean from unavailable).
|
|
189
|
+
*/
|
|
190
|
+
export async function fetchTsserverProjectIdentity(svc, file) {
|
|
191
|
+
try {
|
|
192
|
+
if (typeof svc.executeReadOnlyCommandOnLiveClient !== "function") {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
// No `getAdvertisedCommands` pre-flight: that helper routes through
|
|
196
|
+
// `getClientForFile`, which SPAWNS. The read-only channel already enforces
|
|
197
|
+
// allowlist-by-advertisement server-side and answers `executed:false` for
|
|
198
|
+
// a server that never advertised the command.
|
|
199
|
+
const outcome = await svc.executeReadOnlyCommandOnLiveClient(file, TSSERVER_REQUEST_COMMAND, ["projectInfo", { file, needFileNameList: false }]);
|
|
200
|
+
if (!outcome.executed)
|
|
201
|
+
return undefined;
|
|
202
|
+
const response = outcome.result;
|
|
203
|
+
if (!response || response.success !== true)
|
|
204
|
+
return undefined;
|
|
205
|
+
return classifyProjectInfo(response.body);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
135
211
|
// ---------------------------------------------------------------------------
|
|
136
212
|
// Helpers
|
|
137
213
|
// ---------------------------------------------------------------------------
|
|
@@ -232,6 +232,49 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
|
|
|
232
232
|
// warm-up attempt and its retry, with zero diagnostics either time).
|
|
233
233
|
silentOnClean: true,
|
|
234
234
|
},
|
|
235
|
+
// cue lsp serve (#1522, #1519, #1520). Measured directly against the real
|
|
236
|
+
// v0.17.1 binary (`getWorkspaceDiagnosticsSupport` reports
|
|
237
|
+
// `mode: "push-only"`; no pull support advertised).
|
|
238
|
+
//
|
|
239
|
+
// It reports load/parse (syntax) errors as you type, but leaves
|
|
240
|
+
// conflicting-value/constraint-failure (evaluation) errors to `cue vet`
|
|
241
|
+
// — the #1522 cue-vet auxiliary runner covers that gap. So the syntax
|
|
242
|
+
// diagnostics this strategy governs are a REAL but PARTIAL signal, not
|
|
243
|
+
// full CUE validation.
|
|
244
|
+
//
|
|
245
|
+
// silentOnClean: true — the load-bearing finding. A cold `didOpen` on an
|
|
246
|
+
// already-CLEAN file publishes NOTHING inside the wait budget (measured:
|
|
247
|
+
// `touchFile` returns `inconclusive: true, inconclusiveReason:
|
|
248
|
+
// "diagnostics-wait"` after the full budget, never an affirmative empty
|
|
249
|
+
// array). This reproduces the #1520 review's original "reports
|
|
250
|
+
// conclusively clean while still waiting" concern for the clean-cold-open
|
|
251
|
+
// case specifically. It is NOT silent on every transition, though: once a
|
|
252
|
+
// document is open and a `didChange` lands, the server DOES publish —
|
|
253
|
+
// both the error (edit clean→broken: confirmed, ~930ms warm) and an
|
|
254
|
+
// explicit empty array clearing it (edit broken→clean: confirmed,
|
|
255
|
+
// ~320ms warm, `contentHash`-bound). That edit-triggered empty publish is
|
|
256
|
+
// exactly what the shared push-only clean-confirm gate needs
|
|
257
|
+
// `silentOnClean` for — it only ever governs the "no publish, notify
|
|
258
|
+
// succeeded" case, never a case that already got a real publish.
|
|
259
|
+
//
|
|
260
|
+
// seedFirstPush: true — the one cold-open case that DOES publish (a
|
|
261
|
+
// file that is already broken) sends the complete single diagnostic on
|
|
262
|
+
// its first push; there is no observed partial-then-complete sequence to
|
|
263
|
+
// wait out.
|
|
264
|
+
//
|
|
265
|
+
// aggregateWaitMs: 2000 covers the measured warm edit-to-publish latency
|
|
266
|
+
// (~930ms, syntax reparse) with margin; a cold spawn's first push (~2.1s
|
|
267
|
+
// end-to-end including process start) is bounded separately by
|
|
268
|
+
// maxClientWaitMs, not this per-diagnostics budget.
|
|
269
|
+
cue: {
|
|
270
|
+
seedFirstPush: true,
|
|
271
|
+
pullRetryBudgetMs: 0,
|
|
272
|
+
debounceMs: 150,
|
|
273
|
+
aggregateWaitMs: 2000,
|
|
274
|
+
expectSemanticSecondPush: false,
|
|
275
|
+
reopenOnResync: false,
|
|
276
|
+
silentOnClean: true,
|
|
277
|
+
},
|
|
235
278
|
};
|
|
236
279
|
/** Native TS7 can publish multiple versionless partial-program snapshots for a
|
|
237
280
|
* single open. Its first push is therefore provisional; a quiet window, rather
|