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.
Files changed (170) hide show
  1. package/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
  2. package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
  3. package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
  4. package/.agents/skills/work-with-pr/SKILL.md +19 -5
  5. package/.opencode/skills/work-with-pr/SKILL.md +19 -5
  6. package/dist/agents/types.d.ts +7 -6
  7. package/dist/cli/index.js +460 -309
  8. package/dist/cli-node/index.js +460 -309
  9. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
  10. package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
  11. package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
  12. package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
  13. package/dist/index.js +593 -310
  14. package/dist/plugin/tool-execute-before.d.ts +2 -0
  15. package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
  16. package/dist/skills/ultraresearch/SKILL.md +11 -2
  17. package/dist/skills/ulw-plan/SKILL.md +2 -1
  18. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  19. package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
  20. package/dist/tools/background-task/constants.d.ts +1 -1
  21. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
  22. package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
  23. package/dist/tui.js +25 -10
  24. package/package.json +13 -13
  25. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
  26. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
  27. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +336 -173
  30. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
  31. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
  33. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
  34. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
  35. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
  36. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
  37. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
  38. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
  39. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
  40. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
  41. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
  42. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
  43. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
  46. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  47. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  49. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  51. package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
  52. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
  53. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  54. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
  56. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
  57. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  58. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
  59. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
  60. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
  61. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
  62. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
  63. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
  64. package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
  65. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
  66. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
  67. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
  68. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
  69. package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
  70. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
  71. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
  72. package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
  73. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  74. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  75. package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
  76. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  77. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  78. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  79. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
  82. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
  83. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  84. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  85. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
  86. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
  87. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
  88. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
  89. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
  90. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
  91. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
  92. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
  93. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
  94. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
  95. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
  96. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
  97. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
  98. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
  99. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
  100. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
  101. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
  102. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
  103. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
  104. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
  105. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
  106. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
  107. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
  108. package/packages/omo-codex/plugin/package-lock.json +30 -22
  109. package/packages/omo-codex/plugin/package.json +2 -1
  110. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
  111. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
  112. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
  113. package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
  114. package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
  115. package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
  116. package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
  117. package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
  118. package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
  119. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  120. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  121. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  122. package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
  123. package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
  124. package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
  125. package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
  126. package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
  127. package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
  128. package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
  129. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
  130. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
  131. package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
  132. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
  133. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
  134. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
  135. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
  136. package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
  137. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
  138. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  139. package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
  140. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  141. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
  142. package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
  143. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
  144. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
  145. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
  146. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
  147. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
  148. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
  149. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
  150. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
  151. package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
  152. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
  153. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
  154. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
  155. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  156. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
  157. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
  158. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
  159. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
  160. package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
  161. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
  162. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
  163. package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
  164. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
  165. package/packages/omo-codex/scripts/install-local.mjs +1 -0
  166. package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
  167. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  168. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  169. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
  170. 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
- const resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
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
- (options.stderr ?? processStderr).write(CODEGRAPH_SKIP_HINT);
87
- return 1;
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
- const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
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 (!nodeSupport.supported) return { kind: "unsupported-node" };
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 hooksConfigPath = resolve(pluginRoot, "hooks/hooks.json");
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 hooksConfig = JSON.parse(readFileSync(hooksConfigPath, "utf8"));
502
+ const pluginConfig: unknown = JSON.parse(readFileSync(pluginConfigPath, "utf8"));
541
503
 
542
504
  // when
543
- const sessionStartHooks = hooksConfig.hooks.SessionStart;
544
- const commands = sessionStartHooks.map((entry: { readonly hooks: readonly [{ readonly command: string }] }) => {
545
- return entry.hooks[0].command;
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(commands).toContain('node "${PLUGIN_ROOT}/components/codegraph/dist/cli.js" hook session-start');
550
- expect(commands.indexOf('node "${PLUGIN_ROOT}/components/bootstrap/dist/cli.js" hook session-start')).toBeLessThan(
551
- commands.indexOf('node "${PLUGIN_ROOT}/components/codegraph/dist/cli.js" hook session-start'),
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" }),
@@ -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
+ });
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 30,
11
- "statusMessage": "LazyCodex(4.11.1): Checking Comments"
11
+ "statusMessage": "(OmO) Checking Comments"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-comment-checker",
3
- "version": "4.11.1",
3
+ "version": "4.12.1",
4
4
  "description": "Codex plugin that runs comment-checker after edit-like PostToolUse hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",