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
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// components/codegraph/src/cli.ts
|
|
4
|
-
import { realpathSync as
|
|
5
|
-
import { basename as basename5, resolve as
|
|
4
|
+
import { realpathSync as realpathSync7 } from "node:fs";
|
|
5
|
+
import { basename as basename5, resolve as resolve9 } from "node:path";
|
|
6
6
|
import { stderr as processStderr4 } from "node:process";
|
|
7
7
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
8
8
|
|
|
9
9
|
// components/codegraph/src/hook.ts
|
|
10
|
-
import {
|
|
10
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
11
11
|
import { homedir as homedir13 } from "node:os";
|
|
12
|
-
import { join as join13 } from "node:path";
|
|
13
12
|
import {
|
|
14
13
|
cwd as processCwd2,
|
|
15
14
|
env as processEnv2,
|
|
@@ -56,6 +55,7 @@ var SAFE_AMBIENT_ENV_KEYS = new Set([
|
|
|
56
55
|
var SAFE_CODEGRAPH_RUNTIME_ENV_KEYS = new Set([
|
|
57
56
|
"CODEGRAPH_ALLOW_UNSAFE_NODE",
|
|
58
57
|
"CODEGRAPH_BIN",
|
|
58
|
+
"CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS",
|
|
59
59
|
"CODEGRAPH_FAKE_LOG",
|
|
60
60
|
"CODEGRAPH_NO_DAEMON",
|
|
61
61
|
"CODEGRAPH_NODE_BIN",
|
|
@@ -67,7 +67,7 @@ function buildCodegraphEnv(options = {}) {
|
|
|
67
67
|
const homeDir = options.homeDir ?? homedir();
|
|
68
68
|
return {
|
|
69
69
|
[CODEGRAPH_INSTALL_DIR_ENV]: join(homeDir, ".omo", "codegraph"),
|
|
70
|
-
[CODEGRAPH_NO_DAEMON_ENV]: "1",
|
|
70
|
+
...options.daemon === false ? { [CODEGRAPH_NO_DAEMON_ENV]: "1" } : {},
|
|
71
71
|
[CODEGRAPH_NO_DOWNLOAD_ENV]: "1",
|
|
72
72
|
[CODEGRAPH_TELEMETRY_ENV]: "0",
|
|
73
73
|
[DO_NOT_TRACK_ENV]: "1"
|
|
@@ -399,6 +399,9 @@ var ANSI_ESCAPE_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
|
399
399
|
var CODEGRAPH_STATUS_PROJECT_PATTERN = /^.*?\bProject:\s*(.+?)\s*$/im;
|
|
400
400
|
var CODEGRAPH_STATUS_UNINITIALIZED_PATTERN = /^.*?\bNot initialized\s*$/im;
|
|
401
401
|
var CODEGRAPH_INIT_HINT_PATTERN = /Run\s+["'`]codegraph init["'`]\s+(?:in that project first|to initialize)\.?/i;
|
|
402
|
+
var CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN = /The project at (.+?) isn't indexed with codegraph\b/i;
|
|
403
|
+
var CODEGRAPH_NO_PROJECT_LOADED_PATTERN = /No CodeGraph project is loaded for this session\./i;
|
|
404
|
+
var CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN = /^Searched for a \.codegraph\/ directory starting from:\s*(.+?)\s*$/im;
|
|
402
405
|
function getCodegraphUninitializedProject(input) {
|
|
403
406
|
const output = textFromUnknown(input.toolOutput);
|
|
404
407
|
if (!isCodegraphTool(input.toolName))
|
|
@@ -439,6 +442,16 @@ function extractProjectPath(output) {
|
|
|
439
442
|
const uninitializedProject = uninitializedMatch?.[1]?.trim();
|
|
440
443
|
if (uninitializedProject && uninitializedProject.length > 0)
|
|
441
444
|
return uninitializedProject;
|
|
445
|
+
const notIndexedMatch = normalizedOutput.match(CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN);
|
|
446
|
+
const notIndexedProject = notIndexedMatch?.[1]?.trim();
|
|
447
|
+
if (notIndexedProject && notIndexedProject.length > 0)
|
|
448
|
+
return notIndexedProject;
|
|
449
|
+
if (CODEGRAPH_NO_PROJECT_LOADED_PATTERN.test(normalizedOutput)) {
|
|
450
|
+
const searchedFromMatch = normalizedOutput.match(CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN);
|
|
451
|
+
const searchedFromProject = searchedFromMatch?.[1]?.trim();
|
|
452
|
+
if (searchedFromProject && searchedFromProject.length > 0)
|
|
453
|
+
return searchedFromProject;
|
|
454
|
+
}
|
|
442
455
|
if (!looksLikeCodegraphUninitializedOutput(normalizedOutput))
|
|
443
456
|
return null;
|
|
444
457
|
const statusMatch = normalizedOutput.match(CODEGRAPH_STATUS_PROJECT_PATTERN);
|
|
@@ -479,16 +492,101 @@ function isRecord(value) {
|
|
|
479
492
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
480
493
|
}
|
|
481
494
|
|
|
495
|
+
// ../../utils/src/codegraph/managed-runtime.ts
|
|
496
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
497
|
+
import { join as join6, resolve as resolve4 } from "node:path";
|
|
498
|
+
|
|
499
|
+
// ../../utils/src/record-type-guard.ts
|
|
500
|
+
function isPlainRecord(value) {
|
|
501
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// ../../utils/src/codegraph/manifest.ts
|
|
505
|
+
var CODEGRAPH_PINNED_VERSION = "1.4.1";
|
|
506
|
+
var CODEGRAPH_PROVISION_MANIFEST = {
|
|
507
|
+
assets: {
|
|
508
|
+
"darwin-arm64": {
|
|
509
|
+
executableName: "codegraph",
|
|
510
|
+
sha256: "4a679ae5a5cb9fff900dd59bb786da6a581b7f68f4cf713bdedd137e347d34dc",
|
|
511
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-arm64.tar.gz"
|
|
512
|
+
},
|
|
513
|
+
"darwin-x64": {
|
|
514
|
+
executableName: "codegraph",
|
|
515
|
+
sha256: "436f96943cfd926ea6d0a8454f18833d21254d5fd9b3d224317b1426132def95",
|
|
516
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-x64.tar.gz"
|
|
517
|
+
},
|
|
518
|
+
"linux-arm64": {
|
|
519
|
+
executableName: "codegraph",
|
|
520
|
+
sha256: "0d62c5eb2722f8d19d20f7a1bd974445e18d5294cb59be116a0c3d55ce87591f",
|
|
521
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-arm64.tar.gz"
|
|
522
|
+
},
|
|
523
|
+
"linux-x64": {
|
|
524
|
+
executableName: "codegraph",
|
|
525
|
+
sha256: "fb585ff5018d6faaa46d282b61f4f689bc7967ed8a1b467a5c556dd7ced9b542",
|
|
526
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-x64.tar.gz"
|
|
527
|
+
},
|
|
528
|
+
"win32-arm64": {
|
|
529
|
+
executableName: "codegraph.cmd",
|
|
530
|
+
sha256: "e2a2a28c802a79804c7df203afa50bd461309c6c180ce3f76079fdc7cddc7697",
|
|
531
|
+
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.4.1.tgz"
|
|
532
|
+
},
|
|
533
|
+
"win32-x64": {
|
|
534
|
+
executableName: "codegraph.cmd",
|
|
535
|
+
sha256: "4f08700fda5f4a03ad5b2956135c5788d739a351b3433db2b5820e5d5224c30d",
|
|
536
|
+
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.4.1.tgz"
|
|
537
|
+
}
|
|
538
|
+
},
|
|
539
|
+
version: CODEGRAPH_PINNED_VERSION
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// ../../utils/src/codegraph/managed-runtime.ts
|
|
543
|
+
function resolvePinnedCodegraphBin(installDir, options = {}) {
|
|
544
|
+
if (installDir === undefined)
|
|
545
|
+
return null;
|
|
546
|
+
const fileExists = options.fileExists ?? existsSync3;
|
|
547
|
+
const readText = options.readText ?? ((filePath) => readFileSync3(filePath, "utf8"));
|
|
548
|
+
const expectedBin = join6(installDir, "bin", (options.platform ?? process.platform) === "win32" ? "codegraph.cmd" : "codegraph");
|
|
549
|
+
const markerPath = join6(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`);
|
|
550
|
+
if (!fileExists(expectedBin) || !fileExists(markerPath))
|
|
551
|
+
return null;
|
|
552
|
+
let markerText;
|
|
553
|
+
try {
|
|
554
|
+
markerText = readText(markerPath);
|
|
555
|
+
} catch {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
const marker = parseProvisionMarker(markerText);
|
|
559
|
+
if (marker === null || marker.version !== CODEGRAPH_PINNED_VERSION)
|
|
560
|
+
return null;
|
|
561
|
+
return resolve4(marker.binPath) === resolve4(expectedBin) ? expectedBin : null;
|
|
562
|
+
}
|
|
563
|
+
function parseProvisionMarker(text) {
|
|
564
|
+
try {
|
|
565
|
+
const value = JSON.parse(text);
|
|
566
|
+
if (!isPlainRecord(value))
|
|
567
|
+
return null;
|
|
568
|
+
const binPath = value["binPath"];
|
|
569
|
+
const version = value["version"];
|
|
570
|
+
if (typeof binPath !== "string" || typeof version !== "string")
|
|
571
|
+
return null;
|
|
572
|
+
return { binPath, version };
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (error instanceof SyntaxError)
|
|
575
|
+
return null;
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
482
580
|
// ../../utils/src/codegraph/resolve.ts
|
|
483
|
-
import { existsSync as
|
|
581
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
484
582
|
import { homedir as homedir6 } from "node:os";
|
|
485
583
|
import { spawnSync } from "node:child_process";
|
|
486
|
-
import { basename as basename2, dirname as dirname2, join as
|
|
584
|
+
import { basename as basename2, dirname as dirname2, join as join8 } from "node:path";
|
|
487
585
|
import { createRequire } from "node:module";
|
|
488
586
|
|
|
489
587
|
// ../../utils/src/runtime/which.ts
|
|
490
588
|
import { accessSync, constants } from "node:fs";
|
|
491
|
-
import { delimiter, join as
|
|
589
|
+
import { delimiter, join as join7 } from "node:path";
|
|
492
590
|
var runtime = globalThis;
|
|
493
591
|
function isUnsafeCommandName(commandName) {
|
|
494
592
|
if (commandName.includes("/") || commandName.includes("\\"))
|
|
@@ -543,7 +641,7 @@ function bunWhich(commandName) {
|
|
|
543
641
|
return null;
|
|
544
642
|
for (const pathEntry of pathEntries) {
|
|
545
643
|
for (const candidateName of candidateNames) {
|
|
546
|
-
const candidatePath =
|
|
644
|
+
const candidatePath = join7(pathEntry, candidateName);
|
|
547
645
|
if (isExecutable(candidatePath))
|
|
548
646
|
return candidatePath;
|
|
549
647
|
}
|
|
@@ -660,18 +758,13 @@ function defaultNodeRuntime(env, fileExists, which, nodeVersion) {
|
|
|
660
758
|
return null;
|
|
661
759
|
}
|
|
662
760
|
function defaultProvisionedBin(homeDir, fileExists) {
|
|
663
|
-
|
|
664
|
-
const candidates = [
|
|
665
|
-
join7(homeDir, ".omo", "codegraph", "bin", binaryName),
|
|
666
|
-
join7(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
|
|
667
|
-
];
|
|
668
|
-
return candidates.find((candidate) => fileExists(candidate)) ?? null;
|
|
761
|
+
return resolvePinnedCodegraphBin(join8(homeDir, ".omo", "codegraph"), { fileExists });
|
|
669
762
|
}
|
|
670
763
|
function resolveBundledShim(requireResolve, fileExists) {
|
|
671
764
|
try {
|
|
672
765
|
const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
|
|
673
766
|
const packageRoot = dirname2(packageJson);
|
|
674
|
-
const candidates = [
|
|
767
|
+
const candidates = [join8(packageRoot, "bin", "codegraph.js"), join8(packageRoot, "npm-shim.js")];
|
|
675
768
|
return candidates.find((candidate) => fileExists(candidate)) ?? null;
|
|
676
769
|
} catch (error) {
|
|
677
770
|
if (error instanceof Error)
|
|
@@ -687,7 +780,7 @@ function resolveBundledShim(requireResolve, fileExists) {
|
|
|
687
780
|
}
|
|
688
781
|
function resolveCodegraphCommand(options = {}) {
|
|
689
782
|
const env = options.env ?? process.env;
|
|
690
|
-
const fileExists = options.fileExists ??
|
|
783
|
+
const fileExists = options.fileExists ?? existsSync4;
|
|
691
784
|
const configuredBin = env[CODEGRAPH_ENV_BIN]?.trim() || env[CODEGRAPH_LEGACY_ENV_BIN]?.trim();
|
|
692
785
|
if (configuredBin !== undefined && configuredBin.length > 0) {
|
|
693
786
|
return { argsPrefix: [], command: configuredBin, exists: fileExists(configuredBin), source: "env" };
|
|
@@ -712,15 +805,97 @@ function resolveCodegraphCommand(options = {}) {
|
|
|
712
805
|
};
|
|
713
806
|
}
|
|
714
807
|
|
|
808
|
+
// ../../utils/src/process-tree.ts
|
|
809
|
+
import { execFile, spawn } from "node:child_process";
|
|
810
|
+
import { StringDecoder } from "node:string_decoder";
|
|
811
|
+
function runProcessWithTreeTimeout(options) {
|
|
812
|
+
return new Promise((resolvePromise) => {
|
|
813
|
+
const child = spawn(options.command, [...options.args], {
|
|
814
|
+
cwd: options.cwd,
|
|
815
|
+
detached: process.platform !== "win32",
|
|
816
|
+
env: options.env,
|
|
817
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
818
|
+
windowsHide: true
|
|
819
|
+
});
|
|
820
|
+
let stderr = "";
|
|
821
|
+
let stderrBytes = 0;
|
|
822
|
+
let stdout = "";
|
|
823
|
+
let stdoutBytes = 0;
|
|
824
|
+
let timedOut = false;
|
|
825
|
+
let overflowed = false;
|
|
826
|
+
let settled = false;
|
|
827
|
+
let treeTermination;
|
|
828
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
829
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
830
|
+
const capture = (target, chunk) => {
|
|
831
|
+
if (overflowed)
|
|
832
|
+
return;
|
|
833
|
+
const currentBytes = target === "stdout" ? stdoutBytes : stderrBytes;
|
|
834
|
+
if (currentBytes + chunk.length > options.maxBuffer) {
|
|
835
|
+
overflowed = true;
|
|
836
|
+
treeTermination ??= terminateProcessTree(child.pid);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
if (target === "stdout") {
|
|
840
|
+
stdoutBytes += chunk.length;
|
|
841
|
+
stdout += stdoutDecoder.write(chunk);
|
|
842
|
+
} else {
|
|
843
|
+
stderrBytes += chunk.length;
|
|
844
|
+
stderr += stderrDecoder.write(chunk);
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
child.stdout.on("data", (chunk) => capture("stdout", chunk));
|
|
848
|
+
child.stderr.on("data", (chunk) => capture("stderr", chunk));
|
|
849
|
+
const timeout = setTimeout(() => {
|
|
850
|
+
timedOut = true;
|
|
851
|
+
treeTermination ??= terminateProcessTree(child.pid);
|
|
852
|
+
}, options.timeoutMs);
|
|
853
|
+
timeout.unref();
|
|
854
|
+
const settle = async (exitCode, signal) => {
|
|
855
|
+
if (settled)
|
|
856
|
+
return;
|
|
857
|
+
settled = true;
|
|
858
|
+
clearTimeout(timeout);
|
|
859
|
+
await treeTermination;
|
|
860
|
+
stderr += stderrDecoder.end();
|
|
861
|
+
stdout += stdoutDecoder.end();
|
|
862
|
+
resolvePromise({ exitCode, signal, stderr, stdout, timedOut });
|
|
863
|
+
};
|
|
864
|
+
child.once("error", () => void settle(1, null));
|
|
865
|
+
child.once("close", (code, signal) => void settle(overflowed ? 1 : code ?? 1, signal));
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
function terminateProcessTree(pid) {
|
|
869
|
+
if (pid === undefined)
|
|
870
|
+
return Promise.resolve();
|
|
871
|
+
if (process.platform === "win32")
|
|
872
|
+
return taskkillProcessTree(pid);
|
|
873
|
+
try {
|
|
874
|
+
process.kill(-pid, "SIGKILL");
|
|
875
|
+
} catch (error) {
|
|
876
|
+
if (!isIgnorableKillError(error))
|
|
877
|
+
throw error;
|
|
878
|
+
}
|
|
879
|
+
return Promise.resolve();
|
|
880
|
+
}
|
|
881
|
+
function taskkillProcessTree(pid) {
|
|
882
|
+
return new Promise((resolvePromise) => {
|
|
883
|
+
execFile("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { timeout: 5000, windowsHide: true }, () => resolvePromise());
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
function isIgnorableKillError(error) {
|
|
887
|
+
return error instanceof Error && "code" in error && (error.code === "EPERM" || error.code === "ESRCH");
|
|
888
|
+
}
|
|
889
|
+
|
|
715
890
|
// shared/src/config-loader.ts
|
|
716
891
|
import { homedir as homedir8 } from "node:os";
|
|
717
892
|
|
|
718
893
|
// ../../utils/src/omo-config/loader.ts
|
|
719
|
-
import { existsSync as
|
|
894
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
720
895
|
import { homedir as homedir7 } from "node:os";
|
|
721
896
|
|
|
722
897
|
// ../../utils/src/omo-config/body.ts
|
|
723
|
-
import { readFileSync as
|
|
898
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
724
899
|
|
|
725
900
|
// ../../utils/src/deep-merge.ts
|
|
726
901
|
var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
@@ -1597,8 +1772,9 @@ function parseJsoncSafe(content) {
|
|
|
1597
1772
|
var HARNESS_IDS = ["codex", "opencode", "omo"];
|
|
1598
1773
|
var SETTING_HARNESS_SUPPORT = {
|
|
1599
1774
|
"codegraph.auto_provision": HARNESS_IDS,
|
|
1775
|
+
"codegraph.daemon": ["codex", "opencode"],
|
|
1600
1776
|
"codegraph.enabled": HARNESS_IDS,
|
|
1601
|
-
"codegraph.excluded_roots": ["codex"],
|
|
1777
|
+
"codegraph.excluded_roots": ["codex", "opencode"],
|
|
1602
1778
|
"codegraph.install_dir": HARNESS_IDS,
|
|
1603
1779
|
"codegraph.telemetry": HARNESS_IDS,
|
|
1604
1780
|
"codegraph.watch_debounce_ms": ["opencode", "omo"]
|
|
@@ -1608,6 +1784,7 @@ var SETTING_HARNESS_SUPPORT = {
|
|
|
1608
1784
|
var BUILT_IN_DEFAULTS = {
|
|
1609
1785
|
codegraph: {
|
|
1610
1786
|
auto_provision: true,
|
|
1787
|
+
daemon: true,
|
|
1611
1788
|
enabled: true,
|
|
1612
1789
|
telemetry: false
|
|
1613
1790
|
}
|
|
@@ -1615,6 +1792,7 @@ var BUILT_IN_DEFAULTS = {
|
|
|
1615
1792
|
var HARNESS_BLOCK_KEYS = HARNESS_IDS.map((harness) => `[${harness}]`);
|
|
1616
1793
|
var CODEGRAPH_SETTING_KEYS = [
|
|
1617
1794
|
"auto_provision",
|
|
1795
|
+
"daemon",
|
|
1618
1796
|
"enabled",
|
|
1619
1797
|
"excluded_roots",
|
|
1620
1798
|
"install_dir",
|
|
@@ -1688,6 +1866,10 @@ function setCodegraphSetting(config, key, value) {
|
|
|
1688
1866
|
if (typeof value === "boolean")
|
|
1689
1867
|
config.auto_provision = value;
|
|
1690
1868
|
return;
|
|
1869
|
+
case "daemon":
|
|
1870
|
+
if (typeof value === "boolean")
|
|
1871
|
+
config.daemon = value;
|
|
1872
|
+
return;
|
|
1691
1873
|
case "enabled":
|
|
1692
1874
|
if (typeof value === "boolean")
|
|
1693
1875
|
config.enabled = value;
|
|
@@ -1762,7 +1944,7 @@ function normalizeActiveHarnessBlock(value, harness, pathPrefix, warnings) {
|
|
|
1762
1944
|
}
|
|
1763
1945
|
function loadConfigFile(path, harness) {
|
|
1764
1946
|
try {
|
|
1765
|
-
const content =
|
|
1947
|
+
const content = readFileSync4(path, "utf-8");
|
|
1766
1948
|
const parsed = parseJsoncSafe(content);
|
|
1767
1949
|
if (parsed.errors.length > 0) {
|
|
1768
1950
|
return {
|
|
@@ -1885,22 +2067,22 @@ function buildEnvOverrides(harness, env, warnings, merge) {
|
|
|
1885
2067
|
}
|
|
1886
2068
|
|
|
1887
2069
|
// ../../utils/src/omo-config/resolve.ts
|
|
1888
|
-
import { existsSync as
|
|
1889
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
2070
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
2071
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join9, relative, resolve as resolve5 } from "node:path";
|
|
1890
2072
|
function containsPath(parent, child) {
|
|
1891
2073
|
const pathToChild = relative(parent, child);
|
|
1892
2074
|
return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute2(pathToChild);
|
|
1893
2075
|
}
|
|
1894
2076
|
function findProjectConfigPathsNearestFirst(cwd, homeDir) {
|
|
1895
|
-
const startDir =
|
|
1896
|
-
const stopBeforeDir = containsPath(
|
|
2077
|
+
const startDir = resolve5(cwd);
|
|
2078
|
+
const stopBeforeDir = containsPath(resolve5(homeDir), startDir) ? resolve5(homeDir) : null;
|
|
1897
2079
|
const paths = [];
|
|
1898
2080
|
let currentDir = startDir;
|
|
1899
2081
|
while (true) {
|
|
1900
2082
|
if (stopBeforeDir !== null && currentDir === stopBeforeDir)
|
|
1901
2083
|
break;
|
|
1902
|
-
const configPath =
|
|
1903
|
-
if (
|
|
2084
|
+
const configPath = join9(currentDir, ".omo", "config.jsonc");
|
|
2085
|
+
if (existsSync5(configPath)) {
|
|
1904
2086
|
paths.push(configPath);
|
|
1905
2087
|
}
|
|
1906
2088
|
const parentDir = dirname3(currentDir);
|
|
@@ -1911,7 +2093,7 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
|
|
|
1911
2093
|
return paths;
|
|
1912
2094
|
}
|
|
1913
2095
|
function resolveOmoConfigPaths(options) {
|
|
1914
|
-
const globalPath =
|
|
2096
|
+
const globalPath = join9(resolve5(options.homeDir), ".omo", "config.jsonc");
|
|
1915
2097
|
const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
|
|
1916
2098
|
return [
|
|
1917
2099
|
{ path: globalPath, scope: "global" },
|
|
@@ -1936,7 +2118,7 @@ function loadOmoConfig(options) {
|
|
|
1936
2118
|
const sources = [];
|
|
1937
2119
|
const warnings = [];
|
|
1938
2120
|
for (const candidate of resolveOmoConfigPaths({ cwd, homeDir })) {
|
|
1939
|
-
if (!
|
|
2121
|
+
if (!existsSync6(candidate.path)) {
|
|
1940
2122
|
if (candidate.scope === "global") {
|
|
1941
2123
|
sources.push(toMissingSource(candidate));
|
|
1942
2124
|
}
|
|
@@ -2007,77 +2189,131 @@ function isNonFatalCodegraphGcError(error) {
|
|
|
2007
2189
|
|
|
2008
2190
|
// components/codegraph/src/hook-sweep.ts
|
|
2009
2191
|
import { fileURLToPath } from "node:url";
|
|
2010
|
-
// ../../utils/src/
|
|
2011
|
-
import { existsSync as
|
|
2192
|
+
// ../../utils/src/process-sweep/sweeper.ts
|
|
2193
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, statSync as statSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2012
2194
|
import { homedir as homedir10 } from "node:os";
|
|
2013
|
-
import { dirname as
|
|
2014
|
-
|
|
2015
|
-
// ../../utils/src/codegraph/process-exec.ts
|
|
2016
|
-
import { execFile } from "node:child_process";
|
|
2195
|
+
import { dirname as dirname5, join as join12 } from "node:path";
|
|
2017
2196
|
|
|
2018
|
-
// ../../utils/src/codegraph/
|
|
2019
|
-
import {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2197
|
+
// ../../utils/src/codegraph/daemon-lock.ts
|
|
2198
|
+
import { readFileSync as readFileSync5, realpathSync as realpathSync4 } from "node:fs";
|
|
2199
|
+
import { dirname as dirname4, join as join10, resolve as resolve6 } from "node:path";
|
|
2200
|
+
function parseDaemonLock(raw) {
|
|
2201
|
+
const trimmed = raw.trim();
|
|
2202
|
+
if (trimmed.length === 0)
|
|
2203
|
+
return null;
|
|
2204
|
+
try {
|
|
2205
|
+
const parsed = JSON.parse(trimmed);
|
|
2206
|
+
if (typeof parsed === "object" && parsed !== null && "pid" in parsed) {
|
|
2207
|
+
const pid = parsed.pid;
|
|
2208
|
+
if (typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
|
|
2209
|
+
const record = parsed;
|
|
2210
|
+
return {
|
|
2211
|
+
pid,
|
|
2212
|
+
...typeof record["socketPath"] === "string" ? { socketPath: record["socketPath"] } : {},
|
|
2213
|
+
...typeof record["startedAt"] === "number" ? { startedAt: record["startedAt"] } : {},
|
|
2214
|
+
...typeof record["version"] === "string" ? { version: record["version"] } : {}
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
return null;
|
|
2219
|
+
} catch (error) {
|
|
2220
|
+
if (!(error instanceof SyntaxError))
|
|
2221
|
+
throw error;
|
|
2034
2222
|
}
|
|
2035
|
-
|
|
2223
|
+
const legacyPid = Number(trimmed);
|
|
2224
|
+
if (Number.isSafeInteger(legacyPid) && legacyPid > 0)
|
|
2225
|
+
return { pid: legacyPid };
|
|
2226
|
+
return null;
|
|
2036
2227
|
}
|
|
2037
|
-
function
|
|
2038
|
-
const
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2228
|
+
function daemonLockCandidates(projectRoot) {
|
|
2229
|
+
const dirs = new Set;
|
|
2230
|
+
const resolved = resolve6(projectRoot);
|
|
2231
|
+
collectAncestors(resolved, dirs);
|
|
2232
|
+
collectAncestors(realpathIfPossible2(resolved), dirs);
|
|
2233
|
+
return [...dirs].map((dir) => join10(dir, ".codegraph", "daemon.pid"));
|
|
2234
|
+
}
|
|
2235
|
+
function evaluateDaemonStaleness(pid, projectRoot) {
|
|
2236
|
+
let sawLock = false;
|
|
2237
|
+
for (const lockPath of daemonLockCandidates(projectRoot)) {
|
|
2238
|
+
const raw = readLockIfPresent(lockPath);
|
|
2239
|
+
if (raw === undefined)
|
|
2043
2240
|
continue;
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2241
|
+
if (raw === null)
|
|
2242
|
+
return { stale: false, reason: "lock-unreadable" };
|
|
2243
|
+
sawLock = true;
|
|
2244
|
+
const lock = parseDaemonLock(raw);
|
|
2245
|
+
if (lock === null)
|
|
2246
|
+
return { stale: false, reason: "lock-unparseable" };
|
|
2247
|
+
if (lock.pid === pid)
|
|
2248
|
+
return { stale: false, reason: "lock-pid-match" };
|
|
2249
|
+
}
|
|
2250
|
+
return sawLock ? { stale: true, reason: "lock-pid-mismatch" } : { stale: true, reason: "lock-absent" };
|
|
2251
|
+
}
|
|
2252
|
+
function readLockIfPresent(lockPath) {
|
|
2253
|
+
try {
|
|
2254
|
+
return readFileSync5(lockPath, "utf8");
|
|
2255
|
+
} catch (error) {
|
|
2256
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
2257
|
+
return;
|
|
2258
|
+
if (error instanceof Error && "code" in error && error.code === "ENOTDIR")
|
|
2259
|
+
return;
|
|
2260
|
+
return null;
|
|
2050
2261
|
}
|
|
2051
|
-
return processes;
|
|
2052
2262
|
}
|
|
2053
|
-
function
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
continue;
|
|
2062
|
-
if (!isOrphaned(processInfo, livePids))
|
|
2063
|
-
continue;
|
|
2064
|
-
zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
|
|
2263
|
+
function collectAncestors(start, output) {
|
|
2264
|
+
let current = start;
|
|
2265
|
+
for (;; ) {
|
|
2266
|
+
output.add(current);
|
|
2267
|
+
const parent = dirname4(current);
|
|
2268
|
+
if (parent === current)
|
|
2269
|
+
return;
|
|
2270
|
+
current = parent;
|
|
2065
2271
|
}
|
|
2066
|
-
return zombies;
|
|
2067
2272
|
}
|
|
2068
|
-
function
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2273
|
+
function realpathIfPossible2(path) {
|
|
2274
|
+
try {
|
|
2275
|
+
return realpathSync4(path);
|
|
2276
|
+
} catch (error) {
|
|
2277
|
+
if (error instanceof Error)
|
|
2278
|
+
return path;
|
|
2279
|
+
throw error;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
// ../../utils/src/process-sweep/command-match.ts
|
|
2284
|
+
import { posix, win32 } from "node:path";
|
|
2285
|
+
function splitCommandTokens(command) {
|
|
2286
|
+
const tokens = [];
|
|
2287
|
+
let current = "";
|
|
2288
|
+
let quote = null;
|
|
2289
|
+
let tokenStarted = false;
|
|
2290
|
+
for (const char of command) {
|
|
2291
|
+
if (quote !== null) {
|
|
2292
|
+
if (char === quote) {
|
|
2293
|
+
quote = null;
|
|
2294
|
+
} else {
|
|
2295
|
+
current += char;
|
|
2296
|
+
}
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
if (char === '"' || char === "'") {
|
|
2300
|
+
quote = char;
|
|
2301
|
+
tokenStarted = true;
|
|
2302
|
+
continue;
|
|
2303
|
+
}
|
|
2304
|
+
if (/\s/.test(char)) {
|
|
2305
|
+
if (tokenStarted || current.length > 0) {
|
|
2306
|
+
tokens.push(current);
|
|
2307
|
+
current = "";
|
|
2308
|
+
tokenStarted = false;
|
|
2309
|
+
}
|
|
2072
2310
|
continue;
|
|
2073
|
-
const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
|
|
2074
|
-
if (hasExecutableToken(normalizedCommand, serveWrapper))
|
|
2075
|
-
return { kind: "serve-wrapper", root };
|
|
2076
|
-
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
|
|
2077
|
-
return { kind: "upstream-codegraph", root };
|
|
2078
2311
|
}
|
|
2312
|
+
current += char;
|
|
2079
2313
|
}
|
|
2080
|
-
|
|
2314
|
+
if (tokenStarted || current.length > 0)
|
|
2315
|
+
tokens.push(current);
|
|
2316
|
+
return tokens;
|
|
2081
2317
|
}
|
|
2082
2318
|
function hasExecutableToken(command, expectedPath) {
|
|
2083
2319
|
let searchFrom = 0;
|
|
@@ -2093,24 +2329,19 @@ function hasExecutableToken(command, expectedPath) {
|
|
|
2093
2329
|
}
|
|
2094
2330
|
}
|
|
2095
2331
|
function tokenLooksExecutable(command, tokenStart) {
|
|
2096
|
-
|
|
2332
|
+
let prefix = command.slice(0, tokenStart).trimEnd();
|
|
2097
2333
|
if (prefix.length === 0)
|
|
2098
2334
|
return true;
|
|
2099
|
-
const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
|
|
2100
|
-
const previousToken = prefix.slice(previousTokenStart);
|
|
2101
|
-
const executableName = previousToken.split("/").at(-1) ?? previousToken;
|
|
2102
|
-
return /^node\d*(\.exe)?$/.test(executableName) || /^bun(\.exe)?$/.test(executableName);
|
|
2103
|
-
}
|
|
2104
|
-
function upstreamPackagePathIsUnderRoot(command, root) {
|
|
2105
|
-
let searchFrom = 0;
|
|
2106
2335
|
for (;; ) {
|
|
2107
|
-
const
|
|
2108
|
-
|
|
2336
|
+
const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
|
|
2337
|
+
const previousToken = prefix.slice(previousTokenStart);
|
|
2338
|
+
if (!previousToken.startsWith("-")) {
|
|
2339
|
+
const executableName = previousToken.split("/").at(-1) ?? previousToken;
|
|
2340
|
+
return /^node\d*(\.exe)?$/i.test(executableName) || /^bun(\.exe)?$/i.test(executableName);
|
|
2341
|
+
}
|
|
2342
|
+
prefix = prefix.slice(0, previousTokenStart).trimEnd();
|
|
2343
|
+
if (prefix.length === 0)
|
|
2109
2344
|
return false;
|
|
2110
|
-
const tokenStart = findTokenStart(command, packageIndex);
|
|
2111
|
-
if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
|
|
2112
|
-
return true;
|
|
2113
|
-
searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
|
|
2114
2345
|
}
|
|
2115
2346
|
}
|
|
2116
2347
|
function findTokenStart(command, index) {
|
|
@@ -2144,6 +2375,39 @@ function normalizeForComparison2(value, platform) {
|
|
|
2144
2375
|
const normalized = value.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
2145
2376
|
return platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2146
2377
|
}
|
|
2378
|
+
|
|
2379
|
+
// ../../utils/src/process-sweep/process-table.ts
|
|
2380
|
+
function parsePosixProcessTable(output) {
|
|
2381
|
+
const processes = [];
|
|
2382
|
+
for (const line of output.split(/\r?\n/)) {
|
|
2383
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
|
|
2384
|
+
if (match === null)
|
|
2385
|
+
continue;
|
|
2386
|
+
const pid = Number(match[1]);
|
|
2387
|
+
const ppid = Number(match[2]);
|
|
2388
|
+
const command = match[3];
|
|
2389
|
+
if (!isValidProcessId(pid) || !Number.isInteger(ppid) || ppid < 0 || command === undefined)
|
|
2390
|
+
continue;
|
|
2391
|
+
processes.push({ command, pid, ppid });
|
|
2392
|
+
}
|
|
2393
|
+
return processes;
|
|
2394
|
+
}
|
|
2395
|
+
function parseWindowsProcessTable(output) {
|
|
2396
|
+
const parsed = parseJson(output);
|
|
2397
|
+
const entries = Array.isArray(parsed) ? parsed : parsed === undefined ? [] : [parsed];
|
|
2398
|
+
const processes = [];
|
|
2399
|
+
for (const entry of entries) {
|
|
2400
|
+
if (!isRecord3(entry))
|
|
2401
|
+
continue;
|
|
2402
|
+
const pid = numberField(entry, "ProcessId");
|
|
2403
|
+
const ppid = numberField(entry, "ParentProcessId");
|
|
2404
|
+
const command = stringField(entry, "CommandLine");
|
|
2405
|
+
if (pid === undefined || ppid === undefined || command === undefined || command.trim().length === 0)
|
|
2406
|
+
continue;
|
|
2407
|
+
processes.push({ command, pid, ppid });
|
|
2408
|
+
}
|
|
2409
|
+
return processes;
|
|
2410
|
+
}
|
|
2147
2411
|
function isOrphaned(processInfo, livePids) {
|
|
2148
2412
|
return processInfo.ppid === 1 || !livePids.has(processInfo.ppid);
|
|
2149
2413
|
}
|
|
@@ -2171,13 +2435,113 @@ function isRecord3(value) {
|
|
|
2171
2435
|
return typeof value === "object" && value !== null;
|
|
2172
2436
|
}
|
|
2173
2437
|
|
|
2174
|
-
// ../../utils/src/
|
|
2175
|
-
|
|
2438
|
+
// ../../utils/src/process-sweep/codegraph-family.ts
|
|
2439
|
+
var SERVE_WRAPPER_SUFFIX = "/components/codegraph/dist/serve.js";
|
|
2440
|
+
var UPSTREAM_PACKAGE_SEGMENT = "/@colbymchenry/codegraph/";
|
|
2441
|
+
function selectZombieCodegraphProcesses(processes, options) {
|
|
2442
|
+
const platform = options.platform ?? process.platform;
|
|
2443
|
+
const livePids = new Set(processes.map((processInfo) => processInfo.pid));
|
|
2444
|
+
const roots = normalizeRoots(options.ownedRoots, platform);
|
|
2445
|
+
const zombies = [];
|
|
2446
|
+
for (const processInfo of processes) {
|
|
2447
|
+
const daemon = matchDaemonCommand(processInfo.command, roots, platform);
|
|
2448
|
+
if (daemon !== null) {
|
|
2449
|
+
if (!isOrphaned(processInfo, livePids))
|
|
2450
|
+
continue;
|
|
2451
|
+
zombies.push({
|
|
2452
|
+
...processInfo,
|
|
2453
|
+
daemonProjectRoot: daemon.projectRoot,
|
|
2454
|
+
matchedRoot: daemon.root,
|
|
2455
|
+
matchKind: "upstream-daemon"
|
|
2456
|
+
});
|
|
2457
|
+
continue;
|
|
2458
|
+
}
|
|
2459
|
+
const match = matchOwnedCodegraphCommand(processInfo.command, roots, platform);
|
|
2460
|
+
if (match === null)
|
|
2461
|
+
continue;
|
|
2462
|
+
if (!isOrphaned(processInfo, livePids))
|
|
2463
|
+
continue;
|
|
2464
|
+
zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
|
|
2465
|
+
}
|
|
2466
|
+
return zombies;
|
|
2467
|
+
}
|
|
2468
|
+
var STANDALONE_LAUNCHER_SUFFIXES = ["/bin/codegraph", "/bin/codegraph.exe"];
|
|
2469
|
+
var BUNDLE_SCRIPT_SUFFIX = "/lib/dist/bin/codegraph.js";
|
|
2470
|
+
function matchDaemonCommand(command, roots, platform) {
|
|
2471
|
+
const projectRoot = extractDaemonProjectRoot(splitCommandTokens(command));
|
|
2472
|
+
if (projectRoot === null)
|
|
2473
|
+
return null;
|
|
2474
|
+
const normalizedCommand = normalizeForComparison2(command, platform);
|
|
2475
|
+
for (const root of roots) {
|
|
2476
|
+
if (root.length === 0)
|
|
2477
|
+
continue;
|
|
2478
|
+
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root))
|
|
2479
|
+
return { projectRoot, root };
|
|
2480
|
+
for (const suffix of STANDALONE_LAUNCHER_SUFFIXES) {
|
|
2481
|
+
if (hasExecutableToken(normalizedCommand, `${root}${suffix}`))
|
|
2482
|
+
return { projectRoot, root };
|
|
2483
|
+
}
|
|
2484
|
+
if (hasExecutableToken(normalizedCommand, `${root}${BUNDLE_SCRIPT_SUFFIX}`))
|
|
2485
|
+
return { projectRoot, root };
|
|
2486
|
+
}
|
|
2487
|
+
return null;
|
|
2488
|
+
}
|
|
2489
|
+
function extractDaemonProjectRoot(tokens) {
|
|
2490
|
+
if (!tokens.includes("serve") || !tokens.includes("--mcp"))
|
|
2491
|
+
return null;
|
|
2492
|
+
const pathIndex = tokens.indexOf("--path");
|
|
2493
|
+
if (pathIndex < 0)
|
|
2494
|
+
return null;
|
|
2495
|
+
const value = tokens[pathIndex + 1];
|
|
2496
|
+
if (value === undefined || value.length === 0 || value.startsWith("--"))
|
|
2497
|
+
return null;
|
|
2498
|
+
return value;
|
|
2499
|
+
}
|
|
2500
|
+
function matchOwnedCodegraphCommand(command, roots, platform) {
|
|
2501
|
+
const normalizedCommand = normalizeForComparison2(command, platform);
|
|
2502
|
+
for (const root of roots) {
|
|
2503
|
+
if (root.length === 0)
|
|
2504
|
+
continue;
|
|
2505
|
+
const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
|
|
2506
|
+
if (hasExecutableToken(normalizedCommand, serveWrapper))
|
|
2507
|
+
return { kind: "serve-wrapper", root };
|
|
2508
|
+
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
|
|
2509
|
+
return { kind: "upstream-codegraph", root };
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
return null;
|
|
2513
|
+
}
|
|
2514
|
+
function upstreamPackagePathIsUnderRoot(command, root) {
|
|
2515
|
+
let searchFrom = 0;
|
|
2516
|
+
for (;; ) {
|
|
2517
|
+
const packageIndex = command.indexOf(UPSTREAM_PACKAGE_SEGMENT, searchFrom);
|
|
2518
|
+
if (packageIndex < 0)
|
|
2519
|
+
return false;
|
|
2520
|
+
const tokenStart = findTokenStart(command, packageIndex);
|
|
2521
|
+
if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
|
|
2522
|
+
return true;
|
|
2523
|
+
searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
// ../../utils/src/process-sweep/exec.ts
|
|
2528
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
2529
|
+
function enumerateProcesses(platform = process.platform) {
|
|
2176
2530
|
return platform === "win32" ? enumerateWindowsProcesses() : enumeratePosixProcesses();
|
|
2177
2531
|
}
|
|
2178
|
-
function
|
|
2532
|
+
function createDefaultProcessKiller(platform = process.platform) {
|
|
2179
2533
|
return platform === "win32" ? createWindowsKiller() : createPosixKiller();
|
|
2180
2534
|
}
|
|
2535
|
+
function defaultIsProcessAlive(pid) {
|
|
2536
|
+
try {
|
|
2537
|
+
process.kill(pid, 0);
|
|
2538
|
+
return true;
|
|
2539
|
+
} catch (error) {
|
|
2540
|
+
if (!(error instanceof Error))
|
|
2541
|
+
throw error;
|
|
2542
|
+
return processKillErrorMeansAlive(error);
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2181
2545
|
function enumeratePosixProcesses() {
|
|
2182
2546
|
return execFileText("ps", ["-eo", "pid=,ppid=,command="]).then(parsePosixProcessTable);
|
|
2183
2547
|
}
|
|
@@ -2191,16 +2555,7 @@ function enumerateWindowsProcesses() {
|
|
|
2191
2555
|
}
|
|
2192
2556
|
function createPosixKiller() {
|
|
2193
2557
|
return {
|
|
2194
|
-
isAlive:
|
|
2195
|
-
try {
|
|
2196
|
-
process.kill(pid, 0);
|
|
2197
|
-
return true;
|
|
2198
|
-
} catch (error) {
|
|
2199
|
-
if (!(error instanceof Error))
|
|
2200
|
-
throw error;
|
|
2201
|
-
return processKillErrorMeansAlive(error);
|
|
2202
|
-
}
|
|
2203
|
-
},
|
|
2558
|
+
isAlive: defaultIsProcessAlive,
|
|
2204
2559
|
kill: (pid) => {
|
|
2205
2560
|
process.kill(pid, "SIGKILL");
|
|
2206
2561
|
return Promise.resolve();
|
|
@@ -2213,23 +2568,14 @@ function createPosixKiller() {
|
|
|
2213
2568
|
}
|
|
2214
2569
|
function createWindowsKiller() {
|
|
2215
2570
|
return {
|
|
2216
|
-
isAlive:
|
|
2217
|
-
try {
|
|
2218
|
-
process.kill(pid, 0);
|
|
2219
|
-
return true;
|
|
2220
|
-
} catch (error) {
|
|
2221
|
-
if (!(error instanceof Error))
|
|
2222
|
-
throw error;
|
|
2223
|
-
return processKillErrorMeansAlive(error);
|
|
2224
|
-
}
|
|
2225
|
-
},
|
|
2571
|
+
isAlive: defaultIsProcessAlive,
|
|
2226
2572
|
kill: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T", "/F"]),
|
|
2227
2573
|
terminate: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T"])
|
|
2228
2574
|
};
|
|
2229
2575
|
}
|
|
2230
2576
|
function execFileText(command, args) {
|
|
2231
2577
|
return new Promise((resolvePromise, reject) => {
|
|
2232
|
-
|
|
2578
|
+
execFile2(command, [...args], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, windowsHide: true }, (error, stdout) => {
|
|
2233
2579
|
if (error !== null) {
|
|
2234
2580
|
reject(error);
|
|
2235
2581
|
return;
|
|
@@ -2252,10 +2598,10 @@ function processKillErrorMeansAlive(error) {
|
|
|
2252
2598
|
return false;
|
|
2253
2599
|
}
|
|
2254
2600
|
|
|
2255
|
-
// ../../utils/src/
|
|
2256
|
-
import { existsSync as
|
|
2601
|
+
// ../../utils/src/process-sweep/roots.ts
|
|
2602
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, realpathSync as realpathSync5 } from "node:fs";
|
|
2257
2603
|
import { homedir as homedir9 } from "node:os";
|
|
2258
|
-
import { join as
|
|
2604
|
+
import { join as join11, resolve as resolve7 } from "node:path";
|
|
2259
2605
|
function discoverCodegraphOwnedRoots(options = {}) {
|
|
2260
2606
|
const env = options.env ?? process.env;
|
|
2261
2607
|
const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
|
|
@@ -2265,33 +2611,33 @@ function discoverCodegraphOwnedRoots(options = {}) {
|
|
|
2265
2611
|
addRoot(roots, options.pluginRoot);
|
|
2266
2612
|
for (const root of options.extraRoots ?? [])
|
|
2267
2613
|
addRoot(roots, root);
|
|
2268
|
-
for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ??
|
|
2614
|
+
for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join11(homeDir, ".codex"))) {
|
|
2269
2615
|
addRoot(roots, root);
|
|
2270
2616
|
}
|
|
2271
2617
|
return [...roots];
|
|
2272
2618
|
}
|
|
2273
2619
|
function readCodexPluginCacheRoots(codexHome) {
|
|
2274
|
-
const cacheRoot =
|
|
2275
|
-
if (!
|
|
2620
|
+
const cacheRoot = join11(codexHome, "plugins", "cache");
|
|
2621
|
+
if (!existsSync7(cacheRoot))
|
|
2276
2622
|
return [];
|
|
2277
2623
|
const roots = [];
|
|
2278
2624
|
for (const publisher of safeReadDir(cacheRoot)) {
|
|
2279
2625
|
if (!OMO_CODEX_PLUGIN_CACHE_PUBLISHERS.has(publisher))
|
|
2280
2626
|
continue;
|
|
2281
|
-
const omoRoot =
|
|
2282
|
-
if (!
|
|
2627
|
+
const omoRoot = join11(cacheRoot, publisher, "omo");
|
|
2628
|
+
if (!existsSync7(omoRoot))
|
|
2283
2629
|
continue;
|
|
2284
2630
|
for (const version of safeReadDir(omoRoot))
|
|
2285
|
-
roots.push(
|
|
2631
|
+
roots.push(join11(omoRoot, version));
|
|
2286
2632
|
}
|
|
2287
2633
|
return roots;
|
|
2288
2634
|
}
|
|
2289
2635
|
function addRoot(roots, root) {
|
|
2290
2636
|
if (root === undefined || root.trim().length === 0)
|
|
2291
2637
|
return;
|
|
2292
|
-
const resolved =
|
|
2638
|
+
const resolved = resolve7(root);
|
|
2293
2639
|
roots.add(resolved);
|
|
2294
|
-
roots.add(
|
|
2640
|
+
roots.add(realpathIfPossible3(resolved));
|
|
2295
2641
|
}
|
|
2296
2642
|
function safeReadDir(path) {
|
|
2297
2643
|
try {
|
|
@@ -2302,12 +2648,12 @@ function safeReadDir(path) {
|
|
|
2302
2648
|
throw error;
|
|
2303
2649
|
}
|
|
2304
2650
|
}
|
|
2305
|
-
function
|
|
2651
|
+
function realpathIfPossible3(path) {
|
|
2306
2652
|
try {
|
|
2307
|
-
return
|
|
2653
|
+
return realpathSync5(path);
|
|
2308
2654
|
} catch (error) {
|
|
2309
2655
|
if (error instanceof Error)
|
|
2310
|
-
return
|
|
2656
|
+
return resolve7(path);
|
|
2311
2657
|
throw error;
|
|
2312
2658
|
}
|
|
2313
2659
|
}
|
|
@@ -2319,88 +2665,124 @@ function isNonFatalFsError(error) {
|
|
|
2319
2665
|
}
|
|
2320
2666
|
var OMO_CODEX_PLUGIN_CACHE_PUBLISHERS = new Set(["sisyphuslabs"]);
|
|
2321
2667
|
|
|
2322
|
-
// ../../utils/src/
|
|
2668
|
+
// ../../utils/src/process-sweep/sweeper.ts
|
|
2323
2669
|
var DEFAULT_GRACE_MS = 2000;
|
|
2324
2670
|
var DEFAULT_THROTTLE_MS = 60 * 60 * 1000;
|
|
2325
|
-
|
|
2326
|
-
async function sweepCodegraphZombies(options = {}) {
|
|
2327
|
-
const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
|
|
2328
|
-
const stampFile = join10(codegraphDataRoot(homeDir), SWEEP_STAMP_FILE);
|
|
2671
|
+
async function runProcessFamilySweep(config, options) {
|
|
2329
2672
|
const nowMs = options.nowMs ?? Date.now();
|
|
2330
2673
|
const dryRun = options.dryRun === true;
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
return emptyResult("throttled", dryRun, ownedRoots, stampFile);
|
|
2674
|
+
if (options.force !== true && isSweepThrottled(config.stampFile, nowMs, options.throttleMs ?? DEFAULT_THROTTLE_MS)) {
|
|
2675
|
+
return { action: "throttled", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
|
|
2334
2676
|
}
|
|
2335
2677
|
try {
|
|
2336
|
-
const
|
|
2337
|
-
const
|
|
2338
|
-
ownedRoots,
|
|
2339
|
-
...options.platform === undefined ? {} : { platform: options.platform }
|
|
2340
|
-
});
|
|
2341
|
-
const result = dryRun ? { failed: [], killed: [] } : await killCandidates(candidates, options.killer ?? createDefaultCodegraphProcessKiller(options.platform), options);
|
|
2678
|
+
const plan = await config.collect();
|
|
2679
|
+
const { failed, killed } = dryRun ? { failed: [], killed: [] } : await killTargets(plan.killList, options.killer ?? createDefaultProcessKiller(options.platform), options, config.familyLabel);
|
|
2342
2680
|
if (!dryRun)
|
|
2343
|
-
writeSweepStamp(stampFile, nowMs);
|
|
2344
|
-
return {
|
|
2681
|
+
writeSweepStamp(config.stampFile, nowMs);
|
|
2682
|
+
return {
|
|
2683
|
+
action: "swept",
|
|
2684
|
+
candidates: plan.candidates,
|
|
2685
|
+
dryRun,
|
|
2686
|
+
failed,
|
|
2687
|
+
killed,
|
|
2688
|
+
spared: plan.spared,
|
|
2689
|
+
stampFile: config.stampFile
|
|
2690
|
+
};
|
|
2345
2691
|
} catch (error) {
|
|
2346
|
-
options.log?.(
|
|
2347
|
-
return
|
|
2692
|
+
options.log?.(`${config.familyLabel} skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
2693
|
+
return { action: "failed", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
var CODEGRAPH_SWEEP_STAMP_FILE = "zombie-sweep.stamp";
|
|
2697
|
+
async function sweepCodegraphZombies(options = {}) {
|
|
2698
|
+
const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
|
|
2699
|
+
const stampFile = join12(codegraphDataRoot(homeDir), CODEGRAPH_SWEEP_STAMP_FILE);
|
|
2700
|
+
const ownedRoots = options.ownedRoots ?? discoverCodegraphOwnedRoots(options);
|
|
2701
|
+
const result = await runProcessFamilySweep({
|
|
2702
|
+
familyLabel: "CodeGraph zombie sweep",
|
|
2703
|
+
stampFile,
|
|
2704
|
+
collect: async () => {
|
|
2705
|
+
const provider = options.processProvider ?? (() => enumerateProcesses(options.platform));
|
|
2706
|
+
const candidates = selectZombieCodegraphProcesses(await provider(), {
|
|
2707
|
+
ownedRoots,
|
|
2708
|
+
...options.platform === undefined ? {} : { platform: options.platform }
|
|
2709
|
+
});
|
|
2710
|
+
const { killList, spared } = partitionByDaemonStaleness(candidates, options.log);
|
|
2711
|
+
return { candidates, killList, spared };
|
|
2712
|
+
}
|
|
2713
|
+
}, options);
|
|
2714
|
+
return { ...result, ownedRoots };
|
|
2715
|
+
}
|
|
2716
|
+
function partitionByDaemonStaleness(candidates, log) {
|
|
2717
|
+
const killList = [];
|
|
2718
|
+
const spared = [];
|
|
2719
|
+
for (const candidate of candidates) {
|
|
2720
|
+
if (candidate.matchKind !== "upstream-daemon") {
|
|
2721
|
+
killList.push(candidate);
|
|
2722
|
+
continue;
|
|
2723
|
+
}
|
|
2724
|
+
const staleness = evaluateDaemonStaleness(candidate.pid, candidate.daemonProjectRoot ?? candidate.matchedRoot);
|
|
2725
|
+
if (staleness.stale) {
|
|
2726
|
+
log?.(`CodeGraph zombie sweep sweeping stale daemon pid ${candidate.pid} (${staleness.reason})`);
|
|
2727
|
+
killList.push(candidate);
|
|
2728
|
+
continue;
|
|
2729
|
+
}
|
|
2730
|
+
log?.(`CodeGraph zombie sweep spared live daemon pid ${candidate.pid} (${staleness.reason})`);
|
|
2731
|
+
spared.push(candidate);
|
|
2348
2732
|
}
|
|
2733
|
+
return { killList, spared };
|
|
2349
2734
|
}
|
|
2350
|
-
async function
|
|
2735
|
+
async function killTargets(targets, killer, options, familyLabel) {
|
|
2351
2736
|
const failed = [];
|
|
2352
2737
|
const killed = [];
|
|
2353
|
-
for (const
|
|
2354
|
-
const terminated = await safelyTerminate(
|
|
2738
|
+
for (const target of targets) {
|
|
2739
|
+
const terminated = await safelyTerminate(target.pid, killer, failed, options.log, familyLabel);
|
|
2355
2740
|
if (!terminated)
|
|
2356
2741
|
continue;
|
|
2357
2742
|
await delay(options.graceMs ?? DEFAULT_GRACE_MS);
|
|
2358
|
-
if (!await killer.isAlive(
|
|
2359
|
-
killed.push(
|
|
2743
|
+
if (!await killer.isAlive(target.pid)) {
|
|
2744
|
+
killed.push(target);
|
|
2360
2745
|
continue;
|
|
2361
2746
|
}
|
|
2362
|
-
if (await safelyKill(
|
|
2363
|
-
killed.push(
|
|
2747
|
+
if (await safelyKill(target.pid, killer, failed, options.log, familyLabel))
|
|
2748
|
+
killed.push(target);
|
|
2364
2749
|
}
|
|
2365
2750
|
return { failed, killed };
|
|
2366
2751
|
}
|
|
2367
|
-
async function safelyTerminate(pid, killer, failed, log) {
|
|
2752
|
+
async function safelyTerminate(pid, killer, failed, log, familyLabel) {
|
|
2368
2753
|
try {
|
|
2369
2754
|
await killer.terminate(pid);
|
|
2370
2755
|
return true;
|
|
2371
2756
|
} catch (error) {
|
|
2372
2757
|
const message = error instanceof Error ? error.message : String(error);
|
|
2373
2758
|
failed.push({ error: message, pid, stage: "terminate" });
|
|
2374
|
-
log?.(
|
|
2759
|
+
log?.(`${familyLabel} failed to terminate pid ${pid}: ${message}`);
|
|
2375
2760
|
return false;
|
|
2376
2761
|
}
|
|
2377
2762
|
}
|
|
2378
|
-
async function safelyKill(pid, killer, failed, log) {
|
|
2763
|
+
async function safelyKill(pid, killer, failed, log, familyLabel) {
|
|
2379
2764
|
try {
|
|
2380
2765
|
await killer.kill(pid);
|
|
2381
2766
|
return true;
|
|
2382
2767
|
} catch (error) {
|
|
2383
2768
|
const message = error instanceof Error ? error.message : String(error);
|
|
2384
2769
|
failed.push({ error: message, pid, stage: "kill" });
|
|
2385
|
-
log?.(
|
|
2770
|
+
log?.(`${familyLabel} failed to kill pid ${pid}: ${message}`);
|
|
2386
2771
|
return false;
|
|
2387
2772
|
}
|
|
2388
2773
|
}
|
|
2389
2774
|
function isSweepThrottled(stampFile, nowMs, throttleMs) {
|
|
2390
|
-
if (!
|
|
2775
|
+
if (!existsSync8(stampFile))
|
|
2391
2776
|
return false;
|
|
2392
2777
|
return nowMs - statSync2(stampFile).mtimeMs < throttleMs;
|
|
2393
2778
|
}
|
|
2394
2779
|
function writeSweepStamp(stampFile, nowMs) {
|
|
2395
|
-
mkdirSync2(
|
|
2780
|
+
mkdirSync2(dirname5(stampFile), { recursive: true });
|
|
2396
2781
|
writeFileSync2(stampFile, `${new Date(nowMs).toISOString()}
|
|
2397
2782
|
`);
|
|
2398
2783
|
const stampDate = new Date(nowMs);
|
|
2399
2784
|
utimesSync(stampFile, stampDate, stampDate);
|
|
2400
2785
|
}
|
|
2401
|
-
function emptyResult(action, dryRun, ownedRoots, stampFile) {
|
|
2402
|
-
return { action, candidates: [], dryRun, failed: [], killed: [], ownedRoots, stampFile };
|
|
2403
|
-
}
|
|
2404
2786
|
function delay(ms) {
|
|
2405
2787
|
if (ms <= 0)
|
|
2406
2788
|
return Promise.resolve();
|
|
@@ -2425,71 +2807,31 @@ function defaultPluginRoot() {
|
|
|
2425
2807
|
}
|
|
2426
2808
|
|
|
2427
2809
|
// components/codegraph/src/session-start-worker.ts
|
|
2428
|
-
import {
|
|
2429
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "node:fs";
|
|
2810
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
|
|
2430
2811
|
import { homedir as homedir12 } from "node:os";
|
|
2431
|
-
import { extname, join as
|
|
2812
|
+
import { extname, join as join14 } from "node:path";
|
|
2432
2813
|
import { cwd as processCwd, env as processEnv, execPath as processExecPath, stderr as processStderr } from "node:process";
|
|
2433
2814
|
|
|
2434
2815
|
// ../../utils/src/codegraph/provision.ts
|
|
2435
2816
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
2436
|
-
import { execFile as
|
|
2817
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
2437
2818
|
import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
2438
|
-
import { existsSync as
|
|
2819
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
2439
2820
|
import { homedir as homedir11, hostname } from "node:os";
|
|
2440
|
-
import { basename as basename3, join as
|
|
2821
|
+
import { basename as basename3, join as join13 } from "node:path";
|
|
2441
2822
|
import { promisify } from "node:util";
|
|
2442
|
-
|
|
2443
|
-
// ../../utils/src/codegraph/manifest.ts
|
|
2444
|
-
var CODEGRAPH_PROVISION_MANIFEST = {
|
|
2445
|
-
assets: {
|
|
2446
|
-
"darwin-arm64": {
|
|
2447
|
-
executableName: "codegraph",
|
|
2448
|
-
sha256: "95bb27bf6382b69659e158e0c04d71cc394778951e1317d582be7807e7866908",
|
|
2449
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-arm64.tar.gz"
|
|
2450
|
-
},
|
|
2451
|
-
"darwin-x64": {
|
|
2452
|
-
executableName: "codegraph",
|
|
2453
|
-
sha256: "3311cc1d1f0f0ad742709b6a43d8a9187b1ef0af0dd30e0b58008dc673e29478",
|
|
2454
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-x64.tar.gz"
|
|
2455
|
-
},
|
|
2456
|
-
"linux-arm64": {
|
|
2457
|
-
executableName: "codegraph",
|
|
2458
|
-
sha256: "e16f612bc96c2ebccd04574cbed500c9939147c80666ad6bb024398dff7992ae",
|
|
2459
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-arm64.tar.gz"
|
|
2460
|
-
},
|
|
2461
|
-
"linux-x64": {
|
|
2462
|
-
executableName: "codegraph",
|
|
2463
|
-
sha256: "d45a068f44596a85c7ba7d0ef924eaf7103fbbf3cafbeb668127daff60a52228",
|
|
2464
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-x64.tar.gz"
|
|
2465
|
-
},
|
|
2466
|
-
"win32-arm64": {
|
|
2467
|
-
executableName: "codegraph.cmd",
|
|
2468
|
-
sha256: "8d57ced73b24d35f758f2ede2318e80e1d7241987f37a999e3d80edb6fddf961",
|
|
2469
|
-
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.0.1.tgz"
|
|
2470
|
-
},
|
|
2471
|
-
"win32-x64": {
|
|
2472
|
-
executableName: "codegraph.cmd",
|
|
2473
|
-
sha256: "52607fe73b05e741fd1087da2ceca9d3c8f565e36bf1a7070600bdbdf3931e32",
|
|
2474
|
-
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.0.1.tgz"
|
|
2475
|
-
}
|
|
2476
|
-
},
|
|
2477
|
-
version: "1.0.1"
|
|
2478
|
-
};
|
|
2479
|
-
|
|
2480
|
-
// ../../utils/src/codegraph/provision.ts
|
|
2481
2823
|
var DEFAULT_LOCK_WAIT_MS = 5000;
|
|
2482
2824
|
var DEFAULT_LOCK_STALE_MS = 120000;
|
|
2483
2825
|
var DEFAULT_DOWNLOAD_TIMEOUT_MS = 60000;
|
|
2484
|
-
var execFileAsync = promisify(
|
|
2826
|
+
var execFileAsync = promisify(execFile3);
|
|
2485
2827
|
function platformKey() {
|
|
2486
2828
|
return `${process.platform}-${process.arch}`;
|
|
2487
2829
|
}
|
|
2488
2830
|
function markerPath(installDir, version) {
|
|
2489
|
-
return
|
|
2831
|
+
return join13(installDir, ".provisioned", `codegraph-${version}.json`);
|
|
2490
2832
|
}
|
|
2491
2833
|
function defaultInstallDir() {
|
|
2492
|
-
return
|
|
2834
|
+
return join13(homedir11(), ".omo", "codegraph");
|
|
2493
2835
|
}
|
|
2494
2836
|
function sha256(bytes) {
|
|
2495
2837
|
return createHash2("sha256").update(bytes).digest("hex");
|
|
@@ -2509,7 +2851,7 @@ async function removeEmptyDirectory(path) {
|
|
|
2509
2851
|
}
|
|
2510
2852
|
}
|
|
2511
2853
|
function sleep(ms) {
|
|
2512
|
-
return new Promise((
|
|
2854
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
2513
2855
|
}
|
|
2514
2856
|
async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
|
|
2515
2857
|
const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -2523,7 +2865,7 @@ function forcedBadChecksumOptions(options) {
|
|
|
2523
2865
|
const key = options.platformKey ?? platformKey();
|
|
2524
2866
|
return {
|
|
2525
2867
|
downloader: async () => new TextEncoder().encode("checksum mismatch"),
|
|
2526
|
-
installDir: options.installDir ??
|
|
2868
|
+
installDir: options.installDir ?? join13(options.lockDir, "codegraph-force-bad-checksum"),
|
|
2527
2869
|
manifest: {
|
|
2528
2870
|
assets: {
|
|
2529
2871
|
[key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
|
|
@@ -2534,13 +2876,13 @@ function forcedBadChecksumOptions(options) {
|
|
|
2534
2876
|
};
|
|
2535
2877
|
}
|
|
2536
2878
|
async function readMarker(path) {
|
|
2537
|
-
if (!
|
|
2879
|
+
if (!existsSync9(path))
|
|
2538
2880
|
return null;
|
|
2539
2881
|
try {
|
|
2540
2882
|
const raw = JSON.parse(await readFile(path, "utf8"));
|
|
2541
2883
|
if (typeof raw === "object" && raw !== null && "binPath" in raw) {
|
|
2542
2884
|
const value = raw.binPath;
|
|
2543
|
-
return typeof value === "string" &&
|
|
2885
|
+
return typeof value === "string" && existsSync9(value) ? value : null;
|
|
2544
2886
|
}
|
|
2545
2887
|
return null;
|
|
2546
2888
|
} catch (error) {
|
|
@@ -2551,7 +2893,7 @@ async function readMarker(path) {
|
|
|
2551
2893
|
}
|
|
2552
2894
|
async function acquireLock(lockPath, waitMs, staleMs) {
|
|
2553
2895
|
const startedAt = Date.now();
|
|
2554
|
-
await mkdir(
|
|
2896
|
+
await mkdir(join13(lockPath, ".."), { recursive: true });
|
|
2555
2897
|
while (Date.now() - startedAt <= waitMs) {
|
|
2556
2898
|
try {
|
|
2557
2899
|
await mkdir(lockPath);
|
|
@@ -2576,24 +2918,24 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
|
|
|
2576
2918
|
const roots = await readdir(extractDir);
|
|
2577
2919
|
if (roots.length !== 1)
|
|
2578
2920
|
throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
|
|
2579
|
-
const bundleDir =
|
|
2921
|
+
const bundleDir = join13(extractDir, roots[0] ?? "");
|
|
2580
2922
|
const bundleEntries = await readdir(bundleDir);
|
|
2581
2923
|
await mkdir(installDir, { recursive: true });
|
|
2582
2924
|
for (const entry of bundleEntries) {
|
|
2583
|
-
await rm(
|
|
2584
|
-
await rename(
|
|
2925
|
+
await rm(join13(installDir, entry), { force: true, recursive: true });
|
|
2926
|
+
await rename(join13(bundleDir, entry), join13(installDir, entry));
|
|
2585
2927
|
}
|
|
2586
|
-
const destination =
|
|
2587
|
-
if (!
|
|
2928
|
+
const destination = join13(installDir, "bin", executableName);
|
|
2929
|
+
if (!existsSync9(destination))
|
|
2588
2930
|
throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
|
|
2589
2931
|
await chmod(destination, 493);
|
|
2590
2932
|
return destination;
|
|
2591
2933
|
}
|
|
2592
2934
|
async function installAsset(layout) {
|
|
2593
2935
|
const { asset, downloader, installDir, version } = layout;
|
|
2594
|
-
const stagingDir =
|
|
2595
|
-
const archivePath =
|
|
2596
|
-
const extractDir =
|
|
2936
|
+
const stagingDir = join13(installDir, ".staging", randomUUID());
|
|
2937
|
+
const archivePath = join13(stagingDir, basename3(asset.url));
|
|
2938
|
+
const extractDir = join13(stagingDir, "extract");
|
|
2597
2939
|
try {
|
|
2598
2940
|
await mkdir(extractDir, { recursive: true });
|
|
2599
2941
|
const bytes = await downloader(asset);
|
|
@@ -2607,13 +2949,13 @@ async function installAsset(layout) {
|
|
|
2607
2949
|
await writeFile(archivePath, bytes);
|
|
2608
2950
|
await extractTarGz(archivePath, extractDir);
|
|
2609
2951
|
const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
|
|
2610
|
-
await mkdir(
|
|
2952
|
+
await mkdir(join13(installDir, ".provisioned"), { recursive: true });
|
|
2611
2953
|
await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
|
|
2612
2954
|
`);
|
|
2613
2955
|
return destination;
|
|
2614
2956
|
} finally {
|
|
2615
2957
|
await rm(stagingDir, { force: true, recursive: true });
|
|
2616
|
-
await removeEmptyDirectory(
|
|
2958
|
+
await removeEmptyDirectory(join13(installDir, ".staging"));
|
|
2617
2959
|
}
|
|
2618
2960
|
}
|
|
2619
2961
|
async function ensureCodegraphProvisioned(options) {
|
|
@@ -2626,7 +2968,7 @@ async function ensureCodegraphProvisioned(options) {
|
|
|
2626
2968
|
const existing = await readMarker(marker);
|
|
2627
2969
|
if (existing !== null)
|
|
2628
2970
|
return { binPath: existing, provisioned: true };
|
|
2629
|
-
const lockPath =
|
|
2971
|
+
const lockPath = join13(options.lockDir, `codegraph-${hostname()}.lock`);
|
|
2630
2972
|
const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
|
|
2631
2973
|
if (release === null)
|
|
2632
2974
|
return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
|
|
@@ -2652,7 +2994,7 @@ async function ensureCodegraphProvisioned(options) {
|
|
|
2652
2994
|
|
|
2653
2995
|
// components/codegraph/src/session-start-worker.ts
|
|
2654
2996
|
var SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
|
|
2655
|
-
var CODEGRAPH_VERSION =
|
|
2997
|
+
var CODEGRAPH_VERSION = CODEGRAPH_PINNED_VERSION;
|
|
2656
2998
|
var COMMAND_TIMEOUT_MS = 60000;
|
|
2657
2999
|
var WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
|
|
2658
3000
|
var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
|
|
@@ -2716,15 +3058,15 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
|
|
|
2716
3058
|
return { kind: "unsupported-node" };
|
|
2717
3059
|
if (config.auto_provision === false)
|
|
2718
3060
|
return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
|
|
2719
|
-
const installDir = trustedInstallDir ??
|
|
2720
|
-
const provisioned = await deps.ensureProvisioned({ installDir, lockDir:
|
|
3061
|
+
const installDir = trustedInstallDir ?? join14(homeDir, ".omo", "codegraph");
|
|
3062
|
+
const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join14(installDir, ".locks"), version: CODEGRAPH_VERSION });
|
|
2721
3063
|
if (!provisioned.provisioned || provisioned.binPath === undefined) {
|
|
2722
3064
|
return { error: provisioned.error ?? "provisioning did not produce a binary", kind: "unavailable", source: resolved.source };
|
|
2723
3065
|
}
|
|
2724
3066
|
return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
|
|
2725
3067
|
}
|
|
2726
3068
|
function codegraphEnvForConfig(config, homeDir) {
|
|
2727
|
-
const env = buildCodegraphEnv({ homeDir });
|
|
3069
|
+
const env = buildCodegraphEnv({ daemon: false, homeDir });
|
|
2728
3070
|
return config.trustedCodegraphInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: config.trustedCodegraphInstallDir };
|
|
2729
3071
|
}
|
|
2730
3072
|
function canUseResolvedCommand(resolved, nodeSupport) {
|
|
@@ -2764,15 +3106,14 @@ function jsonSaysInitialized(value) {
|
|
|
2764
3106
|
}
|
|
2765
3107
|
async function runCodegraphCommand(projectRoot, command, args, options) {
|
|
2766
3108
|
const invocation = resolveCodegraphCommandInvocation(command, args);
|
|
2767
|
-
return
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
});
|
|
3109
|
+
return runProcessWithTreeTimeout({
|
|
3110
|
+
args: invocation.args,
|
|
3111
|
+
command: invocation.command,
|
|
3112
|
+
cwd: projectRoot,
|
|
3113
|
+
env: buildCodegraphChildEnv({ ambientEnv: processEnv, codegraphEnv: options.env }),
|
|
3114
|
+
maxBuffer: 1024 * 1024,
|
|
3115
|
+
timeoutMs: options.timeoutMs
|
|
3116
|
+
}).then(({ exitCode, stderr, stdout, timedOut }) => ({ exitCode, stderr, stdout, timedOut }));
|
|
2776
3117
|
}
|
|
2777
3118
|
function resolveCodegraphCommandInvocation(command, args, platform = process.platform) {
|
|
2778
3119
|
if (platform !== "win32")
|
|
@@ -2785,9 +3126,9 @@ function resolveCodegraphCommandInvocation(command, args, platform = process.pla
|
|
|
2785
3126
|
return { args: ["/d", "/s", "/c", command, ...args], command: "cmd.exe" };
|
|
2786
3127
|
}
|
|
2787
3128
|
function appendOutcome(homeDir, outcome) {
|
|
2788
|
-
const logDir =
|
|
3129
|
+
const logDir = join14(homeDir, ".omo", "codegraph");
|
|
2789
3130
|
mkdirSync3(logDir, { recursive: true });
|
|
2790
|
-
appendFileSync2(
|
|
3131
|
+
appendFileSync2(join14(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
|
|
2791
3132
|
`);
|
|
2792
3133
|
}
|
|
2793
3134
|
function safeLogOutcome(logOutcome, outcome) {
|
|
@@ -2802,18 +3143,7 @@ function safeLogOutcome(logOutcome, outcome) {
|
|
|
2802
3143
|
}
|
|
2803
3144
|
}
|
|
2804
3145
|
function provisionedBinFromInstallDir(installDir) {
|
|
2805
|
-
|
|
2806
|
-
return null;
|
|
2807
|
-
const candidate = join12(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
2808
|
-
return existsSync9(candidate) ? candidate : null;
|
|
2809
|
-
}
|
|
2810
|
-
function resolveExitCode(error) {
|
|
2811
|
-
if ("code" in error && typeof error.code === "number")
|
|
2812
|
-
return error.code;
|
|
2813
|
-
return 1;
|
|
2814
|
-
}
|
|
2815
|
-
function toOutputText(value) {
|
|
2816
|
-
return Buffer.isBuffer(value) ? value.toString("utf8") : value;
|
|
3146
|
+
return resolvePinnedCodegraphBin(installDir);
|
|
2817
3147
|
}
|
|
2818
3148
|
function resolveHomeDir2(env) {
|
|
2819
3149
|
return env["HOME"] ?? env["USERPROFILE"] ?? homedir12();
|
|
@@ -2846,13 +3176,6 @@ async function executeCodegraphSessionStartHook(options = {}) {
|
|
|
2846
3176
|
const projectRoot = resolveProjectRoot(input, options.cwd ?? processCwd2());
|
|
2847
3177
|
const homeDir = resolveHomeDir3(env);
|
|
2848
3178
|
const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
|
|
2849
|
-
pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
|
|
2850
|
-
await sweepCodegraphZombiesBestEffort({
|
|
2851
|
-
env,
|
|
2852
|
-
homeDir,
|
|
2853
|
-
...config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir },
|
|
2854
|
-
log: writeDebugLog
|
|
2855
|
-
}, options.sweepZombies);
|
|
2856
3179
|
if (config.codegraph?.enabled === false) {
|
|
2857
3180
|
return { action: "skipped-disabled", exitCode: 0 };
|
|
2858
3181
|
}
|
|
@@ -2864,7 +3187,15 @@ async function executeCodegraphSessionStartHook(options = {}) {
|
|
|
2864
3187
|
if (exclusion.excluded) {
|
|
2865
3188
|
return { action: "skipped-excluded", exitCode: 0 };
|
|
2866
3189
|
}
|
|
3190
|
+
pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
|
|
3191
|
+
await sweepCodegraphZombiesBestEffort({
|
|
3192
|
+
env,
|
|
3193
|
+
homeDir,
|
|
3194
|
+
...config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir },
|
|
3195
|
+
log: writeDebugLog
|
|
3196
|
+
}, options.sweepZombies);
|
|
2867
3197
|
const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
|
|
3198
|
+
daemon: config.codegraph?.daemon !== false,
|
|
2868
3199
|
env,
|
|
2869
3200
|
homeDir,
|
|
2870
3201
|
projectRoot,
|
|
@@ -2895,7 +3226,7 @@ async function isCodegraphProjectInitialized(options) {
|
|
|
2895
3226
|
return false;
|
|
2896
3227
|
const invocation = resolveCodegraphCommandInvocation(resolved.command, [...resolved.argsPrefix, "status", "--json"]);
|
|
2897
3228
|
const codegraphEnv = {
|
|
2898
|
-
...buildCodegraphEnv({ homeDir: options.homeDir }),
|
|
3229
|
+
...buildCodegraphEnv({ daemon: options.daemon, homeDir: options.homeDir }),
|
|
2899
3230
|
...options.trustedCodegraphInstallDir === undefined ? {} : { CODEGRAPH_INSTALL_DIR: options.trustedCodegraphInstallDir }
|
|
2900
3231
|
};
|
|
2901
3232
|
const status = await runStatusProbe(options.projectRoot, invocation.command, invocation.args, buildCodegraphChildEnv({ ambientEnv: options.env, codegraphEnv, runtimeEnv: options.env }));
|
|
@@ -2904,22 +3235,14 @@ async function isCodegraphProjectInitialized(options) {
|
|
|
2904
3235
|
return codegraphStatusSaysInitialized(status.stdout);
|
|
2905
3236
|
}
|
|
2906
3237
|
function runStatusProbe(projectRoot, command, args, env) {
|
|
2907
|
-
return
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
}, (error, stdout) => {
|
|
2916
|
-
if (error === null) {
|
|
2917
|
-
resolveProbe({ exitCode: 0, stdout: toOutputText2(stdout), timedOut: false });
|
|
2918
|
-
return;
|
|
2919
|
-
}
|
|
2920
|
-
resolveProbe({ exitCode: resolveExitCode2(error), stdout: toOutputText2(stdout), timedOut: error.killed === true });
|
|
2921
|
-
});
|
|
2922
|
-
});
|
|
3238
|
+
return runProcessWithTreeTimeout({
|
|
3239
|
+
args,
|
|
3240
|
+
command,
|
|
3241
|
+
cwd: projectRoot,
|
|
3242
|
+
env,
|
|
3243
|
+
maxBuffer: 1024 * 1024,
|
|
3244
|
+
timeoutMs: STATUS_PROBE_TIMEOUT_MS
|
|
3245
|
+
}).then(({ exitCode, stdout, timedOut }) => ({ exitCode, stdout, timedOut }));
|
|
2923
3246
|
}
|
|
2924
3247
|
function codegraphStatusSaysInitialized(stdout) {
|
|
2925
3248
|
const parsed = parseJson3(stdout);
|
|
@@ -2935,9 +3258,7 @@ function codegraphStatusSaysInitialized(stdout) {
|
|
|
2935
3258
|
return (normalized.includes("initialized") || normalized.includes("ready")) && !normalized.includes("not initialized") && !normalized.includes("uninitialized");
|
|
2936
3259
|
}
|
|
2937
3260
|
function provisionedBinFromInstallDir2(installDir) {
|
|
2938
|
-
|
|
2939
|
-
return null;
|
|
2940
|
-
return join13(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
3261
|
+
return resolvePinnedCodegraphBin(installDir);
|
|
2941
3262
|
}
|
|
2942
3263
|
async function executeCodegraphPostToolUseHook(options = {}) {
|
|
2943
3264
|
const env = options.env ?? processEnv2;
|
|
@@ -2980,20 +3301,12 @@ function writeDebugLog(message) {
|
|
|
2980
3301
|
`);
|
|
2981
3302
|
}
|
|
2982
3303
|
function spawnDetachedWorker(invocation) {
|
|
2983
|
-
const child =
|
|
3304
|
+
const child = spawn2(invocation.command, [...invocation.args], { detached: true, env: invocation.env, stdio: "ignore" });
|
|
2984
3305
|
child.unref();
|
|
2985
3306
|
}
|
|
2986
3307
|
function resolveHomeDir3(env) {
|
|
2987
3308
|
return env["HOME"] ?? env["USERPROFILE"] ?? homedir13();
|
|
2988
3309
|
}
|
|
2989
|
-
function resolveExitCode2(error) {
|
|
2990
|
-
if ("code" in error && typeof error.code === "number")
|
|
2991
|
-
return error.code;
|
|
2992
|
-
return 1;
|
|
2993
|
-
}
|
|
2994
|
-
function toOutputText2(value) {
|
|
2995
|
-
return Buffer.isBuffer(value) ? value.toString("utf8") : value;
|
|
2996
|
-
}
|
|
2997
3310
|
function resolveProjectRoot(input, fallback) {
|
|
2998
3311
|
if (!isRecord5(input))
|
|
2999
3312
|
return fallback;
|
|
@@ -3027,9 +3340,9 @@ function defaultWorkerCliPath() {
|
|
|
3027
3340
|
}
|
|
3028
3341
|
|
|
3029
3342
|
// components/codegraph/src/serve.ts
|
|
3030
|
-
import { existsSync as existsSync10, realpathSync as
|
|
3343
|
+
import { existsSync as existsSync10, realpathSync as realpathSync6 } from "node:fs";
|
|
3031
3344
|
import { homedir as homedir14 } from "node:os";
|
|
3032
|
-
import { basename as basename4, join as
|
|
3345
|
+
import { basename as basename4, join as join15, resolve as resolve8 } from "node:path";
|
|
3033
3346
|
import {
|
|
3034
3347
|
cwd as processCwd3,
|
|
3035
3348
|
env as processEnv3,
|
|
@@ -3040,10 +3353,10 @@ import {
|
|
|
3040
3353
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
3041
3354
|
|
|
3042
3355
|
// components/codegraph/src/mcp-bridge.ts
|
|
3043
|
-
import { spawn as
|
|
3356
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
3044
3357
|
|
|
3045
3358
|
// ../../mcp-stdio-core/src/record.ts
|
|
3046
|
-
function
|
|
3359
|
+
function isPlainRecord2(value) {
|
|
3047
3360
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3048
3361
|
}
|
|
3049
3362
|
// ../../mcp-stdio-core/src/responses.ts
|
|
@@ -3090,7 +3403,7 @@ ${body}` : `${body}
|
|
|
3090
3403
|
await writeChunk(output, payload);
|
|
3091
3404
|
}
|
|
3092
3405
|
function writeChunk(output, chunk) {
|
|
3093
|
-
return new Promise((
|
|
3406
|
+
return new Promise((resolve8, reject) => {
|
|
3094
3407
|
let settled = false;
|
|
3095
3408
|
const onError = (error) => {
|
|
3096
3409
|
if (settled)
|
|
@@ -3110,7 +3423,7 @@ function writeChunk(output, chunk) {
|
|
|
3110
3423
|
return;
|
|
3111
3424
|
}
|
|
3112
3425
|
output.removeListener("error", onError);
|
|
3113
|
-
|
|
3426
|
+
resolve8();
|
|
3114
3427
|
});
|
|
3115
3428
|
} catch (error) {
|
|
3116
3429
|
output.removeListener("error", onError);
|
|
@@ -3202,16 +3515,35 @@ function bufferFromChunk(chunk) {
|
|
|
3202
3515
|
|
|
3203
3516
|
// ../../mcp-stdio-core/src/server.ts
|
|
3204
3517
|
var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
|
|
3518
|
+
var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
|
|
3205
3519
|
var noopLog = () => {};
|
|
3520
|
+
function isProcessAlive(pid) {
|
|
3521
|
+
try {
|
|
3522
|
+
process.kill(pid, 0);
|
|
3523
|
+
return true;
|
|
3524
|
+
} catch (error) {
|
|
3525
|
+
return !hasErrorCode(error, "ESRCH");
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3206
3528
|
async function runJsonRpcStdioServer(config) {
|
|
3207
3529
|
const log = config.log ?? noopLog;
|
|
3208
3530
|
const idleTimeoutMs = config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
3209
|
-
|
|
3531
|
+
let isClosed = false;
|
|
3532
|
+
const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
|
|
3533
|
+
isClosed = true;
|
|
3534
|
+
config.onIdleTimeout?.();
|
|
3535
|
+
});
|
|
3536
|
+
const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
|
|
3537
|
+
isClosed = true;
|
|
3538
|
+
log("parent_exit", { parent_pid: parentPid, poll_interval_ms: pollIntervalMs });
|
|
3539
|
+
config.onParentExit?.();
|
|
3540
|
+
config.input.destroy();
|
|
3541
|
+
});
|
|
3210
3542
|
log("stdio_started", { cwd: process.cwd(), idle_timeout_ms: idleTimeoutMs });
|
|
3211
3543
|
idleTimer.arm();
|
|
3212
3544
|
try {
|
|
3213
3545
|
for await (const message of readStdioJsonRpcMessages(config.input)) {
|
|
3214
|
-
if (
|
|
3546
|
+
if (isClosed)
|
|
3215
3547
|
break;
|
|
3216
3548
|
idleTimer.arm();
|
|
3217
3549
|
if (message.kind === "parse_error") {
|
|
@@ -3222,8 +3554,12 @@ async function runJsonRpcStdioServer(config) {
|
|
|
3222
3554
|
if (!await handleRequest(message, config, log))
|
|
3223
3555
|
break;
|
|
3224
3556
|
}
|
|
3557
|
+
} catch (error) {
|
|
3558
|
+
if (!(isClosed && hasErrorCode(error, "ERR_STREAM_PREMATURE_CLOSE")))
|
|
3559
|
+
throw error;
|
|
3225
3560
|
} finally {
|
|
3226
3561
|
idleTimer.clear();
|
|
3562
|
+
watchdog.clear();
|
|
3227
3563
|
log("stdio_stopped");
|
|
3228
3564
|
}
|
|
3229
3565
|
}
|
|
@@ -3240,8 +3576,8 @@ async function handleParseError(message, config, log) {
|
|
|
3240
3576
|
}
|
|
3241
3577
|
async function handleRequest(message, config, log) {
|
|
3242
3578
|
const parsed = message.payload;
|
|
3243
|
-
const id =
|
|
3244
|
-
const method =
|
|
3579
|
+
const id = isPlainRecord2(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
3580
|
+
const method = isPlainRecord2(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
3245
3581
|
log("request", { id: id === null ? null : String(id), method });
|
|
3246
3582
|
let response;
|
|
3247
3583
|
try {
|
|
@@ -3279,9 +3615,33 @@ function isTerminalOutputError(error) {
|
|
|
3279
3615
|
return false;
|
|
3280
3616
|
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
3281
3617
|
}
|
|
3282
|
-
function
|
|
3618
|
+
function hasErrorCode(error, code) {
|
|
3619
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
3620
|
+
}
|
|
3621
|
+
function createParentWatchdog(config, onDeadParent) {
|
|
3622
|
+
if (config === undefined)
|
|
3623
|
+
return { clear: () => {} };
|
|
3624
|
+
const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_PARENT_POLL_INTERVAL_MS;
|
|
3625
|
+
if (pollIntervalMs <= 0)
|
|
3626
|
+
return { clear: () => {} };
|
|
3627
|
+
const parentPid = config.parentPid ?? process.ppid;
|
|
3628
|
+
const probeAlive = config.probeAlive ?? isProcessAlive;
|
|
3629
|
+
let fired = false;
|
|
3630
|
+
const timer = setInterval(() => {
|
|
3631
|
+
if (fired || probeAlive(parentPid))
|
|
3632
|
+
return;
|
|
3633
|
+
fired = true;
|
|
3634
|
+
onDeadParent(parentPid, pollIntervalMs);
|
|
3635
|
+
}, pollIntervalMs);
|
|
3636
|
+
timer.unref();
|
|
3637
|
+
return {
|
|
3638
|
+
clear: () => {
|
|
3639
|
+
clearInterval(timer);
|
|
3640
|
+
}
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
3283
3644
|
let timer = null;
|
|
3284
|
-
let isClosed = false;
|
|
3285
3645
|
return {
|
|
3286
3646
|
arm: () => {
|
|
3287
3647
|
if (timer !== null)
|
|
@@ -3289,9 +3649,8 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
3289
3649
|
if (idleTimeoutMs <= 0)
|
|
3290
3650
|
return;
|
|
3291
3651
|
timer = setTimeout(() => {
|
|
3292
|
-
isClosed = true;
|
|
3293
3652
|
log("idle_timeout", { idle_timeout_ms: idleTimeoutMs });
|
|
3294
|
-
|
|
3653
|
+
onTimeout();
|
|
3295
3654
|
}, idleTimeoutMs);
|
|
3296
3655
|
timer.unref();
|
|
3297
3656
|
},
|
|
@@ -3300,8 +3659,7 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
3300
3659
|
return;
|
|
3301
3660
|
clearTimeout(timer);
|
|
3302
3661
|
timer = null;
|
|
3303
|
-
}
|
|
3304
|
-
closed: () => isClosed
|
|
3662
|
+
}
|
|
3305
3663
|
};
|
|
3306
3664
|
}
|
|
3307
3665
|
// components/codegraph/src/serve-invocation.ts
|
|
@@ -3334,9 +3692,10 @@ class CodegraphBridgeStdioError extends Error {
|
|
|
3334
3692
|
var CODEGRAPH_NODE_DESCRIPTION = "Inspect one named symbol or file. In symbol mode, includeCode=true includes leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces return structural outlines with member lists by design. For container source, request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit.";
|
|
3335
3693
|
var CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION = "Symbol mode: include leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces intentionally return structural outlines with members; request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit for source.";
|
|
3336
3694
|
var CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE = "Container symbols intentionally return structural outlines with members. For source, request a specific member symbol or call codegraph_node in file mode with symbolsOnly=false plus offset/limit around the symbol location.";
|
|
3695
|
+
var SIGKILL_ESCALATION_MS = 2000;
|
|
3337
3696
|
async function runBridgedCodegraphProcess(command, args, options) {
|
|
3338
3697
|
const invocation = resolveServeProcessInvocation(command, args);
|
|
3339
|
-
const child =
|
|
3698
|
+
const child = spawn3(invocation.command, invocation.args, {
|
|
3340
3699
|
cwd: options.cwd,
|
|
3341
3700
|
env: options.env,
|
|
3342
3701
|
stdio: ["pipe", "pipe", "inherit"]
|
|
@@ -3359,17 +3718,24 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3359
3718
|
resolveExit(signal === null ? 0 : 1);
|
|
3360
3719
|
});
|
|
3361
3720
|
});
|
|
3362
|
-
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
3363
|
-
defaultResponseMode = mode;
|
|
3364
|
-
});
|
|
3365
|
-
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode);
|
|
3366
|
-
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
3367
|
-
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
3368
3721
|
const destroyChildPipes = () => {
|
|
3369
3722
|
childInput.destroy();
|
|
3370
3723
|
childOutput.destroy();
|
|
3371
3724
|
};
|
|
3372
3725
|
childExit.then(destroyChildPipes, destroyChildPipes);
|
|
3726
|
+
let parentWatchdogFired = false;
|
|
3727
|
+
const parentWatchdog = createParentWatchdog(options.parentWatchdog, () => {
|
|
3728
|
+
parentWatchdogFired = true;
|
|
3729
|
+
options.input.destroy();
|
|
3730
|
+
destroyChildPipes();
|
|
3731
|
+
terminateCodegraphChild(child);
|
|
3732
|
+
});
|
|
3733
|
+
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
3734
|
+
defaultResponseMode = mode;
|
|
3735
|
+
}, () => parentWatchdogFired);
|
|
3736
|
+
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode, () => parentWatchdogFired);
|
|
3737
|
+
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
3738
|
+
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
3373
3739
|
try {
|
|
3374
3740
|
return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
|
|
3375
3741
|
} catch (error) {
|
|
@@ -3380,58 +3746,85 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3380
3746
|
return;
|
|
3381
3747
|
});
|
|
3382
3748
|
throw error;
|
|
3749
|
+
} finally {
|
|
3750
|
+
parentWatchdog.clear();
|
|
3383
3751
|
}
|
|
3384
3752
|
}
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3753
|
+
function terminateCodegraphChild(child) {
|
|
3754
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
3755
|
+
return;
|
|
3756
|
+
child.kill("SIGTERM");
|
|
3757
|
+
const escalation = setTimeout(() => {
|
|
3758
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
3759
|
+
child.kill("SIGKILL");
|
|
3760
|
+
}, SIGKILL_ESCALATION_MS);
|
|
3761
|
+
escalation.unref();
|
|
3762
|
+
}
|
|
3763
|
+
function isWatchdogTeardownError(error) {
|
|
3764
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
3765
|
+
return false;
|
|
3766
|
+
return error.code === "ERR_STREAM_PREMATURE_CLOSE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END" || error.code === "EPIPE";
|
|
3767
|
+
}
|
|
3768
|
+
async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode, tolerateWatchdogClose) {
|
|
3769
|
+
try {
|
|
3770
|
+
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
3771
|
+
if (message.kind === "parse_error") {
|
|
3772
|
+
continue;
|
|
3773
|
+
}
|
|
3774
|
+
const responseMode = message.responseMode;
|
|
3775
|
+
setDefaultResponseMode(responseMode);
|
|
3776
|
+
const key = responseModeKey(message.payload);
|
|
3777
|
+
if (key !== null) {
|
|
3778
|
+
pendingResponses.set(key, {
|
|
3779
|
+
method: jsonRpcMethod(message.payload),
|
|
3780
|
+
responseMode,
|
|
3781
|
+
toolName: jsonRpcToolName(message.payload)
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
await writeLine(childInput, JSON.stringify(message.payload));
|
|
3399
3785
|
}
|
|
3400
|
-
|
|
3786
|
+
childInput.end();
|
|
3787
|
+
} catch (error) {
|
|
3788
|
+
if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
|
|
3789
|
+
throw error;
|
|
3401
3790
|
}
|
|
3402
|
-
childInput.end();
|
|
3403
3791
|
}
|
|
3404
|
-
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3792
|
+
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode, tolerateWatchdogClose) {
|
|
3793
|
+
try {
|
|
3794
|
+
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
3795
|
+
if (message.kind === "parse_error") {
|
|
3796
|
+
await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3797
|
+
continue;
|
|
3798
|
+
}
|
|
3799
|
+
const key = responseModeKey(message.payload);
|
|
3800
|
+
const pendingResponse = key === null ? undefined : pendingResponses.get(key);
|
|
3801
|
+
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
3802
|
+
if (key !== null)
|
|
3803
|
+
pendingResponses.delete(key);
|
|
3804
|
+
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3409
3805
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
if (key !== null)
|
|
3414
|
-
pendingResponses.delete(key);
|
|
3415
|
-
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3806
|
+
} catch (error) {
|
|
3807
|
+
if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
|
|
3808
|
+
throw error;
|
|
3416
3809
|
}
|
|
3417
3810
|
}
|
|
3418
3811
|
function responseModeKey(payload) {
|
|
3419
|
-
if (!
|
|
3812
|
+
if (!isPlainRecord2(payload) || !("id" in payload))
|
|
3420
3813
|
return null;
|
|
3421
3814
|
const id = jsonRpcId(payload["id"]);
|
|
3422
3815
|
return `${typeof id}:${String(id)}`;
|
|
3423
3816
|
}
|
|
3424
3817
|
function jsonRpcMethod(payload) {
|
|
3425
|
-
if (!
|
|
3818
|
+
if (!isPlainRecord2(payload))
|
|
3426
3819
|
return null;
|
|
3427
3820
|
const method = payload["method"];
|
|
3428
3821
|
return typeof method === "string" ? method : null;
|
|
3429
3822
|
}
|
|
3430
3823
|
function jsonRpcToolName(payload) {
|
|
3431
|
-
if (jsonRpcMethod(payload) !== "tools/call" || !
|
|
3824
|
+
if (jsonRpcMethod(payload) !== "tools/call" || !isPlainRecord2(payload))
|
|
3432
3825
|
return null;
|
|
3433
3826
|
const params = payload["params"];
|
|
3434
|
-
if (!
|
|
3827
|
+
if (!isPlainRecord2(params))
|
|
3435
3828
|
return null;
|
|
3436
3829
|
const name = params["name"];
|
|
3437
3830
|
return typeof name === "string" ? name : null;
|
|
@@ -3445,14 +3838,14 @@ function clarifyCodegraphResponse(payload, pendingResponse) {
|
|
|
3445
3838
|
return payload;
|
|
3446
3839
|
}
|
|
3447
3840
|
function clarifyCodegraphToolsList(payload) {
|
|
3448
|
-
if (!
|
|
3841
|
+
if (!isPlainRecord2(payload))
|
|
3449
3842
|
return payload;
|
|
3450
3843
|
const result = payload["result"];
|
|
3451
|
-
if (!
|
|
3844
|
+
if (!isPlainRecord2(result) || !Array.isArray(result["tools"]))
|
|
3452
3845
|
return payload;
|
|
3453
3846
|
let changed = false;
|
|
3454
3847
|
const tools = result["tools"].map((tool) => {
|
|
3455
|
-
if (!
|
|
3848
|
+
if (!isPlainRecord2(tool) || tool["name"] !== "codegraph_node")
|
|
3456
3849
|
return tool;
|
|
3457
3850
|
if (!hasCodegraphNodeContractMetadata(tool))
|
|
3458
3851
|
return tool;
|
|
@@ -3469,7 +3862,7 @@ function clarifyCodegraphNodeTool(tool) {
|
|
|
3469
3862
|
description: CODEGRAPH_NODE_DESCRIPTION
|
|
3470
3863
|
};
|
|
3471
3864
|
const inputSchema = tool["inputSchema"];
|
|
3472
|
-
if (
|
|
3865
|
+
if (isPlainRecord2(inputSchema))
|
|
3473
3866
|
clarified["inputSchema"] = clarifyCodegraphNodeInputSchema(inputSchema);
|
|
3474
3867
|
return clarified;
|
|
3475
3868
|
}
|
|
@@ -3477,17 +3870,17 @@ function hasCodegraphNodeContractMetadata(tool) {
|
|
|
3477
3870
|
if (typeof tool["description"] === "string")
|
|
3478
3871
|
return true;
|
|
3479
3872
|
const inputSchema = tool["inputSchema"];
|
|
3480
|
-
if (!
|
|
3873
|
+
if (!isPlainRecord2(inputSchema))
|
|
3481
3874
|
return false;
|
|
3482
3875
|
const properties = inputSchema["properties"];
|
|
3483
|
-
return
|
|
3876
|
+
return isPlainRecord2(properties) && isPlainRecord2(properties["includeCode"]);
|
|
3484
3877
|
}
|
|
3485
3878
|
function clarifyCodegraphNodeInputSchema(inputSchema) {
|
|
3486
3879
|
const properties = inputSchema["properties"];
|
|
3487
|
-
if (!
|
|
3880
|
+
if (!isPlainRecord2(properties))
|
|
3488
3881
|
return inputSchema;
|
|
3489
3882
|
const includeCode = properties["includeCode"];
|
|
3490
|
-
if (!
|
|
3883
|
+
if (!isPlainRecord2(includeCode))
|
|
3491
3884
|
return inputSchema;
|
|
3492
3885
|
return {
|
|
3493
3886
|
...inputSchema,
|
|
@@ -3501,14 +3894,14 @@ function clarifyCodegraphNodeInputSchema(inputSchema) {
|
|
|
3501
3894
|
};
|
|
3502
3895
|
}
|
|
3503
3896
|
function clarifyCodegraphNodeCallResult(payload) {
|
|
3504
|
-
if (!
|
|
3897
|
+
if (!isPlainRecord2(payload))
|
|
3505
3898
|
return payload;
|
|
3506
3899
|
const result = payload["result"];
|
|
3507
|
-
if (!
|
|
3900
|
+
if (!isPlainRecord2(result) || !Array.isArray(result["content"]))
|
|
3508
3901
|
return payload;
|
|
3509
3902
|
let changed = false;
|
|
3510
3903
|
const content = result["content"].map((item) => {
|
|
3511
|
-
if (!
|
|
3904
|
+
if (!isPlainRecord2(item) || item["type"] !== "text" || typeof item["text"] !== "string")
|
|
3512
3905
|
return item;
|
|
3513
3906
|
const text = clarifyContainerOutlineGuidance(item["text"]);
|
|
3514
3907
|
if (text === item["text"])
|
|
@@ -3544,11 +3937,12 @@ async function runUnavailableCodegraphMcpServer(options) {
|
|
|
3544
3937
|
serverVersion: options.serverVersion
|
|
3545
3938
|
},
|
|
3546
3939
|
input: options.input,
|
|
3547
|
-
output: options.output
|
|
3940
|
+
output: options.output,
|
|
3941
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3548
3942
|
});
|
|
3549
3943
|
}
|
|
3550
3944
|
async function handleUnavailableCodegraphMcpRequest(input, options) {
|
|
3551
|
-
if (!
|
|
3945
|
+
if (!isPlainRecord2(input)) {
|
|
3552
3946
|
return errorResponse(null, -32600, "Invalid Request");
|
|
3553
3947
|
}
|
|
3554
3948
|
const id = jsonRpcId(input["id"]);
|
|
@@ -3576,7 +3970,7 @@ async function handleUnavailableCodegraphMcpRequest(input, options) {
|
|
|
3576
3970
|
return errorResponse(id, -32601, `Method not found: ${String(method)}`);
|
|
3577
3971
|
}
|
|
3578
3972
|
function requestedProtocolVersion(params) {
|
|
3579
|
-
if (!
|
|
3973
|
+
if (!isPlainRecord2(params) || typeof params["protocolVersion"] !== "string")
|
|
3580
3974
|
return "2024-11-05";
|
|
3581
3975
|
return params["protocolVersion"];
|
|
3582
3976
|
}
|
|
@@ -3588,7 +3982,7 @@ var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config
|
|
|
3588
3982
|
`;
|
|
3589
3983
|
var CODEGRAPH_EXCLUDED_HINT = `CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.
|
|
3590
3984
|
`;
|
|
3591
|
-
var CODEGRAPH_VERSION2 =
|
|
3985
|
+
var CODEGRAPH_VERSION2 = CODEGRAPH_PINNED_VERSION;
|
|
3592
3986
|
var PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"];
|
|
3593
3987
|
async function runCodegraphServe(options = {}) {
|
|
3594
3988
|
const env = options.env ?? processEnv3;
|
|
@@ -3636,7 +4030,7 @@ async function runCodegraphServe(options = {}) {
|
|
|
3636
4030
|
return runUnavailableMcp(buildCodegraphNodeSkipHint(nodeSupport), options);
|
|
3637
4031
|
}
|
|
3638
4032
|
const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
|
|
3639
|
-
const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, options.buildEnv);
|
|
4033
|
+
const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, codegraphConfig.daemon !== false, options.buildEnv);
|
|
3640
4034
|
const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
|
|
3641
4035
|
return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
|
|
3642
4036
|
cwd: projectCwd,
|
|
@@ -3644,7 +4038,8 @@ async function runCodegraphServe(options = {}) {
|
|
|
3644
4038
|
input: options.stdin ?? processStdin2,
|
|
3645
4039
|
output: options.stdout ?? processStdout2,
|
|
3646
4040
|
stderr: options.stderr ?? processStderr3,
|
|
3647
|
-
stdio: "pipe"
|
|
4041
|
+
stdio: "pipe",
|
|
4042
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3648
4043
|
});
|
|
3649
4044
|
}
|
|
3650
4045
|
async function runUnavailableMcp(reason, options) {
|
|
@@ -3653,7 +4048,8 @@ async function runUnavailableMcp(reason, options) {
|
|
|
3653
4048
|
input: options.stdin ?? processStdin2,
|
|
3654
4049
|
output: options.stdout ?? processStdout2,
|
|
3655
4050
|
reason,
|
|
3656
|
-
serverVersion: CODEGRAPH_VERSION2
|
|
4051
|
+
serverVersion: CODEGRAPH_VERSION2,
|
|
4052
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3657
4053
|
});
|
|
3658
4054
|
return 0;
|
|
3659
4055
|
}
|
|
@@ -3662,10 +4058,10 @@ async function provisionMissingCodegraph(options) {
|
|
|
3662
4058
|
return null;
|
|
3663
4059
|
if (options.config.auto_provision === false)
|
|
3664
4060
|
return null;
|
|
3665
|
-
const installDir = options.trustedInstallDir ??
|
|
4061
|
+
const installDir = options.trustedInstallDir ?? join15(options.homeDir, ".omo", "codegraph");
|
|
3666
4062
|
const result = await options.ensureProvisioned({
|
|
3667
4063
|
installDir,
|
|
3668
|
-
lockDir:
|
|
4064
|
+
lockDir: join15(installDir, ".locks"),
|
|
3669
4065
|
version: CODEGRAPH_VERSION2
|
|
3670
4066
|
});
|
|
3671
4067
|
if (!result.provisioned || result.binPath === undefined)
|
|
@@ -3682,8 +4078,8 @@ function shouldSkipResolvedCommand(resolution, commandExists) {
|
|
|
3682
4078
|
function looksLikePath2(command) {
|
|
3683
4079
|
return command.includes("/") || command.includes("\\");
|
|
3684
4080
|
}
|
|
3685
|
-
function codegraphEnvForConfig2(trustedInstallDir, homeDir, buildEnv) {
|
|
3686
|
-
const env =
|
|
4081
|
+
function codegraphEnvForConfig2(trustedInstallDir, homeDir, daemon, buildEnv) {
|
|
4082
|
+
const env = buildEnv?.({ daemon, homeDir }) ?? buildCodegraphEnv({ daemon, homeDir });
|
|
3687
4083
|
return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
|
|
3688
4084
|
}
|
|
3689
4085
|
function resolveProjectCwd(env, fallback) {
|
|
@@ -3691,17 +4087,14 @@ function resolveProjectCwd(env, fallback) {
|
|
|
3691
4087
|
const candidate = env[key]?.trim();
|
|
3692
4088
|
if (candidate === undefined || candidate.length === 0)
|
|
3693
4089
|
continue;
|
|
3694
|
-
const resolved =
|
|
4090
|
+
const resolved = resolve8(candidate);
|
|
3695
4091
|
if (existsSync10(resolved))
|
|
3696
4092
|
return resolved;
|
|
3697
4093
|
}
|
|
3698
|
-
return
|
|
4094
|
+
return resolve8(fallback);
|
|
3699
4095
|
}
|
|
3700
4096
|
function provisionedBinFromInstallDir3(installDir) {
|
|
3701
|
-
|
|
3702
|
-
return null;
|
|
3703
|
-
const candidate = join14(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
3704
|
-
return existsSync10(candidate) ? candidate : null;
|
|
4097
|
+
return resolvePinnedCodegraphBin(installDir);
|
|
3705
4098
|
}
|
|
3706
4099
|
async function runCodegraphServeCli() {
|
|
3707
4100
|
process.exitCode = await runCodegraphServe();
|
|
@@ -3720,7 +4113,7 @@ function isDirectInvocation(argvPath) {
|
|
|
3720
4113
|
const moduleName = basename4(modulePath);
|
|
3721
4114
|
if (moduleName !== "serve.js" && moduleName !== "serve.ts")
|
|
3722
4115
|
return false;
|
|
3723
|
-
return
|
|
4116
|
+
return realpathSync6(resolve8(argvPath)) === realpathSync6(modulePath);
|
|
3724
4117
|
}
|
|
3725
4118
|
|
|
3726
4119
|
// components/codegraph/src/sweep-cli.ts
|
|
@@ -3767,6 +4160,7 @@ function writeSweepReport(stdout, result) {
|
|
|
3767
4160
|
failed: result.failed,
|
|
3768
4161
|
killed: result.killed.map(formatProcess),
|
|
3769
4162
|
ownedRoots: result.ownedRoots,
|
|
4163
|
+
spared: result.spared.map(formatProcess),
|
|
3770
4164
|
stampFile: result.stampFile
|
|
3771
4165
|
})}
|
|
3772
4166
|
`);
|
|
@@ -3830,7 +4224,7 @@ function isDirectInvocation2(argvPath) {
|
|
|
3830
4224
|
const moduleName = basename5(modulePath);
|
|
3831
4225
|
if (moduleName !== "cli.js" && moduleName !== "cli.ts")
|
|
3832
4226
|
return false;
|
|
3833
|
-
return
|
|
4227
|
+
return realpathSync7(resolve9(argvPath)) === realpathSync7(modulePath);
|
|
3834
4228
|
}
|
|
3835
4229
|
export {
|
|
3836
4230
|
runCodegraphCli
|