oh-my-codex 0.19.1 → 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 (212) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -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__/plugin-marketplace-idempotent.test.js +3 -3
  59. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
  60. package/dist/cli/__tests__/resume.test.js +95 -6
  61. package/dist/cli/__tests__/resume.test.js.map +1 -1
  62. package/dist/cli/__tests__/setup-install-mode.test.js +46 -18
  63. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  64. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +3 -3
  65. package/dist/cli/__tests__/setup-refresh.test.js +29 -7
  66. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  67. package/dist/cli/__tests__/uninstall.test.js +4 -4
  68. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  69. package/dist/cli/agents.js +1 -1
  70. package/dist/cli/agents.js.map +1 -1
  71. package/dist/cli/capabilities.d.ts +3 -0
  72. package/dist/cli/capabilities.d.ts.map +1 -0
  73. package/dist/cli/capabilities.js +118 -0
  74. package/dist/cli/capabilities.js.map +1 -0
  75. package/dist/cli/doctor.d.ts +1 -1
  76. package/dist/cli/doctor.d.ts.map +1 -1
  77. package/dist/cli/doctor.js +9 -4
  78. package/dist/cli/doctor.js.map +1 -1
  79. package/dist/cli/index.d.ts +7 -4
  80. package/dist/cli/index.d.ts.map +1 -1
  81. package/dist/cli/index.js +77 -19
  82. package/dist/cli/index.js.map +1 -1
  83. package/dist/cli/plugin-marketplace.d.ts +1 -0
  84. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  85. package/dist/cli/plugin-marketplace.js +31 -0
  86. package/dist/cli/plugin-marketplace.js.map +1 -1
  87. package/dist/cli/setup.d.ts.map +1 -1
  88. package/dist/cli/setup.js +7 -4
  89. package/dist/cli/setup.js.map +1 -1
  90. package/dist/config/__tests__/generator-idempotent.test.js +23 -23
  91. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  92. package/dist/config/__tests__/generator-notify.test.js +9 -9
  93. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  94. package/dist/config/__tests__/models.test.js +51 -26
  95. package/dist/config/__tests__/models.test.js.map +1 -1
  96. package/dist/config/generator.d.ts +1 -1
  97. package/dist/config/generator.d.ts.map +1 -1
  98. package/dist/config/models.d.ts +16 -6
  99. package/dist/config/models.d.ts.map +1 -1
  100. package/dist/config/models.js +19 -8
  101. package/dist/config/models.js.map +1 -1
  102. package/dist/hooks/__tests__/keyword-detector.test.js +12 -4
  103. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  104. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +1 -1
  105. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +2 -2
  106. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  107. package/dist/hooks/__tests__/tmux-hook-engine.test.js +2 -2
  108. package/dist/leader/__tests__/contract.test.js +108 -1
  109. package/dist/leader/__tests__/contract.test.js.map +1 -1
  110. package/dist/leader/contract.d.ts +26 -0
  111. package/dist/leader/contract.d.ts.map +1 -1
  112. package/dist/leader/contract.js +170 -0
  113. package/dist/leader/contract.js.map +1 -1
  114. package/dist/modes/base.d.ts +1 -1
  115. package/dist/modes/base.d.ts.map +1 -1
  116. package/dist/pipeline/__tests__/stages.test.js +27 -1
  117. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  118. package/dist/pipeline/stages/ralplan.d.ts +2 -1
  119. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  120. package/dist/pipeline/stages/ralplan.js +1 -0
  121. package/dist/pipeline/stages/ralplan.js.map +1 -1
  122. package/dist/pipeline/stages/ultragoal.d.ts +5 -1
  123. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
  124. package/dist/pipeline/stages/ultragoal.js +14 -4
  125. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  126. package/dist/ralplan/__tests__/runtime.test.js +132 -0
  127. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  128. package/dist/ralplan/runtime.d.ts +17 -0
  129. package/dist/ralplan/runtime.d.ts.map +1 -1
  130. package/dist/ralplan/runtime.js +97 -1
  131. package/dist/ralplan/runtime.js.map +1 -1
  132. package/dist/scripts/__tests__/codex-native-hook.test.js +412 -0
  133. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  134. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  135. package/dist/scripts/codex-native-hook.js +238 -12
  136. package/dist/scripts/codex-native-hook.js.map +1 -1
  137. package/dist/state/__tests__/operations.test.js +450 -0
  138. package/dist/state/__tests__/operations.test.js.map +1 -1
  139. package/dist/state/__tests__/workflow-transition.test.js +14 -0
  140. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  141. package/dist/state/operations.d.ts.map +1 -1
  142. package/dist/state/operations.js +72 -11
  143. package/dist/state/operations.js.map +1 -1
  144. package/dist/state/terminal-normalization.d.ts +8 -0
  145. package/dist/state/terminal-normalization.d.ts.map +1 -0
  146. package/dist/state/terminal-normalization.js +127 -0
  147. package/dist/state/terminal-normalization.js.map +1 -0
  148. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  149. package/dist/state/workflow-transition-reconcile.js +3 -1
  150. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  151. package/dist/team/__tests__/delegation-policy.test.js +2 -2
  152. package/dist/team/__tests__/delegation-policy.test.js.map +1 -1
  153. package/dist/team/__tests__/model-contract.test.js +25 -25
  154. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  155. package/dist/team/__tests__/runtime.test.js +28 -28
  156. package/dist/team/__tests__/runtime.test.js.map +1 -1
  157. package/dist/team/__tests__/scaling.test.js +7 -7
  158. package/dist/team/__tests__/scaling.test.js.map +1 -1
  159. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +5 -5
  160. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -1
  161. package/dist/team/__tests__/tmux-session.test.js +12 -12
  162. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  163. package/dist/team/__tests__/worker-bootstrap.test.js +57 -9
  164. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  165. package/dist/team/__tests__/worker-runtime-identity.test.js +3 -3
  166. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  167. package/dist/team/model-contract.d.ts +1 -1
  168. package/dist/team/model-contract.d.ts.map +1 -1
  169. package/dist/team/runtime.d.ts.map +1 -1
  170. package/dist/team/runtime.js +11 -0
  171. package/dist/team/runtime.js.map +1 -1
  172. package/dist/team/worker-bootstrap.d.ts +2 -0
  173. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  174. package/dist/team/worker-bootstrap.js +6 -1
  175. package/dist/team/worker-bootstrap.js.map +1 -1
  176. package/dist/ultragoal/__tests__/artifacts.test.js +68 -1
  177. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  178. package/dist/ultragoal/artifacts.d.ts +5 -1
  179. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  180. package/dist/ultragoal/artifacts.js +41 -9
  181. package/dist/ultragoal/artifacts.js.map +1 -1
  182. package/dist/utils/__tests__/agents-model-table.test.js +7 -7
  183. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  184. package/dist/utils/__tests__/worktree-tool-context.test.d.ts +2 -0
  185. package/dist/utils/__tests__/worktree-tool-context.test.d.ts.map +1 -0
  186. package/dist/utils/__tests__/worktree-tool-context.test.js +118 -0
  187. package/dist/utils/__tests__/worktree-tool-context.test.js.map +1 -0
  188. package/dist/utils/worktree-tool-context.d.ts +25 -0
  189. package/dist/utils/worktree-tool-context.d.ts.map +1 -0
  190. package/dist/utils/worktree-tool-context.js +116 -0
  191. package/dist/utils/worktree-tool-context.js.map +1 -0
  192. package/package.json +1 -1
  193. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  194. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +96 -10
  195. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
  196. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -1
  197. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +5 -5
  198. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +3 -3
  199. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
  200. package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
  201. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +2 -2
  202. package/prompts/prometheus-strict-metis.md +1 -1
  203. package/skills/ai-slop-cleaner/SKILL.md +1 -1
  204. package/skills/code-review/SKILL.md +1 -1
  205. package/skills/ecomode/references/agent-tiers.md +1 -1
  206. package/skills/omx-setup/SKILL.md +5 -5
  207. package/skills/prometheus-strict/SKILL.md +3 -3
  208. package/skills/ralplan/SKILL.md +1 -1
  209. package/skills/team/SKILL.md +1 -1
  210. package/skills/ultrawork/references/agent-tiers.md +2 -2
  211. package/src/scripts/__tests__/codex-native-hook.test.ts +477 -0
  212. package/src/scripts/codex-native-hook.ts +272 -11
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";
@@ -42,10 +42,12 @@ import { runAuthHotswap } from "../auth/hotswap.js";
42
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";
43
43
  import { getBaseStateDir, getStateDir, listModeStateFilesWithScopePreference, } from "../mcp/state-paths.js";
