oh-my-opencode 5.0.0-beta.34 → 5.0.0-beta.35

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 (217) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +1 -3
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +1 -1
  3. package/.agents/skills/tech-debt-audit/SKILL.md +6 -76
  4. package/README.ja.md +1 -1
  5. package/README.ko.md +1 -1
  6. package/README.md +1 -1
  7. package/README.ru.md +1 -1
  8. package/README.zh-cn.md +1 -1
  9. package/THIRD-PARTY-NOTICES.md +27 -99
  10. package/dist/cli/index.js +48342 -48539
  11. package/dist/cli-node/index.js +49017 -49214
  12. package/dist/config/index.d.ts +1 -1
  13. package/dist/config/schema/hooks.d.ts +0 -1
  14. package/dist/config/schema/oh-my-opencode-config.d.ts +0 -10
  15. package/dist/config/schema.d.ts +0 -1
  16. package/dist/create-hooks.d.ts +0 -1
  17. package/dist/hooks/index.d.ts +0 -1
  18. package/dist/index.js +11675 -13715
  19. package/dist/mcp/index.d.ts +0 -4
  20. package/dist/mcp/types.d.ts +0 -1
  21. package/dist/oh-my-opencode.schema.json +1 -45
  22. package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
  23. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  24. package/dist/shared/omo-process-sweep.d.ts +2 -4
  25. package/dist/skills/init-deep/SKILL.md +13 -13
  26. package/dist/skills/ulw-plan/SKILL.md +0 -1
  27. package/dist/tui.js +44809 -44883
  28. package/package.json +16 -18
  29. package/packages/omo-codex/THIRD-PARTY-NOTICES.md +0 -17
  30. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -3
  31. package/packages/omo-codex/plugin/.mcp.json +0 -6
  32. package/packages/omo-codex/plugin/AGENTS.md +5 -5
  33. package/packages/omo-codex/plugin/README.md +1 -1
  34. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +1 -15
  35. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  36. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  37. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  38. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  40. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  41. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  42. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
  44. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  45. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  46. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  47. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  48. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  49. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  50. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  51. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +1 -1
  52. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  53. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  54. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +2 -2
  55. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  56. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  57. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +0 -1
  58. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  59. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
  60. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  61. package/packages/omo-codex/plugin/components/ulw-loop/README.md +11 -1
  62. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +2 -2
  63. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.d.ts +12 -0
  64. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +45 -0
  65. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +1 -0
  66. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +5 -0
  67. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +10 -3
  68. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +35 -38
  69. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +278 -193
  70. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.d.ts +5 -0
  71. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.js +7 -51
  72. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.js +39 -22
  73. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.d.ts +13 -1
  74. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.js +64 -8
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +5 -1
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +37 -18
  77. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  78. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  79. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -1
  80. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-codex-validation.ts +81 -0
  81. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +6 -0
  82. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +10 -3
  83. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +32 -63
  84. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-aggregate.ts +7 -53
  85. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-artifacts.ts +50 -31
  86. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-fields.ts +67 -14
  87. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +6 -1
  88. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +36 -17
  89. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +26 -0
  90. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +47 -2
  91. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-aggregate-basics.test.ts +258 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-cap-and-dedupe.test.ts +22 -0
  93. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-poisoning-cascades.test.ts +97 -0
  94. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-single-report.test.ts +241 -0
  95. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  96. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  97. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  98. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  99. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  100. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  101. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  102. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  103. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  104. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  105. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  106. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  107. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  108. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  109. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  110. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  111. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
  112. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  113. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  116. package/packages/omo-codex/plugin/package-lock.json +12 -146
  117. package/packages/omo-codex/plugin/package.json +1 -2
  118. package/packages/omo-codex/plugin/scripts/AGENTS.md +0 -1
  119. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +0 -1
  120. package/packages/omo-codex/plugin/scripts/auto-update.mjs +0 -9
  121. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +0 -1
  122. package/packages/omo-codex/plugin/shared/src/config-loader.ts +2 -102
  123. package/packages/omo-codex/plugin/shared/src/config-migration.ts +0 -1
  124. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +41 -130
  125. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +13 -13
  126. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
  127. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +2 -2
  128. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -1
  129. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +0 -1
  130. package/packages/omo-codex/plugin/test/AGENTS.md +2 -2
  131. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +2 -21
  132. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -2
  133. package/packages/omo-codex/plugin/test/aggregate-mcp.test.mjs +2 -7
  134. package/packages/omo-codex/plugin/test/auto-update.test.mjs +0 -25
  135. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +0 -31
  136. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +0 -50
  137. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +0 -1
  138. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -3
  139. package/packages/omo-codex/scripts/install-config-git-bash.test.mjs +0 -23
  140. package/packages/omo-codex/scripts/install-dist/install-local.mjs +227 -435
  141. package/packages/omo-codex/scripts/install-git-bash-mcp-env.test.mjs +1 -25
  142. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +0 -36
  143. package/packages/shared-skills/skills/init-deep/SKILL.md +13 -13
  144. package/packages/shared-skills/skills/ulw-plan/SKILL.md +0 -1
  145. package/dist/config/schema/codegraph.d.ts +0 -12
  146. package/dist/hooks/codegraph-bootstrap/command-runner.d.ts +0 -17
  147. package/dist/hooks/codegraph-bootstrap/hook.d.ts +0 -35
  148. package/dist/hooks/codegraph-bootstrap/index.d.ts +0 -1
  149. package/dist/hooks/codegraph-bootstrap/project-root.d.ts +0 -1
  150. package/dist/hooks/codegraph-bootstrap/status.d.ts +0 -11
  151. package/dist/mcp/codegraph.d.ts +0 -16
  152. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +0 -58
  153. package/packages/omo-codex/plugin/components/codegraph/LICENSE +0 -21
  154. package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +0 -2951
  155. package/packages/omo-codex/plugin/components/codegraph/NOTICE +0 -16
  156. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +0 -12326
  157. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9908
  158. package/packages/omo-codex/plugin/components/codegraph/package.json +0 -33
  159. package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +0 -29
  160. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +0 -79
  161. package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +0 -33
  162. package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +0 -25
  163. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +0 -131
  164. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +0 -258
  165. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +0 -310
  166. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +0 -92
  167. package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +0 -34
  168. package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +0 -29
  169. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +0 -263
  170. package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +0 -106
  171. package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +0 -145
  172. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +0 -22
  173. package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +0 -139
  174. package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +0 -15
  175. package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +0 -32
  176. package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +0 -109
  177. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +0 -148
  178. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +0 -175
  179. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +0 -81
  180. package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +0 -34
  181. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +0 -112
  182. package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +0 -26
  183. package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +0 -160
  184. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +0 -50
  185. package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +0 -29
  186. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +0 -320
  187. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +0 -172
  188. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +0 -91
  189. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +0 -100
  190. package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +0 -76
  191. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +0 -133
  192. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +0 -245
  193. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +0 -69
  194. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +0 -43
  195. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +0 -147
  196. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable-idle.test.ts +0 -47
  197. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +0 -175
  198. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +0 -385
  199. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +0 -206
  200. package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +0 -58
  201. package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +0 -104
  202. package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +0 -65
  203. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +0 -106
  204. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +0 -116
  205. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +0 -258
  206. package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +0 -56
  207. package/packages/omo-codex/plugin/components/codegraph/tsconfig.build.json +0 -13
  208. package/packages/omo-codex/plugin/components/codegraph/tsconfig.json +0 -25
  209. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-aggregate.test.ts +0 -101
  210. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +0 -18
  211. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +0 -17
  212. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/editor.mjs +0 -125
  213. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/jsonc.mjs +0 -43
  214. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/scaffold.mjs +0 -29
  215. package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +0 -121
  216. package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +0 -76
  217. package/packages/omo-codex/plugin/test/migrate-omo-sot.test.mjs +0 -179
