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
@@ -8,13 +8,205 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
8
8
 
9
9
  // components/codegraph/src/hook.ts
10
10
  import { spawn } from "node:child_process";
11
- import { homedir as homedir7 } from "node:os";
11
+ import { homedir as homedir8 } from "node:os";
12
12
  import { cwd as processCwd2, env as processEnv2, stdin as processStdin, stdout as processStdout } from "node:process";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
15
- // ../../utils/src/omo-config/loader.ts
16
- import { existsSync as existsSync2, readFileSync } from "node:fs";
15
+ // ../../utils/src/codegraph/guidance.ts
16
+ import { homedir as homedir2 } from "node:os";
17
+
18
+ // ../../utils/src/codegraph/workspace.ts
19
+ import { createHash } from "node:crypto";
20
+ import {
21
+ appendFileSync,
22
+ existsSync,
23
+ lstatSync,
24
+ mkdirSync,
25
+ readFileSync,
26
+ readdirSync,
27
+ realpathSync,
28
+ rmSync,
29
+ statSync,
30
+ symlinkSync
31
+ } from "node:fs";
17
32
  import { homedir } from "node:os";
33
+ import { basename, join, resolve } from "node:path";
34
+ function sanitizeBase(value) {
35
+ const sanitized = value.replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-");
36
+ return sanitized.length > 0 ? sanitized : "workspace";
37
+ }
38
+ function codegraphDataRoot(homeDir) {
39
+ return join(homeDir, ".omo", "codegraph");
40
+ }
41
+ function workspaceStorageName(workspace) {
42
+ const resolved = resolve(workspace);
43
+ const hash = createHash("sha256").update(resolved).digest("hex").slice(0, 16);
44
+ return `${sanitizeBase(basename(resolved))}-${hash}`;
45
+ }
46
+ function resolveCodegraphWorkspacePaths(workspace, options = {}) {
47
+ const resolvedWorkspace = resolve(workspace);
48
+ const dataRoot = codegraphDataRoot(options.homeDir ?? homedir());
49
+ return {
50
+ dataDir: join(dataRoot, "projects", workspaceStorageName(resolvedWorkspace)),
51
+ dataRoot,
52
+ projectLink: join(resolvedWorkspace, ".codegraph")
53
+ };
54
+ }
55
+ function fallbackResult(dataRoot, projectLink, reason) {
56
+ return { dataDir: projectLink, dataRoot, linked: false, mode: "in-place-fallback", projectLink, reason };
57
+ }
58
+ function isSameFilesystem(workspace, dataRoot, override) {
59
+ if (override !== undefined)
60
+ return override;
61
+ return statSync(workspace).dev === statSync(dataRoot).dev;
62
+ }
63
+ function ensureInPlaceFallback(projectLink) {
64
+ if (!existsSync(projectLink))
65
+ mkdirSync(projectLink, { recursive: true });
66
+ }
67
+ function prepareCodegraphWorkspace(workspace, options = {}) {
68
+ const resolvedWorkspace = resolve(workspace);
69
+ const { dataDir, dataRoot, projectLink } = resolveCodegraphWorkspacePaths(resolvedWorkspace, options);
70
+ try {
71
+ mkdirSync(dataDir, { recursive: true });
72
+ if (existsSync(projectLink)) {
73
+ const linkStat = lstatSync(projectLink);
74
+ if (!linkStat.isSymbolicLink()) {
75
+ return { dataDir: projectLink, dataRoot, linked: false, mode: "in-project", projectLink };
76
+ }
77
+ if (realpathSync(projectLink) === realpathSync(dataDir)) {
78
+ return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
79
+ }
80
+ return fallbackResult(dataRoot, projectLink, "existing .codegraph symlink points outside OMO store");
81
+ }
82
+ if (!isSameFilesystem(resolvedWorkspace, dataRoot, options.sameFilesystem)) {
83
+ ensureInPlaceFallback(projectLink);
84
+ return fallbackResult(dataRoot, projectLink, "workspace and OMO store are on different filesystems");
85
+ }
86
+ const symlink = options.symlink ?? symlinkSync;
87
+ symlink(dataDir, projectLink, (options.platform ?? process.platform) === "win32" ? "junction" : "dir");
88
+ return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
89
+ } catch (error) {
90
+ const reason = error instanceof Error ? error.message : String(error);
91
+ try {
92
+ ensureInPlaceFallback(projectLink);
93
+ } catch (fallbackError) {
94
+ return fallbackResult(dataRoot, projectLink, `${reason}; fallback failed: ${String(fallbackError)}`);
95
+ }
96
+ return fallbackResult(dataRoot, projectLink, reason);
97
+ }
98
+ }
99
+ function ensureCodegraphGitignored(workspace) {
100
+ const gitDir = join(workspace, ".git");
101
+ if (!existsSync(gitDir))
102
+ return false;
103
+ const excludePath = join(gitDir, "info", "exclude");
104
+ try {
105
+ mkdirSync(join(gitDir, "info"), { recursive: true });
106
+ const existing = existsSync(excludePath) ? readFileSync(excludePath, "utf8") : "";
107
+ if (existing.split(/\r?\n/).includes(".codegraph"))
108
+ return true;
109
+ appendFileSync(excludePath, `${existing.endsWith(`
110
+ `) || existing.length === 0 ? "" : `
111
+ `}.codegraph
112
+ `);
113
+ return true;
114
+ } catch (error) {
115
+ if (error instanceof Error)
116
+ return false;
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ // ../../utils/src/codegraph/guidance.ts
122
+ var CODEGRAPH_UNINITIALIZED_PATTERN = /CodeGraph not initialized in ([\s\S]*?)\.\s*Run ['`]codegraph init['`] in that project first\./i;
123
+ var ANSI_ESCAPE_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
124
+ var CODEGRAPH_STATUS_PROJECT_PATTERN = /^.*?\bProject:\s*(.+?)\s*$/im;
125
+ var CODEGRAPH_STATUS_UNINITIALIZED_PATTERN = /^.*?\bNot initialized\s*$/im;
126
+ var CODEGRAPH_INIT_HINT_PATTERN = /Run\s+["'`]codegraph init["'`]\s+(?:in that project first|to initialize)\.?/i;
127
+ function getCodegraphUninitializedProject(input) {
128
+ const output = textFromUnknown(input.toolOutput);
129
+ if (!isCodegraphTool(input.toolName))
130
+ return null;
131
+ const projectPath = extractProjectPath(output);
132
+ if (projectPath !== null)
133
+ return projectPath;
134
+ if (!looksLikeCodegraphUninitializedOutput(output))
135
+ return null;
136
+ return typeof input.cwd === "string" && input.cwd.trim().length > 0 ? input.cwd.trim() : null;
137
+ }
138
+ function buildCodegraphInitGuidance(projectPath, options = {}) {
139
+ const { dataDir, dataRoot, projectLink } = resolveCodegraphWorkspacePaths(projectPath, {
140
+ homeDir: options.homeDir ?? homedir2()
141
+ });
142
+ const displayProjectPath = formatDisplayPath(projectPath);
143
+ const displayProjectLink = formatDisplayPath(projectLink);
144
+ const displayDataDir = formatDisplayPath(dataDir);
145
+ const displayDataRoot = formatDisplayPath(dataRoot);
146
+ return [
147
+ "OMO CodeGraph initialization guidance:",
148
+ "",
149
+ `CodeGraph is not initialized for ${displayProjectPath}. Initialize it through OMO's global local store instead of leaving a standalone project-local index.`,
150
+ "",
151
+ `- Link or create ${displayProjectLink} so it points at ${displayDataDir} under the OMO store ${displayDataRoot}.`,
152
+ `- Then run \`codegraph init\` from ${displayProjectPath} and retry the CodeGraph tool.`,
153
+ "- OMO's CodeGraph bootstrap does this automatically on session start; if bootstrap just ran, wait for it to finish and retry."
154
+ ].join(`
155
+ `);
156
+ }
157
+ function buildCodegraphInitGuidanceForToolResult(input, options = {}) {
158
+ const projectPath = getCodegraphUninitializedProject(input);
159
+ return projectPath === null ? null : buildCodegraphInitGuidance(projectPath, options);
160
+ }
161
+ function extractProjectPath(output) {
162
+ const normalizedOutput = normalizeCodegraphOutput(output);
163
+ const uninitializedMatch = normalizedOutput.match(CODEGRAPH_UNINITIALIZED_PATTERN);
164
+ const uninitializedProject = uninitializedMatch?.[1]?.trim();
165
+ if (uninitializedProject && uninitializedProject.length > 0)
166
+ return uninitializedProject;
167
+ if (!looksLikeCodegraphUninitializedOutput(normalizedOutput))
168
+ return null;
169
+ const statusMatch = normalizedOutput.match(CODEGRAPH_STATUS_PROJECT_PATTERN);
170
+ const statusProject = statusMatch?.[1]?.trim();
171
+ return statusProject && statusProject.length > 0 ? statusProject : null;
172
+ }
173
+ function looksLikeCodegraphUninitializedOutput(output) {
174
+ const normalizedOutput = normalizeCodegraphOutput(output);
175
+ if (normalizedOutput.match(CODEGRAPH_UNINITIALIZED_PATTERN) !== null)
176
+ return true;
177
+ return CODEGRAPH_STATUS_UNINITIALIZED_PATTERN.test(normalizedOutput) && CODEGRAPH_INIT_HINT_PATTERN.test(normalizedOutput);
178
+ }
179
+ function normalizeCodegraphOutput(output) {
180
+ return output.replace(ANSI_ESCAPE_PATTERN, "");
181
+ }
182
+ function isCodegraphTool(toolName) {
183
+ if (typeof toolName !== "string")
184
+ return false;
185
+ return toolName.startsWith("codegraph.") || toolName.startsWith("codegraph_") || toolName.startsWith("mcp__codegraph__");
186
+ }
187
+ function formatDisplayPath(value) {
188
+ return JSON.stringify(value);
189
+ }
190
+ function textFromUnknown(value) {
191
+ if (typeof value === "string")
192
+ return value;
193
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
194
+ return String(value);
195
+ if (Array.isArray(value))
196
+ return value.map(textFromUnknown).filter(Boolean).join(`
197
+ `);
198
+ if (!isRecord(value))
199
+ return "";
200
+ return Object.entries(value).map(([key, nested]) => `${key}: ${textFromUnknown(nested)}`).filter((line) => line.trim().length > 0).join(`
201
+ `);
202
+ }
203
+ function isRecord(value) {
204
+ return typeof value === "object" && value !== null && !Array.isArray(value);
205
+ }
206
+
207
+ // ../../utils/src/omo-config/loader.ts
208
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
209
+ import { homedir as homedir3 } from "node:os";
18
210
 
19
211
  // ../../utils/src/deep-merge.ts
20
212
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
@@ -970,22 +1162,22 @@ function buildEnvOverrides(harness, env, warnings, merge) {
970
1162
  }
971
1163
 
972
1164
  // ../../utils/src/omo-config/resolve.ts
973
- import { existsSync } from "node:fs";
974
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
1165
+ import { existsSync as existsSync2 } from "node:fs";
1166
+ import { dirname, isAbsolute, join as join2, relative, resolve as resolve2 } from "node:path";
975
1167
  function containsPath(parent, child) {
976
1168
  const pathToChild = relative(parent, child);
977
1169
  return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute(pathToChild);
978
1170
  }
979
1171
  function findProjectConfigPathsNearestFirst(cwd, homeDir) {
980
- const startDir = resolve(cwd);
981
- const stopBeforeDir = containsPath(resolve(homeDir), startDir) ? resolve(homeDir) : null;
1172
+ const startDir = resolve2(cwd);
1173
+ const stopBeforeDir = containsPath(resolve2(homeDir), startDir) ? resolve2(homeDir) : null;
982
1174
  const paths = [];
983
1175
  let currentDir = startDir;
984
1176
  while (true) {
985
1177
  if (stopBeforeDir !== null && currentDir === stopBeforeDir)
986
1178
  break;
987
- const configPath = join(currentDir, ".omo", "config.jsonc");
988
- if (existsSync(configPath)) {
1179
+ const configPath = join2(currentDir, ".omo", "config.jsonc");
1180
+ if (existsSync2(configPath)) {
989
1181
  paths.push(configPath);
990
1182
  }
991
1183
  const parentDir = dirname(currentDir);
@@ -996,7 +1188,7 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
996
1188
  return paths;
997
1189
  }
998
1190
  function resolveOmoConfigPaths(options) {
999
- const globalPath = join(resolve(options.homeDir), ".omo", "config.jsonc");
1191
+ const globalPath = join2(resolve2(options.homeDir), ".omo", "config.jsonc");
1000
1192
  const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
1001
1193
  return [
1002
1194
  { path: globalPath, scope: "global" },
@@ -1028,7 +1220,7 @@ var CODEGRAPH_SETTING_KEYS = [
1028
1220
  "telemetry",
1029
1221
  "watch_debounce_ms"
1030
1222
  ];
1031
- function isRecord(value) {
1223
+ function isRecord2(value) {
1032
1224
  return isPlainObject(value);
1033
1225
  }
1034
1226
  function hasOwn(record, key) {
@@ -1056,7 +1248,7 @@ function mergeValues(base, override) {
1056
1248
  }
1057
1249
  function mergeCodegraphConfig(base, override) {
1058
1250
  const merged = mergeValues(base, override);
1059
- if (!isRecord(merged))
1251
+ if (!isRecord2(merged))
1060
1252
  return;
1061
1253
  const codegraph = {};
1062
1254
  for (const key of CODEGRAPH_SETTING_KEYS) {
@@ -1111,7 +1303,7 @@ function setCodegraphSetting2(config, key, value) {
1111
1303
  }
1112
1304
  }
1113
1305
  function normalizeCodegraphSection(section, pathPrefix, warnings) {
1114
- if (!isRecord(section)) {
1306
+ if (!isRecord2(section)) {
1115
1307
  warnings.push(`${pathPrefix} must be an object`);
1116
1308
  return {};
1117
1309
  }
@@ -1131,7 +1323,7 @@ function normalizeCodegraphSection(section, pathPrefix, warnings) {
1131
1323
  return codegraph;
1132
1324
  }
1133
1325
  function normalizeConfigBody(value, pathPrefix, warnings) {
1134
- if (!isRecord(value)) {
1326
+ if (!isRecord2(value)) {
1135
1327
  warnings.push(`${pathPrefix} must be an object`);
1136
1328
  return {};
1137
1329
  }
@@ -1152,7 +1344,7 @@ function normalizeConfigBody(value, pathPrefix, warnings) {
1152
1344
  return config;
1153
1345
  }
1154
1346
  function normalizeActiveHarnessBlock(value, harness, pathPrefix, warnings) {
1155
- if (!isRecord(value))
1347
+ if (!isRecord2(value))
1156
1348
  return {};
1157
1349
  const blockKey = `[${harness}]`;
1158
1350
  if (!hasOwn(value, blockKey))
@@ -1161,7 +1353,7 @@ function normalizeActiveHarnessBlock(value, harness, pathPrefix, warnings) {
1161
1353
  }
1162
1354
  function loadConfigFile(path, harness) {
1163
1355
  try {
1164
- const content = readFileSync(path, "utf-8");
1356
+ const content = readFileSync2(path, "utf-8");
1165
1357
  const parsed = parseJsoncSafe(content);
1166
1358
  if (parsed.errors.length > 0) {
1167
1359
  return {
@@ -1207,13 +1399,13 @@ function validateHarnessApplicability(config, harness) {
1207
1399
  }
1208
1400
  function loadOmoConfig(options) {
1209
1401
  const cwd = options.cwd ?? process.cwd();
1210
- const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir();
1402
+ const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir3();
1211
1403
  const env = options.env ?? process.env;
1212
1404
  let config = BUILT_IN_DEFAULTS;
1213
1405
  const sources = [];
1214
1406
  const warnings = [];
1215
1407
  for (const candidate of resolveOmoConfigPaths({ cwd, homeDir })) {
1216
- if (!existsSync2(candidate.path)) {
1408
+ if (!existsSync3(candidate.path)) {
1217
1409
  if (candidate.scope === "global") {
1218
1410
  sources.push(toMissingSource(candidate));
1219
1411
  }
@@ -1253,21 +1445,21 @@ function getCodexOmoConfig(options = {}) {
1253
1445
  // components/codegraph/src/session-start-worker.ts
1254
1446
  import { execFile as execFile2 } from "node:child_process";
1255
1447
  import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "node:fs";
1256
- import { homedir as homedir6 } from "node:os";
1448
+ import { homedir as homedir7 } from "node:os";
1257
1449
  import { extname, join as join7 } from "node:path";
1258
1450
  import { cwd as processCwd, env as processEnv, stderr as processStderr } from "node:process";
1259
1451
 
1260
1452
  // ../../utils/src/codegraph/env.ts
1261
- import { homedir as homedir2 } from "node:os";
1262
- import { join as join2 } from "node:path";
1453
+ import { homedir as homedir4 } from "node:os";
1454
+ import { join as join3 } from "node:path";
1263
1455
  var CODEGRAPH_INSTALL_DIR_ENV = "CODEGRAPH_INSTALL_DIR";
1264
1456
  var CODEGRAPH_NO_DOWNLOAD_ENV = "CODEGRAPH_NO_DOWNLOAD";
1265
1457
  var CODEGRAPH_TELEMETRY_ENV = "CODEGRAPH_TELEMETRY";
1266
1458
  var DO_NOT_TRACK_ENV = "DO_NOT_TRACK";
1267
1459
  function buildCodegraphEnv(options = {}) {
1268
- const homeDir = options.homeDir ?? homedir2();
1460
+ const homeDir = options.homeDir ?? homedir4();
1269
1461
  return {
1270
- [CODEGRAPH_INSTALL_DIR_ENV]: join2(homeDir, ".omo", "codegraph"),
1462
+ [CODEGRAPH_INSTALL_DIR_ENV]: join3(homeDir, ".omo", "codegraph"),
1271
1463
  [CODEGRAPH_NO_DOWNLOAD_ENV]: "1",
1272
1464
  [CODEGRAPH_TELEMETRY_ENV]: "0",
1273
1465
  [DO_NOT_TRACK_ENV]: "1"
@@ -1304,12 +1496,12 @@ function parseNodeMajor(version) {
1304
1496
  }
1305
1497
 
1306
1498
  // ../../utils/src/codegraph/provision.ts
1307
- import { createHash, randomUUID } from "node:crypto";
1499
+ import { createHash as createHash2, randomUUID } from "node:crypto";
1308
1500
  import { execFile } from "node:child_process";
1309
1501
  import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
1310
- import { existsSync as existsSync3 } from "node:fs";
1311
- import { homedir as homedir3, hostname } from "node:os";
1312
- import { basename, join as join3 } from "node:path";
1502
+ import { existsSync as existsSync4 } from "node:fs";
1503
+ import { homedir as homedir5, hostname } from "node:os";
1504
+ import { basename as basename2, join as join4 } from "node:path";
1313
1505
  import { promisify } from "node:util";
1314
1506
 
1315
1507
  // ../../utils/src/codegraph/manifest.ts
@@ -1358,13 +1550,13 @@ function platformKey() {
1358
1550
  return `${process.platform}-${process.arch}`;
1359
1551
  }
1360
1552
  function markerPath(installDir, version) {
1361
- return join3(installDir, ".provisioned", `codegraph-${version}.json`);
1553
+ return join4(installDir, ".provisioned", `codegraph-${version}.json`);
1362
1554
  }
1363
1555
  function defaultInstallDir() {
1364
- return join3(homedir3(), ".omo", "codegraph");
1556
+ return join4(homedir5(), ".omo", "codegraph");
1365
1557
  }
1366
1558
  function sha256(bytes) {
1367
- return createHash("sha256").update(bytes).digest("hex");
1559
+ return createHash2("sha256").update(bytes).digest("hex");
1368
1560
  }
1369
1561
  function isErrnoException(error) {
1370
1562
  return error instanceof Error && "code" in error;
@@ -1381,7 +1573,7 @@ async function removeEmptyDirectory(path) {
1381
1573
  }
1382
1574
  }
1383
1575
  function sleep(ms) {
1384
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1576
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
1385
1577
  }
1386
1578
  async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
1387
1579
  const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
@@ -1395,7 +1587,7 @@ function forcedBadChecksumOptions(options) {
1395
1587
  const key = options.platformKey ?? platformKey();
1396
1588
  return {
1397
1589
  downloader: async () => new TextEncoder().encode("checksum mismatch"),
1398
- installDir: options.installDir ?? join3(options.lockDir, "codegraph-force-bad-checksum"),
1590
+ installDir: options.installDir ?? join4(options.lockDir, "codegraph-force-bad-checksum"),
1399
1591
  manifest: {
1400
1592
  assets: {
1401
1593
  [key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
@@ -1406,13 +1598,13 @@ function forcedBadChecksumOptions(options) {
1406
1598
  };
1407
1599
  }
1408
1600
  async function readMarker(path) {
1409
- if (!existsSync3(path))
1601
+ if (!existsSync4(path))
1410
1602
  return null;
1411
1603
  try {
1412
1604
  const raw = JSON.parse(await readFile(path, "utf8"));
1413
1605
  if (typeof raw === "object" && raw !== null && "binPath" in raw) {
1414
1606
  const value = raw.binPath;
1415
- return typeof value === "string" && existsSync3(value) ? value : null;
1607
+ return typeof value === "string" && existsSync4(value) ? value : null;
1416
1608
  }
1417
1609
  return null;
1418
1610
  } catch (error) {
@@ -1423,7 +1615,7 @@ async function readMarker(path) {
1423
1615
  }
1424
1616
  async function acquireLock(lockPath, waitMs, staleMs) {
1425
1617
  const startedAt = Date.now();
1426
- await mkdir(join3(lockPath, ".."), { recursive: true });
1618
+ await mkdir(join4(lockPath, ".."), { recursive: true });
1427
1619
  while (Date.now() - startedAt <= waitMs) {
1428
1620
  try {
1429
1621
  await mkdir(lockPath);
@@ -1448,44 +1640,44 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
1448
1640
  const roots = await readdir(extractDir);
1449
1641
  if (roots.length !== 1)
1450
1642
  throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
1451
- const bundleDir = join3(extractDir, roots[0] ?? "");
1643
+ const bundleDir = join4(extractDir, roots[0] ?? "");
1452
1644
  const bundleEntries = await readdir(bundleDir);
1453
1645
  await mkdir(installDir, { recursive: true });
1454
1646
  for (const entry of bundleEntries) {
1455
- await rm(join3(installDir, entry), { force: true, recursive: true });
1456
- await rename(join3(bundleDir, entry), join3(installDir, entry));
1647
+ await rm(join4(installDir, entry), { force: true, recursive: true });
1648
+ await rename(join4(bundleDir, entry), join4(installDir, entry));
1457
1649
  }
1458
- const destination = join3(installDir, "bin", executableName);
1459
- if (!existsSync3(destination))
1650
+ const destination = join4(installDir, "bin", executableName);
1651
+ if (!existsSync4(destination))
1460
1652
  throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
1461
1653
  await chmod(destination, 493);
1462
1654
  return destination;
1463
1655
  }
1464
1656
  async function installAsset(layout) {
1465
1657
  const { asset, downloader, installDir, version } = layout;
1466
- const stagingDir = join3(installDir, ".staging", randomUUID());
1467
- const archivePath = join3(stagingDir, basename(asset.url));
1468
- const extractDir = join3(stagingDir, "extract");
1658
+ const stagingDir = join4(installDir, ".staging", randomUUID());
1659
+ const archivePath = join4(stagingDir, basename2(asset.url));
1660
+ const extractDir = join4(stagingDir, "extract");
1469
1661
  try {
1470
1662
  await mkdir(extractDir, { recursive: true });
1471
1663
  const bytes = await downloader(asset);
1472
1664
  const actualChecksum = sha256(bytes);
1473
1665
  if (actualChecksum !== asset.sha256) {
1474
- throw new Error(`checksum mismatch for ${basename(asset.url)}: expected ${asset.sha256}, got ${actualChecksum}`);
1666
+ throw new Error(`checksum mismatch for ${basename2(asset.url)}: expected ${asset.sha256}, got ${actualChecksum}`);
1475
1667
  }
1476
1668
  if (!asset.url.endsWith(".tar.gz") && !asset.url.endsWith(".tgz")) {
1477
- throw new Error(`unsupported CodeGraph archive type for ${basename(asset.url)}`);
1669
+ throw new Error(`unsupported CodeGraph archive type for ${basename2(asset.url)}`);
1478
1670
  }
1479
1671
  await writeFile(archivePath, bytes);
1480
1672
  await extractTarGz(archivePath, extractDir);
1481
1673
  const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
1482
- await mkdir(join3(installDir, ".provisioned"), { recursive: true });
1674
+ await mkdir(join4(installDir, ".provisioned"), { recursive: true });
1483
1675
  await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
1484
1676
  `);
1485
1677
  return destination;
1486
1678
  } finally {
1487
1679
  await rm(stagingDir, { force: true, recursive: true });
1488
- await removeEmptyDirectory(join3(installDir, ".staging"));
1680
+ await removeEmptyDirectory(join4(installDir, ".staging"));
1489
1681
  }
1490
1682
  }
1491
1683
  async function ensureCodegraphProvisioned(options) {
@@ -1498,7 +1690,7 @@ async function ensureCodegraphProvisioned(options) {
1498
1690
  const existing = await readMarker(marker);
1499
1691
  if (existing !== null)
1500
1692
  return { binPath: existing, provisioned: true };
1501
- const lockPath = join3(options.lockDir, `codegraph-${hostname()}.lock`);
1693
+ const lockPath = join4(options.lockDir, `codegraph-${hostname()}.lock`);
1502
1694
  const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
1503
1695
  if (release === null)
1504
1696
  return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
@@ -1523,15 +1715,15 @@ async function ensureCodegraphProvisioned(options) {
1523
1715
  }
1524
1716
 
1525
1717
  // ../../utils/src/codegraph/resolve.ts
1526
- import { existsSync as existsSync4 } from "node:fs";
1527
- import { homedir as homedir4 } from "node:os";
1718
+ import { existsSync as existsSync5 } from "node:fs";
1719
+ import { homedir as homedir6 } from "node:os";
1528
1720
  import { spawnSync } from "node:child_process";
1529
- import { basename as basename2, dirname as dirname2, join as join5 } from "node:path";
1721
+ import { basename as basename3, dirname as dirname2, join as join6 } from "node:path";
1530
1722
  import { createRequire } from "node:module";
1531
1723
 
1532
1724
  // ../../utils/src/runtime/which.ts
1533
1725
  import { accessSync, constants } from "node:fs";
1534
- import { delimiter, join as join4 } from "node:path";
1726
+ import { delimiter, join as join5 } from "node:path";
1535
1727
  var runtime = globalThis;
1536
1728
  function isUnsafeCommandName(commandName) {
1537
1729
  if (commandName.includes("/") || commandName.includes("\\"))
@@ -1586,7 +1778,7 @@ function bunWhich(commandName) {
1586
1778
  return null;
1587
1779
  for (const pathEntry of pathEntries) {
1588
1780
  for (const candidateName of candidateNames) {
1589
- const candidatePath = join4(pathEntry, candidateName);
1781
+ const candidatePath = join5(pathEntry, candidateName);
1590
1782
  if (isExecutable(candidatePath))
1591
1783
  return candidatePath;
1592
1784
  }
@@ -1595,6 +1787,9 @@ function bunWhich(commandName) {
1595
1787
  }
1596
1788
 
1597
1789
  // ../../utils/src/codegraph/resolve.ts
1790
+ function codegraphCommandRequiresSupportedLocalNode(resolution) {
1791
+ return resolution.source !== "bundled" && resolution.source !== "env" && resolution.source !== "provisioned";
1792
+ }
1598
1793
  var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
1599
1794
  var CODEGRAPH_ENV_BIN = "OMO_CODEGRAPH_BIN";
1600
1795
  var CODEGRAPH_LEGACY_ENV_BIN = "CODEGRAPH_BIN";
@@ -1624,7 +1819,7 @@ ${result.stderr}`.trim().split(/\s+/)[0];
1624
1819
  }
1625
1820
  }
1626
1821
  function isNodeExecutableName(filePath) {
1627
- const executable = basename2(filePath).toLowerCase();
1822
+ const executable = basename3(filePath).toLowerCase();
1628
1823
  return executable === "node" || executable === "node.exe" || /^node\d+(\.exe)?$/.test(executable);
1629
1824
  }
1630
1825
  function looksLikePath(command) {
@@ -1664,8 +1859,8 @@ function defaultNodeRuntime(env, fileExists, which, nodeVersion) {
1664
1859
  function defaultProvisionedBin(homeDir, fileExists) {
1665
1860
  const binaryName = process.platform === "win32" ? "codegraph.cmd" : "codegraph";
1666
1861
  const candidates = [
1667
- join5(homeDir, ".omo", "codegraph", "bin", binaryName),
1668
- join5(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
1862
+ join6(homeDir, ".omo", "codegraph", "bin", binaryName),
1863
+ join6(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
1669
1864
  ];
1670
1865
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
1671
1866
  }
@@ -1673,7 +1868,7 @@ function resolveBundledShim(requireResolve, fileExists) {
1673
1868
  try {
1674
1869
  const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
1675
1870
  const packageRoot = dirname2(packageJson);
1676
- const candidates = [join5(packageRoot, "bin", "codegraph.js"), join5(packageRoot, "npm-shim.js")];
1871
+ const candidates = [join6(packageRoot, "bin", "codegraph.js"), join6(packageRoot, "npm-shim.js")];
1677
1872
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
1678
1873
  } catch (error) {
1679
1874
  if (error instanceof Error)
@@ -1689,7 +1884,7 @@ function resolveBundledShim(requireResolve, fileExists) {
1689
1884
  }
1690
1885
  function resolveCodegraphCommand(options = {}) {
1691
1886
  const env = options.env ?? process.env;
1692
- const fileExists = options.fileExists ?? existsSync4;
1887
+ const fileExists = options.fileExists ?? existsSync5;
1693
1888
  const configuredBin = env[CODEGRAPH_ENV_BIN]?.trim() || env[CODEGRAPH_LEGACY_ENV_BIN]?.trim();
1694
1889
  if (configuredBin !== undefined && configuredBin.length > 0) {
1695
1890
  return { argsPrefix: [], command: configuredBin, exists: fileExists(configuredBin), source: "env" };
@@ -1701,7 +1896,7 @@ function resolveCodegraphCommand(options = {}) {
1701
1896
  if (bundled !== null && runtime2 !== null) {
1702
1897
  return { argsPrefix: [bundled], command: runtime2, exists: true, source: "bundled" };
1703
1898
  }
1704
- const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir4(), fileExists);
1899
+ const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir6(), fileExists);
1705
1900
  if (provisioned !== null && fileExists(provisioned)) {
1706
1901
  return { argsPrefix: [], command: provisioned, exists: true, source: "provisioned" };
1707
1902
  }
@@ -1714,102 +1909,6 @@ function resolveCodegraphCommand(options = {}) {
1714
1909
  };
1715
1910
  }
1716
1911
 
1717
- // ../../utils/src/codegraph/workspace.ts
1718
- import { createHash as createHash2 } from "node:crypto";
1719
- import {
1720
- appendFileSync,
1721
- existsSync as existsSync5,
1722
- lstatSync,
1723
- mkdirSync,
1724
- readFileSync as readFileSync2,
1725
- readdirSync,
1726
- realpathSync,
1727
- rmSync,
1728
- statSync,
1729
- symlinkSync
1730
- } from "node:fs";
1731
- import { homedir as homedir5 } from "node:os";
1732
- import { basename as basename3, join as join6, resolve as resolve2 } from "node:path";
1733
- function sanitizeBase(value) {
1734
- const sanitized = value.replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-");
1735
- return sanitized.length > 0 ? sanitized : "workspace";
1736
- }
1737
- function codegraphDataRoot(homeDir) {
1738
- return join6(homeDir, ".omo", "codegraph");
1739
- }
1740
- function workspaceStorageName(workspace) {
1741
- const resolved = resolve2(workspace);
1742
- const hash = createHash2("sha256").update(resolved).digest("hex").slice(0, 16);
1743
- return `${sanitizeBase(basename3(resolved))}-${hash}`;
1744
- }
1745
- function fallbackResult(dataRoot, projectLink, reason) {
1746
- return { dataDir: projectLink, dataRoot, linked: false, mode: "in-place-fallback", projectLink, reason };
1747
- }
1748
- function isSameFilesystem(workspace, dataRoot, override) {
1749
- if (override !== undefined)
1750
- return override;
1751
- return statSync(workspace).dev === statSync(dataRoot).dev;
1752
- }
1753
- function ensureInPlaceFallback(projectLink) {
1754
- if (!existsSync5(projectLink))
1755
- mkdirSync(projectLink, { recursive: true });
1756
- }
1757
- function prepareCodegraphWorkspace(workspace, options = {}) {
1758
- const resolvedWorkspace = resolve2(workspace);
1759
- const dataRoot = codegraphDataRoot(options.homeDir ?? homedir5());
1760
- const dataDir = join6(dataRoot, "projects", workspaceStorageName(resolvedWorkspace));
1761
- const projectLink = join6(resolvedWorkspace, ".codegraph");
1762
- try {
1763
- mkdirSync(dataDir, { recursive: true });
1764
- if (existsSync5(projectLink)) {
1765
- const linkStat = lstatSync(projectLink);
1766
- if (!linkStat.isSymbolicLink()) {
1767
- return { dataDir: projectLink, dataRoot, linked: false, mode: "in-project", projectLink };
1768
- }
1769
- if (realpathSync(projectLink) === realpathSync(dataDir)) {
1770
- return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
1771
- }
1772
- return fallbackResult(dataRoot, projectLink, "existing .codegraph symlink points outside OMO store");
1773
- }
1774
- if (!isSameFilesystem(resolvedWorkspace, dataRoot, options.sameFilesystem)) {
1775
- ensureInPlaceFallback(projectLink);
1776
- return fallbackResult(dataRoot, projectLink, "workspace and OMO store are on different filesystems");
1777
- }
1778
- const symlink = options.symlink ?? symlinkSync;
1779
- symlink(dataDir, projectLink, (options.platform ?? process.platform) === "win32" ? "junction" : "dir");
1780
- return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
1781
- } catch (error) {
1782
- const reason = error instanceof Error ? error.message : String(error);
1783
- try {
1784
- ensureInPlaceFallback(projectLink);
1785
- } catch (fallbackError) {
1786
- return fallbackResult(dataRoot, projectLink, `${reason}; fallback failed: ${String(fallbackError)}`);
1787
- }
1788
- return fallbackResult(dataRoot, projectLink, reason);
1789
- }
1790
- }
1791
- function ensureCodegraphGitignored(workspace) {
1792
- const gitDir = join6(workspace, ".git");
1793
- if (!existsSync5(gitDir))
1794
- return false;
1795
- const excludePath = join6(gitDir, "info", "exclude");
1796
- try {
1797
- mkdirSync(join6(gitDir, "info"), { recursive: true });
1798
- const existing = existsSync5(excludePath) ? readFileSync2(excludePath, "utf8") : "";
1799
- if (existing.split(/\r?\n/).includes(".codegraph"))
1800
- return true;
1801
- appendFileSync(excludePath, `${existing.endsWith(`
1802
- `) || existing.length === 0 ? "" : `
1803
- `}.codegraph
1804
- `);
1805
- return true;
1806
- } catch (error) {
1807
- if (error instanceof Error)
1808
- return false;
1809
- throw error;
1810
- }
1811
- }
1812
-
1813
1912
  // components/codegraph/src/session-start-worker.ts
1814
1913
  var SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
1815
1914
  var CODEGRAPH_VERSION = "1.0.1";
@@ -1863,13 +1962,10 @@ function finish(action, detail, logOutcome) {
1863
1962
  }
1864
1963
  async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport) {
1865
1964
  const resolved = deps.resolveCommand({ env, homeDir, provisioned: () => provisionedBinFromInstallDir(config.install_dir) });
1866
- if (resolved.exists) {
1867
- if (resolved.source !== "bundled" && resolved.source !== "env" && !nodeSupport.supported) {
1868
- return { kind: "unsupported-node" };
1869
- }
1965
+ if (resolved.exists && canUseResolvedCommand(resolved, nodeSupport)) {
1870
1966
  return { kind: "resolved", resolution: resolved };
1871
1967
  }
1872
- if (!nodeSupport.supported)
1968
+ if (resolved.exists && config.auto_provision === false)
1873
1969
  return { kind: "unsupported-node" };
1874
1970
  if (config.auto_provision === false)
1875
1971
  return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
@@ -1880,6 +1976,9 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
1880
1976
  }
1881
1977
  return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
1882
1978
  }
1979
+ function canUseResolvedCommand(resolved, nodeSupport) {
1980
+ return !codegraphCommandRequiresSupportedLocalNode(resolved) || nodeSupport.supported;
1981
+ }
1883
1982
  function decideStartupAction(status) {
1884
1983
  if (status.timedOut)
1885
1984
  return { kind: "skip", reason: "status timed out" };
@@ -1897,7 +1996,7 @@ ${status.stderr ?? ""}`.toLowerCase();
1897
1996
  return { kind: "sync" };
1898
1997
  }
1899
1998
  function jsonSaysInitialized(value) {
1900
- if (!isRecord2(value))
1999
+ if (!isRecord3(value))
1901
2000
  return;
1902
2001
  const initialized = value["initialized"] ?? value["isInitialized"] ?? value["ready"];
1903
2002
  if (typeof initialized === "boolean")
@@ -1963,7 +2062,7 @@ function toOutputText(value) {
1963
2062
  return Buffer.isBuffer(value) ? value.toString("utf8") : value;
1964
2063
  }
1965
2064
  function resolveHomeDir(env) {
1966
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir6();
2065
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir7();
1967
2066
  }
1968
2067
  function parseJson(text) {
1969
2068
  try {
@@ -1974,7 +2073,7 @@ function parseJson(text) {
1974
2073
  throw error;
1975
2074
  }
1976
2075
  }
1977
- function isRecord2(value) {
2076
+ function isRecord3(value) {
1978
2077
  return typeof value === "object" && value !== null;
1979
2078
  }
1980
2079
 
@@ -1983,6 +2082,9 @@ var CODEGRAPH_SESSION_START_NOTICE = "LazyCodex CodeGraph bootstrap scheduled in
1983
2082
  async function runCodegraphSessionStartHook(options = {}) {
1984
2083
  return (await executeCodegraphSessionStartHook(options)).exitCode;
1985
2084
  }
2085
+ async function runCodegraphPostToolUseHookCli(options = {}) {
2086
+ return (await executeCodegraphPostToolUseHook(options)).exitCode;
2087
+ }
1986
2088
  async function executeCodegraphSessionStartHook(options = {}) {
1987
2089
  const env = options.env ?? processEnv2;
1988
2090
  const input = await readHookInput(options.stdin ?? processStdin);
@@ -2000,6 +2102,30 @@ async function executeCodegraphSessionStartHook(options = {}) {
2000
2102
  writeHookJson(options.stdout ?? processStdout);
2001
2103
  return { action: "spawned", exitCode: 0 };
2002
2104
  }
2105
+ async function executeCodegraphPostToolUseHook(options = {}) {
2106
+ const env = options.env ?? processEnv2;
2107
+ const input = await readHookInput(options.stdin ?? processStdin);
2108
+ const output = runCodegraphPostToolUseHook(input, { homeDir: resolveHomeDir2(env) });
2109
+ if (output.length === 0)
2110
+ return { action: "skipped", exitCode: 0 };
2111
+ (options.stdout ?? processStdout).write(output);
2112
+ return { action: "emitted-guidance", exitCode: 0 };
2113
+ }
2114
+ function runCodegraphPostToolUseHook(input, options = {}) {
2115
+ const toolName = isRecord4(input) ? input["tool_name"] : undefined;
2116
+ const cwd = isRecord4(input) ? input["cwd"] : undefined;
2117
+ const toolOutput = isRecord4(input) ? input["tool_response"] ?? input["tool_output"] ?? input["response"] : input;
2118
+ const guidance = buildCodegraphInitGuidanceForToolResult({ cwd, toolName, toolOutput }, options);
2119
+ if (guidance === null)
2120
+ return "";
2121
+ return `${JSON.stringify({
2122
+ hookSpecificOutput: {
2123
+ hookEventName: "PostToolUse",
2124
+ additionalContext: guidance
2125
+ }
2126
+ })}
2127
+ `;
2128
+ }
2003
2129
  function writeHookJson(stdout) {
2004
2130
  const output = {
2005
2131
  hookSpecificOutput: {
@@ -2015,10 +2141,10 @@ function spawnDetachedWorker(invocation) {
2015
2141
  child.unref();
2016
2142
  }
2017
2143
  function resolveHomeDir2(env) {
2018
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir7();
2144
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir8();
2019
2145
  }
2020
2146
  function resolveProjectRoot(input, fallback) {
2021
- if (!isRecord3(input))
2147
+ if (!isRecord4(input))
2022
2148
  return fallback;
2023
2149
  const cwd = input["cwd"];
2024
2150
  return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : fallback;
@@ -2042,7 +2168,7 @@ function parseJson2(text) {
2042
2168
  throw error;
2043
2169
  }
2044
2170
  }
2045
- function isRecord3(value) {
2171
+ function isRecord4(value) {
2046
2172
  return typeof value === "object" && value !== null;
2047
2173
  }
2048
2174
  function defaultWorkerCliPath() {
@@ -2052,7 +2178,7 @@ function defaultWorkerCliPath() {
2052
2178
  // components/codegraph/src/serve.ts
2053
2179
  import { spawn as spawn2 } from "node:child_process";
2054
2180
  import { existsSync as existsSync7, realpathSync as realpathSync2 } from "node:fs";
2055
- import { homedir as homedir8 } from "node:os";
2181
+ import { homedir as homedir9 } from "node:os";
2056
2182
  import { basename as basename4, extname as extname2, join as join8, resolve as resolve3 } from "node:path";
2057
2183
  import {
2058
2184
  cwd as processCwd3,
@@ -2065,11 +2191,12 @@ var CODEGRAPH_SKIP_HINT = `CodeGraph MCP skipped: codegraph binary not found. In
2065
2191
  `;
2066
2192
  var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.
2067
2193
  `;
2194
+ var CODEGRAPH_VERSION2 = "1.0.1";
2068
2195
  var WINDOWS_CMD_EXTENSIONS2 = new Set([".bat", ".cmd"]);
2069
2196
  var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
2070
2197
  async function runCodegraphServe(options = {}) {
2071
2198
  const env = options.env ?? processEnv3;
2072
- const homeDir = options.homeDir ?? homedir8();
2199
+ const homeDir = options.homeDir ?? homedir9();
2073
2200
  const config = options.config ?? getCodexOmoConfig({ cwd: options.cwd ?? processCwd3(), env, homeDir });
2074
2201
  const codegraphConfig = config.codegraph ?? {};
2075
2202
  if (codegraphConfig.enabled === false) {
@@ -2081,13 +2208,26 @@ async function runCodegraphServe(options = {}) {
2081
2208
  homeDir,
2082
2209
  provisioned: () => provisionedBinFromInstallDir2(codegraphConfig.install_dir)
2083
2210
  };
2084
- const resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
2211
+ let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
2212
+ const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
2085
2213
  if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync7)) {
2086
- (options.stderr ?? processStderr2).write(CODEGRAPH_SKIP_HINT);
2087
- return 1;
2214
+ if (resolution.source === "path" && !nodeSupport.supported) {
2215
+ (options.stderr ?? processStderr2).write(buildCodegraphNodeSkipHint(nodeSupport));
2216
+ return 1;
2217
+ }
2218
+ const provisioned = await provisionMissingCodegraph({
2219
+ config: codegraphConfig,
2220
+ ensureProvisioned: options.ensureProvisioned ?? ensureCodegraphProvisioned,
2221
+ homeDir,
2222
+ resolution
2223
+ });
2224
+ if (provisioned === null) {
2225
+ (options.stderr ?? processStderr2).write(CODEGRAPH_SKIP_HINT);
2226
+ return 1;
2227
+ }
2228
+ resolution = provisioned;
2088
2229
  }
2089
- const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
2090
- if (resolution.source !== "bundled" && resolution.source !== "env" && !nodeSupport.supported) {
2230
+ if (codegraphCommandRequiresSupportedLocalNode(resolution) && !nodeSupport.supported) {
2091
2231
  (options.stderr ?? processStderr2).write(buildCodegraphNodeSkipHint(nodeSupport));
2092
2232
  return 1;
2093
2233
  }
@@ -2102,6 +2242,21 @@ async function runCodegraphServe(options = {}) {
2102
2242
  stdio: "inherit"
2103
2243
  });
2104
2244
  }
2245
+ async function provisionMissingCodegraph(options) {
2246
+ if (options.resolution.source === "env")
2247
+ return null;
2248
+ if (options.config.auto_provision === false)
2249
+ return null;
2250
+ const installDir = options.config.install_dir ?? join8(options.homeDir, ".omo", "codegraph");
2251
+ const result = await options.ensureProvisioned({
2252
+ installDir,
2253
+ lockDir: join8(installDir, ".locks"),
2254
+ version: CODEGRAPH_VERSION2
2255
+ });
2256
+ if (!result.provisioned || result.binPath === undefined)
2257
+ return null;
2258
+ return { argsPrefix: [], command: result.binPath, exists: true, source: "provisioned" };
2259
+ }
2105
2260
  function shouldSkipResolvedCommand(resolution, commandExists) {
2106
2261
  if (resolution.source !== "env")
2107
2262
  return false;
@@ -2176,6 +2331,14 @@ async function runCodegraphCli(options = {}) {
2176
2331
  if (command === "hook" && subcommand === "session-start") {
2177
2332
  return runCodegraphSessionStartHook(options);
2178
2333
  }
2334
+ if (command === "hook" && subcommand === "post-tool-use") {
2335
+ const hookOptions = {
2336
+ ...options.env === undefined ? {} : { env: options.env },
2337
+ ...options.stdin === undefined ? {} : { stdin: options.stdin },
2338
+ ...options.stdout === undefined ? {} : { stdout: options.stdout }
2339
+ };
2340
+ return runCodegraphPostToolUseHookCli(hookOptions);
2341
+ }
2179
2342
  if (command === "hook" && subcommand === "session-start-worker") {
2180
2343
  const workerOptions = {
2181
2344
  ...options.workerOptions,