44
44
  import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
45
+ import { normalizeTerminalWorkflowState } from "../state/terminal-normalization.js";
45
46
  import { readPersistedSetupPreferences, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
46
47
  import { discoverProjectRuntimeCodexHomes } from "./project-runtime-codex-homes.js";
47
- import { materializePackagedOmxPluginCache, packagedOmxPluginVersion, resolvePackagedOmxMarketplace, upsertLocalOmxMarketplaceRegistration, upsertLocalOmxPluginEnablement, } from "./plugin-marketplace.js";
48
+ import { discoverOmxPluginCacheDirs, hasLocalOmxPluginEnablement, materializePackagedOmxPluginCache, packagedOmxPluginVersion, resolvePackagedOmxMarketplace, upsertLocalOmxMarketplaceRegistration, upsertLocalOmxPluginEnablement, } from "./plugin-marketplace.js";
48
49
  import { escapeTomlString, readTopLevelTomlString, upsertTopLevelTomlString } from "../utils/toml.js";
50
+ import { CANONICAL_REASONING_EFFORTS, isAmbiguousUnsupportedReasoningEffort, } from "../config/models.js";
49
51
  export { readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
50
52
  import { SKILL_ACTIVE_STATE_MODE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, syncCanonicalSkillStateForMode, } from "../state/skill-active.js";
51
53
  import { isTrackedWorkflowMode } from "../state/workflow-transition.js";
@@ -70,9 +72,11 @@ import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
70
72
  import { collectInheritableTeamWorkerArgs as collectInheritableTeamWorkerArgsShared, parseTeamWorkerLaunchArgs, resolveTeamWorkerLaunchArgs, resolveTeamLowComplexityDefaultModel, TEAM_WORKER_INHERITED_MODEL_ENV, } from "../team/model-contract.js";
71
73
  import { parseWorktreeMode, planWorktreeTarget, ensureWorktree, } from "../team/worktree.js";
72
74
  import { ensureReusableNodeModules } from "../utils/repo-deps.js";
75
+ import { resolveWorktreeToolContext, worktreeToolContextEnv } from "../utils/worktree-tool-context.js";
73
76
  import { OMX_NOTIFY_TEMP_CONTRACT_ENV, parseNotifyTempContractFromArgs, serializeNotifyTempContract, } from "../notifications/temp-contract.js";
74
77
  import { execInjectCommand } from "../exec/followup.js";
75
78
  import { imagegenCommand } from "../imagegen/continuation.js";
79
+ import { capabilitiesCommand } from "./capabilities.js";
76
80
  export function resolveNotifyFallbackWatcherScript(pkgRoot = getPackageRoot()) {
77
81
  return resolveDistScript(pkgRoot, "notify-fallback-watcher.js");
78
82
  }
@@ -118,6 +122,8 @@ Usage:
118
122
  omx api Run native omx-api localhost gateway commands (serve|status|stop|generate)
119
123
  omx session Search and summarize local session history (--codex-home <path> escape hatch)
120
124
  omx url Passive URL reader (read <url> --json)
125
+ omx capabilities
126
+ Lock/check deterministic configured tool, skill, agent, and observation surfaces
121
127
  omx agents-init [path]
122
128
  Bootstrap lightweight AGENTS.md files for a repo/subtree
123
129
  omx agents Manage Codex native agent TOML files
@@ -223,9 +229,10 @@ const OMX_MODEL_INSTRUCTIONS_FILE_ENV = "OMX_MODEL_INSTRUCTIONS_FILE";
223
229
  const OMX_INSTANCE_OPTION = "@omx_instance_id";
224
230
  const OMX_RALPH_APPEND_INSTRUCTIONS_FILE_ENV = "OMX_RALPH_APPEND_INSTRUCTIONS_FILE";
225
231
  const OMX_AUTORESEARCH_APPEND_INSTRUCTIONS_FILE_ENV = "OMX_AUTORESEARCH_APPEND_INSTRUCTIONS_FILE";
226
- const REASONING_MODES = ["low", "medium", "high", "xhigh"];
232
+ const REASONING_MODES = CANONICAL_REASONING_EFFORTS;
227
233
  const REASONING_MODE_SET = new Set(REASONING_MODES);
228
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.';
229
236
  const ALLOWED_SHELLS = new Set([
230
237
  "/bin/sh",
231
238
  "/bin/bash",
@@ -264,6 +271,7 @@ const NESTED_HELP_COMMANDS = new Set([
264
271
  "agents-init",
265
272
  "deepinit",
266
273
  "exec",
274
+ "capabilities",
267
275
  "mission",
268
276
  "imagegen",
269
277
  "hooks",
@@ -567,6 +575,11 @@ async function linkOrCopyCodexHomeEntry(source, destination) {
567
575
  await copyFile(source, destination);
568
576
  }
569
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
+ }
570
583
  function isCodexSqliteArtifact(entryName) {
571
584
  return /^(?:state|logs)_\d+\.sqlite(?:-(?:shm|wal))?$/.test(entryName);
572
585
  }
@@ -629,7 +642,7 @@ async function persistProjectLaunchRuntimeHistoryArtifacts(runtimeCodexHome, pro
629
642
  continue;
630
643
  const destination = join(projectCodexHome, entryName);
631
644
  if (sourceStat.isDirectory()) {
632
- await cp(source, destination, { recursive: true, force: true, verbatimSymlinks: true });
645
+ await cp(source, destination, { recursive: true, force: true, preserveTimestamps: true, verbatimSymlinks: true });
633
646
  continue;
634
647
  }
635
648
  if (entryName === "history.jsonl" || entryName === "session_index.jsonl") {
@@ -637,7 +650,7 @@ async function persistProjectLaunchRuntimeHistoryArtifacts(runtimeCodexHome, pro
637
650
  continue;
638
651
  }
639
652
  if (sourceStat.isFile()) {
640
- await copyFile(source, destination);
653
+ await copyFilePreservingTimestamps(source, destination);
641
654
  }
642
655
  }
643
656
  }
@@ -666,10 +679,10 @@ async function materializeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, s
666
679
  await rm(destination, { recursive: true, force: true });
667
680
  const sourceStat = await lstat(source);
668
681
  if (sourceStat.isDirectory()) {
669
- await cp(source, destination, { recursive: true, force: true, dereference: true });
682
+ await cp(source, destination, { recursive: true, force: true, dereference: true, preserveTimestamps: true });
670
683
  continue;
671
684
  }
672
- await copyFile(source, destination);
685
+ await copyFilePreservingTimestamps(source, destination);
673
686
  }
674
687
  }
675
688
  async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceCodexHome, mergedHistorySourceRealpaths) {
@@ -684,7 +697,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
684
697
  const sourceStat = await stat(source);
685
698
  if (sourceStat.isDirectory()) {
686
699
  await mkdir(destination, { recursive: true });
687
- await cp(source, destination, { recursive: true, force: true, dereference: true });
700
+ await cp(source, destination, { recursive: true, force: true, dereference: true, preserveTimestamps: true });
688
701
  mergedHistorySourceRealpaths.add(sourceRealpath);
689
702
  continue;
690
703
  }
@@ -696,7 +709,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
696
709
  const destinationStat = await stat(destination);
697
710
  if (!destinationStat.isFile()) {
698
711
  await rm(destination, { recursive: true, force: true });
699
- await copyFile(source, destination);
712
+ await copyFilePreservingTimestamps(source, destination);
700
713
  mergedHistorySourceRealpaths.add(sourceRealpath);
701
714
  continue;
702
715
  }
@@ -707,7 +720,7 @@ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceC
707
720
  mergedHistorySourceRealpaths.add(sourceRealpath);
708
721
  continue;
709
722
  }
710
- await copyFile(source, destination);
723
+ await copyFilePreservingTimestamps(source, destination);
711
724
  mergedHistorySourceRealpaths.add(sourceRealpath);
712
725
  }
713
726
  }
