oh-my-codex 0.19.0 → 0.20.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 (245) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +8 -1
  4. package/crates/omx-api/src/lib.rs +3 -3
  5. package/crates/omx-api/tests/cli.rs +4 -4
  6. package/crates/omx-explore/src/main.rs +4 -4
  7. package/crates/omx-sparkshell/src/codex_bridge.rs +2 -2
  8. package/dist/agents/__tests__/definitions.test.js +3 -3
  9. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  10. package/dist/agents/__tests__/native-config.test.js +71 -42
  11. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  12. package/dist/agents/definitions.d.ts +1 -1
  13. package/dist/agents/definitions.d.ts.map +1 -1
  14. package/dist/agents/definitions.js +3 -3
  15. package/dist/agents/definitions.js.map +1 -1
  16. package/dist/agents/native-config.d.ts +2 -2
  17. package/dist/agents/native-config.d.ts.map +1 -1
  18. package/dist/agents/native-config.js +7 -5
  19. package/dist/agents/native-config.js.map +1 -1
  20. package/dist/autopilot/__tests__/planner-routing.test.js +19 -12
  21. package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
  22. package/dist/autopilot/__tests__/ralplan-gate.test.js +151 -0
  23. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  24. package/dist/autopilot/planner-routing.d.ts.map +1 -1
  25. package/dist/autopilot/planner-routing.js +4 -2
  26. package/dist/autopilot/planner-routing.js.map +1 -1
  27. package/dist/autopilot/ralplan-gate.d.ts +1 -0
  28. package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
  29. package/dist/autopilot/ralplan-gate.js +38 -2
  30. package/dist/autopilot/ralplan-gate.js.map +1 -1
  31. package/dist/autoresearch/runtime.d.ts +2 -0
  32. package/dist/autoresearch/runtime.d.ts.map +1 -1
  33. package/dist/autoresearch/runtime.js +8 -0
  34. package/dist/autoresearch/runtime.js.map +1 -1
  35. package/dist/capabilities/__tests__/lockfile.test.d.ts +2 -0
  36. package/dist/capabilities/__tests__/lockfile.test.d.ts.map +1 -0
  37. package/dist/capabilities/__tests__/lockfile.test.js +115 -0
  38. package/dist/capabilities/__tests__/lockfile.test.js.map +1 -0
  39. package/dist/capabilities/lockfile.d.ts +102 -0
  40. package/dist/capabilities/lockfile.d.ts.map +1 -0
  41. package/dist/capabilities/lockfile.js +334 -0
  42. package/dist/capabilities/lockfile.js.map +1 -0
  43. package/dist/cli/__tests__/agents.test.js +5 -5
  44. package/dist/cli/__tests__/agents.test.js.map +1 -1
  45. package/dist/cli/__tests__/capabilities.test.d.ts +2 -0
  46. package/dist/cli/__tests__/capabilities.test.d.ts.map +1 -0
  47. package/dist/cli/__tests__/capabilities.test.js +135 -0
  48. package/dist/cli/__tests__/capabilities.test.js.map +1 -0
  49. package/dist/cli/__tests__/codex-plugin-layout.test.js +237 -6
  50. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  51. package/dist/cli/__tests__/doctor-context-window-warning.test.js +9 -9
  52. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
  53. package/dist/cli/__tests__/doctor-invalid-config.test.js +1 -1
  54. package/dist/cli/__tests__/doctor-spark-routing.test.js +22 -6
  55. package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
  56. package/dist/cli/__tests__/index.test.js +53 -18
  57. package/dist/cli/__tests__/index.test.js.map +1 -1
  58. package/dist/cli/__tests__/mission.test.d.ts +2 -0
  59. package/dist/cli/__tests__/mission.test.d.ts.map +1 -0
  60. package/dist/cli/__tests__/mission.test.js +239 -0
  61. package/dist/cli/__tests__/mission.test.js.map +1 -0
  62. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +3 -3
  63. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
  64. package/dist/cli/__tests__/resume.test.js +95 -6
  65. package/dist/cli/__tests__/resume.test.js.map +1 -1
  66. package/dist/cli/__tests__/session-scoped-runtime.test.js +67 -0
  67. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  68. package/dist/cli/__tests__/setup-install-mode.test.js +46 -18
  69. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  70. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +3 -3
  71. package/dist/cli/__tests__/setup-refresh.test.js +29 -7
  72. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  73. package/dist/cli/__tests__/ultragoal.test.js +1 -1
  74. package/dist/cli/__tests__/uninstall.test.js +4 -4
  75. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  76. package/dist/cli/agents.js +1 -1
  77. package/dist/cli/agents.js.map +1 -1
  78. package/dist/cli/capabilities.d.ts +3 -0
  79. package/dist/cli/capabilities.d.ts.map +1 -0
  80. package/dist/cli/capabilities.js +118 -0
  81. package/dist/cli/capabilities.js.map +1 -0
  82. package/dist/cli/doctor.d.ts +1 -1
  83. package/dist/cli/doctor.d.ts.map +1 -1
  84. package/dist/cli/doctor.js +9 -4
  85. package/dist/cli/doctor.js.map +1 -1
  86. package/dist/cli/index.d.ts +7 -4
  87. package/dist/cli/index.d.ts.map +1 -1
  88. package/dist/cli/index.js +107 -23
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/cli/mission.d.ts +36 -0
  91. package/dist/cli/mission.d.ts.map +1 -0
  92. package/dist/cli/mission.js +443 -0
  93. package/dist/cli/mission.js.map +1 -0
  94. package/dist/cli/plugin-marketplace.d.ts +1 -0
  95. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  96. package/dist/cli/plugin-marketplace.js +31 -0
  97. package/dist/cli/plugin-marketplace.js.map +1 -1
  98. package/dist/cli/setup.d.ts.map +1 -1
  99. package/dist/cli/setup.js +7 -4
  100. package/dist/cli/setup.js.map +1 -1
  101. package/dist/config/__tests__/generator-idempotent.test.js +23 -23
  102. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  103. package/dist/config/__tests__/generator-notify.test.js +9 -9
  104. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  105. package/dist/config/__tests__/models.test.js +51 -26
  106. package/dist/config/__tests__/models.test.js.map +1 -1
  107. package/dist/config/generator.d.ts +1 -1
  108. package/dist/config/generator.d.ts.map +1 -1
  109. package/dist/config/models.d.ts +16 -6
  110. package/dist/config/models.d.ts.map +1 -1
  111. package/dist/config/models.js +19 -8
  112. package/dist/config/models.js.map +1 -1
  113. package/dist/hooks/__tests__/keyword-detector.test.js +12 -4
  114. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +1 -1
  116. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +2 -2
  117. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  118. package/dist/hooks/__tests__/tmux-hook-engine.test.js +2 -2
  119. package/dist/hud/__tests__/state.test.js +31 -6
  120. package/dist/hud/__tests__/state.test.js.map +1 -1
  121. package/dist/hud/state.d.ts.map +1 -1
  122. package/dist/hud/state.js +7 -3
  123. package/dist/hud/state.js.map +1 -1
  124. package/dist/leader/__tests__/contract.test.js +108 -1
  125. package/dist/leader/__tests__/contract.test.js.map +1 -1
  126. package/dist/leader/contract.d.ts +26 -0
  127. package/dist/leader/contract.d.ts.map +1 -1
  128. package/dist/leader/contract.js +170 -0
  129. package/dist/leader/contract.js.map +1 -1
  130. package/dist/mcp/__tests__/state-paths.test.js +32 -1
  131. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  132. package/dist/mcp/state-paths.d.ts +4 -0
  133. package/dist/mcp/state-paths.d.ts.map +1 -1
  134. package/dist/mcp/state-paths.js +6 -15
  135. package/dist/mcp/state-paths.js.map +1 -1
  136. package/dist/modes/base.d.ts +1 -1
  137. package/dist/modes/base.d.ts.map +1 -1
  138. package/dist/pipeline/__tests__/stages.test.js +27 -1
  139. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  140. package/dist/pipeline/stages/ralplan.d.ts +2 -1
  141. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  142. package/dist/pipeline/stages/ralplan.js +1 -0
  143. package/dist/pipeline/stages/ralplan.js.map +1 -1
  144. package/dist/pipeline/stages/ultragoal.d.ts +5 -1
  145. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
  146. package/dist/pipeline/stages/ultragoal.js +14 -4
  147. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  148. package/dist/ralplan/__tests__/consensus-gate.test.js +193 -0
  149. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  150. package/dist/ralplan/__tests__/runtime.test.js +132 -0
  151. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  152. package/dist/ralplan/consensus-gate.js +24 -3
  153. package/dist/ralplan/consensus-gate.js.map +1 -1
  154. package/dist/ralplan/runtime.d.ts +17 -0
  155. package/dist/ralplan/runtime.d.ts.map +1 -1
  156. package/dist/ralplan/runtime.js +97 -1
  157. package/dist/ralplan/runtime.js.map +1 -1
  158. package/dist/scripts/__tests__/codex-native-hook.test.js +762 -20
  159. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  160. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  161. package/dist/scripts/codex-native-hook.js +306 -22
  162. package/dist/scripts/codex-native-hook.js.map +1 -1
  163. package/dist/scripts/generate-catalog-docs.js +1 -0
  164. package/dist/scripts/generate-catalog-docs.js.map +1 -1
  165. package/dist/state/__tests__/operations.test.js +737 -0
  166. package/dist/state/__tests__/operations.test.js.map +1 -1
  167. package/dist/state/__tests__/skill-active.test.js +59 -0
  168. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  169. package/dist/state/__tests__/workflow-transition.test.js +14 -0
  170. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  171. package/dist/state/operations.d.ts.map +1 -1
  172. package/dist/state/operations.js +80 -17
  173. package/dist/state/operations.js.map +1 -1
  174. package/dist/state/skill-active.js +3 -3
  175. package/dist/state/skill-active.js.map +1 -1
  176. package/dist/state/terminal-normalization.d.ts +8 -0
  177. package/dist/state/terminal-normalization.d.ts.map +1 -0
  178. package/dist/state/terminal-normalization.js +127 -0
  179. package/dist/state/terminal-normalization.js.map +1 -0
  180. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  181. package/dist/state/workflow-transition-reconcile.js +3 -1
  182. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  183. package/dist/team/__tests__/delegation-policy.test.js +2 -2
  184. package/dist/team/__tests__/delegation-policy.test.js.map +1 -1
  185. package/dist/team/__tests__/model-contract.test.js +25 -25
  186. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  187. package/dist/team/__tests__/runtime.test.js +28 -28
  188. package/dist/team/__tests__/runtime.test.js.map +1 -1
  189. package/dist/team/__tests__/scaling.test.js +7 -7
  190. package/dist/team/__tests__/scaling.test.js.map +1 -1
  191. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +5 -5
  192. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -1
  193. package/dist/team/__tests__/tmux-session.test.js +12 -12
  194. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  195. package/dist/team/__tests__/worker-bootstrap.test.js +57 -9
  196. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  197. package/dist/team/__tests__/worker-runtime-identity.test.js +3 -3
  198. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  199. package/dist/team/model-contract.d.ts +1 -1
  200. package/dist/team/model-contract.d.ts.map +1 -1
  201. package/dist/team/runtime.d.ts.map +1 -1
  202. package/dist/team/runtime.js +11 -0
  203. package/dist/team/runtime.js.map +1 -1
  204. package/dist/team/worker-bootstrap.d.ts +2 -0
  205. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  206. package/dist/team/worker-bootstrap.js +6 -1
  207. package/dist/team/worker-bootstrap.js.map +1 -1
  208. package/dist/ultragoal/__tests__/artifacts.test.js +82 -5
  209. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  210. package/dist/ultragoal/artifacts.d.ts +5 -1
  211. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  212. package/dist/ultragoal/artifacts.js +111 -14
  213. package/dist/ultragoal/artifacts.js.map +1 -1
  214. package/dist/utils/__tests__/agents-model-table.test.js +7 -7
  215. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  216. package/dist/utils/__tests__/worktree-tool-context.test.d.ts +2 -0
  217. package/dist/utils/__tests__/worktree-tool-context.test.d.ts.map +1 -0
  218. package/dist/utils/__tests__/worktree-tool-context.test.js +118 -0
  219. package/dist/utils/__tests__/worktree-tool-context.test.js.map +1 -0
  220. package/dist/utils/worktree-tool-context.d.ts +25 -0
  221. package/dist/utils/worktree-tool-context.d.ts.map +1 -0
  222. package/dist/utils/worktree-tool-context.js +116 -0
  223. package/dist/utils/worktree-tool-context.js.map +1 -0
  224. package/package.json +1 -1
  225. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  226. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +96 -10
  227. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
  228. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -1
  229. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +5 -5
  230. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +3 -3
  231. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
  232. package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
  233. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +2 -2
  234. package/prompts/prometheus-strict-metis.md +1 -1
  235. package/skills/ai-slop-cleaner/SKILL.md +1 -1
  236. package/skills/code-review/SKILL.md +1 -1
  237. package/skills/ecomode/references/agent-tiers.md +1 -1
  238. package/skills/omx-setup/SKILL.md +5 -5
  239. package/skills/prometheus-strict/SKILL.md +3 -3
  240. package/skills/ralplan/SKILL.md +1 -1
  241. package/skills/team/SKILL.md +1 -1
  242. package/skills/ultrawork/references/agent-tiers.md +2 -2
  243. package/src/scripts/__tests__/codex-native-hook.test.ts +824 -7
  244. package/src/scripts/codex-native-hook.ts +347 -20
  245. package/src/scripts/generate-catalog-docs.ts +1 -0
