oh-my-opencode 4.18.2 → 4.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/command/omomomo.md +1 -1
- package/.agents/skills/omomomo/SKILL.md +1 -1
- package/.opencode/command/omomomo.md +1 -1
- package/README.ja.md +6 -6
- package/README.ko.md +6 -6
- package/README.md +8 -8
- package/README.ru.md +6 -6
- package/README.zh-cn.md +6 -6
- package/dist/agents/atlas/agent.d.ts +7 -6
- package/dist/agents/gpt-prompt-identity.d.ts +3 -0
- package/dist/agents/sisyphus/gpt-5-5.d.ts +1 -1
- package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +1 -0
- package/dist/agents/sisyphus/index.d.ts +5 -0
- package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
- package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
- package/dist/agents/sisyphus-junior/index.d.ts +2 -0
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +781 -215
- package/dist/cli-node/index.js +781 -215
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/agent-overrides.d.ts +48 -48
- package/dist/config/schema/browser-automation.d.ts +1 -0
- package/dist/config/schema/categories.d.ts +6 -6
- package/dist/config/schema/codegraph.d.ts +2 -0
- package/dist/config/schema/commands.d.ts +1 -3
- package/dist/config/schema/default-mode.d.ts +1 -1
- package/dist/config/schema/fallback-models.d.ts +5 -5
- package/dist/config/schema/goal.d.ts +7 -0
- package/dist/config/schema/hooks.d.ts +1 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +56 -58
- package/dist/config/schema/ralph-loop.d.ts +1 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/create-hooks.d.ts +1 -1
- package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
- package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
- package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
- package/dist/hooks/goal/command-arguments.d.ts +13 -0
- package/dist/hooks/goal/controller.d.ts +26 -0
- package/dist/hooks/goal/index.d.ts +23 -0
- package/dist/hooks/goal/prompt.d.ts +3 -0
- package/dist/hooks/goal/store.d.ts +8 -0
- package/dist/hooks/goal/tools.d.ts +10 -0
- package/dist/hooks/goal/types.d.ts +93 -0
- package/dist/hooks/goal/validation.d.ts +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/keyword-detector/hook.d.ts +1 -2
- package/dist/hooks/ralph-loop/types.d.ts +1 -1
- package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
- package/dist/hooks/start-work/notepad-scaffold.d.ts +10 -0
- package/dist/index.js +5398 -5109
- package/dist/oh-my-opencode.schema.json +34 -19
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
- package/dist/plugin/chat-message/types.d.ts +23 -10
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
- package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
- package/dist/plugin/stop-continuation.d.ts +2 -2
- package/dist/shared/omo-process-sweep.d.ts +18 -0
- package/dist/shared/system-directive.d.ts +0 -1
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/dist/skills/ulw-plan/SKILL.md +31 -8
- package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/dist/skills/ulw-research/SKILL.md +3 -3
- package/dist/testing/create-plugin-module.d.ts +1 -0
- package/dist/tools/delegate-task/types.d.ts +0 -1
- package/dist/tui.js +138 -80
- package/package.json +14 -14
- package/packages/git-bash-mcp/dist/cli.js +54 -8
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +60 -0
- package/packages/lsp-core/src/lsp/client.ts +14 -1
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +2 -2
- package/packages/lsp-core/src/mcp.ts +9 -0
- package/packages/lsp-daemon/dist/cli.js +319 -51
- package/packages/lsp-daemon/dist/client.js +136 -48
- package/packages/lsp-daemon/dist/daemon-client.d.ts +0 -10
- package/packages/lsp-daemon/dist/daemon-client.js +4 -34
- package/packages/lsp-daemon/dist/daemon-failure-result.d.ts +3 -0
- package/packages/lsp-daemon/dist/daemon-failure-result.js +38 -0
- package/packages/lsp-daemon/dist/daemon-request-error.d.ts +14 -0
- package/packages/lsp-daemon/dist/daemon-request-error.js +26 -0
- package/packages/lsp-daemon/dist/daemon-server.js +5 -1
- package/packages/lsp-daemon/dist/index.js +137 -48
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +1 -0
- package/packages/lsp-daemon/dist/version-reap.d.ts +26 -0
- package/packages/lsp-daemon/dist/version-reap.js +182 -0
- package/packages/lsp-tools-mcp/dist/cli.js +61 -10
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +6 -1
- package/packages/lsp-tools-mcp/dist/mcp.js +61 -10
- package/packages/lsp-tools-mcp/dist/tools.js +6 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +416 -25
- 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/setup.ts +22 -2
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +7 -6
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +638 -267
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +178 -89
- package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +98 -32
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +5 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +15 -6
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +6 -2
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +1 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +148 -0
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +31 -2
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +65 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -7
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +57 -3
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +41 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +109 -8
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +43 -0
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +80 -40
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +11 -0
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +11 -0
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +60 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +147 -60
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +3 -71
- package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +198 -23
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +6 -5
- package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -10
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +31 -8
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +42 -0
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +6 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.d.ts +21 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +64 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +15 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +85 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +0 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +998 -593
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +10 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +84 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +81 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +7 -59
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +12 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.js +122 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +8 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +84 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +13 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +49 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +13 -45
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +4 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +20 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +125 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +59 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +6 -58
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +12 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/validation-batch.ts +122 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +76 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +111 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +67 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +57 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +152 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +29 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts +147 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch.test.ts +73 -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-codegraph-init-guidance.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 +2 -2
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -2
- 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 +2 -2
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +41 -41
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +3 -18
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +43 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +31 -8
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +11 -11
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +26 -0
- package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +41 -0
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +3 -18
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +401 -22
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
- package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +31 -8
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
- package/dist/skills/ultraresearch/SKILL.md +0 -10
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
|
@@ -167,16 +167,35 @@ function bufferFromChunk(chunk) {
|
|
|
167
167
|
|
|
168
168
|
// ../mcp-stdio-core/src/server.ts
|
|
169
169
|
var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
|
|
170
|
+
var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
|
|
170
171
|
var noopLog = () => {};
|
|
172
|
+
function isProcessAlive(pid) {
|
|
173
|
+
try {
|
|
174
|
+
process.kill(pid, 0);
|
|
175
|
+
return true;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return !hasErrorCode(error, "ESRCH");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
171
180
|
async function runJsonRpcStdioServer(config) {
|
|
172
181
|
const log = config.log ?? noopLog;
|
|
173
182
|
const idleTimeoutMs = config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
174
|
-
|
|
183
|
+
let isClosed = false;
|
|
184
|
+
const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
|
|
185
|
+
isClosed = true;
|
|
186
|
+
config.onIdleTimeout?.();
|
|
187
|
+
});
|
|
188
|
+
const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
|
|
189
|
+
isClosed = true;
|
|
190
|
+
log("parent_exit", { parent_pid: parentPid, poll_interval_ms: pollIntervalMs });
|
|
191
|
+
config.onParentExit?.();
|
|
192
|
+
config.input.destroy();
|
|
193
|
+
});
|
|
175
194
|
log("stdio_started", { cwd: process.cwd(), idle_timeout_ms: idleTimeoutMs });
|
|
176
195
|
idleTimer.arm();
|
|
177
196
|
try {
|
|
178
197
|
for await (const message of readStdioJsonRpcMessages(config.input)) {
|
|
179
|
-
if (
|
|
198
|
+
if (isClosed)
|
|
180
199
|
break;
|
|
181
200
|
idleTimer.arm();
|
|
182
201
|
if (message.kind === "parse_error") {
|
|
@@ -187,8 +206,12 @@ async function runJsonRpcStdioServer(config) {
|
|
|
187
206
|
if (!await handleRequest(message, config, log))
|
|
188
207
|
break;
|
|
189
208
|
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (!(isClosed && hasErrorCode(error, "ERR_STREAM_PREMATURE_CLOSE")))
|
|
211
|
+
throw error;
|
|
190
212
|
} finally {
|
|
191
213
|
idleTimer.clear();
|
|
214
|
+
watchdog.clear();
|
|
192
215
|
log("stdio_stopped");
|
|
193
216
|
}
|
|
194
217
|
}
|
|
@@ -244,9 +267,33 @@ function isTerminalOutputError(error) {
|
|
|
244
267
|
return false;
|
|
245
268
|
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
246
269
|
}
|
|
247
|
-
function
|
|
270
|
+
function hasErrorCode(error, code) {
|
|
271
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
272
|
+
}
|
|
273
|
+
function createParentWatchdog(config, onDeadParent) {
|
|
274
|
+
if (config === undefined)
|
|
275
|
+
return { clear: () => {} };
|
|
276
|
+
const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_PARENT_POLL_INTERVAL_MS;
|
|
277
|
+
if (pollIntervalMs <= 0)
|
|
278
|
+
return { clear: () => {} };
|
|
279
|
+
const parentPid = config.parentPid ?? process.ppid;
|
|
280
|
+
const probeAlive = config.probeAlive ?? isProcessAlive;
|
|
281
|
+
let fired = false;
|
|
282
|
+
const timer = setInterval(() => {
|
|
283
|
+
if (fired || probeAlive(parentPid))
|
|
284
|
+
return;
|
|
285
|
+
fired = true;
|
|
286
|
+
onDeadParent(parentPid, pollIntervalMs);
|
|
287
|
+
}, pollIntervalMs);
|
|
288
|
+
timer.unref();
|
|
289
|
+
return {
|
|
290
|
+
clear: () => {
|
|
291
|
+
clearInterval(timer);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
248
296
|
let timer = null;
|
|
249
|
-
let isClosed = false;
|
|
250
297
|
return {
|
|
251
298
|
arm: () => {
|
|
252
299
|
if (timer !== null)
|
|
@@ -254,9 +301,8 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
254
301
|
if (idleTimeoutMs <= 0)
|
|
255
302
|
return;
|
|
256
303
|
timer = setTimeout(() => {
|
|
257
|
-
isClosed = true;
|
|
258
304
|
log("idle_timeout", { idle_timeout_ms: idleTimeoutMs });
|
|
259
|
-
|
|
305
|
+
onTimeout();
|
|
260
306
|
}, idleTimeoutMs);
|
|
261
307
|
timer.unref();
|
|
262
308
|
},
|
|
@@ -265,8 +311,7 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
265
311
|
return;
|
|
266
312
|
clearTimeout(timer);
|
|
267
313
|
timer = null;
|
|
268
|
-
}
|
|
269
|
-
closed: () => isClosed
|
|
314
|
+
}
|
|
270
315
|
};
|
|
271
316
|
}
|
|
272
317
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
@@ -3057,8 +3102,13 @@ class LspClient extends LspClientConnection {
|
|
|
3057
3102
|
if (!pushFallbackOnly)
|
|
3058
3103
|
continue;
|
|
3059
3104
|
const remainingMs = deadlineAt - Date.now();
|
|
3060
|
-
if (remainingMs <= 0)
|
|
3105
|
+
if (remainingMs <= 0) {
|
|
3106
|
+
if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
|
|
3107
|
+
const cached = this.documents.getPullCache(snapshot);
|
|
3108
|
+
return { items: cached === null ? [] : [...cached.diagnostics] };
|
|
3109
|
+
}
|
|
3061
3110
|
return this.freshnessTimeout(absPath);
|
|
3111
|
+
}
|
|
3062
3112
|
const waitMs = push.status === "wait" ? Math.min(push.waitMs, remainingMs) : remainingMs;
|
|
3063
3113
|
await waitForDiagnosticsActivity(this.documents.waitForDiagnosticsActivity(snapshot, waitMs), signal);
|
|
3064
3114
|
}
|
|
@@ -5065,6 +5115,81 @@ import { connect } from "node:net";
|
|
|
5065
5115
|
import { homedir as homedir3 } from "node:os";
|
|
5066
5116
|
import { join as join7 } from "node:path";
|
|
5067
5117
|
|
|
5118
|
+
// src/daemon-request-error.ts
|
|
5119
|
+
class DaemonRequestError extends Error {
|
|
5120
|
+
requestWritten;
|
|
5121
|
+
constructor(message, requestWritten) {
|
|
5122
|
+
super(message);
|
|
5123
|
+
this.name = "DaemonRequestError";
|
|
5124
|
+
this.requestWritten = requestWritten;
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
|
|
5128
|
+
class DaemonAuthenticationRejectedError extends DaemonRequestError {
|
|
5129
|
+
constructor() {
|
|
5130
|
+
super("daemon authentication failed before dispatch", true);
|
|
5131
|
+
this.name = "DaemonAuthenticationRejectedError";
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5135
|
+
class DaemonRequestCancelledError extends DaemonRequestError {
|
|
5136
|
+
constructor(requestWritten) {
|
|
5137
|
+
super("daemon request cancelled", requestWritten);
|
|
5138
|
+
this.name = "DaemonRequestCancelledError";
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
class DaemonRequestTimedOutError extends DaemonRequestError {
|
|
5143
|
+
timeoutMs;
|
|
5144
|
+
constructor(requestWritten, timeoutMs) {
|
|
5145
|
+
super("daemon request timed out", requestWritten);
|
|
5146
|
+
this.name = "DaemonRequestTimedOutError";
|
|
5147
|
+
this.timeoutMs = timeoutMs;
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
|
|
5151
|
+
// src/daemon-failure-result.ts
|
|
5152
|
+
function daemonFailureResult(paths, error) {
|
|
5153
|
+
if (error instanceof DaemonRequestCancelledError)
|
|
5154
|
+
return daemonCancelledResult(paths);
|
|
5155
|
+
if (error instanceof DaemonRequestTimedOutError)
|
|
5156
|
+
return daemonTimedOutResult(paths, error.timeoutMs);
|
|
5157
|
+
return daemonUnreachableResult(paths, error);
|
|
5158
|
+
}
|
|
5159
|
+
function daemonCancelledResult(paths) {
|
|
5160
|
+
const text2 = [
|
|
5161
|
+
"LSP daemon request cancelled: the caller aborted this request (for example, the turn was interrupted).",
|
|
5162
|
+
"The daemon stays available; no LSP work was applied. Retry when you are ready.",
|
|
5163
|
+
`Socket: ${paths.socket}`
|
|
5164
|
+
].join(`
|
|
5165
|
+
`);
|
|
5166
|
+
return { content: [{ type: "text", text: text2 }], isError: true };
|
|
5167
|
+
}
|
|
5168
|
+
function daemonTimedOutResult(paths, timeoutMs) {
|
|
5169
|
+
const text2 = [
|
|
5170
|
+
`LSP daemon request timed out after ${timeoutMs}ms: the daemon did not respond in time.`,
|
|
5171
|
+
"The daemon stays available but may be busy. Retry when you are ready.",
|
|
5172
|
+
`Socket: ${paths.socket}`,
|
|
5173
|
+
`Logs: ${paths.log}`
|
|
5174
|
+
].join(`
|
|
5175
|
+
`);
|
|
5176
|
+
return { content: [{ type: "text", text: text2 }], isError: true };
|
|
5177
|
+
}
|
|
5178
|
+
function daemonUnreachableResult(paths, error) {
|
|
5179
|
+
const text2 = [
|
|
5180
|
+
`LSP daemon unreachable: ${errorText(error)}.`,
|
|
5181
|
+
"The MCP server is a thin proxy and never runs language servers in-process.",
|
|
5182
|
+
`Socket: ${paths.socket}`,
|
|
5183
|
+
`Logs: ${paths.log}`,
|
|
5184
|
+
"The daemon is auto-started on demand and will be retried on the next request."
|
|
5185
|
+
].join(`
|
|
5186
|
+
`);
|
|
5187
|
+
return { content: [{ type: "text", text: text2 }], isError: true };
|
|
5188
|
+
}
|
|
5189
|
+
function errorText(error) {
|
|
5190
|
+
return error instanceof Error ? error.message : String(error);
|
|
5191
|
+
}
|
|
5192
|
+
|
|
5068
5193
|
// src/ensure-daemon.ts
|
|
5069
5194
|
import { spawn as spawn2 } from "node:child_process";
|
|
5070
5195
|
import { closeSync as closeSync2, mkdirSync as mkdirSync3, openSync as openSync2 } from "node:fs";
|
|
@@ -5724,29 +5849,6 @@ function parseContext(value) {
|
|
|
5724
5849
|
// src/daemon-client.ts
|
|
5725
5850
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
5726
5851
|
var nextProxyRequestId = 1;
|
|
5727
|
-
|
|
5728
|
-
class DaemonRequestError extends Error {
|
|
5729
|
-
requestWritten;
|
|
5730
|
-
constructor(message, requestWritten) {
|
|
5731
|
-
super(message);
|
|
5732
|
-
this.name = "DaemonRequestError";
|
|
5733
|
-
this.requestWritten = requestWritten;
|
|
5734
|
-
}
|
|
5735
|
-
}
|
|
5736
|
-
|
|
5737
|
-
class DaemonAuthenticationRejectedError extends DaemonRequestError {
|
|
5738
|
-
constructor() {
|
|
5739
|
-
super("daemon authentication failed before dispatch", true);
|
|
5740
|
-
this.name = "DaemonAuthenticationRejectedError";
|
|
5741
|
-
}
|
|
5742
|
-
}
|
|
5743
|
-
|
|
5744
|
-
class DaemonRequestCancelledError extends DaemonRequestError {
|
|
5745
|
-
constructor(requestWritten) {
|
|
5746
|
-
super("daemon request cancelled", requestWritten);
|
|
5747
|
-
this.name = "DaemonRequestCancelledError";
|
|
5748
|
-
}
|
|
5749
|
-
}
|
|
5750
5852
|
async function callToolViaDaemon(name, args, options) {
|
|
5751
5853
|
const context = requireContext(options.context);
|
|
5752
5854
|
const paths = options.paths ?? daemonPaths();
|
|
@@ -5775,7 +5877,7 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5775
5877
|
break;
|
|
5776
5878
|
}
|
|
5777
5879
|
}
|
|
5778
|
-
return
|
|
5880
|
+
return daemonFailureResult(paths, lastError);
|
|
5779
5881
|
}
|
|
5780
5882
|
function callDiagnosticsViaDaemon(filePath, options) {
|
|
5781
5883
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
@@ -5820,17 +5922,6 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5820
5922
|
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve9()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5821
5923
|
});
|
|
5822
5924
|
}
|
|
5823
|
-
function daemonUnreachableResult(paths, error) {
|
|
5824
|
-
const text2 = [
|
|
5825
|
-
`LSP daemon unreachable: ${errorText(error)}.`,
|
|
5826
|
-
"The MCP server is a thin proxy and never runs language servers in-process.",
|
|
5827
|
-
`Socket: ${paths.socket}`,
|
|
5828
|
-
`Logs: ${paths.log}`,
|
|
5829
|
-
"The daemon is auto-started on demand and will be retried on the next request."
|
|
5830
|
-
].join(`
|
|
5831
|
-
`);
|
|
5832
|
-
return { content: [{ type: "text", text: text2 }], isError: true };
|
|
5833
|
-
}
|
|
5834
5925
|
function sendToolCall(paths, token, name, args, options) {
|
|
5835
5926
|
return new Promise((resolve9, reject) => {
|
|
5836
5927
|
const socket = connect(paths.socket);
|
|
@@ -5870,7 +5961,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
5870
5961
|
};
|
|
5871
5962
|
const timer = setTimeout(() => {
|
|
5872
5963
|
sendCancel();
|
|
5873
|
-
finish(() => reject(new
|
|
5964
|
+
finish(() => reject(new DaemonRequestTimedOutError(requestWritten, options.timeoutMs)));
|
|
5874
5965
|
}, options.timeoutMs);
|
|
5875
5966
|
timer.unref();
|
|
5876
5967
|
if (options.signal?.aborted) {
|
|
@@ -5929,9 +6020,6 @@ function allocateProxyRequestId() {
|
|
|
5929
6020
|
function isRetryableTool(name) {
|
|
5930
6021
|
return name !== "rename" && name !== "lsp_rename";
|
|
5931
6022
|
}
|
|
5932
|
-
function errorText(error) {
|
|
5933
|
-
return error instanceof Error ? error.message : String(error);
|
|
5934
|
-
}
|
|
5935
6023
|
|
|
5936
6024
|
// src/proxy.ts
|
|
5937
6025
|
var DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
|
|
@@ -5988,6 +6076,7 @@ async function runMcpStdioProxy(options = {}) {
|
|
|
5988
6076
|
input,
|
|
5989
6077
|
output,
|
|
5990
6078
|
idleTimeoutMs: 0,
|
|
6079
|
+
parentWatchdog: options.parentWatchdog ?? {},
|
|
5991
6080
|
handler: (request, requestOptions) => {
|
|
5992
6081
|
clearStartupWatchdog();
|
|
5993
6082
|
return runWithRequestContext(context, () => handleProxyRequest(request, requestOptions));
|
|
@@ -6081,7 +6170,7 @@ import { dirname as dirname11 } from "node:path";
|
|
|
6081
6170
|
// src/lock.ts
|
|
6082
6171
|
import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeSync as writeSync2 } from "node:fs";
|
|
6083
6172
|
import { dirname as dirname10 } from "node:path";
|
|
6084
|
-
function
|
|
6173
|
+
function isProcessAlive2(pid) {
|
|
6085
6174
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
6086
6175
|
return false;
|
|
6087
6176
|
try {
|
|
@@ -6127,7 +6216,7 @@ function writeLockFile(lockPath, ownerPid) {
|
|
|
6127
6216
|
}
|
|
6128
6217
|
function reapStaleLock(lockPath) {
|
|
6129
6218
|
const pid = readLockPid(lockPath);
|
|
6130
|
-
if (pid !== null &&
|
|
6219
|
+
if (pid !== null && isProcessAlive2(pid))
|
|
6131
6220
|
return false;
|
|
6132
6221
|
unlinkQuietly(lockPath);
|
|
6133
6222
|
return true;
|
|
@@ -6249,7 +6338,7 @@ async function validateExistingOwner(paths, pingOwner) {
|
|
|
6249
6338
|
}
|
|
6250
6339
|
if (ping)
|
|
6251
6340
|
continue;
|
|
6252
|
-
if (
|
|
6341
|
+
if (isProcessAlive2(owner.pid))
|
|
6253
6342
|
throw new DaemonStartupDeferredError("owner_pid_live_unreachable");
|
|
6254
6343
|
const reread = readDaemonOwner(paths);
|
|
6255
6344
|
const endpoint = endpointIdentity(owner.endpoint.path);
|
|
@@ -6311,6 +6400,184 @@ function parseEndpoint(value) {
|
|
|
6311
6400
|
return null;
|
|
6312
6401
|
}
|
|
6313
6402
|
|
|
6403
|
+
// src/version-reap.ts
|
|
6404
|
+
import { execFile } from "node:child_process";
|
|
6405
|
+
import { readdir, readFile, rm } from "node:fs/promises";
|
|
6406
|
+
import { basename as basename4, dirname as dirname12, join as join8 } from "node:path";
|
|
6407
|
+
var TERM_GRACE_MS = 5000;
|
|
6408
|
+
var KILL_GRACE_MS = 1000;
|
|
6409
|
+
var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
|
|
6410
|
+
async function attestDaemonCliProcess(pid, platform, deps = {}) {
|
|
6411
|
+
if (platform === "win32")
|
|
6412
|
+
return false;
|
|
6413
|
+
if (platform === "linux") {
|
|
6414
|
+
const readProcFile = deps.readProcFile ?? defaultReadProcFile;
|
|
6415
|
+
const cmdline = await readProcFile(`/proc/${pid}/cmdline`).catch(() => null);
|
|
6416
|
+
if (cmdline === null)
|
|
6417
|
+
return false;
|
|
6418
|
+
return isNodeCliDaemonArgv(splitCmdline(cmdline));
|
|
6419
|
+
}
|
|
6420
|
+
const executeForStdout = deps.executeForStdout ?? defaultExecuteForStdout;
|
|
6421
|
+
const command = await executeForStdout("/bin/ps", ["-p", String(pid), "-o", "command="]);
|
|
6422
|
+
if (command === null)
|
|
6423
|
+
return false;
|
|
6424
|
+
return isNodeCliDaemonCommand(command.trim());
|
|
6425
|
+
}
|
|
6426
|
+
async function reapStaleDaemonVersions(ownPaths, deps = {}) {
|
|
6427
|
+
const baseDir = dirname12(ownPaths.dir);
|
|
6428
|
+
const platform = deps.platform ?? process.platform;
|
|
6429
|
+
const isAlive = deps.isAlive ?? isProcessAlive2;
|
|
6430
|
+
const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
|
|
6431
|
+
const sendSignal = deps.sendSignal ?? defaultSendSignal;
|
|
6432
|
+
const waitForExit = deps.waitForExit ?? defaultWaitForExit;
|
|
6433
|
+
const removeDir = deps.removeDir ?? ((path2) => rm(path2, { recursive: true, force: true }));
|
|
6434
|
+
const readOwner = deps.readOwner ?? readDaemonOwner;
|
|
6435
|
+
const log = deps.log ?? defaultLog;
|
|
6436
|
+
const termGraceMs = deps.termGraceMs ?? TERM_GRACE_MS;
|
|
6437
|
+
const killGraceMs = deps.killGraceMs ?? KILL_GRACE_MS;
|
|
6438
|
+
const entries = await readdir(baseDir, { withFileTypes: true }).catch(() => []);
|
|
6439
|
+
const results = [];
|
|
6440
|
+
for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
|
|
6441
|
+
if (entry.name === `v${ownPaths.version}`)
|
|
6442
|
+
continue;
|
|
6443
|
+
const version = parseVersionEntry(entry.name);
|
|
6444
|
+
if (version === null || !entry.isDirectory())
|
|
6445
|
+
continue;
|
|
6446
|
+
const versionDir = join8(baseDir, entry.name);
|
|
6447
|
+
const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
|
|
6448
|
+
results.push(await reapOneVersion({
|
|
6449
|
+
version,
|
|
6450
|
+
versionDir,
|
|
6451
|
+
siblingPaths,
|
|
6452
|
+
platform,
|
|
6453
|
+
isAlive,
|
|
6454
|
+
attest,
|
|
6455
|
+
sendSignal,
|
|
6456
|
+
waitForExit,
|
|
6457
|
+
removeDir,
|
|
6458
|
+
readOwner,
|
|
6459
|
+
log,
|
|
6460
|
+
termGraceMs,
|
|
6461
|
+
killGraceMs
|
|
6462
|
+
}));
|
|
6463
|
+
}
|
|
6464
|
+
return results;
|
|
6465
|
+
}
|
|
6466
|
+
async function reapOneVersion(context) {
|
|
6467
|
+
const { version, versionDir } = context;
|
|
6468
|
+
const owner = context.readOwner(context.siblingPaths);
|
|
6469
|
+
if (!owner) {
|
|
6470
|
+
const lockPid = readLockPid(join8(versionDir, "daemon.lock"));
|
|
6471
|
+
if (lockPid !== null && context.isAlive(lockPid)) {
|
|
6472
|
+
context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
|
|
6473
|
+
return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
|
|
6474
|
+
}
|
|
6475
|
+
await context.removeDir(versionDir);
|
|
6476
|
+
return { version, status: "removed", reason: "removed stale version dir without readable owner metadata" };
|
|
6477
|
+
}
|
|
6478
|
+
if (!context.isAlive(owner.pid)) {
|
|
6479
|
+
await context.removeDir(versionDir);
|
|
6480
|
+
return { version, status: "removed", reason: `removed stale version dir for dead owner pid ${owner.pid}` };
|
|
6481
|
+
}
|
|
6482
|
+
if (context.platform === "win32") {
|
|
6483
|
+
context.log(`reap: deferring v${version}: Windows cannot prove pid ownership safely (named-pipe policy)`);
|
|
6484
|
+
return {
|
|
6485
|
+
version,
|
|
6486
|
+
status: "deferred",
|
|
6487
|
+
reason: "Windows cannot prove pid ownership safely; named-pipe reap deferred"
|
|
6488
|
+
};
|
|
6489
|
+
}
|
|
6490
|
+
if (!await context.attest(owner.pid, context.platform)) {
|
|
6491
|
+
context.log(`reap: sparing v${version}: pid ${owner.pid} is alive but cmdline attestation failed (possible recycled pid)`);
|
|
6492
|
+
return {
|
|
6493
|
+
version,
|
|
6494
|
+
status: "spared",
|
|
6495
|
+
reason: `pid ${owner.pid} attestation failed; possible recycled pid`
|
|
6496
|
+
};
|
|
6497
|
+
}
|
|
6498
|
+
return await terminateAttestedOwner(context, owner.pid);
|
|
6499
|
+
}
|
|
6500
|
+
async function terminateAttestedOwner(context, pid) {
|
|
6501
|
+
const { version, versionDir } = context;
|
|
6502
|
+
if (!context.sendSignal(pid, "SIGTERM")) {
|
|
6503
|
+
await context.removeDir(versionDir);
|
|
6504
|
+
return {
|
|
6505
|
+
version,
|
|
6506
|
+
status: "removed",
|
|
6507
|
+
reason: `owner pid ${pid} exited before SIGTERM; removed stale version dir`
|
|
6508
|
+
};
|
|
6509
|
+
}
|
|
6510
|
+
if (await context.waitForExit(pid, context.termGraceMs)) {
|
|
6511
|
+
await context.removeDir(versionDir);
|
|
6512
|
+
return { version, status: "terminated", reason: `terminated attested older daemon pid ${pid} with SIGTERM` };
|
|
6513
|
+
}
|
|
6514
|
+
context.log(`reap: v${version} pid ${pid} survived SIGTERM; escalating to SIGKILL`);
|
|
6515
|
+
if (!context.sendSignal(pid, "SIGKILL") || !await context.waitForExit(pid, context.killGraceMs)) {
|
|
6516
|
+
context.log(`reap: deferring v${version}: pid ${pid} survived SIGKILL`);
|
|
6517
|
+
return { version, status: "deferred", reason: `attested daemon pid ${pid} survived SIGKILL; dir kept` };
|
|
6518
|
+
}
|
|
6519
|
+
await context.removeDir(versionDir);
|
|
6520
|
+
return {
|
|
6521
|
+
version,
|
|
6522
|
+
status: "terminated",
|
|
6523
|
+
reason: `terminated attested older daemon pid ${pid} after SIGKILL escalation`
|
|
6524
|
+
};
|
|
6525
|
+
}
|
|
6526
|
+
function parseVersionEntry(entryName) {
|
|
6527
|
+
const match = VERSION_ENTRY_PATTERN.exec(entryName);
|
|
6528
|
+
return match?.[1] ?? null;
|
|
6529
|
+
}
|
|
6530
|
+
function splitCmdline(buffer) {
|
|
6531
|
+
return buffer.toString("utf8").split("\x00").filter((value) => value.length > 0);
|
|
6532
|
+
}
|
|
6533
|
+
function isNodeCliDaemonArgv(argv) {
|
|
6534
|
+
if (argv.length < 2 || !argv.includes("daemon"))
|
|
6535
|
+
return false;
|
|
6536
|
+
const executable = basename4(argv[0] ?? "");
|
|
6537
|
+
if (!/^node(?:\.exe)?$/i.test(executable))
|
|
6538
|
+
return false;
|
|
6539
|
+
return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
|
|
6540
|
+
}
|
|
6541
|
+
function isNodeCliDaemonCommand(command) {
|
|
6542
|
+
return /\bnode(?:\.exe)?\b/i.test(command) && /\bcli\.js\b/.test(command) && /\bdaemon\b/.test(command);
|
|
6543
|
+
}
|
|
6544
|
+
function defaultReadProcFile(path2) {
|
|
6545
|
+
return readFile(path2);
|
|
6546
|
+
}
|
|
6547
|
+
function defaultExecuteForStdout(file, args) {
|
|
6548
|
+
return new Promise((resolve9) => {
|
|
6549
|
+
execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
|
|
6550
|
+
if (error !== null) {
|
|
6551
|
+
resolve9(null);
|
|
6552
|
+
return;
|
|
6553
|
+
}
|
|
6554
|
+
resolve9(stdout);
|
|
6555
|
+
});
|
|
6556
|
+
});
|
|
6557
|
+
}
|
|
6558
|
+
function defaultSendSignal(pid, signal) {
|
|
6559
|
+
try {
|
|
6560
|
+
process.kill(pid, signal);
|
|
6561
|
+
return true;
|
|
6562
|
+
} catch {
|
|
6563
|
+
return false;
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
6566
|
+
async function defaultWaitForExit(pid, timeoutMs) {
|
|
6567
|
+
const deadline = Date.now() + timeoutMs;
|
|
6568
|
+
for (;; ) {
|
|
6569
|
+
if (!isProcessAlive2(pid))
|
|
6570
|
+
return true;
|
|
6571
|
+
if (Date.now() >= deadline)
|
|
6572
|
+
return false;
|
|
6573
|
+
await new Promise((resolve9) => setTimeout(resolve9, 100));
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
function defaultLog(message) {
|
|
6577
|
+
process.stderr.write(`[lsp-daemon] ${message}
|
|
6578
|
+
`);
|
|
6579
|
+
}
|
|
6580
|
+
|
|
6314
6581
|
// src/daemon-server.ts
|
|
6315
6582
|
var DEFAULT_IDLE_SHUTDOWN_MS = 30 * 60000;
|
|
6316
6583
|
var DEFAULT_IDLE_CHECK_INTERVAL_MS = 60000;
|
|
@@ -6357,6 +6624,7 @@ async function startDaemonServer(paths, options = {}) {
|
|
|
6357
6624
|
throw error;
|
|
6358
6625
|
}
|
|
6359
6626
|
lease.lock.release();
|
|
6627
|
+
reapStaleDaemonVersions(paths).catch((error) => logServerError(error));
|
|
6360
6628
|
let closed = false;
|
|
6361
6629
|
const close = async () => {
|
|
6362
6630
|
if (closed)
|