oh-my-opencode 4.12.0 → 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 (54) hide show
  1. package/dist/cli/index.js +36 -17
  2. package/dist/cli-node/index.js +36 -17
  3. package/dist/index.js +361 -254
  4. package/dist/skills/ultraresearch/SKILL.md +11 -2
  5. package/dist/tools/background-task/constants.d.ts +1 -1
  6. package/dist/tui.js +9 -3
  7. package/package.json +13 -13
  8. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
  9. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  10. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +327 -171
  11. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +275 -31
  12. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  13. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
  14. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
  15. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
  16. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +40 -3
  17. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +6 -5
  18. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +49 -87
  19. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +1 -1
  20. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
  21. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
  22. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
  23. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
  30. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
  31. package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
  32. package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
  33. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
  34. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
  35. package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
  36. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  37. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  38. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
  40. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
  41. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  42. package/packages/omo-codex/plugin/package-lock.json +30 -12
  43. package/packages/omo-codex/plugin/package.json +2 -1
  44. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +1 -0
  45. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
  46. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +36 -0
  47. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +2 -1
  48. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +1 -1
  49. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -0
  50. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
  51. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +1 -0
  52. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
  53. package/packages/omo-codex/scripts/install-dist/install-local.mjs +14 -1
  54. package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
@@ -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
  }