package/dist/cli/index.js CHANGED
@@ -5,9 +5,9 @@
5
5
  import { execFileSync, spawn } from "child_process";
6
6
  import { basename, dirname, join, posix, resolve, win32 } from "path";
7
7
  import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "fs";
8
- import { copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from "fs/promises";
8
+ import { copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, utimes, writeFile } from "fs/promises";
9
9
  import { constants as osConstants, homedir } from "os";
10
- import { createHash } from "crypto";
10
+ import { createHash, randomUUID } from "crypto";
11
11
  import { setup, SETUP_MCP_MODES, SETUP_SCOPES, SETUP_TEAM_MODES, } from "./setup.js";
12
12
  import { uninstall } from "./uninstall.js";
13
13
  import { version } from "./version.js";
@@ -37,14 +37,17 @@ import { mcpServeCommand } from "./mcp-serve.js";
37
37
  import { adaptCommand } from "./adapt.js";
38
38
  import { listCommand } from "./list.js";
39
39
  import { authCommand } from "./auth.js";
40
+ import { missionCommand } from "./mission.js";
40
41
  import { runAuthHotswap } from "../auth/hotswap.js";
41
42
  import { MADMAX_FLAG, CODEX_BYPASS_FLAG, HIGH_REASONING_FLAG, XHIGH_REASONING_FLAG, SPARK_FLAG, MADMAX_SPARK_FLAG, CONFIG_FLAG, LONG_CONFIG_FLAG, } from "./constants.js";
42
43
  import { getBaseStateDir, getStateDir, listModeStateFilesWithScopePreference, } from "../mcp/state-paths.js";
43
44
  import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
45
+ import { normalizeTerminalWorkflowState } from "../state/terminal-normalization.js";
44
46
  import { readPersistedSetupPreferences, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
45
47
  import { discoverProjectRuntimeCodexHomes } from "./project-runtime-codex-homes.js";
46
- import { materializePackagedOmxPluginCache, packagedOmxPluginVersion, resolvePackagedOmxMarketplace, upsertLocalOmxMarketplaceRegistration, upsertLocalOmxPluginEnablement, } from "./plugin-marketplace.js";
48
+ import { discoverOmxPluginCacheDirs, hasLocalOmxPluginEnablement, materializePackagedOmxPluginCache, packagedOmxPluginVersion, resolvePackagedOmxMarketplace, upsertLocalOmxMarketplaceRegistration, upsertLocalOmxPluginEnablement, } from "./plugin-marketplace.js";
47
49
  import { escapeTomlString, readTopLevelTomlString, upsertTopLevelTomlString } from "../utils/toml.js";
50
+ import { CANONICAL_REASONING_EFFORTS, isAmbiguousUnsupportedReasoningEffort, } from "../config/models.js";
48
51
  export { readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
49
52
  import { SKILL_ACTIVE_STATE_MODE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, syncCanonicalSkillStateForMode, } from "../state/skill-active.js";
50
53
  import { isTrackedWorkflowMode } from "../state/workflow-transition.js";
@@ -69,9 +72,11 @@ import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
69
72
  import { collectInheritableTeamWorkerArgs as collectInheritableTeamWorkerArgsShared, parseTeamWorkerLaunchArgs, resolveTeamWorkerLaunchArgs, resolveTeamLowComplexityDefaultModel, TEAM_WORKER_INHERITED_MODEL_ENV, } from "../team/model-contract.js";
70
73
  import { parseWorktreeMode, planWorktreeTarget, ensureWorktree, } from "../team/worktree.js";
71
74
  import { ensureReusableNodeModules } from "../utils/repo-deps.js";
75
+ import { resolveWorktreeToolContext, worktreeToolContextEnv } from "../utils/worktree-tool-context.js";
72
76
  import { OMX_NOTIFY_TEMP_CONTRACT_ENV, parseNotifyTempContractFromArgs, serializeNotifyTempContract, } from "../notifications/temp-contract.js";
73
77
  import { execInjectCommand } from "../exec/followup.js";
74
78
  import { imagegenCommand } from "../imagegen/continuation.js";
79
+ import { capabilitiesCommand } from "./capabilities.js";
75
80
  export function resolveNotifyFallbackWatcherScript(pkgRoot = getPackageRoot()) {
76
81
  return resolveDistScript(pkgRoot, "notify-fallback-watcher.js");
77
82
  }
@@ -92,6 +97,8 @@ Usage:
92
97
  omx exec Run codex exec non-interactively with OMX AGENTS/overlay injection
93
98
  omx exec inject <session-id> --prompt <text>
94
99
  Queue audited follow-up instructions for a running non-interactive exec job
100
+ omx mission <file>
101
+ Run a prompt/checklist file sequentially through omx exec with durable summary
95
102
  omx imagegen continuation <session-id> --artifact <name>
96
103
  Queue a Stop-hook continuation for built-in image generation turns
97
104
  omx setup Install skills, prompts, CLI-first config, and scope-specific AGENTS.md
@@ -115,6 +122,8 @@ Usage:
115
122
  omx api Run native omx-api localhost gateway commands (serve|status|stop|generate)
116
123
  omx session Search and summarize local session history (--codex-home <path> escape hatch)
117
124
  omx url Passive URL reader (read <url> --json)
125
+ omx capabilities
126
+ Lock/check deterministic configured tool, skill, agent, and observation surfaces
118
127
  omx agents-init [path]
119
128
  Bootstrap lightweight AGENTS.md files for a repo/subtree
120
129
  omx agents Manage Codex native agent TOML files
@@ -220,9 +229,10 @@ const OMX_MODEL_INSTRUCTIONS_FILE_ENV = "OMX_MODEL_INSTRUCTIONS_FILE";
220
229
  const OMX_INSTANCE_OPTION = "@omx_instance_id";
221
230
  const OMX_RALPH_APPEND_INSTRUCTIONS_FILE_ENV = "OMX_RALPH_APPEND_INSTRUCTIONS_FILE";
222
231
  const OMX_AUTORESEARCH_APPEND_INSTRUCTIONS_FILE_ENV = "OMX_AUTORESEARCH_APPEND_INSTRUCTIONS_FILE";
223
- const REASONING_MODES = ["low", "medium", "high", "xhigh"];
232
+ const REASONING_MODES = CANONICAL_REASONING_EFFORTS;
224
233
  const REASONING_MODE_SET = new Set(REASONING_MODES);
225
234
  const REASONING_USAGE = "Usage: omx reasoning <low|medium|high|xhigh>";
235
+ const AMBIGUOUS_REASONING_MESSAGE = 'Codex/OMX canonical highest reasoning effort is "xhigh"; "max" and "ultra" are not accepted aliases.';
226
236
  const ALLOWED_SHELLS = new Set([
227
237
  "/bin/sh",
228
238
  "/bin/bash",
@@ -261,6 +271,8 @@ const NESTED_HELP_COMMANDS = new Set([
261
271
  "agents-init",
262
272
  "deepinit",
263
273
  "exec",
274
+ "capabilities",
275
+ "mission",
264
276
  "imagegen",
265
277
  "hooks",
266
278
  "list",
@@ -563,6 +575,11 @@ async function linkOrCopyCodexHomeEntry(source, destination) {
563
575
  await copyFile(source, destination);
564
576
  }
565
577
  }
578
+ async function copyFilePreservingTimestamps(source, destination) {
579
+ await copyFile(source, destination);
580
+ const sourceStat = await stat(source);
581
+ await utimes(destination, sourceStat.atime, sourceStat.mtime);
582
+ }
566
583
  function isCodexSqliteArtifact(entryName) {
567
584
  return /^(?:state|logs)_\d+\.sqlite(?:-(?:shm|wal))?$/.test(entryName);
568
585
  }
@@ -625,7 +642,7 @@ async function persistProjectLaunchRuntimeHistoryArtifacts(runtimeCodexHome, pro
625
642
  continue;
626
643
  const destination = join(projectCodexHome, entryName);
627
644
  if (sourceStat.isDirectory()) {
628
- await cp(source, destination, { recursive: true, force: true, verbatimSymlinks: true });
645
+ await cp(source, destination, { recursive: true, force: true, preserveTimestamps: true, verbatimSymlinks: true });
629
646
  continue;
630
647
  }
631
648
  if (entryName === "history.jsonl" || entryName === "session_index.jsonl") {
@@ -633,7 +650,7 @@ async function persistProjectLaunchRuntimeHistoryArtifacts(runtimeCodexHome, pro
633
650
  continue;
634
651
  }
635
652
  if (sourceStat.isFile()) {
636
- await copyFile(source, destination);
653
+ await copyFilePreservingTimestamps(source, destination);
637
654
  }
638
655
  }
639
656
  }
@@ -662,10 +679,10 @@ async function materializeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, s
662
679
  await rm(destination, { recursive: true, force: true });
663
680
  const sourceStat = await lstat(source);
664
681
  if (sourceStat.isDirectory()) {
665
- await cp(source, destination, { recursive: true, force: true, dereference: true });
682
+ await cp(source, destination, { recursive: true, force: true, dereference: true, preserveTimestamps: true });
666
683
  continue;
667
684
  }
668
- await copyFile(source, destination);
685
+ await copyFilePreservingTimestamps(source, destination);
669
686
  }
670
687
  }
671
688
  async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceCodexHome, mergedHistorySourceRealpaths) {
@@ -680,7 +697,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
680
697
  const sourceStat = await stat(source);
681
698
  if (sourceStat.isDirectory()) {
682
699
  await mkdir(destination, { recursive: true });
683
- await cp(source, destination, { recursive: true, force: true, dereference: true });
700
+ await cp(source, destination, { recursive: true, force: true, dereference: true, preserveTimestamps: true });
684
701
  mergedHistorySourceRealpaths.add(sourceRealpath);
685
702
  continue;
686
703
  }
@@ -692,7 +709,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
692
709
  const destinationStat = await stat(destination);
693
710
  if (!destinationStat.isFile()) {
694
711
  await rm(destination, { recursive: true, force: true });
695
- await copyFile(source, destination);
712
+ await copyFilePreservingTimestamps(source, destination);
696
713
  mergedHistorySourceRealpaths.add(sourceRealpath);
697
714
  continue;
698
715
  }
@@ -703,7 +720,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
703
720
  mergedHistorySourceRealpaths.add(sourceRealpath);
704
721
  continue;
705
722
  }
706
- await copyFile(source, destination);
723
+ await copyFilePreservingTimestamps(source, destination);
707
724
  mergedHistorySourceRealpaths.add(sourceRealpath);
708
725
  }
709
726
  }
@@ -817,10 +834,24 @@ export function parseResumeCodexHomeSelection(args) {
817
834
  projectOnly,
818
835
  };
819
836
  }
