lazycodex-ai 5.0.0-beta.4 → 5.0.0-beta.42
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 +67006 -64814
- 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 +67283 -65068
- package/package.json +9 -9
- package/packages/git-bash-mcp/dist/cli.js +6 -1
- package/packages/lsp-daemon/dist/cli.js +804 -329
- package/packages/lsp-daemon/dist/client.d.ts +10 -0
- package/packages/lsp-daemon/dist/client.js +764 -286
- 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 +768 -295
- 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 +723 -250
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +259 -125
- package/packages/lsp-tools-mcp/dist/mcp.js +725 -252
- package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
- package/packages/lsp-tools-mcp/dist/tools.js +729 -260
- 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 +752 -300
- 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 +4 -3
- 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 +42 -31
- package/packages/omo-codex/plugin/shared/package.json +3 -4
- package/packages/omo-codex/plugin/shared/src/config-loader.ts +2 -102
- package/packages/omo-codex/plugin/shared/src/config-migration.ts +0 -1
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +41 -130
- package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +51 -0
- package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +3 -1
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +12 -8
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/omo-codex/plugin/skills/git-master/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +14 -14
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/lsp-setup/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +101 -419
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +26 -9
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +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 +4 -3
- 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 +8 -3
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +4 -3
- 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 +24 -14
- 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 +2818 -913
- package/packages/{omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md → prompts-core/prompts/ultrawork/codex.md} +15 -10
- package/packages/shared-skills/package.json +7 -1
- package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
- package/packages/shared-skills/skills/ast-grep/SKILL.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
- package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
- package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
- package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
- package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
- package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
- package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +3 -1
- package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
- package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +12 -8
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
- package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
- package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
- package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
- package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
- package/packages/shared-skills/skills/git-master/SKILL.md +1 -1
- package/packages/shared-skills/skills/init-deep/SKILL.md +14 -14
- package/packages/shared-skills/skills/lsp-setup/SKILL.md +1 -1
- package/packages/shared-skills/skills/programming/SKILL.md +1 -1
- package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/shared-skills/skills/review-work/SKILL.md +100 -418
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +26 -9
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
- package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +17 -16
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +7 -8
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
- package/packages/shared-skills/skills/ulw-research/SKILL.md +8 -3
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +4 -3
- package/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)
|
|
@@ -655,6 +686,7 @@ class JsonRpcConnection {
|
|
|
655
686
|
let cancelAfterWrite = false;
|
|
656
687
|
let settled = false;
|
|
657
688
|
const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
|
|
689
|
+
let rejectAfterCancelWrite;
|
|
658
690
|
const responsePromise = new Promise((resolve2, reject) => {
|
|
659
691
|
const cleanup = () => {
|
|
660
692
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -666,15 +698,19 @@ class JsonRpcConnection {
|
|
|
666
698
|
this.pendingRequests.delete(key);
|
|
667
699
|
cleanup();
|
|
668
700
|
const rejectCancelled = () => reject(abortError(options.signal));
|
|
701
|
+
rejectAfterCancelWrite = async () => {
|
|
702
|
+
try {
|
|
703
|
+
await writeCancel();
|
|
704
|
+
} catch (error) {
|
|
705
|
+
this.emitError(toError(error));
|
|
706
|
+
}
|
|
707
|
+
rejectCancelled();
|
|
708
|
+
};
|
|
669
709
|
if (!requestWritten) {
|
|
670
710
|
cancelAfterWrite = true;
|
|
671
|
-
rejectCancelled();
|
|
672
711
|
return;
|
|
673
712
|
}
|
|
674
|
-
|
|
675
|
-
this.emitError(toError(error));
|
|
676
|
-
rejectCancelled();
|
|
677
|
-
});
|
|
713
|
+
rejectAfterCancelWrite();
|
|
678
714
|
};
|
|
679
715
|
const onAbort = () => settleCancel();
|
|
680
716
|
this.pendingRequests.set(key, {
|
|
@@ -702,7 +738,7 @@ class JsonRpcConnection {
|
|
|
702
738
|
await this.writeMessage(message);
|
|
703
739
|
requestWritten = true;
|
|
704
740
|
if (cancelAfterWrite)
|
|
705
|
-
await
|
|
741
|
+
await rejectAfterCancelWrite?.();
|
|
706
742
|
} catch (error) {
|
|
707
743
|
if (settled)
|
|
708
744
|
return responsePromise;
|
|
@@ -741,19 +777,6 @@ class JsonRpcConnection {
|
|
|
741
777
|
this.notificationHandlers.clear();
|
|
742
778
|
this.requestHandlers.clear();
|
|
743
779
|
}
|
|
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
780
|
drainInputBuffer() {
|
|
758
781
|
while (true) {
|
|
759
782
|
const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
|
|
@@ -1101,33 +1124,29 @@ function isPosition(value) {
|
|
|
1101
1124
|
|
|
1102
1125
|
// ../lsp-core/src/lsp/transport.ts
|
|
1103
1126
|
class LspClientNotStartedError extends Error {
|
|
1104
|
-
serverId;
|
|
1105
|
-
root;
|
|
1106
|
-
name = "LspClientNotStartedError";
|
|
1107
1127
|
constructor(serverId, root) {
|
|
1108
1128
|
super("LSP client not started");
|
|
1109
1129
|
this.serverId = serverId;
|
|
1110
1130
|
this.root = root;
|
|
1131
|
+
this.name = "LspClientNotStartedError";
|
|
1111
1132
|
}
|
|
1112
1133
|
}
|
|
1113
1134
|
|
|
1114
1135
|
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
1136
|
constructor(root, server2, timeouts = {}) {
|
|
1127
1137
|
this.root = root;
|
|
1128
1138
|
this.server = server2;
|
|
1139
|
+
this.proc = null;
|
|
1140
|
+
this.connection = null;
|
|
1141
|
+
this.stderrBuffer = [];
|
|
1142
|
+
this.processExited = false;
|
|
1143
|
+
this.diagnosticsStore = new Map;
|
|
1144
|
+
this.workspaceApplyEditHandler = null;
|
|
1145
|
+
this.diagnosticPullSupported = false;
|
|
1146
|
+
this.documentFormattingSupported = false;
|
|
1129
1147
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
1130
1148
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
1149
|
+
this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
|
|
1131
1150
|
}
|
|
1132
1151
|
pid() {
|
|
1133
1152
|
return this.proc?.pid;
|
|
@@ -1147,6 +1166,12 @@ class LspClientTransport {
|
|
|
1147
1166
|
isDiagnosticPullSupported() {
|
|
1148
1167
|
return this.diagnosticPullSupported;
|
|
1149
1168
|
}
|
|
1169
|
+
setDocumentFormattingSupported(supported) {
|
|
1170
|
+
this.documentFormattingSupported = supported;
|
|
1171
|
+
}
|
|
1172
|
+
isDocumentFormattingSupported() {
|
|
1173
|
+
return this.documentFormattingSupported;
|
|
1174
|
+
}
|
|
1150
1175
|
handlePublishDiagnostics(params) {
|
|
1151
1176
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
1152
1177
|
}
|
|
@@ -1222,7 +1247,7 @@ class LspClientTransport {
|
|
|
1222
1247
|
const options = args[1];
|
|
1223
1248
|
const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
|
|
1224
1249
|
const timeoutController = new AbortController;
|
|
1225
|
-
const timeoutHandle = setTimeout(() => {
|
|
1250
|
+
const timeoutHandle = this.timerProvider.setTimeout(() => {
|
|
1226
1251
|
const stderrTail = this.stderrBuffer.slice(-5).join(`
|
|
1227
1252
|
`);
|
|
1228
1253
|
timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
|
|
@@ -1241,7 +1266,7 @@ class LspClientTransport {
|
|
|
1241
1266
|
}
|
|
1242
1267
|
throw error;
|
|
1243
1268
|
} finally {
|
|
1244
|
-
clearTimeout(timeoutHandle);
|
|
1269
|
+
this.timerProvider.clearTimeout(timeoutHandle);
|
|
1245
1270
|
combinedSignal.dispose();
|
|
1246
1271
|
}
|
|
1247
1272
|
}
|
|
@@ -1360,6 +1385,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
1360
1385
|
return false;
|
|
1361
1386
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
1362
1387
|
}
|
|
1388
|
+
function supportsDocumentFormatting(capabilities) {
|
|
1389
|
+
if (capabilities === undefined)
|
|
1390
|
+
return false;
|
|
1391
|
+
const provider = capabilities.documentFormattingProvider;
|
|
1392
|
+
if (provider === undefined || provider === null || provider === false)
|
|
1393
|
+
return false;
|
|
1394
|
+
return provider === true || typeof provider === "object";
|
|
1395
|
+
}
|
|
1363
1396
|
|
|
1364
1397
|
class LspClientConnection extends LspClientTransport {
|
|
1365
1398
|
async initialize() {
|
|
@@ -1376,6 +1409,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1376
1409
|
references: {},
|
|
1377
1410
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
1378
1411
|
publishDiagnostics: {},
|
|
1412
|
+
formatting: { dynamicRegistration: false },
|
|
1379
1413
|
rename: {
|
|
1380
1414
|
prepareSupport: true,
|
|
1381
1415
|
prepareSupportDefaultBehavior: 1
|
|
@@ -1417,6 +1451,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1417
1451
|
initializationOptions: this.server.initialization
|
|
1418
1452
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
1419
1453
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
1454
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
1420
1455
|
await this.sendNotification("initialized", {});
|
|
1421
1456
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
1422
1457
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -1612,6 +1647,17 @@ function canonicalPath(filePath) {
|
|
|
1612
1647
|
return absolute;
|
|
1613
1648
|
}
|
|
1614
1649
|
}
|
|
1650
|
+
function normalizeDocumentUri(uri) {
|
|
1651
|
+
let decoded = uri;
|
|
1652
|
+
try {
|
|
1653
|
+
decoded = decodeURIComponent(uri);
|
|
1654
|
+
} catch {
|
|
1655
|
+
decoded = uri;
|
|
1656
|
+
}
|
|
1657
|
+
if (process.platform !== "win32")
|
|
1658
|
+
return decoded;
|
|
1659
|
+
return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
|
|
1660
|
+
}
|
|
1615
1661
|
function isSameOrDescendant(candidate, parent) {
|
|
1616
1662
|
const suffix = relative2(parent, candidate);
|
|
1617
1663
|
return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
|
|
@@ -1622,17 +1668,18 @@ function movedPath(candidate, oldPath, newPath) {
|
|
|
1622
1668
|
}
|
|
1623
1669
|
|
|
1624
1670
|
class WorkspaceDocumentState {
|
|
1625
|
-
sendNotification;
|
|
1626
|
-
clearDiagnostics;
|
|
1627
|
-
openDocuments = new Map;
|
|
1628
|
-
openByUri = new Map;
|
|
1629
|
-
openPromises = new Map;
|
|
1630
|
-
now;
|
|
1631
|
-
versionlessPublishQuiescenceMs;
|
|
1632
1671
|
constructor(sendNotification, clearDiagnostics, options = {}) {
|
|
1633
1672
|
this.sendNotification = sendNotification;
|
|
1634
1673
|
this.clearDiagnostics = clearDiagnostics;
|
|
1635
|
-
this.
|
|
1674
|
+
this.openDocuments = new Map;
|
|
1675
|
+
this.openByUri = new Map;
|
|
1676
|
+
this.openPromises = new Map;
|
|
1677
|
+
this.timerProvider = options.timerProvider ?? {
|
|
1678
|
+
now: options.now ?? (() => Date.now()),
|
|
1679
|
+
setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
1680
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
1681
|
+
};
|
|
1682
|
+
this.now = () => this.timerProvider.now();
|
|
1636
1683
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
1637
1684
|
}
|
|
1638
1685
|
async openFile(filePath) {
|
|
@@ -1654,7 +1701,7 @@ class WorkspaceDocumentState {
|
|
|
1654
1701
|
return this.openDocuments.get(canonicalPath(filePath))?.version;
|
|
1655
1702
|
}
|
|
1656
1703
|
getStoredDiagnostics(uri) {
|
|
1657
|
-
const state = this.openByUri.get(uri);
|
|
1704
|
+
const state = this.openByUri.get(normalizeDocumentUri(uri));
|
|
1658
1705
|
if (!state)
|
|
1659
1706
|
return [];
|
|
1660
1707
|
return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
|
|
@@ -1676,13 +1723,13 @@ class WorkspaceDocumentState {
|
|
|
1676
1723
|
return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
|
|
1677
1724
|
}
|
|
1678
1725
|
getPullCache(snapshot) {
|
|
1679
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1726
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1680
1727
|
if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
|
|
1681
1728
|
return null;
|
|
1682
1729
|
return state.pullCache;
|
|
1683
1730
|
}
|
|
1684
1731
|
recordPullDiagnostics(snapshot, report) {
|
|
1685
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1732
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1686
1733
|
if (!state)
|
|
1687
1734
|
return;
|
|
1688
1735
|
state.pullCache = {
|
|
@@ -1692,7 +1739,7 @@ class WorkspaceDocumentState {
|
|
|
1692
1739
|
};
|
|
1693
1740
|
}
|
|
1694
1741
|
recordPublishedDiagnostics(params) {
|
|
1695
|
-
const state = this.openByUri.get(params.uri);
|
|
1742
|
+
const state = this.openByUri.get(normalizeDocumentUri(params.uri));
|
|
1696
1743
|
if (!state)
|
|
1697
1744
|
return;
|
|
1698
1745
|
state.publishGeneration += 1;
|
|
@@ -1706,7 +1753,7 @@ class WorkspaceDocumentState {
|
|
|
1706
1753
|
this.notifyWaiters(state);
|
|
1707
1754
|
}
|
|
1708
1755
|
resolvePushDiagnostics(snapshot) {
|
|
1709
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1756
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1710
1757
|
if (!state?.lastPublish)
|
|
1711
1758
|
return { status: "missing" };
|
|
1712
1759
|
const publish = state.lastPublish;
|
|
@@ -1720,7 +1767,7 @@ class WorkspaceDocumentState {
|
|
|
1720
1767
|
return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
|
|
1721
1768
|
}
|
|
1722
1769
|
waitForDiagnosticsActivity(snapshot, timeoutMs) {
|
|
1723
|
-
const state = this.openByUri.get(snapshot.uri);
|
|
1770
|
+
const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
|
|
1724
1771
|
if (!state || timeoutMs <= 0)
|
|
1725
1772
|
return Promise.resolve();
|
|
1726
1773
|
return new Promise((resolveActivity) => {
|
|
@@ -1729,11 +1776,11 @@ class WorkspaceDocumentState {
|
|
|
1729
1776
|
if (settled)
|
|
1730
1777
|
return;
|
|
1731
1778
|
settled = true;
|
|
1732
|
-
clearTimeout(timer);
|
|
1779
|
+
this.timerProvider.clearTimeout(timer);
|
|
1733
1780
|
state.waiters.delete(finish);
|
|
1734
1781
|
resolveActivity();
|
|
1735
1782
|
};
|
|
1736
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
1783
|
+
const timer = this.timerProvider.setTimeout(finish, timeoutMs);
|
|
1737
1784
|
if (typeof timer.unref === "function")
|
|
1738
1785
|
timer.unref();
|
|
1739
1786
|
state.waiters.add(finish);
|
|
@@ -1841,7 +1888,7 @@ class WorkspaceDocumentState {
|
|
|
1841
1888
|
waiters: new Set
|
|
1842
1889
|
};
|
|
1843
1890
|
this.openDocuments.set(path, state);
|
|
1844
|
-
this.openByUri.set(state.uri, state);
|
|
1891
|
+
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
1845
1892
|
this.notifyWaiters(state);
|
|
1846
1893
|
await this.sendNotification("textDocument/didOpen", {
|
|
1847
1894
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
@@ -1866,7 +1913,7 @@ class WorkspaceDocumentState {
|
|
|
1866
1913
|
}
|
|
1867
1914
|
async closeDocument(state) {
|
|
1868
1915
|
this.openDocuments.delete(state.path);
|
|
1869
|
-
this.openByUri.delete(state.uri);
|
|
1916
|
+
this.openByUri.delete(normalizeDocumentUri(state.uri));
|
|
1870
1917
|
this.clearDiagnostics(state.uri);
|
|
1871
1918
|
this.notifyWaiters(state);
|
|
1872
1919
|
await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
|
|
@@ -1895,13 +1942,11 @@ import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3,
|
|
|
1895
1942
|
import { fileURLToPath } from "node:url";
|
|
1896
1943
|
|
|
1897
1944
|
class WorkspaceEditPathError extends Error {
|
|
1898
|
-
path;
|
|
1899
|
-
detail;
|
|
1900
|
-
name = "WorkspaceEditPathError";
|
|
1901
1945
|
constructor(path, detail) {
|
|
1902
1946
|
super(`${detail}: ${path}`);
|
|
1903
1947
|
this.path = path;
|
|
1904
1948
|
this.detail = detail;
|
|
1949
|
+
this.name = "WorkspaceEditPathError";
|
|
1905
1950
|
}
|
|
1906
1951
|
}
|
|
1907
1952
|
function isPathInsideWorkspace(filePath, workspaceRoot) {
|
|
@@ -2193,13 +2238,11 @@ function canonicalFingerprint(operations) {
|
|
|
2193
2238
|
|
|
2194
2239
|
// ../lsp-core/src/lsp/workspace-edit-types.ts
|
|
2195
2240
|
class WorkspaceEditValidationError extends Error {
|
|
2196
|
-
changeIndex;
|
|
2197
|
-
detail;
|
|
2198
|
-
name = "WorkspaceEditValidationError";
|
|
2199
2241
|
constructor(changeIndex, detail) {
|
|
2200
2242
|
super(`change ${changeIndex}: ${detail}`);
|
|
2201
2243
|
this.changeIndex = changeIndex;
|
|
2202
2244
|
this.detail = detail;
|
|
2245
|
+
this.name = "WorkspaceEditValidationError";
|
|
2203
2246
|
}
|
|
2204
2247
|
}
|
|
2205
2248
|
|
|
@@ -2697,10 +2740,9 @@ function simulateDelete(operation, virtual) {
|
|
|
2697
2740
|
import { existsSync as existsSync5, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
|
|
2698
2741
|
import { dirname as dirname4, resolve as resolve5 } from "node:path";
|
|
2699
2742
|
class WorkspaceSnapshotBuilder {
|
|
2700
|
-
workspaceRoot;
|
|
2701
|
-
snapshots = new Map;
|
|
2702
2743
|
constructor(workspaceRoot) {
|
|
2703
2744
|
this.workspaceRoot = workspaceRoot;
|
|
2745
|
+
this.snapshots = new Map;
|
|
2704
2746
|
}
|
|
2705
2747
|
build(operations) {
|
|
2706
2748
|
this.add(this.workspaceRoot, false);
|
|
@@ -2744,8 +2786,10 @@ function snapshotOperations(operations, workspaceRoot) {
|
|
|
2744
2786
|
|
|
2745
2787
|
// ../lsp-core/src/lsp/workspace-edit-plan.ts
|
|
2746
2788
|
class PlanPathIndex {
|
|
2747
|
-
|
|
2748
|
-
|
|
2789
|
+
constructor() {
|
|
2790
|
+
this.firstChangeByPath = new Map;
|
|
2791
|
+
this.reportedPathByCanonical = new Map;
|
|
2792
|
+
}
|
|
2749
2793
|
build(operations) {
|
|
2750
2794
|
for (const operation of operations) {
|
|
2751
2795
|
switch (operation.kind) {
|
|
@@ -2834,14 +2878,11 @@ function isRecord4(value) {
|
|
|
2834
2878
|
}
|
|
2835
2879
|
|
|
2836
2880
|
class WorkspaceMutationController {
|
|
2837
|
-
workspaceRoot;
|
|
2838
|
-
documents;
|
|
2839
|
-
activeLease = null;
|
|
2840
|
-
nextLeaseId = 1;
|
|
2841
|
-
io;
|
|
2842
2881
|
constructor(workspaceRoot, documents) {
|
|
2843
2882
|
this.workspaceRoot = workspaceRoot;
|
|
2844
2883
|
this.documents = documents;
|
|
2884
|
+
this.activeLease = null;
|
|
2885
|
+
this.nextLeaseId = 1;
|
|
2845
2886
|
}
|
|
2846
2887
|
setIo(io) {
|
|
2847
2888
|
this.io = io;
|
|
@@ -2954,14 +2995,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
2954
2995
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
2955
2996
|
|
|
2956
2997
|
class LspClient extends LspClientConnection {
|
|
2957
|
-
diagnosticPullErrors = [];
|
|
2958
|
-
documents;
|
|
2959
|
-
workspaceMutations;
|
|
2960
|
-
diagnosticsFreshnessTimeoutMs;
|
|
2961
2998
|
constructor(root, server2, options = {}) {
|
|
2962
2999
|
super(root, server2, options);
|
|
3000
|
+
this.diagnosticPullErrors = [];
|
|
2963
3001
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
2964
3002
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
3003
|
+
timerProvider: this.timerProvider,
|
|
2965
3004
|
versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
|
|
2966
3005
|
});
|
|
2967
3006
|
this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
|
|
@@ -3014,6 +3053,18 @@ class LspClient extends LspClientConnection {
|
|
|
3014
3053
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
3015
3054
|
}, options);
|
|
3016
3055
|
}
|
|
3056
|
+
async formatDocument(filePath, options, signal) {
|
|
3057
|
+
if (!this.isDocumentFormattingSupported())
|
|
3058
|
+
return null;
|
|
3059
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
3060
|
+
await this.openFile(absPath);
|
|
3061
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
3062
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
3063
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
3064
|
+
options
|
|
3065
|
+
}, requestOptions);
|
|
3066
|
+
return edits ?? [];
|
|
3067
|
+
}
|
|
3017
3068
|
async workspaceSymbols(query, signal) {
|
|
3018
3069
|
const options = signal === undefined ? {} : { signal };
|
|
3019
3070
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -3053,7 +3104,7 @@ class LspClient extends LspClientConnection {
|
|
|
3053
3104
|
const absPath = this.resolveWorkspacePath(filePath);
|
|
3054
3105
|
const uri = pathToFileURL3(absPath).href;
|
|
3055
3106
|
await this.openFile(absPath);
|
|
3056
|
-
const deadlineAt =
|
|
3107
|
+
const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
|
|
3057
3108
|
for (;; ) {
|
|
3058
3109
|
signal?.throwIfAborted();
|
|
3059
3110
|
const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
|
|
@@ -3066,7 +3117,7 @@ class LspClient extends LspClientConnection {
|
|
|
3066
3117
|
if (!pushFallbackOnly) {
|
|
3067
3118
|
const cached = this.documents.getPullCache(snapshot);
|
|
3068
3119
|
try {
|
|
3069
|
-
const remainingMs2 = deadlineAt -
|
|
3120
|
+
const remainingMs2 = deadlineAt - this.timerProvider.now();
|
|
3070
3121
|
if (remainingMs2 <= 0)
|
|
3071
3122
|
return this.freshnessTimeout(absPath);
|
|
3072
3123
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
@@ -3101,7 +3152,7 @@ class LspClient extends LspClientConnection {
|
|
|
3101
3152
|
}
|
|
3102
3153
|
if (!pushFallbackOnly)
|
|
3103
3154
|
continue;
|
|
3104
|
-
const remainingMs = deadlineAt -
|
|
3155
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3105
3156
|
if (remainingMs <= 0) {
|
|
3106
3157
|
if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
|
|
3107
3158
|
const cached = this.documents.getPullCache(snapshot);
|
|
@@ -3259,18 +3310,16 @@ function awaitWithSignal(promise, signal) {
|
|
|
3259
3310
|
}
|
|
3260
3311
|
|
|
3261
3312
|
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
3313
|
constructor(options = {}) {
|
|
3314
|
+
this.clients = new Map;
|
|
3315
|
+
this.pendingStops = new Map;
|
|
3316
|
+
this.respawnBudgets = new Map;
|
|
3317
|
+
this.reaperHandle = null;
|
|
3318
|
+
this.signalDisposer = null;
|
|
3319
|
+
this.disposed = false;
|
|
3272
3320
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
3273
3321
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3322
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3274
3323
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3275
3324
|
this.clientFactory = options.clientFactory ?? ((root, server2) => new LspClient(root, server2));
|
|
3276
3325
|
this.now = options.now ?? (() => Date.now());
|
|
@@ -3290,24 +3339,79 @@ class LspManager {
|
|
|
3290
3339
|
getKey(root, serverId) {
|
|
3291
3340
|
return `${root}::${serverId}`;
|
|
3292
3341
|
}
|
|
3342
|
+
tombstoneStop(key, client) {
|
|
3343
|
+
const stop = stopClientBestEffort(client);
|
|
3344
|
+
this.pendingStops.set(key, stop);
|
|
3345
|
+
stop.finally(() => {
|
|
3346
|
+
if (this.pendingStops.get(key) === stop) {
|
|
3347
|
+
this.pendingStops.delete(key);
|
|
3348
|
+
}
|
|
3349
|
+
});
|
|
3350
|
+
return stop;
|
|
3351
|
+
}
|
|
3352
|
+
recordDeadGeneration(key) {
|
|
3353
|
+
let budget = this.respawnBudgets.get(key);
|
|
3354
|
+
if (budget === undefined) {
|
|
3355
|
+
budget = { deadGenerations: 0, exhaustedAt: null };
|
|
3356
|
+
this.respawnBudgets.set(key, budget);
|
|
3357
|
+
}
|
|
3358
|
+
budget.deadGenerations += 1;
|
|
3359
|
+
}
|
|
3360
|
+
markHealthyGeneration(key) {
|
|
3361
|
+
this.respawnBudgets.delete(key);
|
|
3362
|
+
}
|
|
3363
|
+
ensureRespawnAllowed(key, root, serverId) {
|
|
3364
|
+
const budget = this.respawnBudgets.get(key);
|
|
3365
|
+
if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
|
|
3366
|
+
return;
|
|
3367
|
+
if (budget.exhaustedAt === null) {
|
|
3368
|
+
budget.exhaustedAt = this.now();
|
|
3369
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3370
|
+
}
|
|
3371
|
+
if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
|
|
3372
|
+
throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
|
|
3373
|
+
}
|
|
3374
|
+
budget.deadGenerations = 0;
|
|
3375
|
+
budget.exhaustedAt = null;
|
|
3376
|
+
}
|
|
3293
3377
|
reapStale() {
|
|
3294
3378
|
const t = this.now();
|
|
3295
3379
|
for (const [key, managed] of this.clients) {
|
|
3296
3380
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3297
|
-
stopClientBestEffort(managed.client);
|
|
3298
3381
|
this.clients.delete(key);
|
|
3382
|
+
this.tombstoneStop(key, managed.client);
|
|
3299
3383
|
continue;
|
|
3300
3384
|
}
|
|
3301
3385
|
if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
|
|
3302
|
-
stopClientBestEffort(managed.client);
|
|
3303
3386
|
this.clients.delete(key);
|
|
3387
|
+
this.tombstoneStop(key, managed.client);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
evictForAdmission() {
|
|
3392
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
3393
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
3394
|
+
if (!victim)
|
|
3395
|
+
return;
|
|
3396
|
+
this.clients.delete(victim.key);
|
|
3397
|
+
this.tombstoneStop(victim.key, victim.managed.client);
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
leastRecentlyUsedIdleClient() {
|
|
3401
|
+
let candidate = null;
|
|
3402
|
+
for (const [key, managed] of this.clients) {
|
|
3403
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
3404
|
+
continue;
|
|
3405
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
3406
|
+
candidate = { key, managed };
|
|
3304
3407
|
}
|
|
3305
3408
|
}
|
|
3409
|
+
return candidate;
|
|
3306
3410
|
}
|
|
3307
3411
|
async tryDeleteIfOrphaned(key, managed) {
|
|
3308
3412
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
3309
3413
|
this.clients.delete(key);
|
|
3310
|
-
await
|
|
3414
|
+
await this.tombstoneStop(key, managed.client);
|
|
3311
3415
|
}
|
|
3312
3416
|
}
|
|
3313
3417
|
async getClient(root, server2, signal) {
|
|
@@ -3316,12 +3420,22 @@ class LspManager {
|
|
|
3316
3420
|
}
|
|
3317
3421
|
signal?.throwIfAborted();
|
|
3318
3422
|
const key = this.getKey(root, server2.id);
|
|
3423
|
+
for (;; ) {
|
|
3424
|
+
const pendingStop = this.pendingStops.get(key);
|
|
3425
|
+
if (pendingStop === undefined)
|
|
3426
|
+
break;
|
|
3427
|
+
await awaitWithSignal(pendingStop, signal);
|
|
3428
|
+
signal?.throwIfAborted();
|
|
3429
|
+
}
|
|
3430
|
+
if (this.disposed) {
|
|
3431
|
+
throw new Error("LspManager has been disposed");
|
|
3432
|
+
}
|
|
3319
3433
|
let managed = this.clients.get(key);
|
|
3320
3434
|
if (managed) {
|
|
3321
3435
|
const t = this.now();
|
|
3322
3436
|
if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
|
|
3323
|
-
await stopClientBestEffort(managed.client);
|
|
3324
3437
|
this.clients.delete(key);
|
|
3438
|
+
await this.tombstoneStop(key, managed.client);
|
|
3325
3439
|
managed = undefined;
|
|
3326
3440
|
}
|
|
3327
3441
|
}
|
|
@@ -3342,14 +3456,20 @@ class LspManager {
|
|
|
3342
3456
|
signal.throwIfAborted();
|
|
3343
3457
|
}
|
|
3344
3458
|
if (!managed.client.isAlive()) {
|
|
3345
|
-
|
|
3346
|
-
this.clients.
|
|
3459
|
+
this.recordDeadGeneration(key);
|
|
3460
|
+
if (this.clients.get(key) === managed) {
|
|
3461
|
+
this.clients.delete(key);
|
|
3462
|
+
}
|
|
3463
|
+
await this.tombstoneStop(key, managed.client);
|
|
3347
3464
|
return this.getClient(root, server2, signal);
|
|
3348
3465
|
}
|
|
3466
|
+
this.markHealthyGeneration(key);
|
|
3349
3467
|
managed.refCount++;
|
|
3350
3468
|
managed.lastUsedAt = this.now();
|
|
3351
3469
|
return managed.client;
|
|
3352
3470
|
}
|
|
3471
|
+
this.evictForAdmission();
|
|
3472
|
+
this.ensureRespawnAllowed(key, root, server2.id);
|
|
3353
3473
|
const client = this.clientFactory(root, server2);
|
|
3354
3474
|
const initStartedAt = this.now();
|
|
3355
3475
|
const initPromise = (async () => {
|
|
@@ -3373,7 +3493,7 @@ class LspManager {
|
|
|
3373
3493
|
if (this.clients.get(key) === newManaged) {
|
|
3374
3494
|
this.clients.delete(key);
|
|
3375
3495
|
}
|
|
3376
|
-
await
|
|
3496
|
+
await this.tombstoneStop(key, client);
|
|
3377
3497
|
throw err;
|
|
3378
3498
|
}
|
|
3379
3499
|
newManaged.pendingWaiters--;
|
|
@@ -3384,6 +3504,15 @@ class LspManager {
|
|
|
3384
3504
|
await this.tryDeleteIfOrphaned(key, newManaged);
|
|
3385
3505
|
signal.throwIfAborted();
|
|
3386
3506
|
}
|
|
3507
|
+
if (!client.isAlive()) {
|
|
3508
|
+
this.recordDeadGeneration(key);
|
|
3509
|
+
if (this.clients.get(key) === newManaged) {
|
|
3510
|
+
this.clients.delete(key);
|
|
3511
|
+
}
|
|
3512
|
+
await this.tombstoneStop(key, client);
|
|
3513
|
+
return this.getClient(root, server2, signal);
|
|
3514
|
+
}
|
|
3515
|
+
this.markHealthyGeneration(key);
|
|
3387
3516
|
newManaged.refCount++;
|
|
3388
3517
|
newManaged.lastUsedAt = this.now();
|
|
3389
3518
|
return client;
|
|
@@ -3404,14 +3533,20 @@ class LspManager {
|
|
|
3404
3533
|
if (client && managed.client !== client)
|
|
3405
3534
|
return;
|
|
3406
3535
|
this.clients.delete(key);
|
|
3407
|
-
|
|
3536
|
+
this.tombstoneStop(key, managed.client);
|
|
3408
3537
|
}
|
|
3409
3538
|
warmupClient(root, server2) {
|
|
3410
3539
|
if (this.disposed)
|
|
3411
3540
|
return;
|
|
3412
3541
|
const key = this.getKey(root, server2.id);
|
|
3413
|
-
if (this.clients.has(key))
|
|
3542
|
+
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
3414
3543
|
return;
|
|
3544
|
+
this.evictForAdmission();
|
|
3545
|
+
try {
|
|
3546
|
+
this.ensureRespawnAllowed(key, root, server2.id);
|
|
3547
|
+
} catch {
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3415
3550
|
const client = this.clientFactory(root, server2);
|
|
3416
3551
|
const initStartedAt = this.now();
|
|
3417
3552
|
const initPromise = (async () => {
|
|
@@ -3437,7 +3572,7 @@ class LspManager {
|
|
|
3437
3572
|
if (this.clients.get(key) === managed) {
|
|
3438
3573
|
this.clients.delete(key);
|
|
3439
3574
|
}
|
|
3440
|
-
|
|
3575
|
+
this.tombstoneStop(key, client);
|
|
3441
3576
|
});
|
|
3442
3577
|
}
|
|
3443
3578
|
isServerInitializing(root, serverId) {
|
|
@@ -3481,8 +3616,11 @@ class LspManager {
|
|
|
3481
3616
|
for (const managed of this.clients.values()) {
|
|
3482
3617
|
stopPromises.push(stopClientBestEffort(managed.client));
|
|
3483
3618
|
}
|
|
3619
|
+
const tombstonedStops = [...this.pendingStops.values()];
|
|
3484
3620
|
this.clients.clear();
|
|
3485
|
-
|
|
3621
|
+
this.respawnBudgets.clear();
|
|
3622
|
+
await Promise.allSettled([...stopPromises, ...tombstonedStops]);
|
|
3623
|
+
this.pendingStops.clear();
|
|
3486
3624
|
}
|
|
3487
3625
|
}
|
|
3488
3626
|
var _defaultInstance = null;
|
|
@@ -3500,57 +3638,52 @@ async function disposeDefaultLspManager() {
|
|
|
3500
3638
|
}
|
|
3501
3639
|
}
|
|
3502
3640
|
|
|
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
|
-
|
|
3641
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
3642
|
+
import { existsSync as existsSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
3643
|
+
import { dirname as dirname5, join as join3 } from "node:path";
|
|
3644
|
+
|
|
3645
|
+
// ../lsp-core/src/lsp/workspace-markers.ts
|
|
3646
|
+
var GIT_WORKSPACE_MARKER = ".git";
|
|
3647
|
+
var PROJECT_WORKSPACE_MARKERS = [
|
|
3648
|
+
"package.json",
|
|
3649
|
+
"pyproject.toml",
|
|
3650
|
+
"Cargo.toml",
|
|
3651
|
+
"go.mod",
|
|
3652
|
+
"pom.xml",
|
|
3653
|
+
"build.gradle"
|
|
3654
|
+
];
|
|
3655
|
+
var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
|
|
3656
|
+
|
|
3657
|
+
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
3658
|
+
function findWorkspaceRootOutsideContext(directory) {
|
|
3659
|
+
const marked = nearestMarkedAncestor(directory);
|
|
3660
|
+
if (marked !== undefined)
|
|
3661
|
+
return marked;
|
|
3662
|
+
return realpathSync4(nearestExistingAncestor(directory));
|
|
3663
|
+
}
|
|
3664
|
+
function nearestMarkedAncestor(directory) {
|
|
3665
|
+
let current = directory;
|
|
3666
|
+
for (;; ) {
|
|
3667
|
+
if (existsSync6(current) && WORKSPACE_MARKERS.some((marker) => existsSync6(join3(current, marker)))) {
|
|
3668
|
+
return realpathSync4(current);
|
|
3669
|
+
}
|
|
3670
|
+
const parent = dirname5(current);
|
|
3671
|
+
if (parent === current)
|
|
3672
|
+
return;
|
|
3673
|
+
current = parent;
|
|
3518
3674
|
}
|
|
3519
3675
|
}
|
|
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);
|
|
3676
|
+
function nearestExistingAncestor(directory) {
|
|
3677
|
+
let current = directory;
|
|
3678
|
+
while (!existsSync6(current)) {
|
|
3679
|
+
const parent = dirname5(current);
|
|
3680
|
+
if (parent === current)
|
|
3681
|
+
return current;
|
|
3682
|
+
current = parent;
|
|
3683
|
+
}
|
|
3684
|
+
return current;
|
|
3549
3685
|
}
|
|
3550
3686
|
|
|
3551
|
-
// ../lsp-core/src/lsp/config-loader.ts
|
|
3552
|
-
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
|
|
3553
|
-
|
|
3554
3687
|
// ../lsp-core/src/lsp/server-definitions.ts
|
|
3555
3688
|
var LSP_INSTALL_HINTS = {
|
|
3556
3689
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -3596,6 +3729,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
3596
3729
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
3597
3730
|
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
3731
|
};
|
|
3732
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
3733
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
3734
|
+
vue: "bun add -d @vue/language-server",
|
|
3735
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
3736
|
+
oxlint: "bun add -d oxlint",
|
|
3737
|
+
biome: "bun add -d @biomejs/biome",
|
|
3738
|
+
svelte: "bun add -d svelte-language-server",
|
|
3739
|
+
astro: "bun add -d @astrojs/language-server",
|
|
3740
|
+
bash: "bun add -d bash-language-server",
|
|
3741
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
3742
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
3743
|
+
php: "bun add -d intelephense",
|
|
3744
|
+
prisma: "bun add -d prisma",
|
|
3745
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
3746
|
+
pyright: "uv add --dev pyright",
|
|
3747
|
+
basedpyright: "uv add --dev basedpyright",
|
|
3748
|
+
ruff: "uv add --dev ruff",
|
|
3749
|
+
ty: "uv add --dev ty",
|
|
3750
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
3751
|
+
};
|
|
3599
3752
|
var BUILTIN_SERVERS = {
|
|
3600
3753
|
typescript: {
|
|
3601
3754
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -3698,7 +3851,56 @@ var BUILTIN_SERVERS = {
|
|
|
3698
3851
|
}
|
|
3699
3852
|
};
|
|
3700
3853
|
|
|
3854
|
+
// ../lsp-core/src/lsp/server-install-state.ts
|
|
3855
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
3856
|
+
import { dirname as dirname6 } from "node:path";
|
|
3857
|
+
function getInstallDecisionsPath() {
|
|
3858
|
+
return lspRequestContext().installDecisionsPath;
|
|
3859
|
+
}
|
|
3860
|
+
function loadInstallDecisions() {
|
|
3861
|
+
const path = getInstallDecisionsPath();
|
|
3862
|
+
if (!existsSync7(path))
|
|
3863
|
+
return {};
|
|
3864
|
+
try {
|
|
3865
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
3866
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
3867
|
+
} catch {
|
|
3868
|
+
return {};
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
function loadInstallDecision(serverId) {
|
|
3872
|
+
return loadInstallDecisions()[serverId];
|
|
3873
|
+
}
|
|
3874
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
3875
|
+
const decisions = loadInstallDecisions();
|
|
3876
|
+
decisions[serverId] = { decision, decidedAt };
|
|
3877
|
+
writeInstallDecisions(decisions);
|
|
3878
|
+
}
|
|
3879
|
+
function isInstallDecision(value) {
|
|
3880
|
+
return value === "declined" || value === "allowed";
|
|
3881
|
+
}
|
|
3882
|
+
function writeInstallDecisions(decisions) {
|
|
3883
|
+
const path = getInstallDecisionsPath();
|
|
3884
|
+
mkdirSync(dirname6(path), { recursive: true });
|
|
3885
|
+
const tmpPath = `${path}.tmp`;
|
|
3886
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3887
|
+
`, "utf8");
|
|
3888
|
+
renameSync2(tmpPath, path);
|
|
3889
|
+
}
|
|
3890
|
+
function isInstallDecisions(value) {
|
|
3891
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3892
|
+
}
|
|
3893
|
+
function isInstallDecisionRecord(value) {
|
|
3894
|
+
if (!isRecord5(value))
|
|
3895
|
+
return false;
|
|
3896
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3897
|
+
}
|
|
3898
|
+
function isRecord5(value) {
|
|
3899
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3900
|
+
}
|
|
3901
|
+
|
|
3701
3902
|
// ../lsp-core/src/lsp/config-loader.ts
|
|
3903
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
|
|
3702
3904
|
function getProjectConfigPaths() {
|
|
3703
3905
|
return lspRequestContext().projectConfigPaths;
|
|
3704
3906
|
}
|
|
@@ -3706,7 +3908,7 @@ function getUserConfigPath() {
|
|
|
3706
3908
|
return lspRequestContext().userConfigPath;
|
|
3707
3909
|
}
|
|
3708
3910
|
function loadJsonFile(path) {
|
|
3709
|
-
if (!
|
|
3911
|
+
if (!existsSync8(path))
|
|
3710
3912
|
return null;
|
|
3711
3913
|
try {
|
|
3712
3914
|
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
@@ -3894,54 +4096,155 @@ function getDisabledServerIds() {
|
|
|
3894
4096
|
}
|
|
3895
4097
|
|
|
3896
4098
|
// ../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
|
-
|
|
4099
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
4100
|
+
import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
|
|
4101
|
+
var LOCAL_BIN_RULES = [
|
|
4102
|
+
{
|
|
4103
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
4104
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
4105
|
+
},
|
|
4106
|
+
{
|
|
4107
|
+
markers: [
|
|
4108
|
+
"pyproject.toml",
|
|
4109
|
+
"ty.toml",
|
|
4110
|
+
"requirements.txt",
|
|
4111
|
+
"setup.py",
|
|
4112
|
+
"setup.cfg",
|
|
4113
|
+
"Pipfile",
|
|
4114
|
+
"pyrightconfig.json",
|
|
4115
|
+
"ruff.toml",
|
|
4116
|
+
".ruff.toml"
|
|
4117
|
+
],
|
|
4118
|
+
binDirs: [
|
|
4119
|
+
join4(".venv", "bin"),
|
|
4120
|
+
join4(".venv", "Scripts"),
|
|
4121
|
+
join4("venv", "bin"),
|
|
4122
|
+
join4("venv", "Scripts"),
|
|
4123
|
+
join4(".env", "bin"),
|
|
4124
|
+
join4(".env", "Scripts")
|
|
4125
|
+
]
|
|
4126
|
+
},
|
|
4127
|
+
{
|
|
4128
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
4129
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
4130
|
+
},
|
|
4131
|
+
{
|
|
4132
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
4133
|
+
binDirs: ["bin"]
|
|
3908
4134
|
}
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
4135
|
+
];
|
|
4136
|
+
var resolutionCache = new Map;
|
|
4137
|
+
var probeCount = 0;
|
|
4138
|
+
function probe(path) {
|
|
4139
|
+
probeCount += 1;
|
|
4140
|
+
return existsSync9(path);
|
|
4141
|
+
}
|
|
4142
|
+
function executableSuffixes(platform, pathExt) {
|
|
4143
|
+
if (platform !== "win32")
|
|
4144
|
+
return [""];
|
|
4145
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
4146
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
4147
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
4148
|
+
}
|
|
4149
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
4150
|
+
for (const suffix of suffixes) {
|
|
4151
|
+
const candidate = join4(directory, command + suffix);
|
|
4152
|
+
if (probe(candidate))
|
|
4153
|
+
return candidate;
|
|
4154
|
+
}
|
|
4155
|
+
return null;
|
|
4156
|
+
}
|
|
4157
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
4158
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
4159
|
+
let current = resolve7(workingDirectory);
|
|
4160
|
+
while (true) {
|
|
4161
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
4162
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
4163
|
+
continue;
|
|
4164
|
+
for (const binDir of rule.binDirs) {
|
|
4165
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
4166
|
+
if (found !== null)
|
|
4167
|
+
return found;
|
|
4168
|
+
}
|
|
3918
4169
|
}
|
|
4170
|
+
if (probe(join4(current, ".git")))
|
|
4171
|
+
return null;
|
|
4172
|
+
if (boundary !== undefined && current === boundary)
|
|
4173
|
+
return null;
|
|
4174
|
+
const parent = dirname7(current);
|
|
4175
|
+
if (parent === current)
|
|
4176
|
+
return null;
|
|
4177
|
+
current = parent;
|
|
3919
4178
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
4179
|
+
}
|
|
4180
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
4181
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
4182
|
+
if (platform === "win32" && !pathEnv) {
|
|
3922
4183
|
pathEnv = process.env["Path"] ?? "";
|
|
3923
4184
|
}
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
}
|
|
4185
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
4186
|
+
if (entry.length === 0)
|
|
4187
|
+
continue;
|
|
4188
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
4189
|
+
if (found !== null)
|
|
4190
|
+
return found;
|
|
3931
4191
|
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
4192
|
+
return null;
|
|
4193
|
+
}
|
|
4194
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
4195
|
+
if (command.length === 0)
|
|
4196
|
+
return null;
|
|
4197
|
+
const [cmd] = command;
|
|
4198
|
+
if (cmd === undefined || cmd.length === 0)
|
|
4199
|
+
return null;
|
|
4200
|
+
const platform = options.platform ?? process.platform;
|
|
4201
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
4202
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
4203
|
+
const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
4204
|
+
return probe(explicit) ? explicit : null;
|
|
4205
|
+
}
|
|
4206
|
+
const cacheKey = JSON.stringify([
|
|
4207
|
+
workingDirectory ?? "",
|
|
4208
|
+
cmd,
|
|
4209
|
+
platform,
|
|
4210
|
+
options.stopAt ?? "",
|
|
4211
|
+
options.pathExt ?? "",
|
|
4212
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
4213
|
+
]);
|
|
4214
|
+
const cached = resolutionCache.get(cacheKey);
|
|
4215
|
+
if (cached !== undefined)
|
|
4216
|
+
return cached;
|
|
4217
|
+
let resolved = null;
|
|
4218
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
4219
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
4220
|
+
}
|
|
4221
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
4222
|
+
if (resolved === null && cmd === "node")
|
|
4223
|
+
resolved = cmd;
|
|
4224
|
+
resolutionCache.set(cacheKey, resolved);
|
|
4225
|
+
return resolved;
|
|
4226
|
+
}
|
|
4227
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
4228
|
+
if (command.length === 0)
|
|
4229
|
+
return false;
|
|
4230
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
3935
4231
|
}
|
|
3936
4232
|
|
|
3937
4233
|
// ../lsp-core/src/lsp/server-resolution.ts
|
|
4234
|
+
function withResolvedCommand(command, binaryPath) {
|
|
4235
|
+
return [binaryPath, ...command.slice(1)];
|
|
4236
|
+
}
|
|
3938
4237
|
function findServerForExtension(ext) {
|
|
3939
4238
|
const servers = getMergedServers();
|
|
4239
|
+
const workingDirectory = contextCwd();
|
|
3940
4240
|
for (const server2 of servers) {
|
|
3941
|
-
if (server2.extensions.includes(ext)
|
|
4241
|
+
if (!server2.extensions.includes(ext))
|
|
4242
|
+
continue;
|
|
4243
|
+
const binaryPath = resolveServerBinary(server2.command, workingDirectory);
|
|
4244
|
+
if (binaryPath !== null) {
|
|
3942
4245
|
const resolvedServer = {
|
|
3943
4246
|
id: server2.id,
|
|
3944
|
-
command: server2.command,
|
|
4247
|
+
command: withResolvedCommand(server2.command, binaryPath),
|
|
3945
4248
|
extensions: server2.extensions,
|
|
3946
4249
|
priority: server2.priority
|
|
3947
4250
|
};
|
|
@@ -3988,6 +4291,7 @@ function findServerForExtension(ext) {
|
|
|
3988
4291
|
function getAllServers() {
|
|
3989
4292
|
const servers = getMergedServers();
|
|
3990
4293
|
const disabled = getDisabledServerIds();
|
|
4294
|
+
const workingDirectory = contextCwd();
|
|
3991
4295
|
const result = [];
|
|
3992
4296
|
const seen = new Set;
|
|
3993
4297
|
for (const server2 of servers) {
|
|
@@ -3995,7 +4299,7 @@ function getAllServers() {
|
|
|
3995
4299
|
continue;
|
|
3996
4300
|
result.push({
|
|
3997
4301
|
id: server2.id,
|
|
3998
|
-
installed: isServerInstalled(server2.command),
|
|
4302
|
+
installed: isServerInstalled(server2.command, workingDirectory),
|
|
3999
4303
|
extensions: server2.extensions,
|
|
4000
4304
|
disabled: false,
|
|
4001
4305
|
source: server2.source,
|
|
@@ -4009,7 +4313,7 @@ function getAllServers() {
|
|
|
4009
4313
|
const builtin = BUILTIN_SERVERS[id];
|
|
4010
4314
|
result.push({
|
|
4011
4315
|
id,
|
|
4012
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
4316
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
4013
4317
|
extensions: builtin?.extensions ?? [],
|
|
4014
4318
|
disabled: true,
|
|
4015
4319
|
source: "disabled",
|
|
@@ -4020,7 +4324,6 @@ function getAllServers() {
|
|
|
4020
4324
|
}
|
|
4021
4325
|
|
|
4022
4326
|
// ../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
4327
|
function isDirectoryPath(filePath) {
|
|
4025
4328
|
try {
|
|
4026
4329
|
return statSync3(filePath).isDirectory();
|
|
@@ -4029,32 +4332,90 @@ function isDirectoryPath(filePath) {
|
|
|
4029
4332
|
}
|
|
4030
4333
|
}
|
|
4031
4334
|
function findWorkspaceRoot(filePath) {
|
|
4032
|
-
const
|
|
4335
|
+
const cwd = contextCwd();
|
|
4336
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4033
4337
|
let dir = abs;
|
|
4034
4338
|
if (!isDirectoryPath(dir)) {
|
|
4035
|
-
dir =
|
|
4036
|
-
}
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4339
|
+
dir = dirname8(dir);
|
|
4340
|
+
}
|
|
4341
|
+
if (!isPathInside(cwd, abs))
|
|
4342
|
+
return findWorkspaceRootOutsideContext(dir);
|
|
4343
|
+
const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
|
|
4344
|
+
let nearestPackageRoot;
|
|
4345
|
+
while (isPathInside(cwd, dir)) {
|
|
4346
|
+
const canonicalDir = existingDirectoryInsideContext(dir, cwd);
|
|
4347
|
+
if (canonicalDir !== undefined) {
|
|
4348
|
+
if (existsSync10(join5(dir, GIT_WORKSPACE_MARKER))) {
|
|
4349
|
+
return canonicalDir;
|
|
4350
|
+
}
|
|
4351
|
+
if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
|
|
4352
|
+
nearestPackageRoot = canonicalDir;
|
|
4042
4353
|
}
|
|
4043
4354
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4355
|
+
if (dir === cwd)
|
|
4356
|
+
break;
|
|
4357
|
+
dir = dirname8(dir);
|
|
4046
4358
|
}
|
|
4047
|
-
return
|
|
4359
|
+
return nearestPackageRoot ?? fallbackRoot;
|
|
4360
|
+
}
|
|
4361
|
+
function hasProjectWorkspaceMarker(directory) {
|
|
4362
|
+
return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync10(join5(directory, marker)));
|
|
4363
|
+
}
|
|
4364
|
+
function resolveReadablePathInsideContext(filePath) {
|
|
4365
|
+
const cwd = contextCwd();
|
|
4366
|
+
const abs = resolve8(cwd, filePath);
|
|
4367
|
+
if (isPathInside(cwd, abs))
|
|
4368
|
+
return abs;
|
|
4369
|
+
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
4370
|
+
if (rebased !== undefined)
|
|
4371
|
+
return rebased;
|
|
4372
|
+
return canonicalizeExistingOrNearestAncestor(abs);
|
|
4048
4373
|
}
|
|
4049
4374
|
function resolvePathInsideContext(filePath) {
|
|
4050
4375
|
const cwd = contextCwd();
|
|
4051
|
-
const abs =
|
|
4376
|
+
const abs = resolveReadablePathInsideContext(filePath);
|
|
4052
4377
|
const canonical = canonicalizeExistingOrNearestAncestor(abs);
|
|
4053
4378
|
if (!isPathInside(cwd, canonical)) {
|
|
4054
4379
|
throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
|
|
4055
4380
|
}
|
|
4056
4381
|
return canonical;
|
|
4057
4382
|
}
|
|
4383
|
+
function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
4384
|
+
let current = path;
|
|
4385
|
+
const suffix = [];
|
|
4386
|
+
while (true) {
|
|
4387
|
+
if (existsSync10(current)) {
|
|
4388
|
+
const canonical = realpathSync5(current);
|
|
4389
|
+
if (isPathInside(cwd, canonical))
|
|
4390
|
+
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
4391
|
+
}
|
|
4392
|
+
const parent = dirname8(current);
|
|
4393
|
+
if (parent === current)
|
|
4394
|
+
return;
|
|
4395
|
+
suffix.unshift(basename3(current));
|
|
4396
|
+
current = parent;
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
function existingDirectoryInsideContext(directory, cwd) {
|
|
4400
|
+
if (!existsSync10(directory))
|
|
4401
|
+
return;
|
|
4402
|
+
const canonical = realpathSync5(directory);
|
|
4403
|
+
if (!statSync3(canonical).isDirectory())
|
|
4404
|
+
return;
|
|
4405
|
+
return isPathInside(cwd, canonical) ? canonical : undefined;
|
|
4406
|
+
}
|
|
4407
|
+
function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
4408
|
+
let current = directory;
|
|
4409
|
+
while (isPathInside(cwd, current)) {
|
|
4410
|
+
const canonical = existingDirectoryInsideContext(current, cwd);
|
|
4411
|
+
if (canonical !== undefined)
|
|
4412
|
+
return canonical;
|
|
4413
|
+
if (current === cwd)
|
|
4414
|
+
return;
|
|
4415
|
+
current = dirname8(current);
|
|
4416
|
+
}
|
|
4417
|
+
return;
|
|
4418
|
+
}
|
|
4058
4419
|
function formatServerLookupError(result) {
|
|
4059
4420
|
if (result.status === "not_installed") {
|
|
4060
4421
|
return formatNotInstalled(result);
|
|
@@ -4078,6 +4439,19 @@ function formatServerLookupError(result) {
|
|
|
4078
4439
|
].join(`
|
|
4079
4440
|
`);
|
|
4080
4441
|
}
|
|
4442
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4443
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4444
|
+
if (localHint === undefined) {
|
|
4445
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4446
|
+
}
|
|
4447
|
+
return [
|
|
4448
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4449
|
+
` ${localHint}`,
|
|
4450
|
+
"",
|
|
4451
|
+
"Or install it globally:",
|
|
4452
|
+
` ${installHint}`
|
|
4453
|
+
];
|
|
4454
|
+
}
|
|
4081
4455
|
function formatNotInstalled(result) {
|
|
4082
4456
|
const { server: server2, installHint } = result;
|
|
4083
4457
|
const extensions = server2.extensions.join(", ");
|
|
@@ -4092,19 +4466,19 @@ function formatNotInstalled(result) {
|
|
|
4092
4466
|
`Command not found: ${server2.command[0]}`,
|
|
4093
4467
|
""
|
|
4094
4468
|
];
|
|
4469
|
+
const installOptions = formatInstallOptions(server2.id, installHint);
|
|
4095
4470
|
if (decision === "allowed") {
|
|
4096
4471
|
return [
|
|
4097
4472
|
...header,
|
|
4098
4473
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
4099
|
-
|
|
4474
|
+
...installOptions.slice(1)
|
|
4100
4475
|
].join(`
|
|
4101
4476
|
`);
|
|
4102
4477
|
}
|
|
4103
4478
|
if (!context.capabilities.installDecisionTool) {
|
|
4104
4479
|
return [
|
|
4105
4480
|
...header,
|
|
4106
|
-
|
|
4107
|
-
` ${installHint}`,
|
|
4481
|
+
...installOptions,
|
|
4108
4482
|
"",
|
|
4109
4483
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4110
4484
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -4113,8 +4487,7 @@ function formatNotInstalled(result) {
|
|
|
4113
4487
|
}
|
|
4114
4488
|
return [
|
|
4115
4489
|
...header,
|
|
4116
|
-
|
|
4117
|
-
` ${installHint}`,
|
|
4490
|
+
...installOptions,
|
|
4118
4491
|
"",
|
|
4119
4492
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4120
4493
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
@@ -4125,7 +4498,7 @@ function formatNotInstalled(result) {
|
|
|
4125
4498
|
].join(`
|
|
4126
4499
|
`);
|
|
4127
4500
|
}
|
|
4128
|
-
var
|
|
4501
|
+
var READ_ONLY_TOOLS = new Set([
|
|
4129
4502
|
"diagnostics",
|
|
4130
4503
|
"definition",
|
|
4131
4504
|
"references",
|
|
@@ -4134,7 +4507,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
|
|
|
4134
4507
|
"prepareRename"
|
|
4135
4508
|
]);
|
|
4136
4509
|
async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
4137
|
-
const absPath = resolvePathInsideContext(filePath);
|
|
4510
|
+
const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
|
|
4138
4511
|
if (isDirectoryPath(absPath)) {
|
|
4139
4512
|
throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
|
|
4140
4513
|
}
|
|
@@ -4149,9 +4522,9 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4149
4522
|
const acquireAndCall = async (allowRetry) => {
|
|
4150
4523
|
const client = await manager.getClient(root, server2, options.signal);
|
|
4151
4524
|
try {
|
|
4152
|
-
return await fn(client, root);
|
|
4525
|
+
return await fn(client, root, absPath);
|
|
4153
4526
|
} catch (err) {
|
|
4154
|
-
if (allowRetry &&
|
|
4527
|
+
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
4155
4528
|
manager.invalidateClient(root, server2.id, client);
|
|
4156
4529
|
return acquireAndCall(false);
|
|
4157
4530
|
}
|
|
@@ -4169,8 +4542,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4169
4542
|
}
|
|
4170
4543
|
|
|
4171
4544
|
// ../lsp-core/src/lsp/directory-diagnostics.ts
|
|
4172
|
-
import { existsSync as
|
|
4173
|
-
import { join as
|
|
4545
|
+
import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
|
|
4546
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
4174
4547
|
|
|
4175
4548
|
// ../lsp-core/src/lsp/formatters.ts
|
|
4176
4549
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -4300,7 +4673,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
4300
4673
|
for (const entry of entries) {
|
|
4301
4674
|
if (files.length >= maxFiles)
|
|
4302
4675
|
return;
|
|
4303
|
-
const fullPath =
|
|
4676
|
+
const fullPath = join6(currentDir, entry);
|
|
4304
4677
|
let stat;
|
|
4305
4678
|
try {
|
|
4306
4679
|
stat = lstatSync4(fullPath);
|
|
@@ -4325,8 +4698,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4325
4698
|
if (!extension.startsWith(".")) {
|
|
4326
4699
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
4327
4700
|
}
|
|
4328
|
-
const absDir =
|
|
4329
|
-
if (!
|
|
4701
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
4702
|
+
if (!existsSync11(absDir)) {
|
|
4330
4703
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
4331
4704
|
}
|
|
4332
4705
|
const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
|
|
@@ -4413,7 +4786,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4413
4786
|
|
|
4414
4787
|
// ../lsp-core/src/lsp/infer-extension.ts
|
|
4415
4788
|
import { lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
4416
|
-
import { join as
|
|
4789
|
+
import { join as join7 } from "node:path";
|
|
4417
4790
|
var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
4418
4791
|
var MAX_SCAN_ENTRIES = 500;
|
|
4419
4792
|
function inferExtensionFromDirectory(directory) {
|
|
@@ -4431,7 +4804,7 @@ function inferExtensionFromDirectory(directory) {
|
|
|
4431
4804
|
for (const entry of entries) {
|
|
4432
4805
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
4433
4806
|
return;
|
|
4434
|
-
const fullPath =
|
|
4807
|
+
const fullPath = join7(dir, entry);
|
|
4435
4808
|
let stat;
|
|
4436
4809
|
try {
|
|
4437
4810
|
stat = lstatSync5(fullPath);
|
|
@@ -4606,7 +4979,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4606
4979
|
const filePath = requireString(params, "filePath");
|
|
4607
4980
|
const severity = severityFilter(params);
|
|
4608
4981
|
try {
|
|
4609
|
-
const absPath =
|
|
4982
|
+
const absPath = resolveReadablePathInsideContext(filePath);
|
|
4610
4983
|
if (isDirectoryPath(absPath)) {
|
|
4611
4984
|
const extension = inferExtensionFromDirectory(absPath);
|
|
4612
4985
|
if (!extension) {
|
|
@@ -4635,7 +5008,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4635
5008
|
};
|
|
4636
5009
|
return text(output2.output, details2);
|
|
4637
5010
|
}
|
|
4638
|
-
const result = await withLspClient(filePath, async (client) => client.diagnostics(
|
|
5011
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
4639
5012
|
if (result.transientError) {
|
|
4640
5013
|
const message = result.transientError.message;
|
|
4641
5014
|
const details2 = {
|
|
@@ -4682,6 +5055,96 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4682
5055
|
throw error;
|
|
4683
5056
|
}
|
|
4684
5057
|
}
|
|
5058
|
+
// ../lsp-core/src/lsp/format-document.ts
|
|
5059
|
+
import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5060
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
5061
|
+
tabSize: 4,
|
|
5062
|
+
insertSpaces: false,
|
|
5063
|
+
trimTrailingWhitespace: true,
|
|
5064
|
+
insertFinalNewline: true,
|
|
5065
|
+
trimFinalNewlines: true
|
|
5066
|
+
};
|
|
5067
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
5068
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
5069
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
5070
|
+
if (edits === null)
|
|
5071
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
5072
|
+
if (edits.length === 0)
|
|
5073
|
+
return UNCHANGED;
|
|
5074
|
+
const before = readFileSync5(filePath, "utf-8");
|
|
5075
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
5076
|
+
if (normalized.text === before)
|
|
5077
|
+
return UNCHANGED;
|
|
5078
|
+
writeAtomically(filePath, normalized.text);
|
|
5079
|
+
await client.openFile(filePath);
|
|
5080
|
+
return {
|
|
5081
|
+
status: "formatted",
|
|
5082
|
+
...lineDelta(normalized.edits)
|
|
5083
|
+
};
|
|
5084
|
+
}
|
|
5085
|
+
function lineDelta(edits) {
|
|
5086
|
+
let linesAdded = 0;
|
|
5087
|
+
let linesRemoved = 0;
|
|
5088
|
+
for (const edit of edits) {
|
|
5089
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
5090
|
+
linesAdded += edit.newText.split(`
|
|
5091
|
+
`).length;
|
|
5092
|
+
}
|
|
5093
|
+
return { linesAdded, linesRemoved };
|
|
5094
|
+
}
|
|
5095
|
+
function writeAtomically(filePath, content) {
|
|
5096
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
5097
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
5098
|
+
try {
|
|
5099
|
+
renameSync3(tempPath, filePath);
|
|
5100
|
+
} catch (error) {
|
|
5101
|
+
try {
|
|
5102
|
+
unlinkSync(tempPath);
|
|
5103
|
+
} catch {}
|
|
5104
|
+
throw error;
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
|
|
5108
|
+
// ../lsp-core/src/tools/format.ts
|
|
5109
|
+
async function executeLspFormat(params, signal) {
|
|
5110
|
+
const filePath = requireString(params, "filePath");
|
|
5111
|
+
try {
|
|
5112
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
5113
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
5114
|
+
} catch (error) {
|
|
5115
|
+
const missingDependency = missingDependencyResult(error, {
|
|
5116
|
+
filePath,
|
|
5117
|
+
status: "unavailable",
|
|
5118
|
+
reason: "server_unavailable",
|
|
5119
|
+
linesAdded: 0,
|
|
5120
|
+
linesRemoved: 0
|
|
5121
|
+
});
|
|
5122
|
+
if (missingDependency)
|
|
5123
|
+
return missingDependency;
|
|
5124
|
+
throw error;
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
function formatDetails(filePath, result) {
|
|
5128
|
+
if (result.status === "unavailable") {
|
|
5129
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
5130
|
+
}
|
|
5131
|
+
return {
|
|
5132
|
+
filePath,
|
|
5133
|
+
status: result.status,
|
|
5134
|
+
linesAdded: result.linesAdded,
|
|
5135
|
+
linesRemoved: result.linesRemoved
|
|
5136
|
+
};
|
|
5137
|
+
}
|
|
5138
|
+
function describeResult(filePath, result) {
|
|
5139
|
+
if (result.status === "unavailable") {
|
|
5140
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
5141
|
+
}
|
|
5142
|
+
if (result.status === "unchanged") {
|
|
5143
|
+
return `Already formatted: ${filePath}`;
|
|
5144
|
+
}
|
|
5145
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
5146
|
+
}
|
|
5147
|
+
|
|
4685
5148
|
// ../lsp-core/src/tools/install-decision.ts
|
|
4686
5149
|
async function executeLspInstallDecision(params) {
|
|
4687
5150
|
const serverId = requireString(params, "server_id");
|
|
@@ -4710,7 +5173,7 @@ async function executeLspGotoDefinition(params, signal) {
|
|
|
4710
5173
|
const line = requireNumber(params, "line");
|
|
4711
5174
|
const character = requireNumber(params, "character");
|
|
4712
5175
|
try {
|
|
4713
|
-
const result = await withLspClient(filePath, async (client) => client.definition(
|
|
5176
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
|
|
4714
5177
|
const locations = !result ? [] : Array.isArray(result) ? result : [result];
|
|
4715
5178
|
const details = { filePath, line, character, locations };
|
|
4716
5179
|
if (locations.length === 0)
|
|
@@ -4735,7 +5198,7 @@ async function executeLspFindReferences(params, signal) {
|
|
|
4735
5198
|
const character = requireNumber(params, "character");
|
|
4736
5199
|
const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
|
|
4737
5200
|
try {
|
|
4738
|
-
const result = await withLspClient(filePath, async (client) => client.references(
|
|
5201
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
|
|
4739
5202
|
const references = Array.isArray(result) ? result : [];
|
|
4740
5203
|
const total = references.length;
|
|
4741
5204
|
const truncated = total > DEFAULT_MAX_REFERENCES;
|
|
@@ -4777,7 +5240,7 @@ async function executeLspPrepareRename(params, signal) {
|
|
|
4777
5240
|
const line = requireNumber(params, "line");
|
|
4778
5241
|
const character = requireNumber(params, "character");
|
|
4779
5242
|
try {
|
|
4780
|
-
const result = await withLspClient(filePath, async (client) => client.prepareRename(
|
|
5243
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
|
|
4781
5244
|
const details = { filePath, line, character, result };
|
|
4782
5245
|
return text(formatPrepareRenameResult(result), details);
|
|
4783
5246
|
} catch (error) {
|
|
@@ -4798,7 +5261,7 @@ async function executeLspRename(params, signal) {
|
|
|
4798
5261
|
const character = requireNumber(params, "character");
|
|
4799
5262
|
const newName = requireString(params, "newName");
|
|
4800
5263
|
try {
|
|
4801
|
-
const result = await withLspClient(filePath, async (client) => client.rename(
|
|
5264
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
|
|
4802
5265
|
const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
|
|
4803
5266
|
return text(formatApplyResult(result.apply), details, !result.apply.success);
|
|
4804
5267
|
} catch (error) {
|
|
@@ -4878,7 +5341,7 @@ async function executeLspSymbols(params, signal) {
|
|
|
4878
5341
|
const symbols2 = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
4879
5342
|
return formatSymbolsResult(filePath, scope, symbols2, limit, query);
|
|
4880
5343
|
}
|
|
4881
|
-
const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(
|
|
5344
|
+
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
4882
5345
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
4883
5346
|
} catch (error) {
|
|
4884
5347
|
const query = optionalString(params, "query");
|
|
@@ -5014,6 +5477,16 @@ var LSP_MCP_TOOLS = [
|
|
|
5014
5477
|
}, ["filePath", "line", "character", "newName"]),
|
|
5015
5478
|
execute: executeLspRename
|
|
5016
5479
|
},
|
|
5480
|
+
{
|
|
5481
|
+
name: "format",
|
|
5482
|
+
aliases: ["lsp_format"],
|
|
5483
|
+
title: "LSP Format",
|
|
5484
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
5485
|
+
inputSchema: objectSchema({
|
|
5486
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
5487
|
+
}, ["filePath"]),
|
|
5488
|
+
execute: executeLspFormat
|
|
5489
|
+
},
|
|
5017
5490
|
{
|
|
5018
5491
|
name: "install_decision",
|
|
5019
5492
|
aliases: ["lsp_install_decision"],
|
|
@@ -5113,11 +5586,10 @@ function requestedProtocolVersion(params) {
|
|
|
5113
5586
|
// src/daemon-client.ts
|
|
5114
5587
|
import { connect } from "node:net";
|
|
5115
5588
|
import { homedir as homedir3 } from "node:os";
|
|
5116
|
-
import { join as
|
|
5589
|
+
import { join as join8 } from "node:path";
|
|
5117
5590
|
|
|
5118
5591
|
// src/daemon-request-error.ts
|
|
5119
5592
|
class DaemonRequestError extends Error {
|
|
5120
|
-
requestWritten;
|
|
5121
5593
|
constructor(message, requestWritten) {
|
|
5122
5594
|
super(message);
|
|
5123
5595
|
this.name = "DaemonRequestError";
|
|
@@ -5140,7 +5612,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
|
|
|
5140
5612
|
}
|
|
5141
5613
|
|
|
5142
5614
|
class DaemonRequestTimedOutError extends DaemonRequestError {
|
|
5143
|
-
timeoutMs;
|
|
5144
5615
|
constructor(requestWritten, timeoutMs) {
|
|
5145
5616
|
super("daemon request timed out", requestWritten);
|
|
5146
5617
|
this.name = "DaemonRequestTimedOutError";
|
|
@@ -5192,9 +5663,9 @@ function errorText(error) {
|
|
|
5192
5663
|
|
|
5193
5664
|
// src/ensure-daemon.ts
|
|
5194
5665
|
import { spawn as spawn2 } from "node:child_process";
|
|
5195
|
-
import { closeSync as closeSync2, existsSync as
|
|
5666
|
+
import { closeSync as closeSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
|
|
5196
5667
|
import { Socket } from "node:net";
|
|
5197
|
-
import { dirname as
|
|
5668
|
+
import { dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
|
|
5198
5669
|
import { argv0, execPath } from "node:process";
|
|
5199
5670
|
|
|
5200
5671
|
// src/ipc-protocol.ts
|
|
@@ -5208,25 +5679,23 @@ import {
|
|
|
5208
5679
|
lstatSync as lstatSync6,
|
|
5209
5680
|
mkdirSync as mkdirSync2,
|
|
5210
5681
|
openSync,
|
|
5211
|
-
readFileSync as
|
|
5212
|
-
unlinkSync,
|
|
5682
|
+
readFileSync as readFileSync6,
|
|
5683
|
+
unlinkSync as unlinkSync2,
|
|
5213
5684
|
writeSync
|
|
5214
5685
|
} from "node:fs";
|
|
5215
|
-
import { dirname as
|
|
5686
|
+
import { dirname as dirname9 } from "node:path";
|
|
5216
5687
|
var OMO_DAEMON_PROTOCOL_VERSION = 1;
|
|
5217
5688
|
var AUTH_ERROR_CODE = -32001;
|
|
5218
5689
|
var PROTOCOL_ERROR_CODE = -32002;
|
|
5219
5690
|
var AUTH_TOKEN_BYTES = 32;
|
|
5220
5691
|
|
|
5221
5692
|
class UnsafePrivateDirectoryError extends Error {
|
|
5222
|
-
path;
|
|
5223
|
-
reason;
|
|
5224
|
-
name = "UnsafePrivateDirectoryError";
|
|
5225
|
-
code = "unsafe_private_directory";
|
|
5226
5693
|
constructor(path, reason) {
|
|
5227
5694
|
super(`unsafe private directory ${path}: ${reason}`);
|
|
5228
5695
|
this.path = path;
|
|
5229
5696
|
this.reason = reason;
|
|
5697
|
+
this.name = "UnsafePrivateDirectoryError";
|
|
5698
|
+
this.code = "unsafe_private_directory";
|
|
5230
5699
|
}
|
|
5231
5700
|
}
|
|
5232
5701
|
function authEnvelope(token) {
|
|
@@ -5234,7 +5703,7 @@ function authEnvelope(token) {
|
|
|
5234
5703
|
}
|
|
5235
5704
|
function readAuthToken(paths) {
|
|
5236
5705
|
try {
|
|
5237
|
-
const token =
|
|
5706
|
+
const token = readFileSync6(paths.auth, "utf8").trim();
|
|
5238
5707
|
return token.length > 0 ? token : null;
|
|
5239
5708
|
} catch (error) {
|
|
5240
5709
|
if (error instanceof Error)
|
|
@@ -5250,7 +5719,7 @@ function readOrCreateAuthToken(paths) {
|
|
|
5250
5719
|
}
|
|
5251
5720
|
function rotateAuthToken(paths) {
|
|
5252
5721
|
try {
|
|
5253
|
-
|
|
5722
|
+
unlinkSync2(paths.auth);
|
|
5254
5723
|
} catch (error) {
|
|
5255
5724
|
if (!(error instanceof Error))
|
|
5256
5725
|
throw error;
|
|
@@ -5322,7 +5791,7 @@ function setPrivateFileMode(path) {
|
|
|
5322
5791
|
chmodSync(path, 384);
|
|
5323
5792
|
}
|
|
5324
5793
|
function createAuthToken(paths) {
|
|
5325
|
-
ensurePrivateDirectory(
|
|
5794
|
+
ensurePrivateDirectory(dirname9(paths.auth));
|
|
5326
5795
|
const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
|
|
5327
5796
|
let fd;
|
|
5328
5797
|
try {
|
|
@@ -5403,27 +5872,25 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
5403
5872
|
|
|
5404
5873
|
// src/runtime-contract.ts
|
|
5405
5874
|
import { statSync as statSync4 } from "node:fs";
|
|
5406
|
-
import { isAbsolute as
|
|
5875
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
5407
5876
|
var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
|
|
5408
5877
|
var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
|
|
5409
5878
|
var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
5410
5879
|
var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
5411
5880
|
|
|
5412
5881
|
class InvalidRuntimeOverrideError extends Error {
|
|
5413
|
-
code = "invalid_runtime_override";
|
|
5414
|
-
reason;
|
|
5415
5882
|
constructor(reason, message) {
|
|
5416
5883
|
super(message);
|
|
5884
|
+
this.code = "invalid_runtime_override";
|
|
5417
5885
|
this.name = "InvalidRuntimeOverrideError";
|
|
5418
5886
|
this.reason = reason;
|
|
5419
5887
|
}
|
|
5420
5888
|
}
|
|
5421
5889
|
|
|
5422
5890
|
class InvalidDaemonVersionError extends Error {
|
|
5423
|
-
code = "invalid_daemon_version";
|
|
5424
|
-
version;
|
|
5425
5891
|
constructor(version) {
|
|
5426
5892
|
super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
|
|
5893
|
+
this.code = "invalid_daemon_version";
|
|
5427
5894
|
this.name = "InvalidDaemonVersionError";
|
|
5428
5895
|
this.version = version;
|
|
5429
5896
|
}
|
|
@@ -5442,12 +5909,12 @@ function resolveDaemonRuntime(env, defaults) {
|
|
|
5442
5909
|
throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
|
|
5443
5910
|
}
|
|
5444
5911
|
if (!hasCliOverride || !hasVersionOverride) {
|
|
5445
|
-
if (!
|
|
5912
|
+
if (!isAbsolute4(defaults.cliPath)) {
|
|
5446
5913
|
throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
|
|
5447
5914
|
}
|
|
5448
5915
|
return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
|
|
5449
5916
|
}
|
|
5450
|
-
if (!
|
|
5917
|
+
if (!isAbsolute4(cliOverride)) {
|
|
5451
5918
|
throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
|
|
5452
5919
|
}
|
|
5453
5920
|
let cliStats;
|
|
@@ -5469,10 +5936,9 @@ var requireFromHere = createRequire(import.meta.url);
|
|
|
5469
5936
|
var MAX_SOCKET_PATH_LENGTH = 100;
|
|
5470
5937
|
|
|
5471
5938
|
class InvalidDaemonDirectoryError extends Error {
|
|
5472
|
-
code = "invalid_daemon_directory";
|
|
5473
|
-
directory;
|
|
5474
5939
|
constructor(directory) {
|
|
5475
5940
|
super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
|
|
5941
|
+
this.code = "invalid_daemon_directory";
|
|
5476
5942
|
this.name = "InvalidDaemonDirectoryError";
|
|
5477
5943
|
this.directory = directory;
|
|
5478
5944
|
}
|
|
@@ -5626,7 +6092,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5626
6092
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
5627
6093
|
}
|
|
5628
6094
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
5629
|
-
return new Promise((
|
|
6095
|
+
return new Promise((resolve10) => {
|
|
5630
6096
|
const socket = new Socket;
|
|
5631
6097
|
let settled = false;
|
|
5632
6098
|
let timer;
|
|
@@ -5638,7 +6104,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5638
6104
|
clearTimeout(timer);
|
|
5639
6105
|
signal?.removeEventListener("abort", onAbort);
|
|
5640
6106
|
socket.destroy();
|
|
5641
|
-
|
|
6107
|
+
resolve10(value);
|
|
5642
6108
|
};
|
|
5643
6109
|
const onAbort = () => finish(null);
|
|
5644
6110
|
const decoder = createLineDecoder((message) => {
|
|
@@ -5662,12 +6128,13 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
5662
6128
|
});
|
|
5663
6129
|
}
|
|
5664
6130
|
function spawnDaemonProcess(paths) {
|
|
5665
|
-
mkdirSync3(
|
|
6131
|
+
mkdirSync3(dirname10(paths.log), { recursive: true });
|
|
5666
6132
|
const logFd = openSync2(paths.log, "a");
|
|
5667
6133
|
try {
|
|
5668
6134
|
const child = spawn2(resolveDaemonNodeExecutable(), [paths.cliPath, "daemon"], {
|
|
5669
6135
|
detached: true,
|
|
5670
|
-
stdio: ["ignore", logFd, logFd]
|
|
6136
|
+
stdio: ["ignore", logFd, logFd],
|
|
6137
|
+
windowsHide: true
|
|
5671
6138
|
});
|
|
5672
6139
|
child.once("spawn", () => closeSync2(logFd));
|
|
5673
6140
|
child.once("error", (error) => {
|
|
@@ -5681,10 +6148,10 @@ function spawnDaemonProcess(paths) {
|
|
|
5681
6148
|
throw error;
|
|
5682
6149
|
}
|
|
5683
6150
|
}
|
|
5684
|
-
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists =
|
|
6151
|
+
function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync12) {
|
|
5685
6152
|
if (pathExists(cachedExecPath))
|
|
5686
6153
|
return cachedExecPath;
|
|
5687
|
-
if (
|
|
6154
|
+
if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
|
|
5688
6155
|
return originalArgv0;
|
|
5689
6156
|
return "node";
|
|
5690
6157
|
}
|
|
@@ -5697,7 +6164,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
5697
6164
|
};
|
|
5698
6165
|
}
|
|
5699
6166
|
function sleepWithSignal(ms, signal) {
|
|
5700
|
-
return new Promise((
|
|
6167
|
+
return new Promise((resolve10) => {
|
|
5701
6168
|
let settled = false;
|
|
5702
6169
|
const finish = () => {
|
|
5703
6170
|
if (settled)
|
|
@@ -5705,7 +6172,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
5705
6172
|
settled = true;
|
|
5706
6173
|
clearTimeout(timer);
|
|
5707
6174
|
signal?.removeEventListener("abort", finish);
|
|
5708
|
-
|
|
6175
|
+
resolve10();
|
|
5709
6176
|
};
|
|
5710
6177
|
const timer = setTimeout(finish, ms);
|
|
5711
6178
|
if (signal?.aborted) {
|
|
@@ -5720,7 +6187,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5720
6187
|
return promise;
|
|
5721
6188
|
if (signal.aborted)
|
|
5722
6189
|
return Promise.reject(abortError3(signal));
|
|
5723
|
-
return new Promise((
|
|
6190
|
+
return new Promise((resolve10, reject) => {
|
|
5724
6191
|
let settled = false;
|
|
5725
6192
|
const finish = (run) => {
|
|
5726
6193
|
if (settled)
|
|
@@ -5731,7 +6198,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
5731
6198
|
};
|
|
5732
6199
|
const onAbort = () => finish(() => reject(abortError3(signal)));
|
|
5733
6200
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5734
|
-
promise.then((value) => finish(() =>
|
|
6201
|
+
promise.then((value) => finish(() => resolve10(value)), (error) => finish(() => reject(error)));
|
|
5735
6202
|
});
|
|
5736
6203
|
}
|
|
5737
6204
|
function throwIfAborted(signal) {
|
|
@@ -5780,7 +6247,10 @@ function parsePingResponse(message) {
|
|
|
5780
6247
|
var CONTEXT_KEY = "_context";
|
|
5781
6248
|
|
|
5782
6249
|
class InvalidDaemonRequestError extends Error {
|
|
5783
|
-
|
|
6250
|
+
constructor() {
|
|
6251
|
+
super(...arguments);
|
|
6252
|
+
this.name = "InvalidDaemonRequestError";
|
|
6253
|
+
}
|
|
5784
6254
|
}
|
|
5785
6255
|
function extractRequestContext(raw) {
|
|
5786
6256
|
if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
|
|
@@ -5896,14 +6366,17 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5896
6366
|
function callDiagnosticsViaDaemon(filePath, options) {
|
|
5897
6367
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
5898
6368
|
}
|
|
6369
|
+
function callFormatViaDaemon(filePath, options) {
|
|
6370
|
+
return callToolViaDaemon("format", { filePath }, options);
|
|
6371
|
+
}
|
|
5899
6372
|
function currentRequestContext(env = process.env) {
|
|
5900
6373
|
const cwd = process.cwd();
|
|
5901
6374
|
const home = env["HOME"] ?? homedir3();
|
|
5902
6375
|
return parseLspRequestContext({
|
|
5903
6376
|
cwd,
|
|
5904
|
-
projectConfigPaths: [
|
|
5905
|
-
userConfigPath:
|
|
5906
|
-
installDecisionsPath:
|
|
6377
|
+
projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
|
|
6378
|
+
userConfigPath: join8(home, ".codex", "lsp-client.json"),
|
|
6379
|
+
installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
|
|
5907
6380
|
capabilities: { installDecisionTool: true }
|
|
5908
6381
|
});
|
|
5909
6382
|
}
|
|
@@ -5918,7 +6391,7 @@ function withContext(args, context) {
|
|
|
5918
6391
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5919
6392
|
if (!signal)
|
|
5920
6393
|
return ensure(paths);
|
|
5921
|
-
return new Promise((
|
|
6394
|
+
return new Promise((resolve10, reject) => {
|
|
5922
6395
|
let settled = false;
|
|
5923
6396
|
const finish = (run) => {
|
|
5924
6397
|
if (settled)
|
|
@@ -5933,11 +6406,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5933
6406
|
return;
|
|
5934
6407
|
}
|
|
5935
6408
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5936
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
6409
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5937
6410
|
});
|
|
5938
6411
|
}
|
|
5939
6412
|
function sendToolCall(paths, token, name, args, options) {
|
|
5940
|
-
return new Promise((
|
|
6413
|
+
return new Promise((resolve10, reject) => {
|
|
5941
6414
|
const socket = connect(paths.socket);
|
|
5942
6415
|
const requestId = allocateProxyRequestId();
|
|
5943
6416
|
let settled = false;
|
|
@@ -5990,7 +6463,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
5990
6463
|
}
|
|
5991
6464
|
const result = toToolResult(message, requestId);
|
|
5992
6465
|
if (result)
|
|
5993
|
-
finish(() =>
|
|
6466
|
+
finish(() => resolve10(result));
|
|
5994
6467
|
else
|
|
5995
6468
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
5996
6469
|
});
|
|
@@ -6158,18 +6631,18 @@ function canonicalizePathList(value) {
|
|
|
6158
6631
|
return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
|
|
6159
6632
|
}
|
|
6160
6633
|
function canonicalizePath(value) {
|
|
6161
|
-
if (value === undefined || !
|
|
6634
|
+
if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
|
|
6162
6635
|
return value;
|
|
6163
|
-
return
|
|
6636
|
+
return realpathSync6(value);
|
|
6164
6637
|
}
|
|
6165
6638
|
function projectRootFromOpenCodeConfigPath(path2) {
|
|
6166
|
-
if (
|
|
6639
|
+
if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
|
|
6167
6640
|
return;
|
|
6168
|
-
const configDir =
|
|
6169
|
-
const configDirName =
|
|
6641
|
+
const configDir = dirname11(path2);
|
|
6642
|
+
const configDirName = basename4(configDir);
|
|
6170
6643
|
if (configDirName !== ".opencode" && configDirName !== ".omo")
|
|
6171
6644
|
return;
|
|
6172
|
-
return
|
|
6645
|
+
return dirname11(configDir);
|
|
6173
6646
|
}
|
|
6174
6647
|
|
|
6175
6648
|
// src/daemon-server.ts
|
|
@@ -6178,12 +6651,12 @@ import { createServer as createServer2 } from "node:net";
|
|
|
6178
6651
|
|
|
6179
6652
|
// src/ownership.ts
|
|
6180
6653
|
import { randomUUID } from "node:crypto";
|
|
6181
|
-
import { existsSync as
|
|
6182
|
-
import { dirname as
|
|
6654
|
+
import { existsSync as existsSync14, lstatSync as lstatSync7, readFileSync as readFileSync8, statSync as statSync5, unlinkSync as unlinkSync4 } from "node:fs";
|
|
6655
|
+
import { dirname as dirname13 } from "node:path";
|
|
6183
6656
|
|
|
6184
6657
|
// src/lock.ts
|
|
6185
|
-
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as
|
|
6186
|
-
import { dirname as
|
|
6658
|
+
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "node:fs";
|
|
6659
|
+
import { dirname as dirname12 } from "node:path";
|
|
6187
6660
|
function isProcessAlive2(pid) {
|
|
6188
6661
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
6189
6662
|
return false;
|
|
@@ -6198,14 +6671,14 @@ function isProcessAlive2(pid) {
|
|
|
6198
6671
|
}
|
|
6199
6672
|
function readLockPid(lockPath) {
|
|
6200
6673
|
try {
|
|
6201
|
-
const pid = Number.parseInt(
|
|
6674
|
+
const pid = Number.parseInt(readFileSync7(lockPath, "utf8").trim(), 10);
|
|
6202
6675
|
return Number.isInteger(pid) ? pid : null;
|
|
6203
6676
|
} catch {
|
|
6204
6677
|
return null;
|
|
6205
6678
|
}
|
|
6206
6679
|
}
|
|
6207
6680
|
function tryAcquireLock(lockPath, ownerPid = process.pid) {
|
|
6208
|
-
mkdirSync4(
|
|
6681
|
+
mkdirSync4(dirname12(lockPath), { recursive: true });
|
|
6209
6682
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
6210
6683
|
const handle = writeLockFile(lockPath, ownerPid);
|
|
6211
6684
|
if (handle)
|
|
@@ -6237,7 +6710,7 @@ function reapStaleLock(lockPath) {
|
|
|
6237
6710
|
}
|
|
6238
6711
|
function unlinkQuietly(path2) {
|
|
6239
6712
|
try {
|
|
6240
|
-
|
|
6713
|
+
unlinkSync3(path2);
|
|
6241
6714
|
} catch (error) {
|
|
6242
6715
|
if (error instanceof Error)
|
|
6243
6716
|
return;
|
|
@@ -6253,17 +6726,19 @@ function errorCode3(error) {
|
|
|
6253
6726
|
|
|
6254
6727
|
// src/ownership.ts
|
|
6255
6728
|
class DaemonAlreadyRunningError extends Error {
|
|
6256
|
-
|
|
6257
|
-
|
|
6729
|
+
constructor() {
|
|
6730
|
+
super(...arguments);
|
|
6731
|
+
this.name = "DaemonAlreadyRunningError";
|
|
6732
|
+
this.code = "daemon_already_running";
|
|
6733
|
+
}
|
|
6258
6734
|
}
|
|
6259
6735
|
|
|
6260
6736
|
class DaemonStartupDeferredError extends Error {
|
|
6261
|
-
reason;
|
|
6262
|
-
name = "DaemonStartupDeferredError";
|
|
6263
|
-
code = "daemon_startup_deferred";
|
|
6264
6737
|
constructor(reason) {
|
|
6265
6738
|
super(`LSP daemon startup deferred: ${reason}`);
|
|
6266
6739
|
this.reason = reason;
|
|
6740
|
+
this.name = "DaemonStartupDeferredError";
|
|
6741
|
+
this.code = "daemon_startup_deferred";
|
|
6267
6742
|
}
|
|
6268
6743
|
}
|
|
6269
6744
|
async function acquireStartupLease(paths, pingOwner) {
|
|
@@ -6286,11 +6761,11 @@ async function acquireStartupLease(paths, pingOwner) {
|
|
|
6286
6761
|
function ensureDaemonDirectories(paths) {
|
|
6287
6762
|
ensurePrivateDirectory(paths.dir);
|
|
6288
6763
|
if (process.platform !== "win32")
|
|
6289
|
-
ensurePrivateDirectory(
|
|
6764
|
+
ensurePrivateDirectory(dirname13(paths.socket));
|
|
6290
6765
|
}
|
|
6291
6766
|
function readDaemonOwner(paths) {
|
|
6292
6767
|
try {
|
|
6293
|
-
return parseOwner(JSON.parse(
|
|
6768
|
+
return parseOwner(JSON.parse(readFileSync8(paths.owner, "utf8")));
|
|
6294
6769
|
} catch (error) {
|
|
6295
6770
|
if (error instanceof Error)
|
|
6296
6771
|
return null;
|
|
@@ -6366,10 +6841,10 @@ async function validateExistingOwner(paths, pingOwner) {
|
|
|
6366
6841
|
throw new DaemonStartupDeferredError("reachable_owner_mismatch");
|
|
6367
6842
|
}
|
|
6368
6843
|
function cleanupDeadOwner(paths, owner) {
|
|
6369
|
-
if (process.platform !== "win32" &&
|
|
6844
|
+
if (process.platform !== "win32" && existsSync14(owner.endpoint.path)) {
|
|
6370
6845
|
const stat = lstatSync7(owner.endpoint.path);
|
|
6371
6846
|
if (stat.isSocket())
|
|
6372
|
-
|
|
6847
|
+
unlinkSync4(owner.endpoint.path);
|
|
6373
6848
|
}
|
|
6374
6849
|
unlinkQuietly(paths.pid);
|
|
6375
6850
|
unlinkQuietly(paths.endpoint);
|
|
@@ -6417,7 +6892,7 @@ function parseEndpoint(value) {
|
|
|
6417
6892
|
// src/version-reap.ts
|
|
6418
6893
|
import { execFile } from "node:child_process";
|
|
6419
6894
|
import { readdir, readFile, rm } from "node:fs/promises";
|
|
6420
|
-
import { basename as
|
|
6895
|
+
import { basename as basename5, dirname as dirname14, join as join9 } from "node:path";
|
|
6421
6896
|
var TERM_GRACE_MS = 5000;
|
|
6422
6897
|
var KILL_GRACE_MS = 1000;
|
|
6423
6898
|
var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
|
|
@@ -6438,7 +6913,7 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
|
|
|
6438
6913
|
return isNodeCliDaemonCommand(command.trim());
|
|
6439
6914
|
}
|
|
6440
6915
|
async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
6441
|
-
const baseDir =
|
|
6916
|
+
const baseDir = dirname14(ownPaths.dir);
|
|
6442
6917
|
const platform = deps.platform ?? process.platform;
|
|
6443
6918
|
const isAlive = deps.isAlive ?? isProcessAlive2;
|
|
6444
6919
|
const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
|
|
@@ -6457,7 +6932,7 @@ async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
|
6457
6932
|
const version = parseVersionEntry(entry.name);
|
|
6458
6933
|
if (version === null || !entry.isDirectory())
|
|
6459
6934
|
continue;
|
|
6460
|
-
const versionDir =
|
|
6935
|
+
const versionDir = join9(baseDir, entry.name);
|
|
6461
6936
|
const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
|
|
6462
6937
|
results.push(await reapOneVersion({
|
|
6463
6938
|
version,
|
|
@@ -6481,7 +6956,7 @@ async function reapOneVersion(context) {
|
|
|
6481
6956
|
const { version, versionDir } = context;
|
|
6482
6957
|
const owner = context.readOwner(context.siblingPaths);
|
|
6483
6958
|
if (!owner) {
|
|
6484
|
-
const lockPid = readLockPid(
|
|
6959
|
+
const lockPid = readLockPid(join9(versionDir, "daemon.lock"));
|
|
6485
6960
|
if (lockPid !== null && context.isAlive(lockPid)) {
|
|
6486
6961
|
context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
|
|
6487
6962
|
return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
|
|
@@ -6547,7 +7022,7 @@ function splitCmdline(buffer) {
|
|
|
6547
7022
|
function isNodeCliDaemonArgv(argv) {
|
|
6548
7023
|
if (argv.length < 2 || !argv.includes("daemon"))
|
|
6549
7024
|
return false;
|
|
6550
|
-
const executable =
|
|
7025
|
+
const executable = basename5(argv[0] ?? "");
|
|
6551
7026
|
if (!/^node(?:\.exe)?$/i.test(executable))
|
|
6552
7027
|
return false;
|
|
6553
7028
|
return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
|
|
@@ -6559,13 +7034,13 @@ function defaultReadProcFile(path2) {
|
|
|
6559
7034
|
return readFile(path2);
|
|
6560
7035
|
}
|
|
6561
7036
|
function defaultExecuteForStdout(file, args) {
|
|
6562
|
-
return new Promise((
|
|
6563
|
-
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
|
|
7037
|
+
return new Promise((resolve10) => {
|
|
7038
|
+
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000, windowsHide: true }, (error, stdout) => {
|
|
6564
7039
|
if (error !== null) {
|
|
6565
|
-
|
|
7040
|
+
resolve10(null);
|
|
6566
7041
|
return;
|
|
6567
7042
|
}
|
|
6568
|
-
|
|
7043
|
+
resolve10(stdout);
|
|
6569
7044
|
});
|
|
6570
7045
|
});
|
|
6571
7046
|
}
|
|
@@ -6584,7 +7059,7 @@ async function defaultWaitForExit(pid, timeoutMs) {
|
|
|
6584
7059
|
return true;
|
|
6585
7060
|
if (Date.now() >= deadline)
|
|
6586
7061
|
return false;
|
|
6587
|
-
await new Promise((
|
|
7062
|
+
await new Promise((resolve10) => setTimeout(resolve10, 100));
|
|
6588
7063
|
}
|
|
6589
7064
|
}
|
|
6590
7065
|
function defaultLog(message) {
|
|
@@ -6691,17 +7166,17 @@ async function assertSelfProbe(paths, token, owner) {
|
|
|
6691
7166
|
throw new DaemonStartupDeferredError("self_probe_failed");
|
|
6692
7167
|
}
|
|
6693
7168
|
function listen(server2, socketPath) {
|
|
6694
|
-
return new Promise((
|
|
7169
|
+
return new Promise((resolve10, reject) => {
|
|
6695
7170
|
const onError = (error) => reject(error);
|
|
6696
7171
|
server2.once("error", onError);
|
|
6697
7172
|
server2.listen(socketPath, () => {
|
|
6698
7173
|
server2.removeListener("error", onError);
|
|
6699
|
-
|
|
7174
|
+
resolve10();
|
|
6700
7175
|
});
|
|
6701
7176
|
});
|
|
6702
7177
|
}
|
|
6703
7178
|
function closeServer(server2) {
|
|
6704
|
-
return new Promise((
|
|
7179
|
+
return new Promise((resolve10) => server2.close(() => resolve10()));
|
|
6705
7180
|
}
|
|
6706
7181
|
function installSignalHandlers(close) {
|
|
6707
7182
|
const handler = () => {
|