oh-my-opencode 5.0.0-beta.5 → 5.0.0-beta.50
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/.agents/command/publish.md +44 -16
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +1 -3
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +1 -1
- package/.agents/skills/pre-publish-review/SKILL.md +9 -12
- package/.agents/skills/publish/SKILL.md +44 -16
- package/.agents/skills/senpi-qa/SKILL.md +80 -0
- package/.agents/skills/senpi-qa/scripts/resolve-evidence-dir.mjs +65 -0
- package/.agents/skills/senpi-qa/scripts/resolve-evidence-dir.test.mjs +171 -0
- package/.agents/skills/tech-debt-audit/SKILL.md +6 -76
- package/.agents/skills/work-with-pr/SKILL.md +37 -23
- package/.opencode/command/publish.md +44 -16
- package/.opencode/skills/pre-publish-review/SKILL.md +9 -12
- package/.opencode/skills/work-with-pr/SKILL.md +37 -23
- package/README.ja.md +58 -46
- package/README.ko.md +60 -48
- package/README.md +58 -58
- package/README.ru.md +55 -46
- package/README.zh-cn.md +54 -46
- package/THIRD-PARTY-NOTICES.md +27 -99
- package/dist/agents/atlas/agent.d.ts +0 -1
- package/dist/agents/gpt-prompt-identity.d.ts +1 -1
- package/dist/agents/sisyphus/grok-4.d.ts +20 -0
- package/dist/agents/sisyphus/index.d.ts +2 -0
- package/dist/agents/sisyphus-agent-config.d.ts +6 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +15 -4
- package/dist/agents/types.d.ts +4 -2
- package/dist/cli/config-manager/parse-opencode-config-file.d.ts +2 -1
- package/dist/cli/doctor/checks/system-plugin.d.ts +4 -3
- package/dist/cli/fallback-lane-policy.d.ts +1 -0
- package/dist/cli/index.js +51536 -59608
- package/dist/cli/install-codex/install-codex-test-fixtures.d.ts +1 -1
- package/dist/cli/run/on-complete-hook.d.ts +2 -0
- package/dist/cli/runtime-commands.d.ts +1 -1
- package/dist/cli/worktree-sweep/classify.d.ts +16 -0
- package/dist/cli/worktree-sweep/format.d.ts +8 -0
- package/dist/cli/worktree-sweep/git.d.ts +19 -0
- package/dist/cli/worktree-sweep/index.d.ts +7 -0
- package/dist/cli/worktree-sweep/options.d.ts +2 -0
- package/dist/cli/worktree-sweep/parse-worktree-list.d.ts +8 -0
- package/dist/cli/worktree-sweep/sweep.d.ts +2 -0
- package/dist/cli/worktree-sweep/types.d.ts +65 -0
- package/dist/cli/worktree-sweep/worktree-sweep.d.ts +2 -0
- package/dist/cli-node/index.js +51554 -59603
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/background-task.d.ts +1 -0
- package/dist/config/schema/commands.d.ts +1 -1
- package/dist/config/schema/hooks.d.ts +1 -2
- package/dist/config/schema/oh-my-opencode-config.d.ts +5 -11
- package/dist/config/schema/ulw-execute.d.ts +5 -0
- package/dist/config/schema.d.ts +0 -1
- package/dist/config/validate.d.ts +2 -0
- package/dist/create-hooks.d.ts +3 -2
- package/dist/features/background-agent/compaction-aware-message-resolver.d.ts +1 -0
- package/dist/features/background-agent/constants.d.ts +0 -7
- package/dist/features/background-agent/error-classifier.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +2 -1
- package/dist/features/background-agent/parent-wake-dispatched-tracker.d.ts +0 -1
- package/dist/features/background-agent/parent-wake-notifier-types.d.ts +1 -1
- package/dist/features/background-agent/parent-wake-prompt-dispatch.d.ts +1 -1
- package/dist/features/background-agent/parent-wake-session-inspector.d.ts +1 -1
- package/dist/features/background-agent/subagent-spawn-limits.d.ts +8 -0
- package/dist/features/btw-side/btw-command-draft.d.ts +7 -0
- package/dist/features/btw-side/context-injector.d.ts +15 -0
- package/dist/features/btw-side/index.d.ts +8 -0
- package/dist/features/btw-side/metadata.d.ts +15 -0
- package/dist/features/btw-side/parent-context-budget.d.ts +9 -0
- package/dist/features/btw-side/server-session-registry.d.ts +8 -0
- package/dist/features/btw-side/tui-adoption-cache.d.ts +13 -0
- package/dist/features/btw-side/tui-adoption-guard.d.ts +5 -0
- package/dist/features/btw-side/tui-controller-types.d.ts +68 -0
- package/dist/features/btw-side/tui-controller.d.ts +19 -0
- package/dist/features/btw-side/tui-escape-return.d.ts +12 -0
- package/dist/features/btw-side/tui-keymap.d.ts +17 -0
- package/dist/features/btw-side/tui-parent-validator.d.ts +6 -0
- package/dist/features/btw-side/tui-picker-options.d.ts +20 -0
- package/dist/features/btw-side/tui-picker.d.ts +9 -0
- package/dist/features/btw-side/tui-prompt-queue.d.ts +8 -0
- package/dist/features/btw-side/tui-session-bridge.d.ts +11 -0
- package/dist/features/btw-side/tui-session-catalog.d.ts +35 -0
- package/dist/features/btw-side/tui-side-removal.d.ts +11 -0
- package/dist/features/btw-side/tui-side-start.d.ts +9 -0
- package/dist/features/btw-side/tui-wiring.d.ts +8 -0
- package/dist/features/builtin-commands/templates/ulw-execute.d.ts +1 -0
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/features/monitor/manager-internals.d.ts +1 -1
- package/dist/features/monitor/output-injector-types.d.ts +1 -1
- package/dist/features/opengateway-provider/index.d.ts +13 -0
- package/dist/features/task-toast-manager/manager.d.ts +0 -24
- package/dist/features/team-mode/tools/messaging-fallback-wake.d.ts +17 -0
- package/dist/features/team-mode/tools/messaging-live-delivery-recipient.d.ts +3 -0
- package/dist/features/team-mode/tools/messaging-runtime.d.ts +7 -0
- package/dist/hooks/anthropic-context-window-limit-recovery/message-storage-directory.d.ts +0 -3
- package/dist/hooks/anthropic-context-window-limit-recovery/state.d.ts +1 -0
- package/dist/hooks/anthropic-context-window-limit-recovery/storage/empty-messages.d.ts +0 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/tool-result-storage.d.ts +11 -0
- package/dist/hooks/atlas/atlas-hook.d.ts +1 -0
- package/dist/hooks/atlas/atlas-lifecycle-store.d.ts +50 -0
- package/dist/hooks/atlas/event-handler.d.ts +1 -0
- package/dist/hooks/atlas/final-wave-approval-gate.test-support.d.ts +50 -0
- package/dist/hooks/atlas/system-reminder-templates.d.ts +0 -1
- package/dist/hooks/atlas/tool-execute-before.d.ts +3 -0
- package/dist/hooks/atlas/types.d.ts +1 -0
- package/dist/hooks/claude-code-hooks/session-hook-state.d.ts +1 -0
- package/dist/hooks/claude-code-hooks/stop.d.ts +2 -0
- package/dist/hooks/claude-code-hooks/todo.d.ts +0 -1
- package/dist/hooks/claude-code-hooks/transcript.d.ts +2 -0
- package/dist/hooks/compaction-context-injector/validated-model.d.ts +2 -0
- package/dist/hooks/fsync-skip-warning/index.d.ts +4 -0
- package/dist/hooks/hashline-edit-diff-enhancer/hook.d.ts +1 -0
- package/dist/hooks/hashline-edit-diff-enhancer/pending-captures.d.ts +13 -0
- package/dist/hooks/index.d.ts +1 -2
- package/dist/hooks/keyword-detector/hook.d.ts +7 -0
- package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +0 -1
- package/dist/hooks/model-fallback/hook.d.ts +1 -1
- package/dist/hooks/prometheus-md-only/agent-resolution.d.ts +2 -2
- package/dist/hooks/runtime-fallback/chat-message-handler.d.ts +2 -0
- package/dist/hooks/runtime-fallback/retry-model-payload.d.ts +1 -0
- package/dist/hooks/runtime-fallback/runtime-model-settings.d.ts +6 -0
- package/dist/hooks/runtime-fallback/session-status-handler.d.ts +1 -1
- package/dist/hooks/runtime-fallback/types.d.ts +3 -1
- package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +1 -0
- package/dist/hooks/{start-work → ulw-execute}/context-info-builder.d.ts +1 -1
- package/dist/hooks/{start-work → ulw-execute}/index.d.ts +1 -1
- package/dist/hooks/ulw-execute/ulw-execute-hook.d.ts +23 -0
- package/dist/index.js +28955 -25346
- package/dist/mcp/index.d.ts +0 -4
- package/dist/mcp/types.d.ts +0 -1
- package/dist/oh-my-opencode.schema.json +21 -47
- package/dist/plugin/chat-message/types.d.ts +3 -3
- package/dist/plugin/chat-message/ulw-execute-message.d.ts +5 -0
- package/dist/plugin/event-session-lifecycle.d.ts +1 -0
- package/dist/plugin/hooks/create-core-hooks.d.ts +2 -2
- package/dist/plugin/hooks/create-session-hooks.d.ts +2 -3
- package/dist/plugin/hooks/create-transform-hooks.d.ts +2 -0
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin-dispose.d.ts +3 -0
- package/dist/shared/agent-tool-restrictions.d.ts +0 -1
- package/dist/shared/compaction-agent-config-checkpoint.d.ts +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/legacy-plugin-warning.d.ts +2 -1
- package/dist/shared/normalize-sdk-response.d.ts +1 -0
- package/dist/shared/omo-process-sweep.d.ts +2 -4
- package/dist/shared/plugin-entry-migrator.d.ts +4 -3
- package/dist/shared/plugin-entry-shape.d.ts +6 -0
- package/dist/shared/runtime-fallback-retry-marker.d.ts +16 -0
- package/dist/shared/shell-env.d.ts +1 -1
- package/dist/skills/ast-grep/AGENTS.md +51 -0
- package/dist/skills/ast-grep/SKILL.md +1 -1
- package/dist/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/dist/skills/coding-agent-sessions/SKILL.md +3 -2
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/dist/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/dist/skills/data-scientist/SKILL.md +99 -239
- package/dist/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/dist/skills/data-scientist/references/placement.md +74 -0
- package/dist/skills/data-scientist/references/polars-lane.md +95 -0
- package/dist/skills/data-scientist/references/uv-setup.md +1 -1
- package/dist/skills/data-scientist/references/visualization.md +64 -0
- package/dist/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/dist/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/dist/skills/debugging/SKILL.md +3 -1
- package/dist/skills/debugging/references/methodology/00-setup.md +12 -0
- package/dist/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/dist/skills/debugging/references/runtimes/go.md +15 -1
- package/dist/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/dist/skills/debugging/references/runtimes/node.md +25 -0
- package/dist/skills/debugging/references/runtimes/python.md +13 -0
- package/dist/skills/debugging/references/runtimes/rust.md +41 -0
- package/dist/skills/debugging/references/scripts/dap.mjs +267 -0
- package/dist/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/dist/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/dist/skills/debugging/references/tools/dap.md +103 -0
- package/dist/skills/debugging/references/tools/frida.md +193 -0
- package/dist/skills/frontend/SKILL.md +12 -8
- package/dist/skills/frontend/references/design/_INDEX.md +1 -0
- package/dist/skills/frontend/references/design/print-paged-media.md +76 -0
- package/dist/skills/frontend/references/design/stylegallery.md +80 -0
- package/dist/skills/frontend/references/designpowers/README.md +1 -1
- package/dist/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/dist/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/dist/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/dist/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/dist/skills/frontend/references/designpowers/routing.md +5 -5
- package/dist/skills/git-master/SKILL.md +1 -1
- package/dist/skills/init-deep/SKILL.md +14 -14
- package/dist/skills/lsp-setup/SKILL.md +1 -1
- package/dist/skills/programming/SKILL.md +1 -1
- package/dist/skills/refactor/SKILL.md +1 -1
- package/dist/skills/remove-ai-slops/SKILL.md +1 -1
- package/dist/skills/review-work/SKILL.md +100 -418
- package/dist/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
- package/dist/skills/ultimate-browsing/SKILL.md +26 -9
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/dist/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/dist/skills/{start-work → ulw-execute}/SKILL.md +17 -16
- package/dist/skills/ulw-plan/SKILL.md +7 -8
- package/dist/skills/ulw-plan/references/full-workflow.md +31 -7
- package/dist/skills/ulw-plan/references/intent-clear.md +2 -1
- package/dist/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/dist/skills/ulw-research/SKILL.md +8 -3
- package/dist/skills/visual-qa/AGENTS.md +58 -0
- package/dist/skills/visual-qa/SKILL.md +4 -3
- package/dist/tools/delegate-task/builtin-categories.d.ts +3 -1
- package/dist/tools/delegate-task/builtin-category-definition.d.ts +2 -1
- package/dist/tools/delegate-task/constants.d.ts +2 -2
- package/dist/tools/delegate-task/openai-categories.d.ts +7 -2
- package/dist/tools/delegate-task/sync-session-cleanup.d.ts +3 -0
- package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -0
- package/dist/tools/delegate-task/tool-description.d.ts +3 -1
- package/dist/tools/delegate-task/types.d.ts +4 -0
- package/dist/tools/session-manager/directory-filter.d.ts +2 -0
- package/dist/tui.d.ts +12 -0
- package/dist/tui.js +37066 -46704
- package/package.json +47 -41
- package/packages/git-bash-mcp/dist/cli.js +6 -1
- package/packages/git-bash-mcp/package.json +1 -1
- package/packages/lsp-core/src/index.ts +1 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +44 -0
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +57 -48
- 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 +163 -13
- package/packages/lsp-core/src/lsp/client-wrapper.ts +110 -23
- package/packages/lsp-core/src/lsp/client.ts +32 -3
- package/packages/lsp-core/src/lsp/connection.ts +16 -0
- package/packages/lsp-core/src/lsp/constants.ts +6 -0
- package/packages/lsp-core/src/lsp/controlled-clock-test-support.ts +61 -0
- package/packages/lsp-core/src/lsp/errors.ts +15 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +10 -3
- 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/json-rpc-connection.ts +11 -6
- 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 +138 -12
- package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
- package/packages/lsp-core/src/lsp/server-definitions.ts +29 -0
- package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
- package/packages/lsp-core/src/lsp/server-installation.ts +200 -27
- package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
- package/packages/lsp-core/src/lsp/server-resolution.ts +18 -5
- package/packages/lsp-core/src/lsp/timer-provider.ts +13 -0
- package/packages/lsp-core/src/lsp/transport-request-timeout.test.ts +73 -0
- package/packages/lsp-core/src/lsp/transport.ts +16 -2
- package/packages/lsp-core/src/lsp/types.ts +8 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +29 -1
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +84 -1
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +30 -11
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +20 -1
- package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
- package/packages/lsp-core/src/mcp.ts +3 -0
- package/packages/lsp-core/src/request-context.test.ts +29 -0
- package/packages/lsp-core/src/request-context.ts +1 -1
- package/packages/lsp-core/src/tool-surface.test.ts +13 -1
- package/packages/lsp-core/src/tools/definitions.ts +14 -0
- package/packages/lsp-core/src/tools/diagnostics.ts +3 -3
- 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 +1 -0
- package/packages/lsp-core/src/tools/navigation.ts +4 -2
- package/packages/lsp-core/src/tools/parameters.test.ts +51 -0
- package/packages/lsp-core/src/tools/rename.ts +4 -2
- package/packages/lsp-core/src/tools/symbols.ts +1 -1
- package/packages/lsp-core/src/tools/types.ts +10 -0
- package/packages/lsp-daemon/dist/cli.js +961 -483
- package/packages/lsp-daemon/dist/client.d.ts +10 -0
- package/packages/lsp-daemon/dist/client.js +976 -495
- package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-client.js +3 -0
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +6 -1
- package/packages/lsp-daemon/dist/ensure-daemon.js +10 -2
- package/packages/lsp-daemon/dist/index.js +881 -405
- package/packages/lsp-daemon/dist/proxy.js +3 -0
- package/packages/lsp-daemon/dist/version-reap.js +1 -1
- package/packages/lsp-daemon/package.json +1 -1
- package/packages/lsp-tools-mcp/dist/cli.js +820 -345
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +272 -138
- package/packages/lsp-tools-mcp/dist/mcp.js +845 -372
- package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
- package/packages/lsp-tools-mcp/dist/tools.js +775 -306
- package/packages/lsp-tools-mcp/package.json +1 -1
- package/packages/omo-codex/THIRD-PARTY-NOTICES.md +4 -21
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +4 -6
- package/packages/omo-codex/plugin/.mcp.json +0 -6
- package/packages/omo-codex/plugin/AGENTS.md +47 -0
- package/packages/omo-codex/plugin/README.md +6 -2
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +193 -148
- 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/bootstrap/src/hook.ts +1 -0
- package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +9 -0
- package/packages/omo-codex/plugin/components/comment-checker/biome.json +2 -2
- package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +2 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -5
- package/packages/omo-codex/plugin/components/comment-checker/src/apply-patch.ts +2 -8
- package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +1 -2
- package/packages/omo-codex/plugin/components/comment-checker/src/request-extractor.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +1 -0
- package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +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 +3 -4
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/biome.json +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/directive.md +2 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +36 -29
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +32 -26
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/types.d.ts +3 -0
- 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 +5 -5
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +32 -28
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/types.ts +3 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +137 -28
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +4 -2
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +30 -15
- package/packages/omo-codex/plugin/components/lsp/biome.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +999 -544
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +1 -1
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +5 -5
- package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +1 -5
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +6 -7
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +1 -2
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +11 -1
- package/packages/omo-codex/plugin/components/rules/AGENTS.md +12 -0
- package/packages/omo-codex/plugin/components/rules/README.md +2 -0
- package/packages/omo-codex/plugin/components/rules/biome.json +2 -2
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +123 -0
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +91 -68
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +7 -7
- package/packages/omo-codex/plugin/components/rules/src/config.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +15 -5
- package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +1 -4
- package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -9
- package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
- package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +17 -25
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
- package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
- package/packages/omo-codex/plugin/components/rules/test/dynamic-target-fingerprints.test.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/test/engine.test.ts +7 -4
- package/packages/omo-codex/plugin/components/rules/test/finder.test.ts +2 -3
- package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +39 -72
- package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +38 -3
- package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
- package/packages/omo-codex/plugin/components/rules/test/matcher.test.ts +2 -3
- package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +1 -1
- package/packages/omo-codex/plugin/components/rules/test/parser.test.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +29 -6
- package/packages/omo-codex/plugin/components/rules/test/rules-engine-consumption.test.ts +3 -6
- package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/test/sources.test.ts +2 -5
- package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +2 -17
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +5 -5
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +4 -10
- package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/telemetry/biome.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +2435 -700
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +2439 -705
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +5 -5
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +1 -4
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -14
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +1 -1
- package/packages/omo-codex/plugin/components/telemetry/test/diagnostics.test.ts +2 -5
- package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -4
- package/packages/omo-codex/plugin/components/ultrawork/README.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-low.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +490 -4
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -6
- package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +30 -14
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +4 -0
- package/packages/omo-codex/plugin/components/ultrawork/src/directive.ts +5 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +9 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
- package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +14 -8
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +12 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/AGENTS.md +4 -4
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/NOTICE +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/README.md +6 -6
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/biome.json +2 -2
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/directive.md +10 -10
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/dist/cli.js +16 -16
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +16 -0
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/package.json +12 -12
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/boulder-reader.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/cli.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/codex-hook.ts +4 -4
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/directive.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/index.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/types.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/boulder-reader.test.ts +3 -3
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/cli.test.ts +4 -11
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/codex-hook.test.ts +24 -22
- package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/biome.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +26 -13
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.d.ts +12 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +45 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +15 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.d.ts +8 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +113 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +40 -39
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +21 -8
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +1264 -429
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +28 -8
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +13 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +15 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +17 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +13 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +34 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +14 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +29 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.d.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.js +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.d.ts +12 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.js +104 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.d.ts +13 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.js +65 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +72 -117
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +6 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +189 -29
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +227 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +20 -6
- package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +75 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +17 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +6 -6
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +6 -4
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +32 -8
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-codex-validation.ts +81 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +31 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +128 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +38 -71
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +24 -8
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +14 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +8 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +35 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +26 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +19 -9
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +25 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +39 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +38 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-aggregate.ts +11 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-artifacts.ts +123 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-fields.ts +71 -15
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +6 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +92 -136
- package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +200 -28
- package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +239 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +36 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +19 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +107 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +132 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +147 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint.test.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-commands.test.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-complete-goals.test.ts +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +35 -8
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +38 -4
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-json-errors.test.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-scope-required.test.ts +144 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-status-next-actions.test.ts +185 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +8 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +37 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/cli-session.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +9 -4
- package/packages/omo-codex/plugin/components/ulw-loop/test/guided-recovery.test.ts +105 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -37
- package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io-cross-process.test.ts +106 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +36 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-aggregate-basics.test.ts +258 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-cap-and-dedupe.test.ts +22 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-fields-messages.test.ts +98 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-lazycodex-surface.test.ts +93 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-poisoning-cascades.test.ts +97 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +51 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-senpi-surface.test.ts +131 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-single-report.test.ts +241 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +58 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +423 -6
- package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +218 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +8 -5
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/surface.test.ts +74 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +13 -8
- package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +1 -0
- 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 +18 -0
- 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 +17 -0
- 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/model-catalog.json +16 -7
- package/packages/omo-codex/plugin/package-lock.json +676 -524
- package/packages/omo-codex/plugin/package.json +2 -3
- package/packages/omo-codex/plugin/scripts/AGENTS.md +39 -0
- package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +1 -2
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +0 -9
- package/packages/omo-codex/plugin/scripts/canonical-ultrawork-directive.mjs +17 -0
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +0 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +8 -4
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +18 -90
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +94 -55
- package/packages/omo-codex/plugin/shared/package.json +3 -4
- package/packages/omo-codex/plugin/shared/src/config-loader.ts +2 -102
- package/packages/omo-codex/plugin/shared/src/config-migration.ts +0 -1
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +41 -130
- package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +51 -0
- package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +3 -1
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +12 -8
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/omo-codex/plugin/skills/git-master/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +18 -16
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +4 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +5 -3
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +5 -3
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +114 -422
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +26 -9
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +26 -13
- package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +26 -28
- package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +30 -4
- package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +32 -8
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +12 -5
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +8 -5
- package/packages/omo-codex/plugin/test/AGENTS.md +47 -0
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +16 -51
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +2 -3
- package/packages/omo-codex/plugin/test/aggregate-mcp.test.mjs +2 -7
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +14 -4
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
- package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
- package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -29
- package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +0 -31
- package/packages/omo-codex/plugin/test/canonical-ultrawork-directive.test.mjs +53 -0
- package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -51
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +88 -2
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +5 -6
- package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -3
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +35 -35
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +107 -15
- package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +168 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +54 -24
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +18 -119
- package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
- package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
- package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
- package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
- package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
- package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +5 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
- package/packages/omo-codex/scripts/AGENTS.md +36 -0
- package/packages/omo-codex/scripts/check-model-catalog-parity.mjs +42 -0
- package/packages/omo-codex/scripts/install-cache-copy.test.mjs +27 -1
- package/packages/omo-codex/scripts/install-config-autonomous-features.test.mjs +1 -1
- package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +2 -1
- package/packages/omo-codex/scripts/install-config-git-bash.test.mjs +0 -23
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +5 -5
- package/packages/omo-codex/scripts/install-config.test.mjs +15 -17
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +3028 -1392
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +3 -4
- package/packages/omo-codex/scripts/install-git-bash-mcp-env.test.mjs +1 -25
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +7 -2
- package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +0 -36
- package/packages/omo-codex/scripts/install-packaged-local.test.mjs +1 -6
- package/packages/{omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md → prompts-core/prompts/ultrawork/codex.md} +26 -20
- package/packages/shared-skills/package.json +7 -1
- package/packages/shared-skills/skill-source-filter.d.ts +16 -0
- package/packages/shared-skills/skill-source-filter.mjs +44 -0
- package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
- package/packages/shared-skills/skills/ast-grep/SKILL.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
- package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
- package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +3 -1
- package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
- package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +12 -8
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/shared-skills/skills/git-master/SKILL.md +1 -1
- package/packages/shared-skills/skills/init-deep/SKILL.md +14 -14
- package/packages/shared-skills/skills/lsp-setup/SKILL.md +1 -1
- package/packages/shared-skills/skills/programming/SKILL.md +1 -1
- package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/shared-skills/skills/review-work/SKILL.md +100 -418
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +26 -9
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +17 -16
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +7 -8
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/shared-skills/skills/ulw-research/SKILL.md +8 -3
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +4 -3
- package/postinstall.mjs +2 -0
- package/script/qa/web-terminal-visual-qa.mjs +2 -0
- package/script/qa/xterm-live-terminal.mjs +18 -2
- package/dist/config/schema/codegraph.d.ts +0 -12
- package/dist/config/schema/start-work.d.ts +0 -5
- package/dist/features/builtin-commands/templates/start-work.d.ts +0 -1
- package/dist/features/builtin-skills/index.d.ts +0 -1
- package/dist/features/builtin-skills/skill-file-loader.d.ts +0 -1
- package/dist/features/builtin-skills/skills/agent-browser-skill.d.ts +0 -1
- package/dist/features/builtin-skills/skills/agent-browser-template.d.ts +0 -1
- package/dist/features/builtin-skills/skills/debugging.d.ts +0 -1
- package/dist/features/builtin-skills/skills/dev-browser.d.ts +0 -1
- package/dist/features/builtin-skills/skills/frontend.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/commit-atomic-planning.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/commit-context-analysis.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/commit-execution-verification.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/commit-workflow.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/history-search-workflow.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/overview.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/quick-reference.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-sections/rebase-workflow.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master-skill-metadata.d.ts +0 -1
- package/dist/features/builtin-skills/skills/git-master.d.ts +0 -1
- package/dist/features/builtin-skills/skills/index.d.ts +0 -1
- package/dist/features/builtin-skills/skills/init-deep.d.ts +0 -1
- package/dist/features/builtin-skills/skills/playwright-cli.d.ts +0 -1
- package/dist/features/builtin-skills/skills/playwright-mcp-skill.d.ts +0 -1
- package/dist/features/builtin-skills/skills/playwright.d.ts +0 -1
- package/dist/features/builtin-skills/skills/remove-ai-slops.d.ts +0 -1
- package/dist/features/builtin-skills/skills/review-work.d.ts +0 -1
- package/dist/features/builtin-skills/skills/security-research.d.ts +0 -1
- package/dist/features/builtin-skills/skills/security-review.d.ts +0 -1
- package/dist/features/builtin-skills/skills/team-mode.d.ts +0 -1
- package/dist/features/builtin-skills/skills/visual-qa.d.ts +0 -1
- package/dist/features/builtin-skills/skills.d.ts +0 -1
- package/dist/features/builtin-skills/types.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/agent-loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/command-loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/discovery-core.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/discovery-paths.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/discovery.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/hook-loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/index.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/install-path-resolver.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/installed-plugin-database.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/loaded-plugin.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/mcp-server-loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/plugin-key.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/plugin-manifest.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/plugin-path-resolver.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/plugin-settings.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/scope-filter.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/skill-loader.d.ts +0 -1
- package/dist/features/claude-code-plugin-loader/types.d.ts +0 -1
- package/dist/hooks/codegraph-bootstrap/command-runner.d.ts +0 -17
- package/dist/hooks/codegraph-bootstrap/hook.d.ts +0 -35
- package/dist/hooks/codegraph-bootstrap/index.d.ts +0 -1
- package/dist/hooks/codegraph-bootstrap/project-root.d.ts +0 -1
- package/dist/hooks/codegraph-bootstrap/status.d.ts +0 -11
- package/dist/hooks/ralph-loop/completion-promise-detector-test-input.d.ts +0 -11
- package/dist/hooks/ralph-loop/loop-session-recovery.d.ts +0 -7
- package/dist/hooks/start-work/start-work-hook.d.ts +0 -23
- package/dist/mcp/codegraph.d.ts +0 -16
- package/dist/plugin/chat-message/start-work-message.d.ts +0 -5
- package/dist/shared/prompt-async-gate/message-inspection-error.d.ts +0 -1
- package/dist/shared/prompt-async-gate/pending-tool-turn.d.ts +0 -1
- package/dist/shared/prompt-async-gate/prompt-message-state.d.ts +0 -1
- package/dist/shared/prompt-async-gate/queue.d.ts +0 -1
- package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +0 -1
- package/dist/shared/prompt-async-gate/reservations.d.ts +0 -1
- package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +0 -1
- package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +0 -1
- package/dist/shared/prompt-async-gate/timing.d.ts +0 -1
- package/dist/shared/prompt-async-gate/types.d.ts +0 -1
- package/dist/skills/data-scientist/references/common-scenarios.md +0 -176
- package/dist/skills/data-scientist/references/execution-templates.md +0 -197
- package/dist/skills/data-scientist/references/integration-patterns.md +0 -153
- package/dist/skills/data-scientist/references/performance-benchmarks.md +0 -37
- package/dist/tools/call-omo-agent/background-agent-executor.d.ts +0 -5
- package/dist/tools/call-omo-agent/message-storage-directory.d.ts +0 -1
- package/dist/tools/delegate-task/anthropic-categories.d.ts +0 -2
- package/dist/tools/delegate-task/model-string-parser.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/process-signal-cleanup.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/missing-dependency-result.d.ts +0 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +0 -58
- package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +0 -2951
- package/packages/omo-codex/plugin/components/codegraph/NOTICE +0 -16
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +0 -12136
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9734
- package/packages/omo-codex/plugin/components/codegraph/package.json +0 -33
- package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +0 -79
- package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +0 -33
- package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +0 -25
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +0 -131
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +0 -258
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +0 -309
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +0 -80
- package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +0 -34
- package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +0 -263
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +0 -106
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +0 -145
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +0 -21
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +0 -139
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +0 -15
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +0 -32
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +0 -109
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +0 -148
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +0 -175
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +0 -81
- package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +0 -34
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +0 -112
- package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +0 -26
- package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +0 -160
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +0 -50
- package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +0 -320
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +0 -172
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +0 -91
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +0 -100
- package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +0 -76
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +0 -133
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +0 -245
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +0 -69
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +0 -43
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +0 -147
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +0 -175
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +0 -385
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +0 -206
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +0 -58
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +0 -104
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +0 -65
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +0 -106
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +0 -116
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +0 -258
- package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +0 -56
- package/packages/omo-codex/plugin/components/codegraph/tsconfig.build.json +0 -13
- package/packages/omo-codex/plugin/components/codegraph/tsconfig.json +0 -25
- package/packages/omo-codex/plugin/components/start-work-continuation/LICENSE +0 -21
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +0 -471
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +0 -18
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +0 -17
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/editor.mjs +0 -125
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/jsonc.mjs +0 -43
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/scaffold.mjs +0 -29
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +0 -121
- package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
- package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
- package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
- package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
- package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
- package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +0 -76
- package/packages/omo-codex/plugin/test/migrate-omo-sot.test.mjs +0 -179
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
- package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
- package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
- package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
- package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
- package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
- /package/dist/hooks/{start-work → ulw-execute}/context-info-formatters.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/explicit-plan-context.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/notepad-scaffold.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/parse-user-request.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/plan-discovery-context.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/plan-selection.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/session-plan-affinity.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/work-initializer.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/worktree-block.d.ts +0 -0
- /package/dist/hooks/{start-work → ulw-execute}/worktree-detector.d.ts +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/.gitattributes +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/CHANGELOG.md +0 -0
- /package/packages/omo-codex/plugin/components/{codegraph → ulw-execute-continuation}/LICENSE +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/plan-checklist.ts +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-completed.json +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-mixed-platforms.json +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-single-codex-work.json +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-all-done.md +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-scaffold.md +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-nested-checkboxes.md +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-unchecked.md +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.build.json +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.json +0 -0
- /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/vitest.config.ts +0 -0
|
@@ -8,11 +8,13 @@ import { argv, execPath as execPath2, stderr } from "node:process";
|
|
|
8
8
|
import { stdin as processStdin } from "node:process";
|
|
9
9
|
|
|
10
10
|
// src/codex-hook.ts
|
|
11
|
-
import { readFileSync as readFileSync9, realpathSync as
|
|
11
|
+
import { readFileSync as readFileSync9, realpathSync as realpathSync7 } from "node:fs";
|
|
12
12
|
import { homedir as homedir3 } from "node:os";
|
|
13
13
|
import { join as join11, resolve as resolve11 } from "node:path";
|
|
14
14
|
|
|
15
15
|
// ../../../../lsp-daemon/dist/client.js
|
|
16
|
+
import { statSync as statSync5 } from "node:fs";
|
|
17
|
+
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
16
18
|
import { connect } from "node:net";
|
|
17
19
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
20
|
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
@@ -42,8 +44,8 @@ import * as path from "node:path";
|
|
|
42
44
|
import { fileURLToPath } from "node:url";
|
|
43
45
|
import { statSync as statSync2 } from "node:fs";
|
|
44
46
|
import { isAbsolute as isAbsolute2 } from "node:path";
|
|
45
|
-
import { existsSync as
|
|
46
|
-
import { dirname as
|
|
47
|
+
import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
|
|
48
|
+
import { basename as basename3, dirname as dirname10, join as join5, resolve as resolve8 } from "node:path";
|
|
47
49
|
import { basename as basename2, extname } from "node:path";
|
|
48
50
|
import { resolve as resolve6 } from "node:path";
|
|
49
51
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
@@ -62,32 +64,32 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
62
64
|
import { dirname as dirname5, relative as relative4, resolve as resolve4 } from "node:path";
|
|
63
65
|
import { existsSync as existsSync6, lstatSync as lstatSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
64
66
|
import { dirname as dirname6, resolve as resolve5 } from "node:path";
|
|
65
|
-
import { existsSync as existsSync7,
|
|
66
|
-
import { dirname as dirname7 } from "node:path";
|
|
67
|
-
import { existsSync as existsSync8, readFileSync as
|
|
68
|
-
import {
|
|
69
|
-
import {
|
|
70
|
-
import { existsSync as
|
|
71
|
-
import { join as
|
|
67
|
+
import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
68
|
+
import { dirname as dirname7, join as join3 } from "node:path";
|
|
69
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
70
|
+
import { dirname as dirname8 } from "node:path";
|
|
71
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
|
|
72
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
73
|
+
import { delimiter as delimiter3, dirname as dirname9, isAbsolute as isAbsolute5, join as join4, resolve as resolve7 } from "node:path";
|
|
74
|
+
import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
|
|
75
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
72
76
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
73
77
|
import { lstatSync as lstatSync6, readdirSync as readdirSync4 } from "node:fs";
|
|
74
|
-
import { join as
|
|
75
|
-
import {
|
|
76
|
-
import { isAbsolute as isAbsolute5 } from "node:path";
|
|
78
|
+
import { join as join7 } from "node:path";
|
|
79
|
+
import { readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
77
80
|
|
|
78
81
|
class LspRequestContextParseError extends Error {
|
|
79
|
-
code;
|
|
80
|
-
name = "LspRequestContextParseError";
|
|
81
82
|
constructor(code, message) {
|
|
82
83
|
super(message);
|
|
83
84
|
this.code = code;
|
|
85
|
+
this.name = "LspRequestContextParseError";
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
class LspRequestContextUnavailableError extends Error {
|
|
88
|
-
name = "LspRequestContextUnavailableError";
|
|
89
90
|
constructor() {
|
|
90
91
|
super("LSP request context is required. Standalone MCP startup must install one with runWithRequestContext(createStandaloneMcpRequestContext()).");
|
|
92
|
+
this.name = "LspRequestContextUnavailableError";
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
var storage = new AsyncLocalStorage;
|
|
@@ -113,18 +115,18 @@ function parseLspRequestContext(value) {
|
|
|
113
115
|
const installDecisionsPath = stringField(value, "installDecisionsPath");
|
|
114
116
|
const capabilities = capabilitiesField(value["capabilities"]);
|
|
115
117
|
const canonical = canonicalCwd(cwd);
|
|
116
|
-
for (const
|
|
117
|
-
requireAbsolutePath(
|
|
118
|
-
const projectPath = canonicalizeExistingOrNearestAncestor(
|
|
118
|
+
for (const path of projectConfigPaths) {
|
|
119
|
+
requireAbsolutePath(path, "projectConfigPaths");
|
|
120
|
+
const projectPath = canonicalizeExistingOrNearestAncestor(path);
|
|
119
121
|
if (!isPathInside(canonical, projectPath)) {
|
|
120
|
-
throw new LspRequestContextParseError("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${
|
|
122
|
+
throw new LspRequestContextParseError("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${path}`);
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
requireAbsolutePath(userConfigPath, "userConfigPath");
|
|
124
126
|
requireAbsolutePath(installDecisionsPath, "installDecisionsPath");
|
|
125
127
|
return {
|
|
126
128
|
cwd: canonical,
|
|
127
|
-
projectConfigPaths: projectConfigPaths.map((
|
|
129
|
+
projectConfigPaths: projectConfigPaths.map((path) => canonicalizeExistingOrNearestAncestor(path)),
|
|
128
130
|
userConfigPath,
|
|
129
131
|
installDecisionsPath,
|
|
130
132
|
capabilities
|
|
@@ -137,8 +139,8 @@ function canonicalCwd(cwd) {
|
|
|
137
139
|
}
|
|
138
140
|
return realpathSync(resolved);
|
|
139
141
|
}
|
|
140
|
-
function canonicalizeExistingOrNearestAncestor(
|
|
141
|
-
let current = resolve(
|
|
142
|
+
function canonicalizeExistingOrNearestAncestor(path) {
|
|
143
|
+
let current = resolve(path);
|
|
142
144
|
const suffix = [];
|
|
143
145
|
while (true) {
|
|
144
146
|
try {
|
|
@@ -180,9 +182,9 @@ function stringArrayField(value, field) {
|
|
|
180
182
|
}
|
|
181
183
|
return fieldValue;
|
|
182
184
|
}
|
|
183
|
-
function requireAbsolutePath(
|
|
184
|
-
if (!isAbsolute(
|
|
185
|
-
throw new LspRequestContextParseError("relative_path", `LSP request context.${field} must be absolute: ${
|
|
185
|
+
function requireAbsolutePath(path, field) {
|
|
186
|
+
if (!isAbsolute(path)) {
|
|
187
|
+
throw new LspRequestContextParseError("relative_path", `LSP request context.${field} must be absolute: ${path}`);
|
|
186
188
|
}
|
|
187
189
|
}
|
|
188
190
|
function isPathInside(parent, child) {
|
|
@@ -214,7 +216,6 @@ function isPlainRecord(value) {
|
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
class DaemonRequestError extends Error {
|
|
217
|
-
requestWritten;
|
|
218
219
|
constructor(message, requestWritten) {
|
|
219
220
|
super(message);
|
|
220
221
|
this.name = "DaemonRequestError";
|
|
@@ -237,7 +238,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
|
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
class DaemonRequestTimedOutError extends DaemonRequestError {
|
|
240
|
-
timeoutMs;
|
|
241
241
|
constructor(requestWritten, timeoutMs) {
|
|
242
242
|
super("daemon request timed out", requestWritten);
|
|
243
243
|
this.name = "DaemonRequestTimedOutError";
|
|
@@ -314,20 +314,18 @@ var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
|
314
314
|
var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
315
315
|
|
|
316
316
|
class InvalidRuntimeOverrideError extends Error {
|
|
317
|
-
code = "invalid_runtime_override";
|
|
318
|
-
reason;
|
|
319
317
|
constructor(reason, message) {
|
|
320
318
|
super(message);
|
|
319
|
+
this.code = "invalid_runtime_override";
|
|
321
320
|
this.name = "InvalidRuntimeOverrideError";
|
|
322
321
|
this.reason = reason;
|
|
323
322
|
}
|
|
324
323
|
}
|
|
325
324
|
|
|
326
325
|
class InvalidDaemonVersionError extends Error {
|
|
327
|
-
code = "invalid_daemon_version";
|
|
328
|
-
version;
|
|
329
326
|
constructor(version) {
|
|
330
327
|
super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
|
|
328
|
+
this.code = "invalid_daemon_version";
|
|
331
329
|
this.name = "InvalidDaemonVersionError";
|
|
332
330
|
this.version = version;
|
|
333
331
|
}
|
|
@@ -371,10 +369,9 @@ var requireFromHere = createRequire(import.meta.url);
|
|
|
371
369
|
var MAX_SOCKET_PATH_LENGTH = 100;
|
|
372
370
|
|
|
373
371
|
class InvalidDaemonDirectoryError extends Error {
|
|
374
|
-
code = "invalid_daemon_directory";
|
|
375
|
-
directory;
|
|
376
372
|
constructor(directory) {
|
|
377
373
|
super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
|
|
374
|
+
this.code = "invalid_daemon_directory";
|
|
378
375
|
this.name = "InvalidDaemonDirectoryError";
|
|
379
376
|
this.directory = directory;
|
|
380
377
|
}
|
|
@@ -524,7 +521,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
524
521
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
525
522
|
}
|
|
526
523
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
527
|
-
return new Promise((
|
|
524
|
+
return new Promise((resolve) => {
|
|
528
525
|
const socket = new Socket;
|
|
529
526
|
let settled = false;
|
|
530
527
|
let timer;
|
|
@@ -536,7 +533,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
536
533
|
clearTimeout(timer);
|
|
537
534
|
signal?.removeEventListener("abort", onAbort);
|
|
538
535
|
socket.destroy();
|
|
539
|
-
|
|
536
|
+
resolve(value);
|
|
540
537
|
};
|
|
541
538
|
const onAbort = () => finish(null);
|
|
542
539
|
const decoder = createLineDecoder((message) => {
|
|
@@ -559,13 +556,17 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
559
556
|
socket.connect(paths.socket);
|
|
560
557
|
});
|
|
561
558
|
}
|
|
562
|
-
function spawnDaemonProcess(paths) {
|
|
559
|
+
function spawnDaemonProcess(paths, deps = {}) {
|
|
563
560
|
mkdirSync2(dirname3(paths.log), { recursive: true });
|
|
564
561
|
const logFd = openSync2(paths.log, "a");
|
|
565
562
|
try {
|
|
566
|
-
const
|
|
563
|
+
const spawnDaemonChild = deps.spawn ?? spawn;
|
|
564
|
+
const executable = deps.resolveExecutable?.() ?? resolveDaemonNodeExecutable();
|
|
565
|
+
const child = spawnDaemonChild(executable, [paths.cliPath, "daemon"], {
|
|
567
566
|
detached: true,
|
|
568
|
-
stdio: ["ignore", logFd, logFd]
|
|
567
|
+
stdio: ["ignore", logFd, logFd],
|
|
568
|
+
windowsHide: true,
|
|
569
|
+
env: { ...process.env, BUN_BE_BUN: "1" }
|
|
569
570
|
});
|
|
570
571
|
child.once("spawn", () => closeSync2(logFd));
|
|
571
572
|
child.once("error", (error) => {
|
|
@@ -595,7 +596,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
595
596
|
};
|
|
596
597
|
}
|
|
597
598
|
function sleepWithSignal(ms, signal) {
|
|
598
|
-
return new Promise((
|
|
599
|
+
return new Promise((resolve) => {
|
|
599
600
|
let settled = false;
|
|
600
601
|
const finish = () => {
|
|
601
602
|
if (settled)
|
|
@@ -603,7 +604,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
603
604
|
settled = true;
|
|
604
605
|
clearTimeout(timer);
|
|
605
606
|
signal?.removeEventListener("abort", finish);
|
|
606
|
-
|
|
607
|
+
resolve();
|
|
607
608
|
};
|
|
608
609
|
const timer = setTimeout(finish, ms);
|
|
609
610
|
if (signal?.aborted) {
|
|
@@ -618,7 +619,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
618
619
|
return promise;
|
|
619
620
|
if (signal.aborted)
|
|
620
621
|
return Promise.reject(abortError(signal));
|
|
621
|
-
return new Promise((
|
|
622
|
+
return new Promise((resolve, reject) => {
|
|
622
623
|
let settled = false;
|
|
623
624
|
const finish = (run) => {
|
|
624
625
|
if (settled)
|
|
@@ -629,7 +630,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
629
630
|
};
|
|
630
631
|
const onAbort = () => finish(() => reject(abortError(signal)));
|
|
631
632
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
632
|
-
promise.then((value) => finish(() =>
|
|
633
|
+
promise.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
633
634
|
});
|
|
634
635
|
}
|
|
635
636
|
function throwIfAborted(signal) {
|
|
@@ -658,18 +659,18 @@ function parsePingResponse(message) {
|
|
|
658
659
|
return null;
|
|
659
660
|
if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint))
|
|
660
661
|
return null;
|
|
661
|
-
const
|
|
662
|
+
const path = Reflect.get(endpoint, "path");
|
|
662
663
|
const kind = Reflect.get(endpoint, "kind");
|
|
663
|
-
if (typeof
|
|
664
|
+
if (typeof path !== "string")
|
|
664
665
|
return null;
|
|
665
666
|
if (kind === "windows")
|
|
666
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
667
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
667
668
|
if (kind === "missing")
|
|
668
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
669
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
669
670
|
const dev = Reflect.get(endpoint, "dev");
|
|
670
671
|
const ino = Reflect.get(endpoint, "ino");
|
|
671
672
|
if (kind === "unix" && typeof dev === "number" && typeof ino === "number") {
|
|
672
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
673
|
+
return { pid, nonce, startedAt, endpoint: { kind, path, dev, ino } };
|
|
673
674
|
}
|
|
674
675
|
return null;
|
|
675
676
|
}
|
|
@@ -686,22 +687,15 @@ function effectiveExtension(filePath) {
|
|
|
686
687
|
}
|
|
687
688
|
|
|
688
689
|
class LspConnectionClosedError extends Error {
|
|
689
|
-
serverId;
|
|
690
|
-
root;
|
|
691
|
-
name = "LspConnectionClosedError";
|
|
692
690
|
constructor(serverId, root, message) {
|
|
693
691
|
super(message ?? `LSP connection closed for ${serverId} at ${root}`);
|
|
694
692
|
this.serverId = serverId;
|
|
695
693
|
this.root = root;
|
|
694
|
+
this.name = "LspConnectionClosedError";
|
|
696
695
|
}
|
|
697
696
|
}
|
|
698
697
|
|
|
699
698
|
class LspProcessExitedError extends Error {
|
|
700
|
-
serverId;
|
|
701
|
-
root;
|
|
702
|
-
exitCode;
|
|
703
|
-
stderrTail;
|
|
704
|
-
name = "LspProcessExitedError";
|
|
705
699
|
constructor(serverId, root, exitCode, stderrTail) {
|
|
706
700
|
const stderrSuffix = stderrTail ? `
|
|
707
701
|
stderr tail: ${stderrTail}` : "";
|
|
@@ -710,46 +704,59 @@ stderr tail: ${stderrTail}` : "";
|
|
|
710
704
|
this.root = root;
|
|
711
705
|
this.exitCode = exitCode;
|
|
712
706
|
this.stderrTail = stderrTail;
|
|
707
|
+
this.name = "LspProcessExitedError";
|
|
713
708
|
}
|
|
714
709
|
}
|
|
715
710
|
|
|
716
711
|
class LspRequestTimeoutError extends Error {
|
|
717
|
-
method;
|
|
718
|
-
stderrTail;
|
|
719
|
-
name = "LspRequestTimeoutError";
|
|
720
712
|
constructor(method, stderrTail) {
|
|
721
713
|
const stderrSuffix = stderrTail ? `
|
|
722
714
|
recent stderr: ${stderrTail}` : "";
|
|
723
715
|
super(`LSP request timeout (method: ${method})${stderrSuffix}`);
|
|
724
716
|
this.method = method;
|
|
725
717
|
this.stderrTail = stderrTail;
|
|
718
|
+
this.name = "LspRequestTimeoutError";
|
|
726
719
|
}
|
|
727
720
|
}
|
|
728
721
|
|
|
729
722
|
class LspInvalidPathError extends Error {
|
|
730
|
-
|
|
723
|
+
constructor() {
|
|
724
|
+
super(...arguments);
|
|
725
|
+
this.name = "LspInvalidPathError";
|
|
726
|
+
}
|
|
731
727
|
}
|
|
732
728
|
|
|
733
729
|
class LspServerLookupError extends Error {
|
|
734
|
-
lookup;
|
|
735
|
-
name = "LspServerLookupError";
|
|
736
730
|
constructor(message, lookup) {
|
|
737
731
|
super(message);
|
|
738
732
|
this.lookup = lookup;
|
|
733
|
+
this.name = "LspServerLookupError";
|
|
739
734
|
}
|
|
740
735
|
}
|
|
741
736
|
|
|
742
737
|
class LspServerInitializingError extends Error {
|
|
743
|
-
originalError;
|
|
744
|
-
name = "LspServerInitializingError";
|
|
745
738
|
constructor(originalError) {
|
|
746
739
|
super(`LSP server is still initializing. Please retry in a few seconds. Original error: ${originalError.message}`);
|
|
747
740
|
this.originalError = originalError;
|
|
741
|
+
this.name = "LspServerInitializingError";
|
|
748
742
|
}
|
|
749
743
|
}
|
|
750
744
|
|
|
751
745
|
class LspProcessSpawnError extends Error {
|
|
752
|
-
|
|
746
|
+
constructor() {
|
|
747
|
+
super(...arguments);
|
|
748
|
+
this.name = "LspProcessSpawnError";
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
class LspClientRespawnBudgetExceededError extends Error {
|
|
753
|
+
constructor(serverId, root, retryLimit) {
|
|
754
|
+
super(`LSP server ${serverId} at ${root} failed to stay alive; respawn budget exhausted ` + `(${retryLimit} consecutive dead generations). Retrying after the cooldown may succeed.`);
|
|
755
|
+
this.serverId = serverId;
|
|
756
|
+
this.root = root;
|
|
757
|
+
this.retryLimit = retryLimit;
|
|
758
|
+
this.name = "LspClientRespawnBudgetExceededError";
|
|
759
|
+
}
|
|
753
760
|
}
|
|
754
761
|
function isLspDeadConnectionError(err) {
|
|
755
762
|
return err instanceof LspConnectionClosedError || err instanceof LspProcessExitedError;
|
|
@@ -762,6 +769,11 @@ function reportBestEffortCleanupError(operation, error, logger = writeCleanupErr
|
|
|
762
769
|
const message = error instanceof Error ? error.message : String(error);
|
|
763
770
|
logger(`[lsp] ignored ${operation} failure during cleanup: ${message}`);
|
|
764
771
|
}
|
|
772
|
+
var realTimerProvider = {
|
|
773
|
+
now: () => Date.now(),
|
|
774
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
775
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
776
|
+
};
|
|
765
777
|
var DEFAULT_MAX_REFERENCES = 200;
|
|
766
778
|
var DEFAULT_MAX_SYMBOLS = 200;
|
|
767
779
|
var DEFAULT_MAX_DIAGNOSTICS = 200;
|
|
@@ -769,9 +781,12 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
|
769
781
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
770
782
|
var INIT_TIMEOUT_MS = 60000;
|
|
771
783
|
var IDLE_TIMEOUT_MS = 5 * 60000;
|
|
784
|
+
var MAX_RESIDENT_CLIENTS = 6;
|
|
772
785
|
var REAPER_INTERVAL_MS = 60000;
|
|
773
786
|
var STOP_HARD_KILL_TIMEOUT_MS = 5000;
|
|
774
787
|
var STOP_SIGKILL_GRACE_MS = 1000;
|
|
788
|
+
var CLIENT_RESPAWN_RETRY_LIMIT = 2;
|
|
789
|
+
var CLIENT_RESPAWN_COOLDOWN_MS = 60000;
|
|
775
790
|
var HEADER_SEPARATOR2 = `\r
|
|
776
791
|
\r
|
|
777
792
|
`;
|
|
@@ -781,20 +796,31 @@ var METHOD_NOT_FOUND = -32601;
|
|
|
781
796
|
var INTERNAL_ERROR = -32603;
|
|
782
797
|
|
|
783
798
|
class JsonRpcConnection {
|
|
784
|
-
reader;
|
|
785
|
-
writer;
|
|
786
|
-
pendingRequests = new Map;
|
|
787
|
-
notificationHandlers = new Map;
|
|
788
|
-
requestHandlers = new Map;
|
|
789
|
-
closeHandlers = [];
|
|
790
|
-
errorHandlers = [];
|
|
791
|
-
inputBuffer = Buffer.alloc(0);
|
|
792
|
-
nextRequestId = 1;
|
|
793
|
-
listening = false;
|
|
794
|
-
disposed = false;
|
|
795
799
|
constructor(reader, writer) {
|
|
796
800
|
this.reader = reader;
|
|
797
801
|
this.writer = writer;
|
|
802
|
+
this.pendingRequests = new Map;
|
|
803
|
+
this.notificationHandlers = new Map;
|
|
804
|
+
this.requestHandlers = new Map;
|
|
805
|
+
this.closeHandlers = [];
|
|
806
|
+
this.errorHandlers = [];
|
|
807
|
+
this.inputBuffer = Buffer.alloc(0);
|
|
808
|
+
this.nextRequestId = 1;
|
|
809
|
+
this.listening = false;
|
|
810
|
+
this.disposed = false;
|
|
811
|
+
this.handleData = (chunk) => {
|
|
812
|
+
const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
813
|
+
this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
|
|
814
|
+
this.drainInputBuffer();
|
|
815
|
+
};
|
|
816
|
+
this.handleClose = () => {
|
|
817
|
+
for (const handler of this.closeHandlers) {
|
|
818
|
+
handler();
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
this.handleStreamError = (error) => {
|
|
822
|
+
this.emitError(error);
|
|
823
|
+
};
|
|
798
824
|
}
|
|
799
825
|
listen() {
|
|
800
826
|
if (this.listening)
|
|
@@ -829,7 +855,8 @@ class JsonRpcConnection {
|
|
|
829
855
|
let cancelAfterWrite = false;
|
|
830
856
|
let settled = false;
|
|
831
857
|
const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
|
|
832
|
-
|
|
858
|
+
let rejectAfterCancelWrite;
|
|
859
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
833
860
|
const cleanup = () => {
|
|
834
861
|
options.signal?.removeEventListener("abort", onAbort);
|
|
835
862
|
};
|
|
@@ -840,22 +867,26 @@ class JsonRpcConnection {
|
|
|
840
867
|
this.pendingRequests.delete(key);
|
|
841
868
|
cleanup();
|
|
842
869
|
const rejectCancelled = () => reject(abortError2(options.signal));
|
|
870
|
+
rejectAfterCancelWrite = async () => {
|
|
871
|
+
try {
|
|
872
|
+
await writeCancel();
|
|
873
|
+
} catch (error) {
|
|
874
|
+
this.emitError(toError(error));
|
|
875
|
+
}
|
|
876
|
+
rejectCancelled();
|
|
877
|
+
};
|
|
843
878
|
if (!requestWritten) {
|
|
844
879
|
cancelAfterWrite = true;
|
|
845
|
-
rejectCancelled();
|
|
846
880
|
return;
|
|
847
881
|
}
|
|
848
|
-
|
|
849
|
-
this.emitError(toError(error));
|
|
850
|
-
rejectCancelled();
|
|
851
|
-
});
|
|
882
|
+
rejectAfterCancelWrite();
|
|
852
883
|
};
|
|
853
884
|
const onAbort = () => settleCancel();
|
|
854
885
|
this.pendingRequests.set(key, {
|
|
855
886
|
resolve(result) {
|
|
856
887
|
settled = true;
|
|
857
888
|
cleanup();
|
|
858
|
-
|
|
889
|
+
resolve(result);
|
|
859
890
|
},
|
|
860
891
|
reject(error) {
|
|
861
892
|
settled = true;
|
|
@@ -876,7 +907,7 @@ class JsonRpcConnection {
|
|
|
876
907
|
await this.writeMessage(message);
|
|
877
908
|
requestWritten = true;
|
|
878
909
|
if (cancelAfterWrite)
|
|
879
|
-
await
|
|
910
|
+
await rejectAfterCancelWrite?.();
|
|
880
911
|
} catch (error) {
|
|
881
912
|
if (settled)
|
|
882
913
|
return responsePromise;
|
|
@@ -915,19 +946,6 @@ class JsonRpcConnection {
|
|
|
915
946
|
this.notificationHandlers.clear();
|
|
916
947
|
this.requestHandlers.clear();
|
|
917
948
|
}
|
|
918
|
-
handleData = (chunk) => {
|
|
919
|
-
const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
920
|
-
this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
|
|
921
|
-
this.drainInputBuffer();
|
|
922
|
-
};
|
|
923
|
-
handleClose = () => {
|
|
924
|
-
for (const handler of this.closeHandlers) {
|
|
925
|
-
handler();
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
handleStreamError = (error) => {
|
|
929
|
-
this.emitError(error);
|
|
930
|
-
};
|
|
931
949
|
drainInputBuffer() {
|
|
932
950
|
while (true) {
|
|
933
951
|
const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
|
|
@@ -1027,13 +1045,13 @@ class JsonRpcConnection {
|
|
|
1027
1045
|
const payload = `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
1028
1046
|
\r
|
|
1029
1047
|
${body}`;
|
|
1030
|
-
return new Promise((
|
|
1048
|
+
return new Promise((resolve, reject) => {
|
|
1031
1049
|
this.writer.write(payload, (error) => {
|
|
1032
1050
|
if (error) {
|
|
1033
1051
|
reject(error);
|
|
1034
1052
|
return;
|
|
1035
1053
|
}
|
|
1036
|
-
|
|
1054
|
+
resolve();
|
|
1037
1055
|
});
|
|
1038
1056
|
});
|
|
1039
1057
|
}
|
|
@@ -1115,9 +1133,9 @@ function validateCwd(cwd) {
|
|
|
1115
1133
|
}
|
|
1116
1134
|
}
|
|
1117
1135
|
function wrap(proc) {
|
|
1118
|
-
const exitedPromise = new Promise((
|
|
1119
|
-
proc.once("close", (code) =>
|
|
1120
|
-
proc.once("error", () =>
|
|
1136
|
+
const exitedPromise = new Promise((resolve) => {
|
|
1137
|
+
proc.once("close", (code) => resolve(code ?? 0));
|
|
1138
|
+
proc.once("error", () => resolve(1));
|
|
1121
1139
|
});
|
|
1122
1140
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
1123
1141
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
@@ -1267,33 +1285,29 @@ function isPosition(value) {
|
|
|
1267
1285
|
}
|
|
1268
1286
|
|
|
1269
1287
|
class LspClientNotStartedError extends Error {
|
|
1270
|
-
serverId;
|
|
1271
|
-
root;
|
|
1272
|
-
name = "LspClientNotStartedError";
|
|
1273
1288
|
constructor(serverId, root) {
|
|
1274
1289
|
super("LSP client not started");
|
|
1275
1290
|
this.serverId = serverId;
|
|
1276
1291
|
this.root = root;
|
|
1292
|
+
this.name = "LspClientNotStartedError";
|
|
1277
1293
|
}
|
|
1278
1294
|
}
|
|
1279
1295
|
|
|
1280
1296
|
class LspClientTransport {
|
|
1281
|
-
root
|
|
1282
|
-
server;
|
|
1283
|
-
proc = null;
|
|
1284
|
-
connection = null;
|
|
1285
|
-
stderrBuffer = [];
|
|
1286
|
-
processExited = false;
|
|
1287
|
-
diagnosticsStore = new Map;
|
|
1288
|
-
requestTimeoutMs;
|
|
1289
|
-
initializeTimeoutMs;
|
|
1290
|
-
workspaceApplyEditHandler = null;
|
|
1291
|
-
diagnosticPullSupported = false;
|
|
1292
|
-
constructor(root, server2, timeouts = {}) {
|
|
1297
|
+
constructor(root, server, timeouts = {}) {
|
|
1293
1298
|
this.root = root;
|
|
1294
|
-
this.server =
|
|
1299
|
+
this.server = server;
|
|
1300
|
+
this.proc = null;
|
|
1301
|
+
this.connection = null;
|
|
1302
|
+
this.stderrBuffer = [];
|
|
1303
|
+
this.processExited = false;
|
|
1304
|
+
this.diagnosticsStore = new Map;
|
|
1305
|
+
this.workspaceApplyEditHandler = null;
|
|
1306
|
+
this.diagnosticPullSupported = false;
|
|
1307
|
+
this.documentFormattingSupported = false;
|
|
1295
1308
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
1296
1309
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
1310
|
+
this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
|
|
1297
1311
|
}
|
|
1298
1312
|
pid() {
|
|
1299
1313
|
return this.proc?.pid;
|
|
@@ -1313,6 +1327,12 @@ class LspClientTransport {
|
|
|
1313
1327
|
isDiagnosticPullSupported() {
|
|
1314
1328
|
return this.diagnosticPullSupported;
|
|
1315
1329
|
}
|
|
1330
|
+
setDocumentFormattingSupported(supported) {
|
|
1331
|
+
this.documentFormattingSupported = supported;
|
|
1332
|
+
}
|
|
1333
|
+
isDocumentFormattingSupported() {
|
|
1334
|
+
return this.documentFormattingSupported;
|
|
1335
|
+
}
|
|
1316
1336
|
handlePublishDiagnostics(params) {
|
|
1317
1337
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
1318
1338
|
}
|
|
@@ -1388,7 +1408,7 @@ class LspClientTransport {
|
|
|
1388
1408
|
const options = args[1];
|
|
1389
1409
|
const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
|
|
1390
1410
|
const timeoutController = new AbortController;
|
|
1391
|
-
const timeoutHandle = setTimeout(() => {
|
|
1411
|
+
const timeoutHandle = this.timerProvider.setTimeout(() => {
|
|
1392
1412
|
const stderrTail = this.stderrBuffer.slice(-5).join(`
|
|
1393
1413
|
`);
|
|
1394
1414
|
timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
|
|
@@ -1407,7 +1427,7 @@ class LspClientTransport {
|
|
|
1407
1427
|
}
|
|
1408
1428
|
throw error;
|
|
1409
1429
|
} finally {
|
|
1410
|
-
clearTimeout(timeoutHandle);
|
|
1430
|
+
this.timerProvider.clearTimeout(timeoutHandle);
|
|
1411
1431
|
combinedSignal.dispose();
|
|
1412
1432
|
}
|
|
1413
1433
|
}
|
|
@@ -1458,8 +1478,8 @@ class LspClientTransport {
|
|
|
1458
1478
|
try {
|
|
1459
1479
|
proc.kill();
|
|
1460
1480
|
let timeoutId;
|
|
1461
|
-
const timeoutPromise = new Promise((
|
|
1462
|
-
timeoutId = setTimeout(
|
|
1481
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1482
|
+
timeoutId = setTimeout(resolve, STOP_HARD_KILL_TIMEOUT_MS);
|
|
1463
1483
|
});
|
|
1464
1484
|
await Promise.race([
|
|
1465
1485
|
proc.exited.then(() => {
|
|
@@ -1475,7 +1495,7 @@ class LspClientTransport {
|
|
|
1475
1495
|
proc.kill("SIGKILL");
|
|
1476
1496
|
await Promise.race([
|
|
1477
1497
|
proc.exited,
|
|
1478
|
-
new Promise((
|
|
1498
|
+
new Promise((resolve) => setTimeout(resolve, STOP_SIGKILL_GRACE_MS))
|
|
1479
1499
|
]);
|
|
1480
1500
|
} catch (error) {
|
|
1481
1501
|
reportBestEffortCleanupError("hard process kill", error instanceof Error ? error : String(error));
|
|
@@ -1524,6 +1544,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
1524
1544
|
return false;
|
|
1525
1545
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
1526
1546
|
}
|
|
1547
|
+
function supportsDocumentFormatting(capabilities) {
|
|
1548
|
+
if (capabilities === undefined)
|
|
1549
|
+
return false;
|
|
1550
|
+
const provider = capabilities.documentFormattingProvider;
|
|
1551
|
+
if (provider === undefined || provider === null || provider === false)
|
|
1552
|
+
return false;
|
|
1553
|
+
return provider === true || typeof provider === "object";
|
|
1554
|
+
}
|
|
1527
1555
|
|
|
1528
1556
|
class LspClientConnection extends LspClientTransport {
|
|
1529
1557
|
async initialize() {
|
|
@@ -1540,6 +1568,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1540
1568
|
references: {},
|
|
1541
1569
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
1542
1570
|
publishDiagnostics: {},
|
|
1571
|
+
formatting: { dynamicRegistration: false },
|
|
1543
1572
|
rename: {
|
|
1544
1573
|
prepareSupport: true,
|
|
1545
1574
|
prepareSupportDefaultBehavior: 1
|
|
@@ -1581,6 +1610,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1581
1610
|
initializationOptions: this.server.initialization
|
|
1582
1611
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
1583
1612
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
1613
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
1584
1614
|
await this.sendNotification("initialized", {});
|
|
1585
1615
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
1586
1616
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -1767,6 +1797,17 @@ function canonicalPath(filePath) {
|
|
|
1767
1797
|
return absolute;
|
|
1768
1798
|
}
|
|
1769
1799
|
}
|
|
1800
|
+
function normalizeDocumentUri(uri) {
|
|
1801
|
+
let decoded = uri;
|
|
1802
|
+
try {
|
|
1803
|
+
decoded = decodeURIComponent(uri);
|
|
1804
|
+
} catch {
|
|
1805
|
+
decoded = uri;
|
|
1806
|
+
}
|
|
1807
|
+
if (process.platform !== "win32")
|
|
1808
|
+
return decoded;
|
|
1809
|
+
return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
|
|
1810
|
+
}
|
|
1770
1811
|
function isSameOrDescendant(candidate, parent) {
|
|
1771
1812
|
const suffix = relative2(parent, candidate);
|
|
1772
1813
|
return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
|
|
@@ -1777,30 +1818,31 @@ function movedPath(candidate, oldPath, newPath) {
|
|
|
1777
1818
|
}
|
|
1778
1819
|
|
|
1779
1820
|
class WorkspaceDocumentState {
|
|
1780
|
-
sendNotification;
|
|
1781
|
-
clearDiagnostics;
|
|
1782
|
-
openDocuments = new Map;
|
|
1783
|
-
openByUri = new Map;
|
|
1784
|
-
openPromises = new Map;
|
|
1785
|
-
now;
|
|
1786
|
-
versionlessPublishQuiescenceMs;
|
|
1787
1821
|
constructor(sendNotification, clearDiagnostics, options = {}) {
|
|
1788
1822
|
this.sendNotification = sendNotification;
|
|
1789
1823
|
this.clearDiagnostics = clearDiagnostics;
|
|
1790
|
-
this.
|
|
1824
|
+
this.openDocuments = new Map;
|
|
1825
|
+
this.openByUri = new Map;
|
|
1826
|
+
this.openPromises = new Map;
|
|
1827
|
+
this.timerProvider = options.timerProvider ?? {
|
|
1828
|
+
now: options.now ?? (() => Date.now()),
|
|
1829
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
1830
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
1831
|
+
};
|
|
1832
|
+
this.now = () => this.timerProvider.now();
|
|
1791
1833
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
1792
1834
|
}
|
|
1793
1835
|
async openFile(filePath) {
|
|
1794
|
-
const
|
|
1795
|
-
const existingOpen = this.openPromises.get(
|
|
1836
|
+
const path = canonicalPath(filePath);
|
|
1837
|
+
const existingOpen = this.openPromises.get(path);
|
|
1796
1838
|
if (existingOpen) {
|
|
1797
1839
|
await existingOpen;
|
|
1798
|
-
return this.openFile(
|
|
1840
|
+
return this.openFile(path);
|
|
1799
1841
|
}
|
|
1800
|
-
const text = readFileSync2(
|
|
1801
|
-
const existing = this.openDocuments.get(
|
|
1842
|
+
const text = readFileSync2(path, "utf-8");
|
|
1843
|
+
const existing = this.openDocuments.get(path);
|
|
1802
1844
|
if (!existing)
|
|
1803
|
-
return this.openDocumentSingleFlight(
|
|
1845
|
+
return this.openDocumentSingleFlight(path, text);
|
|
1804
1846
|
if (existing.text === text)
|
|
1805
1847
|
return;
|
|
1806
1848
|
await this.changeDocument(existing, text);
|
|
@@ -1809,7 +1851,7 @@ class WorkspaceDocumentState {
|
|
|
1809
1851
|
return this.openDocuments.get(canonicalPath(filePath))?.version;
|
|
1810
1852
|
}
|
|
1811
1853
|
getStoredDiagnostics(uri) {
|
|
1812
|
-
const state = this.openByUri.get(uri);
|
|
1854
|
+
const state = this.openByUri.get(normalizeDocumentUri(uri));
|
|
1813
1855
|
if (!state)
|
|
1814
1856
|
return [];
|
|
1815
1857
|
return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
|
|
@@ -1831,13 +1873,13 @@ class WorkspaceDocumentState {
|
|
|
1831
1873
|
return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
|
|
1832
1874
|
}
|
|
1833
1875
|
getPullCache(snapshot) {
|
|
1834
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1876
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1835
1877
|
if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
|
|
1836
1878
|
return null;
|
|
1837
1879
|
return state.pullCache;
|
|
1838
1880
|
}
|
|
1839
1881
|
recordPullDiagnostics(snapshot, report) {
|
|
1840
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1882
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1841
1883
|
if (!state)
|
|
1842
1884
|
return;
|
|
1843
1885
|
state.pullCache = {
|
|
@@ -1847,7 +1889,7 @@ class WorkspaceDocumentState {
|
|
|
1847
1889
|
};
|
|
1848
1890
|
}
|
|
1849
1891
|
recordPublishedDiagnostics(params) {
|
|
1850
|
-
const state = this.openByUri.get(params.uri);
|
|
1892
|
+
const state = this.openByUri.get(normalizeDocumentUri(params.uri));
|
|
1851
1893
|
if (!state)
|
|
1852
1894
|
return;
|
|
1853
1895
|
state.publishGeneration += 1;
|
|
@@ -1861,7 +1903,7 @@ class WorkspaceDocumentState {
|
|
|
1861
1903
|
this.notifyWaiters(state);
|
|
1862
1904
|
}
|
|
1863
1905
|
resolvePushDiagnostics(snapshot) {
|
|
1864
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1906
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1865
1907
|
if (!state?.lastPublish)
|
|
1866
1908
|
return { status: "missing" };
|
|
1867
1909
|
const publish = state.lastPublish;
|
|
@@ -1875,7 +1917,7 @@ class WorkspaceDocumentState {
|
|
|
1875
1917
|
return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
|
|
1876
1918
|
}
|
|
1877
1919
|
waitForDiagnosticsActivity(snapshot, timeoutMs) {
|
|
1878
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1920
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1879
1921
|
if (!state || timeoutMs <= 0)
|
|
1880
1922
|
return Promise.resolve();
|
|
1881
1923
|
return new Promise((resolveActivity) => {
|
|
@@ -1884,18 +1926,18 @@ class WorkspaceDocumentState {
|
|
|
1884
1926
|
if (settled)
|
|
1885
1927
|
return;
|
|
1886
1928
|
settled = true;
|
|
1887
|
-
clearTimeout(timer);
|
|
1929
|
+
this.timerProvider.clearTimeout(timer);
|
|
1888
1930
|
state.waiters.delete(finish);
|
|
1889
1931
|
resolveActivity();
|
|
1890
1932
|
};
|
|
1891
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
1933
|
+
const timer = this.timerProvider.setTimeout(finish, timeoutMs);
|
|
1892
1934
|
if (typeof timer.unref === "function")
|
|
1893
1935
|
timer.unref();
|
|
1894
1936
|
state.waiters.add(finish);
|
|
1895
1937
|
});
|
|
1896
1938
|
}
|
|
1897
1939
|
validateVersions(operations) {
|
|
1898
|
-
const versions = new Map([...this.openDocuments].map(([
|
|
1940
|
+
const versions = new Map([...this.openDocuments].map(([path, state]) => [path, state.version]));
|
|
1899
1941
|
for (const operation of operations) {
|
|
1900
1942
|
if (operation.kind === "text") {
|
|
1901
1943
|
const current = versions.get(operation.path);
|
|
@@ -1911,17 +1953,17 @@ class WorkspaceDocumentState {
|
|
|
1911
1953
|
continue;
|
|
1912
1954
|
}
|
|
1913
1955
|
if (operation.kind === "rename") {
|
|
1914
|
-
const moved = [...versions].filter(([
|
|
1915
|
-
for (const [
|
|
1916
|
-
versions.delete(
|
|
1917
|
-
for (const [
|
|
1918
|
-
versions.set(movedPath(
|
|
1956
|
+
const moved = [...versions].filter(([path]) => isSameOrDescendant(path, operation.oldPath));
|
|
1957
|
+
for (const [path] of moved)
|
|
1958
|
+
versions.delete(path);
|
|
1959
|
+
for (const [path] of moved)
|
|
1960
|
+
versions.set(movedPath(path, operation.oldPath, operation.newPath), 1);
|
|
1919
1961
|
continue;
|
|
1920
1962
|
}
|
|
1921
1963
|
if (operation.kind === "delete") {
|
|
1922
|
-
for (const
|
|
1923
|
-
if (isSameOrDescendant(
|
|
1924
|
-
versions.delete(
|
|
1964
|
+
for (const path of [...versions.keys()]) {
|
|
1965
|
+
if (isSameOrDescendant(path, operation.path))
|
|
1966
|
+
versions.delete(path);
|
|
1925
1967
|
}
|
|
1926
1968
|
continue;
|
|
1927
1969
|
}
|
|
@@ -1965,8 +2007,8 @@ class WorkspaceDocumentState {
|
|
|
1965
2007
|
for (const state of moved)
|
|
1966
2008
|
await this.closeDocument(state);
|
|
1967
2009
|
for (const state of moved) {
|
|
1968
|
-
const
|
|
1969
|
-
await this.openDocumentSingleFlight(
|
|
2010
|
+
const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
|
|
2011
|
+
await this.openDocumentSingleFlight(path, readFileSync2(path, "utf-8"));
|
|
1970
2012
|
}
|
|
1971
2013
|
if (moved.length === 0) {
|
|
1972
2014
|
watched.push({ uri: pathToFileURL2(mutation.oldPath).href, type: 3 });
|
|
@@ -1980,31 +2022,31 @@ class WorkspaceDocumentState {
|
|
|
1980
2022
|
if (removed.length === 0)
|
|
1981
2023
|
watched.push({ uri: pathToFileURL2(mutation.path).href, type: 3 });
|
|
1982
2024
|
}
|
|
1983
|
-
async openDocumentSingleFlight(
|
|
1984
|
-
const existing = this.openPromises.get(
|
|
2025
|
+
async openDocumentSingleFlight(path, text) {
|
|
2026
|
+
const existing = this.openPromises.get(path);
|
|
1985
2027
|
if (existing)
|
|
1986
2028
|
return existing;
|
|
1987
2029
|
const open = (async () => {
|
|
1988
2030
|
const state = {
|
|
1989
|
-
path
|
|
1990
|
-
uri: pathToFileURL2(
|
|
1991
|
-
languageId: getLanguageId(effectiveExtension(
|
|
2031
|
+
path,
|
|
2032
|
+
uri: pathToFileURL2(path).href,
|
|
2033
|
+
languageId: getLanguageId(effectiveExtension(path)),
|
|
1992
2034
|
text,
|
|
1993
2035
|
version: 1,
|
|
1994
2036
|
generation: 1,
|
|
1995
2037
|
publishGeneration: 0,
|
|
1996
2038
|
waiters: new Set
|
|
1997
2039
|
};
|
|
1998
|
-
this.openDocuments.set(
|
|
1999
|
-
this.openByUri.set(state.uri, state);
|
|
2040
|
+
this.openDocuments.set(path, state);
|
|
2041
|
+
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
2000
2042
|
this.notifyWaiters(state);
|
|
2001
2043
|
await this.sendNotification("textDocument/didOpen", {
|
|
2002
2044
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
2003
2045
|
});
|
|
2004
2046
|
})().finally(() => {
|
|
2005
|
-
this.openPromises.delete(
|
|
2047
|
+
this.openPromises.delete(path);
|
|
2006
2048
|
});
|
|
2007
|
-
this.openPromises.set(
|
|
2049
|
+
this.openPromises.set(path, open);
|
|
2008
2050
|
return open;
|
|
2009
2051
|
}
|
|
2010
2052
|
async changeDocument(state, text) {
|
|
@@ -2021,7 +2063,7 @@ class WorkspaceDocumentState {
|
|
|
2021
2063
|
}
|
|
2022
2064
|
async closeDocument(state) {
|
|
2023
2065
|
this.openDocuments.delete(state.path);
|
|
2024
|
-
this.openByUri.delete(state.uri);
|
|
2066
|
+
this.openByUri.delete(normalizeDocumentUri(state.uri));
|
|
2025
2067
|
this.clearDiagnostics(state.uri);
|
|
2026
2068
|
this.notifyWaiters(state);
|
|
2027
2069
|
await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
|
|
@@ -2040,13 +2082,11 @@ function workspaceApplyEditConcurrentFailureReason(phase) {
|
|
|
2040
2082
|
}
|
|
2041
2083
|
|
|
2042
2084
|
class WorkspaceEditPathError extends Error {
|
|
2043
|
-
path
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
constructor(path2, detail) {
|
|
2047
|
-
super(`${detail}: ${path2}`);
|
|
2048
|
-
this.path = path2;
|
|
2085
|
+
constructor(path, detail) {
|
|
2086
|
+
super(`${detail}: ${path}`);
|
|
2087
|
+
this.path = path;
|
|
2049
2088
|
this.detail = detail;
|
|
2089
|
+
this.name = "WorkspaceEditPathError";
|
|
2050
2090
|
}
|
|
2051
2091
|
}
|
|
2052
2092
|
function isPathInsideWorkspace(filePath, workspaceRoot) {
|
|
@@ -2108,26 +2148,26 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
2108
2148
|
return { success: false, error: `${requestedPath}: ${detail}` };
|
|
2109
2149
|
}
|
|
2110
2150
|
}
|
|
2111
|
-
function snapshotPath(
|
|
2112
|
-
if (!existsSync4(
|
|
2151
|
+
function snapshotPath(path, includeChildren) {
|
|
2152
|
+
if (!existsSync4(path))
|
|
2113
2153
|
return { kind: "missing" };
|
|
2114
|
-
const stats = lstatSync2(
|
|
2154
|
+
const stats = lstatSync2(path);
|
|
2115
2155
|
if (stats.isFile())
|
|
2116
|
-
return { kind: "file", content: readFileSync3(
|
|
2156
|
+
return { kind: "file", content: readFileSync3(path, "utf-8") };
|
|
2117
2157
|
if (stats.isDirectory()) {
|
|
2118
|
-
return includeChildren ? { kind: "directory", children: readdirSync(
|
|
2158
|
+
return includeChildren ? { kind: "directory", children: readdirSync(path).sort() } : { kind: "directory" };
|
|
2119
2159
|
}
|
|
2120
|
-
throw new WorkspaceEditPathError(
|
|
2160
|
+
throw new WorkspaceEditPathError(path, "unsupported filesystem entry");
|
|
2121
2161
|
}
|
|
2122
2162
|
var DEFAULT_IO = {
|
|
2123
|
-
writeFile(
|
|
2124
|
-
writeFileSync(
|
|
2163
|
+
writeFile(path, content) {
|
|
2164
|
+
writeFileSync(path, content, "utf-8");
|
|
2125
2165
|
},
|
|
2126
2166
|
rename(oldPath, newPath) {
|
|
2127
2167
|
renameSync(oldPath, newPath);
|
|
2128
2168
|
},
|
|
2129
|
-
remove(
|
|
2130
|
-
rmSync(
|
|
2169
|
+
remove(path, recursive) {
|
|
2170
|
+
rmSync(path, { recursive, force: false });
|
|
2131
2171
|
}
|
|
2132
2172
|
};
|
|
2133
2173
|
function snapshotsEqual(expected, actual) {
|
|
@@ -2140,8 +2180,8 @@ function snapshotsEqual(expected, actual) {
|
|
|
2140
2180
|
}
|
|
2141
2181
|
return true;
|
|
2142
2182
|
}
|
|
2143
|
-
function liveSnapshot(
|
|
2144
|
-
return snapshotPath(
|
|
2183
|
+
function liveSnapshot(path, expected) {
|
|
2184
|
+
return snapshotPath(path, expected.kind === "directory" && expected.children !== undefined);
|
|
2145
2185
|
}
|
|
2146
2186
|
function firstOperationIndex(plan) {
|
|
2147
2187
|
return plan.operations[0]?.changeIndex ?? 0;
|
|
@@ -2162,28 +2202,28 @@ function failedCommit(plan, failure) {
|
|
|
2162
2202
|
};
|
|
2163
2203
|
}
|
|
2164
2204
|
function verifySnapshots(plan) {
|
|
2165
|
-
for (const [
|
|
2205
|
+
for (const [path, expected] of plan.snapshots) {
|
|
2166
2206
|
let actual;
|
|
2167
2207
|
try {
|
|
2168
|
-
actual = liveSnapshot(
|
|
2208
|
+
actual = liveSnapshot(path, expected);
|
|
2169
2209
|
} catch (error) {
|
|
2170
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2210
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2171
2211
|
const detail = error instanceof Error ? error.message : String(error);
|
|
2172
|
-
return failedCommit(plan, { message: `cannot verify snapshot for ${
|
|
2212
|
+
return failedCommit(plan, { message: `cannot verify snapshot for ${path}: ${detail}`, changeIndex });
|
|
2173
2213
|
}
|
|
2174
2214
|
if (!snapshotsEqual(expected, actual)) {
|
|
2175
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2176
|
-
return failedCommit(plan, { message: `workspace state changed before commit: ${
|
|
2215
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2216
|
+
return failedCommit(plan, { message: `workspace state changed before commit: ${path}`, changeIndex });
|
|
2177
2217
|
}
|
|
2178
2218
|
}
|
|
2179
2219
|
return null;
|
|
2180
2220
|
}
|
|
2181
|
-
function addModifiedPath(paths,
|
|
2182
|
-
if (!paths.includes(
|
|
2183
|
-
paths.push(
|
|
2221
|
+
function addModifiedPath(paths, path) {
|
|
2222
|
+
if (!paths.includes(path))
|
|
2223
|
+
paths.push(path);
|
|
2184
2224
|
}
|
|
2185
|
-
function reportedPath(plan,
|
|
2186
|
-
return plan.reportedPathByCanonical.get(
|
|
2225
|
+
function reportedPath(plan, path) {
|
|
2226
|
+
return plan.reportedPathByCanonical.get(path) ?? path;
|
|
2187
2227
|
}
|
|
2188
2228
|
function changedPathsForMutation(mutation) {
|
|
2189
2229
|
return mutation.kind === "rename" ? [mutation.oldPath, mutation.newPath] : [mutation.path];
|
|
@@ -2191,8 +2231,8 @@ function changedPathsForMutation(mutation) {
|
|
|
2191
2231
|
function mutationDelta(operations) {
|
|
2192
2232
|
const changedPaths = new Set;
|
|
2193
2233
|
for (const operation of operations) {
|
|
2194
|
-
for (const
|
|
2195
|
-
changedPaths.add(
|
|
2234
|
+
for (const path of changedPathsForMutation(operation))
|
|
2235
|
+
changedPaths.add(path);
|
|
2196
2236
|
}
|
|
2197
2237
|
return { operations, changedPaths: [...changedPaths].sort() };
|
|
2198
2238
|
}
|
|
@@ -2332,13 +2372,11 @@ function canonicalFingerprint(operations) {
|
|
|
2332
2372
|
}
|
|
2333
2373
|
|
|
2334
2374
|
class WorkspaceEditValidationError extends Error {
|
|
2335
|
-
changeIndex;
|
|
2336
|
-
detail;
|
|
2337
|
-
name = "WorkspaceEditValidationError";
|
|
2338
2375
|
constructor(changeIndex, detail) {
|
|
2339
2376
|
super(`change ${changeIndex}: ${detail}`);
|
|
2340
2377
|
this.changeIndex = changeIndex;
|
|
2341
2378
|
this.detail = detail;
|
|
2379
|
+
this.name = "WorkspaceEditValidationError";
|
|
2342
2380
|
}
|
|
2343
2381
|
}
|
|
2344
2382
|
function isRecord3(value) {
|
|
@@ -2420,14 +2458,14 @@ function parseSinglePathResource(input, kind) {
|
|
|
2420
2458
|
return;
|
|
2421
2459
|
}
|
|
2422
2460
|
if (kind === "create") {
|
|
2423
|
-
const
|
|
2461
|
+
const options = parseOptions(change["options"], ["overwrite", "ignoreIfExists"], changeIndex);
|
|
2424
2462
|
target.operations.push({
|
|
2425
2463
|
kind,
|
|
2426
2464
|
changeIndex,
|
|
2427
2465
|
path: resolvedPath.path,
|
|
2428
2466
|
reportedPath: resolvedPath.requestedPath,
|
|
2429
|
-
overwrite:
|
|
2430
|
-
ignoreIfExists:
|
|
2467
|
+
overwrite: options["overwrite"] ?? false,
|
|
2468
|
+
ignoreIfExists: options["ignoreIfExists"] ?? false,
|
|
2431
2469
|
followedSymbolicLink: resolvedPath.followedSymbolicLink
|
|
2432
2470
|
});
|
|
2433
2471
|
return;
|
|
@@ -2676,12 +2714,12 @@ function isSameOrDescendant2(candidate, parent) {
|
|
|
2676
2714
|
const relativePath = relative4(parent, candidate);
|
|
2677
2715
|
return relativePath === "" || !relativePath.startsWith("..") && relativePath !== "..";
|
|
2678
2716
|
}
|
|
2679
|
-
function removeVirtualSubtree(virtual,
|
|
2717
|
+
function removeVirtualSubtree(virtual, path) {
|
|
2680
2718
|
for (const candidate of [...virtual.keys()]) {
|
|
2681
|
-
if (isSameOrDescendant2(candidate,
|
|
2719
|
+
if (isSameOrDescendant2(candidate, path))
|
|
2682
2720
|
virtual.delete(candidate);
|
|
2683
2721
|
}
|
|
2684
|
-
virtual.set(
|
|
2722
|
+
virtual.set(path, { kind: "missing" });
|
|
2685
2723
|
}
|
|
2686
2724
|
function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
2687
2725
|
const moved = [...virtual.entries()].filter(([candidate]) => isSameOrDescendant2(candidate, oldPath));
|
|
@@ -2692,16 +2730,16 @@ function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
|
2692
2730
|
virtual.set(suffix === "" ? newPath : resolve4(newPath, suffix), entry);
|
|
2693
2731
|
}
|
|
2694
2732
|
}
|
|
2695
|
-
function virtualDirectoryHasChildren(virtual,
|
|
2733
|
+
function virtualDirectoryHasChildren(virtual, path) {
|
|
2696
2734
|
for (const [candidate, entry] of virtual) {
|
|
2697
|
-
if (candidate !==
|
|
2735
|
+
if (candidate !== path && entry.kind !== "missing" && isSameOrDescendant2(candidate, path))
|
|
2698
2736
|
return true;
|
|
2699
2737
|
}
|
|
2700
2738
|
return false;
|
|
2701
2739
|
}
|
|
2702
|
-
function requireVirtualParent(virtual,
|
|
2703
|
-
if (virtual.get(dirname5(
|
|
2704
|
-
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${
|
|
2740
|
+
function requireVirtualParent(virtual, path, changeIndex) {
|
|
2741
|
+
if (virtual.get(dirname5(path))?.kind !== "directory") {
|
|
2742
|
+
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${path}`);
|
|
2705
2743
|
}
|
|
2706
2744
|
}
|
|
2707
2745
|
function simulateOperations(parsed, snapshots) {
|
|
@@ -2820,10 +2858,9 @@ function simulateDelete(operation, virtual) {
|
|
|
2820
2858
|
}
|
|
2821
2859
|
|
|
2822
2860
|
class WorkspaceSnapshotBuilder {
|
|
2823
|
-
workspaceRoot;
|
|
2824
|
-
snapshots = new Map;
|
|
2825
2861
|
constructor(workspaceRoot) {
|
|
2826
2862
|
this.workspaceRoot = workspaceRoot;
|
|
2863
|
+
this.snapshots = new Map;
|
|
2827
2864
|
}
|
|
2828
2865
|
build(operations) {
|
|
2829
2866
|
this.add(this.workspaceRoot, false);
|
|
@@ -2844,21 +2881,21 @@ class WorkspaceSnapshotBuilder {
|
|
|
2844
2881
|
}
|
|
2845
2882
|
return this.snapshots;
|
|
2846
2883
|
}
|
|
2847
|
-
add(
|
|
2848
|
-
let candidate =
|
|
2884
|
+
add(path, includeChildren) {
|
|
2885
|
+
let candidate = path;
|
|
2849
2886
|
while (true) {
|
|
2850
2887
|
const existing = this.snapshots.get(candidate);
|
|
2851
2888
|
if (existing === undefined || includeChildren && existing.kind === "directory" && existing.children === undefined) {
|
|
2852
|
-
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate ===
|
|
2889
|
+
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate === path));
|
|
2853
2890
|
}
|
|
2854
2891
|
if (candidate === this.workspaceRoot)
|
|
2855
2892
|
break;
|
|
2856
2893
|
candidate = dirname6(candidate);
|
|
2857
2894
|
}
|
|
2858
|
-
if (!includeChildren || !existsSync6(
|
|
2895
|
+
if (!includeChildren || !existsSync6(path) || !lstatSync4(path).isDirectory())
|
|
2859
2896
|
return;
|
|
2860
|
-
for (const child of readdirSync2(
|
|
2861
|
-
this.add(resolve5(
|
|
2897
|
+
for (const child of readdirSync2(path))
|
|
2898
|
+
this.add(resolve5(path, child), true);
|
|
2862
2899
|
}
|
|
2863
2900
|
}
|
|
2864
2901
|
function snapshotOperations(operations, workspaceRoot) {
|
|
@@ -2866,8 +2903,10 @@ function snapshotOperations(operations, workspaceRoot) {
|
|
|
2866
2903
|
}
|
|
2867
2904
|
|
|
2868
2905
|
class PlanPathIndex {
|
|
2869
|
-
|
|
2870
|
-
|
|
2906
|
+
constructor() {
|
|
2907
|
+
this.firstChangeByPath = new Map;
|
|
2908
|
+
this.reportedPathByCanonical = new Map;
|
|
2909
|
+
}
|
|
2871
2910
|
build(operations) {
|
|
2872
2911
|
for (const operation of operations) {
|
|
2873
2912
|
switch (operation.kind) {
|
|
@@ -2883,11 +2922,11 @@ class PlanPathIndex {
|
|
|
2883
2922
|
}
|
|
2884
2923
|
}
|
|
2885
2924
|
}
|
|
2886
|
-
add(
|
|
2887
|
-
if (!this.firstChangeByPath.has(
|
|
2888
|
-
this.firstChangeByPath.set(
|
|
2889
|
-
if (!this.reportedPathByCanonical.has(
|
|
2890
|
-
this.reportedPathByCanonical.set(
|
|
2925
|
+
add(path, reportedPath, changeIndex) {
|
|
2926
|
+
if (!this.firstChangeByPath.has(path))
|
|
2927
|
+
this.firstChangeByPath.set(path, changeIndex);
|
|
2928
|
+
if (!this.reportedPathByCanonical.has(path))
|
|
2929
|
+
this.reportedPathByCanonical.set(path, reportedPath);
|
|
2891
2930
|
}
|
|
2892
2931
|
}
|
|
2893
2932
|
function fingerprintWorkspaceEdit(edit, workspaceRoot) {
|
|
@@ -2954,14 +2993,11 @@ function isRecord4(value) {
|
|
|
2954
2993
|
}
|
|
2955
2994
|
|
|
2956
2995
|
class WorkspaceMutationController {
|
|
2957
|
-
workspaceRoot;
|
|
2958
|
-
documents;
|
|
2959
|
-
activeLease = null;
|
|
2960
|
-
nextLeaseId = 1;
|
|
2961
|
-
io;
|
|
2962
2996
|
constructor(workspaceRoot, documents) {
|
|
2963
2997
|
this.workspaceRoot = workspaceRoot;
|
|
2964
2998
|
this.documents = documents;
|
|
2999
|
+
this.activeLease = null;
|
|
3000
|
+
this.nextLeaseId = 1;
|
|
2965
3001
|
}
|
|
2966
3002
|
setIo(io) {
|
|
2967
3003
|
this.io = io;
|
|
@@ -3000,15 +3036,15 @@ class WorkspaceMutationController {
|
|
|
3000
3036
|
};
|
|
3001
3037
|
}
|
|
3002
3038
|
lease.phase = "applying";
|
|
3003
|
-
lease.applyCompletion = new Promise((
|
|
3004
|
-
lease.resolveApply =
|
|
3039
|
+
lease.applyCompletion = new Promise((resolve) => {
|
|
3040
|
+
lease.resolveApply = resolve;
|
|
3005
3041
|
});
|
|
3006
3042
|
const edit = isRecord4(params) ? params["edit"] : undefined;
|
|
3007
|
-
const
|
|
3008
|
-
lease.serverApply =
|
|
3043
|
+
const record = edit === undefined ? { fingerprint: null, result: failure("workspace/applyEdit params.edit is required", 0) } : await this.applyEdit(edit, lease);
|
|
3044
|
+
lease.serverApply = record;
|
|
3009
3045
|
lease.phase = "settled";
|
|
3010
3046
|
lease.resolveApply?.();
|
|
3011
|
-
return responseFor(
|
|
3047
|
+
return responseFor(record.result);
|
|
3012
3048
|
}
|
|
3013
3049
|
async reconcileRename(leaseToken, edit) {
|
|
3014
3050
|
const lease = this.requireActiveLease(leaseToken);
|
|
@@ -3024,16 +3060,16 @@ class WorkspaceMutationController {
|
|
|
3024
3060
|
const applied = await this.applyEdit(edit, lease);
|
|
3025
3061
|
return { edit, apply: applied.result };
|
|
3026
3062
|
}
|
|
3027
|
-
reconcileServerApply(
|
|
3063
|
+
reconcileServerApply(record, edit) {
|
|
3028
3064
|
if (!edit)
|
|
3029
|
-
return { edit, apply:
|
|
3065
|
+
return { edit, apply: record.result };
|
|
3030
3066
|
const fingerprint = fingerprintWorkspaceEdit(edit, this.workspaceRoot);
|
|
3031
|
-
if (fingerprint.success &&
|
|
3032
|
-
return { edit, apply:
|
|
3067
|
+
if (fingerprint.success && record.fingerprint !== null && fingerprint.fingerprint === record.fingerprint) {
|
|
3068
|
+
return { edit, apply: record.result };
|
|
3033
3069
|
}
|
|
3034
3070
|
return {
|
|
3035
3071
|
edit,
|
|
3036
|
-
apply: failure("rename result conflicts with server-applied workspace edit", 0,
|
|
3072
|
+
apply: failure("rename result conflicts with server-applied workspace edit", 0, record.result)
|
|
3037
3073
|
};
|
|
3038
3074
|
}
|
|
3039
3075
|
async applyEdit(edit, lease) {
|
|
@@ -3072,14 +3108,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
3072
3108
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
3073
3109
|
|
|
3074
3110
|
class LspClient extends LspClientConnection {
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
diagnosticsFreshnessTimeoutMs;
|
|
3079
|
-
constructor(root, server2, options = {}) {
|
|
3080
|
-
super(root, server2, options);
|
|
3111
|
+
constructor(root, server, options = {}) {
|
|
3112
|
+
super(root, server, options);
|
|
3113
|
+
this.diagnosticPullErrors = [];
|
|
3081
3114
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
3082
3115
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
3116
|
+
timerProvider: this.timerProvider,
|
|
3083
3117
|
versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
|
|
3084
3118
|
});
|
|
3085
3119
|
this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
|
|
@@ -3132,6 +3166,18 @@ class LspClient extends LspClientConnection {
|
|
|
3132
3166
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
3133
3167
|
}, options);
|
|
3134
3168
|
}
|
|
3169
|
+
async formatDocument(filePath, options, signal) {
|
|
3170
|
+
if (!this.isDocumentFormattingSupported())
|
|
3171
|
+
return null;
|
|
3172
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
3173
|
+
await this.openFile(absPath);
|
|
3174
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
3175
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
3176
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
3177
|
+
options
|
|
3178
|
+
}, requestOptions);
|
|
3179
|
+
return edits ?? [];
|
|
3180
|
+
}
|
|
3135
3181
|
async workspaceSymbols(query, signal) {
|
|
3136
3182
|
const options = signal === undefined ? {} : { signal };
|
|
3137
3183
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -3171,7 +3217,7 @@ class LspClient extends LspClientConnection {
|
|
|
3171
3217
|
const absPath = this.resolveWorkspacePath(filePath);
|
|
3172
3218
|
const uri = pathToFileURL3(absPath).href;
|
|
3173
3219
|
await this.openFile(absPath);
|
|
3174
|
-
const deadlineAt =
|
|
3220
|
+
const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
|
|
3175
3221
|
for (;; ) {
|
|
3176
3222
|
signal?.throwIfAborted();
|
|
3177
3223
|
const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
|
|
@@ -3184,13 +3230,13 @@ class LspClient extends LspClientConnection {
|
|
|
3184
3230
|
if (!pushFallbackOnly) {
|
|
3185
3231
|
const cached = this.documents.getPullCache(snapshot);
|
|
3186
3232
|
try {
|
|
3187
|
-
const
|
|
3188
|
-
if (
|
|
3233
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3234
|
+
if (remainingMs <= 0)
|
|
3189
3235
|
return this.freshnessTimeout(absPath);
|
|
3190
3236
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
3191
3237
|
textDocument: { uri },
|
|
3192
3238
|
...cached?.resultId === undefined ? {} : { previousResultId: cached.resultId }
|
|
3193
|
-
}, { timeoutMs:
|
|
3239
|
+
}, { timeoutMs: remainingMs, ...signal === undefined ? {} : { signal } });
|
|
3194
3240
|
if (!this.documents.isCurrentSnapshot(snapshot))
|
|
3195
3241
|
continue;
|
|
3196
3242
|
const report = this.parseDiagnosticPullReport(result);
|
|
@@ -3219,7 +3265,7 @@ class LspClient extends LspClientConnection {
|
|
|
3219
3265
|
}
|
|
3220
3266
|
if (!pushFallbackOnly)
|
|
3221
3267
|
continue;
|
|
3222
|
-
const remainingMs = deadlineAt -
|
|
3268
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3223
3269
|
if (remainingMs <= 0) {
|
|
3224
3270
|
if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
|
|
3225
3271
|
const cached = this.documents.getPullCache(snapshot);
|
|
@@ -3271,7 +3317,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3271
3317
|
return wait;
|
|
3272
3318
|
if (signal.aborted)
|
|
3273
3319
|
return Promise.reject(abortError3(signal));
|
|
3274
|
-
return new Promise((
|
|
3320
|
+
return new Promise((resolve, reject) => {
|
|
3275
3321
|
const onAbort = () => {
|
|
3276
3322
|
signal.removeEventListener("abort", onAbort);
|
|
3277
3323
|
reject(abortError3(signal));
|
|
@@ -3279,7 +3325,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3279
3325
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
3280
3326
|
wait.then(() => {
|
|
3281
3327
|
signal.removeEventListener("abort", onAbort);
|
|
3282
|
-
|
|
3328
|
+
resolve();
|
|
3283
3329
|
}, (error) => {
|
|
3284
3330
|
signal.removeEventListener("abort", onAbort);
|
|
3285
3331
|
reject(error);
|
|
@@ -3343,7 +3389,7 @@ async function stopClientBestEffort(client) {
|
|
|
3343
3389
|
function awaitWithSignal2(promise, signal) {
|
|
3344
3390
|
if (!signal)
|
|
3345
3391
|
return promise;
|
|
3346
|
-
return new Promise((
|
|
3392
|
+
return new Promise((resolve, reject) => {
|
|
3347
3393
|
let settled = false;
|
|
3348
3394
|
const onAbort = () => {
|
|
3349
3395
|
if (settled)
|
|
@@ -3361,7 +3407,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
3361
3407
|
return;
|
|
3362
3408
|
settled = true;
|
|
3363
3409
|
signal.removeEventListener("abort", onAbort);
|
|
3364
|
-
|
|
3410
|
+
resolve(value);
|
|
3365
3411
|
}, (err) => {
|
|
3366
3412
|
if (settled)
|
|
3367
3413
|
return;
|
|
@@ -3373,20 +3419,18 @@ function awaitWithSignal2(promise, signal) {
|
|
|
3373
3419
|
}
|
|
3374
3420
|
|
|
3375
3421
|
class LspManager {
|
|
3376
|
-
clients = new Map;
|
|
3377
|
-
reaperHandle = null;
|
|
3378
|
-
signalDisposer = null;
|
|
3379
|
-
disposed = false;
|
|
3380
|
-
idleTimeoutMs;
|
|
3381
|
-
initTimeoutMs;
|
|
3382
|
-
reaperIntervalMs;
|
|
3383
|
-
clientFactory;
|
|
3384
|
-
now;
|
|
3385
3422
|
constructor(options = {}) {
|
|
3423
|
+
this.clients = new Map;
|
|
3424
|
+
this.pendingStops = new Map;
|
|
3425
|
+
this.respawnBudgets = new Map;
|
|
3426
|
+
this.reaperHandle = null;
|
|
3427
|
+
this.signalDisposer = null;
|
|
3428
|
+
this.disposed = false;
|
|
3386
3429
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
3387
3430
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3431
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3388
3432
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3389
|
-
this.clientFactory = options.clientFactory ?? ((root,
|
|
3433
|
+
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
3390
3434
|
this.now = options.now ?? (() => Date.now());
|
|
3391
3435
|
this.startReaper();
|
|
3392
3436
|
this.signalDisposer = installProcessSignalCleanup(() => this.stopAll());
|
|
@@ -3404,38 +3448,103 @@ class LspManager {
|
|
|
3404
3448
|
getKey(root, serverId) {
|
|
3405
3449
|
return `${root}::${serverId}`;
|
|
3406
3450
|
}
|
|
3451
|
+
tombstoneStop(key, client) {
|
|
3452
|
+
const stop = stopClientBestEffort(client);
|
|
3453
|
+
this.pendingStops.set(key, stop);
|
|
3454
|
+
stop.finally(() => {
|
|
3455
|
+
if (this.pendingStops.get(key) === stop) {
|
|
3456
|
+
this.pendingStops.delete(key);
|
|
3457
|
+
}
|
|
3458
|
+
});
|
|
3459
|
+
return stop;
|
|
3460
|
+
}
|
|
3461
|
+
recordDeadGeneration(key) {
|
|
3462
|
+
let budget = this.respawnBudgets.get(key);
|
|
3463
|
+
if (budget === undefined) {
|
|
3464
|
+
budget = { deadGenerations: 0, exhaustedAt: null };
|
|
3465
|
+
this.respawnBudgets.set(key, budget);
|
|
3466
|
+
}
|
|
3467
|
+
budget.deadGenerations += 1;
|
|
3468
|
+
}
|
|
3469
|
+
markHealthyGeneration(key) {
|
|
3470
|
+
this.respawnBudgets.delete(key);
|
|
3471
|
+
}
|
|
3472
|
+
ensureRespawnAllowed(key, root, serverId) {
|
|
3473
|
+
const budget = this.respawnBudgets.get(key);
|
|
3474
|
+
if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
|
|
3475
|
+
return;
|
|
3476
|
+
if (budget.exhaustedAt === null) {
|
|
3477
|
+
budget.exhaustedAt = this.now();
|
|
3478
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3479
|
+
}
|
|
3480
|
+
if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
|
|
3481
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3482
|
+
}
|
|
3483
|
+
budget.deadGenerations = 0;
|
|
3484
|
+
budget.exhaustedAt = null;
|
|
3485
|
+
}
|
|
3407
3486
|
reapStale() {
|
|
3408
3487
|
const t = this.now();
|
|
3409
3488
|
for (const [key, managed] of this.clients) {
|
|
3410
3489
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3411
|
-
stopClientBestEffort(managed.client);
|
|
3412
3490
|
this.clients.delete(key);
|
|
3491
|
+
this.tombstoneStop(key, managed.client);
|
|
3413
3492
|
continue;
|
|
3414
3493
|
}
|
|
3415
3494
|
if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
|
|
3416
|
-
stopClientBestEffort(managed.client);
|
|
3417
3495
|
this.clients.delete(key);
|
|
3496
|
+
this.tombstoneStop(key, managed.client);
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
evictForAdmission() {
|
|
3501
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
3502
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
3503
|
+
if (!victim)
|
|
3504
|
+
return;
|
|
3505
|
+
this.clients.delete(victim.key);
|
|
3506
|
+
this.tombstoneStop(victim.key, victim.managed.client);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
leastRecentlyUsedIdleClient() {
|
|
3510
|
+
let candidate = null;
|
|
3511
|
+
for (const [key, managed] of this.clients) {
|
|
3512
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
3513
|
+
continue;
|
|
3514
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
3515
|
+
candidate = { key, managed };
|
|
3418
3516
|
}
|
|
3419
3517
|
}
|
|
3518
|
+
return candidate;
|
|
3420
3519
|
}
|
|
3421
3520
|
async tryDeleteIfOrphaned(key, managed) {
|
|
3422
3521
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
3423
3522
|
this.clients.delete(key);
|
|
3424
|
-
await
|
|
3523
|
+
await this.tombstoneStop(key, managed.client);
|
|
3425
3524
|
}
|
|
3426
3525
|
}
|
|
3427
|
-
async getClient(root,
|
|
3526
|
+
async getClient(root, server, signal) {
|
|
3428
3527
|
if (this.disposed) {
|
|
3429
3528
|
throw new Error("LspManager has been disposed");
|
|
3430
3529
|
}
|
|
3431
3530
|
signal?.throwIfAborted();
|
|
3432
|
-
const key = this.getKey(root,
|
|
3531
|
+
const key = this.getKey(root, server.id);
|
|
3532
|
+
for (;; ) {
|
|
3533
|
+
const pendingStop = this.pendingStops.get(key);
|
|
3534
|
+
if (pendingStop === undefined)
|
|
3535
|
+
break;
|
|
3536
|
+
await awaitWithSignal2(pendingStop, signal);
|
|
3537
|
+
signal?.throwIfAborted();
|
|
3538
|
+
}
|
|
3539
|
+
if (this.disposed) {
|
|
3540
|
+
throw new Error("LspManager has been disposed");
|
|
3541
|
+
}
|
|
3433
3542
|
let managed = this.clients.get(key);
|
|
3434
3543
|
if (managed) {
|
|
3435
3544
|
const t = this.now();
|
|
3436
3545
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3437
|
-
await stopClientBestEffort(managed.client);
|
|
3438
3546
|
this.clients.delete(key);
|
|
3547
|
+
await this.tombstoneStop(key, managed.client);
|
|
3439
3548
|
managed = undefined;
|
|
3440
3549
|
}
|
|
3441
3550
|
}
|
|
@@ -3456,15 +3565,21 @@ class LspManager {
|
|
|
3456
3565
|
signal.throwIfAborted();
|
|
3457
3566
|
}
|
|
3458
3567
|
if (!managed.client.isAlive()) {
|
|
3459
|
-
|
|
3460
|
-
this.clients.
|
|
3461
|
-
|
|
3568
|
+
this.recordDeadGeneration(key);
|
|
3569
|
+
if (this.clients.get(key) === managed) {
|
|
3570
|
+
this.clients.delete(key);
|
|
3571
|
+
}
|
|
3572
|
+
await this.tombstoneStop(key, managed.client);
|
|
3573
|
+
return this.getClient(root, server, signal);
|
|
3462
3574
|
}
|
|
3575
|
+
this.markHealthyGeneration(key);
|
|
3463
3576
|
managed.refCount++;
|
|
3464
3577
|
managed.lastUsedAt = this.now();
|
|
3465
3578
|
return managed.client;
|
|
3466
3579
|
}
|
|
3467
|
-
|
|
3580
|
+
this.evictForAdmission();
|
|
3581
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3582
|
+
const client = this.clientFactory(root, server);
|
|
3468
3583
|
const initStartedAt = this.now();
|
|
3469
3584
|
const initPromise = (async () => {
|
|
3470
3585
|
await client.start();
|
|
@@ -3487,7 +3602,7 @@ class LspManager {
|
|
|
3487
3602
|
if (this.clients.get(key) === newManaged) {
|
|
3488
3603
|
this.clients.delete(key);
|
|
3489
3604
|
}
|
|
3490
|
-
await
|
|
3605
|
+
await this.tombstoneStop(key, client);
|
|
3491
3606
|
throw err;
|
|
3492
3607
|
}
|
|
3493
3608
|
newManaged.pendingWaiters--;
|
|
@@ -3498,6 +3613,15 @@ class LspManager {
|
|
|
3498
3613
|
await this.tryDeleteIfOrphaned(key, newManaged);
|
|
3499
3614
|
signal.throwIfAborted();
|
|
3500
3615
|
}
|
|
3616
|
+
if (!client.isAlive()) {
|
|
3617
|
+
this.recordDeadGeneration(key);
|
|
3618
|
+
if (this.clients.get(key) === newManaged) {
|
|
3619
|
+
this.clients.delete(key);
|
|
3620
|
+
}
|
|
3621
|
+
await this.tombstoneStop(key, client);
|
|
3622
|
+
return this.getClient(root, server, signal);
|
|
3623
|
+
}
|
|
3624
|
+
this.markHealthyGeneration(key);
|
|
3501
3625
|
newManaged.refCount++;
|
|
3502
3626
|
newManaged.lastUsedAt = this.now();
|
|
3503
3627
|
return client;
|
|
@@ -3518,15 +3642,21 @@ class LspManager {
|
|
|
3518
3642
|
if (client && managed.client !== client)
|
|
3519
3643
|
return;
|
|
3520
3644
|
this.clients.delete(key);
|
|
3521
|
-
|
|
3645
|
+
this.tombstoneStop(key, managed.client);
|
|
3522
3646
|
}
|
|
3523
|
-
warmupClient(root,
|
|
3647
|
+
warmupClient(root, server) {
|
|
3524
3648
|
if (this.disposed)
|
|
3525
3649
|
return;
|
|
3526
|
-
const key = this.getKey(root,
|
|
3527
|
-
if (this.clients.has(key))
|
|
3650
|
+
const key = this.getKey(root, server.id);
|
|
3651
|
+
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
3528
3652
|
return;
|
|
3529
|
-
|
|
3653
|
+
this.evictForAdmission();
|
|
3654
|
+
try {
|
|
3655
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3656
|
+
} catch {
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
const client = this.clientFactory(root, server);
|
|
3530
3660
|
const initStartedAt = this.now();
|
|
3531
3661
|
const initPromise = (async () => {
|
|
3532
3662
|
await client.start();
|
|
@@ -3551,7 +3681,7 @@ class LspManager {
|
|
|
3551
3681
|
if (this.clients.get(key) === managed) {
|
|
3552
3682
|
this.clients.delete(key);
|
|
3553
3683
|
}
|
|
3554
|
-
|
|
3684
|
+
this.tombstoneStop(key, client);
|
|
3555
3685
|
});
|
|
3556
3686
|
}
|
|
3557
3687
|
isServerInitializing(root, serverId) {
|
|
@@ -3595,8 +3725,11 @@ class LspManager {
|
|
|
3595
3725
|
for (const managed of this.clients.values()) {
|
|
3596
3726
|
stopPromises.push(stopClientBestEffort(managed.client));
|
|
3597
3727
|
}
|
|
3728
|
+
const tombstonedStops = [...this.pendingStops.values()];
|
|
3598
3729
|
this.clients.clear();
|
|
3599
|
-
|
|
3730
|
+
this.respawnBudgets.clear();
|
|
3731
|
+
await Promise.allSettled([...stopPromises, ...tombstonedStops]);
|
|
3732
|
+
this.pendingStops.clear();
|
|
3600
3733
|
}
|
|
3601
3734
|
}
|
|
3602
3735
|
var _defaultInstance = null;
|
|
@@ -3606,49 +3739,43 @@ function getLspManager() {
|
|
|
3606
3739
|
}
|
|
3607
3740
|
return _defaultInstance;
|
|
3608
3741
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3742
|
+
var GIT_WORKSPACE_MARKER = ".git";
|
|
3743
|
+
var PROJECT_WORKSPACE_MARKERS = [
|
|
3744
|
+
"package.json",
|
|
3745
|
+
"pyproject.toml",
|
|
3746
|
+
"Cargo.toml",
|
|
3747
|
+
"go.mod",
|
|
3748
|
+
"pom.xml",
|
|
3749
|
+
"build.gradle"
|
|
3750
|
+
];
|
|
3751
|
+
var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
|
|
3752
|
+
function findWorkspaceRootOutsideContext(directory) {
|
|
3753
|
+
const marked = nearestMarkedAncestor(directory);
|
|
3754
|
+
if (marked !== undefined)
|
|
3755
|
+
return marked;
|
|
3756
|
+
return realpathSync4(nearestExistingAncestor(directory));
|
|
3757
|
+
}
|
|
3758
|
+
function nearestMarkedAncestor(directory) {
|
|
3759
|
+
let current = directory;
|
|
3760
|
+
for (;; ) {
|
|
3761
|
+
if (existsSync7(current) && WORKSPACE_MARKERS.some((marker) => existsSync7(join3(current, marker)))) {
|
|
3762
|
+
return realpathSync4(current);
|
|
3763
|
+
}
|
|
3764
|
+
const parent = dirname7(current);
|
|
3765
|
+
if (parent === current)
|
|
3766
|
+
return;
|
|
3767
|
+
current = parent;
|
|
3621
3768
|
}
|
|
3622
3769
|
}
|
|
3623
|
-
function
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
}
|
|
3631
|
-
|
|
3632
|
-
return value === "declined" || value === "allowed";
|
|
3633
|
-
}
|
|
3634
|
-
function writeInstallDecisions(decisions) {
|
|
3635
|
-
const path2 = getInstallDecisionsPath();
|
|
3636
|
-
mkdirSync3(dirname7(path2), { recursive: true });
|
|
3637
|
-
const tmpPath = `${path2}.tmp`;
|
|
3638
|
-
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3639
|
-
`, "utf8");
|
|
3640
|
-
renameSync2(tmpPath, path2);
|
|
3641
|
-
}
|
|
3642
|
-
function isInstallDecisions(value) {
|
|
3643
|
-
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3644
|
-
}
|
|
3645
|
-
function isInstallDecisionRecord(value) {
|
|
3646
|
-
if (!isRecord5(value))
|
|
3647
|
-
return false;
|
|
3648
|
-
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3649
|
-
}
|
|
3650
|
-
function isRecord5(value) {
|
|
3651
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3770
|
+
function nearestExistingAncestor(directory) {
|
|
3771
|
+
let current = directory;
|
|
3772
|
+
while (!existsSync7(current)) {
|
|
3773
|
+
const parent = dirname7(current);
|
|
3774
|
+
if (parent === current)
|
|
3775
|
+
return current;
|
|
3776
|
+
current = parent;
|
|
3777
|
+
}
|
|
3778
|
+
return current;
|
|
3652
3779
|
}
|
|
3653
3780
|
var LSP_INSTALL_HINTS = {
|
|
3654
3781
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -3694,6 +3821,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
3694
3821
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
3695
3822
|
razor: "Razor runs through the Roslyn language server (cohosting). " + "Install: dotnet tool install -g roslyn-language-server --prerelease (requires v5.8.0+). See https://github.com/dotnet/razor"
|
|
3696
3823
|
};
|
|
3824
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
3825
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
3826
|
+
vue: "bun add -d @vue/language-server",
|
|
3827
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
3828
|
+
oxlint: "bun add -d oxlint",
|
|
3829
|
+
biome: "bun add -d @biomejs/biome",
|
|
3830
|
+
svelte: "bun add -d svelte-language-server",
|
|
3831
|
+
astro: "bun add -d @astrojs/language-server",
|
|
3832
|
+
bash: "bun add -d bash-language-server",
|
|
3833
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
3834
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
3835
|
+
php: "bun add -d intelephense",
|
|
3836
|
+
prisma: "bun add -d prisma",
|
|
3837
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
3838
|
+
pyright: "uv add --dev pyright",
|
|
3839
|
+
basedpyright: "uv add --dev basedpyright",
|
|
3840
|
+
ruff: "uv add --dev ruff",
|
|
3841
|
+
ty: "uv add --dev ty",
|
|
3842
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
3843
|
+
};
|
|
3697
3844
|
var BUILTIN_SERVERS = {
|
|
3698
3845
|
typescript: {
|
|
3699
3846
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -3795,17 +3942,61 @@ var BUILTIN_SERVERS = {
|
|
|
3795
3942
|
extensions: [".razor", ".cshtml"]
|
|
3796
3943
|
}
|
|
3797
3944
|
};
|
|
3945
|
+
function getInstallDecisionsPath() {
|
|
3946
|
+
return lspRequestContext().installDecisionsPath;
|
|
3947
|
+
}
|
|
3948
|
+
function loadInstallDecisions() {
|
|
3949
|
+
const path = getInstallDecisionsPath();
|
|
3950
|
+
if (!existsSync8(path))
|
|
3951
|
+
return {};
|
|
3952
|
+
try {
|
|
3953
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
3954
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
3955
|
+
} catch {
|
|
3956
|
+
return {};
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
function loadInstallDecision(serverId) {
|
|
3960
|
+
return loadInstallDecisions()[serverId];
|
|
3961
|
+
}
|
|
3962
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
3963
|
+
const decisions = loadInstallDecisions();
|
|
3964
|
+
decisions[serverId] = { decision, decidedAt };
|
|
3965
|
+
writeInstallDecisions(decisions);
|
|
3966
|
+
}
|
|
3967
|
+
function isInstallDecision(value) {
|
|
3968
|
+
return value === "declined" || value === "allowed";
|
|
3969
|
+
}
|
|
3970
|
+
function writeInstallDecisions(decisions) {
|
|
3971
|
+
const path = getInstallDecisionsPath();
|
|
3972
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
3973
|
+
const tmpPath = `${path}.tmp`;
|
|
3974
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3975
|
+
`, "utf8");
|
|
3976
|
+
renameSync2(tmpPath, path);
|
|
3977
|
+
}
|
|
3978
|
+
function isInstallDecisions(value) {
|
|
3979
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3980
|
+
}
|
|
3981
|
+
function isInstallDecisionRecord(value) {
|
|
3982
|
+
if (!isRecord5(value))
|
|
3983
|
+
return false;
|
|
3984
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3985
|
+
}
|
|
3986
|
+
function isRecord5(value) {
|
|
3987
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3988
|
+
}
|
|
3798
3989
|
function getProjectConfigPaths() {
|
|
3799
3990
|
return lspRequestContext().projectConfigPaths;
|
|
3800
3991
|
}
|
|
3801
3992
|
function getUserConfigPath() {
|
|
3802
3993
|
return lspRequestContext().userConfigPath;
|
|
3803
3994
|
}
|
|
3804
|
-
function loadJsonFile(
|
|
3805
|
-
if (!
|
|
3995
|
+
function loadJsonFile(path) {
|
|
3996
|
+
if (!existsSync9(path))
|
|
3806
3997
|
return null;
|
|
3807
3998
|
try {
|
|
3808
|
-
const parsed = JSON.parse(readFileSync5(
|
|
3999
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
3809
4000
|
return isConfigJson(parsed) ? parsed : null;
|
|
3810
4001
|
} catch {
|
|
3811
4002
|
return null;
|
|
@@ -3822,8 +4013,8 @@ function loadAllConfigs() {
|
|
|
3822
4013
|
return configs;
|
|
3823
4014
|
}
|
|
3824
4015
|
function loadFirstJsonFile(paths) {
|
|
3825
|
-
for (const
|
|
3826
|
-
const config = loadJsonFile(
|
|
4016
|
+
for (const path of paths) {
|
|
4017
|
+
const config = loadJsonFile(path);
|
|
3827
4018
|
if (config)
|
|
3828
4019
|
return config;
|
|
3829
4020
|
}
|
|
@@ -3849,10 +4040,10 @@ function getMergedServers() {
|
|
|
3849
4040
|
}
|
|
3850
4041
|
if (seen.has(id))
|
|
3851
4042
|
continue;
|
|
3852
|
-
const
|
|
3853
|
-
if (!
|
|
4043
|
+
const server = createServerFromEntry(id, entry, source);
|
|
4044
|
+
if (!server)
|
|
3854
4045
|
continue;
|
|
3855
|
-
servers.push(
|
|
4046
|
+
servers.push(server);
|
|
3856
4047
|
seen.add(id);
|
|
3857
4048
|
}
|
|
3858
4049
|
}
|
|
@@ -3884,7 +4075,7 @@ function createServerFromEntry(id, entry, source) {
|
|
|
3884
4075
|
if (source === "project") {
|
|
3885
4076
|
if (!builtin)
|
|
3886
4077
|
return null;
|
|
3887
|
-
const
|
|
4078
|
+
const server = createServer({
|
|
3888
4079
|
id,
|
|
3889
4080
|
command: builtin.command,
|
|
3890
4081
|
extensions: entry.extensions ?? builtin.extensions,
|
|
@@ -3892,35 +4083,35 @@ function createServerFromEntry(id, entry, source) {
|
|
|
3892
4083
|
source
|
|
3893
4084
|
});
|
|
3894
4085
|
if (entry.initialization !== undefined) {
|
|
3895
|
-
|
|
4086
|
+
server.initialization = entry.initialization;
|
|
3896
4087
|
}
|
|
3897
|
-
return
|
|
4088
|
+
return server;
|
|
3898
4089
|
}
|
|
3899
4090
|
if (entry.command && entry.extensions) {
|
|
3900
|
-
const
|
|
4091
|
+
const server = createServer({
|
|
3901
4092
|
id,
|
|
3902
4093
|
command: entry.command,
|
|
3903
4094
|
extensions: entry.extensions,
|
|
3904
4095
|
priority: entry.priority ?? 0,
|
|
3905
4096
|
source
|
|
3906
4097
|
});
|
|
3907
|
-
applyOptionalServerFields(
|
|
3908
|
-
return
|
|
4098
|
+
applyOptionalServerFields(server, entry);
|
|
4099
|
+
return server;
|
|
3909
4100
|
}
|
|
3910
4101
|
if (!builtin)
|
|
3911
4102
|
return null;
|
|
3912
|
-
const
|
|
4103
|
+
const server = createServer({
|
|
3913
4104
|
id,
|
|
3914
4105
|
command: entry.command ?? builtin.command,
|
|
3915
4106
|
extensions: entry.extensions ?? builtin.extensions,
|
|
3916
4107
|
priority: entry.priority ?? 0,
|
|
3917
4108
|
source
|
|
3918
4109
|
});
|
|
3919
|
-
applyOptionalServerFields(
|
|
3920
|
-
return
|
|
4110
|
+
applyOptionalServerFields(server, entry);
|
|
4111
|
+
return server;
|
|
3921
4112
|
}
|
|
3922
4113
|
function createServer(input) {
|
|
3923
|
-
const
|
|
4114
|
+
const server = {
|
|
3924
4115
|
id: input.id,
|
|
3925
4116
|
command: input.command,
|
|
3926
4117
|
extensions: input.extensions,
|
|
@@ -3928,19 +4119,19 @@ function createServer(input) {
|
|
|
3928
4119
|
source: input.source
|
|
3929
4120
|
};
|
|
3930
4121
|
if (input.env !== undefined) {
|
|
3931
|
-
|
|
4122
|
+
server.env = input.env;
|
|
3932
4123
|
}
|
|
3933
4124
|
if (input.initialization !== undefined) {
|
|
3934
|
-
|
|
4125
|
+
server.initialization = input.initialization;
|
|
3935
4126
|
}
|
|
3936
|
-
return
|
|
4127
|
+
return server;
|
|
3937
4128
|
}
|
|
3938
|
-
function applyOptionalServerFields(
|
|
4129
|
+
function applyOptionalServerFields(server, entry) {
|
|
3939
4130
|
if (entry.env !== undefined) {
|
|
3940
|
-
|
|
4131
|
+
server.env = entry.env;
|
|
3941
4132
|
}
|
|
3942
4133
|
if (entry.initialization !== undefined) {
|
|
3943
|
-
|
|
4134
|
+
server.initialization = entry.initialization;
|
|
3944
4135
|
}
|
|
3945
4136
|
}
|
|
3946
4137
|
function isConfigJson(value) {
|
|
@@ -3988,60 +4179,161 @@ function getDisabledServerIds() {
|
|
|
3988
4179
|
}
|
|
3989
4180
|
return disabled;
|
|
3990
4181
|
}
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4182
|
+
var LOCAL_BIN_RULES = [
|
|
4183
|
+
{
|
|
4184
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
4185
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
4186
|
+
},
|
|
4187
|
+
{
|
|
4188
|
+
markers: [
|
|
4189
|
+
"pyproject.toml",
|
|
4190
|
+
"ty.toml",
|
|
4191
|
+
"requirements.txt",
|
|
4192
|
+
"setup.py",
|
|
4193
|
+
"setup.cfg",
|
|
4194
|
+
"Pipfile",
|
|
4195
|
+
"pyrightconfig.json",
|
|
4196
|
+
"ruff.toml",
|
|
4197
|
+
".ruff.toml"
|
|
4198
|
+
],
|
|
4199
|
+
binDirs: [
|
|
4200
|
+
join4(".venv", "bin"),
|
|
4201
|
+
join4(".venv", "Scripts"),
|
|
4202
|
+
join4("venv", "bin"),
|
|
4203
|
+
join4("venv", "Scripts"),
|
|
4204
|
+
join4(".env", "bin"),
|
|
4205
|
+
join4(".env", "Scripts")
|
|
4206
|
+
]
|
|
4207
|
+
},
|
|
4208
|
+
{
|
|
4209
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
4210
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
4211
|
+
},
|
|
4212
|
+
{
|
|
4213
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
4214
|
+
binDirs: ["bin"]
|
|
4000
4215
|
}
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4216
|
+
];
|
|
4217
|
+
var resolutionCache = new Map;
|
|
4218
|
+
var probeCount = 0;
|
|
4219
|
+
function probe(path) {
|
|
4220
|
+
probeCount += 1;
|
|
4221
|
+
return existsSync10(path);
|
|
4222
|
+
}
|
|
4223
|
+
function executableSuffixes(platform, pathExt) {
|
|
4224
|
+
if (platform !== "win32")
|
|
4225
|
+
return [""];
|
|
4226
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
4227
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
4228
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
4229
|
+
}
|
|
4230
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
4231
|
+
for (const suffix of suffixes) {
|
|
4232
|
+
const candidate = join4(directory, command + suffix);
|
|
4233
|
+
if (probe(candidate))
|
|
4234
|
+
return candidate;
|
|
4235
|
+
}
|
|
4236
|
+
return null;
|
|
4237
|
+
}
|
|
4238
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
4239
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
4240
|
+
let current = resolve7(workingDirectory);
|
|
4241
|
+
while (true) {
|
|
4242
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
4243
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
4244
|
+
continue;
|
|
4245
|
+
for (const binDir of rule.binDirs) {
|
|
4246
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
4247
|
+
if (found !== null)
|
|
4248
|
+
return found;
|
|
4249
|
+
}
|
|
4010
4250
|
}
|
|
4251
|
+
if (probe(join4(current, ".git")))
|
|
4252
|
+
return null;
|
|
4253
|
+
if (boundary !== undefined && current === boundary)
|
|
4254
|
+
return null;
|
|
4255
|
+
const parent = dirname9(current);
|
|
4256
|
+
if (parent === current)
|
|
4257
|
+
return null;
|
|
4258
|
+
current = parent;
|
|
4011
4259
|
}
|
|
4012
|
-
|
|
4013
|
-
|
|
4260
|
+
}
|
|
4261
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
4262
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
4263
|
+
if (platform === "win32" && !pathEnv) {
|
|
4014
4264
|
pathEnv = process.env["Path"] ?? "";
|
|
4015
4265
|
}
|
|
4016
|
-
const
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
}
|
|
4266
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
4267
|
+
if (entry.length === 0)
|
|
4268
|
+
continue;
|
|
4269
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
4270
|
+
if (found !== null)
|
|
4271
|
+
return found;
|
|
4023
4272
|
}
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4273
|
+
return null;
|
|
4274
|
+
}
|
|
4275
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
4276
|
+
if (command.length === 0)
|
|
4277
|
+
return null;
|
|
4278
|
+
const [cmd] = command;
|
|
4279
|
+
if (cmd === undefined || cmd.length === 0)
|
|
4280
|
+
return null;
|
|
4281
|
+
const platform = options.platform ?? process.platform;
|
|
4282
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
4283
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
4284
|
+
const explicit = isAbsolute5(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
4285
|
+
return probe(explicit) ? explicit : null;
|
|
4286
|
+
}
|
|
4287
|
+
const cacheKey = JSON.stringify([
|
|
4288
|
+
workingDirectory ?? "",
|
|
4289
|
+
cmd,
|
|
4290
|
+
platform,
|
|
4291
|
+
options.stopAt ?? "",
|
|
4292
|
+
options.pathExt ?? "",
|
|
4293
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
4294
|
+
]);
|
|
4295
|
+
const cached = resolutionCache.get(cacheKey);
|
|
4296
|
+
if (cached !== undefined)
|
|
4297
|
+
return cached;
|
|
4298
|
+
let resolved = null;
|
|
4299
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
4300
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
4301
|
+
}
|
|
4302
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
4303
|
+
if (resolved === null && cmd === "node")
|
|
4304
|
+
resolved = cmd;
|
|
4305
|
+
resolutionCache.set(cacheKey, resolved);
|
|
4306
|
+
return resolved;
|
|
4307
|
+
}
|
|
4308
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
4309
|
+
if (command.length === 0)
|
|
4310
|
+
return false;
|
|
4311
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
4312
|
+
}
|
|
4313
|
+
function withResolvedCommand(command, binaryPath) {
|
|
4314
|
+
return [binaryPath, ...command.slice(1)];
|
|
4027
4315
|
}
|
|
4028
4316
|
function findServerForExtension(ext) {
|
|
4029
4317
|
const servers = getMergedServers();
|
|
4030
|
-
|
|
4031
|
-
|
|
4318
|
+
const workingDirectory = contextCwd();
|
|
4319
|
+
for (const server of servers) {
|
|
4320
|
+
if (!server.extensions.includes(ext))
|
|
4321
|
+
continue;
|
|
4322
|
+
const binaryPath = resolveServerBinary(server.command, workingDirectory);
|
|
4323
|
+
if (binaryPath !== null) {
|
|
4032
4324
|
const resolvedServer = {
|
|
4033
|
-
id:
|
|
4034
|
-
command:
|
|
4035
|
-
extensions:
|
|
4036
|
-
priority:
|
|
4325
|
+
id: server.id,
|
|
4326
|
+
command: withResolvedCommand(server.command, binaryPath),
|
|
4327
|
+
extensions: server.extensions,
|
|
4328
|
+
priority: server.priority
|
|
4037
4329
|
};
|
|
4038
|
-
if (
|
|
4330
|
+
if (server.env !== undefined) {
|
|
4039
4331
|
return {
|
|
4040
4332
|
status: "found",
|
|
4041
4333
|
server: {
|
|
4042
4334
|
...resolvedServer,
|
|
4043
|
-
env:
|
|
4044
|
-
...
|
|
4335
|
+
env: server.env,
|
|
4336
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4045
4337
|
}
|
|
4046
4338
|
};
|
|
4047
4339
|
}
|
|
@@ -4049,20 +4341,20 @@ function findServerForExtension(ext) {
|
|
|
4049
4341
|
status: "found",
|
|
4050
4342
|
server: {
|
|
4051
4343
|
...resolvedServer,
|
|
4052
|
-
...
|
|
4344
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4053
4345
|
}
|
|
4054
4346
|
};
|
|
4055
4347
|
}
|
|
4056
4348
|
}
|
|
4057
|
-
for (const
|
|
4058
|
-
if (
|
|
4059
|
-
const installHint = LSP_INSTALL_HINTS[
|
|
4349
|
+
for (const server of servers) {
|
|
4350
|
+
if (server.extensions.includes(ext)) {
|
|
4351
|
+
const installHint = LSP_INSTALL_HINTS[server.id] ?? `Install '${server.command[0]}' and ensure it's in your PATH`;
|
|
4060
4352
|
return {
|
|
4061
4353
|
status: "not_installed",
|
|
4062
4354
|
server: {
|
|
4063
|
-
id:
|
|
4064
|
-
command:
|
|
4065
|
-
extensions:
|
|
4355
|
+
id: server.id,
|
|
4356
|
+
command: server.command,
|
|
4357
|
+
extensions: server.extensions
|
|
4066
4358
|
},
|
|
4067
4359
|
installHint
|
|
4068
4360
|
};
|
|
@@ -4078,20 +4370,21 @@ function findServerForExtension(ext) {
|
|
|
4078
4370
|
function getAllServers() {
|
|
4079
4371
|
const servers = getMergedServers();
|
|
4080
4372
|
const disabled = getDisabledServerIds();
|
|
4373
|
+
const workingDirectory = contextCwd();
|
|
4081
4374
|
const result = [];
|
|
4082
4375
|
const seen = new Set;
|
|
4083
|
-
for (const
|
|
4084
|
-
if (seen.has(
|
|
4376
|
+
for (const server of servers) {
|
|
4377
|
+
if (seen.has(server.id))
|
|
4085
4378
|
continue;
|
|
4086
4379
|
result.push({
|
|
4087
|
-
id:
|
|
4088
|
-
installed: isServerInstalled(
|
|
4089
|
-
extensions:
|
|
4380
|
+
id: server.id,
|
|
4381
|
+
installed: isServerInstalled(server.command, workingDirectory),
|
|
4382
|
+
extensions: server.extensions,
|
|
4090
4383
|
disabled: false,
|
|
4091
|
-
source:
|
|
4092
|
-
priority:
|
|
4384
|
+
source: server.source,
|
|
4385
|
+
priority: server.priority
|
|
4093
4386
|
});
|
|
4094
|
-
seen.add(
|
|
4387
|
+
seen.add(server.id);
|
|
4095
4388
|
}
|
|
4096
4389
|
for (const id of disabled) {
|
|
4097
4390
|
if (seen.has(id))
|
|
@@ -4099,7 +4392,7 @@ function getAllServers() {
|
|
|
4099
4392
|
const builtin = BUILTIN_SERVERS[id];
|
|
4100
4393
|
result.push({
|
|
4101
4394
|
id,
|
|
4102
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
4395
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
4103
4396
|
extensions: builtin?.extensions ?? [],
|
|
4104
4397
|
disabled: true,
|
|
4105
4398
|
source: "disabled",
|
|
@@ -4108,7 +4401,6 @@ function getAllServers() {
|
|
|
4108
4401
|
}
|
|
4109
4402
|
return result;
|
|
4110
4403
|
}
|
|
4111
|
-
var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
4112
4404
|
function isDirectoryPath(filePath) {
|
|
4113
4405
|
try {
|
|
4114
4406
|
return statSync4(filePath).isDirectory();
|
|
@@ -4117,32 +4409,90 @@ function isDirectoryPath(filePath) {
|
|
|
4117
4409
|
}
|
|
4118
4410
|
}
|
|
4119
4411
|
function findWorkspaceRoot(filePath) {
|
|
4120
|
-
const
|
|
4412
|
+
const cwd = contextCwd();
|
|
4413
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4121
4414
|
let dir = abs;
|
|
4122
4415
|
if (!isDirectoryPath(dir)) {
|
|
4123
|
-
dir =
|
|
4124
|
-
}
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4416
|
+
dir = dirname10(dir);
|
|
4417
|
+
}
|
|
4418
|
+
if (!isPathInside(cwd, abs))
|
|
4419
|
+
return findWorkspaceRootOutsideContext(dir);
|
|
4420
|
+
const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
|
|
4421
|
+
let nearestPackageRoot;
|
|
4422
|
+
while (isPathInside(cwd, dir)) {
|
|
4423
|
+
const canonicalDir = existingDirectoryInsideContext(dir, cwd);
|
|
4424
|
+
if (canonicalDir !== undefined) {
|
|
4425
|
+
if (existsSync11(join5(dir, GIT_WORKSPACE_MARKER))) {
|
|
4426
|
+
return canonicalDir;
|
|
4427
|
+
}
|
|
4428
|
+
if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
|
|
4429
|
+
nearestPackageRoot = canonicalDir;
|
|
4130
4430
|
}
|
|
4131
4431
|
}
|
|
4132
|
-
|
|
4133
|
-
|
|
4432
|
+
if (dir === cwd)
|
|
4433
|
+
break;
|
|
4434
|
+
dir = dirname10(dir);
|
|
4134
4435
|
}
|
|
4135
|
-
return
|
|
4436
|
+
return nearestPackageRoot ?? fallbackRoot;
|
|
4437
|
+
}
|
|
4438
|
+
function hasProjectWorkspaceMarker(directory) {
|
|
4439
|
+
return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync11(join5(directory, marker)));
|
|
4440
|
+
}
|
|
4441
|
+
function resolveReadablePathInsideContext(filePath) {
|
|
4442
|
+
const cwd = contextCwd();
|
|
4443
|
+
const abs = resolve8(cwd, filePath);
|
|
4444
|
+
if (isPathInside(cwd, abs))
|
|
4445
|
+
return abs;
|
|
4446
|
+
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
4447
|
+
if (rebased !== undefined)
|
|
4448
|
+
return rebased;
|
|
4449
|
+
return canonicalizeExistingOrNearestAncestor(abs);
|
|
4136
4450
|
}
|
|
4137
4451
|
function resolvePathInsideContext(filePath) {
|
|
4138
4452
|
const cwd = contextCwd();
|
|
4139
|
-
const abs =
|
|
4453
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4140
4454
|
const canonical = canonicalizeExistingOrNearestAncestor(abs);
|
|
4141
4455
|
if (!isPathInside(cwd, canonical)) {
|
|
4142
4456
|
throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
|
|
4143
4457
|
}
|
|
4144
4458
|
return canonical;
|
|
4145
4459
|
}
|
|
4460
|
+
function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
4461
|
+
let current = path;
|
|
4462
|
+
const suffix = [];
|
|
4463
|
+
while (true) {
|
|
4464
|
+
if (existsSync11(current)) {
|
|
4465
|
+
const canonical = realpathSync5(current);
|
|
4466
|
+
if (isPathInside(cwd, canonical))
|
|
4467
|
+
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
4468
|
+
}
|
|
4469
|
+
const parent = dirname10(current);
|
|
4470
|
+
if (parent === current)
|
|
4471
|
+
return;
|
|
4472
|
+
suffix.unshift(basename3(current));
|
|
4473
|
+
current = parent;
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
function existingDirectoryInsideContext(directory, cwd) {
|
|
4477
|
+
if (!existsSync11(directory))
|
|
4478
|
+
return;
|
|
4479
|
+
const canonical = realpathSync5(directory);
|
|
4480
|
+
if (!statSync4(canonical).isDirectory())
|
|
4481
|
+
return;
|
|
4482
|
+
return isPathInside(cwd, canonical) ? canonical : undefined;
|
|
4483
|
+
}
|
|
4484
|
+
function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
4485
|
+
let current = directory;
|
|
4486
|
+
while (isPathInside(cwd, current)) {
|
|
4487
|
+
const canonical = existingDirectoryInsideContext(current, cwd);
|
|
4488
|
+
if (canonical !== undefined)
|
|
4489
|
+
return canonical;
|
|
4490
|
+
if (current === cwd)
|
|
4491
|
+
return;
|
|
4492
|
+
current = dirname10(current);
|
|
4493
|
+
}
|
|
4494
|
+
return;
|
|
4495
|
+
}
|
|
4146
4496
|
function formatServerLookupError(result) {
|
|
4147
4497
|
if (result.status === "not_installed") {
|
|
4148
4498
|
return formatNotInstalled(result);
|
|
@@ -4166,33 +4516,46 @@ function formatServerLookupError(result) {
|
|
|
4166
4516
|
].join(`
|
|
4167
4517
|
`);
|
|
4168
4518
|
}
|
|
4519
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4520
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4521
|
+
if (localHint === undefined) {
|
|
4522
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4523
|
+
}
|
|
4524
|
+
return [
|
|
4525
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4526
|
+
` ${localHint}`,
|
|
4527
|
+
"",
|
|
4528
|
+
"Or install it globally:",
|
|
4529
|
+
` ${installHint}`
|
|
4530
|
+
];
|
|
4531
|
+
}
|
|
4169
4532
|
function formatNotInstalled(result) {
|
|
4170
|
-
const { server
|
|
4171
|
-
const extensions =
|
|
4172
|
-
const decision = loadInstallDecision(
|
|
4533
|
+
const { server, installHint } = result;
|
|
4534
|
+
const extensions = server.extensions.join(", ");
|
|
4535
|
+
const decision = loadInstallDecision(server.id)?.decision;
|
|
4173
4536
|
const context = lspRequestContext();
|
|
4174
4537
|
if (decision === "declined") {
|
|
4175
|
-
return `LSP server '${
|
|
4538
|
+
return `LSP server '${server.id}' (${extensions}) is NOT INSTALLED; user previously declined installation — proceed without LSP.`;
|
|
4176
4539
|
}
|
|
4177
4540
|
const header = [
|
|
4178
|
-
`LSP server '${
|
|
4541
|
+
`LSP server '${server.id}' for ${extensions} is NOT INSTALLED.`,
|
|
4179
4542
|
"",
|
|
4180
|
-
`Command not found: ${
|
|
4543
|
+
`Command not found: ${server.command[0]}`,
|
|
4181
4544
|
""
|
|
4182
4545
|
];
|
|
4546
|
+
const installOptions = formatInstallOptions(server.id, installHint);
|
|
4183
4547
|
if (decision === "allowed") {
|
|
4184
4548
|
return [
|
|
4185
4549
|
...header,
|
|
4186
4550
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
4187
|
-
|
|
4551
|
+
...installOptions.slice(1)
|
|
4188
4552
|
].join(`
|
|
4189
4553
|
`);
|
|
4190
4554
|
}
|
|
4191
4555
|
if (!context.capabilities.installDecisionTool) {
|
|
4192
4556
|
return [
|
|
4193
4557
|
...header,
|
|
4194
|
-
|
|
4195
|
-
` ${installHint}`,
|
|
4558
|
+
...installOptions,
|
|
4196
4559
|
"",
|
|
4197
4560
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4198
4561
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -4201,19 +4564,18 @@ function formatNotInstalled(result) {
|
|
|
4201
4564
|
}
|
|
4202
4565
|
return [
|
|
4203
4566
|
...header,
|
|
4204
|
-
|
|
4205
|
-
` ${installHint}`,
|
|
4567
|
+
...installOptions,
|
|
4206
4568
|
"",
|
|
4207
4569
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4208
4570
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
4209
4571
|
"- If the user declines, OR has NOT explicitly asked for LSP installation:",
|
|
4210
|
-
` call lsp_install_decision { server_id: "${
|
|
4572
|
+
` call lsp_install_decision { server_id: "${server.id}", decision: "declined" },`,
|
|
4211
4573
|
` which writes to ${context.installDecisionsPath},`,
|
|
4212
4574
|
" then ignore this message and proceed WITHOUT LSP."
|
|
4213
4575
|
].join(`
|
|
4214
4576
|
`);
|
|
4215
4577
|
}
|
|
4216
|
-
var
|
|
4578
|
+
var READ_ONLY_TOOLS = new Set([
|
|
4217
4579
|
"diagnostics",
|
|
4218
4580
|
"definition",
|
|
4219
4581
|
"references",
|
|
@@ -4222,7 +4584,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
|
|
|
4222
4584
|
"prepareRename"
|
|
4223
4585
|
]);
|
|
4224
4586
|
async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
4225
|
-
const absPath = resolvePathInsideContext(filePath);
|
|
4587
|
+
const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
|
|
4226
4588
|
if (isDirectoryPath(absPath)) {
|
|
4227
4589
|
throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
|
|
4228
4590
|
}
|
|
@@ -4231,26 +4593,26 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4231
4593
|
if (result.status !== "found") {
|
|
4232
4594
|
throw new LspServerLookupError(formatServerLookupError(result), result);
|
|
4233
4595
|
}
|
|
4234
|
-
const
|
|
4596
|
+
const server = result.server;
|
|
4235
4597
|
const root = findWorkspaceRoot(absPath);
|
|
4236
4598
|
const manager = options.manager ?? getLspManager();
|
|
4237
4599
|
const acquireAndCall = async (allowRetry) => {
|
|
4238
|
-
const client = await manager.getClient(root,
|
|
4600
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4239
4601
|
try {
|
|
4240
|
-
return await fn(client, root);
|
|
4602
|
+
return await fn(client, root, absPath);
|
|
4241
4603
|
} catch (err) {
|
|
4242
|
-
if (allowRetry &&
|
|
4243
|
-
manager.invalidateClient(root,
|
|
4604
|
+
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
4605
|
+
manager.invalidateClient(root, server.id, client);
|
|
4244
4606
|
return acquireAndCall(false);
|
|
4245
4607
|
}
|
|
4246
4608
|
if (err instanceof LspRequestTimeoutError) {
|
|
4247
|
-
if (manager.isServerInitializing(root,
|
|
4609
|
+
if (manager.isServerInitializing(root, server.id)) {
|
|
4248
4610
|
throw new LspServerInitializingError(err);
|
|
4249
4611
|
}
|
|
4250
4612
|
}
|
|
4251
4613
|
throw err;
|
|
4252
4614
|
} finally {
|
|
4253
|
-
manager.releaseClient(root,
|
|
4615
|
+
manager.releaseClient(root, server.id);
|
|
4254
4616
|
}
|
|
4255
4617
|
};
|
|
4256
4618
|
return acquireAndCall(true);
|
|
@@ -4266,10 +4628,10 @@ function uriToPath(uri) {
|
|
|
4266
4628
|
}
|
|
4267
4629
|
function formatLocation(loc) {
|
|
4268
4630
|
if ("targetUri" in loc) {
|
|
4269
|
-
const
|
|
4270
|
-
const
|
|
4271
|
-
const
|
|
4272
|
-
return `${
|
|
4631
|
+
const uri = uriToPath(loc.targetUri);
|
|
4632
|
+
const line = loc.targetRange.start.line + 1;
|
|
4633
|
+
const char = loc.targetRange.start.character;
|
|
4634
|
+
return `${uri}:${line}:${char}`;
|
|
4273
4635
|
}
|
|
4274
4636
|
const uri = uriToPath(loc.uri);
|
|
4275
4637
|
const line = loc.range.start.line + 1;
|
|
@@ -4379,7 +4741,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
4379
4741
|
for (const entry of entries) {
|
|
4380
4742
|
if (files.length >= maxFiles)
|
|
4381
4743
|
return;
|
|
4382
|
-
const fullPath =
|
|
4744
|
+
const fullPath = join6(currentDir, entry);
|
|
4383
4745
|
let stat;
|
|
4384
4746
|
try {
|
|
4385
4747
|
stat = lstatSync5(fullPath);
|
|
@@ -4404,15 +4766,15 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4404
4766
|
if (!extension.startsWith(".")) {
|
|
4405
4767
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
4406
4768
|
}
|
|
4407
|
-
const absDir =
|
|
4408
|
-
if (!
|
|
4769
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
4770
|
+
if (!existsSync12(absDir)) {
|
|
4409
4771
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
4410
4772
|
}
|
|
4411
4773
|
const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
|
|
4412
4774
|
if (serverResult.status !== "found") {
|
|
4413
4775
|
throw new LspServerLookupError(formatServerLookupError(serverResult));
|
|
4414
4776
|
}
|
|
4415
|
-
const
|
|
4777
|
+
const server = serverResult.server;
|
|
4416
4778
|
const allFiles = (options.listFiles ?? collectFilesWithExtension)(absDir, extension, maxFiles + 1);
|
|
4417
4779
|
const wasCapped = allFiles.length > maxFiles;
|
|
4418
4780
|
const filesToProcess = allFiles.slice(0, maxFiles);
|
|
@@ -4432,7 +4794,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4432
4794
|
const fileErrors = [];
|
|
4433
4795
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4434
4796
|
options.signal?.throwIfAborted();
|
|
4435
|
-
const client = await manager.getClient(root,
|
|
4797
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4436
4798
|
try {
|
|
4437
4799
|
let nextIndex = 0;
|
|
4438
4800
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -4460,7 +4822,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4460
4822
|
});
|
|
4461
4823
|
await Promise.all(workers);
|
|
4462
4824
|
} finally {
|
|
4463
|
-
manager.releaseClient(root,
|
|
4825
|
+
manager.releaseClient(root, server.id);
|
|
4464
4826
|
}
|
|
4465
4827
|
const displayDiagnostics = allDiagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS);
|
|
4466
4828
|
const wasDiagCapped = allDiagnostics.length > DEFAULT_MAX_DIAGNOSTICS;
|
|
@@ -4506,7 +4868,7 @@ function inferExtensionFromDirectory(directory) {
|
|
|
4506
4868
|
for (const entry of entries) {
|
|
4507
4869
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
4508
4870
|
return;
|
|
4509
|
-
const fullPath =
|
|
4871
|
+
const fullPath = join7(dir, entry);
|
|
4510
4872
|
let stat;
|
|
4511
4873
|
try {
|
|
4512
4874
|
stat = lstatSync6(fullPath);
|
|
@@ -4655,8 +5017,8 @@ function severityFilter(params) {
|
|
|
4655
5017
|
function clientOptions(signal) {
|
|
4656
5018
|
return signal === undefined ? {} : { signal };
|
|
4657
5019
|
}
|
|
4658
|
-
function text(
|
|
4659
|
-
return { content: [{ type: "text", text
|
|
5020
|
+
function text(text, details, isError = false) {
|
|
5021
|
+
return { content: [{ type: "text", text }], details, isError };
|
|
4660
5022
|
}
|
|
4661
5023
|
function asDiagnosticArray(result) {
|
|
4662
5024
|
if (!result)
|
|
@@ -4669,12 +5031,12 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4669
5031
|
const filePath = requireString(params, "filePath");
|
|
4670
5032
|
const severity = severityFilter(params);
|
|
4671
5033
|
try {
|
|
4672
|
-
const absPath =
|
|
5034
|
+
const absPath = resolveReadablePathInsideContext(filePath);
|
|
4673
5035
|
if (isDirectoryPath(absPath)) {
|
|
4674
5036
|
const extension = inferExtensionFromDirectory(absPath);
|
|
4675
5037
|
if (!extension) {
|
|
4676
5038
|
const message = `No supported source files found in directory: ${absPath}`;
|
|
4677
|
-
const
|
|
5039
|
+
const details = {
|
|
4678
5040
|
filePath,
|
|
4679
5041
|
severity,
|
|
4680
5042
|
mode: "directory",
|
|
@@ -4684,24 +5046,24 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4684
5046
|
error: message,
|
|
4685
5047
|
errorKind: "no_files"
|
|
4686
5048
|
};
|
|
4687
|
-
return text(message,
|
|
5049
|
+
return text(message, details);
|
|
4688
5050
|
}
|
|
4689
|
-
const
|
|
4690
|
-
const
|
|
5051
|
+
const output = await aggregateDiagnosticsForDirectory(absPath, extension, severity, undefined, signal === undefined ? {} : { signal });
|
|
5052
|
+
const details = {
|
|
4691
5053
|
filePath,
|
|
4692
5054
|
severity,
|
|
4693
5055
|
mode: "directory",
|
|
4694
5056
|
diagnostics: [],
|
|
4695
|
-
totalDiagnostics:
|
|
5057
|
+
totalDiagnostics: output.totalDiagnostics,
|
|
4696
5058
|
truncated: false,
|
|
4697
|
-
fileFailures: [...
|
|
5059
|
+
fileFailures: [...output.fileFailures]
|
|
4698
5060
|
};
|
|
4699
|
-
return text(
|
|
5061
|
+
return text(output.output, details);
|
|
4700
5062
|
}
|
|
4701
|
-
const result = await withLspClient(filePath, async (client) => client.diagnostics(
|
|
5063
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
4702
5064
|
if (result.transientError) {
|
|
4703
5065
|
const message = result.transientError.message;
|
|
4704
|
-
const
|
|
5066
|
+
const details = {
|
|
4705
5067
|
filePath,
|
|
4706
5068
|
severity,
|
|
4707
5069
|
mode: "file",
|
|
@@ -4711,7 +5073,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4711
5073
|
error: message,
|
|
4712
5074
|
errorKind: result.transientError.kind
|
|
4713
5075
|
};
|
|
4714
|
-
return text(message,
|
|
5076
|
+
return text(message, details, true);
|
|
4715
5077
|
}
|
|
4716
5078
|
const diagnostics = filterDiagnosticsBySeverity(asDiagnosticArray(result), severity);
|
|
4717
5079
|
const total = diagnostics.length;
|
|
@@ -4745,13 +5107,98 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4745
5107
|
throw error;
|
|
4746
5108
|
}
|
|
4747
5109
|
}
|
|
5110
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
5111
|
+
tabSize: 4,
|
|
5112
|
+
insertSpaces: false,
|
|
5113
|
+
trimTrailingWhitespace: true,
|
|
5114
|
+
insertFinalNewline: true,
|
|
5115
|
+
trimFinalNewlines: true
|
|
5116
|
+
};
|
|
5117
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
5118
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
5119
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
5120
|
+
if (edits === null)
|
|
5121
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
5122
|
+
if (edits.length === 0)
|
|
5123
|
+
return UNCHANGED;
|
|
5124
|
+
const before = readFileSync6(filePath, "utf-8");
|
|
5125
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
5126
|
+
if (normalized.text === before)
|
|
5127
|
+
return UNCHANGED;
|
|
5128
|
+
writeAtomically(filePath, normalized.text);
|
|
5129
|
+
await client.openFile(filePath);
|
|
5130
|
+
return {
|
|
5131
|
+
status: "formatted",
|
|
5132
|
+
...lineDelta(normalized.edits)
|
|
5133
|
+
};
|
|
5134
|
+
}
|
|
5135
|
+
function lineDelta(edits) {
|
|
5136
|
+
let linesAdded = 0;
|
|
5137
|
+
let linesRemoved = 0;
|
|
5138
|
+
for (const edit of edits) {
|
|
5139
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
5140
|
+
linesAdded += edit.newText.split(`
|
|
5141
|
+
`).length;
|
|
5142
|
+
}
|
|
5143
|
+
return { linesAdded, linesRemoved };
|
|
5144
|
+
}
|
|
5145
|
+
function writeAtomically(filePath, content) {
|
|
5146
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
5147
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
5148
|
+
try {
|
|
5149
|
+
renameSync3(tempPath, filePath);
|
|
5150
|
+
} catch (error) {
|
|
5151
|
+
try {
|
|
5152
|
+
unlinkSync2(tempPath);
|
|
5153
|
+
} catch {}
|
|
5154
|
+
throw error;
|
|
5155
|
+
}
|
|
5156
|
+
}
|
|
5157
|
+
async function executeLspFormat(params, signal) {
|
|
5158
|
+
const filePath = requireString(params, "filePath");
|
|
5159
|
+
try {
|
|
5160
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
5161
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
5162
|
+
} catch (error) {
|
|
5163
|
+
const missingDependency = missingDependencyResult(error, {
|
|
5164
|
+
filePath,
|
|
5165
|
+
status: "unavailable",
|
|
5166
|
+
reason: "server_unavailable",
|
|
5167
|
+
linesAdded: 0,
|
|
5168
|
+
linesRemoved: 0
|
|
5169
|
+
});
|
|
5170
|
+
if (missingDependency)
|
|
5171
|
+
return missingDependency;
|
|
5172
|
+
throw error;
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
function formatDetails(filePath, result) {
|
|
5176
|
+
if (result.status === "unavailable") {
|
|
5177
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
5178
|
+
}
|
|
5179
|
+
return {
|
|
5180
|
+
filePath,
|
|
5181
|
+
status: result.status,
|
|
5182
|
+
linesAdded: result.linesAdded,
|
|
5183
|
+
linesRemoved: result.linesRemoved
|
|
5184
|
+
};
|
|
5185
|
+
}
|
|
5186
|
+
function describeResult(filePath, result) {
|
|
5187
|
+
if (result.status === "unavailable") {
|
|
5188
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
5189
|
+
}
|
|
5190
|
+
if (result.status === "unchanged") {
|
|
5191
|
+
return `Already formatted: ${filePath}`;
|
|
5192
|
+
}
|
|
5193
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
5194
|
+
}
|
|
4748
5195
|
async function executeLspInstallDecision(params) {
|
|
4749
5196
|
const serverId = requireString(params, "server_id");
|
|
4750
5197
|
const decision = params["decision"];
|
|
4751
5198
|
if (!isInstallDecision(decision)) {
|
|
4752
5199
|
return text(`Invalid decision '${String(decision)}'. Expected "declined" or "allowed".`, { serverId, errorKind: "invalid_decision" }, true);
|
|
4753
5200
|
}
|
|
4754
|
-
const serverIds = [...new Set(getMergedServers().map((
|
|
5201
|
+
const serverIds = [...new Set(getMergedServers().map((server) => server.id))];
|
|
4755
5202
|
if (!serverIds.includes(serverId)) {
|
|
4756
5203
|
const preview = serverIds.slice(0, 20).join(", ");
|
|
4757
5204
|
return text(`Unknown LSP server '${serverId}'. Known servers: ${preview}${serverIds.length > 20 ? "..." : ""}`, { serverId, errorKind: "unknown_server" }, true);
|
|
@@ -4770,7 +5217,7 @@ async function executeLspGotoDefinition(params, signal) {
|
|
|
4770
5217
|
const line = requireNumber(params, "line");
|
|
4771
5218
|
const character = requireNumber(params, "character");
|
|
4772
5219
|
try {
|
|
4773
|
-
const result = await withLspClient(filePath, async (client) => client.definition(
|
|
5220
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
|
|
4774
5221
|
const locations = !result ? [] : Array.isArray(result) ? result : [result];
|
|
4775
5222
|
const details = { filePath, line, character, locations };
|
|
4776
5223
|
if (locations.length === 0)
|
|
@@ -4795,7 +5242,7 @@ async function executeLspFindReferences(params, signal) {
|
|
|
4795
5242
|
const character = requireNumber(params, "character");
|
|
4796
5243
|
const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
|
|
4797
5244
|
try {
|
|
4798
|
-
const result = await withLspClient(filePath, async (client) => client.references(
|
|
5245
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
|
|
4799
5246
|
const references = Array.isArray(result) ? result : [];
|
|
4800
5247
|
const total = references.length;
|
|
4801
5248
|
const truncated = total > DEFAULT_MAX_REFERENCES;
|
|
@@ -4835,7 +5282,7 @@ async function executeLspPrepareRename(params, signal) {
|
|
|
4835
5282
|
const line = requireNumber(params, "line");
|
|
4836
5283
|
const character = requireNumber(params, "character");
|
|
4837
5284
|
try {
|
|
4838
|
-
const result = await withLspClient(filePath, async (client) => client.prepareRename(
|
|
5285
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
|
|
4839
5286
|
const details = { filePath, line, character, result };
|
|
4840
5287
|
return text(formatPrepareRenameResult(result), details);
|
|
4841
5288
|
} catch (error) {
|
|
@@ -4856,7 +5303,7 @@ async function executeLspRename(params, signal) {
|
|
|
4856
5303
|
const character = requireNumber(params, "character");
|
|
4857
5304
|
const newName = requireString(params, "newName");
|
|
4858
5305
|
try {
|
|
4859
|
-
const result = await withLspClient(filePath, async (client) => client.rename(
|
|
5306
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
|
|
4860
5307
|
const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
|
|
4861
5308
|
return text(formatApplyResult(result.apply), details, !result.apply.success);
|
|
4862
5309
|
} catch (error) {
|
|
@@ -4883,10 +5330,10 @@ function objectSchema(properties, required = []) {
|
|
|
4883
5330
|
async function executeLspStatus() {
|
|
4884
5331
|
const servers = getAllServers();
|
|
4885
5332
|
const snapshots = getLspManager().getSnapshot();
|
|
4886
|
-
const installed = servers.filter((
|
|
4887
|
-
const configuredLines = servers.map((
|
|
4888
|
-
const state =
|
|
4889
|
-
return `- ${
|
|
5333
|
+
const installed = servers.filter((server) => server.installed && !server.disabled);
|
|
5334
|
+
const configuredLines = servers.map((server) => {
|
|
5335
|
+
const state = server.disabled ? "disabled" : server.installed ? "installed" : "missing";
|
|
5336
|
+
return `- ${server.id}: ${state}; source=${server.source}; extensions=${server.extensions.join(", ")}`;
|
|
4890
5337
|
});
|
|
4891
5338
|
const activeLines = snapshots.map((snapshot) => {
|
|
4892
5339
|
const state = snapshot.alive ? snapshot.isInitializing ? "initializing" : "alive" : "dead";
|
|
@@ -4927,10 +5374,10 @@ async function executeLspSymbols(params, signal) {
|
|
|
4927
5374
|
errorKind: "missing_query"
|
|
4928
5375
|
});
|
|
4929
5376
|
}
|
|
4930
|
-
const
|
|
4931
|
-
return formatSymbolsResult(filePath, scope,
|
|
5377
|
+
const symbols = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
5378
|
+
return formatSymbolsResult(filePath, scope, symbols, limit, query);
|
|
4932
5379
|
}
|
|
4933
|
-
const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(
|
|
5380
|
+
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
4934
5381
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
4935
5382
|
} catch (error) {
|
|
4936
5383
|
const query = optionalString(params, "query");
|
|
@@ -5064,6 +5511,16 @@ var LSP_MCP_TOOLS = [
|
|
|
5064
5511
|
}, ["filePath", "line", "character", "newName"]),
|
|
5065
5512
|
execute: executeLspRename
|
|
5066
5513
|
},
|
|
5514
|
+
{
|
|
5515
|
+
name: "format",
|
|
5516
|
+
aliases: ["lsp_format"],
|
|
5517
|
+
title: "LSP Format",
|
|
5518
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
5519
|
+
inputSchema: objectSchema({
|
|
5520
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
5521
|
+
}, ["filePath"]),
|
|
5522
|
+
execute: executeLspFormat
|
|
5523
|
+
},
|
|
5067
5524
|
{
|
|
5068
5525
|
name: "install_decision",
|
|
5069
5526
|
aliases: ["lsp_install_decision"],
|
|
@@ -5130,7 +5587,7 @@ function withContext(args, context) {
|
|
|
5130
5587
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5131
5588
|
if (!signal)
|
|
5132
5589
|
return ensure(paths);
|
|
5133
|
-
return new Promise((
|
|
5590
|
+
return new Promise((resolve, reject) => {
|
|
5134
5591
|
let settled = false;
|
|
5135
5592
|
const finish = (run) => {
|
|
5136
5593
|
if (settled)
|
|
@@ -5145,11 +5602,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5145
5602
|
return;
|
|
5146
5603
|
}
|
|
5147
5604
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5148
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
5605
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5149
5606
|
});
|
|
5150
5607
|
}
|
|
5151
5608
|
function sendToolCall(paths, token, name, args, options) {
|
|
5152
|
-
return new Promise((
|
|
5609
|
+
return new Promise((resolve, reject) => {
|
|
5153
5610
|
const socket = connect(paths.socket);
|
|
5154
5611
|
const requestId = allocateProxyRequestId();
|
|
5155
5612
|
let settled = false;
|
|
@@ -5202,7 +5659,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
5202
5659
|
}
|
|
5203
5660
|
const result = toToolResult(message, requestId);
|
|
5204
5661
|
if (result)
|
|
5205
|
-
finish(() =>
|
|
5662
|
+
finish(() => resolve(result));
|
|
5206
5663
|
else
|
|
5207
5664
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
5208
5665
|
});
|
|
@@ -5251,10 +5708,9 @@ var OMO_LSP_DAEMON_VERSION2 = "OMO_LSP_DAEMON_VERSION";
|
|
|
5251
5708
|
var DAEMON_VERSION_PATTERN2 = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
5252
5709
|
|
|
5253
5710
|
class InvalidRuntimeOverrideError2 extends Error {
|
|
5254
|
-
code = "invalid_runtime_override";
|
|
5255
|
-
reason;
|
|
5256
5711
|
constructor(reason, message) {
|
|
5257
5712
|
super(message);
|
|
5713
|
+
this.code = "invalid_runtime_override";
|
|
5258
5714
|
this.name = "InvalidRuntimeOverrideError";
|
|
5259
5715
|
this.reason = reason;
|
|
5260
5716
|
}
|
|
@@ -5274,12 +5730,12 @@ function resolveDaemonRuntime2(env, defaults) {
|
|
|
5274
5730
|
throw new InvalidRuntimeOverrideError2("paired_values_required", `${OMO_LSP_DAEMON_CLI2} and ${OMO_LSP_DAEMON_VERSION2} must be set together`);
|
|
5275
5731
|
}
|
|
5276
5732
|
if (!hasCliOverride || !hasVersionOverride) {
|
|
5277
|
-
if (!
|
|
5733
|
+
if (!isAbsolute6(defaults.cliPath)) {
|
|
5278
5734
|
throw new InvalidRuntimeOverrideError2("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
|
|
5279
5735
|
}
|
|
5280
5736
|
return { cliPath: defaults.cliPath, version: validateDaemonVersion2(defaults.version) };
|
|
5281
5737
|
}
|
|
5282
|
-
if (!
|
|
5738
|
+
if (!isAbsolute6(cliOverride)) {
|
|
5283
5739
|
throw new InvalidRuntimeOverrideError2("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI2} must be an absolute path to an existing regular file`);
|
|
5284
5740
|
}
|
|
5285
5741
|
const stat = statSync5(cliOverride, { throwIfNoEntry: false });
|
|
@@ -5378,8 +5834,8 @@ function normalizeDiagnosticsOutcome(outcome) {
|
|
|
5378
5834
|
return normalizeDiagnosticsText(outcome);
|
|
5379
5835
|
return outcome;
|
|
5380
5836
|
}
|
|
5381
|
-
function normalizeDiagnosticsText(
|
|
5382
|
-
return
|
|
5837
|
+
function normalizeDiagnosticsText(text) {
|
|
5838
|
+
return text.trim();
|
|
5383
5839
|
}
|
|
5384
5840
|
function formatDiagnosticsError(error) {
|
|
5385
5841
|
const message = normalizeDiagnosticsText(error.message);
|
|
@@ -5400,15 +5856,14 @@ function extensionKey(filePath) {
|
|
|
5400
5856
|
}
|
|
5401
5857
|
// ../../../../lsp-core/src/request-context.ts
|
|
5402
5858
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
5403
|
-
import { existsSync as
|
|
5404
|
-
import { basename as
|
|
5859
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync6 } from "node:fs";
|
|
5860
|
+
import { basename as basename4, delimiter as delimiter4, dirname as dirname2, isAbsolute as isAbsolute7, join as join8, relative as relative5, resolve as resolve10 } from "node:path";
|
|
5405
5861
|
|
|
5406
5862
|
class LspRequestContextParseError2 extends Error {
|
|
5407
|
-
code;
|
|
5408
|
-
name = "LspRequestContextParseError";
|
|
5409
5863
|
constructor(code, message) {
|
|
5410
5864
|
super(message);
|
|
5411
5865
|
this.code = code;
|
|
5866
|
+
this.name = "LspRequestContextParseError";
|
|
5412
5867
|
}
|
|
5413
5868
|
}
|
|
5414
5869
|
var storage2 = new AsyncLocalStorage2;
|
|
@@ -5425,44 +5880,44 @@ function parseLspRequestContext2(value) {
|
|
|
5425
5880
|
const installDecisionsPath = stringField2(value, "installDecisionsPath");
|
|
5426
5881
|
const capabilities = capabilitiesField2(value["capabilities"]);
|
|
5427
5882
|
const canonical = canonicalCwd2(cwd);
|
|
5428
|
-
for (const
|
|
5429
|
-
requireAbsolutePath2(
|
|
5430
|
-
const projectPath = canonicalizeExistingOrNearestAncestor2(
|
|
5883
|
+
for (const path of projectConfigPaths) {
|
|
5884
|
+
requireAbsolutePath2(path, "projectConfigPaths");
|
|
5885
|
+
const projectPath = canonicalizeExistingOrNearestAncestor2(path);
|
|
5431
5886
|
if (!isPathInside2(canonical, projectPath)) {
|
|
5432
|
-
throw new LspRequestContextParseError2("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${
|
|
5887
|
+
throw new LspRequestContextParseError2("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${path}`);
|
|
5433
5888
|
}
|
|
5434
5889
|
}
|
|
5435
5890
|
requireAbsolutePath2(userConfigPath, "userConfigPath");
|
|
5436
5891
|
requireAbsolutePath2(installDecisionsPath, "installDecisionsPath");
|
|
5437
5892
|
return {
|
|
5438
5893
|
cwd: canonical,
|
|
5439
|
-
projectConfigPaths: projectConfigPaths.map((
|
|
5894
|
+
projectConfigPaths: projectConfigPaths.map((path) => canonicalizeExistingOrNearestAncestor2(path)),
|
|
5440
5895
|
userConfigPath,
|
|
5441
5896
|
installDecisionsPath,
|
|
5442
5897
|
capabilities
|
|
5443
5898
|
};
|
|
5444
5899
|
}
|
|
5445
5900
|
function canonicalCwd2(cwd) {
|
|
5446
|
-
const resolved =
|
|
5447
|
-
if (!
|
|
5901
|
+
const resolved = resolve10(cwd);
|
|
5902
|
+
if (!existsSync13(resolved) || !statSync6(resolved).isDirectory()) {
|
|
5448
5903
|
throw new LspRequestContextParseError2("invalid_cwd", `LSP request cwd must be an existing directory: ${cwd}`);
|
|
5449
5904
|
}
|
|
5450
|
-
return
|
|
5905
|
+
return realpathSync6(resolved);
|
|
5451
5906
|
}
|
|
5452
|
-
function canonicalizeExistingOrNearestAncestor2(
|
|
5453
|
-
let current =
|
|
5907
|
+
function canonicalizeExistingOrNearestAncestor2(path) {
|
|
5908
|
+
let current = resolve10(path);
|
|
5454
5909
|
const suffix = [];
|
|
5455
5910
|
while (true) {
|
|
5456
5911
|
try {
|
|
5457
|
-
const existing =
|
|
5458
|
-
return suffix.length === 0 ? existing :
|
|
5912
|
+
const existing = realpathSync6(current);
|
|
5913
|
+
return suffix.length === 0 ? existing : join8(existing, ...suffix);
|
|
5459
5914
|
} catch (error) {
|
|
5460
5915
|
if (!isMissingPathError2(error))
|
|
5461
5916
|
throw error;
|
|
5462
5917
|
const parent = dirname2(current);
|
|
5463
5918
|
if (parent === current)
|
|
5464
5919
|
throw error;
|
|
5465
|
-
suffix.unshift(
|
|
5920
|
+
suffix.unshift(basename4(current));
|
|
5466
5921
|
current = parent;
|
|
5467
5922
|
}
|
|
5468
5923
|
}
|
|
@@ -5492,15 +5947,15 @@ function stringArrayField2(value, field) {
|
|
|
5492
5947
|
}
|
|
5493
5948
|
return fieldValue;
|
|
5494
5949
|
}
|
|
5495
|
-
function requireAbsolutePath2(
|
|
5496
|
-
if (!
|
|
5497
|
-
throw new LspRequestContextParseError2("relative_path", `LSP request context.${field} must be absolute: ${
|
|
5950
|
+
function requireAbsolutePath2(path, field) {
|
|
5951
|
+
if (!isAbsolute7(path)) {
|
|
5952
|
+
throw new LspRequestContextParseError2("relative_path", `LSP request context.${field} must be absolute: ${path}`);
|
|
5498
5953
|
}
|
|
5499
5954
|
}
|
|
5500
5955
|
function isPathInside2(parent, child) {
|
|
5501
|
-
const childPath =
|
|
5956
|
+
const childPath = resolve10(child);
|
|
5502
5957
|
const relativePath = relative5(parent, childPath);
|
|
5503
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
5958
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute7(relativePath);
|
|
5504
5959
|
}
|
|
5505
5960
|
function isMissingPathError2(error) {
|
|
5506
5961
|
const code = errorCode2(error);
|
|
@@ -5523,9 +5978,9 @@ function errorCode2(error) {
|
|
|
5523
5978
|
}
|
|
5524
5979
|
|
|
5525
5980
|
// src/daemon-cli-path.ts
|
|
5526
|
-
import { existsSync as existsSync14, readFileSync as
|
|
5981
|
+
import { existsSync as existsSync14, readFileSync as readFileSync7 } from "node:fs";
|
|
5527
5982
|
import { createRequire as createRequire2 } from "node:module";
|
|
5528
|
-
import { dirname as
|
|
5983
|
+
import { dirname as dirname11, join as join9 } from "node:path";
|
|
5529
5984
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
5530
5985
|
var requireFromHere2 = createRequire2(import.meta.url);
|
|
5531
5986
|
var PACKAGE_LSP_DAEMON_CLI = "@code-yeongyu/lsp-daemon/cli";
|
|
@@ -5572,8 +6027,8 @@ function resolveConfiguredLspDaemonCli(cliPath) {
|
|
|
5572
6027
|
}
|
|
5573
6028
|
function readDaemonPackageVersion(cliPath) {
|
|
5574
6029
|
try {
|
|
5575
|
-
const parsed = JSON.parse(
|
|
5576
|
-
if (
|
|
6030
|
+
const parsed = JSON.parse(readFileSync7(join9(dirname11(cliPath), "package.json"), "utf8"));
|
|
6031
|
+
if (isRecord8(parsed) && typeof parsed["version"] === "string" && parsed["version"].length > 0) {
|
|
5577
6032
|
return parsed["version"];
|
|
5578
6033
|
}
|
|
5579
6034
|
} catch (error) {
|
|
@@ -5582,14 +6037,14 @@ function readDaemonPackageVersion(cliPath) {
|
|
|
5582
6037
|
}
|
|
5583
6038
|
return null;
|
|
5584
6039
|
}
|
|
5585
|
-
function
|
|
6040
|
+
function isRecord8(value) {
|
|
5586
6041
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5587
6042
|
}
|
|
5588
6043
|
|
|
5589
6044
|
// src/lsp-session-state.ts
|
|
5590
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as
|
|
6045
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5591
6046
|
import { homedir } from "node:os";
|
|
5592
|
-
import { dirname as
|
|
6047
|
+
import { dirname as dirname12, join as join10 } from "node:path";
|
|
5593
6048
|
function sessionIdFrom(input) {
|
|
5594
6049
|
return typeof input.session_id === "string" && input.session_id.length > 0 ? input.session_id : undefined;
|
|
5595
6050
|
}
|
|
@@ -5618,21 +6073,21 @@ function sessionStatePath(sessionId) {
|
|
|
5618
6073
|
const root = process.env["PLUGIN_DATA"] ?? join10(homedir(), ".codex", "codex-lsp");
|
|
5619
6074
|
return join10(root, "sessions", `${safePathSegment(sessionId)}.json`);
|
|
5620
6075
|
}
|
|
5621
|
-
function readSessionState(
|
|
6076
|
+
function readSessionState(path) {
|
|
5622
6077
|
try {
|
|
5623
|
-
const parsed = JSON.parse(readFileSync8(
|
|
5624
|
-
if (
|
|
6078
|
+
const parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
6079
|
+
if (isRecord9(parsed) && isLspSessionState(parsed))
|
|
5625
6080
|
return normalizeSessionState(parsed);
|
|
5626
6081
|
return emptyState();
|
|
5627
6082
|
} catch (error) {
|
|
5628
|
-
if (error instanceof SyntaxError ||
|
|
6083
|
+
if (error instanceof SyntaxError || isRecord9(error) && error["code"] === "ENOENT")
|
|
5629
6084
|
return emptyState();
|
|
5630
6085
|
throw error;
|
|
5631
6086
|
}
|
|
5632
6087
|
}
|
|
5633
|
-
function writeSessionState(
|
|
5634
|
-
mkdirSync4(
|
|
5635
|
-
|
|
6088
|
+
function writeSessionState(path, state) {
|
|
6089
|
+
mkdirSync4(dirname12(path), { recursive: true });
|
|
6090
|
+
writeFileSync4(path, `${JSON.stringify(state)}
|
|
5636
6091
|
`);
|
|
5637
6092
|
}
|
|
5638
6093
|
function emptyState() {
|
|
@@ -5651,7 +6106,7 @@ function normalizeSessionState(value) {
|
|
|
5651
6106
|
notConfiguredExtensions: Array.isArray(notConfiguredExtensions) ? notConfiguredExtensions.filter((item) => typeof item === "string").sort() : []
|
|
5652
6107
|
};
|
|
5653
6108
|
}
|
|
5654
|
-
function
|
|
6109
|
+
function isRecord9(value) {
|
|
5655
6110
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5656
6111
|
}
|
|
5657
6112
|
|
|
@@ -5662,7 +6117,7 @@ function extractMutatedFilePaths(input) {
|
|
|
5662
6117
|
return [];
|
|
5663
6118
|
if (isFailedToolResponse(input.tool_response))
|
|
5664
6119
|
return [];
|
|
5665
|
-
const toolInput =
|
|
6120
|
+
const toolInput = isRecord10(input.tool_input) ? input.tool_input : {};
|
|
5666
6121
|
const paths = new Set;
|
|
5667
6122
|
addStringValue(paths, toolInput["path"]);
|
|
5668
6123
|
addStringValue(paths, toolInput["filePath"]);
|
|
@@ -5681,7 +6136,7 @@ function isMutationTool(value) {
|
|
|
5681
6136
|
return MUTATION_TOOL_NAMES.has(value.toLowerCase());
|
|
5682
6137
|
}
|
|
5683
6138
|
function isFailedToolResponse(value) {
|
|
5684
|
-
if (!
|
|
6139
|
+
if (!isRecord10(value))
|
|
5685
6140
|
return false;
|
|
5686
6141
|
return value["isError"] === true || value["is_error"] === true || value["error"] === true || value["status"] === "error";
|
|
5687
6142
|
}
|
|
@@ -5707,9 +6162,9 @@ function addPatchInput(paths, value) {
|
|
|
5707
6162
|
return;
|
|
5708
6163
|
for (const line of value.split(`
|
|
5709
6164
|
`)) {
|
|
5710
|
-
const
|
|
5711
|
-
if (
|
|
5712
|
-
paths.add(
|
|
6165
|
+
const path = extractPatchHeaderPath(line);
|
|
6166
|
+
if (path !== undefined)
|
|
6167
|
+
paths.add(path);
|
|
5713
6168
|
}
|
|
5714
6169
|
}
|
|
5715
6170
|
function extractPatchHeaderPath(line) {
|
|
@@ -5724,7 +6179,7 @@ function addPatchFiles(paths, value) {
|
|
|
5724
6179
|
if (!Array.isArray(value))
|
|
5725
6180
|
return;
|
|
5726
6181
|
for (const item of value) {
|
|
5727
|
-
if (!
|
|
6182
|
+
if (!isRecord10(item))
|
|
5728
6183
|
continue;
|
|
5729
6184
|
addStringValue(paths, item["path"]);
|
|
5730
6185
|
addStringValue(paths, item["filePath"]);
|
|
@@ -5733,7 +6188,7 @@ function addPatchFiles(paths, value) {
|
|
|
5733
6188
|
addStringValue(paths, item["move_path"]);
|
|
5734
6189
|
}
|
|
5735
6190
|
}
|
|
5736
|
-
function
|
|
6191
|
+
function isRecord10(value) {
|
|
5737
6192
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5738
6193
|
}
|
|
5739
6194
|
|
|
@@ -5764,10 +6219,10 @@ function postEditOutcomeFromDaemonResult(result) {
|
|
|
5764
6219
|
`);
|
|
5765
6220
|
}
|
|
5766
6221
|
function notConfiguredAvailability(details) {
|
|
5767
|
-
if (!
|
|
6222
|
+
if (!isRecord11(details))
|
|
5768
6223
|
return;
|
|
5769
6224
|
const availability = details["availability"];
|
|
5770
|
-
if (!
|
|
6225
|
+
if (!isRecord11(availability))
|
|
5771
6226
|
return;
|
|
5772
6227
|
if (availability["kind"] !== "not_configured")
|
|
5773
6228
|
return;
|
|
@@ -5775,11 +6230,11 @@ function notConfiguredAvailability(details) {
|
|
|
5775
6230
|
return typeof extension === "string" && extension.length > 0 ? { extension } : undefined;
|
|
5776
6231
|
}
|
|
5777
6232
|
function codexLspRequestContext(env = process.env, cwd = process.cwd()) {
|
|
5778
|
-
const
|
|
6233
|
+
const canonicalCwd = realpathSync7(resolve11(cwd));
|
|
5779
6234
|
const codexHome = resolve11(env["CODEX_HOME"]?.trim() || join11(homedir3(), ".codex"));
|
|
5780
6235
|
return parseLspRequestContext2({
|
|
5781
|
-
cwd:
|
|
5782
|
-
projectConfigPaths: [join11(
|
|
6236
|
+
cwd: canonicalCwd,
|
|
6237
|
+
projectConfigPaths: [join11(canonicalCwd, ".codex", "lsp-client.json")],
|
|
5783
6238
|
userConfigPath: join11(codexHome, "lsp-client.json"),
|
|
5784
6239
|
installDecisionsPath: join11(codexHome, "lsp-install-decisions.json"),
|
|
5785
6240
|
capabilities: { installDecisionTool: true }
|
|
@@ -5882,22 +6337,22 @@ function isContextPressureTranscript(transcriptPath) {
|
|
|
5882
6337
|
throw error;
|
|
5883
6338
|
}
|
|
5884
6339
|
}
|
|
5885
|
-
function hasContextPressureMarker(
|
|
5886
|
-
const normalizedText =
|
|
6340
|
+
function hasContextPressureMarker(text) {
|
|
6341
|
+
const normalizedText = text.toLowerCase();
|
|
5887
6342
|
return CONTEXT_PRESSURE_MARKERS.some((marker) => normalizedText.includes(marker));
|
|
5888
6343
|
}
|
|
5889
|
-
function limitHookText(
|
|
5890
|
-
if (
|
|
5891
|
-
return
|
|
6344
|
+
function limitHookText(text, maxChars) {
|
|
6345
|
+
if (text.length <= maxChars)
|
|
6346
|
+
return text;
|
|
5892
6347
|
const marker = `
|
|
5893
6348
|
|
|
5894
6349
|
[Truncated hook output to ${maxChars} chars to avoid Codex context overflow.]`;
|
|
5895
6350
|
if (marker.length >= maxChars)
|
|
5896
6351
|
return marker.slice(0, maxChars);
|
|
5897
|
-
const head =
|
|
6352
|
+
const head = text.slice(0, maxChars - marker.length).replace(/[ \t\r\n]+$/, "");
|
|
5898
6353
|
return `${head}${marker}`;
|
|
5899
6354
|
}
|
|
5900
|
-
function
|
|
6355
|
+
function isRecord11(value) {
|
|
5901
6356
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5902
6357
|
}
|
|
5903
6358
|
|
|
@@ -5914,7 +6369,7 @@ async function runHookCli(runHook, stdin) {
|
|
|
5914
6369
|
if (!raw.trim())
|
|
5915
6370
|
return;
|
|
5916
6371
|
const parsed = JSON.parse(raw);
|
|
5917
|
-
const input =
|
|
6372
|
+
const input = isRecord11(parsed) ? parsed : {};
|
|
5918
6373
|
const output = await runHook(input);
|
|
5919
6374
|
if (output)
|
|
5920
6375
|
process.stdout.write(output);
|
|
@@ -5957,15 +6412,15 @@ main().catch((error) => {
|
|
|
5957
6412
|
});
|
|
5958
6413
|
async function runPackageLspMcpCli() {
|
|
5959
6414
|
const cliPath = resolveLspDaemonCliPath();
|
|
5960
|
-
const child = spawn3(execPath2, [cliPath, "mcp"], { stdio: "inherit" });
|
|
5961
|
-
await new Promise((
|
|
6415
|
+
const child = spawn3(execPath2, [cliPath, "mcp"], { stdio: "inherit", windowsHide: true });
|
|
6416
|
+
await new Promise((resolve, reject) => {
|
|
5962
6417
|
child.once("error", reject);
|
|
5963
6418
|
child.once("exit", (code, signal) => {
|
|
5964
6419
|
if (code !== null && code !== 0)
|
|
5965
6420
|
process.exitCode = code;
|
|
5966
6421
|
if (code === null && signal !== null)
|
|
5967
6422
|
process.exitCode = 1;
|
|
5968
|
-
|
|
6423
|
+
resolve();
|
|
5969
6424
|
});
|
|
5970
6425
|
});
|
|
5971
6426
|
}
|