@@ -821,10 +834,24 @@ export function parseResumeCodexHomeSelection(args) {
821
834
  projectOnly,
822
835
  };
823
836
  }
824
- 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 = {}) {
825
847
  const selectedCodexHomeDir = codexHomeDir && codexHomeDir.trim() !== ""
826
848
  ? codexHomeDir
827
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
+ }
828
855
  const packagedMarketplace = await resolvePackagedOmxMarketplace(pkgRoot);
829
856
  if (!packagedMarketplace) {
830
857
  return { status: "unavailable", prunedStaleDirs: [], configUpdated: false };
@@ -833,8 +860,6 @@ export async function preflightResumeOmxPluginState(codexHomeDir, pkgRoot = getP
833
860
  const version = materialized.version ?? (await packagedOmxPluginVersion(packagedMarketplace)) ?? undefined;
834
861
  const currentCacheDir = materialized.cacheDir ?? (version ? join(selectedCodexHomeDir, "plugins", "cache", "oh-my-codex-local", "oh-my-codex", version) : undefined);
835
862
  const prunedStaleDirs = [];
836
- const configPath = join(selectedCodexHomeDir, "config.toml");
837
- const existingConfig = existsSync(configPath) ? await readFile(configPath, "utf-8") : "";
838
863
  const nextConfig = upsertLocalOmxMarketplaceRegistration(upsertLocalOmxPluginEnablement(existingConfig), pkgRoot);
839
864
  const configUpdated = nextConfig !== existingConfig;
840
865
  if (configUpdated) {
@@ -856,7 +881,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
856
881
  const selection = parseResumeCodexHomeSelection(args);
857
882
  if (selection.explicitCodexHome) {
858
883
  const codexHomeOverride = resolve(selection.explicitCodexHome);
859
- await preflightResumeOmxPluginState(codexHomeOverride);
884
+ await preflightResumeOmxPluginState(codexHomeOverride, getPackageRoot(), { projectRoot: cwd });
860
885
  return {
861
886
  args: selection.args,
862
887
  prepared: {
@@ -870,7 +895,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
870
895
  const emptyRuntimeCodexHome = runtimeCodexHomePath(cwd, sessionId);
871
896
  await rm(emptyRuntimeCodexHome, { recursive: true, force: true });
872
897
  await mkdir(join(emptyRuntimeCodexHome, "sessions"), { recursive: true });
873
- await preflightResumeOmxPluginState(emptyRuntimeCodexHome);
898
+ await preflightResumeOmxPluginState(emptyRuntimeCodexHome, getPackageRoot(), { projectRoot: cwd });
874
899
  return {
875
900
  args: selection.args,
876
901
  prepared: {
@@ -883,7 +908,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
883
908
  includeHistoryArtifacts: true,
884
909
  extraHistoryCodexHomes: projectHomes.slice(1).map((home) => home.path),
885
910
  });
886
- await preflightResumeOmxPluginState(runtimeCodexHome);
911
+ await preflightResumeOmxPluginState(runtimeCodexHome, getPackageRoot(), { projectRoot: cwd });
887
912
  return {
888
913
  args: selection.args,
889
914
  prepared: {
@@ -895,7 +920,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
895
920
  includeHistoryArtifacts: true,
896
921
  extraHistoryCodexHomes: projectHomes.map((home) => home.path),
897
922
  });
898
- await preflightResumeOmxPluginState(prepared.codexHomeOverride);
923
+ await preflightResumeOmxPluginState(prepared.codexHomeOverride, getPackageRoot(), { projectRoot: cwd });
899
924
  return { args: selection.args, prepared };
900
925
  }
901
926
  export async function persistProjectLaunchRuntimeProjectTrustState(runtimeCodexHome, projectCodexHome) {
@@ -1469,6 +1494,16 @@ function applyDisposableWorktreeOmxRootForLaunch(ensuredWorktree, env = process.
1469
1494
  return;
1470
1495
  env.OMX_ROOT = omxRootOverride;
1471
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
+ }
1472
1507
  function launchArgRequestsDisposableWorktree(arg) {
1473
1508
  return arg === "--worktree" ||
1474
1509
  arg === "-w" ||
@@ -1835,6 +1870,7 @@ export async function main(args) {
1835
1870
  "exec",
1836
1871
  "mission",
1837
1872
  "imagegen",
1873
+ "capabilities",
1838
1874
  "setup",
1839
1875
  "update",
1840
1876
  "list",
@@ -1967,6 +2003,9 @@ export async function main(args) {
1967
2003
  case "api":
1968
2004
  await apiCommand(args.slice(1));
1969
2005
  break;
2006
+ case "capabilities":
2007
+ await capabilitiesCommand(args.slice(1));
2008
+ break;
1970
2009
  case "exec":
1971
2010
  if (launchArgs[0] === "inject") {
1972
2011
  await execInjectCommand(launchArgs);
@@ -2217,7 +2256,10 @@ async function reasoningCommand(args) {
2217
2256
  return;
2218
2257
  }
2219
2258
  if (!REASONING_MODE_SET.has(mode)) {
2220
- 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}`);
2221
2263
  }
2222
2264
  const { mkdir, readFile, writeFile } = await import("fs/promises");
2223
2265
  await mkdir(dirname(configPath), { recursive: true });
@@ -2260,6 +2302,7 @@ export async function launchWithAuthHotswap(args) {
2260
2302
  }
2261
2303
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2262
2304
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2305
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2263
2306
  try {
2264
2307
  await maybeCheckAndPromptUpdate(cwd);
2265
2308
  }
@@ -2367,6 +2410,7 @@ export async function launchWithHud(args) {
2367
2410
  });
2368
2411
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2369
2412
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2413
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2370
2414
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2371
2415
  try {
2372
2416
  await maybeCheckAndPromptUpdate(cwd);
@@ -2467,6 +2511,7 @@ export async function execWithOverlay(args) {
2467
2511
  }
2468
2512
  clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2469
2513
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2514
+ applyWorktreeToolContextForLaunch(cwd, ensuredLaunchWorktree);
2470
2515
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2471
2516
  try {
2472
2517
  await maybeCheckAndPromptUpdate(cwd);
@@ -2553,6 +2598,9 @@ export function normalizeCodexLaunchArgs(args) {
2553
2598
  reasoningMode = "xhigh";
2554
2599
  continue;
2555
2600
  }
2601
+ if (arg === "--max" || arg === "--ultra") {
2602
+ throw new Error(AMBIGUOUS_REASONING_MESSAGE);
2603
+ }
2556
2604
  if (arg === SPARK_FLAG) {
2557
2605
  // Spark model is injected into worker env only (not the leader). Consume flag.
2558
2606
  continue;
@@ -3616,6 +3664,14 @@ export async function cleanupPostLaunchModeStateFiles(cwd, sessionId, dependenci
3616
3664
  && Array.isArray(result.state.active_skills)
3617
3665
  && result.state.active_skills.length > 0;
3618
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
+ }
3619
3675
  if (mode === "ralph") {
3620
3676
  const completedAt = now().toISOString();
3621
3677
  if (markRalphCompletionAuditBlockedForPostLaunch(result.state, cwd, completedAt)) {
@@ -3651,6 +3707,7 @@ export async function cleanupPostLaunchModeStateFiles(cwd, sessionId, dependenci
3651
3707
  result.state.active = false;
3652
3708
  result.state.current_phase = "cancelled";
3653
3709
  result.state.completed_at = completedAt;
3710
+ result.state = normalizeTerminalWorkflowState(result.state, { mode, nowIso: completedAt }).state;
3654
3711
  if (mode === "ralph") {
3655
3712
  result.state.interrupted_at = completedAt;
3656
3713
  result.state.stop_reason = cleanPostLaunchString(result.state.stop_reason) || "session_exit";
@@ -3850,6 +3907,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3850
3907
  }, omxBin);
3851
3908
  const codexEnvWithSession = {
3852
3909
  ...codexBaseEnv,
3910
+ OMX_CODEX_LAUNCH_ID: randomUUID(),
3853
3911
  ...buildHudRuntimeEnv({ sessionId }).env,
3854
3912
  };
3855
3913
  const codexEnv = workerLaunchArgs