oh-my-opencode 4.11.1 → 4.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
- package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
- package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
- package/.agents/skills/work-with-pr/SKILL.md +19 -5
- package/.opencode/skills/work-with-pr/SKILL.md +19 -5
- package/dist/agents/types.d.ts +7 -6
- package/dist/cli/index.js +460 -309
- package/dist/cli-node/index.js +460 -309
- package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
- package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
- package/dist/index.js +593 -310
- package/dist/plugin/tool-execute-before.d.ts +2 -0
- package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
- package/dist/skills/ultraresearch/SKILL.md +11 -2
- package/dist/skills/ulw-plan/SKILL.md +2 -1
- package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
- package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
- package/dist/tools/background-task/constants.d.ts +1 -1
- package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
- package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
- package/dist/tui.js +25 -10
- package/package.json +13 -13
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
- 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/codegraph/dist/cli.js +336 -173
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
- 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/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
- 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/test/package-smoke.test.ts +12 -92
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
- 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 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
- package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
- package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
- package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
- package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
- 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/test-support/package-smoke-fixture.ts +158 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/package-lock.json +30 -22
- package/packages/omo-codex/plugin/package.json +2 -1
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
- package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
- package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
- package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
- package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
- package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
- package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
- package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
- package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
- package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
- package/packages/omo-codex/scripts/install-local.mjs +1 -0
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
|
@@ -17,6 +17,11 @@ import {
|
|
|
17
17
|
evaluateCodegraphNodeSupport,
|
|
18
18
|
} from "../../../../../utils/src/codegraph/node-support.ts";
|
|
19
19
|
import {
|
|
20
|
+
ensureCodegraphProvisioned,
|
|
21
|
+
type EnsureCodegraphProvisionedOptions,
|
|
22
|
+
} from "../../../../../utils/src/codegraph/provision.ts";
|
|
23
|
+
import {
|
|
24
|
+
codegraphCommandRequiresSupportedLocalNode,
|
|
20
25
|
resolveCodegraphCommand,
|
|
21
26
|
type CodegraphCommandResolution,
|
|
22
27
|
type ResolveCodegraphCommandOptions,
|
|
@@ -36,6 +41,9 @@ export type CodegraphServeProcessRunner = (
|
|
|
36
41
|
args: readonly string[],
|
|
37
42
|
options: CodegraphServeProcessOptions,
|
|
38
43
|
) => Promise<number>;
|
|
44
|
+
export type CodegraphProvisioner = (
|
|
45
|
+
options: EnsureCodegraphProvisionedOptions,
|
|
46
|
+
) => ReturnType<typeof ensureCodegraphProvisioned>;
|
|
39
47
|
|
|
40
48
|
export interface ServeProcessInvocation {
|
|
41
49
|
readonly args: readonly string[];
|
|
@@ -57,12 +65,14 @@ export interface RunCodegraphServeOptions {
|
|
|
57
65
|
readonly resolve?: (options: ResolveCodegraphCommandOptions) => ReturnType<typeof resolveCodegraphCommand>;
|
|
58
66
|
readonly runProcess?: CodegraphServeProcessRunner;
|
|
59
67
|
readonly stderr?: CodegraphServeStderr;
|
|
68
|
+
readonly ensureProvisioned?: CodegraphProvisioner;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
const CODEGRAPH_SKIP_HINT =
|
|
63
72
|
"CodeGraph MCP skipped: codegraph binary not found. Install CodeGraph or set OMO_CODEGRAPH_BIN.\n";
|
|
64
73
|
const CODEGRAPH_DISABLED_HINT =
|
|
65
74
|
"CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.\n";
|
|
75
|
+
const CODEGRAPH_VERSION = "1.0.1";
|
|
66
76
|
const WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
|
|
67
77
|
const WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
|
|
68
78
|
|
|
@@ -81,14 +91,27 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
81
91
|
homeDir,
|
|
82
92
|
provisioned: () => provisionedBinFromInstallDir(codegraphConfig.install_dir),
|
|
83
93
|
} satisfies ResolveCodegraphCommandOptions;
|
|
84
|
-
|
|
94
|
+
let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
|
|
95
|
+
const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
|
|
85
96
|
if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync)) {
|
|
86
|
-
(
|
|
87
|
-
|
|
97
|
+
if (resolution.source === "path" && !nodeSupport.supported) {
|
|
98
|
+
(options.stderr ?? processStderr).write(buildCodegraphNodeSkipHint(nodeSupport));
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
const provisioned = await provisionMissingCodegraph({
|
|
102
|
+
config: codegraphConfig,
|
|
103
|
+
ensureProvisioned: options.ensureProvisioned ?? ensureCodegraphProvisioned,
|
|
104
|
+
homeDir,
|
|
105
|
+
resolution,
|
|
106
|
+
});
|
|
107
|
+
if (provisioned === null) {
|
|
108
|
+
(options.stderr ?? processStderr).write(CODEGRAPH_SKIP_HINT);
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
resolution = provisioned;
|
|
88
112
|
}
|
|
89
113
|
|
|
90
|
-
|
|
91
|
-
if (resolution.source !== "bundled" && resolution.source !== "env" && !nodeSupport.supported) {
|
|
114
|
+
if (codegraphCommandRequiresSupportedLocalNode(resolution) && !nodeSupport.supported) {
|
|
92
115
|
(options.stderr ?? processStderr).write(buildCodegraphNodeSkipHint(nodeSupport));
|
|
93
116
|
return 1;
|
|
94
117
|
}
|
|
@@ -105,6 +128,25 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
105
128
|
});
|
|
106
129
|
}
|
|
107
130
|
|
|
131
|
+
async function provisionMissingCodegraph(options: {
|
|
132
|
+
readonly config: CodegraphConfig;
|
|
133
|
+
readonly ensureProvisioned: CodegraphProvisioner;
|
|
134
|
+
readonly homeDir: string;
|
|
135
|
+
readonly resolution: CodegraphCommandResolution;
|
|
136
|
+
}): Promise<CodegraphCommandResolution | null> {
|
|
137
|
+
if (options.resolution.source === "env") return null;
|
|
138
|
+
if (options.config.auto_provision === false) return null;
|
|
139
|
+
|
|
140
|
+
const installDir = options.config.install_dir ?? join(options.homeDir, ".omo", "codegraph");
|
|
141
|
+
const result = await options.ensureProvisioned({
|
|
142
|
+
installDir,
|
|
143
|
+
lockDir: join(installDir, ".locks"),
|
|
144
|
+
version: CODEGRAPH_VERSION,
|
|
145
|
+
});
|
|
146
|
+
if (!result.provisioned || result.binPath === undefined) return null;
|
|
147
|
+
return { argsPrefix: [], command: result.binPath, exists: true, source: "provisioned" };
|
|
148
|
+
}
|
|
149
|
+
|
|
108
150
|
function shouldSkipResolvedCommand(
|
|
109
151
|
resolution: CodegraphCommandResolution,
|
|
110
152
|
commandExists: (filePath: string) => boolean,
|
|
@@ -9,6 +9,7 @@ import { buildCodegraphEnv } from "../../../../../utils/src/codegraph/env.ts";
|
|
|
9
9
|
import { evaluateCodegraphNodeSupport, type CodegraphNodeSupport } from "../../../../../utils/src/codegraph/node-support.ts";
|
|
10
10
|
import { ensureCodegraphProvisioned } from "../../../../../utils/src/codegraph/provision.ts";
|
|
11
11
|
import {
|
|
12
|
+
codegraphCommandRequiresSupportedLocalNode,
|
|
12
13
|
resolveCodegraphCommand,
|
|
13
14
|
type CodegraphCommandResolution,
|
|
14
15
|
} from "../../../../../utils/src/codegraph/resolve.ts";
|
|
@@ -102,13 +103,10 @@ async function resolveOrProvisionCommand(
|
|
|
102
103
|
nodeSupport: CodegraphNodeSupport,
|
|
103
104
|
): Promise<ResolutionResult> {
|
|
104
105
|
const resolved = deps.resolveCommand({ env, homeDir, provisioned: () => provisionedBinFromInstallDir(config.install_dir) });
|
|
105
|
-
if (resolved.exists) {
|
|
106
|
-
if (resolved.source !== "bundled" && resolved.source !== "env" && !nodeSupport.supported) {
|
|
107
|
-
return { kind: "unsupported-node" };
|
|
108
|
-
}
|
|
106
|
+
if (resolved.exists && canUseResolvedCommand(resolved, nodeSupport)) {
|
|
109
107
|
return { kind: "resolved", resolution: resolved };
|
|
110
108
|
}
|
|
111
|
-
if (
|
|
109
|
+
if (resolved.exists && config.auto_provision === false) return { kind: "unsupported-node" };
|
|
112
110
|
if (config.auto_provision === false) return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
|
|
113
111
|
|
|
114
112
|
const installDir = config.install_dir ?? join(homeDir, ".omo", "codegraph");
|
|
@@ -119,6 +117,10 @@ async function resolveOrProvisionCommand(
|
|
|
119
117
|
return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
|
|
120
118
|
}
|
|
121
119
|
|
|
120
|
+
function canUseResolvedCommand(resolved: CodegraphCommandResolution, nodeSupport: CodegraphNodeSupport): boolean {
|
|
121
|
+
return !codegraphCommandRequiresSupportedLocalNode(resolved) || nodeSupport.supported;
|
|
122
|
+
}
|
|
123
|
+
|
|
122
124
|
function decideStartupAction(status: CodegraphCommandResult): { readonly kind: "init" } | { readonly kind: "skip"; readonly reason: string } | { readonly kind: "sync" } {
|
|
123
125
|
if (status.timedOut) return { kind: "skip", reason: "status timed out" };
|
|
124
126
|
const text = `${status.stdout}\n${status.stderr ?? ""}`.toLowerCase();
|
|
@@ -9,12 +9,13 @@ import { runCodegraphCli } from "../src/cli.ts";
|
|
|
9
9
|
import {
|
|
10
10
|
executeCodegraphSessionStartHook,
|
|
11
11
|
resolveCodegraphCommandInvocation,
|
|
12
|
+
runCodegraphPostToolUseHook,
|
|
12
13
|
runCodegraphSessionStartWorker,
|
|
13
14
|
type WorkerSpawnInvocation,
|
|
14
15
|
} from "../src/hook.ts";
|
|
15
16
|
|
|
16
17
|
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
17
|
-
const
|
|
18
|
+
const pluginConfigPath = resolve(pluginRoot, ".codex-plugin/plugin.json");
|
|
18
19
|
|
|
19
20
|
describe("CodeGraph SessionStart hook", () => {
|
|
20
21
|
it("#given hook session-start cli args #when invoked with empty JSON input #then it emits valid JSON and exits zero", async () => {
|
|
@@ -48,6 +49,54 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
48
49
|
}
|
|
49
50
|
});
|
|
50
51
|
|
|
52
|
+
it("#given CodeGraph MCP reports an uninitialized project #when PostToolUse fires #then it emits OMO global-store init guidance", async () => {
|
|
53
|
+
// given
|
|
54
|
+
const output = runCodegraphPostToolUseHook(
|
|
55
|
+
{
|
|
56
|
+
cwd: "/Users/me/project",
|
|
57
|
+
tool_name: "codegraph.codegraph_status",
|
|
58
|
+
tool_response: {
|
|
59
|
+
error: [
|
|
60
|
+
"Tool execution failed: CodeGraph not initialized in /Users/me/project.",
|
|
61
|
+
"Run 'codegraph init' in that project first.",
|
|
62
|
+
].join(" "),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{ homeDir: "/Users/me" },
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// when
|
|
69
|
+
const parsed = JSON.parse(output);
|
|
70
|
+
|
|
71
|
+
// then
|
|
72
|
+
expect(parsed).toEqual({
|
|
73
|
+
hookSpecificOutput: {
|
|
74
|
+
hookEventName: "PostToolUse",
|
|
75
|
+
additionalContext: expect.stringContaining('"/Users/me/.omo/codegraph/projects/project-'),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain('run `codegraph init` from "/Users/me/project"');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("#given real CodeGraph status output has no MCP path phrase #when PostToolUse fires #then it emits OMO global-store init guidance", async () => {
|
|
82
|
+
// given
|
|
83
|
+
const output = runCodegraphPostToolUseHook(
|
|
84
|
+
{
|
|
85
|
+
cwd: "/Users/me/project",
|
|
86
|
+
tool_name: "mcp__codegraph__codegraph_status",
|
|
87
|
+
tool_response: ['Project: /Users/me/project', "Not initialized", 'Run "codegraph init" to initialize'].join("\n"),
|
|
88
|
+
},
|
|
89
|
+
{ homeDir: "/Users/me" },
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// when
|
|
93
|
+
const parsed = JSON.parse(output);
|
|
94
|
+
|
|
95
|
+
// then
|
|
96
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain('CodeGraph is not initialized for "/Users/me/project"');
|
|
97
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain('"/Users/me/.omo/codegraph/projects/project-');
|
|
98
|
+
});
|
|
99
|
+
|
|
51
100
|
it("#given CodeGraph is disabled by Codex SOT config #when SessionStart fires #then it skips without spawning", async () => {
|
|
52
101
|
// given
|
|
53
102
|
const stdout: string[] = [];
|
|
@@ -198,93 +247,6 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
198
247
|
}
|
|
199
248
|
});
|
|
200
249
|
|
|
201
|
-
it("#given an unsupported local Node and a PATH CodeGraph command #when worker runs #then it skips without touching the workspace", async () => {
|
|
202
|
-
// given
|
|
203
|
-
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-"));
|
|
204
|
-
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-home-"));
|
|
205
|
-
const outcomes: unknown[] = [];
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
// when
|
|
209
|
-
const result = await runCodegraphSessionStartWorker({
|
|
210
|
-
cwd: workspace,
|
|
211
|
-
env: { HOME: homeDir },
|
|
212
|
-
nodeVersion: "26.3.0",
|
|
213
|
-
logOutcome: (outcome) => outcomes.push(outcome),
|
|
214
|
-
deps: {
|
|
215
|
-
resolveCommand: () => {
|
|
216
|
-
return { argsPrefix: [], command: "/usr/local/bin/codegraph", exists: true, source: "path" };
|
|
217
|
-
},
|
|
218
|
-
ensureProvisioned: () => {
|
|
219
|
-
throw new Error("ensureProvisioned should not run on unsupported Node");
|
|
220
|
-
},
|
|
221
|
-
prepareWorkspace: () => {
|
|
222
|
-
throw new Error("prepareWorkspace should not run on unsupported Node");
|
|
223
|
-
},
|
|
224
|
-
runCommand: () => {
|
|
225
|
-
throw new Error("runCommand should not run on unsupported Node");
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// then
|
|
231
|
-
expect(result).toEqual({ action: "skipped-unsupported-node" });
|
|
232
|
-
expect(existsSync(join(workspace, ".codegraph"))).toBe(false);
|
|
233
|
-
expect(outcomes).toEqual([{ action: "skipped-unsupported-node", projectRoot: workspace }]);
|
|
234
|
-
} finally {
|
|
235
|
-
rmSync(workspace, { recursive: true, force: true });
|
|
236
|
-
rmSync(homeDir, { recursive: true, force: true });
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it("#given an unsupported local Node but bundled CodeGraph resolves through CODEGRAPH_NODE_BIN #when worker runs #then it bootstraps with the compatible runtime", async () => {
|
|
241
|
-
// given
|
|
242
|
-
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-compatible-node-"));
|
|
243
|
-
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-compatible-node-home-"));
|
|
244
|
-
const nodeBin = "/opt/node22/bin/node";
|
|
245
|
-
const calls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
246
|
-
const outcomes: unknown[] = [];
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
// when
|
|
250
|
-
const result = await runCodegraphSessionStartWorker({
|
|
251
|
-
cwd: workspace,
|
|
252
|
-
env: { CODEGRAPH_NODE_BIN: nodeBin, HOME: homeDir },
|
|
253
|
-
nodeVersion: "26.3.0",
|
|
254
|
-
logOutcome: (outcome) => outcomes.push(outcome),
|
|
255
|
-
deps: {
|
|
256
|
-
ensureGitignored: () => true,
|
|
257
|
-
ensureProvisioned: () => {
|
|
258
|
-
throw new Error("provisioning should not run when bundled CodeGraph resolved");
|
|
259
|
-
},
|
|
260
|
-
prepareWorkspace: () => ({
|
|
261
|
-
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
262
|
-
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
263
|
-
linked: true,
|
|
264
|
-
mode: "global-linked",
|
|
265
|
-
projectLink: join(workspace, ".codegraph"),
|
|
266
|
-
}),
|
|
267
|
-
resolveCommand: () => ({ argsPrefix: ["codegraph.js"], command: nodeBin, exists: true, source: "bundled" }),
|
|
268
|
-
runCommand: (_projectRoot, command, args) => {
|
|
269
|
-
calls.push({ args, command });
|
|
270
|
-
return Promise.resolve({ exitCode: 0, stdout: calls.length === 1 ? '{"initialized":false}' : "", timedOut: false });
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// then
|
|
276
|
-
expect(result).toEqual({ action: "initialized" });
|
|
277
|
-
expect(calls).toEqual([
|
|
278
|
-
{ args: ["codegraph.js", "status", "--json"], command: nodeBin },
|
|
279
|
-
{ args: ["codegraph.js", "init"], command: nodeBin },
|
|
280
|
-
]);
|
|
281
|
-
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "bundled", timedOut: false }]);
|
|
282
|
-
} finally {
|
|
283
|
-
rmSync(workspace, { recursive: true, force: true });
|
|
284
|
-
rmSync(homeDir, { recursive: true, force: true });
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
250
|
it("#given CodeGraph cannot be resolved or provisioned #when worker runs #then it logs a graceful skip", async () => {
|
|
289
251
|
// given
|
|
290
252
|
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-"));
|
|
@@ -537,18 +499,18 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
537
499
|
|
|
538
500
|
it("#given plugin hook config #when inspected #then CodeGraph is registered after bootstrap SessionStart", () => {
|
|
539
501
|
// given
|
|
540
|
-
const
|
|
502
|
+
const pluginConfig: unknown = JSON.parse(readFileSync(pluginConfigPath, "utf8"));
|
|
541
503
|
|
|
542
504
|
// when
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
505
|
+
const hookPaths =
|
|
506
|
+
typeof pluginConfig === "object" && pluginConfig !== null && "hooks" in pluginConfig && Array.isArray(pluginConfig.hooks)
|
|
507
|
+
? pluginConfig.hooks.filter((hookPath): hookPath is string => typeof hookPath === "string")
|
|
508
|
+
: [];
|
|
547
509
|
|
|
548
510
|
// then
|
|
549
|
-
expect(
|
|
550
|
-
expect(
|
|
551
|
-
|
|
511
|
+
expect(hookPaths).toContain("./hooks/session-start-checking-codegraph-bootstrap.json");
|
|
512
|
+
expect(hookPaths.indexOf("./hooks/session-start-checking-bootstrap-provisioning.json")).toBeLessThan(
|
|
513
|
+
hookPaths.indexOf("./hooks/session-start-checking-codegraph-bootstrap.json"),
|
|
552
514
|
);
|
|
553
515
|
});
|
|
554
516
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { runCodegraphSessionStartWorker } from "../src/hook.ts";
|
|
7
|
+
import { runCodegraphServe } from "../src/serve.ts";
|
|
8
|
+
|
|
9
|
+
describe("CodeGraph provisioned launcher Node guard", () => {
|
|
10
|
+
it("#given provisioned CodeGraph binary #when serve runs under unsupported local Node #then it trusts the launcher", async () => {
|
|
11
|
+
// given
|
|
12
|
+
const commandPath = "/home/test/.omo/codegraph/bin/codegraph";
|
|
13
|
+
const spawned: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
14
|
+
|
|
15
|
+
// when
|
|
16
|
+
const exitCode = await runCodegraphServe({
|
|
17
|
+
env: {},
|
|
18
|
+
nodeVersion: "26.3.0",
|
|
19
|
+
buildEnv: () => ({}),
|
|
20
|
+
resolve: () => ({ argsPrefix: [], command: commandPath, exists: true, source: "provisioned" }),
|
|
21
|
+
runProcess: (command, args) => {
|
|
22
|
+
spawned.push({ args, command });
|
|
23
|
+
return Promise.resolve(0);
|
|
24
|
+
},
|
|
25
|
+
stderr: { write: () => undefined },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// then
|
|
29
|
+
expect(exitCode).toBe(0);
|
|
30
|
+
expect(spawned).toEqual([{ args: ["serve", "--mcp"], command: commandPath }]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("#given provisioned CodeGraph exists #when SessionStart worker runs under unsupported local Node #then it bootstraps through the launcher", async () => {
|
|
34
|
+
// given
|
|
35
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node25-"));
|
|
36
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node25-home-"));
|
|
37
|
+
const installDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node25-install-"));
|
|
38
|
+
const binPath = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
39
|
+
const calls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
40
|
+
const outcomes: unknown[] = [];
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
mkdirSync(join(installDir, "bin"), { recursive: true });
|
|
44
|
+
writeFileSync(binPath, "");
|
|
45
|
+
|
|
46
|
+
// when
|
|
47
|
+
const result = await runCodegraphSessionStartWorker({
|
|
48
|
+
config: { codegraph: { enabled: true, install_dir: installDir }, sources: [], warnings: [] },
|
|
49
|
+
nodeVersion: "26.3.0",
|
|
50
|
+
cwd: workspace,
|
|
51
|
+
env: { HOME: homeDir },
|
|
52
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
53
|
+
deps: {
|
|
54
|
+
ensureGitignored: () => true,
|
|
55
|
+
ensureProvisioned: () => {
|
|
56
|
+
throw new Error("provisioning should not run when install_dir binary exists");
|
|
57
|
+
},
|
|
58
|
+
prepareWorkspace: () => ({
|
|
59
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
60
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
61
|
+
linked: true,
|
|
62
|
+
mode: "global-linked",
|
|
63
|
+
projectLink: join(workspace, ".codegraph"),
|
|
64
|
+
}),
|
|
65
|
+
resolveCommand: (options) => {
|
|
66
|
+
const provisioned = options?.provisioned?.() ?? null;
|
|
67
|
+
return {
|
|
68
|
+
argsPrefix: [],
|
|
69
|
+
command: provisioned ?? "missing-codegraph",
|
|
70
|
+
exists: provisioned !== null,
|
|
71
|
+
source: provisioned === null ? "path" : "provisioned",
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
runCommand: (_projectRoot, command, args) => {
|
|
75
|
+
calls.push({ args, command });
|
|
76
|
+
return Promise.resolve({ exitCode: 0, stdout: calls.length === 1 ? '{"initialized":false}' : "", timedOut: false });
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// then
|
|
82
|
+
expect(result).toEqual({ action: "initialized" });
|
|
83
|
+
expect(calls).toEqual([
|
|
84
|
+
{ args: ["status", "--json"], command: binPath },
|
|
85
|
+
{ args: ["init"], command: binPath },
|
|
86
|
+
]);
|
|
87
|
+
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
|
|
88
|
+
} finally {
|
|
89
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
90
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
91
|
+
rmSync(installDir, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { CODEGRAPH_UNSAFE_NODE_ENV } from "../../../../../utils/src/codegraph/node-support.ts";
|
|
4
|
+
import { runCodegraphServe } from "../src/serve.ts";
|
|
5
|
+
|
|
6
|
+
describe("runCodegraphServe node support", () => {
|
|
7
|
+
it("#given Node is too new and no command resolves #when serving MCP #then the unsupported-node hint wins", async () => {
|
|
8
|
+
// given
|
|
9
|
+
const stderr: string[] = [];
|
|
10
|
+
const spawned: string[] = [];
|
|
11
|
+
|
|
12
|
+
// when
|
|
13
|
+
const exitCode = await runCodegraphServe({
|
|
14
|
+
env: { PATH: "/bin" },
|
|
15
|
+
nodeVersion: "26.3.0",
|
|
16
|
+
buildEnv: () => ({}),
|
|
17
|
+
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
18
|
+
runProcess: (command: string) => {
|
|
19
|
+
spawned.push(command);
|
|
20
|
+
return Promise.resolve(0);
|
|
21
|
+
},
|
|
22
|
+
stderr: { write: (chunk: string) => stderr.push(chunk) },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// then
|
|
26
|
+
expect(exitCode).toBe(1);
|
|
27
|
+
expect(spawned).toEqual([]);
|
|
28
|
+
expect(stderr).toHaveLength(1);
|
|
29
|
+
expect(stderr[0]).toContain("CodeGraph MCP skipped");
|
|
30
|
+
expect(stderr[0]).toContain("Node 26 is unsupported");
|
|
31
|
+
expect(stderr[0]).toContain(CODEGRAPH_UNSAFE_NODE_ENV);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { runCodegraphServe } from "../src/serve.ts";
|
|
5
|
+
|
|
6
|
+
describe("runCodegraphServe provisioning", () => {
|
|
7
|
+
it("#given CodeGraph is unresolved #when serving MCP #then provisions CodeGraph before spawning", async () => {
|
|
8
|
+
// given
|
|
9
|
+
const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
|
|
10
|
+
const calls: Array<{
|
|
11
|
+
readonly args: readonly string[];
|
|
12
|
+
readonly command: string;
|
|
13
|
+
readonly env: Record<string, string | undefined>;
|
|
14
|
+
}> = [];
|
|
15
|
+
const stderr: string[] = [];
|
|
16
|
+
|
|
17
|
+
// when
|
|
18
|
+
const exitCode = await runCodegraphServe({
|
|
19
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
20
|
+
env: { PATH: "/bin" },
|
|
21
|
+
homeDir: "/tmp/home",
|
|
22
|
+
nodeVersion: "22.14.0",
|
|
23
|
+
buildEnv: () => ({}),
|
|
24
|
+
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
|
25
|
+
ensureProvisioned: (options) =>
|
|
26
|
+
Promise.resolve({
|
|
27
|
+
binPath: join(options.installDir ?? "/tmp/home/.omo/codegraph", "bin", "codegraph"),
|
|
28
|
+
provisioned: true,
|
|
29
|
+
}),
|
|
30
|
+
runProcess: (command, args, options) => {
|
|
31
|
+
calls.push({ args, command, env: options.env });
|
|
32
|
+
return Promise.resolve(0);
|
|
33
|
+
},
|
|
34
|
+
stderr: { write: (chunk: string) => stderr.push(chunk) },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// then
|
|
38
|
+
expect(exitCode).toBe(0);
|
|
39
|
+
expect(stderr).toEqual([]);
|
|
40
|
+
expect(calls).toEqual([
|
|
41
|
+
{
|
|
42
|
+
args: ["serve", "--mcp"],
|
|
43
|
+
command: binPath,
|
|
44
|
+
env: { PATH: "/bin" },
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -17,6 +17,7 @@ describe("runCodegraphServe", () => {
|
|
|
17
17
|
|
|
18
18
|
// when
|
|
19
19
|
const exitCode = await runCodegraphServe({
|
|
20
|
+
config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
|
|
20
21
|
env: { PATH: "/bin" },
|
|
21
22
|
buildEnv: () => ({}),
|
|
22
23
|
resolve: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
|
package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { existsSync, mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { runCodegraphSessionStartWorker } from "../src/hook.ts";
|
|
7
|
+
|
|
8
|
+
describe("CodeGraph SessionStart worker Node support", () => {
|
|
9
|
+
it("#given an unsupported local Node and a PATH CodeGraph command with auto provisioning disabled #when worker runs #then it skips without touching the workspace", async () => {
|
|
10
|
+
// given
|
|
11
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-"));
|
|
12
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-home-"));
|
|
13
|
+
const outcomes: unknown[] = [];
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// when
|
|
17
|
+
const result = await runCodegraphSessionStartWorker({
|
|
18
|
+
config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
|
|
19
|
+
cwd: workspace,
|
|
20
|
+
env: { HOME: homeDir },
|
|
21
|
+
nodeVersion: "26.3.0",
|
|
22
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
23
|
+
deps: {
|
|
24
|
+
resolveCommand: () => {
|
|
25
|
+
return { argsPrefix: [], command: "/usr/local/bin/codegraph", exists: true, source: "path" };
|
|
26
|
+
},
|
|
27
|
+
ensureProvisioned: () => {
|
|
28
|
+
throw new Error("ensureProvisioned should not run on unsupported Node");
|
|
29
|
+
},
|
|
30
|
+
prepareWorkspace: () => {
|
|
31
|
+
throw new Error("prepareWorkspace should not run on unsupported Node");
|
|
32
|
+
},
|
|
33
|
+
runCommand: () => {
|
|
34
|
+
throw new Error("runCommand should not run on unsupported Node");
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// then
|
|
40
|
+
expect(result).toEqual({ action: "skipped-unsupported-node" });
|
|
41
|
+
expect(existsSync(join(workspace, ".codegraph"))).toBe(false);
|
|
42
|
+
expect(outcomes).toEqual([{ action: "skipped-unsupported-node", projectRoot: workspace }]);
|
|
43
|
+
} finally {
|
|
44
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
45
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("#given an unsupported local Node and a PATH CodeGraph command #when auto provisioning succeeds #then it bootstraps with the provisioned binary", async () => {
|
|
50
|
+
// given
|
|
51
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-provision-"));
|
|
52
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-provision-home-"));
|
|
53
|
+
const binPath = join(homeDir, ".omo", "codegraph", "bin", "codegraph");
|
|
54
|
+
const calls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
55
|
+
const outcomes: unknown[] = [];
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// when
|
|
59
|
+
const result = await runCodegraphSessionStartWorker({
|
|
60
|
+
cwd: workspace,
|
|
61
|
+
env: { HOME: homeDir },
|
|
62
|
+
nodeVersion: "26.3.0",
|
|
63
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
64
|
+
deps: {
|
|
65
|
+
ensureGitignored: () => true,
|
|
66
|
+
ensureProvisioned: () => Promise.resolve({ binPath, provisioned: true }),
|
|
67
|
+
prepareWorkspace: () => ({
|
|
68
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
69
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
70
|
+
linked: true,
|
|
71
|
+
mode: "global-linked",
|
|
72
|
+
projectLink: join(workspace, ".codegraph"),
|
|
73
|
+
}),
|
|
74
|
+
resolveCommand: () => ({ argsPrefix: [], command: "/usr/local/bin/codegraph", exists: true, source: "path" }),
|
|
75
|
+
runCommand: (_projectRoot, command, args) => {
|
|
76
|
+
calls.push({ args, command });
|
|
77
|
+
return Promise.resolve({ exitCode: 0, stdout: calls.length === 1 ? '{"initialized":false}' : "", timedOut: false });
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// then
|
|
83
|
+
expect(result).toEqual({ action: "initialized" });
|
|
84
|
+
expect(calls).toEqual([
|
|
85
|
+
{ args: ["status", "--json"], command: binPath },
|
|
86
|
+
{ args: ["init"], command: binPath },
|
|
87
|
+
]);
|
|
88
|
+
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
|
|
89
|
+
} finally {
|
|
90
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
91
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("#given an unsupported local Node but bundled CodeGraph resolves through CODEGRAPH_NODE_BIN #when worker runs #then it bootstraps with the compatible runtime", async () => {
|
|
96
|
+
// given
|
|
97
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-compatible-node-"));
|
|
98
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-compatible-node-home-"));
|
|
99
|
+
const nodeBin = "/opt/node22/bin/node";
|
|
100
|
+
const calls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
101
|
+
const outcomes: unknown[] = [];
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
// when
|
|
105
|
+
const result = await runCodegraphSessionStartWorker({
|
|
106
|
+
cwd: workspace,
|
|
107
|
+
env: { CODEGRAPH_NODE_BIN: nodeBin, HOME: homeDir },
|
|
108
|
+
nodeVersion: "26.3.0",
|
|
109
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
110
|
+
deps: {
|
|
111
|
+
ensureGitignored: () => true,
|
|
112
|
+
ensureProvisioned: () => {
|
|
113
|
+
throw new Error("provisioning should not run when bundled CodeGraph resolved");
|
|
114
|
+
},
|
|
115
|
+
prepareWorkspace: () => ({
|
|
116
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
117
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
118
|
+
linked: true,
|
|
119
|
+
mode: "global-linked",
|
|
120
|
+
projectLink: join(workspace, ".codegraph"),
|
|
121
|
+
}),
|
|
122
|
+
resolveCommand: () => ({ argsPrefix: ["codegraph.js"], command: nodeBin, exists: true, source: "bundled" }),
|
|
123
|
+
runCommand: (_projectRoot, command, args) => {
|
|
124
|
+
calls.push({ args, command });
|
|
125
|
+
return Promise.resolve({ exitCode: 0, stdout: calls.length === 1 ? '{"initialized":false}' : "", timedOut: false });
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// then
|
|
131
|
+
expect(result).toEqual({ action: "initialized" });
|
|
132
|
+
expect(calls).toEqual([
|
|
133
|
+
{ args: ["codegraph.js", "status", "--json"], command: nodeBin },
|
|
134
|
+
{ args: ["codegraph.js", "init"], command: nodeBin },
|
|
135
|
+
]);
|
|
136
|
+
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "bundled", timedOut: false }]);
|
|
137
|
+
} finally {
|
|
138
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
139
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|