lazycodex-ai 5.0.0-beta.4 → 5.0.0-beta.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +25 -21
- package/README.ko.md +25 -21
- package/README.md +38 -23
- package/README.ru.md +24 -20
- package/README.zh-cn.md +25 -21
- package/dist/cli/config-manager/parse-opencode-config-file.d.ts +2 -1
- package/dist/cli/doctor/checks/system-plugin.d.ts +4 -3
- package/dist/cli/fallback-lane-policy.d.ts +1 -0
- package/dist/cli/index.js +66932 -64746
- 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 +66795 -64586
- package/package.json +9 -9
- package/packages/git-bash-mcp/dist/cli.js +6 -1
- package/packages/lsp-daemon/dist/cli.js +793 -323
- package/packages/lsp-daemon/dist/client.d.ts +10 -0
- package/packages/lsp-daemon/dist/client.js +753 -280
- package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-client.js +3 -0
- package/packages/lsp-daemon/dist/ensure-daemon.js +1 -0
- package/packages/lsp-daemon/dist/index.js +757 -289
- package/packages/lsp-daemon/dist/proxy.js +3 -0
- package/packages/lsp-daemon/dist/version-reap.js +1 -1
- package/packages/lsp-daemon/package.json +1 -1
- package/packages/lsp-tools-mcp/dist/cli.js +712 -244
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +248 -119
- package/packages/lsp-tools-mcp/dist/mcp.js +714 -246
- package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
- package/packages/lsp-tools-mcp/dist/tools.js +718 -254
- package/packages/lsp-tools-mcp/package.json +1 -1
- 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 +2 -2
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +45 -49
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/src/hook.ts +1 -0
- package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +9 -0
- package/packages/omo-codex/plugin/components/comment-checker/biome.json +2 -2
- package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +2 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -5
- package/packages/omo-codex/plugin/components/comment-checker/src/apply-patch.ts +2 -8
- package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +1 -2
- package/packages/omo-codex/plugin/components/comment-checker/src/request-extractor.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +1 -0
- package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +3 -4
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/biome.json +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +1 -5
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +1 -5
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +5 -5
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +1 -5
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +4 -21
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
- 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 +741 -294
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +1 -1
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +5 -5
- package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +1 -5
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +6 -7
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +1 -2
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +11 -1
- package/packages/omo-codex/plugin/components/rules/AGENTS.md +12 -0
- package/packages/omo-codex/plugin/components/rules/biome.json +2 -2
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +60 -45
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +7 -7
- package/packages/omo-codex/plugin/components/rules/src/config.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +9 -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 +1 -2
- 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 +5 -6
- package/packages/omo-codex/plugin/components/rules/test/rules-engine-consumption.test.ts +3 -6
- package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +1 -2
- package/packages/omo-codex/plugin/components/rules/test/sources.test.ts +2 -5
- package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +2 -17
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +5 -5
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +4 -10
- package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/telemetry/biome.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +2463 -437
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +2467 -441
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +5 -5
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +1 -4
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -14
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +1 -1
- package/packages/omo-codex/plugin/components/telemetry/test/diagnostics.test.ts +2 -5
- package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -4
- package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +489 -4
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -6
- package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +30 -14
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +4 -0
- package/packages/omo-codex/plugin/components/ultrawork/src/directive.ts +5 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +9 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
- package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +14 -8
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +12 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/AGENTS.md +2 -2
- 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 +5 -5
- 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 +6 -6
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/dist/cli.js +12 -12
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +28 -0
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/package.json +12 -12
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/boulder-reader.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/cli.ts +1 -1
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/codex-hook.ts +3 -3
- 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}/test/boulder-reader.test.ts +3 -3
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/cli.test.ts +1 -4
- package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/codex-hook.test.ts +8 -22
- package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/biome.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +15 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.d.ts +12 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +45 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +15 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.d.ts +8 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +120 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +40 -39
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +7 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +958 -342
- 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 +27 -6
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +13 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +15 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +17 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +17 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +13 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +19 -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 +69 -111
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +185 -14
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +65 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +22 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-codex-validation.ts +81 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +31 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +134 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +38 -71
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +7 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +14 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +34 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +26 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +19 -9
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +18 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +27 -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 +68 -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 +82 -131
- package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +187 -12
- package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +36 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +95 -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 +133 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +137 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +25 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-status-next-actions.test.ts +183 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +37 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +7 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/guided-recovery.test.ts +105 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -37
- package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/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-poisoning-cascades.test.ts +97 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +46 -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 +48 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +318 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +8 -5
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/surface.test.ts +74 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +13 -8
- package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +1 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/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-checking-ulw-execute-continuation.json +17 -0
- 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 +3 -3
- package/packages/omo-codex/plugin/package-lock.json +676 -524
- package/packages/omo-codex/plugin/package.json +2 -3
- package/packages/omo-codex/plugin/scripts/AGENTS.md +39 -0
- package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +1 -2
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +0 -9
- package/packages/omo-codex/plugin/scripts/canonical-ultrawork-directive.mjs +17 -0
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +0 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +36 -13
- 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/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +11 -7
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +13 -13
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +2 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +15 -3
- package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +19 -26
- package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +22 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -2
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +3 -2
- 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 +9 -48
- 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 +1 -1
- 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 +2 -27
- 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 +2 -2
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +4 -5
- 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 +8 -8
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
- package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +23 -13
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +14 -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/install-dist/install-local.mjs +2817 -913
- package/packages/{omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md → prompts-core/prompts/ultrawork/codex.md} +15 -10
- package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
- package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
- package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
- package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
- package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +11 -7
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/shared-skills/skills/init-deep/SKILL.md +13 -13
- package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +17 -16
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +6 -7
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/shared-skills/skills/ulw-research/SKILL.md +4 -2
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +3 -2
- package/script/qa/web-terminal-visual-qa.mjs +2 -0
- package/script/qa/xterm-live-terminal.mjs +18 -2
- package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/lsp/process-signal-cleanup.d.ts +0 -1
- package/packages/lsp-tools-mcp/dist/missing-dependency-result.d.ts +0 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +0 -58
- package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +0 -2951
- package/packages/omo-codex/plugin/components/codegraph/NOTICE +0 -16
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +0 -12136
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9734
- package/packages/omo-codex/plugin/components/codegraph/package.json +0 -33
- package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +0 -79
- package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +0 -33
- package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +0 -25
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +0 -131
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +0 -258
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +0 -309
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +0 -80
- package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +0 -34
- package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +0 -263
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +0 -106
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +0 -145
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +0 -21
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +0 -139
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +0 -15
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +0 -32
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +0 -109
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +0 -148
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +0 -175
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +0 -81
- package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +0 -34
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +0 -112
- package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +0 -26
- package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +0 -160
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +0 -50
- package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +0 -29
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +0 -320
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +0 -172
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +0 -91
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +0 -100
- package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +0 -76
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +0 -133
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +0 -245
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +0 -69
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +0 -43
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +0 -147
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +0 -175
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +0 -385
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +0 -206
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +0 -58
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +0 -104
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +0 -65
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +0 -106
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +0 -116
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +0 -258
- package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +0 -56
- package/packages/omo-codex/plugin/components/codegraph/tsconfig.build.json +0 -13
- package/packages/omo-codex/plugin/components/codegraph/tsconfig.json +0 -25
- package/packages/omo-codex/plugin/components/start-work-continuation/LICENSE +0 -21
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +0 -471
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +0 -18
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +0 -17
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/editor.mjs +0 -125
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/jsonc.mjs +0 -43
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot/scaffold.mjs +0 -29
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +0 -121
- package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
- package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
- package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
- package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
- package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
- package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +0 -76
- package/packages/omo-codex/plugin/test/migrate-omo-sot.test.mjs +0 -179
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
- package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
- package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
- package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
- package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
- package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
- /package/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}/src/types.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
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { argv, stderr } from "node:process";
|
|
5
5
|
|
|
6
6
|
// src/proxy.ts
|
|
7
|
-
import { existsSync as
|
|
8
|
-
import { basename as
|
|
7
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6 } from "node:fs";
|
|
8
|
+
import { basename as basename4, delimiter as delimiter4, dirname as dirname11, isAbsolute as isAbsolute6 } from "node:path";
|
|
9
9
|
|
|
10
10
|
// ../mcp-stdio-core/src/record.ts
|
|
11
11
|
function isPlainRecord(value) {
|
|
@@ -184,6 +184,7 @@ async function runJsonRpcStdioServer(config) {
|
|
|
184
184
|
const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
|
|
185
185
|
isClosed = true;
|
|
186
186
|
config.onIdleTimeout?.();
|
|
187
|
+
config.input.destroy();
|
|
187
188
|
});
|
|
188
189
|
const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
|
|
189
190
|
isClosed = true;
|
|
@@ -280,7 +281,11 @@ function createParentWatchdog(config, onDeadParent) {
|
|
|
280
281
|
const probeAlive = config.probeAlive ?? isProcessAlive;
|
|
281
282
|
let fired = false;
|
|
282
283
|
const timer = setInterval(() => {
|
|
283
|
-
if (fired
|
|
284
|
+
if (fired)
|
|
285
|
+
return;
|
|
286
|
+
const alive = probeAlive(parentPid);
|
|
287
|
+
config.onPoll?.(alive);
|
|
288
|
+
if (alive)
|
|
284
289
|
return;
|
|
285
290
|
fired = true;
|
|
286
291
|
onDeadParent(parentPid, pollIntervalMs);
|
|
@@ -315,8 +320,8 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
|
315
320
|
};
|
|
316
321
|
}
|
|
317
322
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
318
|
-
import { existsSync as
|
|
319
|
-
import { dirname as
|
|
323
|
+
import { existsSync as existsSync10, realpathSync as realpathSync5, statSync as statSync3 } from "node:fs";
|
|
324
|
+
import { basename as basename3, dirname as dirname8, join as join5, resolve as resolve8 } from "node:path";
|
|
320
325
|
|
|
321
326
|
// ../lsp-core/src/request-context.ts
|
|
322
327
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -325,18 +330,17 @@ import { homedir } from "node:os";
|
|
|
325
330
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
326
331
|
|
|
327
332
|
class LspRequestContextParseError extends Error {
|
|
328
|
-
code;
|
|
329
|
-
name = "LspRequestContextParseError";
|
|
330
333
|
constructor(code, message) {
|
|
331
334
|
super(message);
|
|
332
335
|
this.code = code;
|
|
336
|
+
this.name = "LspRequestContextParseError";
|
|
333
337
|
}
|
|
334
338
|
}
|
|
335
339
|
|
|
336
340
|
class LspRequestContextUnavailableError extends Error {
|
|
337
|
-
name = "LspRequestContextUnavailableError";
|
|
338
341
|
constructor() {
|
|
339
342
|
super("LSP request context is required. Standalone MCP startup must install one with runWithRequestContext(createStandaloneMcpRequestContext()).");
|
|
343
|
+
this.name = "LspRequestContextUnavailableError";
|
|
340
344
|
}
|
|
341
345
|
}
|
|
342
346
|
var storage = new AsyncLocalStorage;
|
|
@@ -356,7 +360,7 @@ function contextCwd() {
|
|
|
356
360
|
}
|
|
357
361
|
function createStandaloneMcpRequestContext(input = {}) {
|
|
358
362
|
const env = input.env ?? process.env;
|
|
359
|
-
const cwd = canonicalCwd(input.cwd ?? process.cwd());
|
|
363
|
+
const cwd = canonicalCwd(input.cwd ?? env["LSP_TOOLS_MCP_CWD"] ?? process.cwd());
|
|
360
364
|
const home = input.homeDir ?? homedir();
|
|
361
365
|
const projectConfigPaths = translateProjectConfigEnv(env["LSP_TOOLS_MCP_PROJECT_CONFIG"], cwd);
|
|
362
366
|
const userConfigPath = translateHomeConfigEnv(env["LSP_TOOLS_MCP_USER_CONFIG"], home, ".codex/lsp-client.json");
|
|
@@ -499,22 +503,15 @@ function effectiveExtension(filePath) {
|
|
|
499
503
|
|
|
500
504
|
// ../lsp-core/src/lsp/errors.ts
|
|
501
505
|
class LspConnectionClosedError extends Error {
|
|
502
|
-
serverId;
|
|
503
|
-
root;
|
|
504
|
-
name = "LspConnectionClosedError";
|
|
505
506
|
constructor(serverId, root, message) {
|
|
506
507
|
super(message ?? `LSP connection closed for ${serverId} at ${root}`);
|
|
507
508
|
this.serverId = serverId;
|
|
508
509
|
this.root = root;
|
|
510
|
+
this.name = "LspConnectionClosedError";
|
|
509
511
|
}
|
|
510
512
|
}
|
|
511
513
|
|
|
512
514
|
class LspProcessExitedError extends Error {
|
|
513
|
-
serverId;
|
|
514
|
-
root;
|
|
515
|
-
exitCode;
|
|
516
|
-
stderrTail;
|
|
517
|
-
name = "LspProcessExitedError";
|
|
518
515
|
constructor(serverId, root, exitCode, stderrTail) {
|
|
519
516
|
const stderrSuffix = stderrTail ? `
|
|
520
517
|
stderr tail: ${stderrTail}` : "";
|
|
@@ -523,46 +520,59 @@ stderr tail: ${stderrTail}` : "";
|
|
|
523
520
|
this.root = root;
|
|
524
521
|
this.exitCode = exitCode;
|
|
525
522
|
this.stderrTail = stderrTail;
|
|
523
|
+
this.name = "LspProcessExitedError";
|
|
526
524
|
}
|
|
527
525
|
}
|
|
528
526
|
|
|
529
527
|
class LspRequestTimeoutError extends Error {
|
|
530
|
-
method;
|
|
531
|
-
stderrTail;
|
|
532
|
-
name = "LspRequestTimeoutError";
|
|
533
528
|
constructor(method, stderrTail) {
|
|
534
529
|
const stderrSuffix = stderrTail ? `
|
|
535
530
|
recent stderr: ${stderrTail}` : "";
|
|
536
531
|
super(`LSP request timeout (method: ${method})${stderrSuffix}`);
|
|
537
532
|
this.method = method;
|
|
538
533
|
this.stderrTail = stderrTail;
|
|
534
|
+
this.name = "LspRequestTimeoutError";
|
|
539
535
|
}
|
|
540
536
|
}
|
|
541
537
|
|
|
542
538
|
class LspInvalidPathError extends Error {
|
|
543
|
-
|
|
539
|
+
constructor() {
|
|
540
|
+
super(...arguments);
|
|
541
|
+
this.name = "LspInvalidPathError";
|
|
542
|
+
}
|
|
544
543
|
}
|
|
545
544
|
|
|
546
545
|
class LspServerLookupError extends Error {
|
|
547
|
-
lookup;
|
|
548
|
-
name = "LspServerLookupError";
|
|
549
546
|
constructor(message, lookup) {
|
|
550
547
|
super(message);
|
|
551
548
|
this.lookup = lookup;
|
|
549
|
+
this.name = "LspServerLookupError";
|
|
552
550
|
}
|
|
553
551
|
}
|
|
554
552
|
|
|
555
553
|
class LspServerInitializingError extends Error {
|
|
556
|
-
originalError;
|
|
557
|
-
name = "LspServerInitializingError";
|
|
558
554
|
constructor(originalError) {
|
|
559
555
|
super(`LSP server is still initializing. Please retry in a few seconds. Original error: ${originalError.message}`);
|
|
560
556
|
this.originalError = originalError;
|
|
557
|
+
this.name = "LspServerInitializingError";
|
|
561
558
|
}
|
|
562
559
|
}
|
|
563
560
|
|
|
564
561
|
class LspProcessSpawnError extends Error {
|
|
565
|
-
|
|
562
|
+
constructor() {
|
|
563
|
+
super(...arguments);
|
|
564
|
+
this.name = "LspProcessSpawnError";
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
class LspClientRespawnBudgetExceededError extends Error {
|
|
569
|
+
constructor(serverId, root, retryLimit) {
|
|
570
|
+
super(`LSP server ${serverId} at ${root} failed to stay alive; respawn budget exhausted ` + `(${retryLimit} consecutive dead generations). Retrying after the cooldown may succeed.`);
|
|
571
|
+
this.serverId = serverId;
|
|
572
|
+
this.root = root;
|
|
573
|
+
this.retryLimit = retryLimit;
|
|
574
|
+
this.name = "LspClientRespawnBudgetExceededError";
|
|
575
|
+
}
|
|
566
576
|
}
|
|
567
577
|
function isLspDeadConnectionError(err) {
|
|
568
578
|
return err instanceof LspConnectionClosedError || err instanceof LspProcessExitedError;
|
|
@@ -585,6 +595,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
|
585
595
|
// ../lsp-core/src/lsp/connection.ts
|
|
586
596
|
import { pathToFileURL } from "node:url";
|
|
587
597
|
|
|
598
|
+
// ../lsp-core/src/lsp/timer-provider.ts
|
|
599
|
+
var realTimerProvider = {
|
|
600
|
+
now: () => Date.now(),
|
|
601
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
602
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
603
|
+
};
|
|
604
|
+
|
|
588
605
|
// ../lsp-core/src/lsp/constants.ts
|
|
589
606
|
var DEFAULT_MAX_REFERENCES = 200;
|
|
590
607
|
var DEFAULT_MAX_SYMBOLS = 200;
|
|
@@ -593,9 +610,12 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
|
593
610
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
594
611
|
var INIT_TIMEOUT_MS = 60000;
|
|
595
612
|
var IDLE_TIMEOUT_MS = 5 * 60000;
|
|
613
|
+
var MAX_RESIDENT_CLIENTS = 6;
|
|
596
614
|
var REAPER_INTERVAL_MS = 60000;
|
|
597
615
|
var STOP_HARD_KILL_TIMEOUT_MS = 5000;
|
|
598
616
|
var STOP_SIGKILL_GRACE_MS = 1000;
|
|
617
|
+
var CLIENT_RESPAWN_RETRY_LIMIT = 2;
|
|
618
|
+
var CLIENT_RESPAWN_COOLDOWN_MS = 60000;
|
|
599
619
|
|
|
600
620
|
// ../lsp-core/src/lsp/json-rpc-connection.ts
|
|
601
621
|
var HEADER_SEPARATOR2 = `\r
|
|
@@ -607,20 +627,31 @@ var METHOD_NOT_FOUND = -32601;
|
|
|
607
627
|
var INTERNAL_ERROR = -32603;
|
|
608
628
|
|
|
609
629
|
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
630
|
constructor(reader, writer) {
|
|
622
631
|
this.reader = reader;
|
|
623
632
|
this.writer = writer;
|
|
633
|
+
this.pendingRequests = new Map;
|
|
634
|
+
this.notificationHandlers = new Map;
|
|
635
|
+
this.requestHandlers = new Map;
|
|
636
|
+
this.closeHandlers = [];
|
|
637
|
+
this.errorHandlers = [];
|
|
638
|
+
this.inputBuffer = Buffer.alloc(0);
|
|
639
|
+
this.nextRequestId = 1;
|
|
640
|
+
this.listening = false;
|
|
641
|
+
this.disposed = false;
|
|
642
|
+
this.handleData = (chunk) => {
|
|
643
|
+
const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
644
|
+
this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
|
|
645
|
+
this.drainInputBuffer();
|
|
646
|
+
};
|
|
647
|
+
this.handleClose = () => {
|
|
648
|
+
for (const handler of this.closeHandlers) {
|
|
649
|
+
handler();
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
this.handleStreamError = (error) => {
|
|
653
|
+
this.emitError(error);
|
|
654
|
+
};
|
|
624
655
|
}
|
|
625
656
|
listen() {
|
|
626
657
|
if (this.listening)
|
|
@@ -741,19 +772,6 @@ class JsonRpcConnection {
|
|
|
741
772
|
this.notificationHandlers.clear();
|
|
742
773
|
this.requestHandlers.clear();
|
|
743
774
|
}
|
|
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
775
|
drainInputBuffer() {
|
|
758
776
|
while (true) {
|
|
759
777
|
const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
|
|
@@ -1101,33 +1119,29 @@ function isPosition(value) {
|
|
|
1101
1119
|
|
|
1102
1120
|
// ../lsp-core/src/lsp/transport.ts
|
|
1103
1121
|
class LspClientNotStartedError extends Error {
|
|
1104
|
-
serverId;
|
|
1105
|
-
root;
|
|
1106
|
-
name = "LspClientNotStartedError";
|
|
1107
1122
|
constructor(serverId, root) {
|
|
1108
1123
|
super("LSP client not started");
|
|
1109
1124
|
this.serverId = serverId;
|
|
1110
1125
|
this.root = root;
|
|
1126
|
+
this.name = "LspClientNotStartedError";
|
|
1111
1127
|
}
|
|
1112
1128
|
}
|
|
1113
1129
|
|
|
1114
1130
|
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
1131
|
constructor(root, server2, timeouts = {}) {
|
|
1127
1132
|
this.root = root;
|
|
1128
1133
|
this.server = server2;
|
|
1134
|
+
this.proc = null;
|
|
1135
|
+
this.connection = null;
|
|
1136
|
+
this.stderrBuffer = [];
|
|
1137
|
+
this.processExited = false;
|
|
1138
|
+
this.diagnosticsStore = new Map;
|
|
1139
|
+
this.workspaceApplyEditHandler = null;
|
|
1140
|
+
this.diagnosticPullSupported = false;
|
|
1141
|
+
this.documentFormattingSupported = false;
|
|
1129
1142
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
1130
1143
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
1144
|
+
this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
|
|
1131
1145
|
}
|
|
1132
1146
|
pid() {
|
|
1133
1147
|
return this.proc?.pid;
|
|
@@ -1147,6 +1161,12 @@ class LspClientTransport {
|
|
|
1147
1161
|
isDiagnosticPullSupported() {
|
|
1148
1162
|
return this.diagnosticPullSupported;
|
|
1149
1163
|
}
|
|
1164
|
+
setDocumentFormattingSupported(supported) {
|
|
1165
|
+
this.documentFormattingSupported = supported;
|
|
1166
|
+
}
|
|
1167
|
+
isDocumentFormattingSupported() {
|
|
1168
|
+
return this.documentFormattingSupported;
|
|
1169
|
+
}
|
|
1150
1170
|
handlePublishDiagnostics(params) {
|
|
1151
1171
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
1152
1172
|
}
|
|
@@ -1222,7 +1242,7 @@ class LspClientTransport {
|
|
|
1222
1242
|
const options = args[1];
|
|
1223
1243
|
const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
|
|
1224
1244
|
const timeoutController = new AbortController;
|
|
1225
|
-
const timeoutHandle = setTimeout(() => {
|
|
1245
|
+
const timeoutHandle = this.timerProvider.setTimeout(() => {
|
|
1226
1246
|
const stderrTail = this.stderrBuffer.slice(-5).join(`
|
|
1227
1247
|
`);
|
|
1228
1248
|
timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
|
|
@@ -1241,7 +1261,7 @@ class LspClientTransport {
|
|
|
1241
1261
|
}
|
|
1242
1262
|
throw error;
|
|
1243
1263
|
} finally {
|
|
1244
|
-
clearTimeout(timeoutHandle);
|
|
1264
|
+
this.timerProvider.clearTimeout(timeoutHandle);
|
|
1245
1265
|
combinedSignal.dispose();
|
|
1246
1266
|
}
|
|
1247
1267
|
}
|
|
@@ -1360,6 +1380,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
1360
1380
|
return false;
|
|
1361
1381
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
1362
1382
|
}
|
|
1383
|
+
function supportsDocumentFormatting(capabilities) {
|
|
1384
|
+
if (capabilities === undefined)
|
|
1385
|
+
return false;
|
|
1386
|
+
const provider = capabilities.documentFormattingProvider;
|
|
1387
|
+
if (provider === undefined || provider === null || provider === false)
|
|
1388
|
+
return false;
|
|
1389
|
+
return provider === true || typeof provider === "object";
|
|
1390
|
+
}
|
|
1363
1391
|
|
|
1364
1392
|
class LspClientConnection extends LspClientTransport {
|
|
1365
1393
|
async initialize() {
|
|
@@ -1376,6 +1404,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1376
1404
|
references: {},
|
|
1377
1405
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
1378
1406
|
publishDiagnostics: {},
|
|
1407
|
+
formatting: { dynamicRegistration: false },
|
|
1379
1408
|
rename: {
|
|
1380
1409
|
prepareSupport: true,
|
|
1381
1410
|
prepareSupportDefaultBehavior: 1
|
|
@@ -1417,6 +1446,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1417
1446
|
initializationOptions: this.server.initialization
|
|
1418
1447
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
1419
1448
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
1449
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
1420
1450
|
await this.sendNotification("initialized", {});
|
|
1421
1451
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
1422
1452
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -1612,6 +1642,17 @@ function canonicalPath(filePath) {
|
|
|
1612
1642
|
return absolute;
|
|
1613
1643
|
}
|
|
1614
1644
|
}
|
|
1645
|
+
function normalizeDocumentUri(uri) {
|
|
1646
|
+
let decoded = uri;
|
|
1647
|
+
try {
|
|
1648
|
+
decoded = decodeURIComponent(uri);
|
|
1649
|
+
} catch {
|
|
1650
|
+
decoded = uri;
|
|
1651
|
+
}
|
|
1652
|
+
if (process.platform !== "win32")
|
|
1653
|
+
return decoded;
|
|
1654
|
+
return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
|
|
1655
|
+
}
|
|
1615
1656
|
function isSameOrDescendant(candidate, parent) {
|
|
1616
1657
|
const suffix = relative2(parent, candidate);
|
|
1617
1658
|
return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
|
|
@@ -1622,17 +1663,18 @@ function movedPath(candidate, oldPath, newPath) {
|
|
|
1622
1663
|
}
|
|
1623
1664
|
|
|
1624
1665
|
class WorkspaceDocumentState {
|
|
1625
|
-
sendNotification;
|
|
1626
|
-
clearDiagnostics;
|
|
1627
|
-
openDocuments = new Map;
|
|
1628
|
-
openByUri = new Map;
|
|
1629
|
-
openPromises = new Map;
|
|
1630
|
-
now;
|
|
1631
|
-
versionlessPublishQuiescenceMs;
|
|
1632
1666
|
constructor(sendNotification, clearDiagnostics, options = {}) {
|
|
1633
1667
|
this.sendNotification = sendNotification;
|
|
1634
1668
|
this.clearDiagnostics = clearDiagnostics;
|
|
1635
|
-
this.
|
|
1669
|
+
this.openDocuments = new Map;
|
|
1670
|
+
this.openByUri = new Map;
|
|
1671
|
+
this.openPromises = new Map;
|
|
1672
|
+
this.timerProvider = options.timerProvider ?? {
|
|
1673
|
+
now: options.now ?? (() => Date.now()),
|
|
1674
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
1675
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
1676
|
+
};
|
|
1677
|
+
this.now = () => this.timerProvider.now();
|
|
1636
1678
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
1637
1679
|
}
|
|
1638
1680
|
async openFile(filePath) {
|
|
@@ -1654,7 +1696,7 @@ class WorkspaceDocumentState {
|
|
|
1654
1696
|
return this.openDocuments.get(canonicalPath(filePath))?.version;
|
|
1655
1697
|
}
|
|
1656
1698
|
getStoredDiagnostics(uri) {
|
|
1657
|
-
const state = this.openByUri.get(uri);
|
|
1699
|
+
const state = this.openByUri.get(normalizeDocumentUri(uri));
|
|
1658
1700
|
if (!state)
|
|
1659
1701
|
return [];
|
|
1660
1702
|
return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
|
|
@@ -1676,13 +1718,13 @@ class WorkspaceDocumentState {
|
|
|
1676
1718
|
return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
|
|
1677
1719
|
}
|
|
1678
1720
|
getPullCache(snapshot) {
|
|
1679
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1721
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1680
1722
|
if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
|
|
1681
1723
|
return null;
|
|
1682
1724
|
return state.pullCache;
|
|
1683
1725
|
}
|
|
1684
1726
|
recordPullDiagnostics(snapshot, report) {
|
|
1685
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1727
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1686
1728
|
if (!state)
|
|
1687
1729
|
return;
|
|
1688
1730
|
state.pullCache = {
|
|
@@ -1692,7 +1734,7 @@ class WorkspaceDocumentState {
|
|
|
1692
1734
|
};
|
|
1693
1735
|
}
|
|
1694
1736
|
recordPublishedDiagnostics(params) {
|
|
1695
|
-
const state = this.openByUri.get(params.uri);
|
|
1737
|
+
const state = this.openByUri.get(normalizeDocumentUri(params.uri));
|
|
1696
1738
|
if (!state)
|
|
1697
1739
|
return;
|
|
1698
1740
|
state.publishGeneration += 1;
|
|
@@ -1706,7 +1748,7 @@ class WorkspaceDocumentState {
|
|
|
1706
1748
|
this.notifyWaiters(state);
|
|
1707
1749
|
}
|
|
1708
1750
|
resolvePushDiagnostics(snapshot) {
|
|
1709
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1751
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1710
1752
|
if (!state?.lastPublish)
|
|
1711
1753
|
return { status: "missing" };
|
|
1712
1754
|
const publish = state.lastPublish;
|
|
@@ -1720,7 +1762,7 @@ class WorkspaceDocumentState {
|
|
|
1720
1762
|
return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
|
|
1721
1763
|
}
|
|
1722
1764
|
waitForDiagnosticsActivity(snapshot, timeoutMs) {
|
|
1723
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1765
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1724
1766
|
if (!state || timeoutMs <= 0)
|
|
1725
1767
|
return Promise.resolve();
|
|
1726
1768
|
return new Promise((resolveActivity) => {
|
|
@@ -1729,11 +1771,11 @@ class WorkspaceDocumentState {
|
|
|
1729
1771
|
if (settled)
|
|
1730
1772
|
return;
|
|
1731
1773
|
settled = true;
|
|
1732
|
-
clearTimeout(timer);
|
|
1774
|
+
this.timerProvider.clearTimeout(timer);
|
|
1733
1775
|
state.waiters.delete(finish);
|
|
1734
1776
|
resolveActivity();
|
|
1735
1777
|
};
|
|
1736
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
1778
|
+
const timer = this.timerProvider.setTimeout(finish, timeoutMs);
|
|
1737
1779
|
if (typeof timer.unref === "function")
|
|
1738
1780
|
timer.unref();
|
|
1739
1781
|
state.waiters.add(finish);
|
|
@@ -1841,7 +1883,7 @@ class WorkspaceDocumentState {
|
|
|
1841
1883
|
waiters: new Set
|
|
1842
1884
|
};
|
|
1843
1885
|
this.openDocuments.set(path, state);
|
|
1844
|
-
this.openByUri.set(state.uri, state);
|
|
1886
|
+
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
1845
1887
|
this.notifyWaiters(state);
|
|
1846
1888
|
await this.sendNotification("textDocument/didOpen", {
|
|
1847
1889
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
@@ -1866,7 +1908,7 @@ class WorkspaceDocumentState {
|
|
|
1866
1908
|
}
|
|
1867
1909
|
async closeDocument(state) {
|
|
1868
1910
|
this.openDocuments.delete(state.path);
|
|
1869
|
-
this.openByUri.delete(state.uri);
|
|
1911
|
+
this.openByUri.delete(normalizeDocumentUri(state.uri));
|
|
1870
1912
|
this.clearDiagnostics(state.uri);
|
|
1871
1913
|
this.notifyWaiters(state);
|
|
1872
1914
|
await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
|
|
@@ -1895,13 +1937,11 @@ import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3,
|
|
|
1895
1937
|
import { fileURLToPath } from "node:url";
|
|
1896
1938
|
|
|
1897
1939
|
class WorkspaceEditPathError extends Error {
|
|
1898
|
-
path;
|
|
1899
|
-
detail;
|
|
1900
|
-
name = "WorkspaceEditPathError";
|
|
1901
1940
|
constructor(path, detail) {
|
|
1902
1941
|
super(`${detail}: ${path}`);
|
|
1903
1942
|
this.path = path;
|
|
1904
1943
|
this.detail = detail;
|
|
1944
|
+
this.name = "WorkspaceEditPathError";
|
|
1905
1945
|
}
|
|
1906
1946
|
}
|
|
1907
1947
|
function isPathInsideWorkspace(filePath, workspaceRoot) {
|
|
@@ -2193,13 +2233,11 @@ function canonicalFingerprint(operations) {
|
|
|
2193
2233
|
|
|
2194
2234
|
// ../lsp-core/src/lsp/workspace-edit-types.ts
|
|
2195
2235
|
class WorkspaceEditValidationError extends Error {
|
|
2196
|
-
changeIndex;
|
|
2197
|
-
detail;
|
|
2198
|
-
name = "WorkspaceEditValidationError";
|
|
2199
2236
|
constructor(changeIndex, detail) {
|
|
2200
2237
|
super(`change ${changeIndex}: ${detail}`);
|
|
2201
2238
|
this.changeIndex = changeIndex;
|
|
2202
2239
|
this.detail = detail;
|
|
2240
|
+
this.name = "WorkspaceEditValidationError";
|
|
2203
2241
|
}
|
|
2204
2242
|
}
|
|
2205
2243
|
|
|
@@ -2697,10 +2735,9 @@ function simulateDelete(operation, virtual) {
|
|
|
2697
2735
|
import { existsSync as existsSync5, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
|
|
2698
2736
|
import { dirname as dirname4, resolve as resolve5 } from "node:path";
|
|
2699
2737
|
class WorkspaceSnapshotBuilder {
|
|
2700
|
-
workspaceRoot;
|
|
2701
|
-
snapshots = new Map;
|
|
2702
2738
|
constructor(workspaceRoot) {
|
|
2703
2739
|
this.workspaceRoot = workspaceRoot;
|
|
2740
|
+
this.snapshots = new Map;
|
|
2704
2741
|
}
|
|
2705
2742
|
build(operations) {
|
|
2706
2743
|
this.add(this.workspaceRoot, false);
|
|
@@ -2744,8 +2781,10 @@ function snapshotOperations(operations, workspaceRoot) {
|
|
|
2744
2781
|
|
|
2745
2782
|
// ../lsp-core/src/lsp/workspace-edit-plan.ts
|
|
2746
2783
|
class PlanPathIndex {
|
|
2747
|
-
|
|
2748
|
-
|
|
2784
|
+
constructor() {
|
|
2785
|
+
this.firstChangeByPath = new Map;
|
|
2786
|
+
this.reportedPathByCanonical = new Map;
|
|
2787
|
+
}
|
|
2749
2788
|
build(operations) {
|
|
2750
2789
|
for (const operation of operations) {
|
|
2751
2790
|
switch (operation.kind) {
|
|
@@ -2834,14 +2873,11 @@ function isRecord4(value) {
|
|
|
2834
2873
|
}
|
|
2835
2874
|
|
|
2836
2875
|
class WorkspaceMutationController {
|
|
2837
|
-
workspaceRoot;
|
|
2838
|
-
documents;
|
|
2839
|
-
activeLease = null;
|
|
2840
|
-
nextLeaseId = 1;
|
|
2841
|
-
io;
|
|
2842
2876
|
constructor(workspaceRoot, documents) {
|
|
2843
2877
|
this.workspaceRoot = workspaceRoot;
|
|
2844
2878
|
this.documents = documents;
|
|
2879
|
+
this.activeLease = null;
|
|
2880
|
+
this.nextLeaseId = 1;
|
|
2845
2881
|
}
|
|
2846
2882
|
setIo(io) {
|
|
2847
2883
|
this.io = io;
|
|
@@ -2954,14 +2990,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
2954
2990
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
2955
2991
|
|
|
2956
2992
|
class LspClient extends LspClientConnection {
|
|
2957
|
-
diagnosticPullErrors = [];
|
|
2958
|
-
documents;
|
|
2959
|
-
workspaceMutations;
|
|
2960
|
-
diagnosticsFreshnessTimeoutMs;
|
|
2961
2993
|
constructor(root, server2, options = {}) {
|
|
2962
2994
|
super(root, server2, options);
|
|
2995
|
+
this.diagnosticPullErrors = [];
|
|
2963
2996
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
2964
2997
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
2998
|
+
timerProvider: this.timerProvider,
|
|
2965
2999
|
versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
|
|
2966
3000
|
});
|
|
2967
3001
|
this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
|
|
@@ -3014,6 +3048,18 @@ class LspClient extends LspClientConnection {
|
|
|
3014
3048
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
3015
3049
|
}, options);
|
|
3016
3050
|
}
|
|
3051
|
+
async formatDocument(filePath, options, signal) {
|
|
3052
|
+
if (!this.isDocumentFormattingSupported())
|
|
3053
|
+
return null;
|
|
3054
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
3055
|
+
await this.openFile(absPath);
|
|
3056
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
3057
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
3058
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
3059
|
+
options
|
|
3060
|
+
}, requestOptions);
|
|
3061
|
+
return edits ?? [];
|
|
3062
|
+
}
|
|
3017
3063
|
async workspaceSymbols(query, signal) {
|
|
3018
3064
|
const options = signal === undefined ? {} : { signal };
|
|
3019
3065
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -3053,7 +3099,7 @@ class LspClient extends LspClientConnection {
|
|
|
3053
3099
|
const absPath = this.resolveWorkspacePath(filePath);
|
|
3054
3100
|
const uri = pathToFileURL3(absPath).href;
|
|
3055
3101
|
await this.openFile(absPath);
|
|
3056
|
-
const deadlineAt =
|
|
3102
|
+
const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
|
|
3057
3103
|
for (;; ) {
|
|
3058
3104
|
signal?.throwIfAborted();
|
|
3059
3105
|
const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
|
|
@@ -3066,7 +3112,7 @@ class LspClient extends LspClientConnection {
|
|
|
3066
3112
|
if (!pushFallbackOnly) {
|
|
3067
3113
|
const cached = this.documents.getPullCache(snapshot);
|
|
3068
3114
|
try {
|
|
3069
|
-
const remainingMs2 = deadlineAt -
|
|
3115
|
+
const remainingMs2 = deadlineAt - this.timerProvider.now();
|
|
3070
3116
|
if (remainingMs2 <= 0)
|
|
3071
3117
|
return this.freshnessTimeout(absPath);
|
|
3072
3118
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
@@ -3101,7 +3147,7 @@ class LspClient extends LspClientConnection {
|
|
|
3101
3147
|
}
|
|
3102
3148
|
if (!pushFallbackOnly)
|
|
3103
3149
|
continue;
|
|
3104
|
-
const remainingMs = deadlineAt -
|
|
3150
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3105
3151
|
if (remainingMs <= 0) {
|
|
3106
3152
|
if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
|
|
3107
3153
|
const cached = this.documents.getPullCache(snapshot);
|
|
@@ -3259,18 +3305,16 @@ function awaitWithSignal(promise, signal) {
|
|
|
3259
3305
|
}
|
|
3260
3306
|
|
|
3261
3307
|
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
3308
|
constructor(options = {}) {
|
|
3309
|
+
this.clients = new Map;
|
|
3310
|
+
this.pendingStops = new Map;
|
|
3311
|
+
this.respawnBudgets = new Map;
|
|
3312
|
+
this.reaperHandle = null;
|
|
3313
|
+
this.signalDisposer = null;
|
|
3314
|
+
this.disposed = false;
|
|
3272
3315
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
3273
3316
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3317
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3274
3318
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3275
3319
|
this.clientFactory = options.clientFactory ?? ((root, server2) => new LspClient(root, server2));
|
|
3276
3320
|
this.now = options.now ?? (() => Date.now());
|
|
@@ -3290,24 +3334,79 @@ class LspManager {
|
|
|
3290
3334
|
getKey(root, serverId) {
|
|
3291
3335
|
return `${root}::${serverId}`;
|
|
3292
3336
|
}
|
|
3337
|
+
tombstoneStop(key, client) {
|
|
3338
|
+
const stop = stopClientBestEffort(client);
|
|
3339
|
+
this.pendingStops.set(key, stop);
|
|
3340
|
+
stop.finally(() => {
|
|
3341
|
+
if (this.pendingStops.get(key) === stop) {
|
|
3342
|
+
this.pendingStops.delete(key);
|
|
3343
|
+
}
|
|
3344
|
+
});
|
|
3345
|
+
return stop;
|
|
3346
|
+
}
|
|
3347
|
+
recordDeadGeneration(key) {
|
|
3348
|
+
let budget = this.respawnBudgets.get(key);
|
|
3349
|
+
if (budget === undefined) {
|
|
3350
|
+
budget = { deadGenerations: 0, exhaustedAt: null };
|
|
3351
|
+
this.respawnBudgets.set(key, budget);
|
|
3352
|
+
}
|
|
3353
|
+
budget.deadGenerations += 1;
|
|
3354
|
+
}
|
|
3355
|
+
markHealthyGeneration(key) {
|
|
3356
|
+
this.respawnBudgets.delete(key);
|
|
3357
|
+
}
|
|
3358
|
+
ensureRespawnAllowed(key, root, serverId) {
|
|
3359
|
+
const budget = this.respawnBudgets.get(key);
|
|
3360
|
+
if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
|
|
3361
|
+
return;
|
|
3362
|
+
if (budget.exhaustedAt === null) {
|
|
3363
|
+
budget.exhaustedAt = this.now();
|
|
3364
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3365
|
+
}
|
|
3366
|
+
if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
|
|
3367
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3368
|
+
}
|
|
3369
|
+
budget.deadGenerations = 0;
|
|
3370
|
+
budget.exhaustedAt = null;
|
|
3371
|
+
}
|
|
3293
3372
|
reapStale() {
|
|
3294
3373
|
const t = this.now();
|
|
3295
3374
|
for (const [key, managed] of this.clients) {
|
|
3296
3375
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3297
|
-
stopClientBestEffort(managed.client);
|
|
3298
3376
|
this.clients.delete(key);
|
|
3377
|
+
this.tombstoneStop(key, managed.client);
|
|
3299
3378
|
continue;
|
|
3300
3379
|
}
|
|
3301
3380
|
if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
|
|
3302
|
-
stopClientBestEffort(managed.client);
|
|
3303
3381
|
this.clients.delete(key);
|
|
3382
|
+
this.tombstoneStop(key, managed.client);
|
|
3304
3383
|
}
|
|
3305
3384
|
}
|
|
3306
3385
|
}
|
|
3386
|
+
evictForAdmission() {
|
|
3387
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
3388
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
3389
|
+
if (!victim)
|
|
3390
|
+
return;
|
|
3391
|
+
this.clients.delete(victim.key);
|
|
3392
|
+
this.tombstoneStop(victim.key, victim.managed.client);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
leastRecentlyUsedIdleClient() {
|
|
3396
|
+
let candidate = null;
|
|
3397
|
+
for (const [key, managed] of this.clients) {
|
|
3398
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
3399
|
+
continue;
|
|
3400
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
3401
|
+
candidate = { key, managed };
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
return candidate;
|
|
3405
|
+
}
|
|
3307
3406
|
async tryDeleteIfOrphaned(key, managed) {
|
|
3308
3407
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
3309
3408
|
this.clients.delete(key);
|
|
3310
|
-
await
|
|
3409
|
+
await this.tombstoneStop(key, managed.client);
|
|
3311
3410
|
}
|
|
3312
3411
|
}
|
|
3313
3412
|
async getClient(root, server2, signal) {
|
|
@@ -3316,12 +3415,22 @@ class LspManager {
|
|
|
3316
3415
|
}
|
|
3317
3416
|
signal?.throwIfAborted();
|
|
3318
3417
|
const key = this.getKey(root, server2.id);
|
|
3418
|
+
for (;; ) {
|
|
3419
|
+
const pendingStop = this.pendingStops.get(key);
|
|
3420
|
+
if (pendingStop === undefined)
|
|
3421
|
+
break;
|
|
3422
|
+
await awaitWithSignal(pendingStop, signal);
|
|
3423
|
+
signal?.throwIfAborted();
|
|
3424
|
+
}
|
|
3425
|
+
if (this.disposed) {
|
|
3426
|
+
throw new Error("LspManager has been disposed");
|
|
3427
|
+
}
|
|
3319
3428
|
let managed = this.clients.get(key);
|
|
3320
3429
|
if (managed) {
|
|
3321
3430
|
const t = this.now();
|
|
3322
3431
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3323
|
-
await stopClientBestEffort(managed.client);
|
|
3324
3432
|
this.clients.delete(key);
|
|
3433
|
+
await this.tombstoneStop(key, managed.client);
|
|
3325
3434
|
managed = undefined;
|
|
3326
3435
|
}
|
|
3327
3436
|
}
|
|
@@ -3342,14 +3451,20 @@ class LspManager {
|
|
|
3342
3451
|
signal.throwIfAborted();
|
|
3343
3452
|
}
|
|
3344
3453
|
if (!managed.client.isAlive()) {
|
|
3345
|
-
|
|
3346
|
-
this.clients.
|
|
3454
|
+
this.recordDeadGeneration(key);
|
|
3455
|
+
if (this.clients.get(key) === managed) {
|
|
3456
|
+
this.clients.delete(key);
|
|
3457
|
+
}
|
|
3458
|
+
await this.tombstoneStop(key, managed.client);
|
|
3347
3459
|
return this.getClient(root, server2, signal);
|
|
3348
3460
|
}
|
|
3461
|
+
this.markHealthyGeneration(key);
|
|
3349
3462
|
managed.refCount++;
|
|
3350
3463
|
managed.lastUsedAt = this.now();
|
|
3351
3464
|
return managed.client;
|
|
3352
3465
|
}
|
|
3466
|
+
this.evictForAdmission();
|
|
3467
|
+
this.ensureRespawnAllowed(key, root, server2.id);
|
|
3353
3468
|
const client = this.clientFactory(root, server2);
|
|
3354
3469
|
const initStartedAt = this.now();
|
|
3355
3470
|
const initPromise = (async () => {
|
|
@@ -3373,7 +3488,7 @@ class LspManager {
|
|
|
3373
3488
|
if (this.clients.get(key) === newManaged) {
|
|
3374
3489
|
this.clients.delete(key);
|
|
3375
3490
|
}
|
|
3376
|
-
await
|
|
3491
|
+
await this.tombstoneStop(key, client);
|
|
3377
3492
|
throw err;
|
|
3378
3493
|
}
|
|
3379
3494
|
newManaged.pendingWaiters--;
|
|
@@ -3384,6 +3499,15 @@ class LspManager {
|
|
|
3384
3499
|
await this.tryDeleteIfOrphaned(key, newManaged);
|
|
3385
3500
|
signal.throwIfAborted();
|
|
3386
3501
|
}
|
|
3502
|
+
if (!client.isAlive()) {
|
|
3503
|
+
this.recordDeadGeneration(key);
|
|
3504
|
+
if (this.clients.get(key) === newManaged) {
|
|
3505
|
+
this.clients.delete(key);
|
|
3506
|
+
}
|
|
3507
|
+
await this.tombstoneStop(key, client);
|
|
3508
|
+
return this.getClient(root, server2, signal);
|
|
3509
|
+
}
|
|
3510
|
+
this.markHealthyGeneration(key);
|
|
3387
3511
|
newManaged.refCount++;
|
|
3388
3512
|
newManaged.lastUsedAt = this.now();
|
|
3389
3513
|
return client;
|
|
@@ -3404,14 +3528,20 @@ class LspManager {
|
|
|
3404
3528
|
if (client && managed.client !== client)
|
|
3405
3529
|
return;
|
|
3406
3530
|
this.clients.delete(key);
|
|
3407
|
-
|
|
3531
|
+
this.tombstoneStop(key, managed.client);
|
|
3408
3532
|
}
|
|
3409
3533
|
warmupClient(root, server2) {
|
|
3410
3534
|
if (this.disposed)
|
|
3411
3535
|
return;
|
|
3412
3536
|
const key = this.getKey(root, server2.id);
|
|
3413
|
-
if (this.clients.has(key))
|
|
3537
|
+
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
3414
3538
|
return;
|
|
3539
|
+
this.evictForAdmission();
|
|
3540
|
+
try {
|
|
3541
|
+
this.ensureRespawnAllowed(key, root, server2.id);
|
|
3542
|
+
} catch {
|
|
3543
|
+
return;
|
|
3544
|
+
}
|
|
3415
3545
|
const client = this.clientFactory(root, server2);
|
|
3416
3546
|
const initStartedAt = this.now();
|
|
3417
3547
|
const initPromise = (async () => {
|
|
@@ -3437,7 +3567,7 @@ class LspManager {
|
|
|
3437
3567
|
if (this.clients.get(key) === managed) {
|
|
3438
3568
|
this.clients.delete(key);
|
|
3439
3569
|
}
|
|
3440
|
-
|
|
3570
|
+
this.tombstoneStop(key, client);
|
|
3441
3571
|
});
|
|
3442
3572
|
}
|
|
3443
3573
|
isServerInitializing(root, serverId) {
|
|
@@ -3481,8 +3611,11 @@ class LspManager {
|
|
|
3481
3611
|
for (const managed of this.clients.values()) {
|
|
3482
3612
|
stopPromises.push(stopClientBestEffort(managed.client));
|
|
3483
3613
|
}
|
|
3614
|
+
const tombstonedStops = [...this.pendingStops.values()];
|
|
3484
3615
|
this.clients.clear();
|
|
3485
|
-
|
|
3616
|
+
this.respawnBudgets.clear();
|
|
3617
|
+
await Promise.allSettled([...stopPromises, ...tombstonedStops]);
|
|
3618
|
+
this.pendingStops.clear();
|
|
3486
3619
|
}
|
|
3487
3620
|
}
|
|
3488
3621
|
var _defaultInstance = null;
|
|
@@ -3500,57 +3633,52 @@ async function disposeDefaultLspManager() {
|
|
|
3500
3633
|
}
|
|
3501
3634
|
}
|
|
3502
3635
|
|
|
3503
|
-
// ../lsp-core/src/lsp/
|
|
3504
|
-
import { existsSync as existsSync6,
|
|
3505
|
-
import { dirname as dirname5 } from "node:path";
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3636
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
3637
|
+
import { existsSync as existsSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
3638
|
+
import { dirname as dirname5, join as join3 } from "node:path";
|
|
3639
|
+
|
|
3640
|
+
// ../lsp-core/src/lsp/workspace-markers.ts
|
|
3641
|
+
var GIT_WORKSPACE_MARKER = ".git";
|
|
3642
|
+
var PROJECT_WORKSPACE_MARKERS = [
|
|
3643
|
+
"package.json",
|
|
3644
|
+
"pyproject.toml",
|
|
3645
|
+
"Cargo.toml",
|
|
3646
|
+
"go.mod",
|
|
3647
|
+
"pom.xml",
|
|
3648
|
+
"build.gradle"
|
|
3649
|
+
];
|
|
3650
|
+
var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
|
|
3651
|
+
|
|
3652
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
3653
|
+
function findWorkspaceRootOutsideContext(directory) {
|
|
3654
|
+
const marked = nearestMarkedAncestor(directory);
|
|
3655
|
+
if (marked !== undefined)
|
|
3656
|
+
return marked;
|
|
3657
|
+
return realpathSync4(nearestExistingAncestor(directory));
|
|
3658
|
+
}
|
|
3659
|
+
function nearestMarkedAncestor(directory) {
|
|
3660
|
+
let current = directory;
|
|
3661
|
+
for (;; ) {
|
|
3662
|
+
if (existsSync6(current) && WORKSPACE_MARKERS.some((marker) => existsSync6(join3(current, marker)))) {
|
|
3663
|
+
return realpathSync4(current);
|
|
3664
|
+
}
|
|
3665
|
+
const parent = dirname5(current);
|
|
3666
|
+
if (parent === current)
|
|
3667
|
+
return;
|
|
3668
|
+
current = parent;
|
|
3518
3669
|
}
|
|
3519
3670
|
}
|
|
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);
|
|
3671
|
+
function nearestExistingAncestor(directory) {
|
|
3672
|
+
let current = directory;
|
|
3673
|
+
while (!existsSync6(current)) {
|
|
3674
|
+
const parent = dirname5(current);
|
|
3675
|
+
if (parent === current)
|
|
3676
|
+
return current;
|
|
3677
|
+
current = parent;
|
|
3678
|
+
}
|
|
3679
|
+
return current;
|
|
3549
3680
|
}
|
|
3550
3681
|
|
|
3551
|
-
// ../lsp-core/src/lsp/config-loader.ts
|
|
3552
|
-
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
|
|
3553
|
-
|
|
3554
3682
|
// ../lsp-core/src/lsp/server-definitions.ts
|
|
3555
3683
|
var LSP_INSTALL_HINTS = {
|
|
3556
3684
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -3596,6 +3724,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
3596
3724
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
3597
3725
|
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
3726
|
};
|
|
3727
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
3728
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
3729
|
+
vue: "bun add -d @vue/language-server",
|
|
3730
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
3731
|
+
oxlint: "bun add -d oxlint",
|
|
3732
|
+
biome: "bun add -d @biomejs/biome",
|
|
3733
|
+
svelte: "bun add -d svelte-language-server",
|
|
3734
|
+
astro: "bun add -d @astrojs/language-server",
|
|
3735
|
+
bash: "bun add -d bash-language-server",
|
|
3736
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
3737
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
3738
|
+
php: "bun add -d intelephense",
|
|
3739
|
+
prisma: "bun add -d prisma",
|
|
3740
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
3741
|
+
pyright: "uv add --dev pyright",
|
|
3742
|
+
basedpyright: "uv add --dev basedpyright",
|
|
3743
|
+
ruff: "uv add --dev ruff",
|
|
3744
|
+
ty: "uv add --dev ty",
|
|
3745
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
3746
|
+
};
|
|
3599
3747
|
var BUILTIN_SERVERS = {
|
|
3600
3748
|
typescript: {
|
|
3601
3749
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -3698,7 +3846,56 @@ var BUILTIN_SERVERS = {
|
|
|
3698
3846
|
}
|
|
3699
3847
|
};
|
|
3700
3848
|
|
|
3849
|
+
// ../lsp-core/src/lsp/server-install-state.ts
|
|
3850
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
3851
|
+
import { dirname as dirname6 } from "node:path";
|
|
3852
|
+
function getInstallDecisionsPath() {
|
|
3853
|
+
return lspRequestContext().installDecisionsPath;
|
|
3854
|
+
}
|
|
3855
|
+
function loadInstallDecisions() {
|
|
3856
|
+
const path = getInstallDecisionsPath();
|
|
3857
|
+
if (!existsSync7(path))
|
|
3858
|
+
return {};
|
|
3859
|
+
try {
|
|
3860
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
3861
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
3862
|
+
} catch {
|
|
3863
|
+
return {};
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
function loadInstallDecision(serverId) {
|
|
3867
|
+
return loadInstallDecisions()[serverId];
|
|
3868
|
+
}
|
|
3869
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
3870
|
+
const decisions = loadInstallDecisions();
|
|
3871
|
+
decisions[serverId] = { decision, decidedAt };
|
|
3872
|
+
writeInstallDecisions(decisions);
|
|
3873
|
+
}
|
|
3874
|
+
function isInstallDecision(value) {
|
|
3875
|
+
return value === "declined" || value === "allowed";
|
|
3876
|
+
}
|
|
3877
|
+
function writeInstallDecisions(decisions) {
|
|
3878
|
+
const path = getInstallDecisionsPath();
|
|
3879
|
+
mkdirSync(dirname6(path), { recursive: true });
|
|
3880
|
+
const tmpPath = `${path}.tmp`;
|
|
3881
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3882
|
+
`, "utf8");
|
|
3883
|
+
renameSync2(tmpPath, path);
|
|
3884
|
+
}
|
|
3885
|
+
function isInstallDecisions(value) {
|
|
3886
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3887
|
+
}
|
|
3888
|
+
function isInstallDecisionRecord(value) {
|
|
3889
|
+
if (!isRecord5(value))
|
|
3890
|
+
return false;
|
|
3891
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3892
|
+
}
|
|
3893
|
+
function isRecord5(value) {
|
|
3894
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3701
3897
|
// ../lsp-core/src/lsp/config-loader.ts
|
|
3898
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
|
|
3702
3899
|
function getProjectConfigPaths() {
|
|
3703
3900
|
return lspRequestContext().projectConfigPaths;
|
|
3704
3901
|
}
|
|
@@ -3706,7 +3903,7 @@ function getUserConfigPath() {
|
|
|
3706
3903
|
return lspRequestContext().userConfigPath;
|
|
3707
3904
|
}
|
|
3708
3905
|
function loadJsonFile(path) {
|
|
3709
|
-
if (!
|
|
3906
|
+
if (!existsSync8(path))
|
|
3710
3907
|
return null;
|
|
3711
3908
|
try {
|
|
3712
3909
|
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
@@ -3894,54 +4091,155 @@ function getDisabledServerIds() {
|
|
|
3894
4091
|
}
|
|
3895
4092
|
|
|
3896
4093
|
// ../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
|
-
|
|
4094
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
4095
|
+
import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
|
|
4096
|
+
var LOCAL_BIN_RULES = [
|
|
4097
|
+
{
|
|
4098
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
4099
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
4100
|
+
},
|
|
4101
|
+
{
|
|
4102
|
+
markers: [
|
|
4103
|
+
"pyproject.toml",
|
|
4104
|
+
"ty.toml",
|
|
4105
|
+
"requirements.txt",
|
|
4106
|
+
"setup.py",
|
|
4107
|
+
"setup.cfg",
|
|
4108
|
+
"Pipfile",
|
|
4109
|
+
"pyrightconfig.json",
|
|
4110
|
+
"ruff.toml",
|
|
4111
|
+
".ruff.toml"
|
|
4112
|
+
],
|
|
4113
|
+
binDirs: [
|
|
4114
|
+
join4(".venv", "bin"),
|
|
4115
|
+
join4(".venv", "Scripts"),
|
|
4116
|
+
join4("venv", "bin"),
|
|
4117
|
+
join4("venv", "Scripts"),
|
|
4118
|
+
join4(".env", "bin"),
|
|
4119
|
+
join4(".env", "Scripts")
|
|
4120
|
+
]
|
|
4121
|
+
},
|
|
4122
|
+
{
|
|
4123
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
4124
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
4125
|
+
},
|
|
4126
|
+
{
|
|
4127
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
4128
|
+
binDirs: ["bin"]
|
|
4129
|
+
}
|
|
4130
|
+
];
|
|
4131
|
+
var resolutionCache = new Map;
|
|
4132
|
+
var probeCount = 0;
|
|
4133
|
+
function probe(path) {
|
|
4134
|
+
probeCount += 1;
|
|
4135
|
+
return existsSync9(path);
|
|
4136
|
+
}
|
|
4137
|
+
function executableSuffixes(platform, pathExt) {
|
|
4138
|
+
if (platform !== "win32")
|
|
4139
|
+
return [""];
|
|
4140
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
4141
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
4142
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
4143
|
+
}
|
|
4144
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
4145
|
+
for (const suffix of suffixes) {
|
|
4146
|
+
const candidate = join4(directory, command + suffix);
|
|
4147
|
+
if (probe(candidate))
|
|
4148
|
+
return candidate;
|
|
3908
4149
|
}
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
4150
|
+
return null;
|
|
4151
|
+
}
|
|
4152
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
4153
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
4154
|
+
let current = resolve7(workingDirectory);
|
|
4155
|
+
while (true) {
|
|
4156
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
4157
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
4158
|
+
continue;
|
|
4159
|
+
for (const binDir of rule.binDirs) {
|
|
4160
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
4161
|
+
if (found !== null)
|
|
4162
|
+
return found;
|
|
4163
|
+
}
|
|
3918
4164
|
}
|
|
4165
|
+
if (probe(join4(current, ".git")))
|
|
4166
|
+
return null;
|
|
4167
|
+
if (boundary !== undefined && current === boundary)
|
|
4168
|
+
return null;
|
|
4169
|
+
const parent = dirname7(current);
|
|
4170
|
+
if (parent === current)
|
|
4171
|
+
return null;
|
|
4172
|
+
current = parent;
|
|
3919
4173
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
4174
|
+
}
|
|
4175
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
4176
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
4177
|
+
if (platform === "win32" && !pathEnv) {
|
|
3922
4178
|
pathEnv = process.env["Path"] ?? "";
|
|
3923
4179
|
}
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
}
|
|
4180
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
4181
|
+
if (entry.length === 0)
|
|
4182
|
+
continue;
|
|
4183
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
4184
|
+
if (found !== null)
|
|
4185
|
+
return found;
|
|
3931
4186
|
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
4187
|
+
return null;
|
|
4188
|
+
}
|
|
4189
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
4190
|
+
if (command.length === 0)
|
|
4191
|
+
return null;
|
|
4192
|
+
const [cmd] = command;
|
|
4193
|
+
if (cmd === undefined || cmd.length === 0)
|
|
4194
|
+
return null;
|
|
4195
|
+
const platform = options.platform ?? process.platform;
|
|
4196
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
4197
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
4198
|
+
const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
4199
|
+
return probe(explicit) ? explicit : null;
|
|
4200
|
+
}
|
|
4201
|
+
const cacheKey = JSON.stringify([
|
|
4202
|
+
workingDirectory ?? "",
|
|
4203
|
+
cmd,
|
|
4204
|
+
platform,
|
|
4205
|
+
options.stopAt ?? "",
|
|
4206
|
+
options.pathExt ?? "",
|
|
4207
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
4208
|
+
]);
|
|
4209
|
+
const cached = resolutionCache.get(cacheKey);
|
|
4210
|
+
if (cached !== undefined)
|
|
4211
|
+
return cached;
|
|
4212
|
+
let resolved = null;
|
|
4213
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
4214
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
4215
|
+
}
|
|
4216
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
4217
|
+
if (resolved === null && cmd === "node")
|
|
4218
|
+
resolved = cmd;
|
|
4219
|
+
resolutionCache.set(cacheKey, resolved);
|
|
4220
|
+
return resolved;
|
|
4221
|
+
}
|
|
4222
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
4223
|
+
if (command.length === 0)
|
|
4224
|
+
return false;
|
|
4225
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
3935
4226
|
}
|
|
3936
4227
|
|
|
3937
4228
|
// ../lsp-core/src/lsp/server-resolution.ts
|
|
4229
|
+
function withResolvedCommand(command, binaryPath) {
|
|
4230
|
+
return [binaryPath, ...command.slice(1)];
|
|
4231
|
+
}
|
|
3938
4232
|
function findServerForExtension(ext) {
|
|
3939
4233
|
const servers = getMergedServers();
|
|
4234
|
+
const workingDirectory = contextCwd();
|
|
3940
4235
|
for (const server2 of servers) {
|
|
3941
|
-
if (server2.extensions.includes(ext)
|
|
4236
|
+
if (!server2.extensions.includes(ext))
|
|
4237
|
+
continue;
|
|
4238
|
+
const binaryPath = resolveServerBinary(server2.command, workingDirectory);
|
|
4239
|
+
if (binaryPath !== null) {
|
|
3942
4240
|
const resolvedServer = {
|
|
3943
4241
|
id: server2.id,
|
|
3944
|
-
command: server2.command,
|
|
4242
|
+
command: withResolvedCommand(server2.command, binaryPath),
|
|
3945
4243
|
extensions: server2.extensions,
|
|
3946
4244
|
priority: server2.priority
|
|
3947
4245
|
};
|
|
@@ -3988,6 +4286,7 @@ function findServerForExtension(ext) {
|
|
|
3988
4286
|
function getAllServers() {
|
|
3989
4287
|
const servers = getMergedServers();
|
|
3990
4288
|
const disabled = getDisabledServerIds();
|
|
4289
|
+
const workingDirectory = contextCwd();
|
|
3991
4290
|
const result = [];
|
|
3992
4291
|
const seen = new Set;
|
|
3993
4292
|
for (const server2 of servers) {
|
|
@@ -3995,7 +4294,7 @@ function getAllServers() {
|
|
|
3995
4294
|
continue;
|
|
3996
4295
|
result.push({
|
|
3997
4296
|
id: server2.id,
|
|
3998
|
-
installed: isServerInstalled(server2.command),
|
|
4297
|
+
installed: isServerInstalled(server2.command, workingDirectory),
|
|
3999
4298
|
extensions: server2.extensions,
|
|
4000
4299
|
disabled: false,
|
|
4001
4300
|
source: server2.source,
|
|
@@ -4009,7 +4308,7 @@ function getAllServers() {
|
|
|
4009
4308
|
const builtin = BUILTIN_SERVERS[id];
|
|
4010
4309
|
result.push({
|
|
4011
4310
|
id,
|
|
4012
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
4311
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
4013
4312
|
extensions: builtin?.extensions ?? [],
|
|
4014
4313
|
disabled: true,
|
|
4015
4314
|
source: "disabled",
|
|
@@ -4020,7 +4319,6 @@ function getAllServers() {
|
|
|
4020
4319
|
}
|
|
4021
4320
|
|
|
4022
4321
|
// ../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
4322
|
function isDirectoryPath(filePath) {
|
|
4025
4323
|
try {
|
|
4026
4324
|
return statSync3(filePath).isDirectory();
|
|
@@ -4029,32 +4327,90 @@ function isDirectoryPath(filePath) {
|
|
|
4029
4327
|
}
|
|
4030
4328
|
}
|
|
4031
4329
|
function findWorkspaceRoot(filePath) {
|
|
4032
|
-
const
|
|
4330
|
+
const cwd = contextCwd();
|
|
4331
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4033
4332
|
let dir = abs;
|
|
4034
4333
|
if (!isDirectoryPath(dir)) {
|
|
4035
|
-
dir =
|
|
4036
|
-
}
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4334
|
+
dir = dirname8(dir);
|
|
4335
|
+
}
|
|
4336
|
+
if (!isPathInside(cwd, abs))
|
|
4337
|
+
return findWorkspaceRootOutsideContext(dir);
|
|
4338
|
+
const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
|
|
4339
|
+
let nearestPackageRoot;
|
|
4340
|
+
while (isPathInside(cwd, dir)) {
|
|
4341
|
+
const canonicalDir = existingDirectoryInsideContext(dir, cwd);
|
|
4342
|
+
if (canonicalDir !== undefined) {
|
|
4343
|
+
if (existsSync10(join5(dir, GIT_WORKSPACE_MARKER))) {
|
|
4344
|
+
return canonicalDir;
|
|
4345
|
+
}
|
|
4346
|
+
if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
|
|
4347
|
+
nearestPackageRoot = canonicalDir;
|
|
4042
4348
|
}
|
|
4043
4349
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4350
|
+
if (dir === cwd)
|
|
4351
|
+
break;
|
|
4352
|
+
dir = dirname8(dir);
|
|
4046
4353
|
}
|
|
4047
|
-
return
|
|
4354
|
+
return nearestPackageRoot ?? fallbackRoot;
|
|
4355
|
+
}
|
|
4356
|
+
function hasProjectWorkspaceMarker(directory) {
|
|
4357
|
+
return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync10(join5(directory, marker)));
|
|
4358
|
+
}
|
|
4359
|
+
function resolveReadablePathInsideContext(filePath) {
|
|
4360
|
+
const cwd = contextCwd();
|
|
4361
|
+
const abs = resolve8(cwd, filePath);
|
|
4362
|
+
if (isPathInside(cwd, abs))
|
|
4363
|
+
return abs;
|
|
4364
|
+
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
4365
|
+
if (rebased !== undefined)
|
|
4366
|
+
return rebased;
|
|
4367
|
+
return canonicalizeExistingOrNearestAncestor(abs);
|
|
4048
4368
|
}
|
|
4049
4369
|
function resolvePathInsideContext(filePath) {
|
|
4050
4370
|
const cwd = contextCwd();
|
|
4051
|
-
const abs =
|
|
4371
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4052
4372
|
const canonical = canonicalizeExistingOrNearestAncestor(abs);
|
|
4053
4373
|
if (!isPathInside(cwd, canonical)) {
|
|
4054
4374
|
throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
|
|
4055
4375
|
}
|
|
4056
4376
|
return canonical;
|
|
4057
4377
|
}
|
|
4378
|
+
function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
4379
|
+
let current = path;
|
|
4380
|
+
const suffix = [];
|
|
4381
|
+
while (true) {
|
|
4382
|
+
if (existsSync10(current)) {
|
|
4383
|
+
const canonical = realpathSync5(current);
|
|
4384
|
+
if (isPathInside(cwd, canonical))
|
|
4385
|
+
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
4386
|
+
}
|
|
4387
|
+
const parent = dirname8(current);
|
|
4388
|
+
if (parent === current)
|
|
4389
|
+
return;
|
|
4390
|
+
suffix.unshift(basename3(current));
|
|
4391
|
+
current = parent;
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
function existingDirectoryInsideContext(directory, cwd) {
|
|
4395
|
+
if (!existsSync10(directory))
|
|
4396
|
+
return;
|
|
4397
|
+
const canonical = realpathSync5(directory);
|
|
4398
|
+
if (!statSync3(canonical).isDirectory())
|
|
4399
|
+
return;
|
|
4400
|
+
return isPathInside(cwd, canonical) ? canonical : undefined;
|
|
4401
|
+
}
|
|
4402
|
+
function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
4403
|
+
let current = directory;
|
|
4404
|
+
while (isPathInside(cwd, current)) {
|
|
4405
|
+
const canonical = existingDirectoryInsideContext(current, cwd);
|
|
4406
|
+
if (canonical !== undefined)
|
|
4407
|
+
return canonical;
|
|
4408
|
+
if (current === cwd)
|
|
4409
|
+
return;
|
|
4410
|
+
current = dirname8(current);
|
|
4411
|
+
}
|
|
4412
|
+
return;
|
|
4413
|
+
}
|
|
4058
4414
|
function formatServerLookupError(result) {
|
|
4059
4415
|
if (result.status === "not_installed") {
|
|
4060
4416
|
return formatNotInstalled(result);
|
|
@@ -4078,6 +4434,19 @@ function formatServerLookupError(result) {
|
|
|
4078
4434
|
].join(`
|
|
4079
4435
|
`);
|
|
4080
4436
|
}
|
|
4437
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4438
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4439
|
+
if (localHint === undefined) {
|
|
4440
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4441
|
+
}
|
|
4442
|
+
return [
|
|
4443
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4444
|
+
` ${localHint}`,
|
|
4445
|
+
"",
|
|
4446
|
+
"Or install it globally:",
|
|
4447
|
+
` ${installHint}`
|
|
4448
|
+
];
|
|
4449
|
+
}
|
|
4081
4450
|
function formatNotInstalled(result) {
|
|
4082
4451
|
const { server: server2, installHint } = result;
|
|
4083
4452
|
const extensions = server2.extensions.join(", ");
|
|
@@ -4092,19 +4461,19 @@ function formatNotInstalled(result) {
|
|
|
4092
4461
|
`Command not found: ${server2.command[0]}`,
|
|
4093
4462
|
""
|
|
4094
4463
|
];
|
|
4464
|
+
const installOptions = formatInstallOptions(server2.id, installHint);
|
|
4095
4465
|
if (decision === "allowed") {
|
|
4096
4466
|
return [
|
|
4097
4467
|
...header,
|
|
4098
4468
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
4099
|
-
|
|
4469
|
+
...installOptions.slice(1)
|
|
4100
4470
|
].join(`
|
|
4101
4471
|
`);
|
|
4102
4472
|
}
|
|
4103
4473
|
if (!context.capabilities.installDecisionTool) {
|
|
4104
4474
|
return [
|
|
4105
4475
|
...header,
|
|
4106
|
-
|
|
4107
|
-
` ${installHint}`,
|
|
4476
|
+
...installOptions,
|
|
4108
4477
|
"",
|
|
4109
4478
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4110
4479
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -4113,8 +4482,7 @@ function formatNotInstalled(result) {
|
|
|
4113
4482
|
}
|
|
4114
4483
|
return [
|
|
4115
4484
|
...header,
|
|
4116
|
-
|
|
4117
|
-
` ${installHint}`,
|
|
4485
|
+
...installOptions,
|
|
4118
4486
|
"",
|
|
4119
4487
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4120
4488
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
@@ -4125,7 +4493,7 @@ function formatNotInstalled(result) {
|
|
|
4125
4493
|
].join(`
|
|
4126
4494
|
`);
|
|
4127
4495
|
}
|
|
4128
|
-
var
|
|
4496
|
+
var READ_ONLY_TOOLS = new Set([
|
|
4129
4497
|
"diagnostics",
|
|
4130
4498
|
"definition",
|
|
4131
4499
|
"references",
|
|
@@ -4134,7 +4502,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
|
|
|
4134
4502
|
"prepareRename"
|
|
4135
4503
|
]);
|
|
4136
4504
|
async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
4137
|
-
const absPath = resolvePathInsideContext(filePath);
|
|
4505
|
+
const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
|
|
4138
4506
|
if (isDirectoryPath(absPath)) {
|
|
4139
4507
|
throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
|
|
4140
4508
|
}
|
|
@@ -4149,9 +4517,9 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4149
4517
|
const acquireAndCall = async (allowRetry) => {
|
|
4150
4518
|
const client = await manager.getClient(root, server2, options.signal);
|
|
4151
4519
|
try {
|
|
4152
|
-
return await fn(client, root);
|
|
4520
|
+
return await fn(client, root, absPath);
|
|
4153
4521
|
} catch (err) {
|
|
4154
|
-
if (allowRetry &&
|
|
4522
|
+
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
4155
4523
|
manager.invalidateClient(root, server2.id, client);
|
|
4156
4524
|
return acquireAndCall(false);
|
|
4157
4525
|
}
|
|
@@ -4169,8 +4537,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4169
4537
|
}
|
|
4170
4538
|
|
|
4171
4539
|
// ../lsp-core/src/lsp/directory-diagnostics.ts
|
|
4172
|
-
import { existsSync as
|
|
4173
|
-
import { join as
|
|
4540
|
+
import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
|
|
4541
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
4174
4542
|
|
|
4175
4543
|
// ../lsp-core/src/lsp/formatters.ts
|
|
4176
4544
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -4300,7 +4668,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
4300
4668
|
for (const entry of entries) {
|
|
4301
4669
|
if (files.length >= maxFiles)
|
|
4302
4670
|
return;
|
|
4303
|
-
const fullPath =
|
|
4671
|
+
const fullPath = join6(currentDir, entry);
|
|
4304
4672
|
let stat;
|
|
4305
4673
|
try {
|
|
4306
4674
|
stat = lstatSync4(fullPath);
|
|
@@ -4325,8 +4693,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4325
4693
|
if (!extension.startsWith(".")) {
|
|
4326
4694
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
4327
4695
|
}
|
|
4328
|
-
const absDir =
|
|
4329
|
-
if (!
|
|
4696
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
4697
|
+
if (!existsSync11(absDir)) {
|
|
4330
4698
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
4331
4699
|
}
|
|
4332
4700
|
const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
|
|
@@ -4413,7 +4781,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4413
4781
|
|
|
4414
4782
|
// ../lsp-core/src/lsp/infer-extension.ts
|
|
4415
4783
|
import { lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
4416
|
-
import { join as
|
|
4784
|
+
import { join as join7 } from "node:path";
|
|
4417
4785
|
var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
4418
4786
|
var MAX_SCAN_ENTRIES = 500;
|
|
4419
4787
|
function inferExtensionFromDirectory(directory) {
|
|
@@ -4431,7 +4799,7 @@ function inferExtensionFromDirectory(directory) {
|
|
|
4431
4799
|
for (const entry of entries) {
|
|
4432
4800
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
4433
4801
|
return;
|
|
4434
|
-
const fullPath =
|
|
4802
|
+
const fullPath = join7(dir, entry);
|
|
4435
4803
|
let stat;
|
|
4436
4804
|
try {
|
|
4437
4805
|
stat = lstatSync5(fullPath);
|
|
@@ -4606,7 +4974,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4606
4974
|
const filePath = requireString(params, "filePath");
|
|
4607
4975
|
const severity = severityFilter(params);
|
|
4608
4976
|
try {
|
|
4609
|
-
const absPath =
|
|
4977
|
+
const absPath = resolveReadablePathInsideContext(filePath);
|
|
4610
4978
|
if (isDirectoryPath(absPath)) {
|
|
4611
4979
|
const extension = inferExtensionFromDirectory(absPath);
|
|
4612
4980
|
if (!extension) {
|
|
@@ -4635,7 +5003,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4635
5003
|
};
|
|
4636
5004
|
return text(output2.output, details2);
|
|
4637
5005
|
}
|
|
4638
|
-
const result = await withLspClient(filePath, async (client) => client.diagnostics(
|
|
5006
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
4639
5007
|
if (result.transientError) {
|
|
4640
5008
|
const message = result.transientError.message;
|
|
4641
5009
|
const details2 = {
|
|
@@ -4682,6 +5050,96 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4682
5050
|
throw error;
|
|
4683
5051
|
}
|
|
4684
5052
|
}
|
|
5053
|
+
// ../lsp-core/src/lsp/format-document.ts
|
|
5054
|
+
import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5055
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
5056
|
+
tabSize: 4,
|
|
5057
|
+
insertSpaces: false,
|
|
5058
|
+
trimTrailingWhitespace: true,
|
|
5059
|
+
insertFinalNewline: true,
|
|
5060
|
+
trimFinalNewlines: true
|
|
5061
|
+
};
|
|
5062
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
5063
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
5064
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
5065
|
+
if (edits === null)
|
|
5066
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
5067
|
+
if (edits.length === 0)
|
|
5068
|
+
return UNCHANGED;
|
|
5069
|
+
const before = readFileSync5(filePath, "utf-8");
|
|
5070
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
5071
|
+
if (normalized.text === before)
|
|
5072
|
+
return UNCHANGED;
|
|
5073
|
+
writeAtomically(filePath, normalized.text);
|
|
5074
|
+
await client.openFile(filePath);
|
|
5075
|
+
return {
|
|
5076
|
+
status: "formatted",
|
|
5077
|
+
...lineDelta(normalized.edits)
|
|
5078
|
+
};
|
|
5079
|
+
}
|
|
5080
|
+
function lineDelta(edits) {
|
|
5081
|
+
let linesAdded = 0;
|
|
5082
|
+
let linesRemoved = 0;
|
|
5083
|
+
for (const edit of edits) {
|
|
5084
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
5085
|
+
linesAdded += edit.newText.split(`
|
|
5086
|
+
`).length;
|
|
5087
|
+
}
|
|
5088
|
+
return { linesAdded, linesRemoved };
|
|
5089
|
+
}
|
|
5090
|
+
function writeAtomically(filePath, content) {
|
|
5091
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
5092
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
5093
|
+
try {
|
|
5094
|
+
renameSync3(tempPath, filePath);
|
|
5095
|
+
} catch (error) {
|
|
5096
|
+
try {
|
|
5097
|
+
unlinkSync(tempPath);
|
|
5098
|
+
} catch {}
|
|
5099
|
+
throw error;
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5103
|
+
// ../lsp-core/src/tools/format.ts
|
|
5104
|
+
async function executeLspFormat(params, signal) {
|
|
5105
|
+
const filePath = requireString(params, "filePath");
|
|
5106
|
+
try {
|
|
5107
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
5108
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
5109
|
+
} catch (error) {
|
|
5110
|
+
const missingDependency = missingDependencyResult(error, {
|
|
5111
|
+
filePath,
|
|
5112
|
+
status: "unavailable",
|
|
5113
|
+
reason: "server_unavailable",
|
|
5114
|
+
linesAdded: 0,
|
|
5115
|
+
linesRemoved: 0
|
|
5116
|
+
});
|
|
5117
|
+
if (missingDependency)
|
|
5118
|
+
return missingDependency;
|
|
5119
|
+
throw error;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
function formatDetails(filePath, result) {
|
|
5123
|
+
if (result.status === "unavailable") {
|
|
5124
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
5125
|
+
}
|
|
5126
|
+
return {
|
|
5127
|
+
filePath,
|
|
5128
|
+
status: result.status,
|
|
5129
|
+
linesAdded: result.linesAdded,
|
|
5130
|
+
linesRemoved: result.linesRemoved
|
|
5131
|
+
};
|
|
5132
|
+
}
|
|
5133
|
+
function describeResult(filePath, result) {
|
|
5134
|
+
if (result.status === "unavailable") {
|
|
5135
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
5136
|
+
}
|
|
5137
|
+
if (result.status === "unchanged") {
|
|
5138
|
+
return `Already formatted: ${filePath}`;
|
|
5139
|
+
}
|
|
5140
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
5141
|
+
}
|
|
5142
|
+
|
|
4685
5143
|
// ../lsp-core/src/tools/install-decision.ts
|
|
4686
5144
|
async function executeLspInstallDecision(params) {
|
|
4687
5145
|
const serverId = requireString(params, "server_id");
|
|
@@ -4710,7 +5168,7 @@ async function executeLspGotoDefinition(params, signal) {
|
|
|
4710
5168
|
const line = requireNumber(params, "line");
|
|
4711
5169
|
const character = requireNumber(params, "character");
|
|
4712
5170
|
try {
|
|
4713
|
-
const result = await withLspClient(filePath, async (client) => client.definition(
|
|
5171
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
|
|
4714
5172
|
const locations = !result ? [] : Array.isArray(result) ? result : [result];
|
|
4715
5173
|
const details = { filePath, line, character, locations };
|
|
4716
5174
|
if (locations.length === 0)
|
|
@@ -4735,7 +5193,7 @@ async function executeLspFindReferences(params, signal) {
|
|
|
4735
5193
|
const character = requireNumber(params, "character");
|
|
4736
5194
|
const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
|
|
4737
5195
|
try {
|
|
4738
|
-
const result = await withLspClient(filePath, async (client) => client.references(
|
|
5196
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
|
|
4739
5197
|
const references = Array.isArray(result) ? result : [];
|
|
4740
5198
|
const total = references.length;
|
|
4741
5199
|
const truncated = total > DEFAULT_MAX_REFERENCES;
|
|
@@ -4777,7 +5235,7 @@ async function executeLspPrepareRename(params, signal) {
|
|
|
4777
5235
|
const line = requireNumber(params, "line");
|
|
4778
5236
|
const character = requireNumber(params, "character");
|
|
4779
5237
|
try {
|
|
4780
|
-
const result = await withLspClient(filePath, async (client) => client.prepareRename(
|
|
5238
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
|
|
4781
5239
|
const details = { filePath, line, character, result };
|
|
4782
5240
|
return text(formatPrepareRenameResult(result), details);
|
|
4783
5241
|
} catch (error) {
|
|
@@ -4798,7 +5256,7 @@ async function executeLspRename(params, signal) {
|
|
|
4798
5256
|
const character = requireNumber(params, "character");
|
|
4799
5257
|
const newName = requireString(params, "newName");
|
|
4800
5258
|
try {
|
|
4801
|
-
const result = await withLspClient(filePath, async (client) => client.rename(
|
|
5259
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
|
|
4802
5260
|
const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
|
|
4803
5261
|
return text(formatApplyResult(result.apply), details, !result.apply.success);
|
|
4804
5262
|
} catch (error) {
|
|
@@ -4878,7 +5336,7 @@ async function executeLspSymbols(params, signal) {
|
|
|
4878
5336
|
const symbols2 = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
4879
5337
|
return formatSymbolsResult(filePath, scope, symbols2, limit, query);
|
|
4880
5338
|
}
|
|
4881
|
-
const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(
|
|
5339
|
+
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
4882
5340
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
4883
5341
|
} catch (error) {
|
|
4884
5342
|
const query = optionalString(params, "query");
|
|
@@ -5014,6 +5472,16 @@ var LSP_MCP_TOOLS = [
|
|
|
5014
5472
|
}, ["filePath", "line", "character", "newName"]),
|
|
5015
5473
|
execute: executeLspRename
|
|
5016
5474
|
},
|
|
5475
|
+
{
|
|
5476
|
+
name: "format",
|
|
5477
|
+
aliases: ["lsp_format"],
|
|
5478
|
+
title: "LSP Format",
|
|
5479
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
5480
|
+
inputSchema: objectSchema({
|
|
5481
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
5482
|
+
}, ["filePath"]),
|
|
5483
|
+
execute: executeLspFormat
|
|
5484
|
+
},
|
|
5017
5485
|
{
|
|
5018
5486
|
name: "install_decision",
|
|
5019
5487
|
aliases: ["lsp_install_decision"],
|
|
@@ -5113,11 +5581,10 @@ function requestedProtocolVersion(params) {
|
|
|
5113
5581
|
// src/daemon-client.ts
|
|
5114
5582
|
import { connect } from "node:net";
|
|
5115
5583
|
import { homedir as homedir3 } from "node:os";
|
|
5116
|
-
import { join as
|
|
5584
|
+
import { join as join8 } from "node:path";
|
|
5117
5585
|
|
|
5118
5586
|
// src/daemon-request-error.ts
|
|
5119
5587
|
class DaemonRequestError extends Error {
|
|
5120
|
-
requestWritten;
|
|
5121
5588
|
constructor(message, requestWritten) {
|
|
5122
5589
|
super(message);
|
|
5123
5590
|
this.name = "DaemonRequestError";
|
|
@@ -5140,7 +5607,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
|
|
|
5140
5607
|
}
|
|
5141
5608
|
|
|
5142
5609
|
class DaemonRequestTimedOutError extends DaemonRequestError {
|
|
5143
|
-
timeoutMs;
|
|
5144
5610
|
constructor(requestWritten, timeoutMs) {
|
|
5145
5611
|
super("daemon request timed out", requestWritten);
|
|
5146
5612
|
this.name = "DaemonRequestTimedOutError";
|
|
@@ -5192,9 +5658,9 @@ function errorText(error) {
|
|
|
5192
5658
|
|
|
5193
5659
|
// src/ensure-daemon.ts
|
|
5194
5660
|
import { spawn as spawn2 } from "node:child_process";
|
|
5195
|
-
import { closeSync as closeSync2, existsSync as
|
|
5661
|
+
import { closeSync as closeSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
|
|
5196
5662
|
import { Socket } from "node:net";
|
|
5197
|
-
import { dirname as
|
|
5663
|
+
import { dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
|
|
5198
5664
|
import { argv0, execPath } from "node:process";
|
|
5199
5665
|
|
|
5200
5666
|
// src/ipc-protocol.ts
|
|
@@ -5208,25 +5674,23 @@ import {
|
|
|
5208
5674
|
lstatSync as lstatSync6,
|
|
5209
5675
|
mkdirSync as mkdirSync2,
|
|
5210
5676
|
openSync,
|
|
5211
|
-
readFileSync as
|
|
5212
|
-
unlinkSync,
|
|
5677
|
+
readFileSync as readFileSync6,
|
|
5678
|
+
unlinkSync as unlinkSync2,
|
|
5213
5679
|
writeSync
|
|
5214
5680
|
} from "node:fs";
|
|
5215
|
-
import { dirname as
|
|
5681
|
+
import { dirname as dirname9 } from "node:path";
|
|
5216
5682
|
var OMO_DAEMON_PROTOCOL_VERSION = 1;
|
|
5217
5683
|
var AUTH_ERROR_CODE = -32001;
|
|
5218
5684
|
var PROTOCOL_ERROR_CODE = -32002;
|
|
5219
5685
|
var AUTH_TOKEN_BYTES = 32;
|
|
5220
5686
|
|
|
5221
5687
|
class UnsafePrivateDirectoryError extends Error {
|
|
5222
|
-
path;
|
|
5223
|
-
reason;
|
|
5224
|
-
name = "UnsafePrivateDirectoryError";
|
|
5225
|
-
code = "unsafe_private_directory";
|
|
5226
5688
|
constructor(path, reason) {
|
|
5227
5689
|
super(`unsafe private directory ${path}: ${reason}`);
|
|
5228
5690
|
this.path = path;
|
|
5229
5691
|
this.reason = reason;
|
|
5692
|
+
this.name = "UnsafePrivateDirectoryError";
|
|
5693
|
+
this.code = "unsafe_private_directory";
|
|
5230
5694
|
}
|
|
5231
5695
|
}
|
|
5232
5696
|
function authEnvelope(token) {
|
|
@@ -5234,7 +5698,7 @@ function authEnvelope(token) {
|
|
|
5234
5698
|
}
|
|
5235
5699
|
function readAuthToken(paths) {
|
|
5236
5700
|
try {
|
|
5237
|
-
const token =
|
|
5701
|
+
const token = readFileSync6(paths.auth, "utf8").trim();
|
|
5238
5702
|
return token.length > 0 ? token : null;
|
|
5239
5703
|
} catch (error) {
|
|
5240
5704
|
if (error instanceof Error)
|
|
@@ -5250,7 +5714,7 @@ function readOrCreateAuthToken(paths) {
|
|
|
5250
5714
|
}
|
|
5251
5715
|
function rotateAuthToken(paths) {
|
|
5252
5716
|
try {
|
|
5253
|
-
|
|
5717
|
+
unlinkSync2(paths.auth);
|
|
5254
5718
|
} catch (error) {
|
|
5255
5719
|
if (!(error instanceof Error))
|
|
5256
5720
|
throw error;
|
|
@@ -5322,7 +5786,7 @@ function setPrivateFileMode(path) {
|
|
|
5322
5786
|
chmodSync(path, 384);
|
|
5323
5787
|
}
|
|
5324
5788
|
function createAuthToken(paths) {
|
|
5325
|
-
ensurePrivateDirectory(
|
|
5789
|
+
ensurePrivateDirectory(dirname9(paths.auth));
|
|
5326
5790
|
const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
|
|
5327
5791
|
let fd;
|
|
5328
5792
|
try {
|
|
@@ -5403,27 +5867,25 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
5403
5867
|
|
|
5404
5868
|
// src/runtime-contract.ts
|
|
5405
5869
|
import { statSync as statSync4 } from "node:fs";
|
|
5406
|
-
import { isAbsolute as
|
|
5870
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
5407
5871
|
var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
|
|
5408
5872
|
var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
|
|
5409
5873
|
var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
5410
5874
|
var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
5411
5875
|
|
|
5412
5876
|
class InvalidRuntimeOverrideError extends Error {
|
|
5413
|
-
code = "invalid_runtime_override";
|
|
5414
|
-
reason;
|
|
5415
5877
|
constructor(reason, message) {
|
|
5416
5878
|
super(message);
|
|
5879
|
+
this.code = "invalid_runtime_override";
|
|
5417
5880
|
this.name = "InvalidRuntimeOverrideError";
|
|
5418
5881
|
this.reason = reason;
|
|
5419
5882
|
}
|
|
5420
5883
|
}
|
|
5421
5884
|
|
|
5422
5885
|
class InvalidDaemonVersionError extends Error {
|
|
5423
|
-
code = "invalid_daemon_version";
|
|
5424
|
-
version;
|
|
5425
5886
|
constructor(version) {
|
|
5426
5887
|
super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
|
|
5888
|
+
this.code = "invalid_daemon_version";
|
|
5427
5889
|
this.name = "InvalidDaemonVersionError";
|
|
5428
5890
|
this.version = version;
|
|
5429
5891
|
}
|
|
@@ -5442,12 +5904,12 @@ function resolveDaemonRuntime(env, defaults) {
|
|
|
5442
5904
|
throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
|
|
5443
5905
|
}
|
|
5444
5906
|
if (!hasCliOverride || !hasVersionOverride) {
|
|
5445
|
-
if (!
|
|
5907
|
+
if (!isAbsolute4(defaults.cliPath)) {
|
|
5446
5908
|
throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
|
|
5447
5909
|
}
|
|
5448
5910
|
return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
|
|
5449
5911
|
}
|
|
5450
|
-
if (!
|
|
5912
|
+
if (!isAbsolute4(cliOverride)) {
|
|
5451
5913
|
throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
|
|
5452
5914
|
}
|
|
5453
5915
|
let cliStats;
|
|
@@ -5469,10 +5931,9 @@ var requireFromHere = createRequire(import.meta.url);
|
|
|
5469
5931
|
var MAX_SOCKET_PATH_LENGTH = 100;
|
|
5470
5932
|
|
|
5471
5933
|
class InvalidDaemonDirectoryError extends Error {
|
|
5472
|
-
code = "invalid_daemon_directory";
|
|
5473
|
-
directory;
|
|
5474
5934
|
constructor(directory) {
|
|
5475
5935
|
super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
|
|
5936
|
+
this.code = "invalid_daemon_directory";
|
|
5476
5937
|
this.name = "InvalidDaemonDirectoryError";
|
|
5477
5938
|
this.directory = directory;
|
|
5478
5939
|
}
|
|
@@ -5626,7 +6087,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5626
6087
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
5627
6088
|
}
|
|
5628
6089
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
5629
|
-
return new Promise((
|
|
6090
|
+
return new Promise((resolve10) => {
|
|
5630
6091
|
const socket = new Socket;
|
|
5631
6092
|
let settled = false;
|
|
5632
6093
|
let timer;
|
|
@@ -5638,7 +6099,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5638
6099
|
clearTimeout(timer);
|
|
5639
6100
|
signal?.removeEventListener("abort", onAbort);
|
|
5640
6101
|
socket.destroy();
|
|
5641
|
-
|
|
6102
|
+
resolve10(value);
|
|
5642
6103
|
};
|
|
5643
6104
|
const onAbort = () => finish(null);
|
|
5644
6105
|
const decoder = createLineDecoder((message) => {
|
|
@@ -5662,12 +6123,13 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5662
6123
|
});
|
|
5663
6124
|
}
|
|
5664
6125
|
function spawnDaemonProcess(paths) {
|
|
5665
|
-
mkdirSync3(
|
|
6126
|
+
mkdirSync3(dirname10(paths.log), { recursive: true });
|
|
5666
6127
|
const logFd = openSync2(paths.log, "a");
|
|
5667
6128
|
try {
|
|
5668
6129
|
const child = spawn2(resolveDaemonNodeExecutable(), [paths.cliPath, "daemon"], {
|
|
5669
6130
|
detached: true,
|
|
5670
|
-
stdio: ["ignore", logFd, logFd]
|
|
6131
|
+
stdio: ["ignore", logFd, logFd],
|
|
6132
|
+
windowsHide: true
|
|
5671
6133
|
});
|
|
5672
6134
|
child.once("spawn", () => closeSync2(logFd));
|
|
5673
6135
|
child.once("error", (error) => {
|
|
@@ -5681,10 +6143,10 @@ function spawnDaemonProcess(paths) {
|
|
|
5681
6143
|
throw error;
|
|
5682
6144
|
}
|
|
5683
6145
|
}
|
|
5684
|
-
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists =
|
|
6146
|
+
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync12) {
|
|
5685
6147
|
if (pathExists(cachedExecPath))
|
|
5686
6148
|
return cachedExecPath;
|
|
5687
|
-
if (
|
|
6149
|
+
if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
|
|
5688
6150
|
return originalArgv0;
|
|
5689
6151
|
return "node";
|
|
5690
6152
|
}
|
|
@@ -5697,7 +6159,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
5697
6159
|
};
|
|
5698
6160
|
}
|
|
5699
6161
|
function sleepWithSignal(ms, signal) {
|
|
5700
|
-
return new Promise((
|
|
6162
|
+
return new Promise((resolve10) => {
|
|
5701
6163
|
let settled = false;
|
|
5702
6164
|
const finish = () => {
|
|
5703
6165
|
if (settled)
|
|
@@ -5705,7 +6167,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
5705
6167
|
settled = true;
|
|
5706
6168
|
clearTimeout(timer);
|
|
5707
6169
|
signal?.removeEventListener("abort", finish);
|
|
5708
|
-
|
|
6170
|
+
resolve10();
|
|
5709
6171
|
};
|
|
5710
6172
|
const timer = setTimeout(finish, ms);
|
|
5711
6173
|
if (signal?.aborted) {
|
|
@@ -5720,7 +6182,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5720
6182
|
return promise;
|
|
5721
6183
|
if (signal.aborted)
|
|
5722
6184
|
return Promise.reject(abortError3(signal));
|
|
5723
|
-
return new Promise((
|
|
6185
|
+
return new Promise((resolve10, reject) => {
|
|
5724
6186
|
let settled = false;
|
|
5725
6187
|
const finish = (run) => {
|
|
5726
6188
|
if (settled)
|
|
@@ -5731,7 +6193,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5731
6193
|
};
|
|
5732
6194
|
const onAbort = () => finish(() => reject(abortError3(signal)));
|
|
5733
6195
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5734
|
-
promise.then((value) => finish(() =>
|
|
6196
|
+
promise.then((value) => finish(() => resolve10(value)), (error) => finish(() => reject(error)));
|
|
5735
6197
|
});
|
|
5736
6198
|
}
|
|
5737
6199
|
function throwIfAborted(signal) {
|
|
@@ -5780,7 +6242,10 @@ function parsePingResponse(message) {
|
|
|
5780
6242
|
var CONTEXT_KEY = "_context";
|
|
5781
6243
|
|
|
5782
6244
|
class InvalidDaemonRequestError extends Error {
|
|
5783
|
-
|
|
6245
|
+
constructor() {
|
|
6246
|
+
super(...arguments);
|
|
6247
|
+
this.name = "InvalidDaemonRequestError";
|
|
6248
|
+
}
|
|
5784
6249
|
}
|
|
5785
6250
|
function extractRequestContext(raw) {
|
|
5786
6251
|
if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
|
|
@@ -5896,14 +6361,17 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5896
6361
|
function callDiagnosticsViaDaemon(filePath, options) {
|
|
5897
6362
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
5898
6363
|
}
|
|
6364
|
+
function callFormatViaDaemon(filePath, options) {
|
|
6365
|
+
return callToolViaDaemon("format", { filePath }, options);
|
|
6366
|
+
}
|
|
5899
6367
|
function currentRequestContext(env = process.env) {
|
|
5900
6368
|
const cwd = process.cwd();
|
|
5901
6369
|
const home = env["HOME"] ?? homedir3();
|
|
5902
6370
|
return parseLspRequestContext({
|
|
5903
6371
|
cwd,
|
|
5904
|
-
projectConfigPaths: [
|
|
5905
|
-
userConfigPath:
|
|
5906
|
-
installDecisionsPath:
|
|
6372
|
+
projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
|
|
6373
|
+
userConfigPath: join8(home, ".codex", "lsp-client.json"),
|
|
6374
|
+
installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
|
|
5907
6375
|
capabilities: { installDecisionTool: true }
|
|
5908
6376
|
});
|
|
5909
6377
|
}
|
|
@@ -5918,7 +6386,7 @@ function withContext(args, context) {
|
|
|
5918
6386
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5919
6387
|
if (!signal)
|
|
5920
6388
|
return ensure(paths);
|
|
5921
|
-
return new Promise((
|
|
6389
|
+
return new Promise((resolve10, reject) => {
|
|
5922
6390
|
let settled = false;
|
|
5923
6391
|
const finish = (run) => {
|
|
5924
6392
|
if (settled)
|
|
@@ -5933,11 +6401,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5933
6401
|
return;
|
|
5934
6402
|
}
|
|
5935
6403
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5936
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
6404
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5937
6405
|
});
|
|
5938
6406
|
}
|
|
5939
6407
|
function sendToolCall(paths, token, name, args, options) {
|
|
5940
|
-
return new Promise((
|
|
6408
|
+
return new Promise((resolve10, reject) => {
|
|
5941
6409
|
const socket = connect(paths.socket);
|
|
5942
6410
|
const requestId = allocateProxyRequestId();
|
|
5943
6411
|
let settled = false;
|
|
@@ -5990,7 +6458,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
5990
6458
|
}
|
|
5991
6459
|
const result = toToolResult(message, requestId);
|
|
5992
6460
|
if (result)
|
|
5993
|
-
finish(() =>
|
|
6461
|
+
finish(() => resolve10(result));
|
|
5994
6462
|
else
|
|
5995
6463
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
5996
6464
|
});
|
|
@@ -6158,18 +6626,18 @@ function canonicalizePathList(value) {
|
|
|
6158
6626
|
return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
|
|
6159
6627
|
}
|
|
6160
6628
|
function canonicalizePath(value) {
|
|
6161
|
-
if (value === undefined || !
|
|
6629
|
+
if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
|
|
6162
6630
|
return value;
|
|
6163
|
-
return
|
|
6631
|
+
return realpathSync6(value);
|
|
6164
6632
|
}
|
|
6165
6633
|
function projectRootFromOpenCodeConfigPath(path2) {
|
|
6166
|
-
if (
|
|
6634
|
+
if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
|
|
6167
6635
|
return;
|
|
6168
|
-
const configDir =
|
|
6169
|
-
const configDirName =
|
|
6636
|
+
const configDir = dirname11(path2);
|
|
6637
|
+
const configDirName = basename4(configDir);
|
|
6170
6638
|
if (configDirName !== ".opencode" && configDirName !== ".omo")
|
|
6171
6639
|
return;
|
|
6172
|
-
return
|
|
6640
|
+
return dirname11(configDir);
|
|
6173
6641
|
}
|
|
6174
6642
|
|
|
6175
6643
|
// src/daemon-server.ts
|
|
@@ -6178,12 +6646,12 @@ import { createServer as createServer2 } from "node:net";
|
|
|
6178
6646
|
|
|
6179
6647
|
// src/ownership.ts
|
|
6180
6648
|
import { randomUUID } from "node:crypto";
|
|
6181
|
-
import { existsSync as
|
|
6182
|
-
import { dirname as
|
|
6649
|
+
import { existsSync as existsSync14, lstatSync as lstatSync7, readFileSync as readFileSync8, statSync as statSync5, unlinkSync as unlinkSync4 } from "node:fs";
|
|
6650
|
+
import { dirname as dirname13 } from "node:path";
|
|
6183
6651
|
|
|
6184
6652
|
// src/lock.ts
|
|
6185
|
-
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as
|
|
6186
|
-
import { dirname as
|
|
6653
|
+
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "node:fs";
|
|
6654
|
+
import { dirname as dirname12 } from "node:path";
|
|
6187
6655
|
function isProcessAlive2(pid) {
|
|
6188
6656
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
6189
6657
|
return false;
|
|
@@ -6198,14 +6666,14 @@ function isProcessAlive2(pid) {
|
|
|
6198
6666
|
}
|
|
6199
6667
|
function readLockPid(lockPath) {
|
|
6200
6668
|
try {
|
|
6201
|
-
const pid = Number.parseInt(
|
|
6669
|
+
const pid = Number.parseInt(readFileSync7(lockPath, "utf8").trim(), 10);
|
|
6202
6670
|
return Number.isInteger(pid) ? pid : null;
|
|
6203
6671
|
} catch {
|
|
6204
6672
|
return null;
|
|
6205
6673
|
}
|
|
6206
6674
|
}
|
|
6207
6675
|
function tryAcquireLock(lockPath, ownerPid = process.pid) {
|
|
6208
|
-
mkdirSync4(
|
|
6676
|
+
mkdirSync4(dirname12(lockPath), { recursive: true });
|
|
6209
6677
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
6210
6678
|
const handle = writeLockFile(lockPath, ownerPid);
|
|
6211
6679
|
if (handle)
|
|
@@ -6237,7 +6705,7 @@ function reapStaleLock(lockPath) {
|
|
|
6237
6705
|
}
|
|
6238
6706
|
function unlinkQuietly(path2) {
|
|
6239
6707
|
try {
|
|
6240
|
-
|
|
6708
|
+
unlinkSync3(path2);
|
|
6241
6709
|
} catch (error) {
|
|
6242
6710
|
if (error instanceof Error)
|
|
6243
6711
|
return;
|
|
@@ -6253,17 +6721,19 @@ function errorCode3(error) {
|
|
|
6253
6721
|
|
|
6254
6722
|
// src/ownership.ts
|
|
6255
6723
|
class DaemonAlreadyRunningError extends Error {
|
|
6256
|
-
|
|
6257
|
-
|
|
6724
|
+
constructor() {
|
|
6725
|
+
super(...arguments);
|
|
6726
|
+
this.name = "DaemonAlreadyRunningError";
|
|
6727
|
+
this.code = "daemon_already_running";
|
|
6728
|
+
}
|
|
6258
6729
|
}
|
|
6259
6730
|
|
|
6260
6731
|
class DaemonStartupDeferredError extends Error {
|
|
6261
|
-
reason;
|
|
6262
|
-
name = "DaemonStartupDeferredError";
|
|
6263
|
-
code = "daemon_startup_deferred";
|
|
6264
6732
|
constructor(reason) {
|
|
6265
6733
|
super(`LSP daemon startup deferred: ${reason}`);
|
|
6266
6734
|
this.reason = reason;
|
|
6735
|
+
this.name = "DaemonStartupDeferredError";
|
|
6736
|
+
this.code = "daemon_startup_deferred";
|
|
6267
6737
|
}
|
|
6268
6738
|
}
|
|
6269
6739
|
async function acquireStartupLease(paths, pingOwner) {
|
|
@@ -6286,11 +6756,11 @@ async function acquireStartupLease(paths, pingOwner) {
|
|
|
6286
6756
|
function ensureDaemonDirectories(paths) {
|
|
6287
6757
|
ensurePrivateDirectory(paths.dir);
|
|
6288
6758
|
if (process.platform !== "win32")
|
|
6289
|
-
ensurePrivateDirectory(
|
|
6759
|
+
ensurePrivateDirectory(dirname13(paths.socket));
|
|
6290
6760
|
}
|
|
6291
6761
|
function readDaemonOwner(paths) {
|
|
6292
6762
|
try {
|
|
6293
|
-
return parseOwner(JSON.parse(
|
|
6763
|
+
return parseOwner(JSON.parse(readFileSync8(paths.owner, "utf8")));
|
|
6294
6764
|
} catch (error) {
|
|
6295
6765
|
if (error instanceof Error)
|
|
6296
6766
|
return null;
|
|
@@ -6366,10 +6836,10 @@ async function validateExistingOwner(paths, pingOwner) {
|
|
|
6366
6836
|
throw new DaemonStartupDeferredError("reachable_owner_mismatch");
|
|
6367
6837
|
}
|
|
6368
6838
|
function cleanupDeadOwner(paths, owner) {
|
|
6369
|
-
if (process.platform !== "win32" &&
|
|
6839
|
+
if (process.platform !== "win32" && existsSync14(owner.endpoint.path)) {
|
|
6370
6840
|
const stat = lstatSync7(owner.endpoint.path);
|
|
6371
6841
|
if (stat.isSocket())
|
|
6372
|
-
|
|
6842
|
+
unlinkSync4(owner.endpoint.path);
|
|
6373
6843
|
}
|
|
6374
6844
|
unlinkQuietly(paths.pid);
|
|
6375
6845
|
unlinkQuietly(paths.endpoint);
|
|
@@ -6417,7 +6887,7 @@ function parseEndpoint(value) {
|
|
|
6417
6887
|
// src/version-reap.ts
|
|
6418
6888
|
import { execFile } from "node:child_process";
|
|
6419
6889
|
import { readdir, readFile, rm } from "node:fs/promises";
|
|
6420
|
-
import { basename as
|
|
6890
|
+
import { basename as basename5, dirname as dirname14, join as join9 } from "node:path";
|
|
6421
6891
|
var TERM_GRACE_MS = 5000;
|
|
6422
6892
|
var KILL_GRACE_MS = 1000;
|
|
6423
6893
|
var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
|
|
@@ -6438,7 +6908,7 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
|
|
|
6438
6908
|
return isNodeCliDaemonCommand(command.trim());
|
|
6439
6909
|
}
|
|
6440
6910
|
async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
6441
|
-
const baseDir =
|
|
6911
|
+
const baseDir = dirname14(ownPaths.dir);
|
|
6442
6912
|
const platform = deps.platform ?? process.platform;
|
|
6443
6913
|
const isAlive = deps.isAlive ?? isProcessAlive2;
|
|
6444
6914
|
const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
|
|
@@ -6457,7 +6927,7 @@ async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
|
6457
6927
|
const version = parseVersionEntry(entry.name);
|
|
6458
6928
|
if (version === null || !entry.isDirectory())
|
|
6459
6929
|
continue;
|
|
6460
|
-
const versionDir =
|
|
6930
|
+
const versionDir = join9(baseDir, entry.name);
|
|
6461
6931
|
const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
|
|
6462
6932
|
results.push(await reapOneVersion({
|
|
6463
6933
|
version,
|
|
@@ -6481,7 +6951,7 @@ async function reapOneVersion(context) {
|
|
|
6481
6951
|
const { version, versionDir } = context;
|
|
6482
6952
|
const owner = context.readOwner(context.siblingPaths);
|
|
6483
6953
|
if (!owner) {
|
|
6484
|
-
const lockPid = readLockPid(
|
|
6954
|
+
const lockPid = readLockPid(join9(versionDir, "daemon.lock"));
|
|
6485
6955
|
if (lockPid !== null && context.isAlive(lockPid)) {
|
|
6486
6956
|
context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
|
|
6487
6957
|
return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
|
|
@@ -6547,7 +7017,7 @@ function splitCmdline(buffer) {
|
|
|
6547
7017
|
function isNodeCliDaemonArgv(argv) {
|
|
6548
7018
|
if (argv.length < 2 || !argv.includes("daemon"))
|
|
6549
7019
|
return false;
|
|
6550
|
-
const executable =
|
|
7020
|
+
const executable = basename5(argv[0] ?? "");
|
|
6551
7021
|
if (!/^node(?:\.exe)?$/i.test(executable))
|
|
6552
7022
|
return false;
|
|
6553
7023
|
return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
|
|
@@ -6559,13 +7029,13 @@ function defaultReadProcFile(path2) {
|
|
|
6559
7029
|
return readFile(path2);
|
|
6560
7030
|
}
|
|
6561
7031
|
function defaultExecuteForStdout(file, args) {
|
|
6562
|
-
return new Promise((
|
|
6563
|
-
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
|
|
7032
|
+
return new Promise((resolve10) => {
|
|
7033
|
+
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000, windowsHide: true }, (error, stdout) => {
|
|
6564
7034
|
if (error !== null) {
|
|
6565
|
-
|
|
7035
|
+
resolve10(null);
|
|
6566
7036
|
return;
|
|
6567
7037
|
}
|
|
6568
|
-
|
|
7038
|
+
resolve10(stdout);
|
|
6569
7039
|
});
|
|
6570
7040
|
});
|
|
6571
7041
|
}
|
|
@@ -6584,7 +7054,7 @@ async function defaultWaitForExit(pid, timeoutMs) {
|
|
|
6584
7054
|
return true;
|
|
6585
7055
|
if (Date.now() >= deadline)
|
|
6586
7056
|
return false;
|
|
6587
|
-
await new Promise((
|
|
7057
|
+
await new Promise((resolve10) => setTimeout(resolve10, 100));
|
|
6588
7058
|
}
|
|
6589
7059
|
}
|
|
6590
7060
|
function defaultLog(message) {
|
|
@@ -6691,17 +7161,17 @@ async function assertSelfProbe(paths, token, owner) {
|
|
|
6691
7161
|
throw new DaemonStartupDeferredError("self_probe_failed");
|
|
6692
7162
|
}
|
|
6693
7163
|
function listen(server2, socketPath) {
|
|
6694
|
-
return new Promise((
|
|
7164
|
+
return new Promise((resolve10, reject) => {
|
|
6695
7165
|
const onError = (error) => reject(error);
|
|
6696
7166
|
server2.once("error", onError);
|
|
6697
7167
|
server2.listen(socketPath, () => {
|
|
6698
7168
|
server2.removeListener("error", onError);
|
|
6699
|
-
|
|
7169
|
+
resolve10();
|
|
6700
7170
|
});
|
|
6701
7171
|
});
|
|
6702
7172
|
}
|
|
6703
7173
|
function closeServer(server2) {
|
|
6704
|
-
return new Promise((
|
|
7174
|
+
return new Promise((resolve10) => server2.close(() => resolve10()));
|
|
6705
7175
|
}
|
|
6706
7176
|
function installSignalHandlers(close) {
|
|
6707
7177
|
const handler = () => {
|