@@ -1,104 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { mkdtempSync, rmSync, utimesSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- import {
7
- clearSessionStartCooldown,
8
- readSessionStartCooldown,
9
- recordSessionStartFailure,
10
- } from "../src/session-start-cooldown.ts";
11
- import {
12
- acquireSessionStartLock,
13
- releaseSessionStartLock,
14
- } from "../src/session-start-lock.ts";
15
-
16
- describe("CodeGraph SessionStart lock", () => {
17
- it("#given a live project lock #when a second hook acquires it #then the second hook is deduplicated", () => {
18
- // given
19
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-lock-home-"));
20
- const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-lock-project-"));
21
- try {
22
- const first = acquireSessionStartLock({ homeDir, nowMs: 10_000, projectRoot, staleMs: 60_000 });
23
- expect(first.kind).toBe("acquired");
24
-
25
- // when
26
- const second = acquireSessionStartLock({ homeDir, nowMs: 10_001, projectRoot, staleMs: 60_000 });
27
-
28
- // then
29
- expect(second).toEqual({ kind: "locked" });
30
- if (first.kind === "acquired") releaseSessionStartLock(first.lock);
31
- } finally {
32
- rmSync(homeDir, { recursive: true, force: true });
33
- rmSync(projectRoot, { recursive: true, force: true });
34
- }
35
- });
36
-
37
- it("#given a project lock older than the stale threshold #when another hook acquires it #then the stale lock is recovered", () => {
38
- // given
39
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-stale-home-"));
40
- const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-stale-project-"));
41
- try {
42
- const first = acquireSessionStartLock({ homeDir, nowMs: 1_000, projectRoot, staleMs: 500 });
43
- expect(first.kind).toBe("acquired");
44
- if (first.kind !== "acquired") return;
45
- const staleDate = new Date(1_000);
46
- utimesSync(first.lock.path, staleDate, staleDate);
47
-
48
- // when
49
- const second = acquireSessionStartLock({ homeDir, nowMs: 2_000, projectRoot, staleMs: 500 });
50
-
51
- // then
52
- expect(second.kind).toBe("acquired");
53
- if (second.kind === "acquired") {
54
- expect(second.recoveredStale).toBe(true);
55
- releaseSessionStartLock(second.lock);
56
- }
57
- } finally {
58
- rmSync(homeDir, { recursive: true, force: true });
59
- rmSync(projectRoot, { recursive: true, force: true });
60
- }
61
- });
62
- });
63
-
64
- describe("CodeGraph SessionStart cooldown", () => {
65
- it("#given a failed worker outcome #when the cooldown is checked #then retries are suppressed until expiry and the next failure backs off", () => {
66
- // given
67
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-home-"));
68
- const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-project-"));
69
- try {
70
- const first = recordSessionStartFailure({
71
- action: "failed",
72
- baseCooldownMs: 1_000,
73
- homeDir,
74
- nowMs: 1_000,
75
- projectRoot,
76
- });
77
-
78
- // when
79
- const active = readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 1_999, projectRoot });
80
- const expired = readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 2_000, projectRoot });
81
- const second = recordSessionStartFailure({
82
- action: "skipped-status",
83
- baseCooldownMs: 1_000,
84
- homeDir,
85
- nowMs: 2_000,
86
- projectRoot,
87
- });
88
-
89
- // then
90
- expect(first).toMatchObject({ cooldownUntil: 2_000, failureCount: 1 });
91
- expect(active).toMatchObject({ cooldownUntil: 2_000, failureCount: 1, kind: "active" });
92
- expect(expired).toEqual({ failureCount: 1, kind: "inactive" });
93
- expect(second).toMatchObject({ cooldownUntil: 4_000, failureCount: 2 });
94
- clearSessionStartCooldown({ homeDir, projectRoot });
95
- expect(readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 2_001, projectRoot })).toEqual({
96
- failureCount: 0,
97
- kind: "inactive",
98
- });
99
- } finally {
100
- rmSync(homeDir, { recursive: true, force: true });
101
- rmSync(projectRoot, { recursive: true, force: true });
102
- }
103
- });
104
- });
@@ -1,65 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- import { runCodegraphSessionStartWorker } from "../src/hook.ts";
7
-
8
- describe("CodeGraph SessionStart trust boundary", () => {
9
- it("#given project config sets install_dir #when worker provisions CodeGraph #then it uses the trusted home install root", async () => {
10
- // given
11
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-untrusted-project-"));
12
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-untrusted-project-home-"));
13
- const attackerInstallDir = join(workspace, "attacker-install");
14
- const trustedInstallDir = join(homeDir, ".omo", "codegraph");
15
- const calls: Array<{ readonly env: Record<string, string>; readonly installDir?: string; readonly lockDir?: string }> = [];
16
- try {
17
- mkdirSync(join(workspace, ".omo"), { recursive: true });
18
- writeFileSync(join(workspace, ".omo", "omo.jsonc"), JSON.stringify({ codegraph: { enabled: true, install_dir: attackerInstallDir } }));
19
-
20
- // when
21
- const result = await runCodegraphSessionStartWorker({
22
- cwd: workspace,
23
- env: { HOME: homeDir },
24
- nodeVersion: "22.14.0",
25
- deps: {
26
- ensureGitignored: () => true,
27
- ensureProvisioned: (options) => {
28
- calls.push({
29
- env: {},
30
- ...(options.installDir === undefined ? {} : { installDir: options.installDir }),
31
- ...(options.lockDir === undefined ? {} : { lockDir: options.lockDir }),
32
- });
33
- return Promise.resolve({ binPath: join(trustedInstallDir, "bin", "codegraph"), provisioned: true });
34
- },
35
- prepareWorkspace: () => ({
36
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
37
- dataRoot: join(homeDir, ".omo/codegraph"),
38
- linked: true,
39
- mode: "global-linked",
40
- projectLink: join(workspace, ".codegraph"),
41
- }),
42
- resolveCommand: (options) => {
43
- expect(options?.provisioned?.()).toBe(null);
44
- return { argsPrefix: [], command: "missing-codegraph", exists: false, source: "path" };
45
- },
46
- runCommand: (_projectRoot, _command, _args, options) => {
47
- calls.push({ env: options.env });
48
- mkdirSync(join(workspace, ".codegraph"), { recursive: true });
49
- writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
50
- return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
51
- },
52
- },
53
- });
54
-
55
- // then
56
- expect(result).toEqual({ action: "initialized" });
57
- expect(calls[0]).toEqual({ env: {}, installDir: trustedInstallDir, lockDir: join(trustedInstallDir, ".locks") });
58
- expect(calls[1]?.env["CODEGRAPH_INSTALL_DIR"]).toBe(trustedInstallDir);
59
- expect(calls[1]?.env["CODEGRAPH_INSTALL_DIR"]).not.toBe(attackerInstallDir);
60
- } finally {
61
- rmSync(workspace, { recursive: true, force: true });
62
- rmSync(homeDir, { recursive: true, force: true });
63
- }
64
- });
65
- });
@@ -1,106 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { existsSync, mkdtempSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- import { runCodegraphSessionStartWorker } from "../src/hook.ts";
7
-
8
- describe("CodeGraph SessionStart worker availability", () => {
9
- it("#given CodeGraph cannot be resolved or provisioned #when worker runs #then it logs a graceful skip", async () => {
10
- // given
11
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-"));
12
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-home-"));
13
- const outcomes: unknown[] = [];
14
- const calls: string[] = [];
15
-
16
- try {
17
- // when
18
- const result = await runCodegraphSessionStartWorker({
19
- cwd: workspace,
20
- env: { HOME: homeDir },
21
- nodeVersion: "22.14.0",
22
- logOutcome: (outcome) => outcomes.push(outcome),
23
- deps: {
24
- ensureGitignored: () => {
25
- calls.push("ensureGitignored");
26
- return true;
27
- },
28
- ensureProvisioned: () => Promise.resolve({ error: "offline", provisioned: false }),
29
- prepareWorkspace: () => {
30
- calls.push("prepareWorkspace");
31
- return {
32
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
33
- dataRoot: join(homeDir, ".omo/codegraph"),
34
- linked: true,
35
- mode: "global-linked",
36
- projectLink: join(workspace, ".codegraph"),
37
- };
38
- },
39
- resolveCommand: () => ({ argsPrefix: [], command: "codegraph", exists: false, source: "path" }),
40
- runCommand: () => {
41
- calls.push("runCommand");
42
- return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
43
- },
44
- },
45
- });
46
-
47
- // then
48
- expect(result).toEqual({ action: "skipped-unavailable" });
49
- expect(calls).toEqual([]);
50
- expect(outcomes).toEqual([
51
- {
52
- action: "skipped-unavailable",
53
- error: "offline",
54
- projectRoot: workspace,
55
- source: "path",
56
- },
57
- ]);
58
- } finally {
59
- rmSync(workspace, { recursive: true, force: true });
60
- rmSync(homeDir, { recursive: true, force: true });
61
- }
62
- });
63
-
64
- it("#given CodeGraph is unavailable and auto provisioning is disabled #when worker runs #then it leaves the project untouched", async () => {
65
- // given
66
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-unavailable-"));
67
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-unavailable-home-"));
68
- const outcomes: unknown[] = [];
69
-
70
- try {
71
- // when
72
- const result = await runCodegraphSessionStartWorker({
73
- config: { codegraph: { auto_provision: false, enabled: true }, sources: [], warnings: [] },
74
- nodeVersion: "22.14.0",
75
- cwd: workspace,
76
- env: { HOME: homeDir },
77
- logOutcome: (outcome) => outcomes.push(outcome),
78
- deps: {
79
- ensureProvisioned: () => {
80
- throw new Error("auto provision should not run");
81
- },
82
- resolveCommand: () => ({ argsPrefix: [], command: "missing-codegraph", exists: false, source: "path" }),
83
- runCommand: () => {
84
- throw new Error("codegraph command should not run");
85
- },
86
- },
87
- });
88
-
89
- // then
90
- expect(result).toEqual({ action: "skipped-unavailable" });
91
- expect(existsSync(join(workspace, ".codegraph"))).toBe(false);
92
- expect(existsSync(join(workspace, ".git", "info", "exclude"))).toBe(false);
93
- expect(outcomes).toEqual([
94
- {
95
- action: "skipped-unavailable",
96
- error: "codegraph binary unavailable and auto_provision is disabled",
97
- projectRoot: workspace,
98
- source: "path",
99
- },
100
- ]);
101
- } finally {
102
- rmSync(workspace, { recursive: true, force: true });
103
- rmSync(homeDir, { recursive: true, force: true });
104
- }
105
- });
106
- });
@@ -1,116 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- import type { CodegraphSessionStartOutcome } from "../src/hook.ts";
7
- import { runCodegraphSessionStartWorker } from "../src/hook.ts";
8
- import { readSessionStartCooldown } from "../src/session-start-cooldown.ts";
9
-
10
- describe("CodeGraph SessionStart worker cooldown", () => {
11
- it("#given codegraph init times out #when the worker finishes #then it records a failed outcome and cooldown", async () => {
12
- // given
13
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-timeout-"));
14
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-timeout-home-"));
15
- const outcomes: CodegraphSessionStartOutcome[] = [];
16
- try {
17
- // when
18
- const result = await runCodegraphSessionStartWorker({
19
- config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
20
- cwd: workspace,
21
- env: { HOME: homeDir },
22
- logOutcome: (outcome) => outcomes.push(outcome),
23
- nodeVersion: "22.14.0",
24
- nowMs: 1_000,
25
- projectProbe: () => ({ kind: "uninitialized" }),
26
- deps: {
27
- ensureGitignored: () => true,
28
- ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
29
- prepareWorkspace: () => ({
30
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
31
- dataRoot: join(homeDir, ".omo/codegraph"),
32
- linked: true,
33
- mode: "global-linked",
34
- projectLink: join(workspace, ".codegraph"),
35
- }),
36
- resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
37
- runCommand: () => Promise.resolve({ exitCode: 1, stdout: "", timedOut: true }),
38
- },
39
- });
40
- const cooldown = readSessionStartCooldown({
41
- baseCooldownMs: 60_000,
42
- homeDir,
43
- nowMs: 2_000,
44
- projectRoot: workspace,
45
- });
46
-
47
- // then
48
- expect(result).toEqual({ action: "failed" });
49
- expect(outcomes).toEqual([{
50
- action: "failed",
51
- error: "codegraph init timed out",
52
- exitCode: 1,
53
- projectRoot: workspace,
54
- source: "path",
55
- timedOut: true,
56
- }]);
57
- expect(cooldown).toEqual({ cooldownUntil: 61_000, failureCount: 1, kind: "active" });
58
- } finally {
59
- rmSync(homeDir, { recursive: true, force: true });
60
- rmSync(workspace, { recursive: true, force: true });
61
- }
62
- });
63
-
64
- it("#given codegraph init exits zero without an exact database #when the worker verifies the result #then it records a failure cooldown", async () => {
65
- // given
66
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-no-db-"));
67
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-no-db-home-"));
68
- const outcomes: CodegraphSessionStartOutcome[] = [];
69
- try {
70
- // when
71
- const result = await runCodegraphSessionStartWorker({
72
- config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
73
- cwd: workspace,
74
- env: { HOME: homeDir },
75
- logOutcome: (outcome) => outcomes.push(outcome),
76
- nodeVersion: "22.14.0",
77
- nowMs: 1_000,
78
- projectProbe: () => ({ kind: "uninitialized" }),
79
- deps: {
80
- ensureGitignored: () => true,
81
- ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
82
- prepareWorkspace: () => ({
83
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
84
- dataRoot: join(homeDir, ".omo/codegraph"),
85
- linked: true,
86
- mode: "global-linked",
87
- projectLink: join(workspace, ".codegraph"),
88
- }),
89
- resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
90
- runCommand: () => Promise.resolve({ exitCode: 0, stdout: "", timedOut: false }),
91
- },
92
- });
93
- const cooldown = readSessionStartCooldown({
94
- baseCooldownMs: 60_000,
95
- homeDir,
96
- nowMs: 2_000,
97
- projectRoot: workspace,
98
- });
99
-
100
- // then
101
- expect(result).toEqual({ action: "failed" });
102
- expect(outcomes).toEqual([{
103
- action: "failed",
104
- error: "codegraph init completed without creating an exact project database",
105
- exitCode: 0,
106
- projectRoot: workspace,
107
- source: "path",
108
- timedOut: false,
109
- }]);
110
- expect(cooldown).toEqual({ cooldownUntil: 61_000, failureCount: 1, kind: "active" });
111
- } finally {
112
- rmSync(homeDir, { recursive: true, force: true });
113
- rmSync(workspace, { recursive: true, force: true });
114
- }
115
- });
116
- });
@@ -1,258 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
7
- import { resolveCodegraphCommandInvocation, runCodegraphSessionStartWorker } from "../src/hook.ts";
8
-
9
- function writeProjectDatabase(workspace: string): void {
10
- mkdirSync(join(workspace, ".codegraph"), { recursive: true });
11
- writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
12
- }
13
-
14
- describe("CodeGraph SessionStart worker flow", () => {
15
- it("#given install_dir has the pinned platform binary #when worker resolves provisioned CodeGraph #then it uses that launcher", async () => {
16
- // given
17
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-platform-"));
18
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-platform-home-"));
19
- const installDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-platform-install-"));
20
- const binPath = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
21
- const calls: { readonly args: readonly string[]; readonly command: string; readonly env: Record<string, string> }[] = [];
22
- const outcomes: unknown[] = [];
23
- try {
24
- mkdirSync(join(installDir, "bin"), { recursive: true });
25
- mkdirSync(join(installDir, ".provisioned"), { recursive: true });
26
- writeFileSync(binPath, "");
27
- writeFileSync(
28
- join(installDir, ".provisioned", `codegraph-${CODEGRAPH_PINNED_VERSION}.json`),
29
- `${JSON.stringify({ binPath, version: CODEGRAPH_PINNED_VERSION })}\n`,
30
- );
31
-
32
- // when
33
- const result = await runCodegraphSessionStartWorker({
34
- config: { codegraph: { enabled: true, install_dir: installDir }, sources: [], trustedCodegraphInstallDir: installDir, warnings: [] },
35
- nodeVersion: "22.14.0",
36
- cwd: workspace,
37
- env: { HOME: homeDir },
38
- logOutcome: (outcome) => outcomes.push(outcome),
39
- deps: {
40
- ensureGitignored: () => true,
41
- ensureProvisioned: () => {
42
- throw new Error("provisioning should not run when install_dir binary exists");
43
- },
44
- prepareWorkspace: () => ({
45
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
46
- dataRoot: join(homeDir, ".omo/codegraph"),
47
- linked: true,
48
- mode: "global-linked",
49
- projectLink: join(workspace, ".codegraph"),
50
- }),
51
- resolveCommand: (options) => {
52
- const provisioned = options?.provisioned?.() ?? null;
53
- return { argsPrefix: [], command: provisioned ?? "missing-codegraph", exists: provisioned !== null, source: provisioned === null ? "path" : "provisioned" };
54
- },
55
- resolveManagedBin: () => binPath,
56
- runCommand: (_projectRoot, command, args, options) => {
57
- calls.push({ args, command, env: options.env });
58
- writeProjectDatabase(workspace);
59
- return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
60
- },
61
- },
62
- });
63
-
64
- // then
65
- expect(result).toEqual({ action: "initialized" });
66
- expect(calls.map((call) => ({ args: [...call.args], command: call.command }))).toEqual([
67
- { args: ["init"], command: binPath },
68
- ]);
69
- expect(calls[0]?.env["CODEGRAPH_INSTALL_DIR"]).toBe(installDir);
70
- expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
71
- } finally {
72
- rmSync(workspace, { recursive: true, force: true });
73
- rmSync(homeDir, { recursive: true, force: true });
74
- rmSync(installDir, { recursive: true, force: true });
75
- }
76
- });
77
-
78
- it("#given Windows codegraph.cmd #when default worker runner builds invocation #then it runs through cmd.exe", () => {
79
- // given
80
- const command = "C:\\Users\\test\\.omo\\codegraph\\bin\\codegraph.cmd";
81
-
82
- // when
83
- const invocation = resolveCodegraphCommandInvocation(command, ["init"], "win32");
84
-
85
- // then
86
- expect(invocation).toEqual({
87
- args: ["/d", "/s", "/c", command, "init"],
88
- command: "cmd.exe",
89
- });
90
- });
91
-
92
- it("#given Windows CodeGraph resolves to a Node script #when default worker runner builds invocation #then Node executes it", () => {
93
- // given
94
- const command = "C:\\Users\\test\\.omo\\codegraph\\bin\\codegraph.cjs";
95
-
96
- // when
97
- const invocation = resolveCodegraphCommandInvocation(command, ["init"], "win32");
98
-
99
- // then
100
- expect(invocation).toEqual({
101
- args: [command, "init"],
102
- command: process.execPath,
103
- });
104
- });
105
-
106
- it("#given non-Windows codegraph command #when default worker runner builds invocation #then it executes directly", () => {
107
- // given
108
- const command = "/home/test/.omo/codegraph/bin/codegraph";
109
-
110
- // when
111
- const invocation = resolveCodegraphCommandInvocation(command, ["sync"], "linux");
112
-
113
- // then
114
- expect(invocation).toEqual({ args: ["sync"], command });
115
- });
116
-
117
- it("#given an uninitialized exact project #when worker runs #then it invokes init directly without a status command", async () => {
118
- // given
119
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-init-direct-"));
120
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-init-direct-home-"));
121
- const calls: { readonly args: readonly string[]; readonly env: Record<string, string> }[] = [];
122
- const outcomes: unknown[] = [];
123
- try {
124
- // when
125
- const result = await runCodegraphSessionStartWorker({
126
- config: { codegraph: { enabled: true, install_dir: "/tmp/codegraph-install" }, sources: [], trustedCodegraphInstallDir: "/tmp/codegraph-install", warnings: [] },
127
- nodeVersion: "22.14.0",
128
- cwd: workspace,
129
- env: { HOME: homeDir },
130
- logOutcome: (outcome) => outcomes.push(outcome),
131
- deps: {
132
- ensureGitignored: () => true,
133
- ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
134
- prepareWorkspace: () => ({
135
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
136
- dataRoot: join(homeDir, ".omo/codegraph"),
137
- linked: true,
138
- mode: "global-linked",
139
- projectLink: join(workspace, ".codegraph"),
140
- }),
141
- resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
142
- runCommand: (_projectRoot, _command, args, options) => {
143
- calls.push({ args, env: options.env });
144
- writeProjectDatabase(workspace);
145
- return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
146
- },
147
- },
148
- });
149
-
150
- // then
151
- expect(result).toEqual({ action: "initialized" });
152
- expect(calls.map((call) => [...call.args])).toEqual([["init"]]);
153
- expect(calls[0]?.env["CODEGRAPH_INSTALL_DIR"]).toBe("/tmp/codegraph-install");
154
- expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "path", timedOut: false }]);
155
- } finally {
156
- rmSync(workspace, { recursive: true, force: true });
157
- rmSync(homeDir, { recursive: true, force: true });
158
- }
159
- });
160
-
161
- it("#given codegraph.daemon=true #when the indexing worker runs #then its env stays daemon-less with CODEGRAPH_NO_DAEMON=1", async () => {
162
- // given
163
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-daemon-"));
164
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-daemon-home-"));
165
- const calls: { readonly args: readonly string[]; readonly command: string; readonly env: Record<string, string> }[] = [];
166
- try {
167
- // when
168
- const result = await runCodegraphSessionStartWorker({
169
- config: { codegraph: { daemon: true, enabled: true, install_dir: "/tmp/codegraph-install" }, sources: [], trustedCodegraphInstallDir: "/tmp/codegraph-install", warnings: [] },
170
- nodeVersion: "22.14.0",
171
- cwd: workspace,
172
- env: { HOME: homeDir },
173
- logOutcome: () => undefined,
174
- deps: {
175
- ensureGitignored: () => true,
176
- ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
177
- prepareWorkspace: () => ({
178
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
179
- dataRoot: join(homeDir, ".omo/codegraph"),
180
- linked: true,
181
- mode: "global-linked",
182
- projectLink: join(workspace, ".codegraph"),
183
- }),
184
- resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
185
- runCommand: (_projectRoot, command, args, options) => {
186
- calls.push({ args, command, env: options.env });
187
- writeProjectDatabase(workspace);
188
- return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
189
- },
190
- },
191
- });
192
-
193
- // then
194
- expect(result).toEqual({ action: "initialized" });
195
- expect(calls.length).toBeGreaterThan(0);
196
- for (const call of calls) {
197
- expect(call.env["CODEGRAPH_NO_DAEMON"]).toBe("1");
198
- }
199
- } finally {
200
- rmSync(workspace, { recursive: true, force: true });
201
- rmSync(homeDir, { recursive: true, force: true });
202
- }
203
- });
204
-
205
- it("#given ambient provider tokens #when default worker runner spawns CodeGraph #then child env only gets safe and controlled variables", async () => {
206
- // given
207
- const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-env-"));
208
- const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-env-home-"));
209
- const logPath = join(homeDir, "child-env.jsonl");
210
- const originalOpenAiKey = process.env["OPENAI_API_KEY"];
211
- process.env["OPENAI_API_KEY"] = "sk-test-secret";
212
-
213
- try {
214
- const fakeCodegraphScript = [
215
- "const fs = require('node:fs');",
216
- `fs.appendFileSync(${JSON.stringify(logPath)}, JSON.stringify({install:process.env.CODEGRAPH_INSTALL_DIR,openai:process.env.OPENAI_API_KEY}) + '\\n');`,
217
- "fs.mkdirSync('.codegraph', { recursive: true });",
218
- "fs.writeFileSync('.codegraph/codegraph.db', 'fixture');",
219
- ].join("");
220
-
221
- // when
222
- const result = await runCodegraphSessionStartWorker({
223
- config: { codegraph: { enabled: true }, sources: [], warnings: [] },
224
- cwd: workspace,
225
- env: { HOME: homeDir },
226
- logOutcome: () => undefined,
227
- nodeVersion: "22.14.0",
228
- deps: {
229
- ensureGitignored: () => true,
230
- ensureProvisioned: () => {
231
- throw new Error("provisioning should not run when command is resolved");
232
- },
233
- prepareWorkspace: () => ({
234
- dataDir: join(homeDir, ".omo/codegraph/projects/test"),
235
- dataRoot: join(homeDir, ".omo/codegraph"),
236
- linked: true,
237
- mode: "global-linked",
238
- projectLink: join(workspace, ".codegraph"),
239
- }),
240
- resolveCommand: () => ({ argsPrefix: ["-e", fakeCodegraphScript], command: process.execPath, exists: true, source: "bundled" }),
241
- },
242
- });
243
-
244
- // then
245
- expect(result).toEqual({ action: "initialized" });
246
- const captured = readFileSync(logPath, "utf8")
247
- .trim()
248
- .split("\n")
249
- .map((line) => JSON.parse(line));
250
- expect(captured).toEqual([{ install: join(homeDir, ".omo", "codegraph") }]);
251
- } finally {
252
- if (originalOpenAiKey === undefined) delete process.env["OPENAI_API_KEY"];
253
- else process.env["OPENAI_API_KEY"] = originalOpenAiKey;
254
- rmSync(workspace, { recursive: true, force: true });
255
- rmSync(homeDir, { recursive: true, force: true });
256
- }
257
- });
258
- });