oh-my-opencode 5.0.0-beta.8 → 5.0.0-beta.81
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 +59 -23
- package/.agents/command/remove-deadcode.md +1 -1
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +1 -3
- package/.agents/skills/hyperplan/SKILL.md +5 -5
- 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 +59 -23
- package/.agents/skills/remove-deadcode/SKILL.md +1 -1
- package/.agents/skills/security-research/SKILL.md +4 -4
- 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/.opencode/command/publish.md +59 -23
- package/.opencode/skills/pre-publish-review/SKILL.md +9 -12
- package/README.ja.md +66 -61
- package/README.ko.md +67 -62
- package/README.md +108 -182
- package/README.ru.md +63 -61
- package/README.zh-cn.md +62 -61
- package/THIRD-PARTY-NOTICES.md +35 -105
- package/dist/agents/atlas/agent.d.ts +0 -1
- package/dist/agents/gpt-prompt-identity.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/browser-provider.d.ts +2 -0
- package/dist/cli/doctor/checks/index.d.ts +2 -0
- package/dist/cli/doctor/checks/latest-version.d.ts +11 -0
- package/dist/cli/doctor/checks/system-plugin.d.ts +4 -3
- package/dist/cli/doctor/framework/constants.d.ts +5 -0
- package/dist/cli/doctor/framework/types.d.ts +2 -0
- package/dist/cli/fallback-lane-policy.d.ts +1 -0
- package/dist/cli/index.js +59118 -63486
- 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 +58841 -63186
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/agent-names.d.ts +0 -1
- package/dist/config/schema/background-task.d.ts +1 -0
- package/dist/config/schema/browser-automation.d.ts +0 -2
- 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 -12
- 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/config-migration/category-deep-split.d.ts +3 -0
- package/dist/config-migration/migration-plans.d.ts +1 -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 +9 -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/background-agent/types.d.ts +4 -0
- package/dist/features/boulder-state/storage.d.ts +1 -1
- 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/hyperplan.d.ts +1 -1
- package/dist/features/builtin-commands/templates/refactor-sections/team-mode-addendum.d.ts +1 -1
- package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
- 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/claude-tasks/storage.d.ts +7 -2
- package/dist/features/hook-message-injector/index.d.ts +1 -0
- package/dist/features/hook-message-injector/sdk-message-lookup.d.ts +1 -0
- 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/lifecycle-inline-spec.d.ts +1 -1
- 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/comment-checker/__fixtures__/download-probe.fixture.d.ts +1 -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 +9 -0
- package/dist/hooks/keyword-detector/ultrawork/index.d.ts +2 -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/plan-format-validator/hook.d.ts +19 -0
- 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/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
- package/dist/index.js +34199 -28037
- package/dist/mcp/index.d.ts +0 -4
- package/dist/mcp/types.d.ts +0 -1
- package/dist/oh-my-opencode.schema.json +28 -59
- package/dist/plugin/chat-message/types.d.ts +6 -4
- 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/stop-continuation.d.ts +3 -0
- package/dist/plugin/system-transform.d.ts +5 -1
- package/dist/plugin-config/omo-config-chain.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/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 +13 -1
- package/dist/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/dist/skills/coding-agent-sessions/SKILL.md +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 +26 -5
- 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/debugging/references/tools/playwright-cli.md +79 -161
- package/dist/skills/frontend/ATTRIBUTION.md +10 -0
- package/dist/skills/frontend/SKILL.md +8 -3
- package/dist/skills/frontend/references/design/README.md +13 -4
- package/dist/skills/frontend/references/design/_INDEX.md +1 -0
- package/dist/skills/frontend/references/design/ambience-skill.md +145 -0
- package/dist/skills/frontend/references/design/aside.md +1 -1
- package/dist/skills/frontend/references/design/clone-from-url.md +1 -1
- package/dist/skills/frontend/references/design/design-system-architecture.md +1 -0
- package/dist/skills/frontend/references/design/interaction-skill.md +2 -0
- package/dist/skills/frontend/references/design/print-paged-media.md +76 -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/frontend/references/perfection/README.md +1 -0
- package/dist/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
- 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 +5 -5
- package/dist/skills/remove-ai-slops/SKILL.md +5 -5
- package/dist/skills/review-work/SKILL.md +101 -419
- package/dist/skills/ultimate-browsing/ATTRIBUTION.md +32 -86
- package/dist/skills/ultimate-browsing/SKILL.md +32 -27
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +111 -0
- package/dist/skills/ultimate-browsing/engine/templates/package.json +2 -2
- package/dist/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
- package/dist/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
- package/dist/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
- package/dist/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
- package/dist/skills/ultimate-browsing/references/chrome-stealth.md +86 -95
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +18 -5
- package/dist/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
- package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
- package/dist/skills/{start-work → ulw-execute}/SKILL.md +24 -22
- package/dist/skills/ulw-plan/SKILL.md +5 -6
- package/dist/skills/ulw-plan/references/full-workflow.md +6 -5
- package/dist/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -1
- package/dist/skills/ulw-research/SKILL.md +10 -5
- package/dist/skills/visual-qa/AGENTS.md +58 -0
- package/dist/skills/visual-qa/SKILL.md +4 -3
- package/dist/skills/visual-qa/references/browser-setup.md +75 -0
- 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 +10 -3
- 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 +22186 -30577
- package/package.json +51 -50
- 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 +9 -1
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +100 -28
- 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 +103 -6
- package/packages/lsp-core/src/lsp/client-wrapper.ts +50 -16
- 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 +90 -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 +35 -11
- 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/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/parameters.test.ts +51 -0
- package/packages/lsp-core/src/tools/types.ts +10 -0
- package/packages/lsp-daemon/dist/cli.js +1421 -960
- package/packages/lsp-daemon/dist/client.d.ts +10 -0
- package/packages/lsp-daemon/dist/client.js +956 -498
- package/packages/lsp-daemon/dist/daemon-client.d.ts +3 -0
- package/packages/lsp-daemon/dist/daemon-client.js +23 -3
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +6 -1
- package/packages/lsp-daemon/dist/ensure-daemon.js +27 -5
- package/packages/lsp-daemon/dist/index.js +860 -407
- package/packages/lsp-daemon/dist/ownership.js +2 -2
- 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 +5 -4
- package/packages/lsp-tools-mcp/dist/cli.js +764 -341
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +274 -138
- package/packages/lsp-tools-mcp/dist/mcp.js +789 -368
- package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
- package/packages/lsp-tools-mcp/dist/tools.js +719 -302
- package/packages/lsp-tools-mcp/package.json +5 -4
- 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 +8402 -408
- 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/bootstrap/src/setup.ts +7 -1
- 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 +6 -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/dist/cli.js +1 -1
- package/packages/omo-codex/plugin/components/git-bash/dist/codex-hook.js +2 -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/git-bash/src/codex-hook.ts +2 -1
- package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +6 -7
- 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 +6 -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 +977 -545
- 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 +6 -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 +8 -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 +6 -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 +5328 -1382
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +5524 -1579
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +6 -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 +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +500 -4
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +6 -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 +4 -5
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +5 -5
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -0
- 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 +11 -11
- 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 +13 -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 +17 -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 +44 -27
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.d.ts +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +30 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +10 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +2 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +5 -78
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.d.ts +12 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +114 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.d.ts +7 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +57 -46
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +2 -2
- 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.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +40 -37
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +2191 -737
- 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 +8 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +35 -23
- 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 +25 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/driver-objective-ack.d.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/driver-objective-ack.js +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence-artifacts.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence-artifacts.js +37 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +24 -12
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.d.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.js +39 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +19 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.d.ts +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.js +108 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +6 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +54 -25
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-goal-factory.d.ts +10 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-goal-factory.js +38 -31
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +10 -7
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +121 -100
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.d.ts +16 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.js +115 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +41 -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.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +25 -13
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +157 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.d.ts +381 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.js +127 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/types.d.ts +130 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/types.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk.d.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk.js +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.d.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.js +67 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +7 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +188 -59
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.js +22 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +259 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +41 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.d.ts +9 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.d.ts +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +11 -11
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +28 -23
- package/packages/omo-codex/plugin/components/ulw-loop/dist/success-criteria-input.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/success-criteria-input.js +41 -0
- 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 +83 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +18 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +7 -6
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +7 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +33 -10
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-codex-validation.ts +52 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +8 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +5 -98
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +134 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +59 -77
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +10 -4
- 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 +52 -46
- 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 +51 -33
- 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 +27 -9
- package/packages/omo-codex/plugin/components/ulw-loop/src/driver-objective-ack.ts +20 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/evidence-artifacts.ts +45 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +23 -16
- package/packages/omo-codex/plugin/components/ulw-loop/src/ledger.ts +38 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +32 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-commit.ts +132 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +67 -54
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-goal-factory.ts +63 -31
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +140 -119
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-log.ts +112 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +61 -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 +38 -13
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +218 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/manifest.ts +156 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/types.ts +143 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-budget-io.ts +59 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +196 -52
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-role-guard.ts +22 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +257 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +45 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-types.ts +13 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +12 -10
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +27 -22
- package/packages/omo-codex/plugin/components/ulw-loop/src/success-criteria-input.ts +56 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +115 -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 +131 -82
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +147 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +16 -22
- 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 +31 -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 +27 -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 +88 -11
- 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/barrier.ts +13 -0
- 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/commit-child.ts +65 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-cli-qa.mjs +76 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-crash.ts +23 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +58 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-writer.ts +65 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/lease-clock.ts +23 -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 +67 -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-commit-log.test.ts +252 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-recovery.test.ts +190 -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 +74 -25
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-log-legacy-projection.test.ts +228 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-log-newest.test.ts +72 -0
- 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/review-blockers.test.ts +9 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-completed-plan.test.ts +43 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-contract.test.ts +137 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-driver-states.test.ts +174 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-dx.test.ts +219 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-session-context.test.ts +169 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +450 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-role-matrix.test.ts +113 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +310 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/status-next-actions-surface.test.ts +133 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +12 -12
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +12 -6
- 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 +992 -681
- package/packages/omo-codex/plugin/package.json +6 -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 +19 -90
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.d.mts +4 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +111 -64
- 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 +13 -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 +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 +26 -5
- 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/debugging/references/tools/playwright-cli.md +79 -161
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +10 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +8 -3
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +13 -4
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/ambience-skill.md +145 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/aside.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -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/frontend/references/perfection/README.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
- package/packages/omo-codex/plugin/skills/git-master/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +20 -18
- 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 +11 -9
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +11 -9
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +116 -424
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +32 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +32 -27
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +111 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +86 -95
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +18 -5
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +44 -27
- package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +35 -36
- package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +31 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +33 -10
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +4 -5
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +5 -5
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -0
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +16 -9
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +10 -7
- package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +75 -0
- 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-default-role.test.mjs +66 -0
- 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 +100 -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 +16149 -4304
- 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} +44 -34
- 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 +13 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +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 +26 -5
- 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/debugging/references/tools/playwright-cli.md +79 -161
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +10 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +8 -3
- package/packages/shared-skills/skills/frontend/references/design/README.md +13 -4
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/shared-skills/skills/frontend/references/design/ambience-skill.md +145 -0
- package/packages/shared-skills/skills/frontend/references/design/aside.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +1 -0
- package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +2 -0
- package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -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/frontend/references/perfection/README.md +1 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
- 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 +5 -5
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +5 -5
- package/packages/shared-skills/skills/review-work/SKILL.md +101 -419
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +32 -86
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +32 -27
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +111 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +86 -95
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +18 -5
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
- package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +24 -22
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +5 -6
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +6 -5
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +10 -5
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +4 -3
- package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +75 -0
- 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/.agents/skills/work-with-pr-workspace/evals/evals.json +0 -76
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.json +0 -138
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.md +0 -42
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +0 -57
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +0 -15
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +0 -454
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +0 -136
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +0 -47
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +0 -163
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +0 -15
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +0 -615
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +0 -99
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +0 -50
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +0 -111
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +0 -37
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +0 -11
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +0 -205
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +0 -78
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +0 -42
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +0 -87
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +0 -11
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +0 -334
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +0 -86
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +0 -23
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +0 -119
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +0 -32
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +0 -221
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +0 -104
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +0 -41
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +0 -84
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +0 -342
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +0 -131
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +0 -39
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +0 -128
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +0 -32
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +0 -143
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +0 -82
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +0 -51
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +0 -69
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +0 -252
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +0 -83
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +0 -33
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +0 -101
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +0 -32
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +0 -387
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +0 -112
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +0 -51
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +0 -75
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +0 -10
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +0 -529
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +0 -127
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +0 -42
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +0 -120
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +0 -1
- package/.agents/skills/work-with-pr-workspace/iteration-1/review.html +0 -1326
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +0 -76
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.json +0 -138
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.md +0 -42
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +0 -57
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +0 -15
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +0 -454
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +0 -136
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +0 -47
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +0 -163
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +0 -15
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +0 -615
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +0 -99
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +0 -50
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +0 -111
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +0 -37
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +0 -11
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +0 -205
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +0 -78
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +0 -42
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +0 -87
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +0 -11
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +0 -334
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +0 -86
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +0 -23
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +0 -119
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +0 -32
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +0 -221
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +0 -104
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +0 -41
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +0 -84
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +0 -342
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +0 -131
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +0 -39
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +0 -128
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +0 -32
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +0 -143
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +0 -82
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +0 -51
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +0 -69
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +0 -252
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +0 -83
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +0 -33
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +0 -101
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +0 -32
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +0 -387
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +0 -112
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +0 -51
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +0 -75
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +0 -10
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +0 -529
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +0 -127
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +0 -42
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +0 -120
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +0 -1
- package/.opencode/skills/work-with-pr-workspace/iteration-1/review.html +0 -1326
- 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/skills/visual-qa/references/agent-browser-setup.md +0 -45
- 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 -12244
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9842
- 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 -477
- 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/skills/visual-qa/references/agent-browser-setup.md +0 -45
- 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/packages/shared-skills/skills/visual-qa/references/agent-browser-setup.md +0 -45
- /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
|
@@ -3,14 +3,450 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { argv, stderr } from "node:process";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
// src/ownership.ts
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { existsSync, lstatSync as lstatSync2, readFileSync as readFileSync3, statSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
9
|
+
import { dirname as dirname3 } from "node:path";
|
|
10
|
+
|
|
11
|
+
// src/lock.ts
|
|
12
|
+
import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync } from "node:fs";
|
|
13
|
+
import { dirname } from "node:path";
|
|
14
|
+
function isProcessAlive(pid) {
|
|
15
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
16
|
+
return false;
|
|
17
|
+
try {
|
|
18
|
+
process.kill(pid, 0);
|
|
19
|
+
return true;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error instanceof Error)
|
|
22
|
+
return errorCode(error) === "EPERM";
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function readLockPid(lockPath) {
|
|
27
|
+
try {
|
|
28
|
+
const pid = Number.parseInt(readFileSync(lockPath, "utf8").trim(), 10);
|
|
29
|
+
return Number.isInteger(pid) ? pid : null;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function tryAcquireLock(lockPath, ownerPid = process.pid) {
|
|
35
|
+
mkdirSync(dirname(lockPath), { recursive: true });
|
|
36
|
+
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
37
|
+
const handle = writeLockFile(lockPath, ownerPid);
|
|
38
|
+
if (handle)
|
|
39
|
+
return handle;
|
|
40
|
+
if (!reapStaleLock(lockPath))
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function writeLockFile(lockPath, ownerPid) {
|
|
46
|
+
try {
|
|
47
|
+
const fd = openSync(lockPath, "wx", 384);
|
|
48
|
+
writeSync(fd, `${ownerPid}
|
|
49
|
+
`);
|
|
50
|
+
closeSync(fd);
|
|
51
|
+
return { release: () => unlinkQuietly(lockPath) };
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (errorCode(error) === "EEXIST")
|
|
54
|
+
return null;
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function reapStaleLock(lockPath) {
|
|
59
|
+
const pid = readLockPid(lockPath);
|
|
60
|
+
if (pid !== null && isProcessAlive(pid))
|
|
61
|
+
return false;
|
|
62
|
+
unlinkQuietly(lockPath);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
function unlinkQuietly(path) {
|
|
66
|
+
try {
|
|
67
|
+
unlinkSync(path);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof Error)
|
|
70
|
+
return;
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function errorCode(error) {
|
|
75
|
+
if (!error || typeof error !== "object" || !("code" in error))
|
|
76
|
+
return;
|
|
77
|
+
const code = Reflect.get(error, "code");
|
|
78
|
+
return typeof code === "string" ? code : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/ipc-protocol.ts
|
|
82
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
83
|
+
import {
|
|
84
|
+
chmodSync,
|
|
85
|
+
closeSync as closeSync2,
|
|
86
|
+
constants,
|
|
87
|
+
fchmodSync,
|
|
88
|
+
fstatSync,
|
|
89
|
+
lstatSync,
|
|
90
|
+
mkdirSync as mkdirSync2,
|
|
91
|
+
openSync as openSync2,
|
|
92
|
+
readFileSync as readFileSync2,
|
|
93
|
+
unlinkSync as unlinkSync2,
|
|
94
|
+
writeSync as writeSync2
|
|
95
|
+
} from "node:fs";
|
|
96
|
+
import { dirname as dirname2 } from "node:path";
|
|
9
97
|
|
|
10
98
|
// ../mcp-stdio-core/src/record.ts
|
|
11
99
|
function isPlainRecord(value) {
|
|
12
100
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
101
|
}
|
|
102
|
+
|
|
103
|
+
// src/ipc-protocol.ts
|
|
104
|
+
var OMO_DAEMON_PROTOCOL_VERSION = 1;
|
|
105
|
+
var AUTH_ERROR_CODE = -32001;
|
|
106
|
+
var PROTOCOL_ERROR_CODE = -32002;
|
|
107
|
+
var AUTH_TOKEN_BYTES = 32;
|
|
108
|
+
|
|
109
|
+
class UnsafePrivateDirectoryError extends Error {
|
|
110
|
+
constructor(path, reason) {
|
|
111
|
+
super(`unsafe private directory ${path}: ${reason}`);
|
|
112
|
+
this.path = path;
|
|
113
|
+
this.reason = reason;
|
|
114
|
+
this.name = "UnsafePrivateDirectoryError";
|
|
115
|
+
this.code = "unsafe_private_directory";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function authEnvelope(token) {
|
|
119
|
+
return { protocolVersion: OMO_DAEMON_PROTOCOL_VERSION, token };
|
|
120
|
+
}
|
|
121
|
+
function readAuthToken(paths) {
|
|
122
|
+
try {
|
|
123
|
+
const token = readFileSync2(paths.auth, "utf8").trim();
|
|
124
|
+
return token.length > 0 ? token : null;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof Error)
|
|
127
|
+
return null;
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function readOrCreateAuthToken(paths) {
|
|
132
|
+
const existing = readAuthToken(paths);
|
|
133
|
+
if (existing)
|
|
134
|
+
return existing;
|
|
135
|
+
return createAuthToken(paths);
|
|
136
|
+
}
|
|
137
|
+
function rotateAuthToken(paths) {
|
|
138
|
+
try {
|
|
139
|
+
unlinkSync2(paths.auth);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (!(error instanceof Error))
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
return createAuthToken(paths);
|
|
145
|
+
}
|
|
146
|
+
function authenticateMessage(raw, expectedToken) {
|
|
147
|
+
const id = jsonRpcId(raw);
|
|
148
|
+
if (!isPlainRecord(raw))
|
|
149
|
+
return authError(id);
|
|
150
|
+
const params = raw["params"];
|
|
151
|
+
if (!isPlainRecord(params))
|
|
152
|
+
return authError(id);
|
|
153
|
+
const envelope = params["_omo"];
|
|
154
|
+
if (!isPlainRecord(envelope))
|
|
155
|
+
return authError(id);
|
|
156
|
+
const protocolVersion = envelope["protocolVersion"];
|
|
157
|
+
if (protocolVersion !== OMO_DAEMON_PROTOCOL_VERSION)
|
|
158
|
+
return protocolError(id);
|
|
159
|
+
const token = envelope["token"];
|
|
160
|
+
if (typeof token !== "string" || !tokenMatches(token, expectedToken))
|
|
161
|
+
return authError(id);
|
|
162
|
+
const cleanParams = { ...params };
|
|
163
|
+
delete cleanParams["_omo"];
|
|
164
|
+
return { input: { ...raw, params: cleanParams }, id, method: typeof raw["method"] === "string" ? raw["method"] : undefined };
|
|
165
|
+
}
|
|
166
|
+
function isAuthErrorResponse(message) {
|
|
167
|
+
if (!isPlainRecord(message))
|
|
168
|
+
return false;
|
|
169
|
+
const error = message["error"];
|
|
170
|
+
if (!isPlainRecord(error))
|
|
171
|
+
return false;
|
|
172
|
+
const data = error["data"];
|
|
173
|
+
return error["code"] === AUTH_ERROR_CODE && isPlainRecord(data) && data["code"] === "daemon_authentication_failed";
|
|
174
|
+
}
|
|
175
|
+
function writePrivateFile(path, data) {
|
|
176
|
+
const fd = openSync2(path, "w", 384);
|
|
177
|
+
try {
|
|
178
|
+
writeSync2(fd, data);
|
|
179
|
+
} finally {
|
|
180
|
+
closeSync2(fd);
|
|
181
|
+
}
|
|
182
|
+
setPrivateFileMode(path);
|
|
183
|
+
}
|
|
184
|
+
function ensurePrivateDirectory(path, options = {}) {
|
|
185
|
+
try {
|
|
186
|
+
mkdirSync2(path, { recursive: true, mode: 448 });
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (errorCode2(error) !== "EEXIST")
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
if (process.platform === "win32")
|
|
192
|
+
return;
|
|
193
|
+
const before = validatePrivateDirectory(path, options);
|
|
194
|
+
const fd = openSync2(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
195
|
+
try {
|
|
196
|
+
fchmodSync(fd, 448);
|
|
197
|
+
const after = validatePrivateDirectory(path, options);
|
|
198
|
+
const openStats = fstatSync(fd);
|
|
199
|
+
if (!sameDirectory(before, after) || !sameDirectory(before, openStats)) {
|
|
200
|
+
throw new UnsafePrivateDirectoryError(path, "changed_during_chmod");
|
|
201
|
+
}
|
|
202
|
+
} finally {
|
|
203
|
+
closeSync2(fd);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function setPrivateFileMode(path) {
|
|
207
|
+
if (process.platform !== "win32")
|
|
208
|
+
chmodSync(path, 384);
|
|
209
|
+
}
|
|
210
|
+
function createAuthToken(paths) {
|
|
211
|
+
ensurePrivateDirectory(dirname2(paths.auth));
|
|
212
|
+
const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
|
|
213
|
+
let fd;
|
|
214
|
+
try {
|
|
215
|
+
fd = openSync2(paths.auth, "wx", 384);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (errorCode2(error) === "EEXIST") {
|
|
218
|
+
const existing = readAuthToken(paths);
|
|
219
|
+
if (existing)
|
|
220
|
+
return existing;
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
writeSync2(fd, `${token}
|
|
226
|
+
`);
|
|
227
|
+
} finally {
|
|
228
|
+
closeSync2(fd);
|
|
229
|
+
}
|
|
230
|
+
setPrivateFileMode(paths.auth);
|
|
231
|
+
return token;
|
|
232
|
+
}
|
|
233
|
+
function errorCode2(error) {
|
|
234
|
+
if (!error || typeof error !== "object" || !("code" in error))
|
|
235
|
+
return;
|
|
236
|
+
const code = Reflect.get(error, "code");
|
|
237
|
+
return typeof code === "string" ? code : undefined;
|
|
238
|
+
}
|
|
239
|
+
function validatePrivateDirectory(path, options) {
|
|
240
|
+
const stats = options.lstat ? options.lstat(path) : lstatPrivateDirectory(path);
|
|
241
|
+
if (stats.isSymbolicLink())
|
|
242
|
+
throw new UnsafePrivateDirectoryError(path, "symlink");
|
|
243
|
+
if (!stats.isDirectory())
|
|
244
|
+
throw new UnsafePrivateDirectoryError(path, "not_directory");
|
|
245
|
+
const currentUid = options.currentUid ? options.currentUid() : process.getuid?.();
|
|
246
|
+
if (currentUid !== undefined && stats.uid !== currentUid) {
|
|
247
|
+
throw new UnsafePrivateDirectoryError(path, "wrong_owner");
|
|
248
|
+
}
|
|
249
|
+
return stats;
|
|
250
|
+
}
|
|
251
|
+
function lstatPrivateDirectory(path) {
|
|
252
|
+
return lstatSync(path);
|
|
253
|
+
}
|
|
254
|
+
function sameDirectory(a, b) {
|
|
255
|
+
return a.dev === b.dev && a.ino === b.ino;
|
|
256
|
+
}
|
|
257
|
+
function tokenMatches(candidate, expected) {
|
|
258
|
+
const candidateBytes = Buffer.from(candidate);
|
|
259
|
+
const expectedBytes = Buffer.from(expected);
|
|
260
|
+
return candidateBytes.length === expectedBytes.length && timingSafeEqual(candidateBytes, expectedBytes);
|
|
261
|
+
}
|
|
262
|
+
function jsonRpcId(raw) {
|
|
263
|
+
if (!isPlainRecord(raw))
|
|
264
|
+
return null;
|
|
265
|
+
const id = raw["id"];
|
|
266
|
+
return typeof id === "string" || typeof id === "number" || id === null ? id : null;
|
|
267
|
+
}
|
|
268
|
+
function authError(id) {
|
|
269
|
+
return {
|
|
270
|
+
jsonrpc: "2.0",
|
|
271
|
+
id,
|
|
272
|
+
error: { code: AUTH_ERROR_CODE, message: "daemon authentication failed", data: { code: "daemon_authentication_failed" } }
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function protocolError(id) {
|
|
276
|
+
return {
|
|
277
|
+
jsonrpc: "2.0",
|
|
278
|
+
id,
|
|
279
|
+
error: { code: PROTOCOL_ERROR_CODE, message: "daemon protocol mismatch", data: { code: "daemon_protocol_mismatch" } }
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/ownership.ts
|
|
284
|
+
class DaemonAlreadyRunningError extends Error {
|
|
285
|
+
constructor() {
|
|
286
|
+
super(...arguments);
|
|
287
|
+
this.name = "DaemonAlreadyRunningError";
|
|
288
|
+
this.code = "daemon_already_running";
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
class DaemonStartupDeferredError extends Error {
|
|
293
|
+
constructor(reason) {
|
|
294
|
+
super(`LSP daemon startup deferred: ${reason}`);
|
|
295
|
+
this.reason = reason;
|
|
296
|
+
this.name = "DaemonStartupDeferredError";
|
|
297
|
+
this.code = "daemon_startup_deferred";
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function acquireStartupLease(paths, pingOwner) {
|
|
301
|
+
ensureDaemonDirectories(paths);
|
|
302
|
+
const lock = tryAcquireLock(paths.lock);
|
|
303
|
+
if (!lock) {
|
|
304
|
+
const token = readAuthToken(paths);
|
|
305
|
+
if (token && await pingOwner(token))
|
|
306
|
+
throw new DaemonAlreadyRunningError("LSP daemon already running");
|
|
307
|
+
throw new DaemonStartupDeferredError("startup_lock_busy");
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
const token = await validateExistingOwner(paths, pingOwner);
|
|
311
|
+
return { lock, token, owner: newOwner(paths) };
|
|
312
|
+
} catch (error) {
|
|
313
|
+
lock.release();
|
|
314
|
+
throw error;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function ensureDaemonDirectories(paths) {
|
|
318
|
+
ensurePrivateDirectory(paths.dir);
|
|
319
|
+
if (process.platform !== "win32")
|
|
320
|
+
ensurePrivateDirectory(dirname3(paths.socket));
|
|
321
|
+
}
|
|
322
|
+
function readDaemonOwner(paths) {
|
|
323
|
+
try {
|
|
324
|
+
return parseOwner(JSON.parse(readFileSync3(paths.owner, "utf8")));
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (error instanceof Error)
|
|
327
|
+
return null;
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function writeDaemonOwner(paths, owner) {
|
|
332
|
+
writePrivateFile(paths.pid, `${owner.pid}
|
|
333
|
+
`);
|
|
334
|
+
writePrivateFile(paths.endpoint, owner.endpoint.path);
|
|
335
|
+
writePrivateFile(paths.owner, `${JSON.stringify(owner)}
|
|
336
|
+
`);
|
|
337
|
+
}
|
|
338
|
+
function removeDaemonMetadataForOwner(paths, owner) {
|
|
339
|
+
const current = readDaemonOwner(paths);
|
|
340
|
+
if (!current || !sameOwner(current, owner))
|
|
341
|
+
return;
|
|
342
|
+
unlinkQuietly(paths.socket);
|
|
343
|
+
unlinkQuietly(paths.pid);
|
|
344
|
+
unlinkQuietly(paths.endpoint);
|
|
345
|
+
unlinkQuietly(paths.owner);
|
|
346
|
+
}
|
|
347
|
+
function endpointIdentity(endpointPath) {
|
|
348
|
+
if (process.platform === "win32")
|
|
349
|
+
return { kind: "windows", path: endpointPath };
|
|
350
|
+
try {
|
|
351
|
+
const stats = statSync(endpointPath);
|
|
352
|
+
return { kind: "unix", path: endpointPath, dev: stats.dev, ino: stats.ino };
|
|
353
|
+
} catch (error) {
|
|
354
|
+
if (error instanceof Error)
|
|
355
|
+
return { kind: "missing", path: endpointPath };
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function sameEndpoint(a, b) {
|
|
360
|
+
if (a.kind !== b.kind || a.path !== b.path)
|
|
361
|
+
return false;
|
|
362
|
+
switch (a.kind) {
|
|
363
|
+
case "unix":
|
|
364
|
+
return b.kind === "unix" && a.dev === b.dev && a.ino === b.ino;
|
|
365
|
+
case "windows":
|
|
366
|
+
return true;
|
|
367
|
+
case "missing":
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function sameOwner(a, b) {
|
|
372
|
+
return a.pid === b.pid && a.nonce === b.nonce && sameEndpoint(a.endpoint, b.endpoint);
|
|
373
|
+
}
|
|
374
|
+
async function validateExistingOwner(paths, pingOwner) {
|
|
375
|
+
let token = readOrCreateAuthToken(paths);
|
|
376
|
+
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
377
|
+
const owner = readDaemonOwner(paths);
|
|
378
|
+
if (!owner)
|
|
379
|
+
return token;
|
|
380
|
+
const ping = await pingOwner(token);
|
|
381
|
+
if (ping && owner.nonce === ping.nonce && sameEndpoint(owner.endpoint, ping.endpoint)) {
|
|
382
|
+
throw new DaemonAlreadyRunningError("LSP daemon already running");
|
|
383
|
+
}
|
|
384
|
+
if (ping)
|
|
385
|
+
continue;
|
|
386
|
+
if (isProcessAlive(owner.pid))
|
|
387
|
+
throw new DaemonStartupDeferredError("owner_pid_live_unreachable");
|
|
388
|
+
const reread = readDaemonOwner(paths);
|
|
389
|
+
if (!reread || !sameOwner(reread, owner)) {
|
|
390
|
+
throw new DaemonStartupDeferredError("owner_changed_during_cleanup");
|
|
391
|
+
}
|
|
392
|
+
cleanupDeadOwner(paths, owner);
|
|
393
|
+
token = rotateAuthToken(paths);
|
|
394
|
+
return token;
|
|
395
|
+
}
|
|
396
|
+
throw new DaemonStartupDeferredError("reachable_owner_mismatch");
|
|
397
|
+
}
|
|
398
|
+
function cleanupDeadOwner(paths, owner) {
|
|
399
|
+
if (process.platform !== "win32" && existsSync(owner.endpoint.path)) {
|
|
400
|
+
const stat = lstatSync2(owner.endpoint.path);
|
|
401
|
+
if (stat.isSocket())
|
|
402
|
+
unlinkSync3(owner.endpoint.path);
|
|
403
|
+
}
|
|
404
|
+
unlinkQuietly(paths.pid);
|
|
405
|
+
unlinkQuietly(paths.endpoint);
|
|
406
|
+
unlinkQuietly(paths.owner);
|
|
407
|
+
}
|
|
408
|
+
function newOwner(paths) {
|
|
409
|
+
return {
|
|
410
|
+
pid: process.pid,
|
|
411
|
+
nonce: randomUUID(),
|
|
412
|
+
startedAt: new Date().toISOString(),
|
|
413
|
+
endpoint: endpointIdentity(paths.socket)
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function parseOwner(value) {
|
|
417
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
418
|
+
return null;
|
|
419
|
+
const pid = Reflect.get(value, "pid");
|
|
420
|
+
const nonce = Reflect.get(value, "nonce");
|
|
421
|
+
const startedAt = Reflect.get(value, "startedAt");
|
|
422
|
+
const endpoint = parseEndpoint(Reflect.get(value, "endpoint"));
|
|
423
|
+
if (typeof pid !== "number" || typeof nonce !== "string" || typeof startedAt !== "string" || !endpoint)
|
|
424
|
+
return null;
|
|
425
|
+
return { pid, nonce, startedAt, endpoint };
|
|
426
|
+
}
|
|
427
|
+
function parseEndpoint(value) {
|
|
428
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
429
|
+
return null;
|
|
430
|
+
const kind = Reflect.get(value, "kind");
|
|
431
|
+
const path = Reflect.get(value, "path");
|
|
432
|
+
if (typeof path !== "string")
|
|
433
|
+
return null;
|
|
434
|
+
if (kind === undefined)
|
|
435
|
+
return endpointIdentity(path);
|
|
436
|
+
if (kind === "windows")
|
|
437
|
+
return { kind, path };
|
|
438
|
+
if (kind === "missing")
|
|
439
|
+
return { kind, path };
|
|
440
|
+
const dev = Reflect.get(value, "dev");
|
|
441
|
+
const ino = Reflect.get(value, "ino");
|
|
442
|
+
if (kind === "unix" && typeof dev === "number" && typeof ino === "number")
|
|
443
|
+
return { kind, path, dev, ino };
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/proxy.ts
|
|
448
|
+
import { existsSync as existsSync14, realpathSync as realpathSync6 } from "node:fs";
|
|
449
|
+
import { basename as basename4, delimiter as delimiter4, dirname as dirname13, isAbsolute as isAbsolute6 } from "node:path";
|
|
14
450
|
// ../mcp-stdio-core/src/responses.ts
|
|
15
451
|
function successResponse(id, result) {
|
|
16
452
|
return { jsonrpc: "2.0", id, result };
|
|
@@ -18,7 +454,7 @@ function successResponse(id, result) {
|
|
|
18
454
|
function errorResponse(id, code, message, data) {
|
|
19
455
|
return { jsonrpc: "2.0", id, error: data === undefined ? { code, message } : { code, message, data } };
|
|
20
456
|
}
|
|
21
|
-
function
|
|
457
|
+
function jsonRpcId2(value) {
|
|
22
458
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
23
459
|
}
|
|
24
460
|
function messageFromError(error) {
|
|
@@ -169,7 +605,7 @@ function bufferFromChunk(chunk) {
|
|
|
169
605
|
var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
|
|
170
606
|
var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
|
|
171
607
|
var noopLog = () => {};
|
|
172
|
-
function
|
|
608
|
+
function isProcessAlive2(pid) {
|
|
173
609
|
try {
|
|
174
610
|
process.kill(pid, 0);
|
|
175
611
|
return true;
|
|
@@ -184,6 +620,7 @@ async function runJsonRpcStdioServer(config) {
|
|
|
184
620
|
const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
|
|
185
621
|
isClosed = true;
|
|
186
622
|
config.onIdleTimeout?.();
|
|
623
|
+
config.input.destroy();
|
|
187
624
|
});
|
|
188
625
|
const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
|
|
189
626
|
isClosed = true;
|
|
@@ -228,7 +665,7 @@ async function handleParseError(message, config, log) {
|
|
|
228
665
|
}
|
|
229
666
|
async function handleRequest(message, config, log) {
|
|
230
667
|
const parsed = message.payload;
|
|
231
|
-
const id = isPlainRecord(parsed) ?
|
|
668
|
+
const id = isPlainRecord(parsed) ? jsonRpcId2(parsed["id"]) : null;
|
|
232
669
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
233
670
|
log("request", { id: id === null ? null : String(id), method });
|
|
234
671
|
let response;
|
|
@@ -277,10 +714,14 @@ function createParentWatchdog(config, onDeadParent) {
|
|
|
277
714
|
if (pollIntervalMs <= 0)
|
|
278
715
|
return { clear: () => {} };
|
|
279
716
|
const parentPid = config.parentPid ?? process.ppid;
|
|
280
|
-
const probeAlive = config.probeAlive ??
|
|
717
|
+
const probeAlive = config.probeAlive ?? isProcessAlive2;
|
|
281
718
|
let fired = false;
|
|
282
719
|
const timer = setInterval(() => {
|
|
283
|
-
if (fired
|
|
720
|
+
if (fired)
|
|
721
|
+
return;
|
|
722
|
+
const alive = probeAlive(parentPid);
|
|
723
|
+
config.onPoll?.(alive);
|
|
724
|
+
if (alive)
|
|
284
725
|
return;
|
|
285
726
|
fired = true;
|
|
286
727
|
onDeadParent(parentPid, pollIntervalMs);
|
|
@@ -315,28 +756,27 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
|
315
756
|
};
|
|
316
757
|
}
|
|
317
758
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
318
|
-
import { existsSync as
|
|
319
|
-
import { basename as basename3, dirname as
|
|
759
|
+
import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
|
|
760
|
+
import { basename as basename3, dirname as dirname11, join as join5, resolve as resolve8 } from "node:path";
|
|
320
761
|
|
|
321
762
|
// ../lsp-core/src/request-context.ts
|
|
322
763
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
323
|
-
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
764
|
+
import { existsSync as existsSync2, realpathSync, statSync as statSync2 } from "node:fs";
|
|
324
765
|
import { homedir } from "node:os";
|
|
325
|
-
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
766
|
+
import { basename, delimiter, dirname as dirname4, isAbsolute, join, relative, resolve } from "node:path";
|
|
326
767
|
|
|
327
768
|
class LspRequestContextParseError extends Error {
|
|
328
|
-
code;
|
|
329
|
-
name = "LspRequestContextParseError";
|
|
330
769
|
constructor(code, message) {
|
|
331
770
|
super(message);
|
|
332
771
|
this.code = code;
|
|
772
|
+
this.name = "LspRequestContextParseError";
|
|
333
773
|
}
|
|
334
774
|
}
|
|
335
775
|
|
|
336
776
|
class LspRequestContextUnavailableError extends Error {
|
|
337
|
-
name = "LspRequestContextUnavailableError";
|
|
338
777
|
constructor() {
|
|
339
778
|
super("LSP request context is required. Standalone MCP startup must install one with runWithRequestContext(createStandaloneMcpRequestContext()).");
|
|
779
|
+
this.name = "LspRequestContextUnavailableError";
|
|
340
780
|
}
|
|
341
781
|
}
|
|
342
782
|
var storage = new AsyncLocalStorage;
|
|
@@ -356,7 +796,7 @@ function contextCwd() {
|
|
|
356
796
|
}
|
|
357
797
|
function createStandaloneMcpRequestContext(input = {}) {
|
|
358
798
|
const env = input.env ?? process.env;
|
|
359
|
-
const cwd = canonicalCwd(input.cwd ?? process.cwd());
|
|
799
|
+
const cwd = canonicalCwd(input.cwd ?? env["LSP_TOOLS_MCP_CWD"] ?? process.cwd());
|
|
360
800
|
const home = input.homeDir ?? homedir();
|
|
361
801
|
const projectConfigPaths = translateProjectConfigEnv(env["LSP_TOOLS_MCP_PROJECT_CONFIG"], cwd);
|
|
362
802
|
const userConfigPath = translateHomeConfigEnv(env["LSP_TOOLS_MCP_USER_CONFIG"], home, ".codex/lsp-client.json");
|
|
@@ -409,7 +849,7 @@ function translateHomeConfigEnv(value, home, fallback) {
|
|
|
409
849
|
}
|
|
410
850
|
function canonicalCwd(cwd) {
|
|
411
851
|
const resolved = resolve(cwd);
|
|
412
|
-
if (!
|
|
852
|
+
if (!existsSync2(resolved) || !statSync2(resolved).isDirectory()) {
|
|
413
853
|
throw new LspRequestContextParseError("invalid_cwd", `LSP request cwd must be an existing directory: ${cwd}`);
|
|
414
854
|
}
|
|
415
855
|
return realpathSync(resolved);
|
|
@@ -424,7 +864,7 @@ function canonicalizeExistingOrNearestAncestor(path) {
|
|
|
424
864
|
} catch (error) {
|
|
425
865
|
if (!isMissingPathError(error))
|
|
426
866
|
throw error;
|
|
427
|
-
const parent =
|
|
867
|
+
const parent = dirname4(current);
|
|
428
868
|
if (parent === current)
|
|
429
869
|
throw error;
|
|
430
870
|
suffix.unshift(basename(current));
|
|
@@ -468,7 +908,7 @@ function isPathInside(parent, child) {
|
|
|
468
908
|
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
469
909
|
}
|
|
470
910
|
function isMissingPathError(error) {
|
|
471
|
-
const code =
|
|
911
|
+
const code = errorCode3(error);
|
|
472
912
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
473
913
|
}
|
|
474
914
|
function rejectUnknownFields(value, allowed, scope) {
|
|
@@ -480,7 +920,7 @@ function rejectUnknownFields(value, allowed, scope) {
|
|
|
480
920
|
function isRecord(value) {
|
|
481
921
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
482
922
|
}
|
|
483
|
-
function
|
|
923
|
+
function errorCode3(error) {
|
|
484
924
|
if (!error || typeof error !== "object" || !("code" in error))
|
|
485
925
|
return;
|
|
486
926
|
const code = Reflect.get(error, "code");
|
|
@@ -499,22 +939,15 @@ function effectiveExtension(filePath) {
|
|
|
499
939
|
|
|
500
940
|
// ../lsp-core/src/lsp/errors.ts
|
|
501
941
|
class LspConnectionClosedError extends Error {
|
|
502
|
-
serverId;
|
|
503
|
-
root;
|
|
504
|
-
name = "LspConnectionClosedError";
|
|
505
942
|
constructor(serverId, root, message) {
|
|
506
943
|
super(message ?? `LSP connection closed for ${serverId} at ${root}`);
|
|
507
944
|
this.serverId = serverId;
|
|
508
945
|
this.root = root;
|
|
946
|
+
this.name = "LspConnectionClosedError";
|
|
509
947
|
}
|
|
510
948
|
}
|
|
511
949
|
|
|
512
950
|
class LspProcessExitedError extends Error {
|
|
513
|
-
serverId;
|
|
514
|
-
root;
|
|
515
|
-
exitCode;
|
|
516
|
-
stderrTail;
|
|
517
|
-
name = "LspProcessExitedError";
|
|
518
951
|
constructor(serverId, root, exitCode, stderrTail) {
|
|
519
952
|
const stderrSuffix = stderrTail ? `
|
|
520
953
|
stderr tail: ${stderrTail}` : "";
|
|
@@ -523,46 +956,59 @@ stderr tail: ${stderrTail}` : "";
|
|
|
523
956
|
this.root = root;
|
|
524
957
|
this.exitCode = exitCode;
|
|
525
958
|
this.stderrTail = stderrTail;
|
|
959
|
+
this.name = "LspProcessExitedError";
|
|
526
960
|
}
|
|
527
961
|
}
|
|
528
962
|
|
|
529
963
|
class LspRequestTimeoutError extends Error {
|
|
530
|
-
method;
|
|
531
|
-
stderrTail;
|
|
532
|
-
name = "LspRequestTimeoutError";
|
|
533
964
|
constructor(method, stderrTail) {
|
|
534
965
|
const stderrSuffix = stderrTail ? `
|
|
535
966
|
recent stderr: ${stderrTail}` : "";
|
|
536
967
|
super(`LSP request timeout (method: ${method})${stderrSuffix}`);
|
|
537
968
|
this.method = method;
|
|
538
969
|
this.stderrTail = stderrTail;
|
|
970
|
+
this.name = "LspRequestTimeoutError";
|
|
539
971
|
}
|
|
540
972
|
}
|
|
541
973
|
|
|
542
974
|
class LspInvalidPathError extends Error {
|
|
543
|
-
|
|
975
|
+
constructor() {
|
|
976
|
+
super(...arguments);
|
|
977
|
+
this.name = "LspInvalidPathError";
|
|
978
|
+
}
|
|
544
979
|
}
|
|
545
980
|
|
|
546
981
|
class LspServerLookupError extends Error {
|
|
547
|
-
lookup;
|
|
548
|
-
name = "LspServerLookupError";
|
|
549
982
|
constructor(message, lookup) {
|
|
550
983
|
super(message);
|
|
551
984
|
this.lookup = lookup;
|
|
985
|
+
this.name = "LspServerLookupError";
|
|
552
986
|
}
|
|
553
987
|
}
|
|
554
988
|
|
|
555
989
|
class LspServerInitializingError extends Error {
|
|
556
|
-
originalError;
|
|
557
|
-
name = "LspServerInitializingError";
|
|
558
990
|
constructor(originalError) {
|
|
559
991
|
super(`LSP server is still initializing. Please retry in a few seconds. Original error: ${originalError.message}`);
|
|
560
992
|
this.originalError = originalError;
|
|
993
|
+
this.name = "LspServerInitializingError";
|
|
561
994
|
}
|
|
562
995
|
}
|
|
563
996
|
|
|
564
997
|
class LspProcessSpawnError extends Error {
|
|
565
|
-
|
|
998
|
+
constructor() {
|
|
999
|
+
super(...arguments);
|
|
1000
|
+
this.name = "LspProcessSpawnError";
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
class LspClientRespawnBudgetExceededError extends Error {
|
|
1005
|
+
constructor(serverId, root, retryLimit) {
|
|
1006
|
+
super(`LSP server ${serverId} at ${root} failed to stay alive; respawn budget exhausted ` + `(${retryLimit} consecutive dead generations). Retrying after the cooldown may succeed.`);
|
|
1007
|
+
this.serverId = serverId;
|
|
1008
|
+
this.root = root;
|
|
1009
|
+
this.retryLimit = retryLimit;
|
|
1010
|
+
this.name = "LspClientRespawnBudgetExceededError";
|
|
1011
|
+
}
|
|
566
1012
|
}
|
|
567
1013
|
function isLspDeadConnectionError(err) {
|
|
568
1014
|
return err instanceof LspConnectionClosedError || err instanceof LspProcessExitedError;
|
|
@@ -585,6 +1031,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
|
585
1031
|
// ../lsp-core/src/lsp/connection.ts
|
|
586
1032
|
import { pathToFileURL } from "node:url";
|
|
587
1033
|
|
|
1034
|
+
// ../lsp-core/src/lsp/timer-provider.ts
|
|
1035
|
+
var realTimerProvider = {
|
|
1036
|
+
now: () => Date.now(),
|
|
1037
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
1038
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
1039
|
+
};
|
|
1040
|
+
|
|
588
1041
|
// ../lsp-core/src/lsp/constants.ts
|
|
589
1042
|
var DEFAULT_MAX_REFERENCES = 200;
|
|
590
1043
|
var DEFAULT_MAX_SYMBOLS = 200;
|
|
@@ -593,9 +1046,12 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
|
593
1046
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
594
1047
|
var INIT_TIMEOUT_MS = 60000;
|
|
595
1048
|
var IDLE_TIMEOUT_MS = 5 * 60000;
|
|
1049
|
+
var MAX_RESIDENT_CLIENTS = 6;
|
|
596
1050
|
var REAPER_INTERVAL_MS = 60000;
|
|
597
1051
|
var STOP_HARD_KILL_TIMEOUT_MS = 5000;
|
|
598
1052
|
var STOP_SIGKILL_GRACE_MS = 1000;
|
|
1053
|
+
var CLIENT_RESPAWN_RETRY_LIMIT = 2;
|
|
1054
|
+
var CLIENT_RESPAWN_COOLDOWN_MS = 60000;
|
|
599
1055
|
|
|
600
1056
|
// ../lsp-core/src/lsp/json-rpc-connection.ts
|
|
601
1057
|
var HEADER_SEPARATOR2 = `\r
|
|
@@ -607,20 +1063,31 @@ var METHOD_NOT_FOUND = -32601;
|
|
|
607
1063
|
var INTERNAL_ERROR = -32603;
|
|
608
1064
|
|
|
609
1065
|
class JsonRpcConnection {
|
|
610
|
-
reader;
|
|
611
|
-
writer;
|
|
612
|
-
pendingRequests = new Map;
|
|
613
|
-
notificationHandlers = new Map;
|
|
614
|
-
requestHandlers = new Map;
|
|
615
|
-
closeHandlers = [];
|
|
616
|
-
errorHandlers = [];
|
|
617
|
-
inputBuffer = Buffer.alloc(0);
|
|
618
|
-
nextRequestId = 1;
|
|
619
|
-
listening = false;
|
|
620
|
-
disposed = false;
|
|
621
1066
|
constructor(reader, writer) {
|
|
622
1067
|
this.reader = reader;
|
|
623
1068
|
this.writer = writer;
|
|
1069
|
+
this.pendingRequests = new Map;
|
|
1070
|
+
this.notificationHandlers = new Map;
|
|
1071
|
+
this.requestHandlers = new Map;
|
|
1072
|
+
this.closeHandlers = [];
|
|
1073
|
+
this.errorHandlers = [];
|
|
1074
|
+
this.inputBuffer = Buffer.alloc(0);
|
|
1075
|
+
this.nextRequestId = 1;
|
|
1076
|
+
this.listening = false;
|
|
1077
|
+
this.disposed = false;
|
|
1078
|
+
this.handleData = (chunk) => {
|
|
1079
|
+
const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
1080
|
+
this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
|
|
1081
|
+
this.drainInputBuffer();
|
|
1082
|
+
};
|
|
1083
|
+
this.handleClose = () => {
|
|
1084
|
+
for (const handler of this.closeHandlers) {
|
|
1085
|
+
handler();
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
this.handleStreamError = (error) => {
|
|
1089
|
+
this.emitError(error);
|
|
1090
|
+
};
|
|
624
1091
|
}
|
|
625
1092
|
listen() {
|
|
626
1093
|
if (this.listening)
|
|
@@ -655,7 +1122,8 @@ class JsonRpcConnection {
|
|
|
655
1122
|
let cancelAfterWrite = false;
|
|
656
1123
|
let settled = false;
|
|
657
1124
|
const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
|
|
658
|
-
|
|
1125
|
+
let rejectAfterCancelWrite;
|
|
1126
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
659
1127
|
const cleanup = () => {
|
|
660
1128
|
options.signal?.removeEventListener("abort", onAbort);
|
|
661
1129
|
};
|
|
@@ -666,22 +1134,26 @@ class JsonRpcConnection {
|
|
|
666
1134
|
this.pendingRequests.delete(key);
|
|
667
1135
|
cleanup();
|
|
668
1136
|
const rejectCancelled = () => reject(abortError(options.signal));
|
|
1137
|
+
rejectAfterCancelWrite = async () => {
|
|
1138
|
+
try {
|
|
1139
|
+
await writeCancel();
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
this.emitError(toError(error));
|
|
1142
|
+
}
|
|
1143
|
+
rejectCancelled();
|
|
1144
|
+
};
|
|
669
1145
|
if (!requestWritten) {
|
|
670
1146
|
cancelAfterWrite = true;
|
|
671
|
-
rejectCancelled();
|
|
672
1147
|
return;
|
|
673
1148
|
}
|
|
674
|
-
|
|
675
|
-
this.emitError(toError(error));
|
|
676
|
-
rejectCancelled();
|
|
677
|
-
});
|
|
1149
|
+
rejectAfterCancelWrite();
|
|
678
1150
|
};
|
|
679
1151
|
const onAbort = () => settleCancel();
|
|
680
1152
|
this.pendingRequests.set(key, {
|
|
681
1153
|
resolve(result) {
|
|
682
1154
|
settled = true;
|
|
683
1155
|
cleanup();
|
|
684
|
-
|
|
1156
|
+
resolve(result);
|
|
685
1157
|
},
|
|
686
1158
|
reject(error) {
|
|
687
1159
|
settled = true;
|
|
@@ -702,7 +1174,7 @@ class JsonRpcConnection {
|
|
|
702
1174
|
await this.writeMessage(message);
|
|
703
1175
|
requestWritten = true;
|
|
704
1176
|
if (cancelAfterWrite)
|
|
705
|
-
await
|
|
1177
|
+
await rejectAfterCancelWrite?.();
|
|
706
1178
|
} catch (error) {
|
|
707
1179
|
if (settled)
|
|
708
1180
|
return responsePromise;
|
|
@@ -741,19 +1213,6 @@ class JsonRpcConnection {
|
|
|
741
1213
|
this.notificationHandlers.clear();
|
|
742
1214
|
this.requestHandlers.clear();
|
|
743
1215
|
}
|
|
744
|
-
handleData = (chunk) => {
|
|
745
|
-
const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
746
|
-
this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
|
|
747
|
-
this.drainInputBuffer();
|
|
748
|
-
};
|
|
749
|
-
handleClose = () => {
|
|
750
|
-
for (const handler of this.closeHandlers) {
|
|
751
|
-
handler();
|
|
752
|
-
}
|
|
753
|
-
};
|
|
754
|
-
handleStreamError = (error) => {
|
|
755
|
-
this.emitError(error);
|
|
756
|
-
};
|
|
757
1216
|
drainInputBuffer() {
|
|
758
1217
|
while (true) {
|
|
759
1218
|
const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
|
|
@@ -853,13 +1312,13 @@ class JsonRpcConnection {
|
|
|
853
1312
|
const payload = `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
854
1313
|
\r
|
|
855
1314
|
${body}`;
|
|
856
|
-
return new Promise((
|
|
1315
|
+
return new Promise((resolve, reject) => {
|
|
857
1316
|
this.writer.write(payload, (error) => {
|
|
858
1317
|
if (error) {
|
|
859
1318
|
reject(error);
|
|
860
1319
|
return;
|
|
861
1320
|
}
|
|
862
|
-
|
|
1321
|
+
resolve();
|
|
863
1322
|
});
|
|
864
1323
|
});
|
|
865
1324
|
}
|
|
@@ -916,7 +1375,7 @@ function toError(error) {
|
|
|
916
1375
|
|
|
917
1376
|
// ../lsp-core/src/lsp/process.ts
|
|
918
1377
|
import { spawn, spawnSync } from "node:child_process";
|
|
919
|
-
import { existsSync as
|
|
1378
|
+
import { existsSync as existsSync3, statSync as statSync3 } from "node:fs";
|
|
920
1379
|
import { delimiter as delimiter2, join as join2 } from "node:path";
|
|
921
1380
|
function isMissingProcessError(error) {
|
|
922
1381
|
if (!(error instanceof Error) || !("code" in error))
|
|
@@ -930,10 +1389,10 @@ function reportKillError(context, error) {
|
|
|
930
1389
|
}
|
|
931
1390
|
function validateCwd(cwd) {
|
|
932
1391
|
try {
|
|
933
|
-
if (!
|
|
1392
|
+
if (!existsSync3(cwd)) {
|
|
934
1393
|
return { valid: false, error: `Working directory does not exist: ${cwd}` };
|
|
935
1394
|
}
|
|
936
|
-
const stats =
|
|
1395
|
+
const stats = statSync3(cwd);
|
|
937
1396
|
if (!stats.isDirectory()) {
|
|
938
1397
|
return { valid: false, error: `Path is not a directory: ${cwd}` };
|
|
939
1398
|
}
|
|
@@ -946,9 +1405,9 @@ function validateCwd(cwd) {
|
|
|
946
1405
|
}
|
|
947
1406
|
}
|
|
948
1407
|
function wrap(proc) {
|
|
949
|
-
const exitedPromise = new Promise((
|
|
950
|
-
proc.once("close", (code) =>
|
|
951
|
-
proc.once("error", () =>
|
|
1408
|
+
const exitedPromise = new Promise((resolve) => {
|
|
1409
|
+
proc.once("close", (code) => resolve(code ?? 0));
|
|
1410
|
+
proc.once("error", () => resolve(1));
|
|
952
1411
|
});
|
|
953
1412
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
954
1413
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
@@ -1018,7 +1477,7 @@ function resolveWindowsCommand(command, env) {
|
|
|
1018
1477
|
for (const baseDirectory of baseDirectories) {
|
|
1019
1478
|
for (const extension of extensions) {
|
|
1020
1479
|
const candidate = baseDirectory ? join2(baseDirectory, `${command}${extension}`) : `${command}${extension}`;
|
|
1021
|
-
if (
|
|
1480
|
+
if (existsSync3(candidate))
|
|
1022
1481
|
return candidate;
|
|
1023
1482
|
}
|
|
1024
1483
|
}
|
|
@@ -1101,33 +1560,29 @@ function isPosition(value) {
|
|
|
1101
1560
|
|
|
1102
1561
|
// ../lsp-core/src/lsp/transport.ts
|
|
1103
1562
|
class LspClientNotStartedError extends Error {
|
|
1104
|
-
serverId;
|
|
1105
|
-
root;
|
|
1106
|
-
name = "LspClientNotStartedError";
|
|
1107
1563
|
constructor(serverId, root) {
|
|
1108
1564
|
super("LSP client not started");
|
|
1109
1565
|
this.serverId = serverId;
|
|
1110
1566
|
this.root = root;
|
|
1567
|
+
this.name = "LspClientNotStartedError";
|
|
1111
1568
|
}
|
|
1112
1569
|
}
|
|
1113
1570
|
|
|
1114
1571
|
class LspClientTransport {
|
|
1115
|
-
root
|
|
1116
|
-
server;
|
|
1117
|
-
proc = null;
|
|
1118
|
-
connection = null;
|
|
1119
|
-
stderrBuffer = [];
|
|
1120
|
-
processExited = false;
|
|
1121
|
-
diagnosticsStore = new Map;
|
|
1122
|
-
requestTimeoutMs;
|
|
1123
|
-
initializeTimeoutMs;
|
|
1124
|
-
workspaceApplyEditHandler = null;
|
|
1125
|
-
diagnosticPullSupported = false;
|
|
1126
|
-
constructor(root, server2, timeouts = {}) {
|
|
1572
|
+
constructor(root, server, timeouts = {}) {
|
|
1127
1573
|
this.root = root;
|
|
1128
|
-
this.server =
|
|
1574
|
+
this.server = server;
|
|
1575
|
+
this.proc = null;
|
|
1576
|
+
this.connection = null;
|
|
1577
|
+
this.stderrBuffer = [];
|
|
1578
|
+
this.processExited = false;
|
|
1579
|
+
this.diagnosticsStore = new Map;
|
|
1580
|
+
this.workspaceApplyEditHandler = null;
|
|
1581
|
+
this.diagnosticPullSupported = false;
|
|
1582
|
+
this.documentFormattingSupported = false;
|
|
1129
1583
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
1130
1584
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
1585
|
+
this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
|
|
1131
1586
|
}
|
|
1132
1587
|
pid() {
|
|
1133
1588
|
return this.proc?.pid;
|
|
@@ -1147,6 +1602,12 @@ class LspClientTransport {
|
|
|
1147
1602
|
isDiagnosticPullSupported() {
|
|
1148
1603
|
return this.diagnosticPullSupported;
|
|
1149
1604
|
}
|
|
1605
|
+
setDocumentFormattingSupported(supported) {
|
|
1606
|
+
this.documentFormattingSupported = supported;
|
|
1607
|
+
}
|
|
1608
|
+
isDocumentFormattingSupported() {
|
|
1609
|
+
return this.documentFormattingSupported;
|
|
1610
|
+
}
|
|
1150
1611
|
handlePublishDiagnostics(params) {
|
|
1151
1612
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
1152
1613
|
}
|
|
@@ -1222,7 +1683,7 @@ class LspClientTransport {
|
|
|
1222
1683
|
const options = args[1];
|
|
1223
1684
|
const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
|
|
1224
1685
|
const timeoutController = new AbortController;
|
|
1225
|
-
const timeoutHandle = setTimeout(() => {
|
|
1686
|
+
const timeoutHandle = this.timerProvider.setTimeout(() => {
|
|
1226
1687
|
const stderrTail = this.stderrBuffer.slice(-5).join(`
|
|
1227
1688
|
`);
|
|
1228
1689
|
timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
|
|
@@ -1241,7 +1702,7 @@ class LspClientTransport {
|
|
|
1241
1702
|
}
|
|
1242
1703
|
throw error;
|
|
1243
1704
|
} finally {
|
|
1244
|
-
clearTimeout(timeoutHandle);
|
|
1705
|
+
this.timerProvider.clearTimeout(timeoutHandle);
|
|
1245
1706
|
combinedSignal.dispose();
|
|
1246
1707
|
}
|
|
1247
1708
|
}
|
|
@@ -1292,8 +1753,8 @@ class LspClientTransport {
|
|
|
1292
1753
|
try {
|
|
1293
1754
|
proc.kill();
|
|
1294
1755
|
let timeoutId;
|
|
1295
|
-
const timeoutPromise = new Promise((
|
|
1296
|
-
timeoutId = setTimeout(
|
|
1756
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1757
|
+
timeoutId = setTimeout(resolve, STOP_HARD_KILL_TIMEOUT_MS);
|
|
1297
1758
|
});
|
|
1298
1759
|
await Promise.race([
|
|
1299
1760
|
proc.exited.then(() => {
|
|
@@ -1309,7 +1770,7 @@ class LspClientTransport {
|
|
|
1309
1770
|
proc.kill("SIGKILL");
|
|
1310
1771
|
await Promise.race([
|
|
1311
1772
|
proc.exited,
|
|
1312
|
-
new Promise((
|
|
1773
|
+
new Promise((resolve) => setTimeout(resolve, STOP_SIGKILL_GRACE_MS))
|
|
1313
1774
|
]);
|
|
1314
1775
|
} catch (error) {
|
|
1315
1776
|
reportBestEffortCleanupError("hard process kill", error instanceof Error ? error : String(error));
|
|
@@ -1360,6 +1821,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
1360
1821
|
return false;
|
|
1361
1822
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
1362
1823
|
}
|
|
1824
|
+
function supportsDocumentFormatting(capabilities) {
|
|
1825
|
+
if (capabilities === undefined)
|
|
1826
|
+
return false;
|
|
1827
|
+
const provider = capabilities.documentFormattingProvider;
|
|
1828
|
+
if (provider === undefined || provider === null || provider === false)
|
|
1829
|
+
return false;
|
|
1830
|
+
return provider === true || typeof provider === "object";
|
|
1831
|
+
}
|
|
1363
1832
|
|
|
1364
1833
|
class LspClientConnection extends LspClientTransport {
|
|
1365
1834
|
async initialize() {
|
|
@@ -1376,6 +1845,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1376
1845
|
references: {},
|
|
1377
1846
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
1378
1847
|
publishDiagnostics: {},
|
|
1848
|
+
formatting: { dynamicRegistration: false },
|
|
1379
1849
|
rename: {
|
|
1380
1850
|
prepareSupport: true,
|
|
1381
1851
|
prepareSupportDefaultBehavior: 1
|
|
@@ -1417,6 +1887,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1417
1887
|
initializationOptions: this.server.initialization
|
|
1418
1888
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
1419
1889
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
1890
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
1420
1891
|
await this.sendNotification("initialized", {});
|
|
1421
1892
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
1422
1893
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -1425,7 +1896,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1425
1896
|
}
|
|
1426
1897
|
|
|
1427
1898
|
// ../lsp-core/src/lsp/workspace-document-state.ts
|
|
1428
|
-
import { readFileSync, realpathSync as realpathSync2 } from "node:fs";
|
|
1899
|
+
import { readFileSync as readFileSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
1429
1900
|
import { relative as relative2, resolve as resolve2 } from "node:path";
|
|
1430
1901
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
1431
1902
|
|
|
@@ -1612,6 +2083,17 @@ function canonicalPath(filePath) {
|
|
|
1612
2083
|
return absolute;
|
|
1613
2084
|
}
|
|
1614
2085
|
}
|
|
2086
|
+
function normalizeDocumentUri(uri) {
|
|
2087
|
+
let decoded = uri;
|
|
2088
|
+
try {
|
|
2089
|
+
decoded = decodeURIComponent(uri);
|
|
2090
|
+
} catch {
|
|
2091
|
+
decoded = uri;
|
|
2092
|
+
}
|
|
2093
|
+
if (process.platform !== "win32")
|
|
2094
|
+
return decoded;
|
|
2095
|
+
return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
|
|
2096
|
+
}
|
|
1615
2097
|
function isSameOrDescendant(candidate, parent) {
|
|
1616
2098
|
const suffix = relative2(parent, candidate);
|
|
1617
2099
|
return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
|
|
@@ -1622,17 +2104,18 @@ function movedPath(candidate, oldPath, newPath) {
|
|
|
1622
2104
|
}
|
|
1623
2105
|
|
|
1624
2106
|
class WorkspaceDocumentState {
|
|
1625
|
-
sendNotification;
|
|
1626
|
-
clearDiagnostics;
|
|
1627
|
-
openDocuments = new Map;
|
|
1628
|
-
openByUri = new Map;
|
|
1629
|
-
openPromises = new Map;
|
|
1630
|
-
now;
|
|
1631
|
-
versionlessPublishQuiescenceMs;
|
|
1632
2107
|
constructor(sendNotification, clearDiagnostics, options = {}) {
|
|
1633
2108
|
this.sendNotification = sendNotification;
|
|
1634
2109
|
this.clearDiagnostics = clearDiagnostics;
|
|
1635
|
-
this.
|
|
2110
|
+
this.openDocuments = new Map;
|
|
2111
|
+
this.openByUri = new Map;
|
|
2112
|
+
this.openPromises = new Map;
|
|
2113
|
+
this.timerProvider = options.timerProvider ?? {
|
|
2114
|
+
now: options.now ?? (() => Date.now()),
|
|
2115
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
2116
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
2117
|
+
};
|
|
2118
|
+
this.now = () => this.timerProvider.now();
|
|
1636
2119
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
1637
2120
|
}
|
|
1638
2121
|
async openFile(filePath) {
|
|
@@ -1642,7 +2125,7 @@ class WorkspaceDocumentState {
|
|
|
1642
2125
|
await existingOpen;
|
|
1643
2126
|
return this.openFile(path);
|
|
1644
2127
|
}
|
|
1645
|
-
const text =
|
|
2128
|
+
const text = readFileSync4(path, "utf-8");
|
|
1646
2129
|
const existing = this.openDocuments.get(path);
|
|
1647
2130
|
if (!existing)
|
|
1648
2131
|
return this.openDocumentSingleFlight(path, text);
|
|
@@ -1654,7 +2137,7 @@ class WorkspaceDocumentState {
|
|
|
1654
2137
|
return this.openDocuments.get(canonicalPath(filePath))?.version;
|
|
1655
2138
|
}
|
|
1656
2139
|
getStoredDiagnostics(uri) {
|
|
1657
|
-
const state = this.openByUri.get(uri);
|
|
2140
|
+
const state = this.openByUri.get(normalizeDocumentUri(uri));
|
|
1658
2141
|
if (!state)
|
|
1659
2142
|
return [];
|
|
1660
2143
|
return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
|
|
@@ -1676,13 +2159,13 @@ class WorkspaceDocumentState {
|
|
|
1676
2159
|
return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
|
|
1677
2160
|
}
|
|
1678
2161
|
getPullCache(snapshot) {
|
|
1679
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
2162
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1680
2163
|
if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
|
|
1681
2164
|
return null;
|
|
1682
2165
|
return state.pullCache;
|
|
1683
2166
|
}
|
|
1684
2167
|
recordPullDiagnostics(snapshot, report) {
|
|
1685
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
2168
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1686
2169
|
if (!state)
|
|
1687
2170
|
return;
|
|
1688
2171
|
state.pullCache = {
|
|
@@ -1692,7 +2175,7 @@ class WorkspaceDocumentState {
|
|
|
1692
2175
|
};
|
|
1693
2176
|
}
|
|
1694
2177
|
recordPublishedDiagnostics(params) {
|
|
1695
|
-
const state = this.openByUri.get(params.uri);
|
|
2178
|
+
const state = this.openByUri.get(normalizeDocumentUri(params.uri));
|
|
1696
2179
|
if (!state)
|
|
1697
2180
|
return;
|
|
1698
2181
|
state.publishGeneration += 1;
|
|
@@ -1706,7 +2189,7 @@ class WorkspaceDocumentState {
|
|
|
1706
2189
|
this.notifyWaiters(state);
|
|
1707
2190
|
}
|
|
1708
2191
|
resolvePushDiagnostics(snapshot) {
|
|
1709
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
2192
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1710
2193
|
if (!state?.lastPublish)
|
|
1711
2194
|
return { status: "missing" };
|
|
1712
2195
|
const publish = state.lastPublish;
|
|
@@ -1720,20 +2203,22 @@ class WorkspaceDocumentState {
|
|
|
1720
2203
|
return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
|
|
1721
2204
|
}
|
|
1722
2205
|
waitForDiagnosticsActivity(snapshot, timeoutMs) {
|
|
1723
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
2206
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1724
2207
|
if (!state || timeoutMs <= 0)
|
|
1725
2208
|
return Promise.resolve();
|
|
2209
|
+
if (state.publishGeneration !== snapshot.publishGeneration)
|
|
2210
|
+
return Promise.resolve();
|
|
1726
2211
|
return new Promise((resolveActivity) => {
|
|
1727
2212
|
let settled = false;
|
|
1728
2213
|
const finish = () => {
|
|
1729
2214
|
if (settled)
|
|
1730
2215
|
return;
|
|
1731
2216
|
settled = true;
|
|
1732
|
-
clearTimeout(timer);
|
|
2217
|
+
this.timerProvider.clearTimeout(timer);
|
|
1733
2218
|
state.waiters.delete(finish);
|
|
1734
2219
|
resolveActivity();
|
|
1735
2220
|
};
|
|
1736
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
2221
|
+
const timer = this.timerProvider.setTimeout(finish, timeoutMs);
|
|
1737
2222
|
if (typeof timer.unref === "function")
|
|
1738
2223
|
timer.unref();
|
|
1739
2224
|
state.waiters.add(finish);
|
|
@@ -1799,7 +2284,7 @@ class WorkspaceDocumentState {
|
|
|
1799
2284
|
const state = this.openDocuments.get(mutation.path);
|
|
1800
2285
|
if (state) {
|
|
1801
2286
|
await this.closeDocument(state);
|
|
1802
|
-
await this.openDocumentSingleFlight(mutation.path,
|
|
2287
|
+
await this.openDocumentSingleFlight(mutation.path, readFileSync4(mutation.path, "utf-8"));
|
|
1803
2288
|
} else {
|
|
1804
2289
|
watched.push({ uri: pathToFileURL2(mutation.path).href, type: mutation.replaced ? 2 : 1 });
|
|
1805
2290
|
}
|
|
@@ -1811,7 +2296,7 @@ class WorkspaceDocumentState {
|
|
|
1811
2296
|
await this.closeDocument(state);
|
|
1812
2297
|
for (const state of moved) {
|
|
1813
2298
|
const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
|
|
1814
|
-
await this.openDocumentSingleFlight(path,
|
|
2299
|
+
await this.openDocumentSingleFlight(path, readFileSync4(path, "utf-8"));
|
|
1815
2300
|
}
|
|
1816
2301
|
if (moved.length === 0) {
|
|
1817
2302
|
watched.push({ uri: pathToFileURL2(mutation.oldPath).href, type: 3 });
|
|
@@ -1841,7 +2326,7 @@ class WorkspaceDocumentState {
|
|
|
1841
2326
|
waiters: new Set
|
|
1842
2327
|
};
|
|
1843
2328
|
this.openDocuments.set(path, state);
|
|
1844
|
-
this.openByUri.set(state.uri, state);
|
|
2329
|
+
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
1845
2330
|
this.notifyWaiters(state);
|
|
1846
2331
|
await this.sendNotification("textDocument/didOpen", {
|
|
1847
2332
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
@@ -1866,7 +2351,7 @@ class WorkspaceDocumentState {
|
|
|
1866
2351
|
}
|
|
1867
2352
|
async closeDocument(state) {
|
|
1868
2353
|
this.openDocuments.delete(state.path);
|
|
1869
|
-
this.openByUri.delete(state.uri);
|
|
2354
|
+
this.openByUri.delete(normalizeDocumentUri(state.uri));
|
|
1870
2355
|
this.clearDiagnostics(state.uri);
|
|
1871
2356
|
this.notifyWaiters(state);
|
|
1872
2357
|
await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
|
|
@@ -1887,21 +2372,19 @@ function workspaceApplyEditConcurrentFailureReason(phase) {
|
|
|
1887
2372
|
}
|
|
1888
2373
|
|
|
1889
2374
|
// ../lsp-core/src/lsp/workspace-edit-commit.ts
|
|
1890
|
-
import { existsSync as
|
|
2375
|
+
import { existsSync as existsSync5, lstatSync as lstatSync4, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
1891
2376
|
|
|
1892
2377
|
// ../lsp-core/src/lsp/workspace-edit-path.ts
|
|
1893
|
-
import { existsSync as
|
|
1894
|
-
import { dirname as
|
|
2378
|
+
import { existsSync as existsSync4, lstatSync as lstatSync3, readFileSync as readFileSync5, readdirSync, realpathSync as realpathSync3 } from "node:fs";
|
|
2379
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve3 } from "node:path";
|
|
1895
2380
|
import { fileURLToPath } from "node:url";
|
|
1896
2381
|
|
|
1897
2382
|
class WorkspaceEditPathError extends Error {
|
|
1898
|
-
path;
|
|
1899
|
-
detail;
|
|
1900
|
-
name = "WorkspaceEditPathError";
|
|
1901
2383
|
constructor(path, detail) {
|
|
1902
2384
|
super(`${detail}: ${path}`);
|
|
1903
2385
|
this.path = path;
|
|
1904
2386
|
this.detail = detail;
|
|
2387
|
+
this.name = "WorkspaceEditPathError";
|
|
1905
2388
|
}
|
|
1906
2389
|
}
|
|
1907
2390
|
function isPathInsideWorkspace(filePath, workspaceRoot) {
|
|
@@ -1910,8 +2393,8 @@ function isPathInsideWorkspace(filePath, workspaceRoot) {
|
|
|
1910
2393
|
}
|
|
1911
2394
|
function canonicalizeMissingPath(filePath) {
|
|
1912
2395
|
let ancestor = filePath;
|
|
1913
|
-
while (!
|
|
1914
|
-
const parent =
|
|
2396
|
+
while (!existsSync4(ancestor)) {
|
|
2397
|
+
const parent = dirname5(ancestor);
|
|
1915
2398
|
if (parent === ancestor)
|
|
1916
2399
|
throw new WorkspaceEditPathError(filePath, "no existing ancestor");
|
|
1917
2400
|
ancestor = parent;
|
|
@@ -1921,14 +2404,14 @@ function canonicalizeMissingPath(filePath) {
|
|
|
1921
2404
|
function canonicalWorkspaceRoot(workspaceRoot) {
|
|
1922
2405
|
try {
|
|
1923
2406
|
const canonical = realpathSync3(resolve3(workspaceRoot));
|
|
1924
|
-
if (!
|
|
2407
|
+
if (!lstatSync3(canonical).isDirectory()) {
|
|
1925
2408
|
return { success: false, error: `workspace root is not a directory: ${workspaceRoot}` };
|
|
1926
2409
|
}
|
|
1927
2410
|
return {
|
|
1928
2411
|
success: true,
|
|
1929
2412
|
path: canonical,
|
|
1930
2413
|
requestedPath: resolve3(workspaceRoot),
|
|
1931
|
-
followedSymbolicLink:
|
|
2414
|
+
followedSymbolicLink: existsSync4(resolve3(workspaceRoot)) && lstatSync3(resolve3(workspaceRoot)).isSymbolicLink()
|
|
1932
2415
|
};
|
|
1933
2416
|
} catch (error) {
|
|
1934
2417
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -1948,7 +2431,7 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
1948
2431
|
return { success: false, error: `non-file URI ${uri}: ${detail}` };
|
|
1949
2432
|
}
|
|
1950
2433
|
try {
|
|
1951
|
-
const canonical =
|
|
2434
|
+
const canonical = existsSync4(requestedPath) ? realpathSync3(requestedPath) : canonicalizeMissingPath(requestedPath);
|
|
1952
2435
|
if (!isPathInsideWorkspace(canonical, workspaceRoot)) {
|
|
1953
2436
|
return { success: false, error: `${requestedPath}: outside workspace ${workspaceRoot}` };
|
|
1954
2437
|
}
|
|
@@ -1956,7 +2439,7 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
1956
2439
|
success: true,
|
|
1957
2440
|
path: canonical,
|
|
1958
2441
|
requestedPath,
|
|
1959
|
-
followedSymbolicLink:
|
|
2442
|
+
followedSymbolicLink: existsSync4(requestedPath) && lstatSync3(requestedPath).isSymbolicLink()
|
|
1960
2443
|
};
|
|
1961
2444
|
} catch (error) {
|
|
1962
2445
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -1964,11 +2447,11 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
1964
2447
|
}
|
|
1965
2448
|
}
|
|
1966
2449
|
function snapshotPath(path, includeChildren) {
|
|
1967
|
-
if (!
|
|
2450
|
+
if (!existsSync4(path))
|
|
1968
2451
|
return { kind: "missing" };
|
|
1969
|
-
const stats =
|
|
2452
|
+
const stats = lstatSync3(path);
|
|
1970
2453
|
if (stats.isFile())
|
|
1971
|
-
return { kind: "file", content:
|
|
2454
|
+
return { kind: "file", content: readFileSync5(path, "utf-8") };
|
|
1972
2455
|
if (stats.isDirectory()) {
|
|
1973
2456
|
return includeChildren ? { kind: "directory", children: readdirSync(path).sort() } : { kind: "directory" };
|
|
1974
2457
|
}
|
|
@@ -2084,7 +2567,7 @@ function commitOperation(context, operation) {
|
|
|
2084
2567
|
}
|
|
2085
2568
|
if (operation.kind === "rename") {
|
|
2086
2569
|
if (operation.replaceDestination) {
|
|
2087
|
-
const targetKind =
|
|
2570
|
+
const targetKind = existsSync5(operation.newPath) && lstatSync4(operation.newPath).isDirectory() ? "directory" : "file";
|
|
2088
2571
|
io.remove(operation.newPath, targetKind === "directory");
|
|
2089
2572
|
accumulator.mutations.push({ kind: "delete", path: operation.newPath, targetKind });
|
|
2090
2573
|
addModifiedPath(accumulator.filesModified, reportedPath(plan, operation.newPath));
|
|
@@ -2193,13 +2676,11 @@ function canonicalFingerprint(operations) {
|
|
|
2193
2676
|
|
|
2194
2677
|
// ../lsp-core/src/lsp/workspace-edit-types.ts
|
|
2195
2678
|
class WorkspaceEditValidationError extends Error {
|
|
2196
|
-
changeIndex;
|
|
2197
|
-
detail;
|
|
2198
|
-
name = "WorkspaceEditValidationError";
|
|
2199
2679
|
constructor(changeIndex, detail) {
|
|
2200
2680
|
super(`change ${changeIndex}: ${detail}`);
|
|
2201
2681
|
this.changeIndex = changeIndex;
|
|
2202
2682
|
this.detail = detail;
|
|
2683
|
+
this.name = "WorkspaceEditValidationError";
|
|
2203
2684
|
}
|
|
2204
2685
|
}
|
|
2205
2686
|
|
|
@@ -2285,14 +2766,14 @@ function parseSinglePathResource(input, kind) {
|
|
|
2285
2766
|
return;
|
|
2286
2767
|
}
|
|
2287
2768
|
if (kind === "create") {
|
|
2288
|
-
const
|
|
2769
|
+
const options = parseOptions(change["options"], ["overwrite", "ignoreIfExists"], changeIndex);
|
|
2289
2770
|
target.operations.push({
|
|
2290
2771
|
kind,
|
|
2291
2772
|
changeIndex,
|
|
2292
2773
|
path: resolvedPath.path,
|
|
2293
2774
|
reportedPath: resolvedPath.requestedPath,
|
|
2294
|
-
overwrite:
|
|
2295
|
-
ignoreIfExists:
|
|
2775
|
+
overwrite: options["overwrite"] ?? false,
|
|
2776
|
+
ignoreIfExists: options["ignoreIfExists"] ?? false,
|
|
2296
2777
|
followedSymbolicLink: resolvedPath.followedSymbolicLink
|
|
2297
2778
|
});
|
|
2298
2779
|
return;
|
|
@@ -2450,7 +2931,7 @@ function parseDocumentChange(input) {
|
|
|
2450
2931
|
}
|
|
2451
2932
|
|
|
2452
2933
|
// ../lsp-core/src/lsp/workspace-edit-simulation.ts
|
|
2453
|
-
import { dirname as
|
|
2934
|
+
import { dirname as dirname6, relative as relative4, resolve as resolve4 } from "node:path";
|
|
2454
2935
|
|
|
2455
2936
|
// ../lsp-core/src/lsp/workspace-edit-text.ts
|
|
2456
2937
|
function comparePosition(left, right) {
|
|
@@ -2574,7 +3055,7 @@ function virtualDirectoryHasChildren(virtual, path) {
|
|
|
2574
3055
|
return false;
|
|
2575
3056
|
}
|
|
2576
3057
|
function requireVirtualParent(virtual, path, changeIndex) {
|
|
2577
|
-
if (virtual.get(
|
|
3058
|
+
if (virtual.get(dirname6(path))?.kind !== "directory") {
|
|
2578
3059
|
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${path}`);
|
|
2579
3060
|
}
|
|
2580
3061
|
}
|
|
@@ -2694,13 +3175,12 @@ function simulateDelete(operation, virtual) {
|
|
|
2694
3175
|
}
|
|
2695
3176
|
|
|
2696
3177
|
// ../lsp-core/src/lsp/workspace-edit-snapshot.ts
|
|
2697
|
-
import { existsSync as
|
|
2698
|
-
import { dirname as
|
|
3178
|
+
import { existsSync as existsSync6, lstatSync as lstatSync5, readdirSync as readdirSync2 } from "node:fs";
|
|
3179
|
+
import { dirname as dirname7, resolve as resolve5 } from "node:path";
|
|
2699
3180
|
class WorkspaceSnapshotBuilder {
|
|
2700
|
-
workspaceRoot;
|
|
2701
|
-
snapshots = new Map;
|
|
2702
3181
|
constructor(workspaceRoot) {
|
|
2703
3182
|
this.workspaceRoot = workspaceRoot;
|
|
3183
|
+
this.snapshots = new Map;
|
|
2704
3184
|
}
|
|
2705
3185
|
build(operations) {
|
|
2706
3186
|
this.add(this.workspaceRoot, false);
|
|
@@ -2730,9 +3210,9 @@ class WorkspaceSnapshotBuilder {
|
|
|
2730
3210
|
}
|
|
2731
3211
|
if (candidate === this.workspaceRoot)
|
|
2732
3212
|
break;
|
|
2733
|
-
candidate =
|
|
3213
|
+
candidate = dirname7(candidate);
|
|
2734
3214
|
}
|
|
2735
|
-
if (!includeChildren || !
|
|
3215
|
+
if (!includeChildren || !existsSync6(path) || !lstatSync5(path).isDirectory())
|
|
2736
3216
|
return;
|
|
2737
3217
|
for (const child of readdirSync2(path))
|
|
2738
3218
|
this.add(resolve5(path, child), true);
|
|
@@ -2744,8 +3224,10 @@ function snapshotOperations(operations, workspaceRoot) {
|
|
|
2744
3224
|
|
|
2745
3225
|
// ../lsp-core/src/lsp/workspace-edit-plan.ts
|
|
2746
3226
|
class PlanPathIndex {
|
|
2747
|
-
|
|
2748
|
-
|
|
3227
|
+
constructor() {
|
|
3228
|
+
this.firstChangeByPath = new Map;
|
|
3229
|
+
this.reportedPathByCanonical = new Map;
|
|
3230
|
+
}
|
|
2749
3231
|
build(operations) {
|
|
2750
3232
|
for (const operation of operations) {
|
|
2751
3233
|
switch (operation.kind) {
|
|
@@ -2761,11 +3243,11 @@ class PlanPathIndex {
|
|
|
2761
3243
|
}
|
|
2762
3244
|
}
|
|
2763
3245
|
}
|
|
2764
|
-
add(path,
|
|
3246
|
+
add(path, reportedPath, changeIndex) {
|
|
2765
3247
|
if (!this.firstChangeByPath.has(path))
|
|
2766
3248
|
this.firstChangeByPath.set(path, changeIndex);
|
|
2767
3249
|
if (!this.reportedPathByCanonical.has(path))
|
|
2768
|
-
this.reportedPathByCanonical.set(path,
|
|
3250
|
+
this.reportedPathByCanonical.set(path, reportedPath);
|
|
2769
3251
|
}
|
|
2770
3252
|
}
|
|
2771
3253
|
function fingerprintWorkspaceEdit(edit, workspaceRoot) {
|
|
@@ -2834,14 +3316,11 @@ function isRecord4(value) {
|
|
|
2834
3316
|
}
|
|
2835
3317
|
|
|
2836
3318
|
class WorkspaceMutationController {
|
|
2837
|
-
workspaceRoot;
|
|
2838
|
-
documents;
|
|
2839
|
-
activeLease = null;
|
|
2840
|
-
nextLeaseId = 1;
|
|
2841
|
-
io;
|
|
2842
3319
|
constructor(workspaceRoot, documents) {
|
|
2843
3320
|
this.workspaceRoot = workspaceRoot;
|
|
2844
3321
|
this.documents = documents;
|
|
3322
|
+
this.activeLease = null;
|
|
3323
|
+
this.nextLeaseId = 1;
|
|
2845
3324
|
}
|
|
2846
3325
|
setIo(io) {
|
|
2847
3326
|
this.io = io;
|
|
@@ -2880,15 +3359,15 @@ class WorkspaceMutationController {
|
|
|
2880
3359
|
};
|
|
2881
3360
|
}
|
|
2882
3361
|
lease.phase = "applying";
|
|
2883
|
-
lease.applyCompletion = new Promise((
|
|
2884
|
-
lease.resolveApply =
|
|
3362
|
+
lease.applyCompletion = new Promise((resolve) => {
|
|
3363
|
+
lease.resolveApply = resolve;
|
|
2885
3364
|
});
|
|
2886
3365
|
const edit = isRecord4(params) ? params["edit"] : undefined;
|
|
2887
|
-
const
|
|
2888
|
-
lease.serverApply =
|
|
3366
|
+
const record = edit === undefined ? { fingerprint: null, result: failure("workspace/applyEdit params.edit is required", 0) } : await this.applyEdit(edit, lease);
|
|
3367
|
+
lease.serverApply = record;
|
|
2889
3368
|
lease.phase = "settled";
|
|
2890
3369
|
lease.resolveApply?.();
|
|
2891
|
-
return responseFor(
|
|
3370
|
+
return responseFor(record.result);
|
|
2892
3371
|
}
|
|
2893
3372
|
async reconcileRename(leaseToken, edit) {
|
|
2894
3373
|
const lease = this.requireActiveLease(leaseToken);
|
|
@@ -2904,16 +3383,16 @@ class WorkspaceMutationController {
|
|
|
2904
3383
|
const applied = await this.applyEdit(edit, lease);
|
|
2905
3384
|
return { edit, apply: applied.result };
|
|
2906
3385
|
}
|
|
2907
|
-
reconcileServerApply(
|
|
3386
|
+
reconcileServerApply(record, edit) {
|
|
2908
3387
|
if (!edit)
|
|
2909
|
-
return { edit, apply:
|
|
3388
|
+
return { edit, apply: record.result };
|
|
2910
3389
|
const fingerprint = fingerprintWorkspaceEdit(edit, this.workspaceRoot);
|
|
2911
|
-
if (fingerprint.success &&
|
|
2912
|
-
return { edit, apply:
|
|
3390
|
+
if (fingerprint.success && record.fingerprint !== null && fingerprint.fingerprint === record.fingerprint) {
|
|
3391
|
+
return { edit, apply: record.result };
|
|
2913
3392
|
}
|
|
2914
3393
|
return {
|
|
2915
3394
|
edit,
|
|
2916
|
-
apply: failure("rename result conflicts with server-applied workspace edit", 0,
|
|
3395
|
+
apply: failure("rename result conflicts with server-applied workspace edit", 0, record.result)
|
|
2917
3396
|
};
|
|
2918
3397
|
}
|
|
2919
3398
|
async applyEdit(edit, lease) {
|
|
@@ -2954,14 +3433,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
2954
3433
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
2955
3434
|
|
|
2956
3435
|
class LspClient extends LspClientConnection {
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
diagnosticsFreshnessTimeoutMs;
|
|
2961
|
-
constructor(root, server2, options = {}) {
|
|
2962
|
-
super(root, server2, options);
|
|
3436
|
+
constructor(root, server, options = {}) {
|
|
3437
|
+
super(root, server, options);
|
|
3438
|
+
this.diagnosticPullErrors = [];
|
|
2963
3439
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
2964
3440
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
3441
|
+
timerProvider: this.timerProvider,
|
|
2965
3442
|
versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
|
|
2966
3443
|
});
|
|
2967
3444
|
this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
|
|
@@ -3014,6 +3491,18 @@ class LspClient extends LspClientConnection {
|
|
|
3014
3491
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
3015
3492
|
}, options);
|
|
3016
3493
|
}
|
|
3494
|
+
async formatDocument(filePath, options, signal) {
|
|
3495
|
+
if (!this.isDocumentFormattingSupported())
|
|
3496
|
+
return null;
|
|
3497
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
3498
|
+
await this.openFile(absPath);
|
|
3499
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
3500
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
3501
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
3502
|
+
options
|
|
3503
|
+
}, requestOptions);
|
|
3504
|
+
return edits ?? [];
|
|
3505
|
+
}
|
|
3017
3506
|
async workspaceSymbols(query, signal) {
|
|
3018
3507
|
const options = signal === undefined ? {} : { signal };
|
|
3019
3508
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -3053,7 +3542,7 @@ class LspClient extends LspClientConnection {
|
|
|
3053
3542
|
const absPath = this.resolveWorkspacePath(filePath);
|
|
3054
3543
|
const uri = pathToFileURL3(absPath).href;
|
|
3055
3544
|
await this.openFile(absPath);
|
|
3056
|
-
const deadlineAt =
|
|
3545
|
+
const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
|
|
3057
3546
|
for (;; ) {
|
|
3058
3547
|
signal?.throwIfAborted();
|
|
3059
3548
|
const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
|
|
@@ -3066,13 +3555,13 @@ class LspClient extends LspClientConnection {
|
|
|
3066
3555
|
if (!pushFallbackOnly) {
|
|
3067
3556
|
const cached = this.documents.getPullCache(snapshot);
|
|
3068
3557
|
try {
|
|
3069
|
-
const
|
|
3070
|
-
if (
|
|
3558
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3559
|
+
if (remainingMs <= 0)
|
|
3071
3560
|
return this.freshnessTimeout(absPath);
|
|
3072
3561
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
3073
3562
|
textDocument: { uri },
|
|
3074
3563
|
...cached?.resultId === undefined ? {} : { previousResultId: cached.resultId }
|
|
3075
|
-
}, { timeoutMs:
|
|
3564
|
+
}, { timeoutMs: remainingMs, ...signal === undefined ? {} : { signal } });
|
|
3076
3565
|
if (!this.documents.isCurrentSnapshot(snapshot))
|
|
3077
3566
|
continue;
|
|
3078
3567
|
const report = this.parseDiagnosticPullReport(result);
|
|
@@ -3101,7 +3590,7 @@ class LspClient extends LspClientConnection {
|
|
|
3101
3590
|
}
|
|
3102
3591
|
if (!pushFallbackOnly)
|
|
3103
3592
|
continue;
|
|
3104
|
-
const remainingMs = deadlineAt -
|
|
3593
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3105
3594
|
if (remainingMs <= 0) {
|
|
3106
3595
|
if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
|
|
3107
3596
|
const cached = this.documents.getPullCache(snapshot);
|
|
@@ -3153,7 +3642,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3153
3642
|
return wait;
|
|
3154
3643
|
if (signal.aborted)
|
|
3155
3644
|
return Promise.reject(abortError2(signal));
|
|
3156
|
-
return new Promise((
|
|
3645
|
+
return new Promise((resolve, reject) => {
|
|
3157
3646
|
const onAbort = () => {
|
|
3158
3647
|
signal.removeEventListener("abort", onAbort);
|
|
3159
3648
|
reject(abortError2(signal));
|
|
@@ -3161,7 +3650,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3161
3650
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
3162
3651
|
wait.then(() => {
|
|
3163
3652
|
signal.removeEventListener("abort", onAbort);
|
|
3164
|
-
|
|
3653
|
+
resolve();
|
|
3165
3654
|
}, (error) => {
|
|
3166
3655
|
signal.removeEventListener("abort", onAbort);
|
|
3167
3656
|
reject(error);
|
|
@@ -3229,7 +3718,7 @@ async function stopClientBestEffort(client) {
|
|
|
3229
3718
|
function awaitWithSignal(promise, signal) {
|
|
3230
3719
|
if (!signal)
|
|
3231
3720
|
return promise;
|
|
3232
|
-
return new Promise((
|
|
3721
|
+
return new Promise((resolve, reject) => {
|
|
3233
3722
|
let settled = false;
|
|
3234
3723
|
const onAbort = () => {
|
|
3235
3724
|
if (settled)
|
|
@@ -3247,7 +3736,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
3247
3736
|
return;
|
|
3248
3737
|
settled = true;
|
|
3249
3738
|
signal.removeEventListener("abort", onAbort);
|
|
3250
|
-
|
|
3739
|
+
resolve(value);
|
|
3251
3740
|
}, (err) => {
|
|
3252
3741
|
if (settled)
|
|
3253
3742
|
return;
|
|
@@ -3259,20 +3748,18 @@ function awaitWithSignal(promise, signal) {
|
|
|
3259
3748
|
}
|
|
3260
3749
|
|
|
3261
3750
|
class LspManager {
|
|
3262
|
-
clients = new Map;
|
|
3263
|
-
reaperHandle = null;
|
|
3264
|
-
signalDisposer = null;
|
|
3265
|
-
disposed = false;
|
|
3266
|
-
idleTimeoutMs;
|
|
3267
|
-
initTimeoutMs;
|
|
3268
|
-
reaperIntervalMs;
|
|
3269
|
-
clientFactory;
|
|
3270
|
-
now;
|
|
3271
3751
|
constructor(options = {}) {
|
|
3752
|
+
this.clients = new Map;
|
|
3753
|
+
this.pendingStops = new Map;
|
|
3754
|
+
this.respawnBudgets = new Map;
|
|
3755
|
+
this.reaperHandle = null;
|
|
3756
|
+
this.signalDisposer = null;
|
|
3757
|
+
this.disposed = false;
|
|
3272
3758
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
3273
3759
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3760
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3274
3761
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3275
|
-
this.clientFactory = options.clientFactory ?? ((root,
|
|
3762
|
+
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
3276
3763
|
this.now = options.now ?? (() => Date.now());
|
|
3277
3764
|
this.startReaper();
|
|
3278
3765
|
this.signalDisposer = installProcessSignalCleanup(() => this.stopAll());
|
|
@@ -3290,38 +3777,103 @@ class LspManager {
|
|
|
3290
3777
|
getKey(root, serverId) {
|
|
3291
3778
|
return `${root}::${serverId}`;
|
|
3292
3779
|
}
|
|
3780
|
+
tombstoneStop(key, client) {
|
|
3781
|
+
const stop = stopClientBestEffort(client);
|
|
3782
|
+
this.pendingStops.set(key, stop);
|
|
3783
|
+
stop.finally(() => {
|
|
3784
|
+
if (this.pendingStops.get(key) === stop) {
|
|
3785
|
+
this.pendingStops.delete(key);
|
|
3786
|
+
}
|
|
3787
|
+
});
|
|
3788
|
+
return stop;
|
|
3789
|
+
}
|
|
3790
|
+
recordDeadGeneration(key) {
|
|
3791
|
+
let budget = this.respawnBudgets.get(key);
|
|
3792
|
+
if (budget === undefined) {
|
|
3793
|
+
budget = { deadGenerations: 0, exhaustedAt: null };
|
|
3794
|
+
this.respawnBudgets.set(key, budget);
|
|
3795
|
+
}
|
|
3796
|
+
budget.deadGenerations += 1;
|
|
3797
|
+
}
|
|
3798
|
+
markHealthyGeneration(key) {
|
|
3799
|
+
this.respawnBudgets.delete(key);
|
|
3800
|
+
}
|
|
3801
|
+
ensureRespawnAllowed(key, root, serverId) {
|
|
3802
|
+
const budget = this.respawnBudgets.get(key);
|
|
3803
|
+
if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
|
|
3804
|
+
return;
|
|
3805
|
+
if (budget.exhaustedAt === null) {
|
|
3806
|
+
budget.exhaustedAt = this.now();
|
|
3807
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3808
|
+
}
|
|
3809
|
+
if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
|
|
3810
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3811
|
+
}
|
|
3812
|
+
budget.deadGenerations = 0;
|
|
3813
|
+
budget.exhaustedAt = null;
|
|
3814
|
+
}
|
|
3293
3815
|
reapStale() {
|
|
3294
3816
|
const t = this.now();
|
|
3295
3817
|
for (const [key, managed] of this.clients) {
|
|
3296
3818
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3297
|
-
stopClientBestEffort(managed.client);
|
|
3298
3819
|
this.clients.delete(key);
|
|
3820
|
+
this.tombstoneStop(key, managed.client);
|
|
3299
3821
|
continue;
|
|
3300
3822
|
}
|
|
3301
3823
|
if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
|
|
3302
|
-
stopClientBestEffort(managed.client);
|
|
3303
3824
|
this.clients.delete(key);
|
|
3825
|
+
this.tombstoneStop(key, managed.client);
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
evictForAdmission() {
|
|
3830
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
3831
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
3832
|
+
if (!victim)
|
|
3833
|
+
return;
|
|
3834
|
+
this.clients.delete(victim.key);
|
|
3835
|
+
this.tombstoneStop(victim.key, victim.managed.client);
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
leastRecentlyUsedIdleClient() {
|
|
3839
|
+
let candidate = null;
|
|
3840
|
+
for (const [key, managed] of this.clients) {
|
|
3841
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
3842
|
+
continue;
|
|
3843
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
3844
|
+
candidate = { key, managed };
|
|
3304
3845
|
}
|
|
3305
3846
|
}
|
|
3847
|
+
return candidate;
|
|
3306
3848
|
}
|
|
3307
3849
|
async tryDeleteIfOrphaned(key, managed) {
|
|
3308
3850
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
3309
3851
|
this.clients.delete(key);
|
|
3310
|
-
await
|
|
3852
|
+
await this.tombstoneStop(key, managed.client);
|
|
3311
3853
|
}
|
|
3312
3854
|
}
|
|
3313
|
-
async getClient(root,
|
|
3855
|
+
async getClient(root, server, signal) {
|
|
3314
3856
|
if (this.disposed) {
|
|
3315
3857
|
throw new Error("LspManager has been disposed");
|
|
3316
3858
|
}
|
|
3317
3859
|
signal?.throwIfAborted();
|
|
3318
|
-
const key = this.getKey(root,
|
|
3860
|
+
const key = this.getKey(root, server.id);
|
|
3861
|
+
for (;; ) {
|
|
3862
|
+
const pendingStop = this.pendingStops.get(key);
|
|
3863
|
+
if (pendingStop === undefined)
|
|
3864
|
+
break;
|
|
3865
|
+
await awaitWithSignal(pendingStop, signal);
|
|
3866
|
+
signal?.throwIfAborted();
|
|
3867
|
+
}
|
|
3868
|
+
if (this.disposed) {
|
|
3869
|
+
throw new Error("LspManager has been disposed");
|
|
3870
|
+
}
|
|
3319
3871
|
let managed = this.clients.get(key);
|
|
3320
3872
|
if (managed) {
|
|
3321
3873
|
const t = this.now();
|
|
3322
3874
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3323
|
-
await stopClientBestEffort(managed.client);
|
|
3324
3875
|
this.clients.delete(key);
|
|
3876
|
+
await this.tombstoneStop(key, managed.client);
|
|
3325
3877
|
managed = undefined;
|
|
3326
3878
|
}
|
|
3327
3879
|
}
|
|
@@ -3342,15 +3894,21 @@ class LspManager {
|
|
|
3342
3894
|
signal.throwIfAborted();
|
|
3343
3895
|
}
|
|
3344
3896
|
if (!managed.client.isAlive()) {
|
|
3345
|
-
|
|
3346
|
-
this.clients.
|
|
3347
|
-
|
|
3897
|
+
this.recordDeadGeneration(key);
|
|
3898
|
+
if (this.clients.get(key) === managed) {
|
|
3899
|
+
this.clients.delete(key);
|
|
3900
|
+
}
|
|
3901
|
+
await this.tombstoneStop(key, managed.client);
|
|
3902
|
+
return this.getClient(root, server, signal);
|
|
3348
3903
|
}
|
|
3904
|
+
this.markHealthyGeneration(key);
|
|
3349
3905
|
managed.refCount++;
|
|
3350
3906
|
managed.lastUsedAt = this.now();
|
|
3351
3907
|
return managed.client;
|
|
3352
3908
|
}
|
|
3353
|
-
|
|
3909
|
+
this.evictForAdmission();
|
|
3910
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3911
|
+
const client = this.clientFactory(root, server);
|
|
3354
3912
|
const initStartedAt = this.now();
|
|
3355
3913
|
const initPromise = (async () => {
|
|
3356
3914
|
await client.start();
|
|
@@ -3373,7 +3931,7 @@ class LspManager {
|
|
|
3373
3931
|
if (this.clients.get(key) === newManaged) {
|
|
3374
3932
|
this.clients.delete(key);
|
|
3375
3933
|
}
|
|
3376
|
-
await
|
|
3934
|
+
await this.tombstoneStop(key, client);
|
|
3377
3935
|
throw err;
|
|
3378
3936
|
}
|
|
3379
3937
|
newManaged.pendingWaiters--;
|
|
@@ -3384,6 +3942,15 @@ class LspManager {
|
|
|
3384
3942
|
await this.tryDeleteIfOrphaned(key, newManaged);
|
|
3385
3943
|
signal.throwIfAborted();
|
|
3386
3944
|
}
|
|
3945
|
+
if (!client.isAlive()) {
|
|
3946
|
+
this.recordDeadGeneration(key);
|
|
3947
|
+
if (this.clients.get(key) === newManaged) {
|
|
3948
|
+
this.clients.delete(key);
|
|
3949
|
+
}
|
|
3950
|
+
await this.tombstoneStop(key, client);
|
|
3951
|
+
return this.getClient(root, server, signal);
|
|
3952
|
+
}
|
|
3953
|
+
this.markHealthyGeneration(key);
|
|
3387
3954
|
newManaged.refCount++;
|
|
3388
3955
|
newManaged.lastUsedAt = this.now();
|
|
3389
3956
|
return client;
|
|
@@ -3404,15 +3971,21 @@ class LspManager {
|
|
|
3404
3971
|
if (client && managed.client !== client)
|
|
3405
3972
|
return;
|
|
3406
3973
|
this.clients.delete(key);
|
|
3407
|
-
|
|
3974
|
+
this.tombstoneStop(key, managed.client);
|
|
3408
3975
|
}
|
|
3409
|
-
warmupClient(root,
|
|
3976
|
+
warmupClient(root, server) {
|
|
3410
3977
|
if (this.disposed)
|
|
3411
3978
|
return;
|
|
3412
|
-
const key = this.getKey(root,
|
|
3413
|
-
if (this.clients.has(key))
|
|
3979
|
+
const key = this.getKey(root, server.id);
|
|
3980
|
+
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
3981
|
+
return;
|
|
3982
|
+
this.evictForAdmission();
|
|
3983
|
+
try {
|
|
3984
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3985
|
+
} catch {
|
|
3414
3986
|
return;
|
|
3415
|
-
|
|
3987
|
+
}
|
|
3988
|
+
const client = this.clientFactory(root, server);
|
|
3416
3989
|
const initStartedAt = this.now();
|
|
3417
3990
|
const initPromise = (async () => {
|
|
3418
3991
|
await client.start();
|
|
@@ -3437,7 +4010,7 @@ class LspManager {
|
|
|
3437
4010
|
if (this.clients.get(key) === managed) {
|
|
3438
4011
|
this.clients.delete(key);
|
|
3439
4012
|
}
|
|
3440
|
-
|
|
4013
|
+
this.tombstoneStop(key, client);
|
|
3441
4014
|
});
|
|
3442
4015
|
}
|
|
3443
4016
|
isServerInitializing(root, serverId) {
|
|
@@ -3481,8 +4054,11 @@ class LspManager {
|
|
|
3481
4054
|
for (const managed of this.clients.values()) {
|
|
3482
4055
|
stopPromises.push(stopClientBestEffort(managed.client));
|
|
3483
4056
|
}
|
|
4057
|
+
const tombstonedStops = [...this.pendingStops.values()];
|
|
3484
4058
|
this.clients.clear();
|
|
3485
|
-
|
|
4059
|
+
this.respawnBudgets.clear();
|
|
4060
|
+
await Promise.allSettled([...stopPromises, ...tombstonedStops]);
|
|
4061
|
+
this.pendingStops.clear();
|
|
3486
4062
|
}
|
|
3487
4063
|
}
|
|
3488
4064
|
var _defaultInstance = null;
|
|
@@ -3500,57 +4076,52 @@ async function disposeDefaultLspManager() {
|
|
|
3500
4076
|
}
|
|
3501
4077
|
}
|
|
3502
4078
|
|
|
3503
|
-
// ../lsp-core/src/lsp/
|
|
3504
|
-
import { existsSync as
|
|
3505
|
-
import { dirname as
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
4079
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
4080
|
+
import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
4081
|
+
import { dirname as dirname8, join as join3 } from "node:path";
|
|
4082
|
+
|
|
4083
|
+
// ../lsp-core/src/lsp/workspace-markers.ts
|
|
4084
|
+
var GIT_WORKSPACE_MARKER = ".git";
|
|
4085
|
+
var PROJECT_WORKSPACE_MARKERS = [
|
|
4086
|
+
"package.json",
|
|
4087
|
+
"pyproject.toml",
|
|
4088
|
+
"Cargo.toml",
|
|
4089
|
+
"go.mod",
|
|
4090
|
+
"pom.xml",
|
|
4091
|
+
"build.gradle"
|
|
4092
|
+
];
|
|
4093
|
+
var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
|
|
4094
|
+
|
|
4095
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
4096
|
+
function findWorkspaceRootOutsideContext(directory) {
|
|
4097
|
+
const marked = nearestMarkedAncestor(directory);
|
|
4098
|
+
if (marked !== undefined)
|
|
4099
|
+
return marked;
|
|
4100
|
+
return realpathSync4(nearestExistingAncestor(directory));
|
|
4101
|
+
}
|
|
4102
|
+
function nearestMarkedAncestor(directory) {
|
|
4103
|
+
let current = directory;
|
|
4104
|
+
for (;; ) {
|
|
4105
|
+
if (existsSync7(current) && WORKSPACE_MARKERS.some((marker) => existsSync7(join3(current, marker)))) {
|
|
4106
|
+
return realpathSync4(current);
|
|
4107
|
+
}
|
|
4108
|
+
const parent = dirname8(current);
|
|
4109
|
+
if (parent === current)
|
|
4110
|
+
return;
|
|
4111
|
+
current = parent;
|
|
3518
4112
|
}
|
|
3519
4113
|
}
|
|
3520
|
-
function
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
}
|
|
3528
|
-
|
|
3529
|
-
return value === "declined" || value === "allowed";
|
|
3530
|
-
}
|
|
3531
|
-
function writeInstallDecisions(decisions) {
|
|
3532
|
-
const path = getInstallDecisionsPath();
|
|
3533
|
-
mkdirSync(dirname5(path), { recursive: true });
|
|
3534
|
-
const tmpPath = `${path}.tmp`;
|
|
3535
|
-
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3536
|
-
`, "utf8");
|
|
3537
|
-
renameSync2(tmpPath, path);
|
|
3538
|
-
}
|
|
3539
|
-
function isInstallDecisions(value) {
|
|
3540
|
-
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3541
|
-
}
|
|
3542
|
-
function isInstallDecisionRecord(value) {
|
|
3543
|
-
if (!isRecord5(value))
|
|
3544
|
-
return false;
|
|
3545
|
-
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3546
|
-
}
|
|
3547
|
-
function isRecord5(value) {
|
|
3548
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4114
|
+
function nearestExistingAncestor(directory) {
|
|
4115
|
+
let current = directory;
|
|
4116
|
+
while (!existsSync7(current)) {
|
|
4117
|
+
const parent = dirname8(current);
|
|
4118
|
+
if (parent === current)
|
|
4119
|
+
return current;
|
|
4120
|
+
current = parent;
|
|
4121
|
+
}
|
|
4122
|
+
return current;
|
|
3549
4123
|
}
|
|
3550
4124
|
|
|
3551
|
-
// ../lsp-core/src/lsp/config-loader.ts
|
|
3552
|
-
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
|
|
3553
|
-
|
|
3554
4125
|
// ../lsp-core/src/lsp/server-definitions.ts
|
|
3555
4126
|
var LSP_INSTALL_HINTS = {
|
|
3556
4127
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -3596,6 +4167,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
3596
4167
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
3597
4168
|
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"
|
|
3598
4169
|
};
|
|
4170
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
4171
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
4172
|
+
vue: "bun add -d @vue/language-server",
|
|
4173
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
4174
|
+
oxlint: "bun add -d oxlint",
|
|
4175
|
+
biome: "bun add -d @biomejs/biome",
|
|
4176
|
+
svelte: "bun add -d svelte-language-server",
|
|
4177
|
+
astro: "bun add -d @astrojs/language-server",
|
|
4178
|
+
bash: "bun add -d bash-language-server",
|
|
4179
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
4180
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
4181
|
+
php: "bun add -d intelephense",
|
|
4182
|
+
prisma: "bun add -d prisma",
|
|
4183
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
4184
|
+
pyright: "uv add --dev pyright",
|
|
4185
|
+
basedpyright: "uv add --dev basedpyright",
|
|
4186
|
+
ruff: "uv add --dev ruff",
|
|
4187
|
+
ty: "uv add --dev ty",
|
|
4188
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
4189
|
+
};
|
|
3599
4190
|
var BUILTIN_SERVERS = {
|
|
3600
4191
|
typescript: {
|
|
3601
4192
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -3698,7 +4289,56 @@ var BUILTIN_SERVERS = {
|
|
|
3698
4289
|
}
|
|
3699
4290
|
};
|
|
3700
4291
|
|
|
4292
|
+
// ../lsp-core/src/lsp/server-install-state.ts
|
|
4293
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4294
|
+
import { dirname as dirname9 } from "node:path";
|
|
4295
|
+
function getInstallDecisionsPath() {
|
|
4296
|
+
return lspRequestContext().installDecisionsPath;
|
|
4297
|
+
}
|
|
4298
|
+
function loadInstallDecisions() {
|
|
4299
|
+
const path = getInstallDecisionsPath();
|
|
4300
|
+
if (!existsSync8(path))
|
|
4301
|
+
return {};
|
|
4302
|
+
try {
|
|
4303
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
4304
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
4305
|
+
} catch {
|
|
4306
|
+
return {};
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
function loadInstallDecision(serverId) {
|
|
4310
|
+
return loadInstallDecisions()[serverId];
|
|
4311
|
+
}
|
|
4312
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
4313
|
+
const decisions = loadInstallDecisions();
|
|
4314
|
+
decisions[serverId] = { decision, decidedAt };
|
|
4315
|
+
writeInstallDecisions(decisions);
|
|
4316
|
+
}
|
|
4317
|
+
function isInstallDecision(value) {
|
|
4318
|
+
return value === "declined" || value === "allowed";
|
|
4319
|
+
}
|
|
4320
|
+
function writeInstallDecisions(decisions) {
|
|
4321
|
+
const path = getInstallDecisionsPath();
|
|
4322
|
+
mkdirSync3(dirname9(path), { recursive: true });
|
|
4323
|
+
const tmpPath = `${path}.tmp`;
|
|
4324
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
4325
|
+
`, "utf8");
|
|
4326
|
+
renameSync2(tmpPath, path);
|
|
4327
|
+
}
|
|
4328
|
+
function isInstallDecisions(value) {
|
|
4329
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
4330
|
+
}
|
|
4331
|
+
function isInstallDecisionRecord(value) {
|
|
4332
|
+
if (!isRecord5(value))
|
|
4333
|
+
return false;
|
|
4334
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
4335
|
+
}
|
|
4336
|
+
function isRecord5(value) {
|
|
4337
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4338
|
+
}
|
|
4339
|
+
|
|
3701
4340
|
// ../lsp-core/src/lsp/config-loader.ts
|
|
4341
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
|
|
3702
4342
|
function getProjectConfigPaths() {
|
|
3703
4343
|
return lspRequestContext().projectConfigPaths;
|
|
3704
4344
|
}
|
|
@@ -3706,10 +4346,10 @@ function getUserConfigPath() {
|
|
|
3706
4346
|
return lspRequestContext().userConfigPath;
|
|
3707
4347
|
}
|
|
3708
4348
|
function loadJsonFile(path) {
|
|
3709
|
-
if (!
|
|
4349
|
+
if (!existsSync9(path))
|
|
3710
4350
|
return null;
|
|
3711
4351
|
try {
|
|
3712
|
-
const parsed = JSON.parse(
|
|
4352
|
+
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
3713
4353
|
return isConfigJson(parsed) ? parsed : null;
|
|
3714
4354
|
} catch {
|
|
3715
4355
|
return null;
|
|
@@ -3753,10 +4393,10 @@ function getMergedServers() {
|
|
|
3753
4393
|
}
|
|
3754
4394
|
if (seen.has(id))
|
|
3755
4395
|
continue;
|
|
3756
|
-
const
|
|
3757
|
-
if (!
|
|
4396
|
+
const server = createServerFromEntry(id, entry, source);
|
|
4397
|
+
if (!server)
|
|
3758
4398
|
continue;
|
|
3759
|
-
servers.push(
|
|
4399
|
+
servers.push(server);
|
|
3760
4400
|
seen.add(id);
|
|
3761
4401
|
}
|
|
3762
4402
|
}
|
|
@@ -3788,7 +4428,7 @@ function createServerFromEntry(id, entry, source) {
|
|
|
3788
4428
|
if (source === "project") {
|
|
3789
4429
|
if (!builtin)
|
|
3790
4430
|
return null;
|
|
3791
|
-
const
|
|
4431
|
+
const server = createServer({
|
|
3792
4432
|
id,
|
|
3793
4433
|
command: builtin.command,
|
|
3794
4434
|
extensions: entry.extensions ?? builtin.extensions,
|
|
@@ -3796,35 +4436,35 @@ function createServerFromEntry(id, entry, source) {
|
|
|
3796
4436
|
source
|
|
3797
4437
|
});
|
|
3798
4438
|
if (entry.initialization !== undefined) {
|
|
3799
|
-
|
|
4439
|
+
server.initialization = entry.initialization;
|
|
3800
4440
|
}
|
|
3801
|
-
return
|
|
4441
|
+
return server;
|
|
3802
4442
|
}
|
|
3803
4443
|
if (entry.command && entry.extensions) {
|
|
3804
|
-
const
|
|
4444
|
+
const server = createServer({
|
|
3805
4445
|
id,
|
|
3806
4446
|
command: entry.command,
|
|
3807
4447
|
extensions: entry.extensions,
|
|
3808
4448
|
priority: entry.priority ?? 0,
|
|
3809
4449
|
source
|
|
3810
4450
|
});
|
|
3811
|
-
applyOptionalServerFields(
|
|
3812
|
-
return
|
|
4451
|
+
applyOptionalServerFields(server, entry);
|
|
4452
|
+
return server;
|
|
3813
4453
|
}
|
|
3814
4454
|
if (!builtin)
|
|
3815
4455
|
return null;
|
|
3816
|
-
const
|
|
4456
|
+
const server = createServer({
|
|
3817
4457
|
id,
|
|
3818
4458
|
command: entry.command ?? builtin.command,
|
|
3819
4459
|
extensions: entry.extensions ?? builtin.extensions,
|
|
3820
4460
|
priority: entry.priority ?? 0,
|
|
3821
4461
|
source
|
|
3822
4462
|
});
|
|
3823
|
-
applyOptionalServerFields(
|
|
3824
|
-
return
|
|
4463
|
+
applyOptionalServerFields(server, entry);
|
|
4464
|
+
return server;
|
|
3825
4465
|
}
|
|
3826
4466
|
function createServer(input) {
|
|
3827
|
-
const
|
|
4467
|
+
const server = {
|
|
3828
4468
|
id: input.id,
|
|
3829
4469
|
command: input.command,
|
|
3830
4470
|
extensions: input.extensions,
|
|
@@ -3832,19 +4472,19 @@ function createServer(input) {
|
|
|
3832
4472
|
source: input.source
|
|
3833
4473
|
};
|
|
3834
4474
|
if (input.env !== undefined) {
|
|
3835
|
-
|
|
4475
|
+
server.env = input.env;
|
|
3836
4476
|
}
|
|
3837
4477
|
if (input.initialization !== undefined) {
|
|
3838
|
-
|
|
4478
|
+
server.initialization = input.initialization;
|
|
3839
4479
|
}
|
|
3840
|
-
return
|
|
4480
|
+
return server;
|
|
3841
4481
|
}
|
|
3842
|
-
function applyOptionalServerFields(
|
|
4482
|
+
function applyOptionalServerFields(server, entry) {
|
|
3843
4483
|
if (entry.env !== undefined) {
|
|
3844
|
-
|
|
4484
|
+
server.env = entry.env;
|
|
3845
4485
|
}
|
|
3846
4486
|
if (entry.initialization !== undefined) {
|
|
3847
|
-
|
|
4487
|
+
server.initialization = entry.initialization;
|
|
3848
4488
|
}
|
|
3849
4489
|
}
|
|
3850
4490
|
function isConfigJson(value) {
|
|
@@ -3894,64 +4534,165 @@ function getDisabledServerIds() {
|
|
|
3894
4534
|
}
|
|
3895
4535
|
|
|
3896
4536
|
// ../lsp-core/src/lsp/server-installation.ts
|
|
3897
|
-
import { existsSync as
|
|
3898
|
-
import { delimiter as delimiter3, join as
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
4537
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
4538
|
+
import { delimiter as delimiter3, dirname as dirname10, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
|
|
4539
|
+
var LOCAL_BIN_RULES = [
|
|
4540
|
+
{
|
|
4541
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
4542
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
4543
|
+
},
|
|
4544
|
+
{
|
|
4545
|
+
markers: [
|
|
4546
|
+
"pyproject.toml",
|
|
4547
|
+
"ty.toml",
|
|
4548
|
+
"requirements.txt",
|
|
4549
|
+
"setup.py",
|
|
4550
|
+
"setup.cfg",
|
|
4551
|
+
"Pipfile",
|
|
4552
|
+
"pyrightconfig.json",
|
|
4553
|
+
"ruff.toml",
|
|
4554
|
+
".ruff.toml"
|
|
4555
|
+
],
|
|
4556
|
+
binDirs: [
|
|
4557
|
+
join4(".venv", "bin"),
|
|
4558
|
+
join4(".venv", "Scripts"),
|
|
4559
|
+
join4("venv", "bin"),
|
|
4560
|
+
join4("venv", "Scripts"),
|
|
4561
|
+
join4(".env", "bin"),
|
|
4562
|
+
join4(".env", "Scripts")
|
|
4563
|
+
]
|
|
4564
|
+
},
|
|
4565
|
+
{
|
|
4566
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
4567
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
4568
|
+
},
|
|
4569
|
+
{
|
|
4570
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
4571
|
+
binDirs: ["bin"]
|
|
4572
|
+
}
|
|
4573
|
+
];
|
|
4574
|
+
var resolutionCache = new Map;
|
|
4575
|
+
var probeCount = 0;
|
|
4576
|
+
function probe(path) {
|
|
4577
|
+
probeCount += 1;
|
|
4578
|
+
return existsSync10(path);
|
|
4579
|
+
}
|
|
4580
|
+
function executableSuffixes(platform, pathExt) {
|
|
4581
|
+
if (platform !== "win32")
|
|
4582
|
+
return [""];
|
|
4583
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
4584
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
4585
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
4586
|
+
}
|
|
4587
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
4588
|
+
for (const suffix of suffixes) {
|
|
4589
|
+
const candidate = join4(directory, command + suffix);
|
|
4590
|
+
if (probe(candidate))
|
|
4591
|
+
return candidate;
|
|
3908
4592
|
}
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
4593
|
+
return null;
|
|
4594
|
+
}
|
|
4595
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
4596
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
4597
|
+
let current = resolve7(workingDirectory);
|
|
4598
|
+
while (true) {
|
|
4599
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
4600
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
4601
|
+
continue;
|
|
4602
|
+
for (const binDir of rule.binDirs) {
|
|
4603
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
4604
|
+
if (found !== null)
|
|
4605
|
+
return found;
|
|
4606
|
+
}
|
|
3918
4607
|
}
|
|
4608
|
+
if (probe(join4(current, ".git")))
|
|
4609
|
+
return null;
|
|
4610
|
+
if (boundary !== undefined && current === boundary)
|
|
4611
|
+
return null;
|
|
4612
|
+
const parent = dirname10(current);
|
|
4613
|
+
if (parent === current)
|
|
4614
|
+
return null;
|
|
4615
|
+
current = parent;
|
|
3919
4616
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
4617
|
+
}
|
|
4618
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
4619
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
4620
|
+
if (platform === "win32" && !pathEnv) {
|
|
3922
4621
|
pathEnv = process.env["Path"] ?? "";
|
|
3923
4622
|
}
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
}
|
|
4623
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
4624
|
+
if (entry.length === 0)
|
|
4625
|
+
continue;
|
|
4626
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
4627
|
+
if (found !== null)
|
|
4628
|
+
return found;
|
|
3931
4629
|
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
4630
|
+
return null;
|
|
4631
|
+
}
|
|
4632
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
4633
|
+
if (command.length === 0)
|
|
4634
|
+
return null;
|
|
4635
|
+
const [cmd] = command;
|
|
4636
|
+
if (cmd === undefined || cmd.length === 0)
|
|
4637
|
+
return null;
|
|
4638
|
+
const platform = options.platform ?? process.platform;
|
|
4639
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
4640
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
4641
|
+
const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
4642
|
+
return probe(explicit) ? explicit : null;
|
|
4643
|
+
}
|
|
4644
|
+
const cacheKey = JSON.stringify([
|
|
4645
|
+
workingDirectory ?? "",
|
|
4646
|
+
cmd,
|
|
4647
|
+
platform,
|
|
4648
|
+
options.stopAt ?? "",
|
|
4649
|
+
options.pathExt ?? "",
|
|
4650
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
4651
|
+
]);
|
|
4652
|
+
const cached = resolutionCache.get(cacheKey);
|
|
4653
|
+
if (cached !== undefined)
|
|
4654
|
+
return cached;
|
|
4655
|
+
let resolved = null;
|
|
4656
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
4657
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
4658
|
+
}
|
|
4659
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
4660
|
+
if (resolved === null && cmd === "node")
|
|
4661
|
+
resolved = cmd;
|
|
4662
|
+
resolutionCache.set(cacheKey, resolved);
|
|
4663
|
+
return resolved;
|
|
4664
|
+
}
|
|
4665
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
4666
|
+
if (command.length === 0)
|
|
4667
|
+
return false;
|
|
4668
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
3935
4669
|
}
|
|
3936
4670
|
|
|
3937
4671
|
// ../lsp-core/src/lsp/server-resolution.ts
|
|
4672
|
+
function withResolvedCommand(command, binaryPath) {
|
|
4673
|
+
return [binaryPath, ...command.slice(1)];
|
|
4674
|
+
}
|
|
3938
4675
|
function findServerForExtension(ext) {
|
|
3939
4676
|
const servers = getMergedServers();
|
|
3940
|
-
|
|
3941
|
-
|
|
4677
|
+
const workingDirectory = contextCwd();
|
|
4678
|
+
for (const server of servers) {
|
|
4679
|
+
if (!server.extensions.includes(ext))
|
|
4680
|
+
continue;
|
|
4681
|
+
const binaryPath = resolveServerBinary(server.command, workingDirectory);
|
|
4682
|
+
if (binaryPath !== null) {
|
|
3942
4683
|
const resolvedServer = {
|
|
3943
|
-
id:
|
|
3944
|
-
command:
|
|
3945
|
-
extensions:
|
|
3946
|
-
priority:
|
|
4684
|
+
id: server.id,
|
|
4685
|
+
command: withResolvedCommand(server.command, binaryPath),
|
|
4686
|
+
extensions: server.extensions,
|
|
4687
|
+
priority: server.priority
|
|
3947
4688
|
};
|
|
3948
|
-
if (
|
|
4689
|
+
if (server.env !== undefined) {
|
|
3949
4690
|
return {
|
|
3950
4691
|
status: "found",
|
|
3951
4692
|
server: {
|
|
3952
4693
|
...resolvedServer,
|
|
3953
|
-
env:
|
|
3954
|
-
...
|
|
4694
|
+
env: server.env,
|
|
4695
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
3955
4696
|
}
|
|
3956
4697
|
};
|
|
3957
4698
|
}
|
|
@@ -3959,20 +4700,20 @@ function findServerForExtension(ext) {
|
|
|
3959
4700
|
status: "found",
|
|
3960
4701
|
server: {
|
|
3961
4702
|
...resolvedServer,
|
|
3962
|
-
...
|
|
4703
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
3963
4704
|
}
|
|
3964
4705
|
};
|
|
3965
4706
|
}
|
|
3966
4707
|
}
|
|
3967
|
-
for (const
|
|
3968
|
-
if (
|
|
3969
|
-
const installHint = LSP_INSTALL_HINTS[
|
|
4708
|
+
for (const server of servers) {
|
|
4709
|
+
if (server.extensions.includes(ext)) {
|
|
4710
|
+
const installHint = LSP_INSTALL_HINTS[server.id] ?? `Install '${server.command[0]}' and ensure it's in your PATH`;
|
|
3970
4711
|
return {
|
|
3971
4712
|
status: "not_installed",
|
|
3972
4713
|
server: {
|
|
3973
|
-
id:
|
|
3974
|
-
command:
|
|
3975
|
-
extensions:
|
|
4714
|
+
id: server.id,
|
|
4715
|
+
command: server.command,
|
|
4716
|
+
extensions: server.extensions
|
|
3976
4717
|
},
|
|
3977
4718
|
installHint
|
|
3978
4719
|
};
|
|
@@ -3988,20 +4729,21 @@ function findServerForExtension(ext) {
|
|
|
3988
4729
|
function getAllServers() {
|
|
3989
4730
|
const servers = getMergedServers();
|
|
3990
4731
|
const disabled = getDisabledServerIds();
|
|
4732
|
+
const workingDirectory = contextCwd();
|
|
3991
4733
|
const result = [];
|
|
3992
4734
|
const seen = new Set;
|
|
3993
|
-
for (const
|
|
3994
|
-
if (seen.has(
|
|
4735
|
+
for (const server of servers) {
|
|
4736
|
+
if (seen.has(server.id))
|
|
3995
4737
|
continue;
|
|
3996
4738
|
result.push({
|
|
3997
|
-
id:
|
|
3998
|
-
installed: isServerInstalled(
|
|
3999
|
-
extensions:
|
|
4739
|
+
id: server.id,
|
|
4740
|
+
installed: isServerInstalled(server.command, workingDirectory),
|
|
4741
|
+
extensions: server.extensions,
|
|
4000
4742
|
disabled: false,
|
|
4001
|
-
source:
|
|
4002
|
-
priority:
|
|
4743
|
+
source: server.source,
|
|
4744
|
+
priority: server.priority
|
|
4003
4745
|
});
|
|
4004
|
-
seen.add(
|
|
4746
|
+
seen.add(server.id);
|
|
4005
4747
|
}
|
|
4006
4748
|
for (const id of disabled) {
|
|
4007
4749
|
if (seen.has(id))
|
|
@@ -4009,7 +4751,7 @@ function getAllServers() {
|
|
|
4009
4751
|
const builtin = BUILTIN_SERVERS[id];
|
|
4010
4752
|
result.push({
|
|
4011
4753
|
id,
|
|
4012
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
4754
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
4013
4755
|
extensions: builtin?.extensions ?? [],
|
|
4014
4756
|
disabled: true,
|
|
4015
4757
|
source: "disabled",
|
|
@@ -4020,10 +4762,9 @@ function getAllServers() {
|
|
|
4020
4762
|
}
|
|
4021
4763
|
|
|
4022
4764
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
4023
|
-
var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
4024
4765
|
function isDirectoryPath(filePath) {
|
|
4025
4766
|
try {
|
|
4026
|
-
return
|
|
4767
|
+
return statSync4(filePath).isDirectory();
|
|
4027
4768
|
} catch {
|
|
4028
4769
|
return false;
|
|
4029
4770
|
}
|
|
@@ -4033,36 +4774,40 @@ function findWorkspaceRoot(filePath) {
|
|
|
4033
4774
|
const abs = resolveReadablePathInsideContext(filePath);
|
|
4034
4775
|
let dir = abs;
|
|
4035
4776
|
if (!isDirectoryPath(dir)) {
|
|
4036
|
-
dir =
|
|
4777
|
+
dir = dirname11(dir);
|
|
4037
4778
|
}
|
|
4779
|
+
if (!isPathInside(cwd, abs))
|
|
4780
|
+
return findWorkspaceRootOutsideContext(dir);
|
|
4038
4781
|
const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
|
|
4782
|
+
let nearestPackageRoot;
|
|
4039
4783
|
while (isPathInside(cwd, dir)) {
|
|
4040
4784
|
const canonicalDir = existingDirectoryInsideContext(dir, cwd);
|
|
4041
4785
|
if (canonicalDir !== undefined) {
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4786
|
+
if (existsSync11(join5(dir, GIT_WORKSPACE_MARKER))) {
|
|
4787
|
+
return canonicalDir;
|
|
4788
|
+
}
|
|
4789
|
+
if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
|
|
4790
|
+
nearestPackageRoot = canonicalDir;
|
|
4046
4791
|
}
|
|
4047
4792
|
}
|
|
4048
4793
|
if (dir === cwd)
|
|
4049
4794
|
break;
|
|
4050
|
-
dir =
|
|
4795
|
+
dir = dirname11(dir);
|
|
4051
4796
|
}
|
|
4052
|
-
return fallbackRoot;
|
|
4797
|
+
return nearestPackageRoot ?? fallbackRoot;
|
|
4798
|
+
}
|
|
4799
|
+
function hasProjectWorkspaceMarker(directory) {
|
|
4800
|
+
return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync11(join5(directory, marker)));
|
|
4053
4801
|
}
|
|
4054
4802
|
function resolveReadablePathInsideContext(filePath) {
|
|
4055
4803
|
const cwd = contextCwd();
|
|
4056
|
-
const abs =
|
|
4804
|
+
const abs = resolve8(cwd, filePath);
|
|
4057
4805
|
if (isPathInside(cwd, abs))
|
|
4058
4806
|
return abs;
|
|
4059
4807
|
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
4060
4808
|
if (rebased !== undefined)
|
|
4061
4809
|
return rebased;
|
|
4062
|
-
|
|
4063
|
-
if (isPathInside(cwd, canonical))
|
|
4064
|
-
return canonical;
|
|
4065
|
-
throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
|
|
4810
|
+
return canonicalizeExistingOrNearestAncestor(abs);
|
|
4066
4811
|
}
|
|
4067
4812
|
function resolvePathInsideContext(filePath) {
|
|
4068
4813
|
const cwd = contextCwd();
|
|
@@ -4077,12 +4822,12 @@ function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
|
4077
4822
|
let current = path;
|
|
4078
4823
|
const suffix = [];
|
|
4079
4824
|
while (true) {
|
|
4080
|
-
if (
|
|
4081
|
-
const canonical =
|
|
4825
|
+
if (existsSync11(current)) {
|
|
4826
|
+
const canonical = realpathSync5(current);
|
|
4082
4827
|
if (isPathInside(cwd, canonical))
|
|
4083
|
-
return suffix.length === 0 ? canonical :
|
|
4828
|
+
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
4084
4829
|
}
|
|
4085
|
-
const parent =
|
|
4830
|
+
const parent = dirname11(current);
|
|
4086
4831
|
if (parent === current)
|
|
4087
4832
|
return;
|
|
4088
4833
|
suffix.unshift(basename3(current));
|
|
@@ -4090,10 +4835,10 @@ function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
|
4090
4835
|
}
|
|
4091
4836
|
}
|
|
4092
4837
|
function existingDirectoryInsideContext(directory, cwd) {
|
|
4093
|
-
if (!
|
|
4838
|
+
if (!existsSync11(directory))
|
|
4094
4839
|
return;
|
|
4095
|
-
const canonical =
|
|
4096
|
-
if (!
|
|
4840
|
+
const canonical = realpathSync5(directory);
|
|
4841
|
+
if (!statSync4(canonical).isDirectory())
|
|
4097
4842
|
return;
|
|
4098
4843
|
return isPathInside(cwd, canonical) ? canonical : undefined;
|
|
4099
4844
|
}
|
|
@@ -4105,7 +4850,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
|
4105
4850
|
return canonical;
|
|
4106
4851
|
if (current === cwd)
|
|
4107
4852
|
return;
|
|
4108
|
-
current =
|
|
4853
|
+
current = dirname11(current);
|
|
4109
4854
|
}
|
|
4110
4855
|
return;
|
|
4111
4856
|
}
|
|
@@ -4132,33 +4877,46 @@ function formatServerLookupError(result) {
|
|
|
4132
4877
|
].join(`
|
|
4133
4878
|
`);
|
|
4134
4879
|
}
|
|
4880
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4881
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4882
|
+
if (localHint === undefined) {
|
|
4883
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4884
|
+
}
|
|
4885
|
+
return [
|
|
4886
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4887
|
+
` ${localHint}`,
|
|
4888
|
+
"",
|
|
4889
|
+
"Or install it globally:",
|
|
4890
|
+
` ${installHint}`
|
|
4891
|
+
];
|
|
4892
|
+
}
|
|
4135
4893
|
function formatNotInstalled(result) {
|
|
4136
|
-
const { server
|
|
4137
|
-
const extensions =
|
|
4138
|
-
const decision = loadInstallDecision(
|
|
4894
|
+
const { server, installHint } = result;
|
|
4895
|
+
const extensions = server.extensions.join(", ");
|
|
4896
|
+
const decision = loadInstallDecision(server.id)?.decision;
|
|
4139
4897
|
const context = lspRequestContext();
|
|
4140
4898
|
if (decision === "declined") {
|
|
4141
|
-
return `LSP server '${
|
|
4899
|
+
return `LSP server '${server.id}' (${extensions}) is NOT INSTALLED; user previously declined installation — proceed without LSP.`;
|
|
4142
4900
|
}
|
|
4143
4901
|
const header = [
|
|
4144
|
-
`LSP server '${
|
|
4902
|
+
`LSP server '${server.id}' for ${extensions} is NOT INSTALLED.`,
|
|
4145
4903
|
"",
|
|
4146
|
-
`Command not found: ${
|
|
4904
|
+
`Command not found: ${server.command[0]}`,
|
|
4147
4905
|
""
|
|
4148
4906
|
];
|
|
4907
|
+
const installOptions = formatInstallOptions(server.id, installHint);
|
|
4149
4908
|
if (decision === "allowed") {
|
|
4150
4909
|
return [
|
|
4151
4910
|
...header,
|
|
4152
4911
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
4153
|
-
|
|
4912
|
+
...installOptions.slice(1)
|
|
4154
4913
|
].join(`
|
|
4155
4914
|
`);
|
|
4156
4915
|
}
|
|
4157
4916
|
if (!context.capabilities.installDecisionTool) {
|
|
4158
4917
|
return [
|
|
4159
4918
|
...header,
|
|
4160
|
-
|
|
4161
|
-
` ${installHint}`,
|
|
4919
|
+
...installOptions,
|
|
4162
4920
|
"",
|
|
4163
4921
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4164
4922
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -4167,13 +4925,12 @@ function formatNotInstalled(result) {
|
|
|
4167
4925
|
}
|
|
4168
4926
|
return [
|
|
4169
4927
|
...header,
|
|
4170
|
-
|
|
4171
|
-
` ${installHint}`,
|
|
4928
|
+
...installOptions,
|
|
4172
4929
|
"",
|
|
4173
4930
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4174
4931
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
4175
4932
|
"- If the user declines, OR has NOT explicitly asked for LSP installation:",
|
|
4176
|
-
` call lsp_install_decision { server_id: "${
|
|
4933
|
+
` call lsp_install_decision { server_id: "${server.id}", decision: "declined" },`,
|
|
4177
4934
|
` which writes to ${context.installDecisionsPath},`,
|
|
4178
4935
|
" then ignore this message and proceed WITHOUT LSP."
|
|
4179
4936
|
].join(`
|
|
@@ -4197,34 +4954,34 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4197
4954
|
if (result.status !== "found") {
|
|
4198
4955
|
throw new LspServerLookupError(formatServerLookupError(result), result);
|
|
4199
4956
|
}
|
|
4200
|
-
const
|
|
4957
|
+
const server = result.server;
|
|
4201
4958
|
const root = findWorkspaceRoot(absPath);
|
|
4202
4959
|
const manager = options.manager ?? getLspManager();
|
|
4203
4960
|
const acquireAndCall = async (allowRetry) => {
|
|
4204
|
-
const client = await manager.getClient(root,
|
|
4961
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4205
4962
|
try {
|
|
4206
4963
|
return await fn(client, root, absPath);
|
|
4207
4964
|
} catch (err) {
|
|
4208
4965
|
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
4209
|
-
manager.invalidateClient(root,
|
|
4966
|
+
manager.invalidateClient(root, server.id, client);
|
|
4210
4967
|
return acquireAndCall(false);
|
|
4211
4968
|
}
|
|
4212
4969
|
if (err instanceof LspRequestTimeoutError) {
|
|
4213
|
-
if (manager.isServerInitializing(root,
|
|
4970
|
+
if (manager.isServerInitializing(root, server.id)) {
|
|
4214
4971
|
throw new LspServerInitializingError(err);
|
|
4215
4972
|
}
|
|
4216
4973
|
}
|
|
4217
4974
|
throw err;
|
|
4218
4975
|
} finally {
|
|
4219
|
-
manager.releaseClient(root,
|
|
4976
|
+
manager.releaseClient(root, server.id);
|
|
4220
4977
|
}
|
|
4221
4978
|
};
|
|
4222
4979
|
return acquireAndCall(true);
|
|
4223
4980
|
}
|
|
4224
4981
|
|
|
4225
4982
|
// ../lsp-core/src/lsp/directory-diagnostics.ts
|
|
4226
|
-
import { existsSync as
|
|
4227
|
-
import { join as
|
|
4983
|
+
import { existsSync as existsSync12, lstatSync as lstatSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
4984
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
4228
4985
|
|
|
4229
4986
|
// ../lsp-core/src/lsp/formatters.ts
|
|
4230
4987
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -4239,10 +4996,10 @@ function uriToPath(uri) {
|
|
|
4239
4996
|
}
|
|
4240
4997
|
function formatLocation(loc) {
|
|
4241
4998
|
if ("targetUri" in loc) {
|
|
4242
|
-
const
|
|
4243
|
-
const
|
|
4244
|
-
const
|
|
4245
|
-
return `${
|
|
4999
|
+
const uri = uriToPath(loc.targetUri);
|
|
5000
|
+
const line = loc.targetRange.start.line + 1;
|
|
5001
|
+
const char = loc.targetRange.start.character;
|
|
5002
|
+
return `${uri}:${line}:${char}`;
|
|
4246
5003
|
}
|
|
4247
5004
|
const uri = uriToPath(loc.uri);
|
|
4248
5005
|
const line = loc.range.start.line + 1;
|
|
@@ -4354,10 +5111,10 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
4354
5111
|
for (const entry of entries) {
|
|
4355
5112
|
if (files.length >= maxFiles)
|
|
4356
5113
|
return;
|
|
4357
|
-
const fullPath =
|
|
5114
|
+
const fullPath = join6(currentDir, entry);
|
|
4358
5115
|
let stat;
|
|
4359
5116
|
try {
|
|
4360
|
-
stat =
|
|
5117
|
+
stat = lstatSync6(fullPath);
|
|
4361
5118
|
} catch {
|
|
4362
5119
|
continue;
|
|
4363
5120
|
}
|
|
@@ -4379,15 +5136,15 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4379
5136
|
if (!extension.startsWith(".")) {
|
|
4380
5137
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
4381
5138
|
}
|
|
4382
|
-
const absDir =
|
|
4383
|
-
if (!
|
|
5139
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
5140
|
+
if (!existsSync12(absDir)) {
|
|
4384
5141
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
4385
5142
|
}
|
|
4386
5143
|
const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
|
|
4387
5144
|
if (serverResult.status !== "found") {
|
|
4388
5145
|
throw new LspServerLookupError(formatServerLookupError(serverResult));
|
|
4389
5146
|
}
|
|
4390
|
-
const
|
|
5147
|
+
const server = serverResult.server;
|
|
4391
5148
|
const allFiles = (options.listFiles ?? collectFilesWithExtension)(absDir, extension, maxFiles + 1);
|
|
4392
5149
|
const wasCapped = allFiles.length > maxFiles;
|
|
4393
5150
|
const filesToProcess = allFiles.slice(0, maxFiles);
|
|
@@ -4407,7 +5164,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4407
5164
|
const fileErrors = [];
|
|
4408
5165
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4409
5166
|
options.signal?.throwIfAborted();
|
|
4410
|
-
const client = await manager.getClient(root,
|
|
5167
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4411
5168
|
try {
|
|
4412
5169
|
let nextIndex = 0;
|
|
4413
5170
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -4435,7 +5192,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4435
5192
|
});
|
|
4436
5193
|
await Promise.all(workers);
|
|
4437
5194
|
} finally {
|
|
4438
|
-
manager.releaseClient(root,
|
|
5195
|
+
manager.releaseClient(root, server.id);
|
|
4439
5196
|
}
|
|
4440
5197
|
const displayDiagnostics = allDiagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS);
|
|
4441
5198
|
const wasDiagCapped = allDiagnostics.length > DEFAULT_MAX_DIAGNOSTICS;
|
|
@@ -4466,8 +5223,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4466
5223
|
}
|
|
4467
5224
|
|
|
4468
5225
|
// ../lsp-core/src/lsp/infer-extension.ts
|
|
4469
|
-
import { lstatSync as
|
|
4470
|
-
import { join as
|
|
5226
|
+
import { lstatSync as lstatSync7, readdirSync as readdirSync4 } from "node:fs";
|
|
5227
|
+
import { join as join7 } from "node:path";
|
|
4471
5228
|
var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
4472
5229
|
var MAX_SCAN_ENTRIES = 500;
|
|
4473
5230
|
function inferExtensionFromDirectory(directory) {
|
|
@@ -4485,10 +5242,10 @@ function inferExtensionFromDirectory(directory) {
|
|
|
4485
5242
|
for (const entry of entries) {
|
|
4486
5243
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
4487
5244
|
return;
|
|
4488
|
-
const fullPath =
|
|
5245
|
+
const fullPath = join7(dir, entry);
|
|
4489
5246
|
let stat;
|
|
4490
5247
|
try {
|
|
4491
|
-
stat =
|
|
5248
|
+
stat = lstatSync7(fullPath);
|
|
4492
5249
|
} catch {
|
|
4493
5250
|
continue;
|
|
4494
5251
|
}
|
|
@@ -4644,8 +5401,8 @@ function clientOptions(signal) {
|
|
|
4644
5401
|
}
|
|
4645
5402
|
|
|
4646
5403
|
// ../lsp-core/src/tools/result.ts
|
|
4647
|
-
function text(
|
|
4648
|
-
return { content: [{ type: "text", text
|
|
5404
|
+
function text(text, details, isError = false) {
|
|
5405
|
+
return { content: [{ type: "text", text }], details, isError };
|
|
4649
5406
|
}
|
|
4650
5407
|
|
|
4651
5408
|
// ../lsp-core/src/tools/diagnostics.ts
|
|
@@ -4665,7 +5422,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4665
5422
|
const extension = inferExtensionFromDirectory(absPath);
|
|
4666
5423
|
if (!extension) {
|
|
4667
5424
|
const message = `No supported source files found in directory: ${absPath}`;
|
|
4668
|
-
const
|
|
5425
|
+
const details = {
|
|
4669
5426
|
filePath,
|
|
4670
5427
|
severity,
|
|
4671
5428
|
mode: "directory",
|
|
@@ -4675,24 +5432,24 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4675
5432
|
error: message,
|
|
4676
5433
|
errorKind: "no_files"
|
|
4677
5434
|
};
|
|
4678
|
-
return text(message,
|
|
5435
|
+
return text(message, details);
|
|
4679
5436
|
}
|
|
4680
|
-
const
|
|
4681
|
-
const
|
|
5437
|
+
const output = await aggregateDiagnosticsForDirectory(absPath, extension, severity, undefined, signal === undefined ? {} : { signal });
|
|
5438
|
+
const details = {
|
|
4682
5439
|
filePath,
|
|
4683
5440
|
severity,
|
|
4684
5441
|
mode: "directory",
|
|
4685
5442
|
diagnostics: [],
|
|
4686
|
-
totalDiagnostics:
|
|
5443
|
+
totalDiagnostics: output.totalDiagnostics,
|
|
4687
5444
|
truncated: false,
|
|
4688
|
-
fileFailures: [...
|
|
5445
|
+
fileFailures: [...output.fileFailures]
|
|
4689
5446
|
};
|
|
4690
|
-
return text(
|
|
5447
|
+
return text(output.output, details);
|
|
4691
5448
|
}
|
|
4692
5449
|
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
4693
5450
|
if (result.transientError) {
|
|
4694
5451
|
const message = result.transientError.message;
|
|
4695
|
-
const
|
|
5452
|
+
const details = {
|
|
4696
5453
|
filePath,
|
|
4697
5454
|
severity,
|
|
4698
5455
|
mode: "file",
|
|
@@ -4702,7 +5459,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4702
5459
|
error: message,
|
|
4703
5460
|
errorKind: result.transientError.kind
|
|
4704
5461
|
};
|
|
4705
|
-
return text(message,
|
|
5462
|
+
return text(message, details, true);
|
|
4706
5463
|
}
|
|
4707
5464
|
const diagnostics = filterDiagnosticsBySeverity(asDiagnosticArray(result), severity);
|
|
4708
5465
|
const total = diagnostics.length;
|
|
@@ -4736,6 +5493,96 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4736
5493
|
throw error;
|
|
4737
5494
|
}
|
|
4738
5495
|
}
|
|
5496
|
+
// ../lsp-core/src/lsp/format-document.ts
|
|
5497
|
+
import { readFileSync as readFileSync8, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5498
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
5499
|
+
tabSize: 4,
|
|
5500
|
+
insertSpaces: false,
|
|
5501
|
+
trimTrailingWhitespace: true,
|
|
5502
|
+
insertFinalNewline: true,
|
|
5503
|
+
trimFinalNewlines: true
|
|
5504
|
+
};
|
|
5505
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
5506
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
5507
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
5508
|
+
if (edits === null)
|
|
5509
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
5510
|
+
if (edits.length === 0)
|
|
5511
|
+
return UNCHANGED;
|
|
5512
|
+
const before = readFileSync8(filePath, "utf-8");
|
|
5513
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
5514
|
+
if (normalized.text === before)
|
|
5515
|
+
return UNCHANGED;
|
|
5516
|
+
writeAtomically(filePath, normalized.text);
|
|
5517
|
+
await client.openFile(filePath);
|
|
5518
|
+
return {
|
|
5519
|
+
status: "formatted",
|
|
5520
|
+
...lineDelta(normalized.edits)
|
|
5521
|
+
};
|
|
5522
|
+
}
|
|
5523
|
+
function lineDelta(edits) {
|
|
5524
|
+
let linesAdded = 0;
|
|
5525
|
+
let linesRemoved = 0;
|
|
5526
|
+
for (const edit of edits) {
|
|
5527
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
5528
|
+
linesAdded += edit.newText.split(`
|
|
5529
|
+
`).length;
|
|
5530
|
+
}
|
|
5531
|
+
return { linesAdded, linesRemoved };
|
|
5532
|
+
}
|
|
5533
|
+
function writeAtomically(filePath, content) {
|
|
5534
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
5535
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
5536
|
+
try {
|
|
5537
|
+
renameSync3(tempPath, filePath);
|
|
5538
|
+
} catch (error) {
|
|
5539
|
+
try {
|
|
5540
|
+
unlinkSync4(tempPath);
|
|
5541
|
+
} catch {}
|
|
5542
|
+
throw error;
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
|
|
5546
|
+
// ../lsp-core/src/tools/format.ts
|
|
5547
|
+
async function executeLspFormat(params, signal) {
|
|
5548
|
+
const filePath = requireString(params, "filePath");
|
|
5549
|
+
try {
|
|
5550
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
5551
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
5552
|
+
} catch (error) {
|
|
5553
|
+
const missingDependency = missingDependencyResult(error, {
|
|
5554
|
+
filePath,
|
|
5555
|
+
status: "unavailable",
|
|
5556
|
+
reason: "server_unavailable",
|
|
5557
|
+
linesAdded: 0,
|
|
5558
|
+
linesRemoved: 0
|
|
5559
|
+
});
|
|
5560
|
+
if (missingDependency)
|
|
5561
|
+
return missingDependency;
|
|
5562
|
+
throw error;
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
function formatDetails(filePath, result) {
|
|
5566
|
+
if (result.status === "unavailable") {
|
|
5567
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
5568
|
+
}
|
|
5569
|
+
return {
|
|
5570
|
+
filePath,
|
|
5571
|
+
status: result.status,
|
|
5572
|
+
linesAdded: result.linesAdded,
|
|
5573
|
+
linesRemoved: result.linesRemoved
|
|
5574
|
+
};
|
|
5575
|
+
}
|
|
5576
|
+
function describeResult(filePath, result) {
|
|
5577
|
+
if (result.status === "unavailable") {
|
|
5578
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
5579
|
+
}
|
|
5580
|
+
if (result.status === "unchanged") {
|
|
5581
|
+
return `Already formatted: ${filePath}`;
|
|
5582
|
+
}
|
|
5583
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
5584
|
+
}
|
|
5585
|
+
|
|
4739
5586
|
// ../lsp-core/src/tools/install-decision.ts
|
|
4740
5587
|
async function executeLspInstallDecision(params) {
|
|
4741
5588
|
const serverId = requireString(params, "server_id");
|
|
@@ -4743,7 +5590,7 @@ async function executeLspInstallDecision(params) {
|
|
|
4743
5590
|
if (!isInstallDecision(decision)) {
|
|
4744
5591
|
return text(`Invalid decision '${String(decision)}'. Expected "declined" or "allowed".`, { serverId, errorKind: "invalid_decision" }, true);
|
|
4745
5592
|
}
|
|
4746
|
-
const serverIds = [...new Set(getMergedServers().map((
|
|
5593
|
+
const serverIds = [...new Set(getMergedServers().map((server) => server.id))];
|
|
4747
5594
|
if (!serverIds.includes(serverId)) {
|
|
4748
5595
|
const preview = serverIds.slice(0, 20).join(", ");
|
|
4749
5596
|
return text(`Unknown LSP server '${serverId}'. Known servers: ${preview}${serverIds.length > 20 ? "..." : ""}`, { serverId, errorKind: "unknown_server" }, true);
|
|
@@ -4883,10 +5730,10 @@ function objectSchema(properties, required = []) {
|
|
|
4883
5730
|
async function executeLspStatus() {
|
|
4884
5731
|
const servers = getAllServers();
|
|
4885
5732
|
const snapshots = getLspManager().getSnapshot();
|
|
4886
|
-
const installed = servers.filter((
|
|
4887
|
-
const configuredLines = servers.map((
|
|
4888
|
-
const state =
|
|
4889
|
-
return `- ${
|
|
5733
|
+
const installed = servers.filter((server) => server.installed && !server.disabled);
|
|
5734
|
+
const configuredLines = servers.map((server) => {
|
|
5735
|
+
const state = server.disabled ? "disabled" : server.installed ? "installed" : "missing";
|
|
5736
|
+
return `- ${server.id}: ${state}; source=${server.source}; extensions=${server.extensions.join(", ")}`;
|
|
4890
5737
|
});
|
|
4891
5738
|
const activeLines = snapshots.map((snapshot) => {
|
|
4892
5739
|
const state = snapshot.alive ? snapshot.isInitializing ? "initializing" : "alive" : "dead";
|
|
@@ -4929,8 +5776,8 @@ async function executeLspSymbols(params, signal) {
|
|
|
4929
5776
|
errorKind: "missing_query"
|
|
4930
5777
|
});
|
|
4931
5778
|
}
|
|
4932
|
-
const
|
|
4933
|
-
return formatSymbolsResult(filePath, scope,
|
|
5779
|
+
const symbols = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
5780
|
+
return formatSymbolsResult(filePath, scope, symbols, limit, query);
|
|
4934
5781
|
}
|
|
4935
5782
|
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
4936
5783
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
@@ -5068,6 +5915,16 @@ var LSP_MCP_TOOLS = [
|
|
|
5068
5915
|
}, ["filePath", "line", "character", "newName"]),
|
|
5069
5916
|
execute: executeLspRename
|
|
5070
5917
|
},
|
|
5918
|
+
{
|
|
5919
|
+
name: "format",
|
|
5920
|
+
aliases: ["lsp_format"],
|
|
5921
|
+
title: "LSP Format",
|
|
5922
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
5923
|
+
inputSchema: objectSchema({
|
|
5924
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
5925
|
+
}, ["filePath"]),
|
|
5926
|
+
execute: executeLspFormat
|
|
5927
|
+
},
|
|
5071
5928
|
{
|
|
5072
5929
|
name: "install_decision",
|
|
5073
5930
|
aliases: ["lsp_install_decision"],
|
|
@@ -5107,7 +5964,7 @@ async function handleLspMcpRequest(input, options = {}) {
|
|
|
5107
5964
|
if (!isPlainRecord(input)) {
|
|
5108
5965
|
return errorResponse(null, -32600, "Invalid Request");
|
|
5109
5966
|
}
|
|
5110
|
-
const id =
|
|
5967
|
+
const id = jsonRpcId2(input["id"]);
|
|
5111
5968
|
const method = input["method"];
|
|
5112
5969
|
if (method === "notifications/initialized")
|
|
5113
5970
|
return;
|
|
@@ -5167,11 +6024,11 @@ function requestedProtocolVersion(params) {
|
|
|
5167
6024
|
// src/daemon-client.ts
|
|
5168
6025
|
import { connect } from "node:net";
|
|
5169
6026
|
import { homedir as homedir3 } from "node:os";
|
|
5170
|
-
import { join as
|
|
6027
|
+
import { join as join8 } from "node:path";
|
|
6028
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
5171
6029
|
|
|
5172
6030
|
// src/daemon-request-error.ts
|
|
5173
6031
|
class DaemonRequestError extends Error {
|
|
5174
|
-
requestWritten;
|
|
5175
6032
|
constructor(message, requestWritten) {
|
|
5176
6033
|
super(message);
|
|
5177
6034
|
this.name = "DaemonRequestError";
|
|
@@ -5194,7 +6051,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
|
|
|
5194
6051
|
}
|
|
5195
6052
|
|
|
5196
6053
|
class DaemonRequestTimedOutError extends DaemonRequestError {
|
|
5197
|
-
timeoutMs;
|
|
5198
6054
|
constructor(requestWritten, timeoutMs) {
|
|
5199
6055
|
super("daemon request timed out", requestWritten);
|
|
5200
6056
|
this.name = "DaemonRequestTimedOutError";
|
|
@@ -5211,243 +6067,46 @@ function daemonFailureResult(paths, error) {
|
|
|
5211
6067
|
return daemonUnreachableResult(paths, error);
|
|
5212
6068
|
}
|
|
5213
6069
|
function daemonCancelledResult(paths) {
|
|
5214
|
-
const
|
|
6070
|
+
const text = [
|
|
5215
6071
|
"LSP daemon request cancelled: the caller aborted this request (for example, the turn was interrupted).",
|
|
5216
6072
|
"The daemon stays available; no LSP work was applied. Retry when you are ready.",
|
|
5217
6073
|
`Socket: ${paths.socket}`
|
|
5218
6074
|
].join(`
|
|
5219
6075
|
`);
|
|
5220
|
-
return { content: [{ type: "text", text
|
|
6076
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
5221
6077
|
}
|
|
5222
6078
|
function daemonTimedOutResult(paths, timeoutMs) {
|
|
5223
|
-
const
|
|
6079
|
+
const text = [
|
|
5224
6080
|
`LSP daemon request timed out after ${timeoutMs}ms: the daemon did not respond in time.`,
|
|
5225
|
-
"The daemon stays available but may be busy. Retry when you are ready.",
|
|
5226
|
-
`Socket: ${paths.socket}`,
|
|
5227
|
-
`Logs: ${paths.log}`
|
|
5228
|
-
].join(`
|
|
5229
|
-
`);
|
|
5230
|
-
return { content: [{ type: "text", text
|
|
5231
|
-
}
|
|
5232
|
-
function daemonUnreachableResult(paths, error) {
|
|
5233
|
-
const text2 = [
|
|
5234
|
-
`LSP daemon unreachable: ${errorText(error)}.`,
|
|
5235
|
-
"The MCP server is a thin proxy and never runs language servers in-process.",
|
|
5236
|
-
`Socket: ${paths.socket}`,
|
|
5237
|
-
`Logs: ${paths.log}`,
|
|
5238
|
-
"The daemon is auto-started on demand and will be retried on the next request."
|
|
5239
|
-
].join(`
|
|
5240
|
-
`);
|
|
5241
|
-
return { content: [{ type: "text", text: text2 }], isError: true };
|
|
5242
|
-
}
|
|
5243
|
-
function errorText(error) {
|
|
5244
|
-
return error instanceof Error ? error.message : String(error);
|
|
5245
|
-
}
|
|
5246
|
-
|
|
5247
|
-
// src/ensure-daemon.ts
|
|
5248
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
5249
|
-
import { closeSync as closeSync2, existsSync as existsSync11, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
|
|
5250
|
-
import { Socket } from "node:net";
|
|
5251
|
-
import { dirname as dirname8, isAbsolute as isAbsolute4 } from "node:path";
|
|
5252
|
-
import { argv0, execPath } from "node:process";
|
|
5253
|
-
|
|
5254
|
-
// src/ipc-protocol.ts
|
|
5255
|
-
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
5256
|
-
import {
|
|
5257
|
-
chmodSync,
|
|
5258
|
-
closeSync,
|
|
5259
|
-
constants,
|
|
5260
|
-
fchmodSync,
|
|
5261
|
-
fstatSync,
|
|
5262
|
-
lstatSync as lstatSync6,
|
|
5263
|
-
mkdirSync as mkdirSync2,
|
|
5264
|
-
openSync,
|
|
5265
|
-
readFileSync as readFileSync5,
|
|
5266
|
-
unlinkSync,
|
|
5267
|
-
writeSync
|
|
5268
|
-
} from "node:fs";
|
|
5269
|
-
import { dirname as dirname7 } from "node:path";
|
|
5270
|
-
var OMO_DAEMON_PROTOCOL_VERSION = 1;
|
|
5271
|
-
var AUTH_ERROR_CODE = -32001;
|
|
5272
|
-
var PROTOCOL_ERROR_CODE = -32002;
|
|
5273
|
-
var AUTH_TOKEN_BYTES = 32;
|
|
5274
|
-
|
|
5275
|
-
class UnsafePrivateDirectoryError extends Error {
|
|
5276
|
-
path;
|
|
5277
|
-
reason;
|
|
5278
|
-
name = "UnsafePrivateDirectoryError";
|
|
5279
|
-
code = "unsafe_private_directory";
|
|
5280
|
-
constructor(path, reason) {
|
|
5281
|
-
super(`unsafe private directory ${path}: ${reason}`);
|
|
5282
|
-
this.path = path;
|
|
5283
|
-
this.reason = reason;
|
|
5284
|
-
}
|
|
5285
|
-
}
|
|
5286
|
-
function authEnvelope(token) {
|
|
5287
|
-
return { protocolVersion: OMO_DAEMON_PROTOCOL_VERSION, token };
|
|
5288
|
-
}
|
|
5289
|
-
function readAuthToken(paths) {
|
|
5290
|
-
try {
|
|
5291
|
-
const token = readFileSync5(paths.auth, "utf8").trim();
|
|
5292
|
-
return token.length > 0 ? token : null;
|
|
5293
|
-
} catch (error) {
|
|
5294
|
-
if (error instanceof Error)
|
|
5295
|
-
return null;
|
|
5296
|
-
throw error;
|
|
5297
|
-
}
|
|
5298
|
-
}
|
|
5299
|
-
function readOrCreateAuthToken(paths) {
|
|
5300
|
-
const existing = readAuthToken(paths);
|
|
5301
|
-
if (existing)
|
|
5302
|
-
return existing;
|
|
5303
|
-
return createAuthToken(paths);
|
|
5304
|
-
}
|
|
5305
|
-
function rotateAuthToken(paths) {
|
|
5306
|
-
try {
|
|
5307
|
-
unlinkSync(paths.auth);
|
|
5308
|
-
} catch (error) {
|
|
5309
|
-
if (!(error instanceof Error))
|
|
5310
|
-
throw error;
|
|
5311
|
-
}
|
|
5312
|
-
return createAuthToken(paths);
|
|
5313
|
-
}
|
|
5314
|
-
function authenticateMessage(raw, expectedToken) {
|
|
5315
|
-
const id = jsonRpcId2(raw);
|
|
5316
|
-
if (!isPlainRecord(raw))
|
|
5317
|
-
return authError(id);
|
|
5318
|
-
const params = raw["params"];
|
|
5319
|
-
if (!isPlainRecord(params))
|
|
5320
|
-
return authError(id);
|
|
5321
|
-
const envelope = params["_omo"];
|
|
5322
|
-
if (!isPlainRecord(envelope))
|
|
5323
|
-
return authError(id);
|
|
5324
|
-
const protocolVersion = envelope["protocolVersion"];
|
|
5325
|
-
if (protocolVersion !== OMO_DAEMON_PROTOCOL_VERSION)
|
|
5326
|
-
return protocolError(id);
|
|
5327
|
-
const token = envelope["token"];
|
|
5328
|
-
if (typeof token !== "string" || !tokenMatches(token, expectedToken))
|
|
5329
|
-
return authError(id);
|
|
5330
|
-
const cleanParams = { ...params };
|
|
5331
|
-
delete cleanParams["_omo"];
|
|
5332
|
-
return { input: { ...raw, params: cleanParams }, id, method: typeof raw["method"] === "string" ? raw["method"] : undefined };
|
|
5333
|
-
}
|
|
5334
|
-
function isAuthErrorResponse(message) {
|
|
5335
|
-
if (!isPlainRecord(message))
|
|
5336
|
-
return false;
|
|
5337
|
-
const error = message["error"];
|
|
5338
|
-
if (!isPlainRecord(error))
|
|
5339
|
-
return false;
|
|
5340
|
-
const data = error["data"];
|
|
5341
|
-
return error["code"] === AUTH_ERROR_CODE && isPlainRecord(data) && data["code"] === "daemon_authentication_failed";
|
|
5342
|
-
}
|
|
5343
|
-
function writePrivateFile(path, data) {
|
|
5344
|
-
const fd = openSync(path, "w", 384);
|
|
5345
|
-
try {
|
|
5346
|
-
writeSync(fd, data);
|
|
5347
|
-
} finally {
|
|
5348
|
-
closeSync(fd);
|
|
5349
|
-
}
|
|
5350
|
-
setPrivateFileMode(path);
|
|
5351
|
-
}
|
|
5352
|
-
function ensurePrivateDirectory(path, options = {}) {
|
|
5353
|
-
try {
|
|
5354
|
-
mkdirSync2(path, { recursive: true, mode: 448 });
|
|
5355
|
-
} catch (error) {
|
|
5356
|
-
if (errorCode2(error) !== "EEXIST")
|
|
5357
|
-
throw error;
|
|
5358
|
-
}
|
|
5359
|
-
if (process.platform === "win32")
|
|
5360
|
-
return;
|
|
5361
|
-
const before = validatePrivateDirectory(path, options);
|
|
5362
|
-
const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
5363
|
-
try {
|
|
5364
|
-
fchmodSync(fd, 448);
|
|
5365
|
-
const after = validatePrivateDirectory(path, options);
|
|
5366
|
-
const openStats = fstatSync(fd);
|
|
5367
|
-
if (!sameDirectory(before, after) || !sameDirectory(before, openStats)) {
|
|
5368
|
-
throw new UnsafePrivateDirectoryError(path, "changed_during_chmod");
|
|
5369
|
-
}
|
|
5370
|
-
} finally {
|
|
5371
|
-
closeSync(fd);
|
|
5372
|
-
}
|
|
5373
|
-
}
|
|
5374
|
-
function setPrivateFileMode(path) {
|
|
5375
|
-
if (process.platform !== "win32")
|
|
5376
|
-
chmodSync(path, 384);
|
|
5377
|
-
}
|
|
5378
|
-
function createAuthToken(paths) {
|
|
5379
|
-
ensurePrivateDirectory(dirname7(paths.auth));
|
|
5380
|
-
const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
|
|
5381
|
-
let fd;
|
|
5382
|
-
try {
|
|
5383
|
-
fd = openSync(paths.auth, "wx", 384);
|
|
5384
|
-
} catch (error) {
|
|
5385
|
-
if (errorCode2(error) === "EEXIST") {
|
|
5386
|
-
const existing = readAuthToken(paths);
|
|
5387
|
-
if (existing)
|
|
5388
|
-
return existing;
|
|
5389
|
-
}
|
|
5390
|
-
throw error;
|
|
5391
|
-
}
|
|
5392
|
-
try {
|
|
5393
|
-
writeSync(fd, `${token}
|
|
5394
|
-
`);
|
|
5395
|
-
} finally {
|
|
5396
|
-
closeSync(fd);
|
|
5397
|
-
}
|
|
5398
|
-
setPrivateFileMode(paths.auth);
|
|
5399
|
-
return token;
|
|
5400
|
-
}
|
|
5401
|
-
function errorCode2(error) {
|
|
5402
|
-
if (!error || typeof error !== "object" || !("code" in error))
|
|
5403
|
-
return;
|
|
5404
|
-
const code = Reflect.get(error, "code");
|
|
5405
|
-
return typeof code === "string" ? code : undefined;
|
|
5406
|
-
}
|
|
5407
|
-
function validatePrivateDirectory(path, options) {
|
|
5408
|
-
const stats = options.lstat ? options.lstat(path) : lstatPrivateDirectory(path);
|
|
5409
|
-
if (stats.isSymbolicLink())
|
|
5410
|
-
throw new UnsafePrivateDirectoryError(path, "symlink");
|
|
5411
|
-
if (!stats.isDirectory())
|
|
5412
|
-
throw new UnsafePrivateDirectoryError(path, "not_directory");
|
|
5413
|
-
const currentUid = options.currentUid ? options.currentUid() : process.getuid?.();
|
|
5414
|
-
if (currentUid !== undefined && stats.uid !== currentUid) {
|
|
5415
|
-
throw new UnsafePrivateDirectoryError(path, "wrong_owner");
|
|
5416
|
-
}
|
|
5417
|
-
return stats;
|
|
5418
|
-
}
|
|
5419
|
-
function lstatPrivateDirectory(path) {
|
|
5420
|
-
return lstatSync6(path);
|
|
5421
|
-
}
|
|
5422
|
-
function sameDirectory(a, b) {
|
|
5423
|
-
return a.dev === b.dev && a.ino === b.ino;
|
|
5424
|
-
}
|
|
5425
|
-
function tokenMatches(candidate, expected) {
|
|
5426
|
-
const candidateBytes = Buffer.from(candidate);
|
|
5427
|
-
const expectedBytes = Buffer.from(expected);
|
|
5428
|
-
return candidateBytes.length === expectedBytes.length && timingSafeEqual(candidateBytes, expectedBytes);
|
|
5429
|
-
}
|
|
5430
|
-
function jsonRpcId2(raw) {
|
|
5431
|
-
if (!isPlainRecord(raw))
|
|
5432
|
-
return null;
|
|
5433
|
-
const id = raw["id"];
|
|
5434
|
-
return typeof id === "string" || typeof id === "number" || id === null ? id : null;
|
|
6081
|
+
"The daemon stays available but may be busy. Retry when you are ready.",
|
|
6082
|
+
`Socket: ${paths.socket}`,
|
|
6083
|
+
`Logs: ${paths.log}`
|
|
6084
|
+
].join(`
|
|
6085
|
+
`);
|
|
6086
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
5435
6087
|
}
|
|
5436
|
-
function
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
6088
|
+
function daemonUnreachableResult(paths, error) {
|
|
6089
|
+
const text = [
|
|
6090
|
+
`LSP daemon unreachable: ${errorText(error)}.`,
|
|
6091
|
+
"The MCP server is a thin proxy and never runs language servers in-process.",
|
|
6092
|
+
`Socket: ${paths.socket}`,
|
|
6093
|
+
`Logs: ${paths.log}`,
|
|
6094
|
+
"The daemon is auto-started on demand and will be retried on the next request."
|
|
6095
|
+
].join(`
|
|
6096
|
+
`);
|
|
6097
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
5442
6098
|
}
|
|
5443
|
-
function
|
|
5444
|
-
return
|
|
5445
|
-
jsonrpc: "2.0",
|
|
5446
|
-
id,
|
|
5447
|
-
error: { code: PROTOCOL_ERROR_CODE, message: "daemon protocol mismatch", data: { code: "daemon_protocol_mismatch" } }
|
|
5448
|
-
};
|
|
6099
|
+
function errorText(error) {
|
|
6100
|
+
return error instanceof Error ? error.message : String(error);
|
|
5449
6101
|
}
|
|
5450
6102
|
|
|
6103
|
+
// src/ensure-daemon.ts
|
|
6104
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
6105
|
+
import { closeSync as closeSync3, existsSync as existsSync13, mkdirSync as mkdirSync4, openSync as openSync3, writeSync as writeSync3 } from "node:fs";
|
|
6106
|
+
import { Socket } from "node:net";
|
|
6107
|
+
import { dirname as dirname12, isAbsolute as isAbsolute5 } from "node:path";
|
|
6108
|
+
import { argv0, execPath } from "node:process";
|
|
6109
|
+
|
|
5451
6110
|
// src/paths.ts
|
|
5452
6111
|
import { createHash as createHash2 } from "node:crypto";
|
|
5453
6112
|
import { createRequire } from "node:module";
|
|
@@ -5456,28 +6115,26 @@ import * as path from "node:path";
|
|
|
5456
6115
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
5457
6116
|
|
|
5458
6117
|
// src/runtime-contract.ts
|
|
5459
|
-
import { statSync as
|
|
5460
|
-
import { isAbsolute as
|
|
6118
|
+
import { statSync as statSync5 } from "node:fs";
|
|
6119
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
5461
6120
|
var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
|
|
5462
6121
|
var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
|
|
5463
6122
|
var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
5464
6123
|
var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
5465
6124
|
|
|
5466
6125
|
class InvalidRuntimeOverrideError extends Error {
|
|
5467
|
-
code = "invalid_runtime_override";
|
|
5468
|
-
reason;
|
|
5469
6126
|
constructor(reason, message) {
|
|
5470
6127
|
super(message);
|
|
6128
|
+
this.code = "invalid_runtime_override";
|
|
5471
6129
|
this.name = "InvalidRuntimeOverrideError";
|
|
5472
6130
|
this.reason = reason;
|
|
5473
6131
|
}
|
|
5474
6132
|
}
|
|
5475
6133
|
|
|
5476
6134
|
class InvalidDaemonVersionError extends Error {
|
|
5477
|
-
code = "invalid_daemon_version";
|
|
5478
|
-
version;
|
|
5479
6135
|
constructor(version) {
|
|
5480
6136
|
super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
|
|
6137
|
+
this.code = "invalid_daemon_version";
|
|
5481
6138
|
this.name = "InvalidDaemonVersionError";
|
|
5482
6139
|
this.version = version;
|
|
5483
6140
|
}
|
|
@@ -5496,17 +6153,17 @@ function resolveDaemonRuntime(env, defaults) {
|
|
|
5496
6153
|
throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
|
|
5497
6154
|
}
|
|
5498
6155
|
if (!hasCliOverride || !hasVersionOverride) {
|
|
5499
|
-
if (!
|
|
6156
|
+
if (!isAbsolute4(defaults.cliPath)) {
|
|
5500
6157
|
throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
|
|
5501
6158
|
}
|
|
5502
6159
|
return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
|
|
5503
6160
|
}
|
|
5504
|
-
if (!
|
|
6161
|
+
if (!isAbsolute4(cliOverride)) {
|
|
5505
6162
|
throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
|
|
5506
6163
|
}
|
|
5507
6164
|
let cliStats;
|
|
5508
6165
|
try {
|
|
5509
|
-
cliStats =
|
|
6166
|
+
cliStats = statSync5(cliOverride);
|
|
5510
6167
|
} catch (error) {
|
|
5511
6168
|
if (!(error instanceof Error))
|
|
5512
6169
|
throw error;
|
|
@@ -5523,10 +6180,9 @@ var requireFromHere = createRequire(import.meta.url);
|
|
|
5523
6180
|
var MAX_SOCKET_PATH_LENGTH = 100;
|
|
5524
6181
|
|
|
5525
6182
|
class InvalidDaemonDirectoryError extends Error {
|
|
5526
|
-
code = "invalid_daemon_directory";
|
|
5527
|
-
directory;
|
|
5528
6183
|
constructor(directory) {
|
|
5529
6184
|
super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
|
|
6185
|
+
this.code = "invalid_daemon_directory";
|
|
5530
6186
|
this.name = "InvalidDaemonDirectoryError";
|
|
5531
6187
|
this.directory = directory;
|
|
5532
6188
|
}
|
|
@@ -5641,9 +6297,11 @@ function createLineDecoder(onMessage, onParseError) {
|
|
|
5641
6297
|
}
|
|
5642
6298
|
|
|
5643
6299
|
// src/ensure-daemon.ts
|
|
5644
|
-
var PROBE_TIMEOUT_MS =
|
|
6300
|
+
var PROBE_TIMEOUT_MS = 2000;
|
|
5645
6301
|
var DEFAULT_READY_TIMEOUT_MS = 5000;
|
|
5646
6302
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
6303
|
+
var FAILED_SPAWN_COOLDOWN_MS = 5000;
|
|
6304
|
+
var failedSpawnUntil = new Map;
|
|
5647
6305
|
|
|
5648
6306
|
class DaemonUnreachableError extends Error {
|
|
5649
6307
|
constructor(socketPath) {
|
|
@@ -5656,11 +6314,22 @@ async function ensureDaemonRunning(paths, deps = defaultEnsureDaemonDeps(), opti
|
|
|
5656
6314
|
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
5657
6315
|
const signal = options.signal;
|
|
5658
6316
|
throwIfAborted(signal);
|
|
5659
|
-
if (await awaitWithSignal2(deps.probe(paths, signal), signal))
|
|
6317
|
+
if (await awaitWithSignal2(deps.probe(paths, signal), signal)) {
|
|
6318
|
+
failedSpawnUntil.delete(paths.socket);
|
|
5660
6319
|
return;
|
|
6320
|
+
}
|
|
5661
6321
|
throwIfAborted(signal);
|
|
6322
|
+
const retryAt = failedSpawnUntil.get(paths.socket);
|
|
6323
|
+
if (retryAt !== undefined && deps.now() < retryAt)
|
|
6324
|
+
throw new DaemonUnreachableError(paths.socket);
|
|
6325
|
+
failedSpawnUntil.delete(paths.socket);
|
|
5662
6326
|
deps.spawnDaemon(paths);
|
|
5663
|
-
|
|
6327
|
+
try {
|
|
6328
|
+
await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal);
|
|
6329
|
+
} catch (error) {
|
|
6330
|
+
failedSpawnUntil.set(paths.socket, deps.now() + FAILED_SPAWN_COOLDOWN_MS);
|
|
6331
|
+
throw error;
|
|
6332
|
+
}
|
|
5664
6333
|
}
|
|
5665
6334
|
async function waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal) {
|
|
5666
6335
|
const deadline = deps.now() + readyTimeoutMs;
|
|
@@ -5680,7 +6349,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5680
6349
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
5681
6350
|
}
|
|
5682
6351
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
5683
|
-
return new Promise((
|
|
6352
|
+
return new Promise((resolve) => {
|
|
5684
6353
|
const socket = new Socket;
|
|
5685
6354
|
let settled = false;
|
|
5686
6355
|
let timer;
|
|
@@ -5692,7 +6361,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5692
6361
|
clearTimeout(timer);
|
|
5693
6362
|
signal?.removeEventListener("abort", onAbort);
|
|
5694
6363
|
socket.destroy();
|
|
5695
|
-
|
|
6364
|
+
resolve(value);
|
|
5696
6365
|
};
|
|
5697
6366
|
const onAbort = () => finish(null);
|
|
5698
6367
|
const decoder = createLineDecoder((message) => {
|
|
@@ -5715,30 +6384,34 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5715
6384
|
socket.connect(paths.socket);
|
|
5716
6385
|
});
|
|
5717
6386
|
}
|
|
5718
|
-
function spawnDaemonProcess(paths) {
|
|
5719
|
-
|
|
5720
|
-
const logFd =
|
|
6387
|
+
function spawnDaemonProcess(paths, deps = {}) {
|
|
6388
|
+
mkdirSync4(dirname12(paths.log), { recursive: true });
|
|
6389
|
+
const logFd = openSync3(paths.log, "a");
|
|
5721
6390
|
try {
|
|
5722
|
-
const
|
|
6391
|
+
const spawnDaemonChild = deps.spawn ?? spawn2;
|
|
6392
|
+
const executable = deps.resolveExecutable?.() ?? resolveDaemonNodeExecutable();
|
|
6393
|
+
const child = spawnDaemonChild(executable, [paths.cliPath, "daemon"], {
|
|
5723
6394
|
detached: true,
|
|
5724
|
-
stdio: ["ignore", logFd, logFd]
|
|
6395
|
+
stdio: ["ignore", logFd, logFd],
|
|
6396
|
+
windowsHide: true,
|
|
6397
|
+
env: { ...process.env, BUN_BE_BUN: "1" }
|
|
5725
6398
|
});
|
|
5726
|
-
child.once("spawn", () =>
|
|
6399
|
+
child.once("spawn", () => closeSync3(logFd));
|
|
5727
6400
|
child.once("error", (error) => {
|
|
5728
|
-
|
|
6401
|
+
writeSync3(logFd, `[lsp-daemon] failed to spawn daemon: ${error.message}
|
|
5729
6402
|
`);
|
|
5730
|
-
|
|
6403
|
+
closeSync3(logFd);
|
|
5731
6404
|
});
|
|
5732
6405
|
child.unref();
|
|
5733
6406
|
} catch (error) {
|
|
5734
|
-
|
|
6407
|
+
closeSync3(logFd);
|
|
5735
6408
|
throw error;
|
|
5736
6409
|
}
|
|
5737
6410
|
}
|
|
5738
|
-
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists =
|
|
6411
|
+
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync13) {
|
|
5739
6412
|
if (pathExists(cachedExecPath))
|
|
5740
6413
|
return cachedExecPath;
|
|
5741
|
-
if (
|
|
6414
|
+
if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
|
|
5742
6415
|
return originalArgv0;
|
|
5743
6416
|
return "node";
|
|
5744
6417
|
}
|
|
@@ -5751,7 +6424,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
5751
6424
|
};
|
|
5752
6425
|
}
|
|
5753
6426
|
function sleepWithSignal(ms, signal) {
|
|
5754
|
-
return new Promise((
|
|
6427
|
+
return new Promise((resolve) => {
|
|
5755
6428
|
let settled = false;
|
|
5756
6429
|
const finish = () => {
|
|
5757
6430
|
if (settled)
|
|
@@ -5759,7 +6432,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
5759
6432
|
settled = true;
|
|
5760
6433
|
clearTimeout(timer);
|
|
5761
6434
|
signal?.removeEventListener("abort", finish);
|
|
5762
|
-
|
|
6435
|
+
resolve();
|
|
5763
6436
|
};
|
|
5764
6437
|
const timer = setTimeout(finish, ms);
|
|
5765
6438
|
if (signal?.aborted) {
|
|
@@ -5774,7 +6447,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5774
6447
|
return promise;
|
|
5775
6448
|
if (signal.aborted)
|
|
5776
6449
|
return Promise.reject(abortError3(signal));
|
|
5777
|
-
return new Promise((
|
|
6450
|
+
return new Promise((resolve, reject) => {
|
|
5778
6451
|
let settled = false;
|
|
5779
6452
|
const finish = (run) => {
|
|
5780
6453
|
if (settled)
|
|
@@ -5785,7 +6458,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5785
6458
|
};
|
|
5786
6459
|
const onAbort = () => finish(() => reject(abortError3(signal)));
|
|
5787
6460
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5788
|
-
promise.then((value) => finish(() =>
|
|
6461
|
+
promise.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
5789
6462
|
});
|
|
5790
6463
|
}
|
|
5791
6464
|
function throwIfAborted(signal) {
|
|
@@ -5814,18 +6487,18 @@ function parsePingResponse(message) {
|
|
|
5814
6487
|
return null;
|
|
5815
6488
|
if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint))
|
|
5816
6489
|
return null;
|
|
5817
|
-
const
|
|
6490
|
+
const path = Reflect.get(endpoint, "path");
|
|
5818
6491
|
const kind = Reflect.get(endpoint, "kind");
|
|
5819
|
-
if (typeof
|
|
6492
|
+
if (typeof path !== "string")
|
|
5820
6493
|
return null;
|
|
5821
6494
|
if (kind === "windows")
|
|
5822
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
6495
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
5823
6496
|
if (kind === "missing")
|
|
5824
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
6497
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
5825
6498
|
const dev = Reflect.get(endpoint, "dev");
|
|
5826
6499
|
const ino = Reflect.get(endpoint, "ino");
|
|
5827
6500
|
if (kind === "unix" && typeof dev === "number" && typeof ino === "number") {
|
|
5828
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
6501
|
+
return { pid, nonce, startedAt, endpoint: { kind, path, dev, ino } };
|
|
5829
6502
|
}
|
|
5830
6503
|
return null;
|
|
5831
6504
|
}
|
|
@@ -5834,7 +6507,10 @@ function parsePingResponse(message) {
|
|
|
5834
6507
|
var CONTEXT_KEY = "_context";
|
|
5835
6508
|
|
|
5836
6509
|
class InvalidDaemonRequestError extends Error {
|
|
5837
|
-
|
|
6510
|
+
constructor() {
|
|
6511
|
+
super(...arguments);
|
|
6512
|
+
this.name = "InvalidDaemonRequestError";
|
|
6513
|
+
}
|
|
5838
6514
|
}
|
|
5839
6515
|
function extractRequestContext(raw) {
|
|
5840
6516
|
if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
|
|
@@ -5916,6 +6592,7 @@ function parseContext(value) {
|
|
|
5916
6592
|
|
|
5917
6593
|
// src/daemon-client.ts
|
|
5918
6594
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
6595
|
+
var STARTUP_BACKOFF_MS = [0, 100, 300];
|
|
5919
6596
|
var nextProxyRequestId = 1;
|
|
5920
6597
|
async function callToolViaDaemon(name, args, options) {
|
|
5921
6598
|
const context = requireContext(options.context);
|
|
@@ -5923,17 +6600,31 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5923
6600
|
const ensure = options.ensure ?? ((ensurePaths, signal) => ensureDaemonRunning(ensurePaths, undefined, signal === undefined ? {} : { signal }));
|
|
5924
6601
|
const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
5925
6602
|
const requestArgs = withContext(args, context);
|
|
6603
|
+
const probe = options.probe ?? ((probePaths, signal) => probeDaemon(probePaths, undefined, signal));
|
|
6604
|
+
const sleep = options.sleep ?? ((ms, signal) => delay(ms, undefined, { signal }));
|
|
5926
6605
|
let lastError;
|
|
5927
6606
|
let authRefreshUsed = false;
|
|
5928
|
-
for (
|
|
6607
|
+
for (const [attempt, backoffMs] of STARTUP_BACKOFF_MS.entries()) {
|
|
5929
6608
|
try {
|
|
5930
|
-
|
|
6609
|
+
if (backoffMs > 0)
|
|
6610
|
+
await sleep(backoffMs, options.signal);
|
|
6611
|
+
if (options.signal?.aborted)
|
|
6612
|
+
throw new DaemonRequestCancelledError(false);
|
|
6613
|
+
if (attempt === 0) {
|
|
6614
|
+
await ensureDaemonAvailable(paths, ensure, options.signal);
|
|
6615
|
+
} else if (!await probe(paths, options.signal)) {
|
|
6616
|
+
throw new DaemonUnreachableError(paths.socket);
|
|
6617
|
+
}
|
|
5931
6618
|
const token = readAuthToken(paths);
|
|
5932
6619
|
if (!token)
|
|
5933
6620
|
throw new DaemonRequestError("daemon auth token missing", false);
|
|
5934
6621
|
const sendOptions = options.signal === undefined ? { timeoutMs } : { timeoutMs, signal: options.signal };
|
|
5935
6622
|
return await sendToolCall(paths, token, name, requestArgs, sendOptions);
|
|
5936
6623
|
} catch (error) {
|
|
6624
|
+
if (options.signal?.aborted) {
|
|
6625
|
+
lastError = new DaemonRequestCancelledError(false);
|
|
6626
|
+
break;
|
|
6627
|
+
}
|
|
5937
6628
|
lastError = error;
|
|
5938
6629
|
if (error instanceof DaemonAuthenticationRejectedError && !authRefreshUsed) {
|
|
5939
6630
|
authRefreshUsed = true;
|
|
@@ -5950,14 +6641,17 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5950
6641
|
function callDiagnosticsViaDaemon(filePath, options) {
|
|
5951
6642
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
5952
6643
|
}
|
|
6644
|
+
function callFormatViaDaemon(filePath, options) {
|
|
6645
|
+
return callToolViaDaemon("format", { filePath }, options);
|
|
6646
|
+
}
|
|
5953
6647
|
function currentRequestContext(env = process.env) {
|
|
5954
6648
|
const cwd = process.cwd();
|
|
5955
6649
|
const home = env["HOME"] ?? homedir3();
|
|
5956
6650
|
return parseLspRequestContext({
|
|
5957
6651
|
cwd,
|
|
5958
|
-
projectConfigPaths: [
|
|
5959
|
-
userConfigPath:
|
|
5960
|
-
installDecisionsPath:
|
|
6652
|
+
projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
|
|
6653
|
+
userConfigPath: join8(home, ".codex", "lsp-client.json"),
|
|
6654
|
+
installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
|
|
5961
6655
|
capabilities: { installDecisionTool: true }
|
|
5962
6656
|
});
|
|
5963
6657
|
}
|
|
@@ -5972,7 +6666,7 @@ function withContext(args, context) {
|
|
|
5972
6666
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5973
6667
|
if (!signal)
|
|
5974
6668
|
return ensure(paths);
|
|
5975
|
-
return new Promise((
|
|
6669
|
+
return new Promise((resolve, reject) => {
|
|
5976
6670
|
let settled = false;
|
|
5977
6671
|
const finish = (run) => {
|
|
5978
6672
|
if (settled)
|
|
@@ -5987,11 +6681,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5987
6681
|
return;
|
|
5988
6682
|
}
|
|
5989
6683
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5990
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
6684
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5991
6685
|
});
|
|
5992
6686
|
}
|
|
5993
6687
|
function sendToolCall(paths, token, name, args, options) {
|
|
5994
|
-
return new Promise((
|
|
6688
|
+
return new Promise((resolve, reject) => {
|
|
5995
6689
|
const socket = connect(paths.socket);
|
|
5996
6690
|
const requestId = allocateProxyRequestId();
|
|
5997
6691
|
let settled = false;
|
|
@@ -6044,7 +6738,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
6044
6738
|
}
|
|
6045
6739
|
const result = toToolResult(message, requestId);
|
|
6046
6740
|
if (result)
|
|
6047
|
-
finish(() =>
|
|
6741
|
+
finish(() => resolve(result));
|
|
6048
6742
|
else
|
|
6049
6743
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
6050
6744
|
});
|
|
@@ -6186,7 +6880,7 @@ function asToolCall(parsed) {
|
|
|
6186
6880
|
if (!isPlainRecord(params) || typeof params["name"] !== "string")
|
|
6187
6881
|
return null;
|
|
6188
6882
|
const args = params["arguments"];
|
|
6189
|
-
return { id:
|
|
6883
|
+
return { id: jsonRpcId2(parsed["id"]), name: params["name"], args: isPlainRecord(args) ? args : {} };
|
|
6190
6884
|
}
|
|
6191
6885
|
function inferOpenCodeProjectCwd(projectConfigEnv) {
|
|
6192
6886
|
if (!projectConfigEnv)
|
|
@@ -6212,266 +6906,28 @@ function canonicalizePathList(value) {
|
|
|
6212
6906
|
return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
|
|
6213
6907
|
}
|
|
6214
6908
|
function canonicalizePath(value) {
|
|
6215
|
-
if (value === undefined || !
|
|
6909
|
+
if (value === undefined || !isAbsolute6(value) || !existsSync14(value))
|
|
6216
6910
|
return value;
|
|
6217
|
-
return
|
|
6911
|
+
return realpathSync6(value);
|
|
6218
6912
|
}
|
|
6219
|
-
function projectRootFromOpenCodeConfigPath(
|
|
6220
|
-
if (basename4(
|
|
6913
|
+
function projectRootFromOpenCodeConfigPath(path) {
|
|
6914
|
+
if (basename4(path) !== "lsp.json" && basename4(path) !== "lsp-client.json")
|
|
6221
6915
|
return;
|
|
6222
|
-
const configDir =
|
|
6916
|
+
const configDir = dirname13(path);
|
|
6223
6917
|
const configDirName = basename4(configDir);
|
|
6224
6918
|
if (configDirName !== ".opencode" && configDirName !== ".omo")
|
|
6225
6919
|
return;
|
|
6226
|
-
return
|
|
6920
|
+
return dirname13(configDir);
|
|
6227
6921
|
}
|
|
6228
6922
|
|
|
6229
6923
|
// src/daemon-server.ts
|
|
6230
6924
|
import { chmodSync as chmodSync2 } from "node:fs";
|
|
6231
6925
|
import { createServer as createServer2 } from "node:net";
|
|
6232
6926
|
|
|
6233
|
-
// src/ownership.ts
|
|
6234
|
-
import { randomUUID } from "node:crypto";
|
|
6235
|
-
import { existsSync as existsSync13, lstatSync as lstatSync7, readFileSync as readFileSync7, statSync as statSync5, unlinkSync as unlinkSync3 } from "node:fs";
|
|
6236
|
-
import { dirname as dirname11 } from "node:path";
|
|
6237
|
-
|
|
6238
|
-
// src/lock.ts
|
|
6239
|
-
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeSync as writeSync3 } from "node:fs";
|
|
6240
|
-
import { dirname as dirname10 } from "node:path";
|
|
6241
|
-
function isProcessAlive2(pid) {
|
|
6242
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
6243
|
-
return false;
|
|
6244
|
-
try {
|
|
6245
|
-
process.kill(pid, 0);
|
|
6246
|
-
return true;
|
|
6247
|
-
} catch (error) {
|
|
6248
|
-
if (error instanceof Error)
|
|
6249
|
-
return errorCode3(error) === "EPERM";
|
|
6250
|
-
throw error;
|
|
6251
|
-
}
|
|
6252
|
-
}
|
|
6253
|
-
function readLockPid(lockPath) {
|
|
6254
|
-
try {
|
|
6255
|
-
const pid = Number.parseInt(readFileSync6(lockPath, "utf8").trim(), 10);
|
|
6256
|
-
return Number.isInteger(pid) ? pid : null;
|
|
6257
|
-
} catch {
|
|
6258
|
-
return null;
|
|
6259
|
-
}
|
|
6260
|
-
}
|
|
6261
|
-
function tryAcquireLock(lockPath, ownerPid = process.pid) {
|
|
6262
|
-
mkdirSync4(dirname10(lockPath), { recursive: true });
|
|
6263
|
-
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
6264
|
-
const handle = writeLockFile(lockPath, ownerPid);
|
|
6265
|
-
if (handle)
|
|
6266
|
-
return handle;
|
|
6267
|
-
if (!reapStaleLock(lockPath))
|
|
6268
|
-
return null;
|
|
6269
|
-
}
|
|
6270
|
-
return null;
|
|
6271
|
-
}
|
|
6272
|
-
function writeLockFile(lockPath, ownerPid) {
|
|
6273
|
-
try {
|
|
6274
|
-
const fd = openSync3(lockPath, "wx", 384);
|
|
6275
|
-
writeSync3(fd, `${ownerPid}
|
|
6276
|
-
`);
|
|
6277
|
-
closeSync3(fd);
|
|
6278
|
-
return { release: () => unlinkQuietly(lockPath) };
|
|
6279
|
-
} catch (error) {
|
|
6280
|
-
if (errorCode3(error) === "EEXIST")
|
|
6281
|
-
return null;
|
|
6282
|
-
throw error;
|
|
6283
|
-
}
|
|
6284
|
-
}
|
|
6285
|
-
function reapStaleLock(lockPath) {
|
|
6286
|
-
const pid = readLockPid(lockPath);
|
|
6287
|
-
if (pid !== null && isProcessAlive2(pid))
|
|
6288
|
-
return false;
|
|
6289
|
-
unlinkQuietly(lockPath);
|
|
6290
|
-
return true;
|
|
6291
|
-
}
|
|
6292
|
-
function unlinkQuietly(path2) {
|
|
6293
|
-
try {
|
|
6294
|
-
unlinkSync2(path2);
|
|
6295
|
-
} catch (error) {
|
|
6296
|
-
if (error instanceof Error)
|
|
6297
|
-
return;
|
|
6298
|
-
throw error;
|
|
6299
|
-
}
|
|
6300
|
-
}
|
|
6301
|
-
function errorCode3(error) {
|
|
6302
|
-
if (!error || typeof error !== "object" || !("code" in error))
|
|
6303
|
-
return;
|
|
6304
|
-
const code = Reflect.get(error, "code");
|
|
6305
|
-
return typeof code === "string" ? code : undefined;
|
|
6306
|
-
}
|
|
6307
|
-
|
|
6308
|
-
// src/ownership.ts
|
|
6309
|
-
class DaemonAlreadyRunningError extends Error {
|
|
6310
|
-
name = "DaemonAlreadyRunningError";
|
|
6311
|
-
code = "daemon_already_running";
|
|
6312
|
-
}
|
|
6313
|
-
|
|
6314
|
-
class DaemonStartupDeferredError extends Error {
|
|
6315
|
-
reason;
|
|
6316
|
-
name = "DaemonStartupDeferredError";
|
|
6317
|
-
code = "daemon_startup_deferred";
|
|
6318
|
-
constructor(reason) {
|
|
6319
|
-
super(`LSP daemon startup deferred: ${reason}`);
|
|
6320
|
-
this.reason = reason;
|
|
6321
|
-
}
|
|
6322
|
-
}
|
|
6323
|
-
async function acquireStartupLease(paths, pingOwner) {
|
|
6324
|
-
ensureDaemonDirectories(paths);
|
|
6325
|
-
const lock = tryAcquireLock(paths.lock);
|
|
6326
|
-
if (!lock) {
|
|
6327
|
-
const token = readAuthToken(paths);
|
|
6328
|
-
if (token && await pingOwner(token))
|
|
6329
|
-
throw new DaemonAlreadyRunningError("LSP daemon already running");
|
|
6330
|
-
throw new DaemonStartupDeferredError("startup_lock_busy");
|
|
6331
|
-
}
|
|
6332
|
-
try {
|
|
6333
|
-
const token = await validateExistingOwner(paths, pingOwner);
|
|
6334
|
-
return { lock, token, owner: newOwner(paths) };
|
|
6335
|
-
} catch (error) {
|
|
6336
|
-
lock.release();
|
|
6337
|
-
throw error;
|
|
6338
|
-
}
|
|
6339
|
-
}
|
|
6340
|
-
function ensureDaemonDirectories(paths) {
|
|
6341
|
-
ensurePrivateDirectory(paths.dir);
|
|
6342
|
-
if (process.platform !== "win32")
|
|
6343
|
-
ensurePrivateDirectory(dirname11(paths.socket));
|
|
6344
|
-
}
|
|
6345
|
-
function readDaemonOwner(paths) {
|
|
6346
|
-
try {
|
|
6347
|
-
return parseOwner(JSON.parse(readFileSync7(paths.owner, "utf8")));
|
|
6348
|
-
} catch (error) {
|
|
6349
|
-
if (error instanceof Error)
|
|
6350
|
-
return null;
|
|
6351
|
-
throw error;
|
|
6352
|
-
}
|
|
6353
|
-
}
|
|
6354
|
-
function writeDaemonOwner(paths, owner) {
|
|
6355
|
-
writePrivateFile(paths.pid, `${owner.pid}
|
|
6356
|
-
`);
|
|
6357
|
-
writePrivateFile(paths.endpoint, owner.endpoint.path);
|
|
6358
|
-
writePrivateFile(paths.owner, `${JSON.stringify(owner)}
|
|
6359
|
-
`);
|
|
6360
|
-
}
|
|
6361
|
-
function removeDaemonMetadataForOwner(paths, owner) {
|
|
6362
|
-
const current = readDaemonOwner(paths);
|
|
6363
|
-
if (!current || !sameOwner(current, owner))
|
|
6364
|
-
return;
|
|
6365
|
-
unlinkQuietly(paths.socket);
|
|
6366
|
-
unlinkQuietly(paths.pid);
|
|
6367
|
-
unlinkQuietly(paths.endpoint);
|
|
6368
|
-
unlinkQuietly(paths.owner);
|
|
6369
|
-
}
|
|
6370
|
-
function endpointIdentity(endpointPath) {
|
|
6371
|
-
if (process.platform === "win32")
|
|
6372
|
-
return { kind: "windows", path: endpointPath };
|
|
6373
|
-
try {
|
|
6374
|
-
const stats = statSync5(endpointPath);
|
|
6375
|
-
return { kind: "unix", path: endpointPath, dev: stats.dev, ino: stats.ino };
|
|
6376
|
-
} catch (error) {
|
|
6377
|
-
if (error instanceof Error)
|
|
6378
|
-
return { kind: "missing", path: endpointPath };
|
|
6379
|
-
throw error;
|
|
6380
|
-
}
|
|
6381
|
-
}
|
|
6382
|
-
function sameEndpoint(a, b) {
|
|
6383
|
-
if (a.kind !== b.kind || a.path !== b.path)
|
|
6384
|
-
return false;
|
|
6385
|
-
switch (a.kind) {
|
|
6386
|
-
case "unix":
|
|
6387
|
-
return b.kind === "unix" && a.dev === b.dev && a.ino === b.ino;
|
|
6388
|
-
case "windows":
|
|
6389
|
-
return true;
|
|
6390
|
-
case "missing":
|
|
6391
|
-
return true;
|
|
6392
|
-
}
|
|
6393
|
-
}
|
|
6394
|
-
function sameOwner(a, b) {
|
|
6395
|
-
return a.pid === b.pid && a.nonce === b.nonce && sameEndpoint(a.endpoint, b.endpoint);
|
|
6396
|
-
}
|
|
6397
|
-
async function validateExistingOwner(paths, pingOwner) {
|
|
6398
|
-
let token = readOrCreateAuthToken(paths);
|
|
6399
|
-
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
6400
|
-
const owner = readDaemonOwner(paths);
|
|
6401
|
-
if (!owner)
|
|
6402
|
-
return token;
|
|
6403
|
-
const ping = await pingOwner(token);
|
|
6404
|
-
if (ping && owner.nonce === ping.nonce && sameEndpoint(owner.endpoint, ping.endpoint)) {
|
|
6405
|
-
throw new DaemonAlreadyRunningError("LSP daemon already running");
|
|
6406
|
-
}
|
|
6407
|
-
if (ping)
|
|
6408
|
-
continue;
|
|
6409
|
-
if (isProcessAlive2(owner.pid))
|
|
6410
|
-
throw new DaemonStartupDeferredError("owner_pid_live_unreachable");
|
|
6411
|
-
const reread = readDaemonOwner(paths);
|
|
6412
|
-
const endpoint = endpointIdentity(owner.endpoint.path);
|
|
6413
|
-
if (!reread || reread.nonce !== owner.nonce || !sameEndpoint(endpoint, owner.endpoint)) {
|
|
6414
|
-
throw new DaemonStartupDeferredError("owner_changed_during_cleanup");
|
|
6415
|
-
}
|
|
6416
|
-
cleanupDeadOwner(paths, owner);
|
|
6417
|
-
token = rotateAuthToken(paths);
|
|
6418
|
-
return token;
|
|
6419
|
-
}
|
|
6420
|
-
throw new DaemonStartupDeferredError("reachable_owner_mismatch");
|
|
6421
|
-
}
|
|
6422
|
-
function cleanupDeadOwner(paths, owner) {
|
|
6423
|
-
if (process.platform !== "win32" && existsSync13(owner.endpoint.path)) {
|
|
6424
|
-
const stat = lstatSync7(owner.endpoint.path);
|
|
6425
|
-
if (stat.isSocket())
|
|
6426
|
-
unlinkSync3(owner.endpoint.path);
|
|
6427
|
-
}
|
|
6428
|
-
unlinkQuietly(paths.pid);
|
|
6429
|
-
unlinkQuietly(paths.endpoint);
|
|
6430
|
-
unlinkQuietly(paths.owner);
|
|
6431
|
-
}
|
|
6432
|
-
function newOwner(paths) {
|
|
6433
|
-
return {
|
|
6434
|
-
pid: process.pid,
|
|
6435
|
-
nonce: randomUUID(),
|
|
6436
|
-
startedAt: new Date().toISOString(),
|
|
6437
|
-
endpoint: endpointIdentity(paths.socket)
|
|
6438
|
-
};
|
|
6439
|
-
}
|
|
6440
|
-
function parseOwner(value) {
|
|
6441
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6442
|
-
return null;
|
|
6443
|
-
const pid = Reflect.get(value, "pid");
|
|
6444
|
-
const nonce = Reflect.get(value, "nonce");
|
|
6445
|
-
const startedAt = Reflect.get(value, "startedAt");
|
|
6446
|
-
const endpoint = parseEndpoint(Reflect.get(value, "endpoint"));
|
|
6447
|
-
if (typeof pid !== "number" || typeof nonce !== "string" || typeof startedAt !== "string" || !endpoint)
|
|
6448
|
-
return null;
|
|
6449
|
-
return { pid, nonce, startedAt, endpoint };
|
|
6450
|
-
}
|
|
6451
|
-
function parseEndpoint(value) {
|
|
6452
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6453
|
-
return null;
|
|
6454
|
-
const kind = Reflect.get(value, "kind");
|
|
6455
|
-
const path2 = Reflect.get(value, "path");
|
|
6456
|
-
if (typeof path2 !== "string")
|
|
6457
|
-
return null;
|
|
6458
|
-
if (kind === undefined)
|
|
6459
|
-
return endpointIdentity(path2);
|
|
6460
|
-
if (kind === "windows")
|
|
6461
|
-
return { kind, path: path2 };
|
|
6462
|
-
if (kind === "missing")
|
|
6463
|
-
return { kind, path: path2 };
|
|
6464
|
-
const dev = Reflect.get(value, "dev");
|
|
6465
|
-
const ino = Reflect.get(value, "ino");
|
|
6466
|
-
if (kind === "unix" && typeof dev === "number" && typeof ino === "number")
|
|
6467
|
-
return { kind, path: path2, dev, ino };
|
|
6468
|
-
return null;
|
|
6469
|
-
}
|
|
6470
|
-
|
|
6471
6927
|
// src/version-reap.ts
|
|
6472
6928
|
import { execFile } from "node:child_process";
|
|
6473
6929
|
import { readdir, readFile, rm } from "node:fs/promises";
|
|
6474
|
-
import { basename as basename5, dirname as
|
|
6930
|
+
import { basename as basename5, dirname as dirname14, join as join9 } from "node:path";
|
|
6475
6931
|
var TERM_GRACE_MS = 5000;
|
|
6476
6932
|
var KILL_GRACE_MS = 1000;
|
|
6477
6933
|
var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
|
|
@@ -6492,13 +6948,13 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
|
|
|
6492
6948
|
return isNodeCliDaemonCommand(command.trim());
|
|
6493
6949
|
}
|
|
6494
6950
|
async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
6495
|
-
const baseDir =
|
|
6951
|
+
const baseDir = dirname14(ownPaths.dir);
|
|
6496
6952
|
const platform = deps.platform ?? process.platform;
|
|
6497
|
-
const isAlive = deps.isAlive ??
|
|
6953
|
+
const isAlive = deps.isAlive ?? isProcessAlive;
|
|
6498
6954
|
const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
|
|
6499
6955
|
const sendSignal = deps.sendSignal ?? defaultSendSignal;
|
|
6500
6956
|
const waitForExit = deps.waitForExit ?? defaultWaitForExit;
|
|
6501
|
-
const removeDir = deps.removeDir ?? ((
|
|
6957
|
+
const removeDir = deps.removeDir ?? ((path) => rm(path, { recursive: true, force: true }));
|
|
6502
6958
|
const readOwner = deps.readOwner ?? readDaemonOwner;
|
|
6503
6959
|
const log = deps.log ?? defaultLog;
|
|
6504
6960
|
const termGraceMs = deps.termGraceMs ?? TERM_GRACE_MS;
|
|
@@ -6511,7 +6967,7 @@ async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
|
6511
6967
|
const version = parseVersionEntry(entry.name);
|
|
6512
6968
|
if (version === null || !entry.isDirectory())
|
|
6513
6969
|
continue;
|
|
6514
|
-
const versionDir =
|
|
6970
|
+
const versionDir = join9(baseDir, entry.name);
|
|
6515
6971
|
const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
|
|
6516
6972
|
results.push(await reapOneVersion({
|
|
6517
6973
|
version,
|
|
@@ -6535,7 +6991,7 @@ async function reapOneVersion(context) {
|
|
|
6535
6991
|
const { version, versionDir } = context;
|
|
6536
6992
|
const owner = context.readOwner(context.siblingPaths);
|
|
6537
6993
|
if (!owner) {
|
|
6538
|
-
const lockPid = readLockPid(
|
|
6994
|
+
const lockPid = readLockPid(join9(versionDir, "daemon.lock"));
|
|
6539
6995
|
if (lockPid !== null && context.isAlive(lockPid)) {
|
|
6540
6996
|
context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
|
|
6541
6997
|
return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
|
|
@@ -6609,17 +7065,17 @@ function isNodeCliDaemonArgv(argv) {
|
|
|
6609
7065
|
function isNodeCliDaemonCommand(command) {
|
|
6610
7066
|
return /\bnode(?:\.exe)?\b/i.test(command) && /\bcli\.js\b/.test(command) && /\bdaemon\b/.test(command);
|
|
6611
7067
|
}
|
|
6612
|
-
function defaultReadProcFile(
|
|
6613
|
-
return readFile(
|
|
7068
|
+
function defaultReadProcFile(path) {
|
|
7069
|
+
return readFile(path);
|
|
6614
7070
|
}
|
|
6615
7071
|
function defaultExecuteForStdout(file, args) {
|
|
6616
|
-
return new Promise((
|
|
6617
|
-
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
|
|
7072
|
+
return new Promise((resolve) => {
|
|
7073
|
+
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000, windowsHide: true }, (error, stdout) => {
|
|
6618
7074
|
if (error !== null) {
|
|
6619
|
-
|
|
7075
|
+
resolve(null);
|
|
6620
7076
|
return;
|
|
6621
7077
|
}
|
|
6622
|
-
|
|
7078
|
+
resolve(stdout);
|
|
6623
7079
|
});
|
|
6624
7080
|
});
|
|
6625
7081
|
}
|
|
@@ -6634,11 +7090,11 @@ function defaultSendSignal(pid, signal) {
|
|
|
6634
7090
|
async function defaultWaitForExit(pid, timeoutMs) {
|
|
6635
7091
|
const deadline = Date.now() + timeoutMs;
|
|
6636
7092
|
for (;; ) {
|
|
6637
|
-
if (!
|
|
7093
|
+
if (!isProcessAlive(pid))
|
|
6638
7094
|
return true;
|
|
6639
7095
|
if (Date.now() >= deadline)
|
|
6640
7096
|
return false;
|
|
6641
|
-
await new Promise((
|
|
7097
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
6642
7098
|
}
|
|
6643
7099
|
}
|
|
6644
7100
|
function defaultLog(message) {
|
|
@@ -6659,7 +7115,7 @@ async function startDaemonServer(paths, options = {}) {
|
|
|
6659
7115
|
lastActiveAt = Date.now();
|
|
6660
7116
|
};
|
|
6661
7117
|
let routeOwner = lease.owner;
|
|
6662
|
-
const
|
|
7118
|
+
const server = createServer2((socket) => {
|
|
6663
7119
|
connections.add(socket);
|
|
6664
7120
|
const activeRequests = new Map;
|
|
6665
7121
|
touch();
|
|
@@ -6677,10 +7133,10 @@ async function startDaemonServer(paths, options = {}) {
|
|
|
6677
7133
|
touch();
|
|
6678
7134
|
});
|
|
6679
7135
|
});
|
|
6680
|
-
|
|
7136
|
+
server.on("error", (error) => logServerError(error));
|
|
6681
7137
|
let owner;
|
|
6682
7138
|
try {
|
|
6683
|
-
await listen(
|
|
7139
|
+
await listen(server, paths.socket);
|
|
6684
7140
|
if (process.platform !== "win32")
|
|
6685
7141
|
chmodSync2(paths.socket, 384);
|
|
6686
7142
|
owner = { ...lease.owner, endpoint: endpointIdentity(paths.socket) };
|
|
@@ -6702,7 +7158,7 @@ async function startDaemonServer(paths, options = {}) {
|
|
|
6702
7158
|
for (const socket of connections)
|
|
6703
7159
|
socket.destroy();
|
|
6704
7160
|
connections.clear();
|
|
6705
|
-
await closeServer(
|
|
7161
|
+
await closeServer(server);
|
|
6706
7162
|
removeDaemonMetadataForOwner(paths, owner);
|
|
6707
7163
|
await disposeDefaultLspManager();
|
|
6708
7164
|
};
|
|
@@ -6723,7 +7179,7 @@ async function startDaemonServer(paths, options = {}) {
|
|
|
6723
7179
|
}, idleCheckIntervalMs);
|
|
6724
7180
|
idleTimer.unref();
|
|
6725
7181
|
installSignalHandlers(close);
|
|
6726
|
-
return { server
|
|
7182
|
+
return { server, close };
|
|
6727
7183
|
}
|
|
6728
7184
|
async function respond(socket, message, token, owner, activeRequests) {
|
|
6729
7185
|
try {
|
|
@@ -6744,18 +7200,18 @@ async function assertSelfProbe(paths, token, owner) {
|
|
|
6744
7200
|
if (!ping || ping.nonce !== owner.nonce)
|
|
6745
7201
|
throw new DaemonStartupDeferredError("self_probe_failed");
|
|
6746
7202
|
}
|
|
6747
|
-
function listen(
|
|
6748
|
-
return new Promise((
|
|
7203
|
+
function listen(server, socketPath) {
|
|
7204
|
+
return new Promise((resolve, reject) => {
|
|
6749
7205
|
const onError = (error) => reject(error);
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
7206
|
+
server.once("error", onError);
|
|
7207
|
+
server.listen(socketPath, () => {
|
|
7208
|
+
server.removeListener("error", onError);
|
|
7209
|
+
resolve();
|
|
6754
7210
|
});
|
|
6755
7211
|
});
|
|
6756
7212
|
}
|
|
6757
|
-
function closeServer(
|
|
6758
|
-
return new Promise((
|
|
7213
|
+
function closeServer(server) {
|
|
7214
|
+
return new Promise((resolve) => server.close(() => resolve()));
|
|
6759
7215
|
}
|
|
6760
7216
|
function installSignalHandlers(close) {
|
|
6761
7217
|
const handler = () => {
|
|
@@ -6804,7 +7260,12 @@ async function main() {
|
|
|
6804
7260
|
process.exitCode = 2;
|
|
6805
7261
|
}
|
|
6806
7262
|
main().catch((error) => {
|
|
6807
|
-
|
|
7263
|
+
if (error instanceof DaemonStartupDeferredError) {
|
|
7264
|
+
stderr.write(`[lsp-daemon] startup deferred: ${error.reason}
|
|
7265
|
+
`);
|
|
7266
|
+
} else {
|
|
7267
|
+
stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
|
|
6808
7268
|
`);
|
|
7269
|
+
}
|
|
6809
7270
|
process.exitCode = 1;
|
|
6810
7271
|
});
|