@@ -1627,7 +1819,7 @@ ${result.stderr}`.trim().split(/\s+/)[0];
1627
1819
  }
1628
1820
  }
1629
1821
  function isNodeExecutableName(filePath) {
1630
- const executable = basename2(filePath).toLowerCase();
1822
+ const executable = basename3(filePath).toLowerCase();
1631
1823
  return executable === "node" || executable === "node.exe" || /^node\d+(\.exe)?$/.test(executable);
1632
1824
  }
1633
1825
  function looksLikePath(command) {
@@ -1667,8 +1859,8 @@ function defaultNodeRuntime(env, fileExists, which, nodeVersion) {
1667
1859
  function defaultProvisionedBin(homeDir, fileExists) {
1668
1860
  const binaryName = process.platform === "win32" ? "codegraph.cmd" : "codegraph";
1669
1861
  const candidates = [
1670
- join5(homeDir, ".omo", "codegraph", "bin", binaryName),
1671
- 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)
1672
1864
  ];
1673
1865
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
1674
1866
  }
@@ -1676,7 +1868,7 @@ function resolveBundledShim(requireResolve, fileExists) {
1676
1868
  try {
1677
1869
  const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
1678
1870
  const packageRoot = dirname2(packageJson);
1679
- 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")];
1680
1872
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
1681
1873
  } catch (error) {
1682
1874
  if (error instanceof Error)
@@ -1692,7 +1884,7 @@ function resolveBundledShim(requireResolve, fileExists) {
1692
1884
  }
1693
1885
  function resolveCodegraphCommand(options = {}) {
1694
1886
  const env = options.env ?? process.env;
1695
- const fileExists = options.fileExists ?? existsSync4;
1887
+ const fileExists = options.fileExists ?? existsSync5;
1696
1888
  const configuredBin = env[CODEGRAPH_ENV_BIN]?.trim() || env[CODEGRAPH_LEGACY_ENV_BIN]?.trim();
1697
1889
  if (configuredBin !== undefined && configuredBin.length > 0) {
1698
1890
  return { argsPrefix: [], command: configuredBin, exists: fileExists(configuredBin), source: "env" };
@@ -1704,7 +1896,7 @@ function resolveCodegraphCommand(options = {}) {
1704
1896
  if (bundled !== null && runtime2 !== null) {
1705
1897
  return { argsPrefix: [bundled], command: runtime2, exists: true, source: "bundled" };
1706
1898
  }
1707
- const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir4(), fileExists);
1899
+ const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir6(), fileExists);
1708
1900
  if (provisioned !== null && fileExists(provisioned)) {
1709
1901
  return { argsPrefix: [], command: provisioned, exists: true, source: "provisioned" };
1710
1902
  }
@@ -1717,102 +1909,6 @@ function resolveCodegraphCommand(options = {}) {
1717
1909
  };
1718
1910
  }
1719
1911
 
1720
- // ../../utils/src/codegraph/workspace.ts
1721
- import { createHash as createHash2 } from "node:crypto";
1722
- import {
1723
- appendFileSync,
1724
- existsSync as existsSync5,
1725
- lstatSync,
1726
- mkdirSync,
1727
- readFileSync as readFileSync2,
1728
- readdirSync,
1729
- realpathSync,
1730
- rmSync,
1731
- statSync,
1732
- symlinkSync
1733
- } from "node:fs";
1734
- import { homedir as homedir5 } from "node:os";
1735
- import { basename as basename3, join as join6, resolve as resolve2 } from "node:path";
1736
- function sanitizeBase(value) {
1737
- const sanitized = value.replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-");
1738
- return sanitized.length > 0 ? sanitized : "workspace";
1739
- }
1740
- function codegraphDataRoot(homeDir) {
1741
- return join6(homeDir, ".omo", "codegraph");
1742
- }
1743
- function workspaceStorageName(workspace) {
1744
- const resolved = resolve2(workspace);
1745
- const hash = createHash2("sha256").update(resolved).digest("hex").slice(0, 16);
1746
- return `${sanitizeBase(basename3(resolved))}-${hash}`;
1747
- }
1748
- function fallbackResult(dataRoot, projectLink, reason) {
1749
- return { dataDir: projectLink, dataRoot, linked: false, mode: "in-place-fallback", projectLink, reason };
1750
- }
1751
- function isSameFilesystem(workspace, dataRoot, override) {
1752
- if (override !== undefined)
1753
- return override;
1754
- return statSync(workspace).dev === statSync(dataRoot).dev;
1755
- }
1756
- function ensureInPlaceFallback(projectLink) {
1757
- if (!existsSync5(projectLink))
1758
- mkdirSync(projectLink, { recursive: true });
1759
- }
1760
- function prepareCodegraphWorkspace(workspace, options = {}) {
1761
- const resolvedWorkspace = resolve2(workspace);
1762
- const dataRoot = codegraphDataRoot(options.homeDir ?? homedir5());
1763
- const dataDir = join6(dataRoot, "projects", workspaceStorageName(resolvedWorkspace));
1764
- const projectLink = join6(resolvedWorkspace, ".codegraph");
1765
- try {
1766
- mkdirSync(dataDir, { recursive: true });
1767
- if (existsSync5(projectLink)) {
1768
- const linkStat = lstatSync(projectLink);
1769
- if (!linkStat.isSymbolicLink()) {
1770
- return { dataDir: projectLink, dataRoot, linked: false, mode: "in-project", projectLink };
1771
- }
1772
- if (realpathSync(projectLink) === realpathSync(dataDir)) {
1773
- return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
1774
- }
1775
- return fallbackResult(dataRoot, projectLink, "existing .codegraph symlink points outside OMO store");
1776
- }
1777
- if (!isSameFilesystem(resolvedWorkspace, dataRoot, options.sameFilesystem)) {
1778
- ensureInPlaceFallback(projectLink);
1779
- return fallbackResult(dataRoot, projectLink, "workspace and OMO store are on different filesystems");
1780
- }
1781
- const symlink = options.symlink ?? symlinkSync;
1782
- symlink(dataDir, projectLink, (options.platform ?? process.platform) === "win32" ? "junction" : "dir");
1783
- return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
1784
- } catch (error) {
1785
- const reason = error instanceof Error ? error.message : String(error);
1786
- try {
1787
- ensureInPlaceFallback(projectLink);
1788
- } catch (fallbackError) {
1789
- return fallbackResult(dataRoot, projectLink, `${reason}; fallback failed: ${String(fallbackError)}`);
1790
- }
1791
- return fallbackResult(dataRoot, projectLink, reason);
1792
- }
1793
- }
1794
- function ensureCodegraphGitignored(workspace) {
1795
- const gitDir = join6(workspace, ".git");
1796
- if (!existsSync5(gitDir))
1797
- return false;
1798
- const excludePath = join6(gitDir, "info", "exclude");
1799
- try {
1800
- mkdirSync(join6(gitDir, "info"), { recursive: true });
1801
- const existing = existsSync5(excludePath) ? readFileSync2(excludePath, "utf8") : "";
1802
- if (existing.split(/\r?\n/).includes(".codegraph"))
1803
- return true;
1804
- appendFileSync(excludePath, `${existing.endsWith(`
1805
- `) || existing.length === 0 ? "" : `
1806
- `}.codegraph
1807
- `);
1808
- return true;
1809
- } catch (error) {
1810
- if (error instanceof Error)
1811
- return false;
1812
- throw error;
1813
- }
1814
- }
1815
-
1816
1912
  // components/codegraph/src/session-start-worker.ts
1817
1913
  var SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
1818
1914
  var CODEGRAPH_VERSION = "1.0.1";
@@ -1866,13 +1962,10 @@ function finish(action, detail, logOutcome) {
1866
1962
  }
1867
1963
  async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport) {
1868
1964
  const resolved = deps.resolveCommand({ env, homeDir, provisioned: () => provisionedBinFromInstallDir(config.install_dir) });
1869
- if (resolved.exists) {
1870
- if (codegraphCommandRequiresSupportedLocalNode(resolved) && !nodeSupport.supported) {
1871
- return { kind: "unsupported-node" };
1872
- }
1965
+ if (resolved.exists && canUseResolvedCommand(resolved, nodeSupport)) {
1873
1966
  return { kind: "resolved", resolution: resolved };
1874
1967
  }
1875
- if (!nodeSupport.supported)
1968
+ if (resolved.exists && config.auto_provision === false)
1876
1969
  return { kind: "unsupported-node" };
1877
1970
  if (config.auto_provision === false)
1878
1971
  return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
@@ -1883,6 +1976,9 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
1883
1976
  }
1884
1977
  return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
1885
1978
  }
1979
+ function canUseResolvedCommand(resolved, nodeSupport) {
1980
+ return !codegraphCommandRequiresSupportedLocalNode(resolved) || nodeSupport.supported;
1981
+ }
1886
1982
  function decideStartupAction(status) {
1887
1983
  if (status.timedOut)
1888
1984
  return { kind: "skip", reason: "status timed out" };
@@ -1900,7 +1996,7 @@ ${status.stderr ?? ""}`.toLowerCase();
1900
1996
  return { kind: "sync" };
