oh-my-opencode 4.15.1 → 4.16.0

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 (142) hide show
  1. package/dist/cli/doctor/checks/tui-plugin-config.d.ts +4 -4
  2. package/dist/cli/index.js +673 -678
  3. package/dist/cli/install-senpi/index.d.ts +1 -0
  4. package/dist/cli/run/poll-for-completion.d.ts +4 -0
  5. package/dist/cli/run/session-resolver.d.ts +1 -0
  6. package/dist/cli/senpi-platform-flag.d.ts +4 -0
  7. package/dist/cli/types.d.ts +2 -1
  8. package/dist/cli-node/index.js +673 -678
  9. package/dist/features/background-agent/manager.d.ts +16 -0
  10. package/dist/hooks/anthropic-context-window-limit-recovery/aggressive-truncation-strategy.d.ts +1 -0
  11. package/dist/index.js +1334 -1146
  12. package/dist/skills/debugging/references/methodology/06-fix.md +6 -0
  13. package/dist/skills/frontend/ATTRIBUTION.md +10 -1
  14. package/dist/skills/frontend/SKILL.md +8 -3
  15. package/dist/skills/frontend/references/design/README.md +1 -1
  16. package/dist/skills/frontend/references/design/_INDEX.md +1 -1
  17. package/dist/skills/frontend/references/design/lazyweb.md +77 -0
  18. package/dist/skills/frontend/references/design/stitch-design-example.md +121 -0
  19. package/dist/skills/programming/SKILL.md +10 -1
  20. package/dist/skills/programming/references/logging.md +91 -0
  21. package/dist/skills/ulw-plan/SKILL.md +5 -5
  22. package/dist/skills/ulw-plan/references/full-workflow.md +7 -7
  23. package/dist/skills/ulw-plan/references/intent-unclear.md +3 -3
  24. package/dist/skills/ulw-research/ATTRIBUTION.md +2 -2
  25. package/dist/skills/ulw-research/SKILL.md +28 -7
  26. package/dist/tools/skill/description-formatter.d.ts +1 -0
  27. package/dist/tools/skill/description-formatter.test-support.d.ts +9 -0
  28. package/dist/tools/skill/zauc-mocks-skill-tools/test-support.d.ts +25 -0
  29. package/dist/tui.js +121 -419
  30. package/package.json +32 -15
  31. package/packages/git-bash-mcp/dist/cli.js +2 -2
  32. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  33. package/packages/omo-codex/plugin/components/bootstrap/AGENTS.md +55 -0
  34. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +19 -16
  35. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  36. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +51 -0
  37. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +936 -248
  38. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +233 -135
  39. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +29 -0
  41. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +13 -0
  42. package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +25 -0
  43. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
  44. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +30 -1
  45. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +16 -2
  46. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +80 -0
  47. package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +34 -0
  48. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +107 -0
  49. package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +26 -0
  50. package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +29 -0
  51. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +8 -21
  52. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +108 -0
  53. package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +76 -0
  54. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +17 -111
  55. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +1 -1
  56. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +45 -67
  57. package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +56 -0
  58. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  59. package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +31 -0
  60. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  61. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +45 -0
  62. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  63. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  64. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +37 -102
  65. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  66. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  67. package/packages/omo-codex/plugin/components/teammode/AGENTS.md +46 -0
  68. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  69. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +6 -0
  70. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +6 -0
  71. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  72. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +5 -2
  73. package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +2 -0
  74. package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
  75. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +51 -2
  76. package/packages/omo-codex/plugin/components/ultrawork/package.json +2 -1
  77. package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +14 -1
  78. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +380 -0
  79. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +5 -2
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +4 -4
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +2 -2
  82. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +5 -3
  83. package/packages/omo-codex/plugin/components/ultrawork/src/skill-pointer.ts +56 -0
  84. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +4 -4
  85. package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +12 -0
  86. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +1 -0
  87. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +82 -0
  88. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +56 -5
  90. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +1 -0
  91. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +5 -1
  92. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.d.ts +2 -1
  93. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.js +5 -3
  94. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.d.ts +7 -0
  95. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.js +46 -0
  96. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  97. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +5 -1
  98. package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-directive.ts +9 -3
  99. package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-skill-pointer.ts +55 -0
  100. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +49 -0
  101. package/packages/omo-codex/plugin/package-lock.json +13 -13
  102. package/packages/omo-codex/plugin/package.json +1 -1
  103. package/packages/omo-codex/plugin/scripts/build-components.mjs +63 -17
  104. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +10 -3
  105. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -0
  106. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +18 -0
  107. package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +6 -0
  108. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +10 -1
  109. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +8 -3
  110. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +1 -1
  111. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -1
  112. package/packages/omo-codex/plugin/skills/frontend/references/design/lazyweb.md +77 -0
  113. package/packages/omo-codex/plugin/skills/frontend/references/design/stitch-design-example.md +121 -0
  114. package/packages/omo-codex/plugin/skills/programming/SKILL.md +10 -1
  115. package/packages/omo-codex/plugin/skills/programming/references/logging.md +91 -0
  116. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +380 -0
  117. package/packages/omo-codex/plugin/skills/ultrawork/agents/openai.yaml +2 -0
  118. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +5 -2
  119. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +4 -4
  120. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +2 -2
  121. package/packages/omo-codex/plugin/skills/ulw-research/ATTRIBUTION.md +2 -2
  122. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +28 -7
  123. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +1 -1
  124. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  125. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +56 -0
  126. package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +98 -0
  127. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +6 -6
  128. package/packages/omo-codex/scripts/install-dist/install-local.mjs +259 -3954
  129. package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +6 -0
  130. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +10 -1
  131. package/packages/shared-skills/skills/frontend/SKILL.md +8 -3
  132. package/packages/shared-skills/skills/frontend/references/design/README.md +1 -1
  133. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -1
  134. package/packages/shared-skills/skills/frontend/references/design/lazyweb.md +77 -0
  135. package/packages/shared-skills/skills/frontend/references/design/stitch-design-example.md +121 -0
  136. package/packages/shared-skills/skills/programming/SKILL.md +10 -1
  137. package/packages/shared-skills/skills/programming/references/logging.md +91 -0
  138. package/packages/shared-skills/skills/ulw-plan/SKILL.md +5 -5
  139. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +7 -7
  140. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +3 -3
  141. package/packages/shared-skills/skills/ulw-research/ATTRIBUTION.md +2 -2
  142. package/packages/shared-skills/skills/ulw-research/SKILL.md +28 -7
@@ -1,22 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // components/codegraph/src/cli.ts
4
- import { realpathSync as realpathSync3 } from "node:fs";
5
- import { basename as basename5, resolve as resolve4 } from "node:path";
6
- import { stderr as processStderr3 } from "node:process";
7
- import { fileURLToPath as fileURLToPath3 } from "node:url";
4
+ import { realpathSync as realpathSync6 } from "node:fs";
5
+ import { basename as basename5, resolve as resolve6 } from "node:path";
6
+ import { stderr as processStderr4 } from "node:process";
7
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
8
8
 
9
9
  // components/codegraph/src/hook.ts
10
- import { execFile as execFile3, spawn } from "node:child_process";
11
- import { homedir as homedir9 } from "node:os";
12
- import { join as join8 } from "node:path";
13
- import { cwd as processCwd2, env as processEnv2, stdin as processStdin, stdout as processStdout } from "node:process";
14
- import { fileURLToPath } from "node:url";
10
+ import { execFile as execFile4, spawn } from "node:child_process";
11
+ import { homedir as homedir13 } from "node:os";
12
+ import { join as join13 } from "node:path";
13
+ import {
14
+ cwd as processCwd2,
15
+ env as processEnv2,
16
+ stderr as processStderr2,
17
+ stdin as processStdin,
18
+ stdout as processStdout
19
+ } from "node:process";
20
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
15
21
 
16
22
  // ../../utils/src/codegraph/env.ts
17
23
  import { homedir } from "node:os";
18
24
  import { join } from "node:path";
19
25
  var CODEGRAPH_INSTALL_DIR_ENV = "CODEGRAPH_INSTALL_DIR";
26
+ var CODEGRAPH_NO_DAEMON_ENV = "CODEGRAPH_NO_DAEMON";
20
27
  var CODEGRAPH_NO_DOWNLOAD_ENV = "CODEGRAPH_NO_DOWNLOAD";
21
28
  var CODEGRAPH_TELEMETRY_ENV = "CODEGRAPH_TELEMETRY";
22
29
  var DO_NOT_TRACK_ENV = "DO_NOT_TRACK";
