oh-my-codex 0.18.7 → 0.18.9

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 (307) hide show
  1. package/Cargo.lock +12 -12
  2. package/Cargo.toml +1 -1
  3. package/README.md +5 -5
  4. package/crates/omx-sparkshell/tests/execution.rs +1 -1
  5. package/dist/agents/__tests__/native-config.test.js +42 -1
  6. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  7. package/dist/agents/definitions.d.ts +8 -0
  8. package/dist/agents/definitions.d.ts.map +1 -1
  9. package/dist/agents/definitions.js +1 -0
  10. package/dist/agents/definitions.js.map +1 -1
  11. package/dist/agents/native-config.d.ts +5 -1
  12. package/dist/agents/native-config.d.ts.map +1 -1
  13. package/dist/agents/native-config.js +17 -2
  14. package/dist/agents/native-config.js.map +1 -1
  15. package/dist/autopilot/__tests__/fsm.test.js +3 -0
  16. package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
  17. package/dist/autopilot/fsm.js +2 -2
  18. package/dist/autopilot/fsm.js.map +1 -1
  19. package/dist/cli/__tests__/auth.test.js +4 -2
  20. package/dist/cli/__tests__/auth.test.js.map +1 -1
  21. package/dist/cli/__tests__/codex-plugin-layout.test.js +512 -1
  22. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  23. package/dist/cli/__tests__/doctor-warning-copy.test.js +39 -0
  24. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  25. package/dist/cli/__tests__/index.test.js +98 -6
  26. package/dist/cli/__tests__/index.test.js.map +1 -1
  27. package/dist/cli/__tests__/package-bin-contract.test.js +28 -8
  28. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  29. package/dist/cli/__tests__/question.test.js +26 -9
  30. package/dist/cli/__tests__/question.test.js.map +1 -1
  31. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +13 -0
  32. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  33. package/dist/cli/__tests__/ralph.test.js +14 -0
  34. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  35. package/dist/cli/__tests__/resume.test.js +50 -1
  36. package/dist/cli/__tests__/resume.test.js.map +1 -1
  37. package/dist/cli/__tests__/setup-install-mode.test.js +89 -0
  38. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  39. package/dist/cli/__tests__/setup-refresh.test.js +65 -0
  40. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  41. package/dist/cli/__tests__/state.test.js +21 -0
  42. package/dist/cli/__tests__/state.test.js.map +1 -1
  43. package/dist/cli/__tests__/team.test.js +2 -2
  44. package/dist/cli/__tests__/update.test.js +323 -18
  45. package/dist/cli/__tests__/update.test.js.map +1 -1
  46. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -1
  47. package/dist/cli/doctor.d.ts.map +1 -1
  48. package/dist/cli/doctor.js +8 -1
  49. package/dist/cli/doctor.js.map +1 -1
  50. package/dist/cli/index.d.ts +21 -4
  51. package/dist/cli/index.d.ts.map +1 -1
  52. package/dist/cli/index.js +143 -28
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/cli/plugin-marketplace.d.ts +14 -2
  55. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  56. package/dist/cli/plugin-marketplace.js +62 -15
  57. package/dist/cli/plugin-marketplace.js.map +1 -1
  58. package/dist/cli/ralph.d.ts.map +1 -1
  59. package/dist/cli/ralph.js +3 -1
  60. package/dist/cli/ralph.js.map +1 -1
  61. package/dist/cli/setup-preferences.d.ts +2 -0
  62. package/dist/cli/setup-preferences.d.ts.map +1 -1
  63. package/dist/cli/setup-preferences.js +4 -0
  64. package/dist/cli/setup-preferences.js.map +1 -1
  65. package/dist/cli/setup.d.ts +3 -0
  66. package/dist/cli/setup.d.ts.map +1 -1
  67. package/dist/cli/setup.js +166 -27
  68. package/dist/cli/setup.js.map +1 -1
  69. package/dist/cli/state.d.ts.map +1 -1
  70. package/dist/cli/state.js +8 -1
  71. package/dist/cli/state.js.map +1 -1
  72. package/dist/cli/tmux-hook.d.ts.map +1 -1
  73. package/dist/cli/tmux-hook.js +16 -0
  74. package/dist/cli/tmux-hook.js.map +1 -1
  75. package/dist/cli/update.d.ts +22 -3
  76. package/dist/cli/update.d.ts.map +1 -1
  77. package/dist/cli/update.js +312 -26
  78. package/dist/cli/update.js.map +1 -1
  79. package/dist/cli/version.d.ts.map +1 -1
  80. package/dist/cli/version.js +5 -9
  81. package/dist/cli/version.js.map +1 -1
  82. package/dist/compat/__tests__/doctor-contract.test.js +12 -1
  83. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  84. package/dist/config/__tests__/generator-notify.test.js +1 -0
  85. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  86. package/dist/config/generator.d.ts +2 -2
  87. package/dist/config/generator.d.ts.map +1 -1
  88. package/dist/config/generator.js +2 -2
  89. package/dist/config/generator.js.map +1 -1
  90. package/dist/config/team-mode.d.ts +12 -0
  91. package/dist/config/team-mode.d.ts.map +1 -0
  92. package/dist/config/team-mode.js +91 -0
  93. package/dist/config/team-mode.js.map +1 -0
  94. package/dist/hooks/__tests__/agents-overlay.test.js +88 -0
  95. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  96. package/dist/hooks/__tests__/code-review-skill-contract.test.js +12 -0
  97. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  98. package/dist/hooks/__tests__/deep-interview-contract.test.js +30 -1
  99. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  100. package/dist/hooks/__tests__/keyword-detector.test.js +423 -3
  101. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  102. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +1 -1
  103. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  104. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +189 -0
  105. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  106. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +35 -2
  107. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  108. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +3 -3
  109. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  110. package/dist/hooks/__tests__/skill-guidance-contract.test.js +21 -0
  111. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
  112. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  113. package/dist/hooks/agents-overlay.js +36 -50
  114. package/dist/hooks/agents-overlay.js.map +1 -1
  115. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +31 -0
  116. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
  117. package/dist/hooks/extensibility/plugin-runner.js +17 -21
  118. package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
  119. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  120. package/dist/hooks/keyword-detector.js +258 -12
  121. package/dist/hooks/keyword-detector.js.map +1 -1
  122. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  123. package/dist/hooks/prompt-guidance-contract.js +6 -0
  124. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  125. package/dist/hooks/session.d.ts +1 -0
  126. package/dist/hooks/session.d.ts.map +1 -1
  127. package/dist/hooks/session.js.map +1 -1
  128. package/dist/hud/__tests__/authority.test.js +435 -32
  129. package/dist/hud/__tests__/authority.test.js.map +1 -1
  130. package/dist/hud/__tests__/hud-tmux-injection.test.js +2 -1
  131. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  132. package/dist/hud/__tests__/index.test.js +42 -0
  133. package/dist/hud/__tests__/index.test.js.map +1 -1
  134. package/dist/hud/__tests__/reconcile.test.js +642 -15
  135. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  136. package/dist/hud/__tests__/render.test.js +61 -0
  137. package/dist/hud/__tests__/render.test.js.map +1 -1
  138. package/dist/hud/__tests__/state.test.js +160 -4
  139. package/dist/hud/__tests__/state.test.js.map +1 -1
  140. package/dist/hud/__tests__/tmux.test.js +180 -21
  141. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  142. package/dist/hud/authority.d.ts +5 -0
  143. package/dist/hud/authority.d.ts.map +1 -1
  144. package/dist/hud/authority.js +324 -28
  145. package/dist/hud/authority.js.map +1 -1
  146. package/dist/hud/index.d.ts +3 -2
  147. package/dist/hud/index.d.ts.map +1 -1
  148. package/dist/hud/index.js +42 -19
  149. package/dist/hud/index.js.map +1 -1
  150. package/dist/hud/reconcile.d.ts +3 -3
  151. package/dist/hud/reconcile.d.ts.map +1 -1
  152. package/dist/hud/reconcile.js +128 -19
  153. package/dist/hud/reconcile.js.map +1 -1
  154. package/dist/hud/render.d.ts.map +1 -1
  155. package/dist/hud/render.js +35 -0
  156. package/dist/hud/render.js.map +1 -1
  157. package/dist/hud/state.d.ts.map +1 -1
  158. package/dist/hud/state.js +65 -80
  159. package/dist/hud/state.js.map +1 -1
  160. package/dist/hud/tmux.d.ts +24 -6
  161. package/dist/hud/tmux.d.ts.map +1 -1
  162. package/dist/hud/tmux.js +136 -38
  163. package/dist/hud/tmux.js.map +1 -1
  164. package/dist/hud/types.d.ts +11 -0
  165. package/dist/hud/types.d.ts.map +1 -1
  166. package/dist/hud/types.js.map +1 -1
  167. package/dist/mcp/__tests__/state-paths.test.js +71 -1
  168. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  169. package/dist/mcp/state-paths.d.ts +32 -0
  170. package/dist/mcp/state-paths.d.ts.map +1 -1
  171. package/dist/mcp/state-paths.js +113 -17
  172. package/dist/mcp/state-paths.js.map +1 -1
  173. package/dist/mcp/state-server.d.ts +4 -4
  174. package/dist/question/__tests__/renderer.test.js +566 -1
  175. package/dist/question/__tests__/renderer.test.js.map +1 -1
  176. package/dist/question/renderer.d.ts +9 -1
  177. package/dist/question/renderer.d.ts.map +1 -1
  178. package/dist/question/renderer.js +246 -70
  179. package/dist/question/renderer.js.map +1 -1
  180. package/dist/scripts/__tests__/codex-native-hook.test.js +837 -101
  181. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  182. package/dist/scripts/__tests__/notify-state-io.test.js +72 -1
  183. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  184. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts +2 -0
  185. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts.map +1 -0
  186. package/dist/scripts/__tests__/notify-tmux-injection.test.js +57 -0
  187. package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -0
  188. package/dist/scripts/__tests__/run-test-files.test.js +74 -0
  189. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  190. package/dist/scripts/__tests__/verify-native-agents.test.js +65 -0
  191. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  192. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  193. package/dist/scripts/codex-native-hook.js +107 -39
  194. package/dist/scripts/codex-native-hook.js.map +1 -1
  195. package/dist/scripts/eval/eval-parity-smoke.js +1 -1
  196. package/dist/scripts/eval/eval-parity-smoke.js.map +1 -1
  197. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  198. package/dist/scripts/notify-hook/auto-nudge.js +3 -1
  199. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  200. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  201. package/dist/scripts/notify-hook/ralph-session-resume.js +3 -10
  202. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  203. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  204. package/dist/scripts/notify-hook/state-io.js +62 -38
  205. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  206. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  207. package/dist/scripts/notify-hook/team-leader-nudge.js +7 -0
  208. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  209. package/dist/scripts/notify-hook/tmux-injection.d.ts +7 -0
  210. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  211. package/dist/scripts/notify-hook/tmux-injection.js +24 -18
  212. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  213. package/dist/scripts/notify-hook.js +75 -11
  214. package/dist/scripts/notify-hook.js.map +1 -1
  215. package/dist/scripts/run-test-files.js +193 -22
  216. package/dist/scripts/run-test-files.js.map +1 -1
  217. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  218. package/dist/scripts/sync-plugin-mirror.js +61 -3
  219. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  220. package/dist/scripts/verify-native-agents.d.ts.map +1 -1
  221. package/dist/scripts/verify-native-agents.js +58 -1
  222. package/dist/scripts/verify-native-agents.js.map +1 -1
  223. package/dist/state/__tests__/operations.test.js +113 -0
  224. package/dist/state/__tests__/operations.test.js.map +1 -1
  225. package/dist/state/__tests__/skill-active.test.js +3 -16
  226. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  227. package/dist/state/__tests__/workflow-transition.test.js +25 -0
  228. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  229. package/dist/state/operations.d.ts.map +1 -1
  230. package/dist/state/operations.js +57 -2
  231. package/dist/state/operations.js.map +1 -1
  232. package/dist/state/skill-active.d.ts.map +1 -1
  233. package/dist/state/skill-active.js +7 -39
  234. package/dist/state/skill-active.js.map +1 -1
  235. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  236. package/dist/state/workflow-transition-reconcile.js +10 -14
  237. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  238. package/dist/team/__tests__/runtime.test.js +1 -1
  239. package/dist/team/__tests__/runtime.test.js.map +1 -1
  240. package/dist/team/__tests__/scaling.test.js +9 -4
  241. package/dist/team/__tests__/scaling.test.js.map +1 -1
  242. package/dist/team/__tests__/tmux-session.test.js +195 -2
  243. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  244. package/dist/team/__tests__/worker-runtime-identity.test.js +4 -2
  245. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  246. package/dist/team/scaling.d.ts.map +1 -1
  247. package/dist/team/scaling.js +3 -2
  248. package/dist/team/scaling.js.map +1 -1
  249. package/dist/team/tmux-session.d.ts +2 -0
  250. package/dist/team/tmux-session.d.ts.map +1 -1
  251. package/dist/team/tmux-session.js +142 -12
  252. package/dist/team/tmux-session.js.map +1 -1
  253. package/dist/utils/__tests__/platform-command.test.js +16 -1
  254. package/dist/utils/__tests__/platform-command.test.js.map +1 -1
  255. package/dist/utils/__tests__/version.test.d.ts +2 -0
  256. package/dist/utils/__tests__/version.test.d.ts.map +1 -0
  257. package/dist/utils/__tests__/version.test.js +51 -0
  258. package/dist/utils/__tests__/version.test.js.map +1 -0
  259. package/dist/utils/paths.d.ts +8 -1
  260. package/dist/utils/paths.d.ts.map +1 -1
  261. package/dist/utils/paths.js +16 -4
  262. package/dist/utils/paths.js.map +1 -1
  263. package/dist/utils/platform-command.d.ts +9 -0
  264. package/dist/utils/platform-command.d.ts.map +1 -1
  265. package/dist/utils/platform-command.js +15 -0
  266. package/dist/utils/platform-command.js.map +1 -1
  267. package/dist/utils/version.d.ts +7 -0
  268. package/dist/utils/version.d.ts.map +1 -0
  269. package/dist/utils/version.js +67 -0
  270. package/dist/utils/version.js.map +1 -0
  271. package/dist/verification/__tests__/ci-rust-gates.test.js +89 -1
  272. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  273. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +16 -2
  274. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  275. package/package.json +11 -10
  276. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  277. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +334 -21
  278. package/plugins/oh-my-codex/hooks/hooks.json +1 -2
  279. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +3 -1
  280. package/plugins/oh-my-codex/skills/code-review/SKILL.md +7 -7
  281. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +51 -11
  282. package/plugins/oh-my-codex/skills/ralph/SKILL.md +22 -22
  283. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +9 -0
  284. package/skills/autopilot/SKILL.md +3 -1
  285. package/skills/code-review/SKILL.md +7 -7
  286. package/skills/deep-interview/SKILL.md +51 -11
  287. package/skills/ralph/SKILL.md +22 -22
  288. package/skills/ultraqa/SKILL.md +9 -0
  289. package/src/scripts/__tests__/codex-native-hook.test.ts +946 -98
  290. package/src/scripts/__tests__/notify-state-io.test.ts +95 -0
  291. package/src/scripts/__tests__/notify-tmux-injection.test.ts +82 -0
  292. package/src/scripts/__tests__/run-test-files.test.ts +102 -0
  293. package/src/scripts/__tests__/verify-native-agents.test.ts +75 -0
  294. package/src/scripts/codex-native-hook.ts +123 -34
  295. package/src/scripts/demo-team-e2e.sh +10 -7
  296. package/src/scripts/eval/eval-parity-smoke.ts +1 -1
  297. package/src/scripts/notify-hook/auto-nudge.ts +3 -1
  298. package/src/scripts/notify-hook/ralph-session-resume.ts +2 -8
  299. package/src/scripts/notify-hook/state-io.ts +75 -37
  300. package/src/scripts/notify-hook/team-leader-nudge.ts +7 -0
  301. package/src/scripts/notify-hook/tmux-injection.ts +35 -19
  302. package/src/scripts/notify-hook.ts +91 -4
  303. package/src/scripts/prepare-build.js +83 -0
  304. package/src/scripts/run-test-files.ts +192 -22
  305. package/src/scripts/sync-plugin-mirror.ts +98 -9
  306. package/src/scripts/verify-native-agents.ts +65 -1
  307. package/src/scripts/postinstall-bootstrap.js +0 -23
