lazycodex-ai 5.1.48 → 5.1.51
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/dist/cli/index.js +1194 -752
- package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
- package/dist/cli/service-auth/commands.d.ts +2 -4
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli/service-auth/keystore.d.ts +26 -2
- package/dist/cli/service-auth/protocol.d.ts +7 -1
- package/dist/cli/service-auth/session.d.ts +6 -0
- package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
- package/dist/cli-node/index.js +1194 -752
- package/package.json +3 -1
- package/packages/lsp-core/package.json +45 -0
- package/packages/lsp-core/src/index.ts +30 -0
- package/packages/lsp-core/src/lsp/bun-command-output.ts +82 -0
- package/packages/lsp-core/src/lsp/bun-project-checks.test.ts +170 -0
- package/packages/lsp-core/src/lsp/bun-project-checks.ts +223 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.ts +14 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +52 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +471 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-pull-timeout.test.ts +64 -0
- package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
- package/packages/lsp-core/src/lsp/client-wrapper.test.ts +213 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +290 -0
- package/packages/lsp-core/src/lsp/client.ts +398 -0
- package/packages/lsp-core/src/lsp/config-loader.ts +254 -0
- package/packages/lsp-core/src/lsp/connection.ts +95 -0
- package/packages/lsp-core/src/lsp/constants.ts +17 -0
- package/packages/lsp-core/src/lsp/controlled-clock-test-support.ts +90 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +221 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +187 -0
- package/packages/lsp-core/src/lsp/effective-extension.ts +10 -0
- package/packages/lsp-core/src/lsp/errors.ts +89 -0
- package/packages/lsp-core/src/lsp/fake-bun-test-support.ts +102 -0
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
- package/packages/lsp-core/src/lsp/fixtures/disposed-stdin-epipe-probe.ts +28 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +234 -0
- package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
- package/packages/lsp-core/src/lsp/format-document.ts +90 -0
- package/packages/lsp-core/src/lsp/formatters.ts +144 -0
- package/packages/lsp-core/src/lsp/infer-extension.ts +66 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection.ts +369 -0
- package/packages/lsp-core/src/lsp/language-mappings.ts +173 -0
- package/packages/lsp-core/src/lsp/manager-lifecycle.test.ts +262 -0
- package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
- package/packages/lsp-core/src/lsp/manager.ts +495 -0
- package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
- package/packages/lsp-core/src/lsp/process-pipe-errors.test.ts +21 -0
- package/packages/lsp-core/src/lsp/process-signal-cleanup.ts +21 -0
- package/packages/lsp-core/src/lsp/process.ts +221 -0
- package/packages/lsp-core/src/lsp/server-definitions.ts +205 -0
- package/packages/lsp-core/src/lsp/server-install-state.ts +67 -0
- package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
- package/packages/lsp-core/src/lsp/server-installation.ts +218 -0
- package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
- package/packages/lsp-core/src/lsp/server-resolution.ts +117 -0
- package/packages/lsp-core/src/lsp/startup-failure.ts +1 -0
- package/packages/lsp-core/src/lsp/timer-provider.ts +13 -0
- package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
- package/packages/lsp-core/src/lsp/transport-request-timeout.test.ts +73 -0
- package/packages/lsp-core/src/lsp/transport.ts +339 -0
- package/packages/lsp-core/src/lsp/types.ts +134 -0
- package/packages/lsp-core/src/lsp/utils.test.ts +72 -0
- package/packages/lsp-core/src/lsp/utils.ts +40 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +218 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +194 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +150 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +392 -0
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +132 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
- package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
- package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
- package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
- package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
- package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
- package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
- package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
- package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
- package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
- package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
- package/packages/lsp-core/src/lsp/workspace-edit.ts +55 -0
- package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
- package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
- package/packages/lsp-core/src/mcp-protocol-pin.test.ts +97 -0
- package/packages/lsp-core/src/mcp.ts +122 -0
- package/packages/lsp-core/src/missing-dependency-result.test.ts +135 -0
- package/packages/lsp-core/src/missing-dependency-result.ts +79 -0
- package/packages/lsp-core/src/post-edit/file-location.ts +55 -0
- package/packages/lsp-core/src/post-edit/index.ts +3 -0
- package/packages/lsp-core/src/post-edit/not-installed-guidance.ts +36 -0
- package/packages/lsp-core/src/post-edit/not-installed.test.ts +224 -0
- package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +205 -0
- package/packages/lsp-core/src/request-context.test.ts +200 -0
- package/packages/lsp-core/src/request-context.ts +235 -0
- package/packages/lsp-core/src/tool-surface.test.ts +173 -0
- package/packages/lsp-core/src/tools/bun-directory-diagnostics.test.ts +113 -0
- package/packages/lsp-core/src/tools/bun-directory-diagnostics.ts +75 -0
- package/packages/lsp-core/src/tools/definitions.ts +156 -0
- package/packages/lsp-core/src/tools/diagnostics.ts +133 -0
- package/packages/lsp-core/src/tools/format.test.ts +56 -0
- package/packages/lsp-core/src/tools/format.ts +56 -0
- package/packages/lsp-core/src/tools/index.ts +11 -0
- package/packages/lsp-core/src/tools/install-decision.ts +39 -0
- package/packages/lsp-core/src/tools/navigation.ts +88 -0
- package/packages/lsp-core/src/tools/parameters.test.ts +51 -0
- package/packages/lsp-core/src/tools/parameters.ts +49 -0
- package/packages/lsp-core/src/tools/rename.ts +69 -0
- package/packages/lsp-core/src/tools/result.ts +5 -0
- package/packages/lsp-core/src/tools/runtime.ts +21 -0
- package/packages/lsp-core/src/tools/schema.ts +9 -0
- package/packages/lsp-core/src/tools/status.ts +28 -0
- package/packages/lsp-core/src/tools/symbols.ts +99 -0
- package/packages/lsp-core/src/tools/types.ts +116 -0
- package/packages/lsp-core/src/tools.ts +1 -0
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
- package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
- package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
- package/packages/shared-skills/skill-source-filter.mjs +6 -2
- package/packages/shared-skills/skills/ast-grep/README.md +1 -1
- package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
- package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
- package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
- package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
- package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
4
|
+
|
|
5
|
+
import { ControlledClock } from "./controlled-clock-test-support.js";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createWorkspaceEditTestHarness,
|
|
9
|
+
diagnostic,
|
|
10
|
+
readEvents,
|
|
11
|
+
waitForEventCount,
|
|
12
|
+
waitForEventCountBySubscription,
|
|
13
|
+
} from "./workspace-apply-edit-test-support.js";
|
|
14
|
+
|
|
15
|
+
const harness = createWorkspaceEditTestHarness();
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await harness.cleanup();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Drives one `diagnostics()` call whose ONLY exit is the freshness window closing: an advertised
|
|
23
|
+
* pull that comes back "method not found" with no publish behind it.
|
|
24
|
+
*
|
|
25
|
+
* That call arms exactly two timers in order - the pull request's own timeout, then the push
|
|
26
|
+
* fallback wait - and the second can only be armed once the first was cleared by the server's
|
|
27
|
+
* reply. Waiting on the second SCHEDULE (not on a delay value, which both share) is therefore the
|
|
28
|
+
* exact signal that the fallback, and not a request timeout, is what the advance closes. On a real
|
|
29
|
+
* clock the same case resolved from whichever of the two real deadlines a starved Windows shard
|
|
30
|
+
* happened to reach first (#8323).
|
|
31
|
+
*/
|
|
32
|
+
async function resolveThroughFreshnessWindow<T>(clock: ControlledClock, start: () => Promise<T>): Promise<T> {
|
|
33
|
+
const scheduledBefore = clock.scheduledDelays.length;
|
|
34
|
+
const pending = start();
|
|
35
|
+
await clock.waitForScheduled(scheduledBefore + 2);
|
|
36
|
+
clock.advanceBy(FRESHNESS_WINDOW_MS);
|
|
37
|
+
return pending;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const FRESHNESS_WINDOW_MS = 500;
|
|
41
|
+
|
|
42
|
+
describe("LspClient diagnostics freshness", () => {
|
|
43
|
+
it("#given a versionless publish that arrives after the current change #when no newer eligible publish arrives before quiescence #then diagnostics wait for that quiescence window and return the versionless payload", async () => {
|
|
44
|
+
const clock = new ControlledClock();
|
|
45
|
+
const context = await harness.makeClient(
|
|
46
|
+
{
|
|
47
|
+
publishDiagnostics: [
|
|
48
|
+
{
|
|
49
|
+
trigger: "didChange",
|
|
50
|
+
diagnostics: [diagnostic("post-generation-versionless")],
|
|
51
|
+
awaitClientDelivery: true,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{ diagnosticsFreshnessTimeoutMs: 80, versionlessPublishQuiescenceMs: 20, timerProvider: clock },
|
|
56
|
+
);
|
|
57
|
+
await context.client.openFile(context.source);
|
|
58
|
+
const versionlessDelivery = waitForEventCount(
|
|
59
|
+
context.events,
|
|
60
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
61
|
+
1,
|
|
62
|
+
);
|
|
63
|
+
writeFileSync(context.source, "const after = 1;\n", "utf-8");
|
|
64
|
+
await context.client.openFile(context.source);
|
|
65
|
+
expect(await versionlessDelivery).toHaveLength(1);
|
|
66
|
+
|
|
67
|
+
const pending = context.client.diagnostics(context.source);
|
|
68
|
+
await clock.waitForTimer(20);
|
|
69
|
+
expect(clock.scheduledDelays.at(-1)).toBe(20);
|
|
70
|
+
clock.advanceBy(20);
|
|
71
|
+
const result = await pending;
|
|
72
|
+
|
|
73
|
+
expect(result.items).toEqual([diagnostic("post-generation-versionless")]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("#given only a pre-generation versionless publish #when a newer local version asks for diagnostics #then the stale versionless publish is ignored and the request does not resolve clean", async () => {
|
|
77
|
+
const clock = new ControlledClock();
|
|
78
|
+
const context = await harness.makeClient(
|
|
79
|
+
{
|
|
80
|
+
publishDiagnostics: [
|
|
81
|
+
{
|
|
82
|
+
trigger: "didOpen",
|
|
83
|
+
diagnostics: [diagnostic("pre-generation-versionless")],
|
|
84
|
+
awaitClientDelivery: true,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{ diagnosticsFreshnessTimeoutMs: 300, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
89
|
+
);
|
|
90
|
+
await context.client.openFile(context.source);
|
|
91
|
+
await waitForEventCount(
|
|
92
|
+
context.events,
|
|
93
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
94
|
+
1,
|
|
95
|
+
);
|
|
96
|
+
const initial = context.client.diagnostics(context.source);
|
|
97
|
+
await clock.waitForTimer(5);
|
|
98
|
+
expect(clock.scheduledDelays.at(-1)).toBe(5);
|
|
99
|
+
clock.advanceBy(5);
|
|
100
|
+
expect((await initial).items).toEqual([diagnostic("pre-generation-versionless")]);
|
|
101
|
+
writeFileSync(context.source, "const after = 1;\n", "utf-8");
|
|
102
|
+
await context.client.openFile(context.source);
|
|
103
|
+
|
|
104
|
+
const pending = context.client.diagnostics(context.source);
|
|
105
|
+
await clock.waitForTimer(300);
|
|
106
|
+
expect(clock.scheduledDelays.at(-1)).toBe(300);
|
|
107
|
+
clock.advanceBy(300);
|
|
108
|
+
const result = await pending;
|
|
109
|
+
|
|
110
|
+
expect(result.items).toEqual([]);
|
|
111
|
+
expect(result.transientError?.kind).toBe("freshness_timeout");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("#given stale and future publish versions #when diagnostics target the current version #then neither stale nor future diagnostics satisfy the request", async () => {
|
|
115
|
+
const staleClock = new ControlledClock();
|
|
116
|
+
const stale = await harness.makeClient(
|
|
117
|
+
{
|
|
118
|
+
publishDiagnostics: [
|
|
119
|
+
{
|
|
120
|
+
trigger: "didChange",
|
|
121
|
+
version: 1,
|
|
122
|
+
diagnostics: [diagnostic("stale")],
|
|
123
|
+
awaitClientDelivery: true,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{ diagnosticsFreshnessTimeoutMs: 100, versionlessPublishQuiescenceMs: 5, timerProvider: staleClock },
|
|
128
|
+
);
|
|
129
|
+
await stale.client.openFile(stale.source);
|
|
130
|
+
const staleDelivery = waitForEventCount(
|
|
131
|
+
stale.events,
|
|
132
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
133
|
+
1,
|
|
134
|
+
);
|
|
135
|
+
writeFileSync(stale.source, "const stale = 1;\n", "utf-8");
|
|
136
|
+
await stale.client.openFile(stale.source);
|
|
137
|
+
expect(await staleDelivery).toHaveLength(1);
|
|
138
|
+
|
|
139
|
+
const stalePending = stale.client.diagnostics(stale.source);
|
|
140
|
+
await staleClock.waitForTimer(100);
|
|
141
|
+
staleClock.advanceBy(100);
|
|
142
|
+
const staleResult = await stalePending;
|
|
143
|
+
|
|
144
|
+
expect(staleResult.items).toEqual([]);
|
|
145
|
+
expect(staleResult.transientError?.kind).toBe("freshness_timeout");
|
|
146
|
+
|
|
147
|
+
await harness.cleanup();
|
|
148
|
+
|
|
149
|
+
const futureClock = new ControlledClock();
|
|
150
|
+
const future = await harness.makeClient(
|
|
151
|
+
{
|
|
152
|
+
publishDiagnostics: [
|
|
153
|
+
{
|
|
154
|
+
trigger: "didChange",
|
|
155
|
+
version: 3,
|
|
156
|
+
diagnostics: [diagnostic("future")],
|
|
157
|
+
awaitClientDelivery: true,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
{ diagnosticsFreshnessTimeoutMs: 100, versionlessPublishQuiescenceMs: 5, timerProvider: futureClock },
|
|
162
|
+
);
|
|
163
|
+
await future.client.openFile(future.source);
|
|
164
|
+
const futureDelivery = waitForEventCount(
|
|
165
|
+
future.events,
|
|
166
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
167
|
+
1,
|
|
168
|
+
);
|
|
169
|
+
writeFileSync(future.source, "const future = 1;\n", "utf-8");
|
|
170
|
+
await future.client.openFile(future.source);
|
|
171
|
+
expect(await futureDelivery).toHaveLength(1);
|
|
172
|
+
|
|
173
|
+
const futurePending = future.client.diagnostics(future.source);
|
|
174
|
+
await futureClock.waitForTimer(100);
|
|
175
|
+
futureClock.advanceBy(100);
|
|
176
|
+
const futureResult = await futurePending;
|
|
177
|
+
|
|
178
|
+
expect(futureResult.items).toEqual([]);
|
|
179
|
+
expect(futureResult.transientError?.kind).toBe("freshness_timeout");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("#given a pull response overtaken by a later local change #when the stale full report returns first #then diagnostics restart within the same request and resolve from the current version", async () => {
|
|
183
|
+
// Both pull reports answer this request, so no freshness deadline may fire: a controlled clock
|
|
184
|
+
// removes the 800ms wall-clock race that a starved shard otherwise wins (#8323).
|
|
185
|
+
const clock = new ControlledClock();
|
|
186
|
+
const context = await harness.makeClient(
|
|
187
|
+
{
|
|
188
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
189
|
+
diagnosticResponses: [
|
|
190
|
+
{
|
|
191
|
+
releaseOnDidChange: true,
|
|
192
|
+
report: { kind: "full", resultId: "v1", items: [diagnostic("pull-stale")] },
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
report: { kind: "full", resultId: "v2", items: [diagnostic("pull-fresh")] },
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
{ diagnosticsFreshnessTimeoutMs: 800, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
200
|
+
);
|
|
201
|
+
await context.client.openFile(context.source);
|
|
202
|
+
|
|
203
|
+
const pending = context.client.diagnostics(context.source);
|
|
204
|
+
await waitForEventCountBySubscription(
|
|
205
|
+
context.events,
|
|
206
|
+
(event) => event.type === "clientRequest" && event.method === "textDocument/diagnostic",
|
|
207
|
+
1,
|
|
208
|
+
);
|
|
209
|
+
writeFileSync(context.source, "const pull_fresh = 1;\n", "utf-8");
|
|
210
|
+
await context.client.openFile(context.source);
|
|
211
|
+
|
|
212
|
+
const result = await pending;
|
|
213
|
+
|
|
214
|
+
expect(result.items).toEqual([diagnostic("pull-fresh")]);
|
|
215
|
+
expect(
|
|
216
|
+
readEvents(context.events).filter(
|
|
217
|
+
(event) => event.type === "clientRequest" && event.method === "textDocument/diagnostic",
|
|
218
|
+
),
|
|
219
|
+
).toHaveLength(2);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("#given a full pull report followed by an unchanged report for the same version and resultId #when diagnostics repeat without a local change #then the cached full items are reused", async () => {
|
|
223
|
+
// Both requests are answered by the server, so a controlled clock keeps the freshness window
|
|
224
|
+
// from becoming a second deadline the shard can starve (#8323).
|
|
225
|
+
const clock = new ControlledClock();
|
|
226
|
+
const context = await harness.makeClient(
|
|
227
|
+
{
|
|
228
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
229
|
+
diagnosticResponses: [
|
|
230
|
+
{
|
|
231
|
+
report: { kind: "full", resultId: "same-version", items: [diagnostic("cached-full")] },
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
report: { kind: "unchanged", resultId: "same-version" },
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
239
|
+
);
|
|
240
|
+
await context.client.openFile(context.source);
|
|
241
|
+
|
|
242
|
+
const first = await context.client.diagnostics(context.source);
|
|
243
|
+
const second = await context.client.diagnostics(context.source);
|
|
244
|
+
|
|
245
|
+
expect(first.items).toEqual([diagnostic("cached-full")]);
|
|
246
|
+
expect(second.items).toEqual([diagnostic("cached-full")]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("#given a server that claims pull support but closes instead of answering #when diagnostics run #then the transport failure is not labeled clean", async () => {
|
|
250
|
+
// Deliberately left on the real clock: the client only notices the dead server when the
|
|
251
|
+
// in-flight pull request's own timeout aborts it, so a timer must actually fire here. Making
|
|
252
|
+
// the transport reject pending requests from the child's exit event is a separate change.
|
|
253
|
+
const context = await harness.makeClient(
|
|
254
|
+
{
|
|
255
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
256
|
+
diagnosticResponses: [{ action: "close" }],
|
|
257
|
+
},
|
|
258
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5 },
|
|
259
|
+
);
|
|
260
|
+
await context.client.openFile(context.source);
|
|
261
|
+
|
|
262
|
+
await expect(context.client.diagnostics(context.source)).rejects.toThrow(/exited|closed/i);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("#given an advertised pull method that is explicitly unsupported and a matching push publish #when diagnostics run #then the client falls back to push diagnostics", async () => {
|
|
266
|
+
// The exact-version publish wakes the push-fallback wait, so no deadline may fire; a controlled
|
|
267
|
+
// clock keeps the 500ms window from winning that race on a starved shard (#8323).
|
|
268
|
+
const clock = new ControlledClock();
|
|
269
|
+
const context = await harness.makeClient(
|
|
270
|
+
{
|
|
271
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
272
|
+
publishDiagnostics: [
|
|
273
|
+
{
|
|
274
|
+
trigger: "didOpen",
|
|
275
|
+
version: 1,
|
|
276
|
+
diagnostics: [diagnostic("push-fallback")],
|
|
277
|
+
awaitClientDelivery: true,
|
|
278
|
+
},
|
|
279
|
+
],
|
|
280
|
+
diagnosticResponses: [{ error: { code: -32601, message: "Method not found" } }],
|
|
281
|
+
},
|
|
282
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
const pending = context.client.diagnostics(context.source);
|
|
286
|
+
const [delivery] = await waitForEventCountBySubscription(
|
|
287
|
+
context.events,
|
|
288
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
289
|
+
1,
|
|
290
|
+
);
|
|
291
|
+
expect(delivery).toBeDefined();
|
|
292
|
+
const result = await pending;
|
|
293
|
+
|
|
294
|
+
expect(result.items).toEqual([diagnostic("push-fallback")]);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("#given a diagnostic pull request times out #when the fake server keeps it pending #then the client sends cancel for the LSP request id", async () => {
|
|
298
|
+
const context = await harness.makeClient(
|
|
299
|
+
{
|
|
300
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
301
|
+
diagnosticResponses: [{ action: "hang" }],
|
|
302
|
+
},
|
|
303
|
+
{ requestTimeoutMs: 30, diagnosticsFreshnessTimeoutMs: 50, versionlessPublishQuiescenceMs: 5 },
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const result = await context.client.diagnostics(context.source);
|
|
307
|
+
const [cancel] = await waitForEventCount(
|
|
308
|
+
context.events,
|
|
309
|
+
(event) => event.type === "clientNotification" && event.method === "$/cancelRequest",
|
|
310
|
+
1,
|
|
311
|
+
);
|
|
312
|
+
const events = readEvents(context.events);
|
|
313
|
+
const request = events.find((event) => event.type === "clientRequest" && event.method === "textDocument/diagnostic");
|
|
314
|
+
|
|
315
|
+
expect(result.transientError?.kind).toBe("freshness_timeout");
|
|
316
|
+
expect(cancel?.params).toEqual({ id: request?.id });
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("#given a server without pull support that never publishes diagnostics #when diagnostics run on a clean file #then the request resolves clean after the freshness window instead of reporting a timeout", async () => {
|
|
320
|
+
const clock = new ControlledClock();
|
|
321
|
+
const context = await harness.makeClient(
|
|
322
|
+
{},
|
|
323
|
+
{ diagnosticsFreshnessTimeoutMs: 60, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
const pending = context.client.diagnostics(context.source);
|
|
327
|
+
await clock.waitForTimer(60);
|
|
328
|
+
expect(clock.scheduledDelays.at(-1)).toBe(60);
|
|
329
|
+
clock.advanceBy(60);
|
|
330
|
+
const result = await pending;
|
|
331
|
+
|
|
332
|
+
expect(result.transientError).toBeUndefined();
|
|
333
|
+
expect(result.items).toEqual([]);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("#given a pull-supported server that cached diagnostics for an older document version #when the file changes and a later pull is rejected as unsupported without any publish #then the fallback resolves empty instead of returning the stale cached diagnostics", async () => {
|
|
337
|
+
const clock = new ControlledClock();
|
|
338
|
+
const context = await harness.makeClient(
|
|
339
|
+
{
|
|
340
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
341
|
+
diagnosticResponses: [
|
|
342
|
+
{ report: { kind: "full", resultId: "v1", items: [diagnostic("stale-pull")] } },
|
|
343
|
+
{ error: { code: -32601, message: "Method not found" } },
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
const first = await context.client.diagnostics(context.source);
|
|
350
|
+
expect(first.items).toEqual([diagnostic("stale-pull")]);
|
|
351
|
+
|
|
352
|
+
writeFileSync(context.source, "const changed = 1;\n");
|
|
353
|
+
await context.client.openFile(context.source);
|
|
354
|
+
|
|
355
|
+
const second = await resolveThroughFreshnessWindow(clock, () => context.client.diagnostics(context.source));
|
|
356
|
+
expect(second.transientError).toBeUndefined();
|
|
357
|
+
expect(second.items).toEqual([]);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("#given a pull-supported server with a current cached pull report #when a later pull is rejected as unsupported without any publish and the document is unchanged #then the fallback resolves with the current cached diagnostics", async () => {
|
|
361
|
+
const clock = new ControlledClock();
|
|
362
|
+
const context = await harness.makeClient(
|
|
363
|
+
{
|
|
364
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
365
|
+
diagnosticResponses: [
|
|
366
|
+
{ report: { kind: "full", resultId: "v1", items: [diagnostic("cached-full")] } },
|
|
367
|
+
{ error: { code: -32601, message: "Method not found" } },
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
const first = await context.client.diagnostics(context.source);
|
|
374
|
+
expect(first.items).toEqual([diagnostic("cached-full")]);
|
|
375
|
+
|
|
376
|
+
const second = await resolveThroughFreshnessWindow(clock, () => context.client.diagnostics(context.source));
|
|
377
|
+
expect(second.transientError).toBeUndefined();
|
|
378
|
+
expect(second.items).toEqual([diagnostic("cached-full")]);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// #9476: the server delays whichever message must come second, so the arrival order at the client
|
|
382
|
+
// is fixed by the fake server instead of scheduler luck. The controlled clock keeps the freshness
|
|
383
|
+
// window from firing: only the matching push publish may resolve the call.
|
|
384
|
+
it("#given the unsupported-pull error response arrives before the matching push publish #when diagnostics run #then the client resolves to that publish", async () => {
|
|
385
|
+
const clock = new ControlledClock();
|
|
386
|
+
const context = await harness.makeClient(
|
|
387
|
+
{
|
|
388
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
389
|
+
publishDiagnostics: [
|
|
390
|
+
{
|
|
391
|
+
trigger: "diagnosticRequest",
|
|
392
|
+
version: 1,
|
|
393
|
+
delayMs: 150,
|
|
394
|
+
diagnostics: [diagnostic("error-first")],
|
|
395
|
+
awaitClientDelivery: true,
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
diagnosticResponses: [{ error: { code: -32601, message: "Method not found" } }],
|
|
399
|
+
},
|
|
400
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
const result = await context.client.diagnostics(context.source);
|
|
404
|
+
|
|
405
|
+
expect(result.items).toEqual([diagnostic("error-first")]);
|
|
406
|
+
expect(result.transientError).toBeUndefined();
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("#given the matching push publish arrives before the unsupported-pull error response #when diagnostics run #then the client resolves to that publish", async () => {
|
|
410
|
+
const clock = new ControlledClock();
|
|
411
|
+
const context = await harness.makeClient(
|
|
412
|
+
{
|
|
413
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
414
|
+
publishDiagnostics: [
|
|
415
|
+
{
|
|
416
|
+
trigger: "diagnosticRequest",
|
|
417
|
+
version: 1,
|
|
418
|
+
diagnostics: [diagnostic("publish-first")],
|
|
419
|
+
awaitClientDelivery: true,
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
diagnosticResponses: [{ delayMs: 150, error: { code: -32601, message: "Method not found" } }],
|
|
423
|
+
},
|
|
424
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: clock },
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const result = await context.client.diagnostics(context.source);
|
|
428
|
+
|
|
429
|
+
expect(result.items).toEqual([diagnostic("publish-first")]);
|
|
430
|
+
expect(result.transientError).toBeUndefined();
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("#given the matching push publish arrived while the pull was in flight and the freshness window elapsed before the unsupported-pull error response #when diagnostics run #then the client resolves to that publish instead of clean", async () => {
|
|
434
|
+
const clock = new ControlledClock();
|
|
435
|
+
let skewMs = 0;
|
|
436
|
+
const skewedClock = {
|
|
437
|
+
now: () => clock.now() + skewMs,
|
|
438
|
+
setTimeout: clock.setTimeout,
|
|
439
|
+
clearTimeout: clock.clearTimeout,
|
|
440
|
+
};
|
|
441
|
+
const context = await harness.makeClient(
|
|
442
|
+
{
|
|
443
|
+
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
444
|
+
publishDiagnostics: [
|
|
445
|
+
{
|
|
446
|
+
trigger: "diagnosticRequest",
|
|
447
|
+
version: 1,
|
|
448
|
+
diagnostics: [diagnostic("publish-before-deadline")],
|
|
449
|
+
awaitClientDelivery: true,
|
|
450
|
+
},
|
|
451
|
+
],
|
|
452
|
+
diagnosticResponses: [{ delayMs: 150, error: { code: -32601, message: "Method not found" } }],
|
|
453
|
+
},
|
|
454
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5, timerProvider: skewedClock },
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const pending = context.client.diagnostics(context.source);
|
|
458
|
+
await waitForEventCountBySubscription(
|
|
459
|
+
context.events,
|
|
460
|
+
(event) => event.type === "clientResponse" && event.method === "workspace/configuration",
|
|
461
|
+
1,
|
|
462
|
+
);
|
|
463
|
+
// The publish is recorded; the freshness window now elapses before the error response lands.
|
|
464
|
+
skewMs = 500;
|
|
465
|
+
const result = await pending;
|
|
466
|
+
|
|
467
|
+
expect(result.items).toEqual([diagnostic("publish-before-deadline")]);
|
|
468
|
+
expect(result.transientError).toBeUndefined();
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
6
|
+
|
|
7
|
+
import { ControlledClock } from "./controlled-clock-test-support.js";
|
|
8
|
+
import { LspClient } from "./client.js";
|
|
9
|
+
import { LspRequestTimeoutError } from "./errors.js";
|
|
10
|
+
import type { ResolvedServer } from "./types.js";
|
|
11
|
+
|
|
12
|
+
const fakeServer: ResolvedServer = {
|
|
13
|
+
id: "pull-timeout-fake",
|
|
14
|
+
command: ["pull-timeout-fake"],
|
|
15
|
+
extensions: [".ts"],
|
|
16
|
+
priority: 0,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
class HangingPullClient extends LspClient {
|
|
20
|
+
readonly grantedPullTimeouts: number[] = [];
|
|
21
|
+
|
|
22
|
+
constructor(root: string, private readonly clock: ControlledClock) {
|
|
23
|
+
super(root, fakeServer, { diagnosticsFreshnessTimeoutMs: 50, versionlessPublishQuiescenceMs: 5, timerProvider: clock });
|
|
24
|
+
this.setDiagnosticPullSupported(true);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
protected override async sendNotification(): Promise<void> {}
|
|
28
|
+
|
|
29
|
+
protected override async sendRequest<T>(
|
|
30
|
+
method: string,
|
|
31
|
+
...args: [] | [unknown] | [unknown, { timeoutMs?: number; signal?: AbortSignal }]
|
|
32
|
+
): Promise<T> {
|
|
33
|
+
if (method !== "textDocument/diagnostic") {
|
|
34
|
+
throw new Error(`unexpected request in hanging-pull fixture: ${method}`);
|
|
35
|
+
}
|
|
36
|
+
const timeoutMs = args[1]?.timeoutMs ?? 0;
|
|
37
|
+
this.grantedPullTimeouts.push(timeoutMs);
|
|
38
|
+
this.clock.advanceBy(timeoutMs);
|
|
39
|
+
throw new LspRequestTimeoutError(method);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("LspClient diagnostics pull timeout conversion", () => {
|
|
44
|
+
let root: string | null = null;
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
if (root !== null) rmSync(root, { recursive: true, force: true });
|
|
48
|
+
root = null;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("#given a pull that exhausts the freshness window #when diagnostics settle #then the timeout converts to freshness_timeout instead of rejecting", async () => {
|
|
52
|
+
root = mkdtempSync(join(tmpdir(), "lsp-pull-timeout-"));
|
|
53
|
+
const source = join(root, "sample.ts");
|
|
54
|
+
writeFileSync(source, "const value = 1;\n", "utf-8");
|
|
55
|
+
const clock = new ControlledClock();
|
|
56
|
+
const client = new HangingPullClient(root, clock);
|
|
57
|
+
|
|
58
|
+
const result = await client.diagnostics(source);
|
|
59
|
+
|
|
60
|
+
expect(client.grantedPullTimeouts).toEqual([50]);
|
|
61
|
+
expect(result.items).toEqual([]);
|
|
62
|
+
expect(result.transientError?.kind).toBe("freshness_timeout");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { createStandaloneMcpRequestContext, runWithRequestContext } from "../request-context.js";
|
|
7
|
+
import { findWorkspaceRoot, resolveReadablePathInsideContext, resolvePathInsideContext } from "./client-wrapper.js";
|
|
8
|
+
import { LspInvalidPathError } from "./errors.js";
|
|
9
|
+
|
|
10
|
+
const tempDirectories: string[] = [];
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
for (const directory of tempDirectories.splice(0)) {
|
|
14
|
+
rmSync(directory, { recursive: true, force: true });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function tempRoot(prefix: string): string {
|
|
19
|
+
const root = mkdtempSync(join(tmpdir(), prefix));
|
|
20
|
+
tempDirectories.push(root);
|
|
21
|
+
return root;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("LSP read-only access outside request cwd", () => {
|
|
25
|
+
it("#given an absolute file outside cwd #when resolving a read path #then returns the canonical path", () => {
|
|
26
|
+
const root = tempRoot("lsp-outcwd-root-");
|
|
27
|
+
const outside = tempRoot("lsp-outcwd-outside-");
|
|
28
|
+
const outsideFile = join(outside, "probe.ts");
|
|
29
|
+
writeFileSync(outsideFile, "export const value = 1;\n");
|
|
30
|
+
|
|
31
|
+
const resolved = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
|
|
32
|
+
resolveReadablePathInsideContext(outsideFile),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(resolved).toBe(realpathSync(outsideFile));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("#given an outside file inside its own marked project #when inferring workspace #then uses that project root", () => {
|
|
39
|
+
const root = tempRoot("lsp-outcwd-marker-root-");
|
|
40
|
+
const outside = tempRoot("lsp-outcwd-marker-outside-");
|
|
41
|
+
mkdirSync(join(outside, ".git"), { recursive: true });
|
|
42
|
+
mkdirSync(join(outside, "src"), { recursive: true });
|
|
43
|
+
const outsideFile = join(outside, "src", "probe.ts");
|
|
44
|
+
writeFileSync(outsideFile, "export const value = 1;\n");
|
|
45
|
+
|
|
46
|
+
const workspace = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
|
|
47
|
+
findWorkspaceRoot(outsideFile),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(workspace).toBe(realpathSync(outside));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("#given an outside file without any marker #when inferring workspace #then falls back to its own directory", () => {
|
|
54
|
+
const root = tempRoot("lsp-outcwd-nomarker-root-");
|
|
55
|
+
const outside = tempRoot("lsp-outcwd-nomarker-outside-");
|
|
56
|
+
const outsideFile = join(outside, "probe.ts");
|
|
57
|
+
writeFileSync(outsideFile, "export const value = 1;\n");
|
|
58
|
+
|
|
59
|
+
const workspace = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
|
|
60
|
+
findWorkspaceRoot(outsideFile),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(workspace).toBe(realpathSync(outside));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("#given an outside file #when resolving a mutating path #then still rejects to keep writes confined", () => {
|
|
67
|
+
const root = tempRoot("lsp-outcwd-write-root-");
|
|
68
|
+
const outside = tempRoot("lsp-outcwd-write-outside-");
|
|
69
|
+
const outsideFile = join(outside, "probe.ts");
|
|
70
|
+
writeFileSync(outsideFile, "export const value = 1;\n");
|
|
71
|
+
|
|
72
|
+
expect(() =>
|
|
73
|
+
runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
|
|
74
|
+
resolvePathInsideContext(outsideFile),
|
|
75
|
+
),
|
|
76
|
+
).toThrow(LspInvalidPathError);
|
|
77
|
+
});
|
|
78
|
+
});
|