1901
1997
  }
1902
1998
  function jsonSaysInitialized(value) {
1903
- if (!isRecord2(value))
1999
+ if (!isRecord3(value))
1904
2000
  return;
1905
2001
  const initialized = value["initialized"] ?? value["isInitialized"] ?? value["ready"];
1906
2002
  if (typeof initialized === "boolean")
@@ -1966,7 +2062,7 @@ function toOutputText(value) {
1966
2062
  return Buffer.isBuffer(value) ? value.toString("utf8") : value;
1967
2063
  }
1968
2064
  function resolveHomeDir(env) {
1969
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir6();
2065
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir7();
1970
2066
  }
1971
2067
  function parseJson(text) {
1972
2068
  try {
@@ -1977,7 +2073,7 @@ function parseJson(text) {
1977
2073
  throw error;
1978
2074
  }
1979
2075
  }
1980
- function isRecord2(value) {
2076
+ function isRecord3(value) {
1981
2077
  return typeof value === "object" && value !== null;
1982
2078
  }
1983
2079
 
@@ -1986,6 +2082,9 @@ var CODEGRAPH_SESSION_START_NOTICE = "LazyCodex CodeGraph bootstrap scheduled in
1986
2082
  async function runCodegraphSessionStartHook(options = {}) {
1987
2083
  return (await executeCodegraphSessionStartHook(options)).exitCode;
1988
2084
  }
2085
+ async function runCodegraphPostToolUseHookCli(options = {}) {
2086
+ return (await executeCodegraphPostToolUseHook(options)).exitCode;
2087
+ }
1989
2088
  async function executeCodegraphSessionStartHook(options = {}) {
1990
2089
  const env = options.env ?? processEnv2;
1991
2090
  const input = await readHookInput(options.stdin ?? processStdin);
@@ -2003,6 +2102,30 @@ async function executeCodegraphSessionStartHook(options = {}) {
2003
2102
  writeHookJson(options.stdout ?? processStdout);
2004
2103
  return { action: "spawned", exitCode: 0 };
2005
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
+ }
2006
2129
  function writeHookJson(stdout) {
2007
2130
  const output = {
2008
2131
  hookSpecificOutput: {
@@ -2018,10 +2141,10 @@ function spawnDetachedWorker(invocation) {
2018
2141
  child.unref();
2019
2142
  }
2020
2143
  function resolveHomeDir2(env) {
2021
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir7();
2144
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir8();
2022
2145
  }
2023
2146
  function resolveProjectRoot(input, fallback) {
2024
- if (!isRecord3(input))
2147
+ if (!isRecord4(input))
2025
2148
  return fallback;
2026
2149
  const cwd = input["cwd"];
2027
2150
  return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : fallback;
@@ -2045,7 +2168,7 @@ function parseJson2(text) {
2045
2168
  throw error;
2046
2169
  }
2047
2170
  }
2048
- function isRecord3(value) {
2171
+ function isRecord4(value) {
2049
2172
  return typeof value === "object" && value !== null;
2050
2173
  }
2051
2174
  function defaultWorkerCliPath() {
@@ -2055,7 +2178,7 @@ function defaultWorkerCliPath() {
2055
2178
  // components/codegraph/src/serve.ts
2056
2179
  import { spawn as spawn2 } from "node:child_process";
2057
2180
  import { existsSync as existsSync7, realpathSync as realpathSync2 } from "node:fs";
2058
- import { homedir as homedir8 } from "node:os";
2181
+ import { homedir as homedir9 } from "node:os";
2059
2182
  import { basename as basename4, extname as extname2, join as join8, resolve as resolve3 } from "node:path";
2060
2183
  import {
2061
2184
  cwd as processCwd3,
@@ -2068,11 +2191,12 @@ var CODEGRAPH_SKIP_HINT = `CodeGraph MCP skipped: codegraph binary not found. In
2068
2191
  `;
2069
2192
  var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.
2070
2193
  `;
2194
+ var CODEGRAPH_VERSION2 = "1.0.1";
2071
2195
  var WINDOWS_CMD_EXTENSIONS2 = new Set([".bat", ".cmd"]);
2072
2196
  var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
2073
2197
  async function runCodegraphServe(options = {}) {
2074
2198
  const env = options.env ?? processEnv3;
2075
- const homeDir = options.homeDir ?? homedir8();
2199
+ const homeDir = options.homeDir ?? homedir9();
2076
2200
  const config = options.config ?? getCodexOmoConfig({ cwd: options.cwd ?? processCwd3(), env, homeDir });
2077
2201
  const codegraphConfig = config.codegraph ?? {};
2078
2202
  if (codegraphConfig.enabled === false) {
@@ -2084,15 +2208,24 @@ async function runCodegraphServe(options = {}) {
2084
2208
  homeDir,
2085
2209
  provisioned: () => provisionedBinFromInstallDir2(codegraphConfig.install_dir)
2086
2210
  };
2087
- const resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
2211
+ let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
2088
2212
  const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
2089
2213
  if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync7)) {
2090
2214
  if (resolution.source === "path" && !nodeSupport.supported) {
2091
2215
  (options.stderr ?? processStderr2).write(buildCodegraphNodeSkipHint(nodeSupport));
2092
2216
  return 1;
2093
2217
  }
2094
- (options.stderr ?? processStderr2).write(CODEGRAPH_SKIP_HINT);
2095
- return 1;
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;
2096
2229
  }
2097
2230
  if (codegraphCommandRequiresSupportedLocalNode(resolution) && !nodeSupport.supported) {
2098
2231
  (options.stderr ?? processStderr2).write(buildCodegraphNodeSkipHint(nodeSupport));
@@ -2109,6 +2242,21 @@ async function runCodegraphServe(options = {}) {
2109
2242
  stdio: "inherit"
2110
2243
  });
2111
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
+ }
2112
2260
  function shouldSkipResolvedCommand(resolution, commandExists) {
2113
2261
  if (resolution.source !== "env")
2114
2262
  return false;
@@ -2183,6 +2331,14 @@ async function runCodegraphCli(options = {}) {
2183
2331
  if (command === "hook" && subcommand === "session-start") {
2184
2332
  return runCodegraphSessionStartHook(options);
2185
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
+ }
2186
2342
  if (command === "hook" && subcommand === "session-start-worker") {
2187
2343
  const workerOptions = {
2188
2344
  ...options.workerOptions,