@@ -50,6 +57,7 @@ var SAFE_CODEGRAPH_RUNTIME_ENV_KEYS = new Set([
50
57
  "CODEGRAPH_ALLOW_UNSAFE_NODE",
51
58
  "CODEGRAPH_BIN",
52
59
  "CODEGRAPH_FAKE_LOG",
60
+ "CODEGRAPH_NO_DAEMON",
53
61
  "CODEGRAPH_NODE_BIN",
54
62
  "OMO_CODEGRAPH_BIN",
55
63
  "OMO_CODEGRAPH_PROJECT_CWD",
@@ -59,6 +67,7 @@ function buildCodegraphEnv(options = {}) {
59
67
  const homeDir = options.homeDir ?? homedir();
60
68
  return {
61
69
  [CODEGRAPH_INSTALL_DIR_ENV]: join(homeDir, ".omo", "codegraph"),
70
+ [CODEGRAPH_NO_DAEMON_ENV]: "1",
62
71
  [CODEGRAPH_NO_DOWNLOAD_ENV]: "1",
63
72
  [CODEGRAPH_TELEMETRY_ENV]: "0",
64
73
  [DO_NOT_TRACK_ENV]: "1"
@@ -86,22 +95,15 @@ function buildCodegraphChildEnv(options = {}) {
86
95
  }
87
96
 
88
97
  // ../../utils/src/codegraph/guidance.ts
89
- import { homedir as homedir3 } from "node:os";
98
+ import { homedir as homedir5 } from "node:os";
90
99
 
91
100
  // ../../utils/src/codegraph/workspace.ts
101
+ import { appendFileSync, existsSync as existsSync2, lstatSync as lstatSync2, mkdirSync, realpathSync as realpathSync3, readFileSync as readFileSync2, statSync, symlinkSync } from "node:fs";
102
+ import { join as join5 } from "node:path";
103
+
104
+ // ../../utils/src/codegraph/paths.ts
92
105
  import { createHash } from "node:crypto";
93
- import {
94
- appendFileSync,
95
- existsSync,
96
- lstatSync,
97
- mkdirSync,
98
- readFileSync,
99
- readdirSync,
100
- realpathSync,
101
- rmSync,
102
- statSync,
103
- symlinkSync
104
- } from "node:fs";
106
+ import { realpathSync } from "node:fs";
105
107
  import { homedir as homedir2 } from "node:os";
106
108
  import { basename, join as join2, resolve } from "node:path";
107
109
  function sanitizeBase(value) {
@@ -111,13 +113,23 @@ function sanitizeBase(value) {
111
113
  function codegraphDataRoot(homeDir) {
112
114
  return join2(homeDir, ".omo", "codegraph");
113
115
  }
116
+ function canonicalizeCodegraphPath(path) {
117
+ const resolved = resolve(path);
118
+ try {
119
+ return realpathSync(resolved);
120
+ } catch (error) {
121
+ if (error instanceof Error)
122
+ return resolved;
123
+ throw error;
124
+ }
125
+ }
114
126
  function workspaceStorageName(workspace) {
115
- const resolved = resolve(workspace);
127
+ const resolved = canonicalizeCodegraphPath(workspace);
116
128
  const hash = createHash("sha256").update(resolved).digest("hex").slice(0, 16);
117
129
  return `${sanitizeBase(basename(resolved))}-${hash}`;
118
130
  }
119
131
  function resolveCodegraphWorkspacePaths(workspace, options = {}) {
120
- const resolvedWorkspace = resolve(workspace);
132
+ const resolvedWorkspace = canonicalizeCodegraphPath(workspace);
121
133
  const dataRoot = codegraphDataRoot(options.homeDir ?? homedir2());
122
134
  return {
123
135
  dataDir: join2(dataRoot, "projects", workspaceStorageName(resolvedWorkspace)),
@@ -125,6 +137,127 @@ function resolveCodegraphWorkspacePaths(workspace, options = {}) {
125
137
  projectLink: join2(resolvedWorkspace, ".codegraph")
126
138
  };
127
139
  }
140
+
141
+ // ../../utils/src/codegraph/store.ts
142
+ import { existsSync, lstatSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
143
+ import { homedir as homedir3 } from "node:os";
144
+ import { join as join3 } from "node:path";
145
+ var CODEGRAPH_PROJECT_SOURCE_METADATA_FILE = "source.json";
146
+ var CODEGRAPH_PROJECT_SOURCE_METADATA_VERSION = 1;
147
+ function writeCodegraphSourceMetadata(dataDir, sourceDir) {
148
+ writeFileSync(join3(dataDir, CODEGRAPH_PROJECT_SOURCE_METADATA_FILE), `${JSON.stringify({ sourceDir, version: CODEGRAPH_PROJECT_SOURCE_METADATA_VERSION }, null, 2)}
149
+ `);
150
+ }
151
+ function readRecordedSourceDir(projectDir) {
152
+ const metadataPath = join3(projectDir, CODEGRAPH_PROJECT_SOURCE_METADATA_FILE);
153
+ if (!existsSync(metadataPath))
154
+ return null;
155
+ try {
156
+ const parsed = JSON.parse(readFileSync(metadataPath, "utf8"));
157
+ if (typeof parsed !== "object" || parsed === null)
158
+ return null;
159
+ const sourceDir = parsed.sourceDir;
160
+ return typeof sourceDir === "string" && sourceDir.trim().length > 0 ? sourceDir : null;
161
+ } catch (error) {
162
+ if (isNonFatalSourceMetadataError(error))
163
+ return null;
164
+ throw error;
165
+ }
166
+ }
167
+ function isNonFatalSourceMetadataError(error) {
168
+ if (error instanceof SyntaxError)
169
+ return true;
170
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
171
+ return typeof code === "string" && ["EACCES", "ENOENT", "ENOTDIR", "EPERM"].includes(code);
172
+ }
173
+ function recordedSourceIsMissing(projectDir) {
174
+ const sourceDir = readRecordedSourceDir(projectDir);
175
+ return sourceDir !== null && !existsSync(sourceDir);
176
+ }
177
+ function pruneDeadCodegraphProjectStores(options = {}) {
178
+ const projectsDir = join3(codegraphDataRoot(options.homeDir ?? homedir3()), "projects");
179
+ const removed = [];
180
+ if (!existsSync(projectsDir))
181
+ return { remainingBytes: 0, removed };
182
+ for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
183
+ if (!entry.isDirectory())
184
+ continue;
185
+ const projectDir = join3(projectsDir, entry.name);
186
+ if (!recordedSourceIsMissing(projectDir))
187
+ continue;
188
+ rmSync(projectDir, { force: true, recursive: true });
189
+ removed.push(projectDir);
190
+ }
191
+ return { remainingBytes: 0, removed };
192
+ }
193
+
194
+ // ../../utils/src/codegraph/exclusion.ts
195
+ import { realpathSync as realpathSync2 } from "node:fs";
196
+ import { homedir as homedir4, tmpdir as osTmpdir } from "node:os";
197
+ import { isAbsolute, join as join4, resolve as resolve2 } from "node:path";
198
+ var POSIX_DEFAULT_EXCLUDED_ROOTS = ["/tmp", "/private/tmp"];
199
+ function expandHome(path, homeDir) {
200
+ if (path === "~")
201
+ return homeDir;
202
+ if (path.startsWith("~/") || path.startsWith("~\\"))
203
+ return join4(homeDir, path.slice(2));
204
+ return path;
205
+ }
206
+ function realpathIfPossible(path) {
207
+ try {
208
+ return realpathSync2(path);
209
+ } catch (error) {
210
+ if (error instanceof Error)
211
+ return resolve2(path);
212
+ throw error;
213
+ }
214
+ }
215
+ function resolveConfiguredRoot(path, homeDir) {
216
+ const expanded = expandHome(path, homeDir);
217
+ return realpathIfPossible(isAbsolute(expanded) ? expanded : join4(homeDir, expanded));
218
+ }
219
+ function normalizeForComparison(path, platform) {
220
+ const normalized = path.replaceAll("\\", "/").replace(/\/+$/, "");
221
+ return platform === "win32" ? normalized.toLowerCase() : normalized;
222
+ }
223
+ function pathIsWithin(path, root, platform) {
224
+ const candidate = normalizeForComparison(path, platform);
225
+ const normalizedRoot = normalizeForComparison(root, platform);
226
+ return candidate === normalizedRoot || candidate.startsWith(`${normalizedRoot}/`);
227
+ }
228
+ function hasOmoPathSegment(path) {
229
+ return path.split(/[\\/]+/).includes(".omo");
230
+ }
231
+ function defaultExcludedRoots(platform, tmpdir) {
232
+ return platform === "win32" ? [tmpdir] : [...POSIX_DEFAULT_EXCLUDED_ROOTS, tmpdir];
233
+ }
234
+ function shouldExcludeCodegraphProject(workspace, options = {}) {
235
+ const platform = options.platform ?? process.platform;
236
+ const homeDir = options.homeDir ?? homedir4();
237
+ const tmpdir = options.tmpdir ?? osTmpdir();
238
+ const resolvedWorkspace = realpathIfPossible(resolve2(workspace));
239
+ if (hasOmoPathSegment(resolvedWorkspace)) {
240
+ return { excluded: true, matchedRoot: ".omo", reason: "omo-state" };
241
+ }
242
+ for (const root of defaultExcludedRoots(platform, tmpdir)) {
243
+ const resolvedRoot = realpathIfPossible(resolve2(root));
244
+ if (pathIsWithin(resolvedWorkspace, resolvedRoot, platform)) {
245
+ return { excluded: true, matchedRoot: root, reason: "tmp-root" };
246
+ }
247
+ }
248
+ for (const root of options.excludedRoots ?? []) {
249
+ const trimmedRoot = root.trim();
250
+ if (trimmedRoot.length === 0)
251
+ continue;
252
+ const resolvedRoot = resolveConfiguredRoot(trimmedRoot, homeDir);
253
+ if (pathIsWithin(resolvedWorkspace, resolvedRoot, platform)) {
254
+ return { excluded: true, matchedRoot: root, reason: "custom-root" };
255
+ }
256
+ }
257
+ return { excluded: false };
258
+ }
259
+
260
+ // ../../utils/src/codegraph/workspace.ts
128
261
  function fallbackResult(dataRoot, projectLink, reason) {
129
262
  return { dataDir: projectLink, dataRoot, linked: false, mode: "in-place-fallback", projectLink, reason };
130
263
  }
@@ -134,20 +267,21 @@ function isSameFilesystem(workspace, dataRoot, override) {
134
267
  return statSync(workspace).dev === statSync(dataRoot).dev;
135
268
  }
136
269
  function ensureInPlaceFallback(projectLink) {
137
- if (!existsSync(projectLink))
270
+ if (!existsSync2(projectLink))
138
271
  mkdirSync(projectLink, { recursive: true });
139
272
  }
140
273
  function prepareCodegraphWorkspace(workspace, options = {}) {
141
- const resolvedWorkspace = resolve(workspace);
274
+ const resolvedWorkspace = canonicalizeCodegraphPath(workspace);
142
275
  const { dataDir, dataRoot, projectLink } = resolveCodegraphWorkspacePaths(resolvedWorkspace, options);
143
276
  try {
144
277
  mkdirSync(dataDir, { recursive: true });
145
- if (existsSync(projectLink)) {
146
- const linkStat = lstatSync(projectLink);
278
+ writeCodegraphSourceMetadata(dataDir, resolvedWorkspace);
279
+ if (existsSync2(projectLink)) {
280
+ const linkStat = lstatSync2(projectLink);
147
281
  if (!linkStat.isSymbolicLink()) {
148
282
  return { dataDir: projectLink, dataRoot, linked: false, mode: "in-project", projectLink };
149
283
  }
150
- if (realpathSync(projectLink) === realpathSync(dataDir)) {
284
+ if (realpathSync3(projectLink) === realpathSync3(dataDir)) {
151
285
  return { dataDir, dataRoot, linked: true, mode: "global-linked", projectLink };
152
286
  }
153
287
  return fallbackResult(dataRoot, projectLink, "existing .codegraph symlink points outside OMO store");
@@ -164,19 +298,20 @@ function prepareCodegraphWorkspace(workspace, options = {}) {
164
298
  try {
165
299
  ensureInPlaceFallback(projectLink);
166
300
  } catch (fallbackError) {
167
- return fallbackResult(dataRoot, projectLink, `${reason}; fallback failed: ${String(fallbackError)}`);
301
+ const fallbackReason = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
302
+ return fallbackResult(dataRoot, projectLink, `${reason}; fallback failed: ${fallbackReason}`);
168
303
  }
169
304
  return fallbackResult(dataRoot, projectLink, reason);
170
305
  }
171
306
  }
172
307
  function ensureCodegraphGitignored(workspace) {
173
- const gitDir = join2(workspace, ".git");
174
- if (!existsSync(gitDir))
308
+ const gitDir = join5(workspace, ".git");
309
+ if (!existsSync2(gitDir))
175
310
  return false;
176
- const excludePath = join2(gitDir, "info", "exclude");
311
+ const excludePath = join5(gitDir, "info", "exclude");
177
312
  try {
178
- mkdirSync(join2(gitDir, "info"), { recursive: true });
179
- const existing = existsSync(excludePath) ? readFileSync(excludePath, "utf8") : "";
313
+ mkdirSync(join5(gitDir, "info"), { recursive: true });
314
+ const existing = existsSync2(excludePath) ? readFileSync2(excludePath, "utf8") : "";
180
315
  if (existing.split(/\r?\n/).includes(".codegraph"))
181
316
  return true;
182
317
  appendFileSync(excludePath, `${existing.endsWith(`
@@ -210,7 +345,7 @@ function getCodegraphUninitializedProject(input) {
210
345
  }
211
346
  function buildCodegraphInitGuidance(projectPath, options = {}) {
212
347
  const { dataDir, dataRoot, projectLink } = resolveCodegraphWorkspacePaths(projectPath, {
213
- homeDir: options.homeDir ?? homedir3()
348
+ homeDir: options.homeDir ?? homedir5()
214
349
  });
215
350
  const displayProjectPath = formatDisplayPath(projectPath);
216
351
  const displayProjectLink = formatDisplayPath(projectLink);
@@ -278,15 +413,15 @@ function isRecord(value) {
278
413
  }
279
414
 
280
415
  // ../../utils/src/codegraph/resolve.ts
281
- import { existsSync as existsSync2 } from "node:fs";
282
- import { homedir as homedir4 } from "node:os";
416
+ import { existsSync as existsSync3 } from "node:fs";
417
+ import { homedir as homedir6 } from "node:os";
283
418
  import { spawnSync } from "node:child_process";
284
- import { basename as basename2, dirname, join as join4 } from "node:path";
419
+ import { basename as basename2, dirname, join as join7 } from "node:path";
285
420
  import { createRequire } from "node:module";
286
421
 
287
422
  // ../../utils/src/runtime/which.ts
288
423
  import { accessSync, constants } from "node:fs";
289
- import { delimiter, join as join3 } from "node:path";
424
+ import { delimiter, join as join6 } from "node:path";
290
425
  var runtime = globalThis;
291
426
  function isUnsafeCommandName(commandName) {
292
427
  if (commandName.includes("/") || commandName.includes("\\"))
@@ -341,7 +476,7 @@ function bunWhich(commandName) {
341
476
  return null;
342
477
  for (const pathEntry of pathEntries) {
343
478
  for (const candidateName of candidateNames) {
344
- const candidatePath = join3(pathEntry, candidateName);
479
+ const candidatePath = join6(pathEntry, candidateName);
345
480
  if (isExecutable(candidatePath))
346
481
  return candidatePath;
347
482
  }
@@ -460,8 +595,8 @@ function defaultNodeRuntime(env, fileExists, which, nodeVersion) {
460
595
  function defaultProvisionedBin(homeDir, fileExists) {
461
596
  const binaryName = process.platform === "win32" ? "codegraph.cmd" : "codegraph";
462
597
  const candidates = [
463
- join4(homeDir, ".omo", "codegraph", "bin", binaryName),
464
- join4(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
598
+ join7(homeDir, ".omo", "codegraph", "bin", binaryName),
599
+ join7(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
465
600
  ];
466
601
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
467
602
  }
@@ -469,7 +604,7 @@ function resolveBundledShim(requireResolve, fileExists) {
469
604
  try {
470
605
  const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
471
606
  const packageRoot = dirname(packageJson);
472
- const candidates = [join4(packageRoot, "bin", "codegraph.js"), join4(packageRoot, "npm-shim.js")];
607
+ const candidates = [join7(packageRoot, "bin", "codegraph.js"), join7(packageRoot, "npm-shim.js")];
473
608
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
474
609
  } catch (error) {
475
610
  if (error instanceof Error)
@@ -485,7 +620,7 @@ function resolveBundledShim(requireResolve, fileExists) {
485
620
  }
486
621
  function resolveCodegraphCommand(options = {}) {
487
622
  const env = options.env ?? process.env;
488
- const fileExists = options.fileExists ?? existsSync2;
623
+ const fileExists = options.fileExists ?? existsSync3;
489
624
  const configuredBin = env[CODEGRAPH_ENV_BIN]?.trim() || env[CODEGRAPH_LEGACY_ENV_BIN]?.trim();
490
625
  if (configuredBin !== undefined && configuredBin.length > 0) {
491
626
  return { argsPrefix: [], command: configuredBin, exists: fileExists(configuredBin), source: "env" };
@@ -497,7 +632,7 @@ function resolveCodegraphCommand(options = {}) {
497
632
  if (bundled !== null && runtime2 !== null) {
498
633
  return { argsPrefix: [bundled], command: runtime2, exists: true, source: "bundled" };
499
634
  }
500
- const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir4(), fileExists);
635
+ const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir6(), fileExists);
501
636
  if (provisioned !== null && fileExists(provisioned)) {
502
637
  return { argsPrefix: [], command: provisioned, exists: true, source: "provisioned" };
503
638
  }
@@ -511,11 +646,14 @@ function resolveCodegraphCommand(options = {}) {
511
646
  }
512
647
 
513
648
  // shared/src/config-loader.ts
514
- import { homedir as homedir6 } from "node:os";
649
+ import { homedir as homedir8 } from "node:os";
515
650
 
516
651
  // ../../utils/src/omo-config/loader.ts
517
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
518
- import { homedir as homedir5 } from "node:os";
652
+ import { existsSync as existsSync5 } from "node:fs";
653
+ import { homedir as homedir7 } from "node:os";
654
+
655
+ // ../../utils/src/omo-config/body.ts
656
+ import { readFileSync as readFileSync3 } from "node:fs";
519
657
 
520
658
  // ../../utils/src/deep-merge.ts
521
659
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
@@ -1393,127 +1531,13 @@ var HARNESS_IDS = ["codex", "opencode", "omo"];
1393
1531
  var SETTING_HARNESS_SUPPORT = {
1394
1532
  "codegraph.auto_provision": HARNESS_IDS,
1395
1533
  "codegraph.enabled": HARNESS_IDS,
1534
+ "codegraph.excluded_roots": ["codex"],
1396
1535
  "codegraph.install_dir": HARNESS_IDS,
1397
1536
  "codegraph.telemetry": HARNESS_IDS,
1398
1537
  "codegraph.watch_debounce_ms": ["opencode", "omo"]
1399
1538
  };
1400
1539
 
1401
- // ../../utils/src/omo-config/env-overrides.ts
1402
- var CODEGRAPH_ENV_KEYS = [
1403
- ["auto_provision", "AUTO_PROVISION", "boolean"],
1404
- ["enabled", "ENABLED", "boolean"],
1405
- ["install_dir", "INSTALL_DIR", "string"],
1406
- ["telemetry", "TELEMETRY", "boolean"],
1407
- ["watch_debounce_ms", "WATCH_DEBOUNCE_MS", "number"]
1408
- ];
1409
- function parseBooleanEnv(value) {
1410
- const normalized = value.trim().toLowerCase();
1411
- if (["1", "true", "yes", "on"].includes(normalized))
1412
- return true;
1413
- if (["0", "false", "no", "off"].includes(normalized))
1414
- return false;
1415
- return null;
1416
- }
1417
- function parseEnvValue(value, kind) {
1418
- if (kind === "boolean")
1419
- return parseBooleanEnv(value);
1420
- if (kind === "number") {
1421
- const parsed = Number(value);
1422
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
1423
- }
1424
- return value;
1425
- }
1426
- function setCodegraphSetting(config, key, value) {
1427
- switch (key) {
1428
- case "auto_provision":
1429
- if (typeof value === "boolean")
1430
- config.auto_provision = value;
1431
- return;
1432
- case "enabled":
1433
- if (typeof value === "boolean")
1434
- config.enabled = value;
1435
- return;
1436
- case "install_dir":
1437
- if (typeof value === "string")
1438
- config.install_dir = value;
1439
- return;
1440
- case "telemetry":
1441
- if (typeof value === "boolean")
1442
- config.telemetry = value;
1443
- return;
1444
- case "watch_debounce_ms":
1445
- if (typeof value === "number")
1446
- config.watch_debounce_ms = value;
1447
- return;
1448
- }
1449
- }
1450
- function buildEnvOverrides(harness, env, warnings, merge) {
1451
- let config = {};
1452
- for (const prefix of ["OMO", harness.toUpperCase()]) {
1453
- const codegraph = {};
1454
- for (const [settingKey, envSuffix, kind] of CODEGRAPH_ENV_KEYS) {
1455
- const envKey = `${prefix}_CODEGRAPH_${envSuffix}`;
1456
- const rawValue = env[envKey];
1457
- if (rawValue === undefined)
1458
- continue;
1459
- const parsed = parseEnvValue(rawValue, kind);
1460
- if (parsed === null) {
1461
- warnings.push(`${envKey} has invalid ${kind} value "${rawValue}"`);
1462
- continue;
1463
- }
1464
- setCodegraphSetting(codegraph, settingKey, parsed);
1465
- }
1466
- if (Object.keys(codegraph).length > 0) {
1467
- config = merge(config, { codegraph });
1468
- }
1469
- }
1470
- return config;
1471
- }
1472
-
1473
- // ../../utils/src/omo-config/resolve.ts
1474
- import { existsSync as existsSync3 } from "node:fs";
1475
- import { dirname as dirname2, isAbsolute, join as join5, relative, resolve as resolve2 } from "node:path";
1476
- function containsPath(parent, child) {
1477
- const pathToChild = relative(parent, child);
1478
- return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute(pathToChild);
1479
- }
1480
- function findProjectConfigPathsNearestFirst(cwd, homeDir) {
1481
- const startDir = resolve2(cwd);
1482
- const stopBeforeDir = containsPath(resolve2(homeDir), startDir) ? resolve2(homeDir) : null;
1483
- const paths = [];
1484
- let currentDir = startDir;
1485
- while (true) {
1486
- if (stopBeforeDir !== null && currentDir === stopBeforeDir)
1487
- break;
1488
- const configPath = join5(currentDir, ".omo", "config.jsonc");
1489
- if (existsSync3(configPath)) {
1490
- paths.push(configPath);
1491
- }
1492
- const parentDir = dirname2(currentDir);
1493
- if (parentDir === currentDir)
1494
- break;
1495
- currentDir = parentDir;
1496
- }
1497
- return paths;
1498
- }
1499
- function resolveOmoConfigPaths(options) {
1500
- const globalPath = join5(resolve2(options.homeDir), ".omo", "config.jsonc");
1501
- const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
1502
- return [
1503
- { path: globalPath, scope: "global" },
1504
- ...projectPathsFarthestFirst.map((path) => ({ path, scope: "project" }))
1505
- ];
1506
- }
1507
- function toMissingSource(candidate) {
1508
- return {
1509
- exists: false,
1510
- loaded: false,
1511
- path: candidate.path,
1512
- scope: candidate.scope
1513
- };
1514
- }
1515
-
1516
- // ../../utils/src/omo-config/loader.ts
1540
+ // ../../utils/src/omo-config/body.ts
1517
1541
  var BUILT_IN_DEFAULTS = {
1518
1542
  codegraph: {
1519
1543
  auto_provision: true,
@@ -1525,6 +1549,7 @@ var HARNESS_BLOCK_KEYS = HARNESS_IDS.map((harness) => `[${harness}]`);
1525
1549
  var CODEGRAPH_SETTING_KEYS = [
1526
1550
  "auto_provision",
1527
1551
  "enabled",
1552
+ "excluded_roots",
1528
1553
  "install_dir",
1529
1554
  "telemetry",
1530
1555
  "watch_debounce_ms"
@@ -1563,7 +1588,7 @@ function mergeCodegraphConfig(base, override) {
1563
1588
  for (const key of CODEGRAPH_SETTING_KEYS) {
1564
1589
  if (!hasOwn(merged, key))
1565
1590
  continue;
1566
- setCodegraphSetting2(codegraph, key, merged[key]);
1591
+ setCodegraphSetting(codegraph, key, merged[key]);
1567
1592
  }
1568
1593
  return Object.keys(codegraph).length > 0 ? codegraph : undefined;
1569
1594
  }
@@ -1580,6 +1605,9 @@ function isKnownHarnessBlockKey(key) {
1580
1605
  return HARNESS_BLOCK_KEYS.includes(key);
1581
1606
  }
1582
1607
  function validateCodegraphValue(key, value) {
1608
+ if (key === "excluded_roots") {
1609
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? null : "must be an array of strings";
1610
+ }
1583
1611
  if (key === "install_dir")
1584
1612
  return typeof value === "string" ? null : "must be a string";
1585
1613
  if (key === "watch_debounce_ms") {
@@ -1587,7 +1615,7 @@ function validateCodegraphValue(key, value) {
1587
1615
  }
1588
1616
  return typeof value === "boolean" ? null : "must be a boolean";
1589
1617
  }
1590
- function setCodegraphSetting2(config, key, value) {
1618
+ function setCodegraphSetting(config, key, value) {
1591
1619
  switch (key) {
1592
1620
  case "auto_provision":
1593
1621
  if (typeof value === "boolean")
@@ -1597,6 +1625,11 @@ function setCodegraphSetting2(config, key, value) {
1597
1625
  if (typeof value === "boolean")
1598
1626
  config.enabled = value;
1599
1627
  return;
1628
+ case "excluded_roots":
1629
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
1630
+ config.excluded_roots = value;
1631
+ }
1632
+ return;
1600
1633
  case "install_dir":
1601
1634
  if (typeof value === "string")
1602
1635
  config.install_dir = value;
@@ -1627,7 +1660,7 @@ function normalizeCodegraphSection(section, pathPrefix, warnings) {
1627
1660
  warnings.push(`${pathPrefix}.${key} ${error}`);
1628
1661
  continue;
1629
1662
  }
1630
- setCodegraphSetting2(codegraph, key, value);
1663
+ setCodegraphSetting(codegraph, key, value);
1631
1664
  }
1632
1665
  return codegraph;
1633
1666
  }
@@ -1662,7 +1695,7 @@ function normalizeActiveHarnessBlock(value, harness, pathPrefix, warnings) {
1662
1695
  }
1663
1696
  function loadConfigFile(path, harness) {
1664
1697
  try {
1665
- const content = readFileSync2(path, "utf-8");
1698
+ const content = readFileSync3(path, "utf-8");
1666
1699
  const parsed = parseJsoncSafe(content);
1667
1700
  if (parsed.errors.length > 0) {
1668
1701
  return {
@@ -1706,15 +1739,137 @@ function validateHarnessApplicability(config, harness) {
1706
1739
  }
1707
1740
  return warnings;
1708
1741
  }
1742
+
1743
+ // ../../utils/src/omo-config/env-overrides.ts
1744
+ var CODEGRAPH_ENV_KEYS = [
1745
+ ["auto_provision", "AUTO_PROVISION", "boolean"],
1746
+ ["enabled", "ENABLED", "boolean"],
1747
+ ["install_dir", "INSTALL_DIR", "string"],
1748
+ ["telemetry", "TELEMETRY", "boolean"],
1749
+ ["watch_debounce_ms", "WATCH_DEBOUNCE_MS", "number"]
1750
+ ];
1751
+ function parseBooleanEnv(value) {
1752
+ const normalized = value.trim().toLowerCase();
1753
+ if (["1", "true", "yes", "on"].includes(normalized))
1754
+ return true;
1755
+ if (["0", "false", "no", "off"].includes(normalized))
1756
+ return false;
1757
+ return null;
1758
+ }
1759
+ function parseEnvValue(value, kind) {
1760
+ if (kind === "boolean")
1761
+ return parseBooleanEnv(value);
1762
+ if (kind === "number") {
1763
+ const parsed = Number(value);
1764
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
1765
+ }
1766
+ return value;
1767
+ }
1768
+ function setCodegraphSetting2(config, key, value) {
1769
+ switch (key) {
1770
+ case "auto_provision":
1771
+ if (typeof value === "boolean")
1772
+ config.auto_provision = value;
1773
+ return;
1774
+ case "enabled":
1775
+ if (typeof value === "boolean")
1776
+ config.enabled = value;
1777
+ return;
1778
+ case "excluded_roots":
1779
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
1780
+ config.excluded_roots = value;
1781
+ }
1782
+ return;
1783
+ case "install_dir":
1784
+ if (typeof value === "string")
1785
+ config.install_dir = value;
1786
+ return;
1787
+ case "telemetry":
1788
+ if (typeof value === "boolean")
1789
+ config.telemetry = value;
1790
+ return;
1791
+ case "watch_debounce_ms":
1792
+ if (typeof value === "number")
1793
+ config.watch_debounce_ms = value;
1794
+ return;
1795
+ }
1796
+ }
1797
+ function buildEnvOverrides(harness, env, warnings, merge) {
1798
+ let config = {};
1799
+ for (const prefix of ["OMO", harness.toUpperCase()]) {
1800
+ const codegraph = {};
1801
+ for (const [settingKey, envSuffix, kind] of CODEGRAPH_ENV_KEYS) {
1802
+ const envKey = `${prefix}_CODEGRAPH_${envSuffix}`;
1803
+ const rawValue = env[envKey];
1804
+ if (rawValue === undefined)
1805
+ continue;
1806
+ const parsed = parseEnvValue(rawValue, kind);
1807
+ if (parsed === null) {
1808
+ warnings.push(`${envKey} has invalid ${kind} value "${rawValue}"`);
1809
+ continue;
1810
+ }
1811
+ setCodegraphSetting2(codegraph, settingKey, parsed);
1812
+ }
1813
+ if (Object.keys(codegraph).length > 0) {
1814
+ config = merge(config, { codegraph });
1815
+ }
1816
+ }
1817
+ return config;
1818
+ }
1819
+
1820
+ // ../../utils/src/omo-config/resolve.ts
1821
+ import { existsSync as existsSync4 } from "node:fs";
1822
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join8, relative, resolve as resolve3 } from "node:path";
1823
+ function containsPath(parent, child) {
1824
+ const pathToChild = relative(parent, child);
1825
+ return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute2(pathToChild);
1826
+ }
1827
+ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
1828
+ const startDir = resolve3(cwd);
1829
+ const stopBeforeDir = containsPath(resolve3(homeDir), startDir) ? resolve3(homeDir) : null;
1830
+ const paths = [];
1831
+ let currentDir = startDir;
1832
+ while (true) {
1833
+ if (stopBeforeDir !== null && currentDir === stopBeforeDir)
1834
+ break;
1835
+ const configPath = join8(currentDir, ".omo", "config.jsonc");
1836
+ if (existsSync4(configPath)) {
1837
+ paths.push(configPath);
1838
+ }
1839
+ const parentDir = dirname2(currentDir);
1840
+ if (parentDir === currentDir)
1841
+ break;
1842
+ currentDir = parentDir;
1843
+ }
1844
+ return paths;
1845
+ }
1846
+ function resolveOmoConfigPaths(options) {
1847
+ const globalPath = join8(resolve3(options.homeDir), ".omo", "config.jsonc");
1848
+ const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
1849
+ return [
1850
+ { path: globalPath, scope: "global" },
1851
+ ...projectPathsFarthestFirst.map((path) => ({ path, scope: "project" }))
1852
+ ];
1853
+ }
1854
+ function toMissingSource(candidate) {
1855
+ return {
1856
+ exists: false,
1857
+ loaded: false,
1858
+ path: candidate.path,
1859
+ scope: candidate.scope
1860
+ };
1861
+ }
1862
+
1863
+ // ../../utils/src/omo-config/loader.ts
1709
1864
  function loadOmoConfig(options) {
1710
1865
  const cwd = options.cwd ?? process.cwd();
1711
- const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir5();
1866
+ const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir7();
1712
1867
  const env = options.env ?? process.env;
1713
1868
  let config = BUILT_IN_DEFAULTS;
1714
1869
  const sources = [];
1715
1870
  const warnings = [];
1716
1871
  for (const candidate of resolveOmoConfigPaths({ cwd, homeDir })) {
1717
- if (!existsSync4(candidate.path)) {
1872
+ if (!existsSync5(candidate.path)) {
1718
1873
  if (candidate.scope === "global") {
1719
1874
  sources.push(toMissingSource(candidate));
1720
1875
  }
@@ -1762,23 +1917,460 @@ function getCodexOmoConfig(options = {}) {
1762
1917
  }
1763
1918
  function resolveHomeDir(options) {
1764
1919
  const env = options.env ?? process.env;
1765
- return options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir6();
1920
+ return options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir8();
1921
+ }
1922
+
1923
+ // components/codegraph/src/cache-gc.ts
1924
+ var NON_FATAL_GC_ERROR_CODES = new Set(["EACCES", "EBUSY", "ENOENT", "ENOTEMPTY", "ENOTDIR", "EPERM"]);
1925
+ function pruneCodegraphProjectStoresBestEffort(homeDir, options = {}) {
1926
+ try {
1927
+ (options.prune ?? pruneDeadCodegraphProjectStores)({ homeDir });
1928
+ } catch (error) {
1929
+ if (!isNonFatalCodegraphGcError(error))
1930
+ throw error;
1931
+ options.debugLog?.(`CodeGraph cache GC skipped: ${error.message}`);
1932
+ }
1933
+ }
1934
+ function isNonFatalCodegraphGcError(error) {
1935
+ if (!(error instanceof Error))
1936
+ return false;
1937
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
1938
+ return typeof code === "string" && NON_FATAL_GC_ERROR_CODES.has(code);
1939
+ }
1940
+
1941
+ // components/codegraph/src/hook-sweep.ts
1942
+ import { fileURLToPath } from "node:url";
1943
+ // ../../utils/src/codegraph/process-sweeper.ts
1944
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, statSync as statSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
1945
+ import { homedir as homedir10 } from "node:os";
1946
+ import { dirname as dirname3, join as join10 } from "node:path";
1947
+
1948
+ // ../../utils/src/codegraph/process-exec.ts
1949
+ import { execFile } from "node:child_process";
1950
+
1951
+ // ../../utils/src/codegraph/process-match.ts
1952
+ import { posix, win32 } from "node:path";
1953
+ var SERVE_WRAPPER_SUFFIX = "/components/codegraph/dist/serve.js";
1954
+ var UPSTREAM_PACKAGE_SEGMENT = "/@colbymchenry/codegraph/";
1955
+ function parsePosixProcessTable(output) {
1956
+ const processes = [];
1957
+ for (const line of output.split(/\r?\n/)) {
1958
+ const match = /^\s*(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
1959
+ if (match === null)
1960
+ continue;
1961
+ const pid = Number(match[1]);
1962
+ const ppid = Number(match[2]);
1963
+ const command = match[3];
1964
+ if (!isValidProcessId(pid) || !Number.isInteger(ppid) || ppid < 0 || command === undefined)
1965
+ continue;
1966
+ processes.push({ command, pid, ppid });
1967
+ }
1968
+ return processes;
1969
+ }
1970
+ function parseWindowsProcessTable(output) {
1971
+ const parsed = parseJson(output);
1972
+ const entries = Array.isArray(parsed) ? parsed : parsed === undefined ? [] : [parsed];
1973
+ const processes = [];
1974
+ for (const entry of entries) {
1975
+ if (!isRecord3(entry))
1976
+ continue;
1977
+ const pid = numberField(entry, "ProcessId");
1978
+ const ppid = numberField(entry, "ParentProcessId");
1979
+ const command = stringField(entry, "CommandLine");
1980
+ if (pid === undefined || ppid === undefined || command === undefined || command.trim().length === 0)
1981
+ continue;
1982
+ processes.push({ command, pid, ppid });
1983
+ }
1984
+ return processes;
1985
+ }
1986
+ function selectZombieCodegraphProcesses(processes, options) {
1987
+ const platform = options.platform ?? process.platform;
1988
+ const livePids = new Set(processes.map((processInfo) => processInfo.pid));
1989
+ const roots = normalizeRoots(options.ownedRoots, platform);
1990
+ const zombies = [];
1991
+ for (const processInfo of processes) {
1992
+ const match = matchOwnedCodegraphCommand(processInfo.command, roots, platform);
1993
+ if (match === null)
1994
+ continue;
1995
+ if (!isOrphaned(processInfo, livePids))
1996
+ continue;
1997
+ zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
1998
+ }
1999
+ return zombies;
2000
+ }
2001
+ function matchOwnedCodegraphCommand(command, roots, platform) {
2002
+ const normalizedCommand = normalizeForComparison2(command, platform);
2003
+ for (const root of roots) {
2004
+ if (root.length === 0)
2005
+ continue;
2006
+ const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
2007
+ if (hasExecutableToken(normalizedCommand, serveWrapper))
2008
+ return { kind: "serve-wrapper", root };
2009
+ if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
2010
+ return { kind: "upstream-codegraph", root };
2011
+ }
2012
+ }
2013
+ return null;
2014
+ }
2015
+ function hasExecutableToken(command, expectedPath) {
2016
+ let searchFrom = 0;
2017
+ for (;; ) {
2018
+ const pathIndex = command.indexOf(expectedPath, searchFrom);
2019
+ if (pathIndex < 0)
2020
+ return false;
2021
+ const tokenStart = findTokenStart(command, pathIndex);
2022
+ const tokenEnd = findTokenEnd(command, pathIndex + expectedPath.length);
2023
+ if (command.slice(tokenStart, tokenEnd) === expectedPath && tokenLooksExecutable(command, tokenStart))
2024
+ return true;
2025
+ searchFrom = pathIndex + expectedPath.length;
2026
+ }
2027
+ }
2028
+ function tokenLooksExecutable(command, tokenStart) {
2029
+ const prefix = command.slice(0, tokenStart).trimEnd();
2030
+ if (prefix.length === 0)
2031
+ return true;
2032
+ const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
2033
+ const previousToken = prefix.slice(previousTokenStart);
2034
+ const executableName = previousToken.split("/").at(-1) ?? previousToken;
2035
+ return /^node\d*(\.exe)?$/.test(executableName) || /^bun(\.exe)?$/.test(executableName);
2036
+ }
2037
+ function upstreamPackagePathIsUnderRoot(command, root) {
2038
+ let searchFrom = 0;
2039
+ for (;; ) {
2040
+ const packageIndex = command.indexOf(UPSTREAM_PACKAGE_SEGMENT, searchFrom);
2041
+ if (packageIndex < 0)
2042
+ return false;
2043
+ const tokenStart = findTokenStart(command, packageIndex);
2044
+ if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
2045
+ return true;
2046
+ searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
2047
+ }
2048
+ }
2049
+ function findTokenStart(command, index) {
2050
+ for (let cursor = index - 1;cursor >= 0; cursor -= 1) {
2051
+ if (/\s|["']/.test(command[cursor] ?? ""))
2052
+ return cursor + 1;
2053
+ }
2054
+ return 0;
2055
+ }
2056
+ function findTokenEnd(command, index) {
2057
+ for (let cursor = index;cursor < command.length; cursor += 1) {
2058
+ if (/\s|["']/.test(command[cursor] ?? ""))
2059
+ return cursor;
2060
+ }
2061
+ return command.length;
2062
+ }
2063
+ function normalizeRoots(roots, platform) {
2064
+ const normalized = new Set;
2065
+ for (const root of roots) {
2066
+ const trimmed = root.trim();
2067
+ if (trimmed.length === 0)
2068
+ continue;
2069
+ normalized.add(normalizeForComparison2(resolvePathForPlatform(trimmed, platform), platform));
2070
+ }
2071
+ return [...normalized].sort((left, right) => right.length - left.length || left.localeCompare(right));
2072
+ }
2073
+ function resolvePathForPlatform(value, platform) {
2074
+ return platform === "win32" ? win32.resolve(value) : posix.resolve(value);
2075
+ }
2076
+ function normalizeForComparison2(value, platform) {
2077
+ const normalized = value.replaceAll("\\", "/").replace(/\/+$/, "");
2078
+ return platform === "win32" ? normalized.toLowerCase() : normalized;
2079
+ }
2080
+ function isOrphaned(processInfo, livePids) {
2081
+ return processInfo.ppid === 1 || !livePids.has(processInfo.ppid);
2082
+ }
2083
+ function isValidProcessId(value) {
2084
+ return Number.isSafeInteger(value) && value > 0;
2085
+ }
2086
+ function parseJson(text) {
2087
+ try {
2088
+ return JSON.parse(text);
2089
+ } catch (error) {
2090
+ if (error instanceof SyntaxError)
2091
+ return;
2092
+ throw error;
2093
+ }
2094
+ }
2095
+ function numberField(record, key) {
2096
+ const value = record[key];
2097
+ return typeof value === "number" && isValidProcessId(value) ? value : undefined;
2098
+ }
2099
+ function stringField(record, key) {
2100
+ const value = record[key];
2101
+ return typeof value === "string" ? value : undefined;
2102
+ }
2103
+ function isRecord3(value) {
2104
+ return typeof value === "object" && value !== null;
2105
+ }
2106
+
2107
+ // ../../utils/src/codegraph/process-exec.ts
2108
+ function enumerateCodegraphProcesses(platform = process.platform) {
2109
+ return platform === "win32" ? enumerateWindowsProcesses() : enumeratePosixProcesses();
2110
+ }
2111
+ function createDefaultCodegraphProcessKiller(platform = process.platform) {
2112
+ return platform === "win32" ? createWindowsKiller() : createPosixKiller();
2113
+ }
2114
+ function enumeratePosixProcesses() {
2115
+ return execFileText("ps", ["-eo", "pid=,ppid=,command="]).then(parsePosixProcessTable);
2116
+ }
2117
+ function enumerateWindowsProcesses() {
2118
+ const command = [
2119
+ "Get-CimInstance Win32_Process",
2120
+ "Select-Object ProcessId,ParentProcessId,CommandLine",
2121
+ "ConvertTo-Json -Compress -Depth 2"
2122
+ ].join(" | ");
2123
+ return execFileText("powershell.exe", ["-NoProfile", "-Command", command]).then(parseWindowsProcessTable);
2124
+ }
2125
+ function createPosixKiller() {
2126
+ return {
2127
+ isAlive: (pid) => {
2128
+ try {
2129
+ process.kill(pid, 0);
2130
+ return true;
2131
+ } catch (error) {
2132
+ if (!(error instanceof Error))
2133
+ throw error;
2134
+ return processKillErrorMeansAlive(error);
2135
+ }
2136
+ },
2137
+ kill: (pid) => {
2138
+ process.kill(pid, "SIGKILL");
2139
+ return Promise.resolve();
2140
+ },
2141
+ terminate: (pid) => {
2142
+ process.kill(pid, "SIGTERM");
2143
+ return Promise.resolve();
2144
+ }
2145
+ };
2146
+ }
2147
+ function createWindowsKiller() {
2148
+ return {
2149
+ isAlive: (pid) => {
2150
+ try {
2151
+ process.kill(pid, 0);
2152
+ return true;
2153
+ } catch (error) {
2154
+ if (!(error instanceof Error))
2155
+ throw error;
2156
+ return processKillErrorMeansAlive(error);
2157
+ }
2158
+ },
2159
+ kill: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T", "/F"]),
2160
+ terminate: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T"])
2161
+ };
2162
+ }
2163
+ function execFileText(command, args) {
2164
+ return new Promise((resolvePromise, reject) => {
2165
+ execFile(command, [...args], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, windowsHide: true }, (error, stdout) => {
2166
+ if (error !== null) {
2167
+ reject(error);
2168
+ return;
2169
+ }
2170
+ resolvePromise(stdout);
2171
+ });
2172
+ });
2173
+ }
2174
+ function execFileVoid(command, args) {
2175
+ return execFileText(command, args).then(() => {
2176
+ return;
2177
+ });
2178
+ }
2179
+ function processKillErrorMeansAlive(error) {
2180
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
2181
+ if (code === "ESRCH")
2182
+ return false;
2183
+ if (code === "EPERM")
2184
+ return true;
2185
+ return false;
2186
+ }
2187
+
2188
+ // ../../utils/src/codegraph/process-roots.ts
2189
+ import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as realpathSync4 } from "node:fs";
2190
+ import { homedir as homedir9 } from "node:os";
2191
+ import { join as join9, resolve as resolve4 } from "node:path";
2192
+ function discoverCodegraphOwnedRoots(options = {}) {
2193
+ const env = options.env ?? process.env;
2194
+ const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
2195
+ const roots = new Set;
2196
+ addRoot(roots, options.trustedCodegraphInstallDir);
2197
+ addRoot(roots, buildCodegraphEnv({ homeDir })[CODEGRAPH_INSTALL_DIR_ENV]);
2198
+ addRoot(roots, options.pluginRoot);
2199
+ for (const root of options.extraRoots ?? [])
2200
+ addRoot(roots, root);
2201
+ for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join9(homeDir, ".codex"))) {
2202
+ addRoot(roots, root);
2203
+ }
2204
+ return [...roots];
2205
+ }
2206
+ function readCodexPluginCacheRoots(codexHome) {
2207
+ const cacheRoot = join9(codexHome, "plugins", "cache");
2208
+ if (!existsSync6(cacheRoot))
2209
+ return [];
2210
+ const roots = [];
2211
+ for (const publisher of safeReadDir(cacheRoot)) {
2212
+ if (!OMO_CODEX_PLUGIN_CACHE_PUBLISHERS.has(publisher))
2213
+ continue;
2214
+ const omoRoot = join9(cacheRoot, publisher, "omo");
2215
+ if (!existsSync6(omoRoot))
2216
+ continue;
2217
+ for (const version of safeReadDir(omoRoot))
2218
+ roots.push(join9(omoRoot, version));
2219
+ }
2220
+ return roots;
2221
+ }
2222
+ function addRoot(roots, root) {
2223
+ if (root === undefined || root.trim().length === 0)
2224
+ return;
2225
+ const resolved = resolve4(root);
2226
+ roots.add(resolved);
2227
+ roots.add(realpathIfPossible2(resolved));
2228
+ }
2229
+ function safeReadDir(path) {
2230
+ try {
2231
+ return readdirSync2(path, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
2232
+ } catch (error) {
2233
+ if (isNonFatalFsError(error))
2234
+ return [];
2235
+ throw error;
2236
+ }
2237
+ }
2238
+ function realpathIfPossible2(path) {
2239
+ try {
2240
+ return realpathSync4(path);
2241
+ } catch (error) {
2242
+ if (error instanceof Error)
2243
+ return resolve4(path);
2244
+ throw error;
2245
+ }
2246
+ }
2247
+ function isNonFatalFsError(error) {
2248
+ if (!(error instanceof Error))
2249
+ return false;
2250
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
2251
+ return typeof code === "string" && ["EACCES", "ENOENT", "ENOTDIR", "EPERM"].includes(code);
2252
+ }
2253
+ var OMO_CODEX_PLUGIN_CACHE_PUBLISHERS = new Set(["sisyphuslabs"]);
2254
+
2255
+ // ../../utils/src/codegraph/process-sweeper.ts
2256
+ var DEFAULT_GRACE_MS = 2000;
2257
+ var DEFAULT_THROTTLE_MS = 60 * 60 * 1000;
2258
+ var SWEEP_STAMP_FILE = "zombie-sweep.stamp";
2259
+ async function sweepCodegraphZombies(options = {}) {
2260
+ const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
2261
+ const stampFile = join10(codegraphDataRoot(homeDir), SWEEP_STAMP_FILE);
2262
+ const nowMs = options.nowMs ?? Date.now();
2263
+ const dryRun = options.dryRun === true;
2264
+ const ownedRoots = options.ownedRoots ?? discoverCodegraphOwnedRoots(options);
2265
+ if (options.force !== true && isSweepThrottled(stampFile, nowMs, options.throttleMs ?? DEFAULT_THROTTLE_MS)) {
2266
+ return emptyResult("throttled", dryRun, ownedRoots, stampFile);
2267
+ }
2268
+ try {
2269
+ const provider = options.processProvider ?? (() => enumerateCodegraphProcesses(options.platform));
2270
+ const candidates = selectZombieCodegraphProcesses(await provider(), {
2271
+ ownedRoots,
2272
+ ...options.platform === undefined ? {} : { platform: options.platform }
2273
+ });
2274
+ const result = dryRun ? { failed: [], killed: [] } : await killCandidates(candidates, options.killer ?? createDefaultCodegraphProcessKiller(options.platform), options);
2275
+ if (!dryRun)
2276
+ writeSweepStamp(stampFile, nowMs);
2277
+ return { action: "swept", candidates, dryRun, failed: result.failed, killed: result.killed, ownedRoots, stampFile };
2278
+ } catch (error) {
2279
+ options.log?.(`CodeGraph zombie sweep skipped: ${error instanceof Error ? error.message : String(error)}`);
2280
+ return emptyResult("failed", dryRun, ownedRoots, stampFile);
2281
+ }
2282
+ }
2283
+ async function killCandidates(candidates, killer, options) {
2284
+ const failed = [];
2285
+ const killed = [];
2286
+ for (const candidate of candidates) {
2287
+ const terminated = await safelyTerminate(candidate.pid, killer, failed, options.log);
2288
+ if (!terminated)
2289
+ continue;
2290
+ await delay(options.graceMs ?? DEFAULT_GRACE_MS);
2291
+ if (!await killer.isAlive(candidate.pid)) {
2292
+ killed.push(candidate);
2293
+ continue;
2294
+ }
2295
+ if (await safelyKill(candidate.pid, killer, failed, options.log))
2296
+ killed.push(candidate);
2297
+ }
2298
+ return { failed, killed };
2299
+ }
2300
+ async function safelyTerminate(pid, killer, failed, log) {
2301
+ try {
2302
+ await killer.terminate(pid);
2303
+ return true;
2304
+ } catch (error) {
2305
+ const message = error instanceof Error ? error.message : String(error);
2306
+ failed.push({ error: message, pid, stage: "terminate" });
2307
+ log?.(`CodeGraph zombie sweep failed to terminate pid ${pid}: ${message}`);
2308
+ return false;
2309
+ }
2310
+ }
2311
+ async function safelyKill(pid, killer, failed, log) {
2312
+ try {
2313
+ await killer.kill(pid);
2314
+ return true;
2315
+ } catch (error) {
2316
+ const message = error instanceof Error ? error.message : String(error);
2317
+ failed.push({ error: message, pid, stage: "kill" });
2318
+ log?.(`CodeGraph zombie sweep failed to kill pid ${pid}: ${message}`);
2319
+ return false;
2320
+ }
2321
+ }
2322
+ function isSweepThrottled(stampFile, nowMs, throttleMs) {
2323
+ if (!existsSync7(stampFile))
2324
+ return false;
2325
+ return nowMs - statSync2(stampFile).mtimeMs < throttleMs;
2326
+ }
2327
+ function writeSweepStamp(stampFile, nowMs) {
2328
+ mkdirSync2(dirname3(stampFile), { recursive: true });
2329
+ writeFileSync2(stampFile, `${new Date(nowMs).toISOString()}
2330
+ `);
2331
+ const stampDate = new Date(nowMs);
2332
+ utimesSync(stampFile, stampDate, stampDate);
2333
+ }
2334
+ function emptyResult(action, dryRun, ownedRoots, stampFile) {
2335
+ return { action, candidates: [], dryRun, failed: [], killed: [], ownedRoots, stampFile };
2336
+ }
2337
+ function delay(ms) {
2338
+ if (ms <= 0)
2339
+ return Promise.resolve();
2340
+ return new Promise((resolvePromise) => {
2341
+ setTimeout(resolvePromise, ms);
2342
+ });
2343
+ }
2344
+ // components/codegraph/src/hook-sweep.ts
2345
+ async function sweepCodegraphZombiesBestEffort(options, sweep = sweepCodegraphZombies) {
2346
+ try {
2347
+ await sweep({
2348
+ ...options,
2349
+ pluginRoot: defaultPluginRoot(),
2350
+ ...options.log === undefined ? {} : { log: options.log }
2351
+ });
2352
+ } catch (error) {
2353
+ options.log?.(`CodeGraph zombie sweep skipped: ${error instanceof Error ? error.message : String(error)}`);
2354
+ }
2355
+ }
2356
+ function defaultPluginRoot() {
2357
+ return fileURLToPath(new URL("../../..", import.meta.url));
1766
2358
  }
1767
2359
 
1768
2360
  // components/codegraph/src/session-start-worker.ts
1769
- import { execFile as execFile2 } from "node:child_process";
1770
- import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "node:fs";
1771
- import { homedir as homedir8 } from "node:os";
1772
- import { extname, join as join7 } from "node:path";
2361
+ import { execFile as execFile3 } from "node:child_process";
2362
+ import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "node:fs";
2363
+ import { homedir as homedir12 } from "node:os";
2364
+ import { extname, join as join12 } from "node:path";
1773
2365
  import { cwd as processCwd, env as processEnv, execPath as processExecPath, stderr as processStderr } from "node:process";
1774
2366
 
1775
2367
  // ../../utils/src/codegraph/provision.ts
1776
2368
  import { createHash as createHash2, randomUUID } from "node:crypto";
1777
- import { execFile } from "node:child_process";
2369
+ import { execFile as execFile2 } from "node:child_process";
1778
2370
  import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
1779
- import { existsSync as existsSync5 } from "node:fs";
1780
- import { homedir as homedir7, hostname } from "node:os";
1781
- import { basename as basename3, join as join6 } from "node:path";
2371
+ import { existsSync as existsSync8 } from "node:fs";
2372
+ import { homedir as homedir11, hostname } from "node:os";
2373
+ import { basename as basename3, join as join11 } from "node:path";
1782
2374
  import { promisify } from "node:util";
1783
2375
 
1784
2376
  // ../../utils/src/codegraph/manifest.ts
@@ -1822,15 +2414,15 @@ var CODEGRAPH_PROVISION_MANIFEST = {
1822
2414
  var DEFAULT_LOCK_WAIT_MS = 5000;
1823
2415
  var DEFAULT_LOCK_STALE_MS = 120000;
1824
2416
  var DEFAULT_DOWNLOAD_TIMEOUT_MS = 60000;
1825
- var execFileAsync = promisify(execFile);
2417
+ var execFileAsync = promisify(execFile2);
1826
2418
  function platformKey() {
1827
2419
  return `${process.platform}-${process.arch}`;
1828
2420
  }
1829
2421
  function markerPath(installDir, version) {
1830
- return join6(installDir, ".provisioned", `codegraph-${version}.json`);
2422
+ return join11(installDir, ".provisioned", `codegraph-${version}.json`);
1831
2423
  }
1832
2424
  function defaultInstallDir() {
1833
- return join6(homedir7(), ".omo", "codegraph");
2425
+ return join11(homedir11(), ".omo", "codegraph");
1834
2426
  }
1835
2427
  function sha256(bytes) {
1836
2428
  return createHash2("sha256").update(bytes).digest("hex");
@@ -1850,7 +2442,7 @@ async function removeEmptyDirectory(path) {
1850
2442
  }
1851
2443
  }
1852
2444
  function sleep(ms) {
1853
- return new Promise((resolve3) => setTimeout(resolve3, ms));
2445
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
1854
2446
  }
1855
2447
  async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
1856
2448
  const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
@@ -1864,7 +2456,7 @@ function forcedBadChecksumOptions(options) {
1864
2456
  const key = options.platformKey ?? platformKey();
1865
2457
  return {
1866
2458
  downloader: async () => new TextEncoder().encode("checksum mismatch"),
1867
- installDir: options.installDir ?? join6(options.lockDir, "codegraph-force-bad-checksum"),
2459
+ installDir: options.installDir ?? join11(options.lockDir, "codegraph-force-bad-checksum"),
1868
2460
  manifest: {
1869
2461
  assets: {
1870
2462
  [key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
@@ -1875,13 +2467,13 @@ function forcedBadChecksumOptions(options) {
1875
2467
  };
1876
2468
  }
1877
2469
  async function readMarker(path) {
1878
- if (!existsSync5(path))
2470
+ if (!existsSync8(path))
1879
2471
  return null;
1880
2472
  try {
1881
2473
  const raw = JSON.parse(await readFile(path, "utf8"));
1882
2474
  if (typeof raw === "object" && raw !== null && "binPath" in raw) {
1883
2475
  const value = raw.binPath;
1884
- return typeof value === "string" && existsSync5(value) ? value : null;
2476
+ return typeof value === "string" && existsSync8(value) ? value : null;
1885
2477
  }
1886
2478
  return null;
1887
2479
  } catch (error) {
@@ -1892,7 +2484,7 @@ async function readMarker(path) {
1892
2484
  }
1893
2485
  async function acquireLock(lockPath, waitMs, staleMs) {
1894
2486
  const startedAt = Date.now();
1895
- await mkdir(join6(lockPath, ".."), { recursive: true });
2487
+ await mkdir(join11(lockPath, ".."), { recursive: true });
1896
2488
  while (Date.now() - startedAt <= waitMs) {
1897
2489
  try {
1898
2490
  await mkdir(lockPath);
@@ -1917,24 +2509,24 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
1917
2509
  const roots = await readdir(extractDir);
1918
2510
  if (roots.length !== 1)
1919
2511
  throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
1920
- const bundleDir = join6(extractDir, roots[0] ?? "");
2512
+ const bundleDir = join11(extractDir, roots[0] ?? "");
1921
2513
  const bundleEntries = await readdir(bundleDir);
1922
2514
  await mkdir(installDir, { recursive: true });
1923
2515
  for (const entry of bundleEntries) {
1924
- await rm(join6(installDir, entry), { force: true, recursive: true });
1925
- await rename(join6(bundleDir, entry), join6(installDir, entry));
2516
+ await rm(join11(installDir, entry), { force: true, recursive: true });
2517
+ await rename(join11(bundleDir, entry), join11(installDir, entry));
1926
2518
  }
1927
- const destination = join6(installDir, "bin", executableName);
1928
- if (!existsSync5(destination))
2519
+ const destination = join11(installDir, "bin", executableName);
2520
+ if (!existsSync8(destination))
1929
2521
  throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
1930
2522
  await chmod(destination, 493);
1931
2523
  return destination;
1932
2524
  }
1933
2525
  async function installAsset(layout) {
1934
2526
  const { asset, downloader, installDir, version } = layout;
1935
- const stagingDir = join6(installDir, ".staging", randomUUID());
1936
- const archivePath = join6(stagingDir, basename3(asset.url));
1937
- const extractDir = join6(stagingDir, "extract");
2527
+ const stagingDir = join11(installDir, ".staging", randomUUID());
2528
+ const archivePath = join11(stagingDir, basename3(asset.url));
2529
+ const extractDir = join11(stagingDir, "extract");
1938
2530
  try {
1939
2531
  await mkdir(extractDir, { recursive: true });
1940
2532
  const bytes = await downloader(asset);
@@ -1948,13 +2540,13 @@ async function installAsset(layout) {
1948
2540
  await writeFile(archivePath, bytes);
1949
2541
  await extractTarGz(archivePath, extractDir);
1950
2542
  const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
1951
- await mkdir(join6(installDir, ".provisioned"), { recursive: true });
2543
+ await mkdir(join11(installDir, ".provisioned"), { recursive: true });
1952
2544
  await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
1953
2545
  `);
1954
2546
  return destination;
1955
2547
  } finally {
1956
2548
  await rm(stagingDir, { force: true, recursive: true });
1957
- await removeEmptyDirectory(join6(installDir, ".staging"));
2549
+ await removeEmptyDirectory(join11(installDir, ".staging"));
1958
2550
  }
1959
2551
  }
1960
2552
  async function ensureCodegraphProvisioned(options) {
@@ -1967,7 +2559,7 @@ async function ensureCodegraphProvisioned(options) {
1967
2559
  const existing = await readMarker(marker);
1968
2560
  if (existing !== null)
1969
2561
  return { binPath: existing, provisioned: true };
1970
- const lockPath = join6(options.lockDir, `codegraph-${hostname()}.lock`);
2562
+ const lockPath = join11(options.lockDir, `codegraph-${hostname()}.lock`);
1971
2563
  const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
1972
2564
  if (release === null)
1973
2565
  return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
@@ -2057,8 +2649,8 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
2057
2649
  return { kind: "unsupported-node" };
2058
2650
  if (config.auto_provision === false)
2059
2651
  return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
2060
- const installDir = trustedInstallDir ?? join7(homeDir, ".omo", "codegraph");
2061
- const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join7(installDir, ".locks"), version: CODEGRAPH_VERSION });
2652
+ const installDir = trustedInstallDir ?? join12(homeDir, ".omo", "codegraph");
2653
+ const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join12(installDir, ".locks"), version: CODEGRAPH_VERSION });
2062
2654
  if (!provisioned.provisioned || provisioned.binPath === undefined) {
2063
2655
  return { error: provisioned.error ?? "provisioning did not produce a binary", kind: "unavailable", source: resolved.source };
2064
2656
  }
@@ -2078,7 +2670,7 @@ function decideStartupAction(status) {
2078
2670
  ${status.stderr ?? ""}`.toLowerCase();
2079
2671
  if (text.includes("not initialized") || text.includes("uninitialized"))
2080
2672
  return { kind: "init" };
2081
- const initialized = jsonSaysInitialized(parseJson(status.stdout));
2673
+ const initialized = jsonSaysInitialized(parseJson2(status.stdout));
2082
2674
  if (initialized === false)
2083
2675
  return { kind: "init" };
2084
2676
  if (initialized === true)
@@ -2088,7 +2680,7 @@ ${status.stderr ?? ""}`.toLowerCase();
2088
2680
  return { kind: "sync" };
2089
2681
  }
2090
2682
  function jsonSaysInitialized(value) {
2091
- if (!isRecord3(value))
2683
+ if (!isRecord4(value))
2092
2684
  return;
2093
2685
  const initialized = value["initialized"] ?? value["isInitialized"] ?? value["ready"];
2094
2686
  if (typeof initialized === "boolean")
@@ -2106,7 +2698,7 @@ function jsonSaysInitialized(value) {
2106
2698
  async function runCodegraphCommand(projectRoot, command, args, options) {
2107
2699
  const invocation = resolveCodegraphCommandInvocation(command, args);
2108
2700
  return new Promise((resolvePromise) => {
2109
- execFile2(invocation.command, [...invocation.args], { cwd: projectRoot, encoding: "utf8", env: buildCodegraphChildEnv({ ambientEnv: processEnv, codegraphEnv: options.env }), maxBuffer: 1024 * 1024, timeout: options.timeoutMs, windowsHide: true }, (error, stdout, stderr) => {
2701
+ execFile3(invocation.command, [...invocation.args], { cwd: projectRoot, encoding: "utf8", env: buildCodegraphChildEnv({ ambientEnv: processEnv, codegraphEnv: options.env }), maxBuffer: 1024 * 1024, timeout: options.timeoutMs, windowsHide: true }, (error, stdout, stderr) => {
2110
2702
  if (error === null) {
2111
2703
  resolvePromise({ exitCode: 0, stderr: toOutputText(stderr), stdout: toOutputText(stdout), timedOut: false });
2112
2704
  return;
@@ -2126,9 +2718,9 @@ function resolveCodegraphCommandInvocation(command, args, platform = process.pla
2126
2718
  return { args: ["/d", "/s", "/c", command, ...args], command: "cmd.exe" };
2127
2719
  }
2128
2720
  function appendOutcome(homeDir, outcome) {
2129
- const logDir = join7(homeDir, ".omo", "codegraph");
2130
- mkdirSync2(logDir, { recursive: true });
2131
- appendFileSync2(join7(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
2721
+ const logDir = join12(homeDir, ".omo", "codegraph");
2722
+ mkdirSync3(logDir, { recursive: true });
2723
+ appendFileSync2(join12(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
2132
2724
  `);
2133
2725
  }
2134
2726
  function safeLogOutcome(logOutcome, outcome) {
@@ -2145,8 +2737,8 @@ function safeLogOutcome(logOutcome, outcome) {
2145
2737
  function provisionedBinFromInstallDir(installDir) {
2146
2738
  if (installDir === undefined)
2147
2739
  return null;
2148
- const candidate = join7(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2149
- return existsSync6(candidate) ? candidate : null;
2740
+ const candidate = join12(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2741
+ return existsSync9(candidate) ? candidate : null;
2150
2742
  }
2151
2743
  function resolveExitCode(error) {
2152
2744
  if ("code" in error && typeof error.code === "number")
@@ -2157,9 +2749,9 @@ function toOutputText(value) {
2157
2749
  return Buffer.isBuffer(value) ? value.toString("utf8") : value;
2158
2750
  }
2159
2751
  function resolveHomeDir2(env) {
2160
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir8();
2752
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir12();
2161
2753
  }
2162
- function parseJson(text) {
2754
+ function parseJson2(text) {
2163
2755
  try {
2164
2756
  return JSON.parse(text);
2165
2757
  } catch (error) {
@@ -2168,7 +2760,7 @@ function parseJson(text) {
2168
2760
  throw error;
2169
2761
  }
2170
2762
  }
2171
- function isRecord3(value) {
2763
+ function isRecord4(value) {
2172
2764
  return typeof value === "object" && value !== null;
2173
2765
  }
2174
2766
 
@@ -2187,9 +2779,24 @@ async function executeCodegraphSessionStartHook(options = {}) {
2187
2779
  const projectRoot = resolveProjectRoot(input, options.cwd ?? processCwd2());
2188
2780
  const homeDir = resolveHomeDir3(env);
2189
2781
  const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
2782
+ pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
2783
+ await sweepCodegraphZombiesBestEffort({
2784
+ env,
2785
+ homeDir,
2786
+ ...config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir },
2787
+ log: writeDebugLog
2788
+ }, options.sweepZombies);
2190
2789
  if (config.codegraph?.enabled === false) {
2191
2790
  return { action: "skipped-disabled", exitCode: 0 };
2192
2791
  }
2792
+ const excludedRoots = config.codegraph?.excluded_roots;
2793
+ const exclusion = shouldExcludeCodegraphProject(projectRoot, {
2794
+ homeDir,
2795
+ ...excludedRoots === undefined ? {} : { excludedRoots }
2796
+ });
2797
+ if (exclusion.excluded) {
2798
+ return { action: "skipped-excluded", exitCode: 0 };
2799
+ }
2193
2800
  const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
2194
2801
  env,
2195
2802
  homeDir,
@@ -2231,7 +2838,7 @@ async function isCodegraphProjectInitialized(options) {
2231
2838
  }
2232
2839
  function runStatusProbe(projectRoot, command, args, env) {
2233
2840
  return new Promise((resolveProbe) => {
2234
- execFile3(command, [...args], {
2841
+ execFile4(command, [...args], {
2235
2842
  cwd: projectRoot,
2236
2843
  encoding: "utf8",
2237
2844
  env,
@@ -2248,8 +2855,8 @@ function runStatusProbe(projectRoot, command, args, env) {
2248
2855
  });
2249
2856
  }
2250
2857
  function codegraphStatusSaysInitialized(stdout) {
2251
- const parsed = parseJson2(stdout);
2252
- if (!isRecord4(parsed))
2858
+ const parsed = parseJson3(stdout);
2859
+ if (!isRecord5(parsed))
2253
2860
  return false;
2254
2861
  const initialized = parsed["initialized"] ?? parsed["isInitialized"] ?? parsed["ready"];
2255
2862
  if (typeof initialized === "boolean")
@@ -2263,7 +2870,7 @@ function codegraphStatusSaysInitialized(stdout) {
2263
2870
  function provisionedBinFromInstallDir2(installDir) {
2264
2871
  if (installDir === undefined)
2265
2872
  return null;
2266
- return join8(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2873
+ return join13(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2267
2874
  }
2268
2875
  async function executeCodegraphPostToolUseHook(options = {}) {
2269
2876
  const env = options.env ?? processEnv2;
@@ -2275,9 +2882,9 @@ async function executeCodegraphPostToolUseHook(options = {}) {
2275
2882
  return { action: "emitted-guidance", exitCode: 0 };
2276
2883
  }
2277
2884
  function runCodegraphPostToolUseHook(input, options = {}) {
2278
- const toolName = isRecord4(input) ? input["tool_name"] : undefined;
2279
- const cwd = isRecord4(input) ? input["cwd"] : undefined;
2280
- const toolOutput = isRecord4(input) ? input["tool_response"] ?? input["tool_output"] ?? input["response"] : input;
2885
+ const toolName = isRecord5(input) ? input["tool_name"] : undefined;
2886
+ const cwd = isRecord5(input) ? input["cwd"] : undefined;
2887
+ const toolOutput = isRecord5(input) ? input["tool_response"] ?? input["tool_output"] ?? input["response"] : input;
2281
2888
  const guidance = buildCodegraphInitGuidanceForToolResult({ cwd, toolName, toolOutput }, options);
2282
2889
  if (guidance === null)
2283
2890
  return "";
@@ -2299,12 +2906,18 @@ function writeHookJson(stdout) {
2299
2906
  stdout.write(`${JSON.stringify(output)}
2300
2907
  `);
2301
2908
  }
2909
+ function writeDebugLog(message) {
2910
+ if (processEnv2["OMO_CODEGRAPH_DEBUG"] !== "1")
2911
+ return;
2912
+ processStderr2.write(`${message}
2913
+ `);
2914
+ }
2302
2915
  function spawnDetachedWorker(invocation) {
2303
2916
  const child = spawn(invocation.command, [...invocation.args], { detached: true, env: invocation.env, stdio: "ignore" });
2304
2917
  child.unref();
2305
2918
  }
2306
2919
  function resolveHomeDir3(env) {
2307
- return env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
2920
+ return env["HOME"] ?? env["USERPROFILE"] ?? homedir13();
2308
2921
  }
2309
2922
  function resolveExitCode2(error) {
2310
2923
  if ("code" in error && typeof error.code === "number")
@@ -2315,7 +2928,7 @@ function toOutputText2(value) {
2315
2928
  return Buffer.isBuffer(value) ? value.toString("utf8") : value;
2316
2929
  }
2317
2930
  function resolveProjectRoot(input, fallback) {
2318
- if (!isRecord4(input))
2931
+ if (!isRecord5(input))
2319
2932
  return fallback;
2320
2933
  const cwd = input["cwd"];
2321
2934
  return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : fallback;
@@ -2328,9 +2941,9 @@ async function readHookInput(stdin) {
2328
2941
  text += typeof chunk === "string" ? chunk : String(chunk);
2329
2942
  if (text.trim().length === 0)
2330
2943
  return;
2331
- return parseJson2(text);
2944
+ return parseJson3(text);
2332
2945
  }
2333
- function parseJson2(text) {
2946
+ function parseJson3(text) {
2334
2947
  try {
2335
2948
  return JSON.parse(text);
2336
2949
  } catch (error) {
@@ -2339,25 +2952,25 @@ function parseJson2(text) {
2339
2952
  throw error;
2340
2953
  }
2341
2954
  }
2342
- function isRecord4(value) {
2955
+ function isRecord5(value) {
2343
2956
  return typeof value === "object" && value !== null;
2344
2957
  }
2345
2958
  function defaultWorkerCliPath() {
2346
- return fileURLToPath(import.meta.url);
2959
+ return fileURLToPath2(import.meta.url);
2347
2960
  }
2348
2961
 
2349
2962
  // components/codegraph/src/serve.ts
2350
- import { existsSync as existsSync7, realpathSync as realpathSync2 } from "node:fs";
2351
- import { homedir as homedir10 } from "node:os";
2352
- import { basename as basename4, join as join9, resolve as resolve3 } from "node:path";
2963
+ import { existsSync as existsSync10, realpathSync as realpathSync5 } from "node:fs";
2964
+ import { homedir as homedir14 } from "node:os";
2965
+ import { basename as basename4, join as join14, resolve as resolve5 } from "node:path";
2353
2966
  import {
2354
2967
  cwd as processCwd3,
2355
2968
  env as processEnv3,
2356
2969
  stdin as processStdin2,
2357
- stderr as processStderr2,
2970
+ stderr as processStderr3,
2358
2971
  stdout as processStdout2
2359
2972
  } from "node:process";
2360
- import { fileURLToPath as fileURLToPath2 } from "node:url";
2973
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
2361
2974
 
2362
2975
  // components/codegraph/src/mcp-bridge.ts
2363
2976
  import { spawn as spawn2 } from "node:child_process";
@@ -2834,11 +3447,13 @@ var CODEGRAPH_SKIP_HINT = `CodeGraph MCP skipped: codegraph binary not found. In
2834
3447
  `;
2835
3448
  var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.
2836
3449
  `;
3450
+ var CODEGRAPH_EXCLUDED_HINT = `CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.
3451
+ `;
2837
3452
  var CODEGRAPH_VERSION2 = "1.0.1";
2838
3453
  var PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"];
2839
3454
  async function runCodegraphServe(options = {}) {
2840
3455
  const env = options.env ?? processEnv3;
2841
- const homeDir = options.homeDir ?? homedir10();
3456
+ const homeDir = options.homeDir ?? homedir14();
2842
3457
  const wrapperCwd = options.cwd ?? processCwd3();
2843
3458
  const projectCwd = resolveProjectCwd(env, wrapperCwd);
2844
3459
  const config = options.config ?? getCodexOmoConfig({ cwd: projectCwd, env, homeDir });
@@ -2846,6 +3461,14 @@ async function runCodegraphServe(options = {}) {
2846
3461
  if (codegraphConfig.enabled === false) {
2847
3462
  return runUnavailableMcp(CODEGRAPH_DISABLED_HINT, options);
2848
3463
  }
3464
+ const excludedRoots = codegraphConfig.excluded_roots;
3465
+ const exclusion = shouldExcludeCodegraphProject(projectCwd, {
3466
+ homeDir,
3467
+ ...excludedRoots === undefined ? {} : { excludedRoots }
3468
+ });
3469
+ if (exclusion.excluded) {
3470
+ return runUnavailableMcp(CODEGRAPH_EXCLUDED_HINT, options);
3471
+ }
2849
3472
  const trustedInstallDir = config.trustedCodegraphInstallDir;
2850
3473
  const resolutionOptions = {
2851
3474
  env,
@@ -2854,7 +3477,7 @@ async function runCodegraphServe(options = {}) {
2854
3477
  };
2855
3478
  let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
2856
3479
  const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
2857
- if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync7)) {
3480
+ if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync10)) {
2858
3481
  if (resolution.source === "path" && !nodeSupport.supported) {
2859
3482
  return runUnavailableMcp(buildCodegraphNodeSkipHint(nodeSupport), options);
2860
3483
  }
@@ -2881,12 +3504,12 @@ async function runCodegraphServe(options = {}) {
2881
3504
  env: mergedEnv,
2882
3505
  input: options.stdin ?? processStdin2,
2883
3506
  output: options.stdout ?? processStdout2,
2884
- stderr: options.stderr ?? processStderr2,
3507
+ stderr: options.stderr ?? processStderr3,
2885
3508
  stdio: "pipe"
2886
3509
  });
2887
3510
  }
2888
3511
  async function runUnavailableMcp(reason, options) {
2889
- (options.stderr ?? processStderr2).write(reason);
3512
+ (options.stderr ?? processStderr3).write(reason);
2890
3513
  await runUnavailableCodegraphMcpServer({
2891
3514
  input: options.stdin ?? processStdin2,
2892
3515
  output: options.stdout ?? processStdout2,
@@ -2900,10 +3523,10 @@ async function provisionMissingCodegraph(options) {
2900
3523
  return null;
2901
3524
  if (options.config.auto_provision === false)
2902
3525
  return null;
2903
- const installDir = options.trustedInstallDir ?? join9(options.homeDir, ".omo", "codegraph");
3526
+ const installDir = options.trustedInstallDir ?? join14(options.homeDir, ".omo", "codegraph");
2904
3527
  const result = await options.ensureProvisioned({
2905
3528
  installDir,
2906
- lockDir: join9(installDir, ".locks"),
3529
+ lockDir: join14(installDir, ".locks"),
2907
3530
  version: CODEGRAPH_VERSION2
2908
3531
  });
2909
3532
  if (!result.provisioned || result.binPath === undefined)
@@ -2921,7 +3544,7 @@ function looksLikePath2(command) {
2921
3544
  return command.includes("/") || command.includes("\\");
2922
3545
  }
2923
3546
  function codegraphEnvForConfig2(trustedInstallDir, homeDir, buildEnv) {
2924
- const env = buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir });
3547
+ const env = { ...buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir }), [CODEGRAPH_NO_DAEMON_ENV]: "1" };
2925
3548
  return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
2926
3549
  }
2927
3550
  function resolveProjectCwd(env, fallback) {
@@ -2929,24 +3552,24 @@ function resolveProjectCwd(env, fallback) {
2929
3552
  const candidate = env[key]?.trim();
2930
3553
  if (candidate === undefined || candidate.length === 0)
2931
3554
  continue;
2932
- const resolved = resolve3(candidate);
2933
- if (existsSync7(resolved))
3555
+ const resolved = resolve5(candidate);
3556
+ if (existsSync10(resolved))
2934
3557
  return resolved;
2935
3558
  }
2936
- return resolve3(fallback);
3559
+ return resolve5(fallback);
2937
3560
  }
2938
3561
  function provisionedBinFromInstallDir3(installDir) {
2939
3562
  if (installDir === undefined)
2940
3563
  return null;
2941
- const candidate = join9(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
2942
- return existsSync7(candidate) ? candidate : null;
3564
+ const candidate = join14(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
3565
+ return existsSync10(candidate) ? candidate : null;
2943
3566
  }
2944
3567
  async function runCodegraphServeCli() {
2945
3568
  process.exitCode = await runCodegraphServe();
2946
3569
  }
2947
3570
  if (isDirectInvocation(process.argv[1])) {
2948
3571
  runCodegraphServeCli().catch((error) => {
2949
- processStderr2.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
3572
+ processStderr3.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
2950
3573
  `);
2951
3574
  process.exitCode = 1;
2952
3575
  });
@@ -2954,11 +3577,68 @@ if (isDirectInvocation(process.argv[1])) {
2954
3577
  function isDirectInvocation(argvPath) {
2955
3578
  if (argvPath === undefined)
2956
3579
  return false;
2957
- const modulePath = fileURLToPath2(import.meta.url);
3580
+ const modulePath = fileURLToPath3(import.meta.url);
2958
3581
  const moduleName = basename4(modulePath);
2959
3582
  if (moduleName !== "serve.js" && moduleName !== "serve.ts")
2960
3583
  return false;
2961
- return realpathSync2(resolve3(argvPath)) === realpathSync2(modulePath);
3584
+ return realpathSync5(resolve5(argvPath)) === realpathSync5(modulePath);
3585
+ }
3586
+
3587
+ // components/codegraph/src/sweep-cli.ts
3588
+ async function runCodegraphSweepCli(options = {}) {
3589
+ const args = parseSweepCliArgs(options.argv ?? process.argv);
3590
+ const result = await sweepCodegraphZombies({
3591
+ ...options,
3592
+ dryRun: args.dryRun,
3593
+ extraRoots: args.roots,
3594
+ force: args.force,
3595
+ ...args.roots.length > 0 ? { ownedRoots: args.roots } : {}
3596
+ });
3597
+ writeSweepReport(options.stdout ?? process.stdout, result);
3598
+ return result.action === "failed" ? 1 : 0;
3599
+ }
3600
+ function parseSweepCliArgs(argv) {
3601
+ const roots = [];
3602
+ let dryRun = false;
3603
+ let force = false;
3604
+ for (let index = 3;index < argv.length; index += 1) {
3605
+ const arg = argv[index];
3606
+ if (arg === "--dry-run") {
3607
+ dryRun = true;
3608
+ continue;
3609
+ }
3610
+ if (arg === "--force") {
3611
+ force = true;
3612
+ continue;
3613
+ }
3614
+ if (arg === "--root") {
3615
+ const value = argv[index + 1];
3616
+ if (value !== undefined && value.trim().length > 0)
3617
+ roots.push(value);
3618
+ index += 1;
3619
+ }
3620
+ }
3621
+ return { dryRun, force, roots };
3622
+ }
3623
+ function writeSweepReport(stdout, result) {
3624
+ stdout.write(`${JSON.stringify({
3625
+ action: result.action,
3626
+ candidates: result.candidates.map(formatProcess),
3627
+ dryRun: result.dryRun,
3628
+ failed: result.failed,
3629
+ killed: result.killed.map(formatProcess),
3630
+ ownedRoots: result.ownedRoots,
3631
+ stampFile: result.stampFile
3632
+ })}
3633
+ `);
3634
+ }
3635
+ function formatProcess(processInfo) {
3636
+ return {
3637
+ matchKind: processInfo.matchKind,
3638
+ matchedRoot: processInfo.matchedRoot,
3639
+ pid: processInfo.pid,
3640
+ ppid: processInfo.ppid
3641
+ };
2962
3642
  }
2963
3643
 
2964
3644
  // components/codegraph/src/cli.ts
@@ -2966,6 +3646,14 @@ async function runCodegraphCli(options = {}) {
2966
3646
  const argv = options.argv ?? process.argv;
2967
3647
  const command = argv[2];
2968
3648
  const subcommand = argv[3];
3649
+ if (command === "sweep") {
3650
+ return runCodegraphSweepCli({
3651
+ ...options.sweepOptions,
3652
+ argv,
3653
+ ...options.env === undefined ? {} : { env: options.env },
3654
+ ...options.stdout === undefined ? {} : { stdout: options.stdout }
3655
+ });
3656
+ }
2969
3657
  if (command === "hook" && subcommand === "session-start") {
2970
3658
  return runCodegraphSessionStartHook(options);
2971
3659
  }
@@ -2991,7 +3679,7 @@ async function runCodegraphCli(options = {}) {
2991
3679
  }
2992
3680
  if (isDirectInvocation2(process.argv[1])) {
2993
3681
  runCodegraphCli().catch((error) => {
2994
- processStderr3.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
3682
+ processStderr4.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
2995
3683
  `);
2996
3684
  process.exitCode = 1;
2997
3685
  });
@@ -2999,11 +3687,11 @@ if (isDirectInvocation2(process.argv[1])) {
2999
3687
  function isDirectInvocation2(argvPath) {
3000
3688
  if (argvPath === undefined)
3001
3689
  return false;
3002
- const modulePath = fileURLToPath3(import.meta.url);
3690
+ const modulePath = fileURLToPath4(import.meta.url);
3003
3691
  const moduleName = basename5(modulePath);
3004
3692
  if (moduleName !== "cli.js" && moduleName !== "cli.ts")
3005
3693
  return false;
3006
- return realpathSync3(resolve4(argvPath)) === realpathSync3(modulePath);
3694
+ return realpathSync6(resolve6(argvPath)) === realpathSync6(modulePath);
3007
3695
  }
3008
3696
  export {
3009
3697
  runCodegraphCli