@@ -1,9 +1,10 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
+ import { mkdirSync, writeFileSync } from 'node:fs';
3
4
  import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
4
5
  import { dirname, join } from 'node:path';
5
6
  import { tmpdir } from 'node:os';
6
- import { isInstallVersionBump, isNewerVersion, maybeCheckAndPromptUpdate, readUserInstallStamp, resolveAutoUpdateMode, resolveInstalledCliEntry, runDeferredGlobalUpdate, runImmediateUpdate, shouldCheckForUpdates, spawnInstalledSetupRefresh, writeUserInstallStamp, } from '../update.js';
7
+ import { isInstallVersionBump, isNewerVersion, maybeCheckAndPromptUpdate, readUserInstallStamp, resolveAutoUpdateMode, resolveGlobalInstallRoot, resolveInstalledCliEntry, formatDeferredSetupCommand, resolveSetupRefreshArgs, runDeferredGlobalUpdate, runGlobalUpdate, runImmediateUpdate, shouldCheckForUpdates, spawnInstalledSetupRefresh, writeUserInstallStamp, } from '../update.js';
7
8
  const PACKAGE_NAME = 'oh-my-codex';
8
9
  describe('isNewerVersion', () => {
9
10
  it('returns true when latest has higher major', () => {
@@ -151,6 +152,7 @@ describe('maybeCheckAndPromptUpdate', () => {
151
152
  }
152
153
  it('schedules a deferred update after a successful startup prompt', async () => {
153
154
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-'));
155
+ const originalMode = process.env.OMX_AUTO_UPDATE;
154
156
  const originalLog = console.log;
155
157
  const logs = [];
156
158
  let inlineUpdateCalls = 0;
@@ -159,6 +161,7 @@ describe('maybeCheckAndPromptUpdate', () => {
159
161
  console.log = (...args) => {
160
162
  logs.push(args.map((arg) => String(arg)).join(' '));
161
163
  };
164
+ delete process.env.OMX_AUTO_UPDATE;
162
165
  try {
163
166
  await withInteractiveTty(async () => {
164
167
  await maybeCheckAndPromptUpdate(cwd, {
@@ -189,15 +192,23 @@ describe('maybeCheckAndPromptUpdate', () => {
189
192
  assert.match(logs.join('\n'), /Log: .*update-test\.log/);
190
193
  }
191
194
  finally {
195
+ if (typeof originalMode === 'string') {
196
+ process.env.OMX_AUTO_UPDATE = originalMode;
197
+ }
198
+ else {
199
+ delete process.env.OMX_AUTO_UPDATE;
200
+ }
192
201
  console.log = originalLog;
193
202
  await rm(cwd, { recursive: true, force: true });
194
203
  }
195
204
  });
196
205
  it('keeps startup update deferred so local setup is not refreshed inline', async () => {
197
206
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-'));
207
+ const originalMode = process.env.OMX_AUTO_UPDATE;
198
208
  const originalLog = console.log;
199
209
  const receivedCwds = [];
200
210
  console.log = () => undefined;
211
+ delete process.env.OMX_AUTO_UPDATE;
201
212
  try {
202
213
  await withInteractiveTty(async () => {
203
214
  await maybeCheckAndPromptUpdate(cwd, {
@@ -216,6 +227,12 @@ describe('maybeCheckAndPromptUpdate', () => {
216
227
  assert.deepEqual(receivedCwds, [cwd]);
217
228
  }
218
229
  finally {
230
+ if (typeof originalMode === 'string') {
231
+ process.env.OMX_AUTO_UPDATE = originalMode;
232
+ }
233
+ else {
234
+ delete process.env.OMX_AUTO_UPDATE;
235
+ }
219
236
  console.log = originalLog;
220
237
  await rm(cwd, { recursive: true, force: true });
221
238
  }
@@ -296,12 +313,14 @@ describe('maybeCheckAndPromptUpdate', () => {
296
313
  });
297
314
  it('reports scheduler diagnostics when startup deferral cannot be launched', async () => {
298
315
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-'));
316
+ const originalMode = process.env.OMX_AUTO_UPDATE;
299
317
  const originalLog = console.log;
300
318
  const logs = [];
301
319
  let setupRefreshCalls = 0;
302
320
  console.log = (...args) => {
303
321
  logs.push(args.map((arg) => String(arg)).join(' '));
304
322
  };
323
+ delete process.env.OMX_AUTO_UPDATE;
305
324
  try {
306
325
  await withInteractiveTty(async () => {
307
326
  await maybeCheckAndPromptUpdate(cwd, {
@@ -321,6 +340,12 @@ describe('maybeCheckAndPromptUpdate', () => {
321
340
  assert.match(logs.join('\n'), /update-test\.log/);
322
341
  }
323
342
  finally {
343
+ if (typeof originalMode === 'string') {
344
+ process.env.OMX_AUTO_UPDATE = originalMode;
345
+ }
346
+ else {
347
+ delete process.env.OMX_AUTO_UPDATE;
348
+ }
324
349
  console.log = originalLog;
325
350
  await rm(cwd, { recursive: true, force: true });
326
351
  }
@@ -380,6 +405,89 @@ describe('maybeCheckAndPromptUpdate', () => {
380
405
  }
381
406
  });
382
407
  });
408
+ describe('direct npm spawn fallback', () => {
409
+ function enoentResult() {
410
+ const error = Object.assign(new Error('spawnSync npm ENOENT'), { code: 'ENOENT' });
411
+ return { status: null, signal: null, error, stdout: '', stderr: '', output: [null, '', ''], pid: 0 };
412
+ }
413
+ function okResult(stdout = '') {
414
+ return { status: 0, signal: null, error: undefined, stdout, stderr: '', output: [null, stdout, ''], pid: 0 };
415
+ }
416
+ it('falls back to npm.cmd for win32 global installs when direct npm spawn returns ENOENT', () => {
417
+ const calls = [];
418
+ const result = runGlobalUpdate(((command, args) => {
419
+ calls.push({ command, args: args });
420
+ return command === 'npm' ? enoentResult() : okResult();
421
+ }), 'win32');
422
+ assert.equal(result.ok, true);
423
+ assert.deepEqual(calls.map((call) => call.command), ['npm', 'npm.cmd']);
424
+ assert.deepEqual(calls[0].args, ['install', '-g', 'oh-my-codex@latest']);
425
+ assert.deepEqual(calls[1].args, ['install', '-g', 'oh-my-codex@latest']);
426
+ });
427
+ it('does not fall back to npm.cmd for non-Windows ENOENT failures', () => {
428
+ const calls = [];
429
+ const result = runGlobalUpdate(((command) => {
430
+ calls.push(command);
431
+ return enoentResult();
432
+ }), 'linux');
433
+ assert.equal(result.ok, false);
434
+ assert.match(result.stderr, /ENOENT/);
435
+ assert.deepEqual(calls, ['npm']);
436
+ });
437
+ it('packs the dev branch from a local checkout instead of globally installing the git dependency spec', () => {
438
+ const originalNpmLocation = process.env.npm_config_location;
439
+ const calls = [];
440
+ process.env.npm_config_location = 'global';
441
+ try {
442
+ const result = runGlobalUpdate('github:Yeachan-Heo/oh-my-codex#dev', ((command, args, options) => {
443
+ calls.push({ command, args: args, cwd: options?.cwd, env: options?.env });
444
+ if (command === 'git' && args[0] === 'clone') {
445
+ mkdirSync(String(args[args.length - 1]), { recursive: true });
446
+ }
447
+ if (command === 'git' && args[0] === 'rev-parse') {
448
+ return okResult('1234567890abcdef\n');
449
+ }
450
+ if (command === 'npm' && args[0] === 'pack') {
451
+ writeFileSync(join(options?.cwd ?? process.cwd(), 'oh-my-codex-0.18.9.tgz'), 'packed');
452
+ return okResult(JSON.stringify([{ filename: 'oh-my-codex-0.18.9.tgz' }]));
453
+ }
454
+ return okResult();
455
+ }), 'linux');
456
+ assert.equal(result.ok, true);
457
+ assert.deepEqual(calls.map((call) => [call.command, ...call.args.slice(0, 3)]), [
458
+ ['git', 'clone', '--depth', '1'],
459
+ ['git', 'rev-parse', 'HEAD'],
460
+ ['npm', 'install', '--global=false', '--location=project'],
461
+ ['npm', 'run', 'prepack'],
462
+ ['npm', 'pack', '--ignore-scripts', '--json'],
463
+ ['npm', 'install', '-g', join(calls[2].cwd ?? '', 'oh-my-codex-0.18.9.tgz')],
464
+ ]);
465
+ const dependencyInstall = calls.find((call) => call.command === 'npm' && call.args[0] === 'install' && call.args.includes('--include=dev'));
466
+ assert.equal(dependencyInstall?.env?.npm_config_global, 'false');
467
+ assert.equal(dependencyInstall?.env?.npm_config_location, 'project');
468
+ assert.equal(calls.some((call) => call.args.includes('github:Yeachan-Heo/oh-my-codex#dev')), false);
469
+ }
470
+ finally {
471
+ if (typeof originalNpmLocation === 'string') {
472
+ process.env.npm_config_location = originalNpmLocation;
473
+ }
474
+ else {
475
+ delete process.env.npm_config_location;
476
+ }
477
+ }
478
+ });
479
+ it('falls back to npm.cmd for win32 global-root lookup when direct npm spawn returns ENOENT', () => {
480
+ const calls = [];
481
+ const root = resolveGlobalInstallRoot(((command, args) => {
482
+ calls.push({ command, args: args });
483
+ return command === 'npm' ? enoentResult() : okResult('C:\\Users\\alice\\AppData\\Roaming\\npm\\node_modules\r\n');
484
+ }), 'win32');
485
+ assert.equal(root, 'C:\\Users\\alice\\AppData\\Roaming\\npm\\node_modules');
486
+ assert.deepEqual(calls.map((call) => call.command), ['npm', 'npm.cmd']);
487
+ assert.deepEqual(calls[0].args, ['root', '-g']);
488
+ assert.deepEqual(calls[1].args, ['root', '-g']);
489
+ });
490
+ });
383
491
  describe('runImmediateUpdate', () => {
384
492
  it('bypasses the passive cadence and updates immediately on explicit request', async () => {
385
493
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-now-'));
@@ -390,6 +498,7 @@ describe('runImmediateUpdate', () => {
390
498
  const logs = [];
391
499
  let setupCalls = 0;
392
500
  const refreshCwds = [];
501
+ const installSources = [];
393
502
  let updateCalls = 0;
394
503
  let latestCalls = 0;
395
504
  console.log = (...args) => {
@@ -408,8 +517,9 @@ describe('runImmediateUpdate', () => {
408
517
  latestCalls += 1;
409
518
  return '0.14.1';
410
519
  },
411
- runGlobalUpdate: () => {
520
+ runGlobalUpdate: (installSource) => {
412
521
  updateCalls += 1;
522
+ installSources.push(installSource);
413
523
  return { ok: true, stderr: '' };
414
524
  },
415
525
  runSetupRefresh: async (refreshCwd) => {
@@ -421,10 +531,13 @@ describe('runImmediateUpdate', () => {
421
531
  assert.equal(result.status, 'updated');
422
532
  assert.equal(latestCalls, 1);
423
533
  assert.equal(updateCalls, 1);
534
+ assert.deepEqual(installSources, [`${PACKAGE_NAME}@latest`]);
424
535
  assert.equal(setupCalls, 1);
425
536
  assert.deepEqual(refreshCwds, [cwd]);
537
+ assert.match(logs.join('\n'), /Selected update channel: stable/);
538
+ assert.match(logs.join('\n'), /Install source: oh-my-codex@latest/);
426
539
  assert.match(logs.join('\n'), /Running: npm install -g oh-my-codex@latest/);
427
- assert.match(logs.join('\n'), /Updated to v0\.14\.1/);
540
+ assert.match(logs.join('\n'), /Updated stable channel to v0\.14\.1/);
428
541
  const stamp = JSON.parse(await readFile(stampPath, 'utf-8'));
429
542
  assert.equal(stamp.installed_version, '0.14.1');
430
543
  assert.equal(stamp.setup_completed_version, '0.14.1');
@@ -440,12 +553,13 @@ describe('runImmediateUpdate', () => {
440
553
  await rm(cwd, { recursive: true, force: true });
441
554
  }
442
555
  });
443
- it('reports up-to-date status for explicit update when npm is already current', async () => {
556
+ it('force-installs stable for explicit update even when npm is already current', async () => {
444
557
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-now-'));
445
558
  const stampPath = join(cwd, '.codex', '.omx', 'install-state.json');
446
559
  const originalCodexHome = process.env.CODEX_HOME;
447
560
  const originalLog = console.log;
448
561
  const logs = [];
562
+ const installSources = [];
449
563
  let updateCalls = 0;
450
564
  let refreshCalls = 0;
451
565
  console.log = (...args) => {
@@ -461,8 +575,9 @@ describe('runImmediateUpdate', () => {
461
575
  const result = await runImmediateUpdate(cwd, {
462
576
  getCurrentVersion: async () => '0.14.0',
463
577
  fetchLatestVersion: async () => '0.14.0',
464
- runGlobalUpdate: () => {
578
+ runGlobalUpdate: (installSource) => {
465
579
  updateCalls += 1;
580
+ installSources.push(installSource);
466
581
  return { ok: true, stderr: '' };
467
582
  },
468
583
  runSetupRefresh: async () => {
@@ -470,10 +585,12 @@ describe('runImmediateUpdate', () => {
470
585
  return { ok: true, stderr: '' };
471
586
  },
472
587
  });
473
- assert.equal(result.status, 'up-to-date');
474
- assert.equal(updateCalls, 0);
475
- assert.equal(refreshCalls, 0);
476
- assert.match(logs.join('\n'), /already up to date \(v0\.14\.0\)/);
588
+ assert.equal(result.status, 'updated');
589
+ assert.equal(updateCalls, 1);
590
+ assert.equal(refreshCalls, 1);
591
+ assert.deepEqual(installSources, [`${PACKAGE_NAME}@latest`]);
592
+ assert.match(logs.join('\n'), /Selected update channel: stable/);
593
+ assert.match(logs.join('\n'), /Running: npm install -g oh-my-codex@latest/);
477
594
  }
478
595
  finally {
479
596
  console.log = originalLog;
@@ -486,12 +603,14 @@ describe('runImmediateUpdate', () => {
486
603
  await rm(cwd, { recursive: true, force: true });
487
604
  }
488
605
  });
489
- it('runs setup refresh for explicit update when current version matches but setup stamp is stale', async () => {
606
+ it('uses stable as a rollback path while preserving persisted setup preferences', async () => {
490
607
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-now-'));
491
608
  const stampPath = join(cwd, '.codex', '.omx', 'install-state.json');
492
609
  const originalCodexHome = process.env.CODEX_HOME;
493
610
  const originalLog = console.log;
494
611
  const logs = [];
612
+ const installSources = [];
613
+ const setupArgs = resolveSetupRefreshArgs;
495
614
  let refreshCalls = 0;
496
615
  console.log = (...args) => {
497
616
  logs.push(args.map((arg) => String(arg)).join(' '));
@@ -503,21 +622,34 @@ describe('runImmediateUpdate', () => {
503
622
  setup_completed_version: '0.13.9',
504
623
  updated_at: '2026-04-20T00:00:00.000Z',
505
624
  }, stampPath);
625
+ await mkdir(join(cwd, '.omx'), { recursive: true });
626
+ await writeFile(join(cwd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'user', installMode: 'plugin', mcpMode: 'none', teamMode: 'disabled' }, null, 2));
506
627
  const result = await runImmediateUpdate(cwd, {
507
628
  getCurrentVersion: async () => '0.14.0',
508
629
  fetchLatestVersion: async () => '0.14.0',
509
- runGlobalUpdate: () => {
510
- throw new Error('global update should not run when already current');
630
+ runGlobalUpdate: (installSource) => {
631
+ installSources.push(installSource);
632
+ return { ok: true, stderr: '', revision: '1234567890ab' };
511
633
  },
512
634
  runSetupRefresh: async () => {
513
635
  refreshCalls += 1;
636
+ assert.deepEqual(setupArgs(cwd), [
637
+ 'setup',
638
+ '--scope',
639
+ 'user',
640
+ '--plugin',
641
+ '--mcp',
642
+ 'none',
643
+ '--disable-team',
644
+ ]);
514
645
  return { ok: true, stderr: '' };
515
646
  },
516
- });
517
- assert.equal(result.status, 'up-to-date');
647
+ }, { channel: 'stable' });
648
+ assert.equal(result.status, 'updated');
649
+ assert.deepEqual(installSources, [`${PACKAGE_NAME}@latest`]);
518
650
  assert.equal(refreshCalls, 1);
519
- assert.match(logs.join('\n'), /Running setup refresh/);
520
- assert.match(logs.join('\n'), /Setup refresh completed for v0\.14\.0/);
651
+ assert.match(logs.join('\n'), /Selected update channel: stable/);
652
+ assert.match(logs.join('\n'), /Install source: oh-my-codex@latest/);
521
653
  const stamp = JSON.parse(await readFile(stampPath, 'utf-8'));
522
654
  assert.equal(stamp.installed_version, '0.14.0');
523
655
  assert.equal(stamp.setup_completed_version, '0.14.0');
@@ -533,8 +665,66 @@ describe('runImmediateUpdate', () => {
533
665
  await rm(cwd, { recursive: true, force: true });
534
666
  }
535
667
  });
668
+ it('installs the upstream dev branch without implying npm latest', async () => {
669
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-update-now-dev-'));
670
+ const stampPath = join(cwd, '.codex', '.omx', 'install-state.json');
671
+ const originalCodexHome = process.env.CODEX_HOME;
672
+ const originalLog = console.log;
673
+ const logs = [];
674
+ const installSources = [];
675
+ let latestCalls = 0;
676
+ let refreshCalls = 0;
677
+ console.log = (...args) => {
678
+ logs.push(args.map((arg) => String(arg)).join(' '));
679
+ };
680
+ process.env.CODEX_HOME = join(cwd, '.codex');
681
+ try {
682
+ const result = await runImmediateUpdate(cwd, {
683
+ getCurrentVersion: async () => '0.14.0',
684
+ fetchLatestVersion: async () => {
685
+ latestCalls += 1;
686
+ return '0.14.0';
687
+ },
688
+ runGlobalUpdate: (installSource) => {
689
+ installSources.push(installSource);
690
+ return { ok: true, stderr: '', revision: '1234567890ab' };
691
+ },
692
+ runSetupRefresh: async () => {
693
+ refreshCalls += 1;
694
+ return { ok: true, stderr: '' };
695
+ },
696
+ getInstalledVersionAfterUpdate: async () => '0.15.0',
697
+ getInstalledRevisionAfterUpdate: async () => null,
698
+ }, { channel: 'dev' });
699
+ assert.equal(result.status, 'updated');
700
+ assert.equal(latestCalls, 0);
701
+ assert.equal(refreshCalls, 1);
702
+ assert.deepEqual(installSources, ['github:Yeachan-Heo/oh-my-codex#dev']);
703
+ assert.match(logs.join('\n'), /Selected update channel: dev/);
704
+ assert.match(logs.join('\n'), /Install source: github:Yeachan-Heo\/oh-my-codex#dev/);
705
+ assert.match(logs.join('\n'), /Running: clone dev branch, run prepack, then npm install -g the packed tarball/);
706
+ assert.doesNotMatch(logs.join('\n'), /dev.*oh-my-codex@latest/i);
707
+ const stamp = JSON.parse(await readFile(stampPath, 'utf-8'));
708
+ assert.equal(stamp.installed_version, '0.15.0');
709
+ assert.equal(stamp.setup_completed_version, '0.15.0');
710
+ assert.equal(stamp.install_channel, 'dev');
711
+ assert.equal(stamp.install_source, 'github:Yeachan-Heo/oh-my-codex#dev');
712
+ assert.equal(stamp.install_revision, '1234567890ab');
713
+ }
714
+ finally {
715
+ console.log = originalLog;
716
+ if (typeof originalCodexHome === 'string') {
717
+ process.env.CODEX_HOME = originalCodexHome;
718
+ }
719
+ else {
720
+ delete process.env.CODEX_HOME;
721
+ }
722
+ await rm(cwd, { recursive: true, force: true });
723
+ }
724
+ });
536
725
  it('continues explicit update when update-check state cannot be written', async () => {
537
726
  const cwd = await mkdtemp(join(tmpdir(), 'omx-update-now-'));
727
+ const originalCodexHome = process.env.CODEX_HOME;
538
728
  const originalLog = console.log;
539
729
  const logs = [];
540
730
  let updateCalls = 0;
@@ -542,6 +732,7 @@ describe('runImmediateUpdate', () => {
542
732
  console.log = (...args) => {
543
733
  logs.push(args.map((arg) => String(arg)).join(' '));
544
734
  };
735
+ process.env.CODEX_HOME = join(cwd, '.codex');
545
736
  try {
546
737
  const result = await runImmediateUpdate(cwd, {
547
738
  getCurrentVersion: async () => '0.14.0',
@@ -561,10 +752,16 @@ describe('runImmediateUpdate', () => {
561
752
  assert.equal(result.status, 'updated');
562
753
  assert.equal(updateCalls, 1);
563
754
  assert.equal(refreshCalls, 1);
564
- assert.match(logs.join('\n'), /Updated to v0\.14\.1/);
755
+ assert.match(logs.join('\n'), /Updated stable channel to v0\.14\.1/);
565
756
  }
566
757
  finally {
567
758
  console.log = originalLog;
759
+ if (typeof originalCodexHome === 'string') {
760
+ process.env.CODEX_HOME = originalCodexHome;
761
+ }
762
+ else {
763
+ delete process.env.CODEX_HOME;
764
+ }
568
765
  await rm(cwd, { recursive: true, force: true });
569
766
  }
570
767
  });
@@ -667,12 +864,67 @@ describe('runDeferredGlobalUpdate', () => {
667
864
  assert.equal(calls[0].options.env?.OMX_DEFERRED_UPDATE_LOG, result.logPath);
668
865
  assert.match(calls[0].args[4], /Get-Process -Id \$parentPid/);
669
866
  assert.match(calls[0].args[4], /npm install -g oh-my-codex@latest/);
670
- assert.match(calls[0].args[4], /omx setup/);
867
+ assert.match(calls[0].args[4], /& 'omx' 'setup'/);
868
+ }
869
+ finally {
870
+ await rm(cwd, { recursive: true, force: true });
871
+ }
872
+ });
873
+ it('preserves plugin setup delivery mode for deferred post-update refreshes', async () => {
874
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-deferred-update-plugin-'));
875
+ const calls = [];
876
+ try {
877
+ await mkdir(join(cwd, '.omx'), { recursive: true });
878
+ await writeFile(join(cwd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'user', installMode: 'plugin', mcpMode: 'none', teamMode: 'disabled' }, null, 2));
879
+ const result = runDeferredGlobalUpdate(cwd, ((command, args) => {
880
+ calls.push({ command, args: args });
881
+ return {
882
+ once() {
883
+ return this;
884
+ },
885
+ unref() { },
886
+ };
887
+ }), 'linux', 12345);
888
+ assert.equal(result.ok, true);
889
+ assert.equal(calls.length, 1);
890
+ assert.match(calls[0].args[1], /'omx' 'setup' '--scope' 'user' '--plugin' '--mcp' 'none' '--disable-team'/);
671
891
  }
672
892
  finally {
673
893
  await rm(cwd, { recursive: true, force: true });
674
894
  }
675
895
  });
896
+ it('snapshots deferred setup refresh args when scheduling the detached updater', async () => {
897
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-deferred-update-snapshot-'));
898
+ const calls = [];
899
+ try {
900
+ await mkdir(join(cwd, '.omx'), { recursive: true });
901
+ const setupScopePath = join(cwd, '.omx', 'setup-scope.json');
902
+ await writeFile(setupScopePath, JSON.stringify({ scope: 'user', installMode: 'plugin', mcpMode: 'none', teamMode: 'disabled' }, null, 2));
903
+ const result = runDeferredGlobalUpdate(cwd, ((command, args) => {
904
+ calls.push({ command, args: args });
905
+ return {
906
+ once() {
907
+ return this;
908
+ },
909
+ unref() { },
910
+ };
911
+ }), 'linux', 12345);
912
+ await writeFile(setupScopePath, JSON.stringify({ scope: 'project', installMode: 'legacy', mcpMode: 'compat' }, null, 2));
913
+ assert.equal(result.ok, true);
914
+ assert.equal(calls.length, 1);
915
+ assert.match(calls[0].args[1], /'omx' 'setup' '--scope' 'user' '--plugin' '--mcp' 'none' '--disable-team'/);
916
+ assert.doesNotMatch(calls[0].args[1], /compat/);
917
+ assert.doesNotMatch(calls[0].args[1], /legacy/);
918
+ }
919
+ finally {
920
+ await rm(cwd, { recursive: true, force: true });
921
+ }
922
+ });
923
+ it('quotes deferred setup command arguments at the shell boundary', () => {
924
+ const args = ['setup', '--scope', 'user project', '--mcp', "none'; echo pwned #", '--flag', ''];
925
+ assert.equal(formatDeferredSetupCommand('linux', 'omx tool', args), "'omx tool' 'setup' '--scope' 'user project' '--mcp' 'none'\\''; echo pwned #' '--flag' ''");
926
+ assert.equal(formatDeferredSetupCommand('win32', 'omx tool', args), "& 'omx tool' 'setup' '--scope' 'user project' '--mcp' 'none''; echo pwned #' '--flag' ''");
927
+ });
676
928
  });
677
929
  describe('post-update setup refresh handoff', () => {
678
930
  it('uses the installed package bin entry when resolving the refreshed CLI', async () => {
@@ -722,5 +974,58 @@ describe('post-update setup refresh handoff', () => {
722
974
  assert.equal(result.ok, true);
723
975
  assert.equal(receivedTimeout, undefined);
724
976
  });
977
+ it('passes persisted plugin setup choices to the updated CLI refresh', async () => {
978
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-update-plugin-refresh-'));
979
+ const received = [];
980
+ try {
981
+ await mkdir(join(cwd, '.omx'), { recursive: true });
982
+ await writeFile(join(cwd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'user', installMode: 'plugin', mcpMode: 'none', teamMode: 'disabled' }, null, 2));
983
+ const result = spawnInstalledSetupRefresh('/tmp/omx.js', cwd, ((command, args) => {
984
+ received.push({ command, args: args });
985
+ return { status: 0, error: undefined };
986
+ }));
987
+ assert.equal(result.ok, true);
988
+ assert.deepEqual(received[0]?.args, [
989
+ '/tmp/omx.js',
990
+ 'setup',
991
+ '--scope',
992
+ 'user',
993
+ '--plugin',
994
+ '--mcp',
995
+ 'none',
996
+ '--disable-team',
997
+ ]);
998
+ assert.deepEqual(resolveSetupRefreshArgs(cwd), [
999
+ 'setup',
1000
+ '--scope',
1001
+ 'user',
1002
+ '--plugin',
1003
+ '--mcp',
1004
+ 'none',
1005
+ '--disable-team',
1006
+ ]);
1007
+ }
1008
+ finally {
1009
+ await rm(cwd, { recursive: true, force: true });
1010
+ }
1011
+ });
1012
+ it('migrates legacy project-local scope when building update setup refresh args', async () => {
1013
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-update-plugin-legacy-scope-'));
1014
+ try {
1015
+ await mkdir(join(cwd, '.omx'), { recursive: true });
1016
+ await writeFile(join(cwd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'project-local', installMode: 'plugin', mcpMode: 'none' }, null, 2));
1017
+ assert.deepEqual(resolveSetupRefreshArgs(cwd), [
1018
+ 'setup',
1019
+ '--scope',
1020
+ 'project',
1021
+ '--plugin',
1022
+ '--mcp',
1023
+ 'none',
1024
+ ]);
1025
+ }
1026
+ finally {
1027
+ await rm(cwd, { recursive: true, force: true });
1028
+ }
1029
+ });
725
1030
  });
726
1031
  //# sourceMappingURL=update.test.js.map