oh-my-opencode 4.19.0 → 4.19.2
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 +6 -6
- package/README.ru.md +6 -6
- package/README.zh-cn.md +6 -6
- package/dist/agents/atlas/agent.d.ts +5 -3
- package/dist/agents/explore.d.ts +4 -2
- package/dist/agents/gpt-prompt-identity.d.ts +3 -0
- package/dist/agents/hephaestus/agent.d.ts +4 -2
- package/dist/agents/librarian.d.ts +4 -2
- package/dist/agents/metis.d.ts +4 -2
- package/dist/agents/momus.d.ts +3 -2
- package/dist/agents/multimodal-looker.d.ts +4 -2
- package/dist/agents/oracle.d.ts +4 -2
- package/dist/agents/sisyphus/claude-opus-5.d.ts +33 -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 +2 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +5 -2
- package/dist/agents/sisyphus-junior/agent.d.ts +4 -1
- package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +23577 -19269
- package/dist/cli-node/index.js +23577 -19269
- package/dist/config/schema/agent-names.d.ts +26 -26
- package/dist/config/schema/agent-overrides.d.ts +400 -400
- package/dist/config/schema/browser-automation.d.ts +2 -2
- package/dist/config/schema/categories.d.ts +36 -36
- package/dist/config/schema/codegraph.d.ts +2 -0
- package/dist/config/schema/commands.d.ts +2 -2
- package/dist/config/schema/dynamic-context-pruning.d.ts +1 -1
- package/dist/config/schema/experimental.d.ts +1 -1
- package/dist/config/schema/fallback-models.d.ts +25 -25
- package/dist/config/schema/hooks.d.ts +43 -43
- package/dist/config/schema/internal/permission.d.ts +9 -9
- package/dist/config/schema/keyword-detector.d.ts +6 -6
- package/dist/config/schema/oh-my-opencode-config.d.ts +404 -402
- package/dist/config/schema/tmux.d.ts +6 -6
- package/dist/create-hooks.d.ts +35 -35
- package/dist/features/background-agent/spawner/tmux-callback-invoker.d.ts +11 -0
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/claude-tasks/types.d.ts +4 -4
- package/dist/features/team-mode/team-runtime/shutdown-helpers.d.ts +1 -1
- package/dist/features/team-mode/team-runtime/shutdown-test-fixtures.d.ts +4 -4
- package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +42 -42
- package/dist/features/tmux-subagent/environment-eligibility.d.ts +2 -0
- package/dist/features/tmux-subagent/index.d.ts +1 -0
- package/dist/features/tmux-subagent/tracked-session-state.d.ts +1 -0
- package/dist/features/tui-sidebar/snapshot-schema.d.ts +6 -6
- package/dist/help/schema/acp.d.ts +3 -3
- package/dist/help/schema/doctor.d.ts +4 -4
- package/dist/help/schema/status.d.ts +3 -3
- package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
- package/dist/hooks/goal/types.d.ts +5 -5
- package/dist/hooks/non-interactive-env/constants.d.ts +4 -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/hooks/start-work/parse-user-request.d.ts +2 -0
- package/dist/hooks/start-work/worktree-block.d.ts +5 -0
- package/dist/index.js +27370 -21301
- package/dist/mcp/types.d.ts +3 -3
- package/dist/oh-my-opencode.schema.json +11 -0
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -0
- package/dist/plugin/command-execute-before.d.ts +3 -3
- package/dist/plugin/hooks/create-core-hooks.d.ts +25 -25
- package/dist/shared/omo-process-sweep.d.ts +18 -0
- package/dist/shared/tmux/tmux-utils/environment.d.ts +1 -1
- package/dist/shared/tmux/tmux-utils.d.ts +1 -1
- package/dist/shared/typescript-native-source-parser.d.ts +7 -0
- package/dist/skills/coding-agent-sessions/SKILL.md +5 -2
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/dist/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/dist/skills/debugging/SKILL.md +2 -1
- package/dist/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/dist/skills/programming/SKILL.md +11 -1
- package/dist/skills/programming/references/logging.md +6 -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 +75 -11
- package/dist/skills/start-work/SKILL.md +12 -2
- package/dist/skills/ulw-plan/SKILL.md +21 -2
- package/dist/skills/ulw-plan/references/full-workflow.md +12 -1
- package/dist/skills/ulw-plan/references/intent-clear.md +1 -1
- package/dist/testing/create-plugin-module.d.ts +1 -0
- package/dist/tools/task/types.d.ts +10 -10
- package/dist/tui.js +23442 -19182
- 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 +62 -2
- 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 +72 -12
- 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/dist/cli.js +779 -385
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +302 -173
- 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 +23 -42
- 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 +17 -9
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +18 -25
- 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 +5 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +176 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +6 -1
- 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/provisioned-node-guard.test.ts +6 -0
- 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 +2 -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 +42 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +122 -10
- 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 +101 -64
- 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/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/directive.md +1 -1
- 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/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/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/plan.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +12 -7
- 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/ultrawork/SKILL.md +12 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +21 -2
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +1 -1
- 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/directive.md +12 -7
- 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/SKILL.md +2 -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/shared/test/config-loader.test.ts +44 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +5 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +11 -1
- package/packages/omo-codex/plugin/skills/programming/references/logging.md +6 -1
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +75 -11
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +12 -7
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +21 -2
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +1 -1
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +9 -9
- 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/sync-skills-orchestration.test.mjs +22 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +49 -5
- package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +5 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/packages/shared-skills/skills/debugging/SKILL.md +2 -1
- package/packages/shared-skills/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/packages/shared-skills/skills/programming/SKILL.md +11 -1
- package/packages/shared-skills/skills/programming/references/logging.md +6 -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 +75 -11
- package/packages/shared-skills/skills/start-work/SKILL.md +12 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +21 -2
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +1 -1
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
import { executeCodegraphSessionStartHook, type WorkerSpawnInvocation } from "../src/hook.ts";
|
|
9
|
+
|
|
10
|
+
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
11
|
+
|
|
12
|
+
// Observed verbatim from a REAL codegraph 1.4.1 binary running `status --json` (exit 0)
|
|
13
|
+
// against a project store built by a REAL codegraph 1.0.1 binary
|
|
14
|
+
// (see .omo/evidence/codegraph-daemon-process-hygiene/task-2-store-upgrade.txt).
|
|
15
|
+
const MIGRATED_1_0_1_STORE_STATUS_JSON = JSON.stringify({
|
|
16
|
+
initialized: true,
|
|
17
|
+
version: "1.4.1",
|
|
18
|
+
projectPath: "/private/tmp/cg-task2/fixture",
|
|
19
|
+
indexPath: "/private/tmp/cg-task2/fixture/.codegraph",
|
|
20
|
+
lastIndexed: "2026-07-21T04:28:09.593Z",
|
|
21
|
+
fileCount: 2,
|
|
22
|
+
nodeCount: 5,
|
|
23
|
+
edgeCount: 4,
|
|
24
|
+
dbSizeBytes: 159744,
|
|
25
|
+
backend: "node-sqlite",
|
|
26
|
+
journalMode: "wal",
|
|
27
|
+
nodesByKind: { file: 2, function: 3 },
|
|
28
|
+
languages: ["typescript"],
|
|
29
|
+
pendingChanges: { added: 0, modified: 0, removed: 0 },
|
|
30
|
+
worktreeMismatch: null,
|
|
31
|
+
index: {
|
|
32
|
+
builtWithVersion: "1.0.1",
|
|
33
|
+
builtWithExtractionVersion: 24,
|
|
34
|
+
currentExtractionVersion: 24,
|
|
35
|
+
reindexRecommended: false,
|
|
36
|
+
state: null,
|
|
37
|
+
pendingRefs: 0,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function createAllowedWorkspace(prefix: string): string {
|
|
42
|
+
return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// On win32 execFile cannot run a #!/bin/sh script, so emit a codegraph.cmd batch file instead;
|
|
46
|
+
// resolveCodegraphCommandInvocation wraps .cmd in `cmd.exe /d /s /c`, exactly like the real codegraph.cmd.
|
|
47
|
+
function createFakeCodegraphBin(scripts: {
|
|
48
|
+
readonly posix: string;
|
|
49
|
+
readonly win32: string;
|
|
50
|
+
readonly win32Sidecar?: string;
|
|
51
|
+
}): { readonly binPath: string; readonly dir: string } {
|
|
52
|
+
const dir = mkdtempSync(join(tmpdir(), "omo-codegraph-fake-bin-"));
|
|
53
|
+
if (process.platform === "win32") {
|
|
54
|
+
const binPath = join(dir, "codegraph.cmd");
|
|
55
|
+
writeFileSync(binPath, scripts.win32);
|
|
56
|
+
if (scripts.win32Sidecar !== undefined) writeFileSync(join(dir, "hang.cjs"), scripts.win32Sidecar);
|
|
57
|
+
return { binPath, dir };
|
|
58
|
+
}
|
|
59
|
+
const binPath = join(dir, "codegraph");
|
|
60
|
+
writeFileSync(binPath, scripts.posix, { mode: 0o755 });
|
|
61
|
+
chmodSync(binPath, 0o755);
|
|
62
|
+
return { binPath, dir };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Keep the probe hermetic on POSIX but viable on win32: resolveCodegraphCommandInvocation wraps
|
|
66
|
+
// the fake .cmd in `cmd.exe /d /s /c`, and Windows can only resolve cmd.exe when the child env
|
|
67
|
+
// carries the real system PATH (System32) plus SystemRoot (both whitelisted in SAFE_AMBIENT_ENV_KEYS).
|
|
68
|
+
// A POSIX-only PATH makes the probe spawn fail, so the hook reports not-initialized and spawns.
|
|
69
|
+
function probeEnv(homeDir: string, binPath: string): Record<string, string> {
|
|
70
|
+
if (process.platform === "win32") {
|
|
71
|
+
const env: Record<string, string> = {
|
|
72
|
+
HOME: homeDir,
|
|
73
|
+
OMO_CODEGRAPH_BIN: binPath,
|
|
74
|
+
};
|
|
75
|
+
if (process.env["PATH"] !== undefined) env["PATH"] = process.env["PATH"];
|
|
76
|
+
if (process.env["SystemRoot"] !== undefined) env["SystemRoot"] = process.env["SystemRoot"];
|
|
77
|
+
return env;
|
|
78
|
+
}
|
|
79
|
+
return { HOME: homeDir, OMO_CODEGRAPH_BIN: binPath, PATH: "/usr/bin:/bin" };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isProcessAlive(pid: number): boolean {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(pid, 0);
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1.4.1 binary", () => {
|
|
92
|
+
it("#given a real 1.4.1 status payload for a migrated 1.0.1 store #when SessionStart probes via the default probe #then it stays silent without spawning a re-init worker", async () => {
|
|
93
|
+
// given
|
|
94
|
+
const stdout: string[] = [];
|
|
95
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
96
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-upgrade-home-"));
|
|
97
|
+
// The payload is a single JSON line with no cmd metacharacters (% ^ & < > |), so a plain echo is safe.
|
|
98
|
+
const fake = createFakeCodegraphBin({
|
|
99
|
+
posix: `#!/bin/sh\nprintf '%s\\n' '${MIGRATED_1_0_1_STORE_STATUS_JSON}'\n`,
|
|
100
|
+
win32: `@echo off\r\n@echo ${MIGRATED_1_0_1_STORE_STATUS_JSON}\r\n`,
|
|
101
|
+
});
|
|
102
|
+
const workspace = createAllowedWorkspace("codegraph-upgrade-workspace");
|
|
103
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
// when
|
|
107
|
+
const result = await executeCodegraphSessionStartHook({
|
|
108
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
109
|
+
cwd: workspace,
|
|
110
|
+
env: probeEnv(homeDir, fake.binPath),
|
|
111
|
+
stdin: Readable.from(["{}"]),
|
|
112
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
113
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// then
|
|
117
|
+
expect(result).toEqual({ action: "skipped-initialized", exitCode: 0 });
|
|
118
|
+
expect(spawned).toEqual([]);
|
|
119
|
+
expect(stdout.join("")).toBe("");
|
|
120
|
+
} finally {
|
|
121
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
122
|
+
rmSync(fake.dir, { recursive: true, force: true });
|
|
123
|
+
rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("#given the status probe spawns a hanging descendant #when SessionStart times out #then it exits promptly and reaps the descendant", async () => {
|
|
128
|
+
// given
|
|
129
|
+
const stdout: string[] = [];
|
|
130
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
131
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-slow-home-"));
|
|
132
|
+
const survivorPidPath = join(homeDir, "survivor.pid");
|
|
133
|
+
const fake = createFakeCodegraphBin({
|
|
134
|
+
posix: "#!/bin/sh\nsleep 30 &\necho \"$!\" > \"$HOME/survivor.pid\"\nwait\n",
|
|
135
|
+
win32: '@echo off\r\nnode "%~dp0hang.cjs"\r\n',
|
|
136
|
+
win32Sidecar: [
|
|
137
|
+
'const { spawn } = require("node:child_process");',
|
|
138
|
+
'const { writeFileSync } = require("node:fs");',
|
|
139
|
+
'const { join } = require("node:path");',
|
|
140
|
+
'const child = spawn(process.execPath, ["-e", "setInterval(() => {}, 1000)"], { stdio: "ignore" });',
|
|
141
|
+
'writeFileSync(join(process.env.HOME, "survivor.pid"), String(child.pid));',
|
|
142
|
+
"setInterval(() => {}, 1000);",
|
|
143
|
+
"",
|
|
144
|
+
].join("\n"),
|
|
145
|
+
});
|
|
146
|
+
const workspace = createAllowedWorkspace("codegraph-slow-probe-workspace");
|
|
147
|
+
let descendantPid: number | undefined;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
// when
|
|
151
|
+
const startedAt = Date.now();
|
|
152
|
+
const result = await executeCodegraphSessionStartHook({
|
|
153
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
154
|
+
cwd: workspace,
|
|
155
|
+
env: probeEnv(homeDir, fake.binPath),
|
|
156
|
+
stdin: Readable.from(["{}"]),
|
|
157
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
158
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
159
|
+
});
|
|
160
|
+
const elapsedMs = Date.now() - startedAt;
|
|
161
|
+
descendantPid = Number.parseInt(readFileSync(survivorPidPath, "utf8").trim(), 10);
|
|
162
|
+
|
|
163
|
+
// then
|
|
164
|
+
expect(result.exitCode).toBe(0);
|
|
165
|
+
expect(result.action).toBe("spawned");
|
|
166
|
+
expect(spawned).toHaveLength(1);
|
|
167
|
+
expect(elapsedMs).toBeLessThan(15_000);
|
|
168
|
+
expect(isProcessAlive(descendantPid)).toBeFalse();
|
|
169
|
+
} finally {
|
|
170
|
+
if (descendantPid !== undefined && isProcessAlive(descendantPid)) process.kill(descendantPid, "SIGKILL");
|
|
171
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
172
|
+
rmSync(fake.dir, { recursive: true, force: true });
|
|
173
|
+
rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -215,6 +215,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
215
215
|
// given
|
|
216
216
|
const stdout: string[] = [];
|
|
217
217
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
218
|
+
const statusProbeDaemonValues: boolean[] = [];
|
|
218
219
|
const workspace = createAllowedWorkspace("codegraph-workspace");
|
|
219
220
|
|
|
220
221
|
try {
|
|
@@ -226,12 +227,16 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
226
227
|
stdin: Readable.from(["{}"]),
|
|
227
228
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
228
229
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
229
|
-
statusProbe: () =>
|
|
230
|
+
statusProbe: (options) => {
|
|
231
|
+
statusProbeDaemonValues.push(options.daemon);
|
|
232
|
+
return Promise.resolve(false);
|
|
233
|
+
},
|
|
230
234
|
workerCliPath: "/plugin/components/codegraph/dist/cli.js",
|
|
231
235
|
});
|
|
232
236
|
|
|
233
237
|
// then
|
|
234
238
|
expect(result).toEqual({ action: "spawned", exitCode: 0 });
|
|
239
|
+
expect(statusProbeDaemonValues).toEqual([true]);
|
|
235
240
|
expect(spawned).toEqual([
|
|
236
241
|
{
|
|
237
242
|
args: ["/plugin/components/codegraph/dist/cli.js", "hook", "session-start-worker"],
|
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
import { chmodSync, writeFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
+
export const CODEGRAPH_141_DEFAULT_TOOLS: readonly Record<string, unknown>[] = [
|
|
4
|
+
{
|
|
5
|
+
name: "codegraph_explore",
|
|
6
|
+
description:
|
|
7
|
+
"PRIMARY TOOL — call FIRST for almost any question OR before an edit: how does X work, architecture, a bug, where/what is X, surveying an area, or the symbols you are about to change. Returns the verbatim source of the relevant symbols grouped by file in ONE capped call (Read-equivalent — treat the shown source as already Read; do NOT re-open those files), plus the call path among them. Query can be a natural-language question OR a bag of symbol/file names. Usually the ONLY call you need — more accurate context, in far fewer tokens and round-trips than a search/Read/Grep loop.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
query: {
|
|
12
|
+
type: "string",
|
|
13
|
+
description:
|
|
14
|
+
'Symbol names, file names, or short code terms to explore (e.g., "AuthService loginUser session-manager", "GraphTraverser BFS impact traversal.ts"). For a flow question, name the symbols spanning the flow (e.g. "mutateElement renderScene"). A natural-language question works too — no prior codegraph_search needed.',
|
|
15
|
+
},
|
|
16
|
+
maxFiles: {
|
|
17
|
+
type: "number",
|
|
18
|
+
description: "Maximum number of files to include source code from (default: 12)",
|
|
19
|
+
default: 12,
|
|
20
|
+
},
|
|
21
|
+
projectPath: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description:
|
|
24
|
+
"Absolute path to the project to query (or any directory inside it) — codegraph uses the nearest .codegraph/ index at or above that path. Omit to use this session's default project. Pass it to query a second codebase, or when the server root has no index of its own (e.g. a monorepo where only sub-projects are indexed, so there is no default project).",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
required: ["query"],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
3
32
|
export function writeFakeNewlineCodegraph(filePath: string): void {
|
|
4
33
|
writeFileSync(
|
|
5
34
|
filePath,
|
|
@@ -12,10 +41,10 @@ export function writeFakeNewlineCodegraph(filePath: string): void {
|
|
|
12
41
|
"rl.on('line', (line) => {",
|
|
13
42
|
" const request = JSON.parse(line);",
|
|
14
43
|
" if (request.method === 'initialize') {",
|
|
15
|
-
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.
|
|
44
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.4.1' } } }) + '\\n');",
|
|
16
45
|
" }",
|
|
17
46
|
" if (request.method === 'tools/list') {",
|
|
18
|
-
|
|
47
|
+
` process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: ${JSON.stringify(CODEGRAPH_141_DEFAULT_TOOLS)} } }) + '\\n');`,
|
|
19
48
|
" }",
|
|
20
49
|
"});",
|
|
21
50
|
].join("\n"),
|
|
@@ -43,7 +43,7 @@ describe("CodeGraph component runtime package metadata", () => {
|
|
|
43
43
|
const files = packageJson.files ?? [];
|
|
44
44
|
|
|
45
45
|
// then
|
|
46
|
-
expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.
|
|
46
|
+
expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.4.1");
|
|
47
47
|
expect(files).toContain("LICENSE");
|
|
48
48
|
expect(files).toContain("NODE-RUNTIME-LICENSES.md");
|
|
49
49
|
expect(files).toContain("NOTICE");
|
|
@@ -3,6 +3,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
|
+
import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
|
|
6
7
|
import { runCodegraphSessionStartWorker } from "../src/hook.ts";
|
|
7
8
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
8
9
|
|
|
@@ -41,7 +42,12 @@ describe("CodeGraph provisioned launcher Node guard", () => {
|
|
|
41
42
|
|
|
42
43
|
try {
|
|
43
44
|
mkdirSync(join(installDir, "bin"), { recursive: true });
|
|
45
|
+
mkdirSync(join(installDir, ".provisioned"), { recursive: true });
|
|
44
46
|
writeFileSync(binPath, "");
|
|
47
|
+
writeFileSync(
|
|
48
|
+
join(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`),
|
|
49
|
+
`${JSON.stringify({ binPath, version: CODEGRAPH_PINNED_VERSION })}\n`,
|
|
50
|
+
);
|
|
45
51
|
|
|
46
52
|
// when
|
|
47
53
|
const result = await runCodegraphSessionStartWorker({
|
package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { mkdirSync, mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { PassThrough, Writable } from "node:stream";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
+
import { isProcessAlive } from "../../../../../mcp-stdio-core/src/index.ts";
|
|
7
8
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
8
9
|
import {
|
|
9
10
|
frameMcpRequest,
|
|
10
11
|
writeFakeExitingCodegraph,
|
|
12
|
+
writeFakeHeldOpenCodegraph,
|
|
11
13
|
} from "./mcp-bridge-fixtures.ts";
|
|
12
14
|
|
|
13
15
|
const componentRoot = realpathSync(
|
|
@@ -66,4 +68,66 @@ describe("runCodegraphServe MCP bridge lifecycle", () => {
|
|
|
66
68
|
rmSync(tempRoot, { recursive: true, force: true });
|
|
67
69
|
}
|
|
68
70
|
});
|
|
71
|
+
|
|
72
|
+
it("#given a held-open Codegraph child and a dead parent #when the bridge watchdog polls #then the child is terminated and the bridge settles through the child-exit path", async () => {
|
|
73
|
+
// given
|
|
74
|
+
const tempRoot = mkdtempSync(
|
|
75
|
+
join(componentRoot, ".tmp-codegraph-orphan-"),
|
|
76
|
+
);
|
|
77
|
+
const projectRoot = join(tempRoot, "project");
|
|
78
|
+
const fakeCodegraph = join(tempRoot, "codegraph-held-open.cjs");
|
|
79
|
+
const childPidFile = join(tempRoot, "child.pid");
|
|
80
|
+
// Client stdio is held open and never sees EOF, so the parent-liveness
|
|
81
|
+
// watchdog is the only settle path. The probe reports the parent alive
|
|
82
|
+
// until the child has started, making the poll fire deterministically.
|
|
83
|
+
const input = new PassThrough();
|
|
84
|
+
const output = new PassThrough();
|
|
85
|
+
output.resume();
|
|
86
|
+
let childPid: number | undefined;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
mkdirSync(projectRoot, { recursive: true });
|
|
90
|
+
writeFakeHeldOpenCodegraph(fakeCodegraph);
|
|
91
|
+
const run = runCodegraphServe({
|
|
92
|
+
cwd: tempRoot,
|
|
93
|
+
env: {
|
|
94
|
+
CODEGRAPH_ALLOW_UNSAFE_NODE: "1",
|
|
95
|
+
CODEGRAPH_FAKE_LOG: childPidFile,
|
|
96
|
+
OMO_CODEGRAPH_BIN: fakeCodegraph,
|
|
97
|
+
OMO_CODEGRAPH_PROJECT_CWD: projectRoot,
|
|
98
|
+
PATH: process.env["PATH"],
|
|
99
|
+
},
|
|
100
|
+
nodeVersion: "22.14.0",
|
|
101
|
+
buildEnv: () => ({}),
|
|
102
|
+
resolve: () => ({
|
|
103
|
+
argsPrefix: [],
|
|
104
|
+
command: fakeCodegraph,
|
|
105
|
+
exists: true,
|
|
106
|
+
source: "env",
|
|
107
|
+
}),
|
|
108
|
+
stderr: { write: () => undefined },
|
|
109
|
+
stdin: input,
|
|
110
|
+
stdout: output,
|
|
111
|
+
parentWatchdog: {
|
|
112
|
+
pollIntervalMs: 10,
|
|
113
|
+
probeAlive: () => !existsSync(childPidFile),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// when
|
|
118
|
+
const exitCode = await run;
|
|
119
|
+
|
|
120
|
+
// then
|
|
121
|
+
expect(exitCode).not.toBe(0);
|
|
122
|
+
childPid = Number(readFileSync(childPidFile, "utf8"));
|
|
123
|
+
expect(isProcessAlive(childPid)).toBe(false);
|
|
124
|
+
} finally {
|
|
125
|
+
if (childPid !== undefined && isProcessAlive(childPid)) {
|
|
126
|
+
process.kill(childPid, "SIGKILL");
|
|
127
|
+
}
|
|
128
|
+
input.destroy();
|
|
129
|
+
output.destroy();
|
|
130
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
69
133
|
});
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
8
8
|
import {
|
|
9
9
|
arrayProperty,
|
|
10
|
+
CODEGRAPH_141_DEFAULT_TOOLS,
|
|
10
11
|
findTool,
|
|
11
12
|
frameMcpRequest,
|
|
12
13
|
parseMcpBodies,
|
|
@@ -86,19 +87,14 @@ describe("runCodegraphServe MCP protocol bridge", () => {
|
|
|
86
87
|
result: {
|
|
87
88
|
capabilities: { tools: { listChanged: false } },
|
|
88
89
|
protocolVersion: "2025-06-18",
|
|
89
|
-
serverInfo: { name: "codegraph", version: "1.
|
|
90
|
+
serverInfo: { name: "codegraph", version: "1.4.1" },
|
|
90
91
|
},
|
|
91
92
|
},
|
|
92
93
|
{
|
|
93
94
|
id: 2,
|
|
94
95
|
jsonrpc: "2.0",
|
|
95
96
|
result: {
|
|
96
|
-
tools:
|
|
97
|
-
{ name: "codegraph_search" },
|
|
98
|
-
{ name: "codegraph_node" },
|
|
99
|
-
{ name: "codegraph_explore" },
|
|
100
|
-
{ name: "codegraph_callers" },
|
|
101
|
-
],
|
|
97
|
+
tools: CODEGRAPH_141_DEFAULT_TOOLS,
|
|
102
98
|
},
|
|
103
99
|
},
|
|
104
100
|
]);
|
|
@@ -17,6 +17,7 @@ describe("runCodegraphServe MCP unavailable facade", () => {
|
|
|
17
17
|
const run = runCodegraphServe({
|
|
18
18
|
config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
|
|
19
19
|
env: { PATH: "/bin" },
|
|
20
|
+
nodeVersion: "22.14.0",
|
|
20
21
|
buildEnv: () => ({}),
|
|
21
22
|
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
22
23
|
stderr: { write: (chunk: string) => stderr.push(chunk) },
|
|
@@ -47,7 +48,7 @@ describe("runCodegraphServe MCP unavailable facade", () => {
|
|
|
47
48
|
result: {
|
|
48
49
|
capabilities: { tools: { listChanged: false } },
|
|
49
50
|
protocolVersion: "2025-06-18",
|
|
50
|
-
serverInfo: { name: "codegraph", version: "1.
|
|
51
|
+
serverInfo: { name: "codegraph", version: "1.4.1" },
|
|
51
52
|
},
|
|
52
53
|
});
|
|
53
54
|
});
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
5
5
|
|
|
6
6
|
describe("runCodegraphServe provisioning", () => {
|
|
7
|
-
it("#given CodeGraph is unresolved #when serving MCP #then provisions CodeGraph
|
|
7
|
+
it("#given CodeGraph is unresolved and daemon is omitted #when serving MCP #then provisions CodeGraph with daemon-on", async () => {
|
|
8
8
|
// given
|
|
9
9
|
const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
|
|
10
10
|
const calls: Array<{
|
|
@@ -20,7 +20,6 @@ describe("runCodegraphServe provisioning", () => {
|
|
|
20
20
|
env: { PATH: "/bin" },
|
|
21
21
|
homeDir: "/tmp/home",
|
|
22
22
|
nodeVersion: "22.14.0",
|
|
23
|
-
buildEnv: () => ({}),
|
|
24
23
|
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
25
24
|
ensureProvisioned: (options) =>
|
|
26
25
|
Promise.resolve({
|
|
@@ -41,8 +40,63 @@ describe("runCodegraphServe provisioning", () => {
|
|
|
41
40
|
{
|
|
42
41
|
args: ["serve", "--mcp"],
|
|
43
42
|
command: binPath,
|
|
44
|
-
env: {
|
|
43
|
+
env: {
|
|
44
|
+
CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
|
|
45
|
+
CODEGRAPH_NO_DOWNLOAD: "1",
|
|
46
|
+
CODEGRAPH_TELEMETRY: "0",
|
|
47
|
+
DO_NOT_TRACK: "1",
|
|
48
|
+
PATH: "/bin",
|
|
49
|
+
},
|
|
45
50
|
},
|
|
46
51
|
]);
|
|
47
52
|
});
|
|
53
|
+
|
|
54
|
+
it("#given CodeGraph is unresolved and codegraph.daemon=false #when serving MCP #then provisions CodeGraph with daemon-off", async () => {
|
|
55
|
+
// given
|
|
56
|
+
const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
|
|
57
|
+
const calls: Array<{
|
|
58
|
+
readonly args: readonly string[];
|
|
59
|
+
readonly command: string;
|
|
60
|
+
readonly env: Record<string, string | undefined>;
|
|
61
|
+
}> = [];
|
|
62
|
+
const stderr: string[] = [];
|
|
63
|
+
|
|
64
|
+
// when
|
|
65
|
+
const exitCode = await runCodegraphServe({
|
|
66
|
+
config: { codegraph: { daemon: false, enabled: true }, sources: [], warnings: [] },
|
|
67
|
+
env: { PATH: "/bin" },
|
|
68
|
+
homeDir: "/tmp/home",
|
|
69
|
+
nodeVersion: "22.14.0",
|
|
70
|
+
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
71
|
+
ensureProvisioned: (options) =>
|
|
72
|
+
Promise.resolve({
|
|
73
|
+
binPath: join(options.installDir ?? "/tmp/home/.omo/codegraph", "bin", "codegraph"),
|
|
74
|
+
provisioned: true,
|
|
75
|
+
}),
|
|
76
|
+
runProcess: (command, args, options) => {
|
|
77
|
+
calls.push({ args, command, env: options.env });
|
|
78
|
+
return Promise.resolve(0);
|
|
79
|
+
},
|
|
80
|
+
stderr: { write: (chunk: string) => stderr.push(chunk) },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// then
|
|
84
|
+
expect(exitCode).toBe(0);
|
|
85
|
+
expect(stderr).toEqual([]);
|
|
86
|
+
expect(calls).toEqual([
|
|
87
|
+
{
|
|
88
|
+
args: ["serve", "--mcp"],
|
|
89
|
+
command: binPath,
|
|
90
|
+
env: {
|
|
91
|
+
CODEGRAPH_INSTALL_DIR: join("/tmp/home", ".omo", "codegraph"),
|
|
92
|
+
CODEGRAPH_NO_DAEMON: "1",
|
|
93
|
+
CODEGRAPH_NO_DOWNLOAD: "1",
|
|
94
|
+
CODEGRAPH_TELEMETRY: "0",
|
|
95
|
+
DO_NOT_TRACK: "1",
|
|
96
|
+
PATH: "/bin",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
expect(calls[0]?.env["CODEGRAPH_NO_DAEMON"]).toBe("1");
|
|
101
|
+
});
|
|
48
102
|
});
|
|
@@ -17,6 +17,7 @@ describe("runCodegraphServe unavailable CodeGraph paths", () => {
|
|
|
17
17
|
...closedMcpStdio(),
|
|
18
18
|
config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
|
|
19
19
|
env: { PATH: "/bin" },
|
|
20
|
+
nodeVersion: "22.14.0",
|
|
20
21
|
buildEnv: () => ({}),
|
|
21
22
|
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
22
23
|
runProcess: (command: string) => {
|
|
@@ -122,6 +123,47 @@ describe("runCodegraphServe unavailable CodeGraph paths", () => {
|
|
|
122
123
|
rmSync(workspace, { recursive: true, force: true });
|
|
123
124
|
}
|
|
124
125
|
});
|
|
126
|
+
|
|
127
|
+
it("#given the unavailable facade with held-open stdio and a dead parent #when the watchdog polls #then the placeholder server settles without waiting for stdin EOF", async () => {
|
|
128
|
+
// given
|
|
129
|
+
// win32: the real-timer watchdog + PassThrough.destroy() teardown race leaves
|
|
130
|
+
// the read loop's async iterator pending on Windows, so this held-open-stdin
|
|
131
|
+
// case cannot settle under bun:test (which has no fake timers). The watchdog
|
|
132
|
+
// settle path IS covered deterministically by mcp-stdio-core's fake-timer test
|
|
133
|
+
// (passes on win32) and by real-process QA (task-13-*); production settles via
|
|
134
|
+
// stdin EOF, exercised by the other tests in this file that run on win32.
|
|
135
|
+
if (process.platform === "win32") return;
|
|
136
|
+
// Client stdio is held open and never sees EOF, so the parent-liveness
|
|
137
|
+
// watchdog is the only settle path for the placeholder server.
|
|
138
|
+
const stdin = new PassThrough();
|
|
139
|
+
const stdout = new PassThrough();
|
|
140
|
+
stdout.resume();
|
|
141
|
+
const stderr: string[] = [];
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
// when
|
|
145
|
+
const exitCode = await runCodegraphServe({
|
|
146
|
+
config: { codegraph: { enabled: false }, sources: [], warnings: [] },
|
|
147
|
+
env: {},
|
|
148
|
+
stdin,
|
|
149
|
+
stdout,
|
|
150
|
+
stderr: { write: (chunk: string) => stderr.push(chunk) },
|
|
151
|
+
parentWatchdog: { pollIntervalMs: 10, probeAlive: () => false },
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// then
|
|
155
|
+
expect(exitCode).toBe(0);
|
|
156
|
+
expect(stderr).toEqual([
|
|
157
|
+
"CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.\n",
|
|
158
|
+
]);
|
|
159
|
+
} finally {
|
|
160
|
+
// The held-open streams are never ended by the test; destroy them so the
|
|
161
|
+
// bun test runner's event loop can drain and exit (an undestroyed
|
|
162
|
+
// PassThrough keeps the process alive on win32 and hangs the suite).
|
|
163
|
+
stdin.destroy();
|
|
164
|
+
stdout.destroy();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
125
167
|
});
|
|
126
168
|
|
|
127
169
|
function closedMcpStdio(): { readonly stdin: PassThrough; readonly stdout: PassThrough } {
|