820
- export async function preflightResumeOmxPluginState(codexHomeDir, pkgRoot = getPackageRoot()) {
837
+ async function shouldPreflightResumeOmxPluginState(selectedCodexHomeDir, existingConfig, options) {
838
+ if (hasLocalOmxPluginEnablement(existingConfig))
839
+ return true;
840
+ if (options.projectRoot &&
841
+ readPersistedSetupPreferences(options.projectRoot)?.installMode === "plugin") {
842
+ return true;
843
+ }
844
+ return (await discoverOmxPluginCacheDirs(selectedCodexHomeDir)).length > 0;
845
+ }
846
+ export async function preflightResumeOmxPluginState(codexHomeDir, pkgRoot = getPackageRoot(), options = {}) {
821
847
  const selectedCodexHomeDir = codexHomeDir && codexHomeDir.trim() !== ""
822
848
  ? codexHomeDir
823
849
  : join(homedir(), ".codex");
850
+ const configPath = join(selectedCodexHomeDir, "config.toml");
851
+ const existingConfig = existsSync(configPath) ? await readFile(configPath, "utf-8") : "";
852
+ if (!(await shouldPreflightResumeOmxPluginState(selectedCodexHomeDir, existingConfig, options))) {
853
+ return { status: "skipped", prunedStaleDirs: [], configUpdated: false };
854
+ }
824
855
  const packagedMarketplace = await resolvePackagedOmxMarketplace(pkgRoot);
825
856
  if (!packagedMarketplace) {
826
857
  return { status: "unavailable", prunedStaleDirs: [], configUpdated: false };
@@ -829,8 +860,6 @@ export async function preflightResumeOmxPluginState(codexHomeDir, pkgRoot = getP
829
860
  const version = materialized.version ?? (await packagedOmxPluginVersion(packagedMarketplace)) ?? undefined;
830
861
  const currentCacheDir = materialized.cacheDir ?? (version ? join(selectedCodexHomeDir, "plugins", "cache", "oh-my-codex-local", "oh-my-codex", version) : undefined);
831
862
  const prunedStaleDirs = [];
832
- const configPath = join(selectedCodexHomeDir, "config.toml");
833
- const existingConfig = existsSync(configPath) ? await readFile(configPath, "utf-8") : "";
834
863
  const nextConfig = upsertLocalOmxMarketplaceRegistration(upsertLocalOmxPluginEnablement(existingConfig), pkgRoot);
835
864
  const configUpdated = nextConfig !== existingConfig;
836
865
  if (configUpdated) {
@@ -852,7 +881,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
852
881
  const selection = parseResumeCodexHomeSelection(args);
853
882
  if (selection.explicitCodexHome) {
854
883
  const codexHomeOverride = resolve(selection.explicitCodexHome);
855
- await preflightResumeOmxPluginState(codexHomeOverride);
884
+ await preflightResumeOmxPluginState(codexHomeOverride, getPackageRoot(), { projectRoot: cwd });
856
885
  return {
857
886
  args: selection.args,
858
887
  prepared: {
@@ -866,7 +895,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
866
895
  const emptyRuntimeCodexHome = runtimeCodexHomePath(cwd, sessionId);
867
896
  await rm(emptyRuntimeCodexHome, { recursive: true, force: true });
868
897
  await mkdir(join(emptyRuntimeCodexHome, "sessions"), { recursive: true });
869
- await preflightResumeOmxPluginState(emptyRuntimeCodexHome);
898
+ await preflightResumeOmxPluginState(emptyRuntimeCodexHome, getPackageRoot(), { projectRoot: cwd });
870
899
  return {
871
900
  args: selection.args,
872
901
  prepared: {
@@ -879,7 +908,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
879
908
  includeHistoryArtifacts: true,
880
909
  extraHistoryCodexHomes: projectHomes.slice(1).map((home) => home.path),
881
910
  });
882
- await preflightResumeOmxPluginState(runtimeCodexHome);
911
+ await preflightResumeOmxPluginState(runtimeCodexHome, getPackageRoot(), { projectRoot: cwd });
883
912
  return {
884
913
  args: selection.args,
885
914
  prepared: {
@@ -891,7 +920,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
891
920
  includeHistoryArtifacts: true,
892
921
  extraHistoryCodexHomes: projectHomes.map((home) => home.path),
893
922
  });
894
- await preflightResumeOmxPluginState(prepared.codexHomeOverride);
923
+ await preflightResumeOmxPluginState(prepared.codexHomeOverride, getPackageRoot(), { projectRoot: cwd });
895
924
  return { args: selection.args, prepared };
896
925
  }
897
926
  export async function persistProjectLaunchRuntimeProjectTrustState(runtimeCodexHome, projectCodexHome) {
@@ -1465,6 +1494,16 @@ function applyDisposableWorktreeOmxRootForLaunch(ensuredWorktree, env = process.
1465
1494
  return;
1466
1495
  env.OMX_ROOT = omxRootOverride;
1467
1496
  }
1497
+ function applyWorktreeToolContextForLaunch(cwd, ensuredWorktree, env = process.env) {
1498
+ const context = resolveWorktreeToolContext({
1499
+ cwd,
1500
+ scope: "launch",
1501
+ repoRoot: ensuredWorktree?.enabled ? ensuredWorktree.repoRoot : undefined,
1502
+ worktreeRoot: ensuredWorktree?.enabled ? ensuredWorktree.worktreePath : cwd,
1503
+ env,
1504
+ });
1505
+ Object.assign(env, worktreeToolContextEnv(context));
1506
+ }
1468
1507
  function launchArgRequestsDisposableWorktree(arg) {
1469
1508
  return arg === "--worktree" ||
1470
1509
  arg === "-w" ||
@@ -1829,7 +1868,9 @@ export async function main(args) {
1829
1868
  const knownCommands = new Set([
1830
1869
  "launch",
1831
1870
  "exec",
1871
+ "mission",
1832
1872
  "imagegen",
1873
+ "capabilities",
1833
1874
  "setup",
1834
1875
  "update",
1835
1876
  "list",
@@ -1962,6 +2003,9 @@ export async function main(args) {
1962
2003
  case "api":
1963
2004
  await apiCommand(args.slice(1));
1964
2005
  break;
2006
+ case "capabilities":
2007
+ await capabilitiesCommand(args.slice(1));
2008
+ break;
1965
2009
  case "exec":
1966
2010
  if (launchArgs[0] === "inject") {
1967
2011
  await execInjectCommand(launchArgs);
@@ -1970,6 +2014,18 @@ export async function main(args) {
1970
2014
  await execWithOverlay(launchArgs);
1971
2015
  }
1972
2016
  break;
2017
+ case "mission":
2018
+ await missionCommand(args.slice(1), {
2019
+ runTask: async (prompt, codexArgs) => {
2020
+ const priorExitCode = process.exitCode;
2021
+ process.exitCode = undefined;
2022
+ await execWithOverlay([...codexArgs, prompt]);
2023
+ const exitCode = typeof process.exitCode === "number" ? process.exitCode : 0;
2024
+ process.exitCode = priorExitCode;
2025
+ return exitCode;
2026
+ },
2027
+ });
2028
+ break;
1973
2029
  case "imagegen":
1974
2030
  await imagegenCommand(args.slice(1));
1975
2031
  break;
@@ -2092,6 +2148,11 @@ async function readStaleCurrentAutopilotStatus(cwd) {
2092
2148
  return null;
2093
2149
  return { phase: phase ?? "active" };
2094
2150
  }
2151
+ function formatDurableUltragoalStatusForCli(status) {
2152
+ return status === "failed"
2153
+ ? "ultragoal: FAILED (phase: failed)"
2154
+ : `ultragoal: ACTIVE (phase: ${status})`;
2155
+ }
2095
2156
  async function showStatus() {
2096
2157
  const { readFile } = await import("fs/promises");
2097
2158
  const cwd = process.cwd();
@@ -2128,7 +2189,7 @@ async function showStatus() {
2128
2189
  const ultragoalState = await readUltragoalState(cwd).catch(() => null);
2129
2190
  if (states.length === 0) {
2130
2191
  if (ultragoalState?.active) {
2131
- console.log(`ultragoal: ACTIVE (phase: ${ultragoalState.status})`);
2192
+ console.log(formatDurableUltragoalStatusForCli(ultragoalState.status ?? "active"));
2132
2193
  return;
2133
2194
  }
2134
2195
  const staleAutopilot = await readStaleCurrentAutopilotStatus(cwd);
@@ -2139,6 +2200,7 @@ async function showStatus() {
2139
2200
  console.log("No active modes.");
2140
2201
  return;
2141
2202
  }
2203
+ let hasAuthoritativeActiveUltragoalMode = false;
2142
2204
  for (const path of states) {
2143
2205
  const content = await readFile(path, "utf-8");
2144
2206
  let state;
@@ -2151,12 +2213,15 @@ async function showStatus() {
2151
2213
  }
2152
2214
  const file = basename(path);
2153
2215
  const mode = file.replace("-state.json", "");
2154
- if (mode === "ultragoal" && ultragoalState?.active)
2216
+ if (mode === "ultragoal" && state.active === true) {
2217
+ hasAuthoritativeActiveUltragoalMode = true;
2218
+ }
2219
+ if (mode === "ultragoal" && ultragoalState?.active && state.active !== true)
2155
2220
  continue;
2156
2221
  console.log(`${mode}: ${state.active === true ? "ACTIVE" : "inactive"} (phase: ${String(state.current_phase || "n/a")})`);
2157
2222
  }
2158
- if (ultragoalState?.active) {
2159
- console.log(`ultragoal: ACTIVE (phase: ${ultragoalState.status})`);
2223
+ if (ultragoalState?.active && !hasAuthoritativeActiveUltragoalMode) {
2224
+ console.log(formatDurableUltragoalStatusForCli(ultragoalState.status ?? "active"));
2160
2225
  }
2161
2226
  if (!hasAuthoritativeActiveMode && !ultragoalState?.active) {
2162
2227
  const staleAutopilot = await readStaleCurrentAutopilotStatus(cwd);
@@ -2191,7 +2256,10 @@ async function reasoningCommand(args) {
2191
2256
  return;
2192
2257
  }
2193
2258
  if (!REASONING_MODE_SET.has(mode)) {
2194
- throw new Error(`Invalid reasoning mode "${mode}". Expected one of: ${REASONING_MODES.join(", ")}.\n${REASONING_USAGE}`);
2259
+ const guidance = isAmbiguousUnsupportedReasoningEffort(mode)
2260
+ ? `${AMBIGUOUS_REASONING_MESSAGE}\n`
2261
+ : "";
2262
+ throw new Error(`${guidance}Invalid reasoning mode "${mode}". Expected one of: ${REASONING_MODES.join(", ")}.\n${REASONING_USAGE}`);
2195
2263
  }
2196
2264
  const { mkdir, readFile, writeFile } = await import("fs/promises");
2197
2265
  await mkdir(dirname(configPath), { recursive: true });
@@ -2234,6 +2302,7 @@ export async function launchWithAuthHotswap(args) {
2234
2302
  }
2235
2303
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2236
2304
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2305
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2237
2306
  try {
2238
2307
  await maybeCheckAndPromptUpdate(cwd);
2239
2308
  }
@@ -2341,6 +2410,7 @@ export async function launchWithHud(args) {
2341
2410
  });
2342
2411
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2343
2412
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2413
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2344
2414
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2345
2415
  try {
2346
2416
  await maybeCheckAndPromptUpdate(cwd);
@@ -2441,6 +2511,7 @@ export async function execWithOverlay(args) {
2441
2511
  }
2442
2512
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2443
2513
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2514
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2444
2515
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2445
2516
  try {
2446
2517
  await maybeCheckAndPromptUpdate(cwd);
@@ -2527,6 +2598,9 @@ export function normalizeCodexLaunchArgs(args) {
2527
2598
  reasoningMode = "xhigh";
2528
2599
  continue;
2529
2600
  }
2601
+ if (arg === "--max" || arg === "--ultra") {
2602
+ throw new Error(AMBIGUOUS_REASONING_MESSAGE);
2603
+ }
2530
2604
  if (arg === SPARK_FLAG) {
2531
2605
  // Spark model is injected into worker env only (not the leader). Consume flag.
2532
2606
  continue;
@@ -3590,6 +3664,14 @@ export async function cleanupPostLaunchModeStateFiles(cwd, sessionId, dependenci
3590
3664
  && Array.isArray(result.state.active_skills)
3591
3665
  && result.state.active_skills.length > 0;
3592
3666
  if (result.state.active !== true && !skillStateStillVisible) {
3667
+ const completedAt = now().toISOString();
3668
+ const normalized = mode === SKILL_ACTIVE_STATE_MODE
3669
+ ? { state: result.state, changed: false }
3670
+ : normalizeTerminalWorkflowState(result.state, { mode, nowIso: completedAt });
3671
+ if (normalized.changed) {
3672
+ result.state = normalized.state;
3673
+ await writeFile(path, JSON.stringify(result.state, null, 2));
3674
+ }
3593
3675
  if (mode === "ralph") {
3594
3676
  const completedAt = now().toISOString();
3595
3677
  if (markRalphCompletionAuditBlockedForPostLaunch(result.state, cwd, completedAt)) {
@@ -3625,6 +3707,7 @@ export async function cleanupPostLaunchModeStateFiles(cwd, sessionId, dependenci
3625
3707
  result.state.active = false;
3626
3708
  result.state.current_phase = "cancelled";
3627
3709
  result.state.completed_at = completedAt;
3710
+ result.state = normalizeTerminalWorkflowState(result.state, { mode, nowIso: completedAt }).state;
3628
3711
  if (mode === "ralph") {
3629
3712
  result.state.interrupted_at = completedAt;
3630
3713
  result.state.stop_reason = cleanPostLaunchString(result.state.stop_reason) || "session_exit";
@@ -3824,6 +3907,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3824
3907
  }, omxBin);
3825
3908
  const codexEnvWithSession = {
3826
3909
  ...codexBaseEnv,
3910
+ OMX_CODEX_LAUNCH_ID: randomUUID(),
3827
3911
  ...buildHudRuntimeEnv({ sessionId }).env,
3828
3912
  };
3829
3913
  const codexEnv = workerLaunchArgs