oh-my-codex 0.18.16 → 0.19.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 (208) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/crates/omx-sparkshell/tests/execution.rs +8 -1
  4. package/dist/agents/__tests__/definitions.test.js +5 -5
  5. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  6. package/dist/agents/__tests__/native-config.test.js +18 -14
  7. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  8. package/dist/agents/definitions.d.ts +2 -2
  9. package/dist/agents/definitions.d.ts.map +1 -1
  10. package/dist/agents/definitions.js +4 -4
  11. package/dist/agents/definitions.js.map +1 -1
  12. package/dist/agents/native-config.d.ts +1 -0
  13. package/dist/agents/native-config.d.ts.map +1 -1
  14. package/dist/agents/native-config.js +18 -16
  15. package/dist/agents/native-config.js.map +1 -1
  16. package/dist/auth/hotswap.d.ts.map +1 -1
  17. package/dist/auth/hotswap.js +17 -4
  18. package/dist/auth/hotswap.js.map +1 -1
  19. package/dist/autopilot/__tests__/planner-routing.test.js +2 -2
  20. package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
  21. package/dist/autopilot/fsm.d.ts +1 -1
  22. package/dist/autopilot/fsm.d.ts.map +1 -1
  23. package/dist/autopilot/fsm.js +1 -1
  24. package/dist/autopilot/fsm.js.map +1 -1
  25. package/dist/cli/__tests__/auth.test.js +78 -3
  26. package/dist/cli/__tests__/auth.test.js.map +1 -1
  27. package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -5
  28. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  29. package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -0
  30. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  31. package/dist/cli/__tests__/index.test.js +96 -8
  32. package/dist/cli/__tests__/index.test.js.map +1 -1
  33. package/dist/cli/__tests__/launch-fallback.test.js +135 -1
  34. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  35. package/dist/cli/__tests__/mcp-parity.test.js +2 -4
  36. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  37. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +14 -0
  38. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
  39. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +8 -0
  40. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  41. package/dist/cli/__tests__/resume.test.js +229 -1
  42. package/dist/cli/__tests__/resume.test.js.map +1 -1
  43. package/dist/cli/__tests__/session-scoped-runtime.test.js +46 -0
  44. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  45. package/dist/cli/__tests__/setup-install-mode.test.js +37 -0
  46. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  47. package/dist/cli/__tests__/ultragoal.test.js +21 -0
  48. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  49. package/dist/cli/__tests__/version.test.js +13 -1
  50. package/dist/cli/__tests__/version.test.js.map +1 -1
  51. package/dist/cli/auth.d.ts +1 -1
  52. package/dist/cli/auth.d.ts.map +1 -1
  53. package/dist/cli/auth.js +49 -9
  54. package/dist/cli/auth.js.map +1 -1
  55. package/dist/cli/index.d.ts +25 -2
  56. package/dist/cli/index.d.ts.map +1 -1
  57. package/dist/cli/index.js +233 -32
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  60. package/dist/cli/plugin-marketplace.js +22 -1
  61. package/dist/cli/plugin-marketplace.js.map +1 -1
  62. package/dist/cli/ralph.d.ts.map +1 -1
  63. package/dist/cli/ralph.js +4 -0
  64. package/dist/cli/ralph.js.map +1 -1
  65. package/dist/cli/setup.d.ts.map +1 -1
  66. package/dist/cli/setup.js +3 -1
  67. package/dist/cli/setup.js.map +1 -1
  68. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +7 -0
  69. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
  70. package/dist/goal-workflows/codex-goal-snapshot.js +1 -1
  71. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  72. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +12 -0
  73. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  74. package/dist/hooks/__tests__/keyword-detector.test.js +267 -7
  75. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  76. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  77. package/dist/hooks/keyword-detector.js +143 -30
  78. package/dist/hooks/keyword-detector.js.map +1 -1
  79. package/dist/hud/__tests__/reconcile.test.js +121 -0
  80. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  81. package/dist/hud/__tests__/state.test.js +110 -0
  82. package/dist/hud/__tests__/state.test.js.map +1 -1
  83. package/dist/hud/__tests__/tmux.test.js +1 -1
  84. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  85. package/dist/hud/reconcile.d.ts +3 -1
  86. package/dist/hud/reconcile.d.ts.map +1 -1
  87. package/dist/hud/reconcile.js +281 -151
  88. package/dist/hud/reconcile.js.map +1 -1
  89. package/dist/hud/render.d.ts.map +1 -1
  90. package/dist/hud/render.js +4 -2
  91. package/dist/hud/render.js.map +1 -1
  92. package/dist/hud/state.d.ts.map +1 -1
  93. package/dist/hud/state.js +44 -12
  94. package/dist/hud/state.js.map +1 -1
  95. package/dist/hud/tmux.d.ts.map +1 -1
  96. package/dist/hud/tmux.js +1 -4
  97. package/dist/hud/tmux.js.map +1 -1
  98. package/dist/hud/types.d.ts +5 -0
  99. package/dist/hud/types.d.ts.map +1 -1
  100. package/dist/hud/types.js.map +1 -1
  101. package/dist/leader/__tests__/contract.test.d.ts +2 -0
  102. package/dist/leader/__tests__/contract.test.d.ts.map +1 -0
  103. package/dist/leader/__tests__/contract.test.js +75 -0
  104. package/dist/leader/__tests__/contract.test.js.map +1 -0
  105. package/dist/leader/contract.d.ts +26 -0
  106. package/dist/leader/contract.d.ts.map +1 -0
  107. package/dist/leader/contract.js +97 -0
  108. package/dist/leader/contract.js.map +1 -0
  109. package/dist/modes/base.d.ts.map +1 -1
  110. package/dist/modes/base.js +22 -7
  111. package/dist/modes/base.js.map +1 -1
  112. package/dist/notifications/__tests__/dispatcher.test.js +16 -0
  113. package/dist/notifications/__tests__/dispatcher.test.js.map +1 -1
  114. package/dist/notifications/__tests__/profiles.test.js +87 -0
  115. package/dist/notifications/__tests__/profiles.test.js.map +1 -1
  116. package/dist/notifications/config.d.ts +1 -0
  117. package/dist/notifications/config.d.ts.map +1 -1
  118. package/dist/notifications/config.js +60 -22
  119. package/dist/notifications/config.js.map +1 -1
  120. package/dist/notifications/dispatcher.d.ts.map +1 -1
  121. package/dist/notifications/dispatcher.js +6 -16
  122. package/dist/notifications/dispatcher.js.map +1 -1
  123. package/dist/pipeline/__tests__/stages.test.js +2 -0
  124. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  125. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
  126. package/dist/pipeline/stages/ultragoal.js +6 -1
  127. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  128. package/dist/question/__tests__/renderer.test.js +58 -4
  129. package/dist/question/__tests__/renderer.test.js.map +1 -1
  130. package/dist/question/renderer.d.ts +1 -1
  131. package/dist/question/renderer.d.ts.map +1 -1
  132. package/dist/question/renderer.js +73 -5
  133. package/dist/question/renderer.js.map +1 -1
  134. package/dist/ralplan/__tests__/runtime.test.js +202 -0
  135. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  136. package/dist/ralplan/runtime.d.ts +7 -0
  137. package/dist/ralplan/runtime.d.ts.map +1 -1
  138. package/dist/ralplan/runtime.js +63 -4
  139. package/dist/ralplan/runtime.js.map +1 -1
  140. package/dist/scripts/__tests__/codex-native-hook.test.js +8484 -4560
  141. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  142. package/dist/scripts/codex-native-hook.d.ts +1 -0
  143. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  144. package/dist/scripts/codex-native-hook.js +4387 -190
  145. package/dist/scripts/codex-native-hook.js.map +1 -1
  146. package/dist/state/__tests__/operations.test.js +1137 -0
  147. package/dist/state/__tests__/operations.test.js.map +1 -1
  148. package/dist/state/__tests__/planning-gate.test.js +410 -0
  149. package/dist/state/__tests__/planning-gate.test.js.map +1 -1
  150. package/dist/state/operations.d.ts +10 -0
  151. package/dist/state/operations.d.ts.map +1 -1
  152. package/dist/state/operations.js +242 -8
  153. package/dist/state/operations.js.map +1 -1
  154. package/dist/state/skill-active.d.ts +4 -1
  155. package/dist/state/skill-active.d.ts.map +1 -1
  156. package/dist/state/skill-active.js +5 -3
  157. package/dist/state/skill-active.js.map +1 -1
  158. package/dist/state/workflow-transition.d.ts.map +1 -1
  159. package/dist/state/workflow-transition.js +642 -1
  160. package/dist/state/workflow-transition.js.map +1 -1
  161. package/dist/subagents/__tests__/tracker.test.js +248 -1
  162. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  163. package/dist/subagents/tracker.d.ts +60 -0
  164. package/dist/subagents/tracker.d.ts.map +1 -1
  165. package/dist/subagents/tracker.js +225 -1
  166. package/dist/subagents/tracker.js.map +1 -1
  167. package/dist/team/__tests__/model-contract.test.js +72 -4
  168. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  169. package/dist/team/__tests__/runtime.test.js +44 -2
  170. package/dist/team/__tests__/runtime.test.js.map +1 -1
  171. package/dist/team/__tests__/tmux-session.test.js +127 -8
  172. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  173. package/dist/team/__tests__/worker-runtime-identity.test.js +89 -0
  174. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  175. package/dist/team/model-contract.d.ts +3 -0
  176. package/dist/team/model-contract.d.ts.map +1 -1
  177. package/dist/team/model-contract.js +42 -5
  178. package/dist/team/model-contract.js.map +1 -1
  179. package/dist/team/runtime.d.ts +2 -1
  180. package/dist/team/runtime.d.ts.map +1 -1
  181. package/dist/team/runtime.js +21 -11
  182. package/dist/team/runtime.js.map +1 -1
  183. package/dist/team/scaling.d.ts.map +1 -1
  184. package/dist/team/scaling.js +13 -11
  185. package/dist/team/scaling.js.map +1 -1
  186. package/dist/team/tmux-session.d.ts +1 -0
  187. package/dist/team/tmux-session.d.ts.map +1 -1
  188. package/dist/team/tmux-session.js +63 -13
  189. package/dist/team/tmux-session.js.map +1 -1
  190. package/dist/ultragoal/__tests__/artifacts.test.js +7 -0
  191. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  192. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  193. package/dist/ultragoal/artifacts.js +5 -0
  194. package/dist/ultragoal/artifacts.js.map +1 -1
  195. package/dist/utils/__tests__/agents-model-table.test.js +2 -2
  196. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  197. package/package.json +1 -1
  198. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  199. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +19 -7
  200. package/plugins/oh-my-codex/skills/code-review/SKILL.md +16 -0
  201. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +23 -0
  202. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +3 -2
  203. package/skills/code-review/SKILL.md +16 -0
  204. package/skills/ecomode/references/agent-tiers.md +1 -1
  205. package/skills/ultragoal/SKILL.md +23 -0
  206. package/skills/ultrawork/references/agent-tiers.md +3 -2
  207. package/src/scripts/__tests__/codex-native-hook.test.ts +14014 -9097
  208. package/src/scripts/codex-native-hook.ts +4459 -199
package/dist/cli/index.js CHANGED
@@ -5,7 +5,7 @@
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, symlink, writeFile } from "fs/promises";
8
+ import { copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from "fs/promises";
9
9
  import { constants as osConstants, homedir } from "os";
10
10
  import { createHash } from "crypto";
11
11
  import { setup, SETUP_MCP_MODES, SETUP_SCOPES, SETUP_TEAM_MODES, } from "./setup.js";
@@ -43,6 +43,7 @@ import { getBaseStateDir, getStateDir, listModeStateFilesWithScopePreference, }
43
43
  import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
44
44
  import { readPersistedSetupPreferences, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
45
45
  import { discoverProjectRuntimeCodexHomes } from "./project-runtime-codex-homes.js";
46
+ import { materializePackagedOmxPluginCache, packagedOmxPluginVersion, resolvePackagedOmxMarketplace, upsertLocalOmxMarketplaceRegistration, upsertLocalOmxPluginEnablement, } from "./plugin-marketplace.js";
46
47
  import { escapeTomlString, readTopLevelTomlString, upsertTopLevelTomlString } from "../utils/toml.js";
47
48
  export { readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, } from "./codex-home.js";
48
49
  import { SKILL_ACTIVE_STATE_MODE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, syncCanonicalSkillStateForMode, } from "../state/skill-active.js";
@@ -65,7 +66,7 @@ rememberOmxLaunchContext({ argv1: process.argv[1], cwd: process.cwd(), env: proc
65
66
  import { classifySpawnError, resolveTmuxBinaryForPlatform, spawnPlatformCommandSync, } from "../utils/platform-command.js";
66
67
  import { buildHookEvent } from "../hooks/extensibility/events.js";
67
68
  import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
68
- import { collectInheritableTeamWorkerArgs as collectInheritableTeamWorkerArgsShared, resolveTeamWorkerLaunchArgs, resolveTeamLowComplexityDefaultModel, } from "../team/model-contract.js";
69
+ import { collectInheritableTeamWorkerArgs as collectInheritableTeamWorkerArgsShared, parseTeamWorkerLaunchArgs, resolveTeamWorkerLaunchArgs, resolveTeamLowComplexityDefaultModel, TEAM_WORKER_INHERITED_MODEL_ENV, } from "../team/model-contract.js";
69
70
  import { parseWorktreeMode, planWorktreeTarget, ensureWorktree, } from "../team/worktree.js";
70
71
  import { ensureReusableNodeModules } from "../utils/repo-deps.js";
71
72
  import { OMX_NOTIFY_TEMP_CONTRACT_ENV, parseNotifyTempContractFromArgs, serializeNotifyTempContract, } from "../notifications/temp-contract.js";
@@ -667,26 +668,43 @@ async function materializeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, s
667
668
  await copyFile(source, destination);
668
669
  }
669
670
  }
670
- async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceCodexHome) {
671
+ async function mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, sourceCodexHome, mergedHistorySourceRealpaths) {
671
672
  for (const entryName of PROJECT_LAUNCH_DURABLE_HISTORY_ENTRY_NAMES) {
672
673
  const source = join(sourceCodexHome, entryName);
673
674
  if (!existsSync(source))
674
675
  continue;
676
+ const sourceRealpath = realpathSync(source);
677
+ if (mergedHistorySourceRealpaths.has(sourceRealpath))
678
+ continue;
675
679
  const destination = join(runtimeCodexHome, entryName);
676
- const sourceStat = await lstat(source);
680
+ const sourceStat = await stat(source);
677
681
  if (sourceStat.isDirectory()) {
678
682
  await mkdir(destination, { recursive: true });
679
683
  await cp(source, destination, { recursive: true, force: true, dereference: true });
684
+ mergedHistorySourceRealpaths.add(sourceRealpath);
680
685
  continue;
681
686
  }
687
+ if (entryName === "sessions")
688
+ continue;
689
+ if (!sourceStat.isFile())
690
+ continue;
682
691
  if (existsSync(destination)) {
692
+ const destinationStat = await stat(destination);
693
+ if (!destinationStat.isFile()) {
694
+ await rm(destination, { recursive: true, force: true });
695
+ await copyFile(source, destination);
696
+ mergedHistorySourceRealpaths.add(sourceRealpath);
697
+ continue;
698
+ }
683
699
  const existing = await readFile(destination, "utf-8").catch(() => "");
684
700
  const addition = await readFile(source, "utf-8");
685
701
  const separator = existing === "" || existing.endsWith("\n") || addition === "" ? "" : "\n";
686
702
  await writeFile(destination, `${existing}${separator}${addition}`, "utf-8");
703
+ mergedHistorySourceRealpaths.add(sourceRealpath);
687
704
  continue;
688
705
  }
689
706
  await copyFile(source, destination);
707
+ mergedHistorySourceRealpaths.add(sourceRealpath);
690
708
  }
691
709
  }
692
710
  export async function persistProjectLaunchRuntimeAuthState(runtimeCodexHome, projectCodexHome) {
@@ -730,9 +748,15 @@ export async function prepareRuntimeCodexHomeForProjectLaunch(cwd, sessionId, pr
730
748
  }
731
749
  await ensureProjectLaunchRuntimeHistoryLinks(runtimeCodexHome, projectCodexHome);
732
750
  if (options.includeHistoryArtifacts === true && (options.extraHistoryCodexHomes?.length ?? 0) > 0) {
751
+ const mergedHistorySourceRealpaths = new Set();
752
+ for (const entryName of PROJECT_LAUNCH_DURABLE_HISTORY_ENTRY_NAMES) {
753
+ const source = join(projectCodexHome, entryName);
754
+ if (existsSync(source))
755
+ mergedHistorySourceRealpaths.add(realpathSync(source));
756
+ }
733
757
  await materializeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, projectCodexHome);
734
758
  for (const extraCodexHome of options.extraHistoryCodexHomes ?? []) {
735
- await mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, extraCodexHome);
759
+ await mergeProjectLaunchRuntimeHistoryEntries(runtimeCodexHome, extraCodexHome, mergedHistorySourceRealpaths);
736
760
  }
737
761
  }
738
762
  return runtimeCodexHome;
@@ -793,13 +817,46 @@ export function parseResumeCodexHomeSelection(args) {
793
817
  projectOnly,
794
818
  };
795
819
  }
820
+ export async function preflightResumeOmxPluginState(codexHomeDir, pkgRoot = getPackageRoot()) {
821
+ const selectedCodexHomeDir = codexHomeDir && codexHomeDir.trim() !== ""
822
+ ? codexHomeDir
823
+ : join(homedir(), ".codex");
824
+ const packagedMarketplace = await resolvePackagedOmxMarketplace(pkgRoot);
825
+ if (!packagedMarketplace) {
826
+ return { status: "unavailable", prunedStaleDirs: [], configUpdated: false };
827
+ }
828
+ const materialized = await materializePackagedOmxPluginCache(selectedCodexHomeDir, packagedMarketplace);
829
+ const version = materialized.version ?? (await packagedOmxPluginVersion(packagedMarketplace)) ?? undefined;
830
+ const currentCacheDir = materialized.cacheDir ?? (version ? join(selectedCodexHomeDir, "plugins", "cache", "oh-my-codex-local", "oh-my-codex", version) : undefined);
831
+ const prunedStaleDirs = [];
832
+ const configPath = join(selectedCodexHomeDir, "config.toml");
833
+ const existingConfig = existsSync(configPath) ? await readFile(configPath, "utf-8") : "";
834
+ const nextConfig = upsertLocalOmxMarketplaceRegistration(upsertLocalOmxPluginEnablement(existingConfig), pkgRoot);
835
+ const configUpdated = nextConfig !== existingConfig;
836
+ if (configUpdated) {
837
+ await mkdir(dirname(configPath), { recursive: true });
838
+ await writeFile(configPath, nextConfig, "utf-8");
839
+ }
840
+ return {
841
+ status: "prepared",
842
+ version,
843
+ cacheDir: currentCacheDir,
844
+ prunedStaleDirs,
845
+ configUpdated,
846
+ };
847
+ }
848
+ function isResumeCodexLaunch(args) {
849
+ return args.includes("resume");
850
+ }
796
851
  async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = process.env) {
797
852
  const selection = parseResumeCodexHomeSelection(args);
798
853
  if (selection.explicitCodexHome) {
854
+ const codexHomeOverride = resolve(selection.explicitCodexHome);
855
+ await preflightResumeOmxPluginState(codexHomeOverride);
799
856
  return {
800
857
  args: selection.args,
801
858
  prepared: {
802
- codexHomeOverride: resolve(selection.explicitCodexHome),
859
+ codexHomeOverride,
803
860
  },
804
861
  };
805
862
  }
@@ -809,6 +866,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
809
866
  const emptyRuntimeCodexHome = runtimeCodexHomePath(cwd, sessionId);
810
867
  await rm(emptyRuntimeCodexHome, { recursive: true, force: true });
811
868
  await mkdir(join(emptyRuntimeCodexHome, "sessions"), { recursive: true });
869
+ await preflightResumeOmxPluginState(emptyRuntimeCodexHome);
812
870
  return {
813
871
  args: selection.args,
814
872
  prepared: {
@@ -821,6 +879,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
821
879
  includeHistoryArtifacts: true,
822
880
  extraHistoryCodexHomes: projectHomes.slice(1).map((home) => home.path),
823
881
  });
882
+ await preflightResumeOmxPluginState(runtimeCodexHome);
824
883
  return {
825
884
  args: selection.args,
826
885
  prepared: {
@@ -832,6 +891,7 @@ async function prepareResumeCodexHomeForLaunch(cwd, sessionId, args, env = proce
832
891
  includeHistoryArtifacts: true,
833
892
  extraHistoryCodexHomes: projectHomes.map((home) => home.path),
834
893
  });
894
+ await preflightResumeOmxPluginState(prepared.codexHomeOverride);
835
895
  return { args: selection.args, prepared };
836
896
  }
837
897
  export async function persistProjectLaunchRuntimeProjectTrustState(runtimeCodexHome, projectCodexHome) {
@@ -1362,20 +1422,88 @@ export function resolveDisposableWorktreeOmxRootForLaunch(ensuredWorktree, env =
1362
1422
  return undefined;
1363
1423
  return ensuredWorktree.repoRoot;
1364
1424
  }
1425
+ function buildMadmaxWorktreeRuntimeEnvOverlay(runtimeContext) {
1426
+ if (!runtimeContext)
1427
+ return {};
1428
+ return {
1429
+ OMX_ROOT: runtimeContext.omxRoot,
1430
+ ...(runtimeContext.omxStateRoot ? { OMX_STATE_ROOT: runtimeContext.omxStateRoot } : {}),
1431
+ ...(runtimeContext.boxedActive ? { OMXBOX_ACTIVE: "1" } : {}),
1432
+ OMX_SOURCE_CWD: runtimeContext.sourceCwd,
1433
+ ...(runtimeContext.madmaxDetachedContext
1434
+ ? { [OMX_MADMAX_DETACHED_CONTEXT_ENV]: runtimeContext.madmaxDetachedContext }
1435
+ : {}),
1436
+ };
1437
+ }
1438
+ export function captureMadmaxWorktreeRuntimeContext(options) {
1439
+ const env = options.env ?? process.env;
1440
+ if (!options.worktreeEnabled)
1441
+ return undefined;
1442
+ if (!launchArgsRequestMadmaxIsolation(options.originalLaunchArgs))
1443
+ return undefined;
1444
+ if (env.OMXBOX_ACTIVE !== "1")
1445
+ return undefined;
1446
+ const inheritedRoot = resolveInheritedMadmaxRoot(env);
1447
+ if (!inheritedRoot)
1448
+ return undefined;
1449
+ const sourceCwd = env.OMX_SOURCE_CWD?.trim() || options.sourceCwd;
1450
+ const worktreeCwd = options.worktreeCwd?.trim();
1451
+ const omxStateRoot = env.OMX_STATE_ROOT?.trim();
1452
+ const madmaxDetachedContext = env[OMX_MADMAX_DETACHED_CONTEXT_ENV]?.trim();
1453
+ return {
1454
+ omxRoot: resolveLaunchPath(options.sourceCwd, inheritedRoot),
1455
+ ...(omxStateRoot ? { omxStateRoot: resolveLaunchPath(options.sourceCwd, omxStateRoot) } : {}),
1456
+ sourceCwd,
1457
+ ...(worktreeCwd && worktreeCwd !== sourceCwd ? { worktreeCwd } : {}),
1458
+ ...(madmaxDetachedContext ? { madmaxDetachedContext } : {}),
1459
+ boxedActive: true,
1460
+ };
1461
+ }
1365
1462
  function applyDisposableWorktreeOmxRootForLaunch(ensuredWorktree, env = process.env) {
1366
1463
  const omxRootOverride = resolveDisposableWorktreeOmxRootForLaunch(ensuredWorktree, env);
1367
1464
  if (!omxRootOverride)
1368
1465
  return;
1369
1466
  env.OMX_ROOT = omxRootOverride;
1370
1467
  }
1371
- export function shouldAutoIsolateMadmaxLaunch(command, launchArgs, env = process.env) {
1468
+ function launchArgRequestsDisposableWorktree(arg) {
1469
+ return arg === "--worktree" ||
1470
+ arg === "-w" ||
1471
+ arg.startsWith("--worktree=") ||
1472
+ // Covers both `-w=<name>` and `-w<name>`; an explicit `-w=` check would be a
1473
+ // strict subset of this clause, so it is omitted as redundant.
1474
+ (arg.startsWith("-w") && arg.length > 2);
1475
+ }
1476
+ function launchArgsRequestMadmaxIsolation(launchArgs) {
1477
+ return launchArgs.some((arg) => arg === MADMAX_FLAG || arg === MADMAX_SPARK_FLAG);
1478
+ }
1479
+ function launchArgsRequestDisposableWorktree(launchArgs) {
1480
+ return launchArgs.some((arg) => launchArgRequestsDisposableWorktree(arg));
1481
+ }
1482
+ function clearInheritedMadmaxRootForDisposableWorktreeLaunch(launchArgs, env = process.env) {
1483
+ if (!launchArgsRequestDisposableWorktree(launchArgs))
1484
+ return;
1485
+ if (env.OMXBOX_ACTIVE !== "1")
1486
+ return;
1487
+ delete env.OMX_ROOT;
1488
+ delete env.OMX_STATE_ROOT;
1489
+ delete env.OMXBOX_ACTIVE;
1490
+ delete env.OMX_SOURCE_CWD;
1491
+ delete env[OMX_MADMAX_DETACHED_CONTEXT_ENV];
1492
+ }
1493
+ export function shouldAutoIsolateMadmaxLaunch(command, launchArgs, env = process.env, cwd = process.cwd()) {
1372
1494
  if (command !== "launch" && command !== "exec")
1373
1495
  return false;
1374
- if (env.OMX_NO_BOX === "1" || env.OMXBOX_ACTIVE === "1")
1496
+ if (env.OMX_NO_BOX === "1")
1375
1497
  return false;
1376
- if (env.OMX_ROOT || env.OMX_STATE_ROOT)
1498
+ if (!launchArgsRequestMadmaxIsolation(launchArgs))
1377
1499
  return false;
1378
- return launchArgs.some((arg) => arg === MADMAX_FLAG || arg === MADMAX_SPARK_FLAG);
1500
+ const inheritedContext = env[OMX_MADMAX_DETACHED_CONTEXT_ENV]?.trim();
1501
+ if (env.OMXBOX_ACTIVE === "1" && inheritedContext && !resolveInheritedMadmaxRoot(env)) {
1502
+ return false;
1503
+ }
1504
+ if (madmaxInheritedContextMatchesLaunch(cwd, launchArgs, env))
1505
+ return false;
1506
+ return true;
1379
1507
  }
1380
1508
  function sanitizeRunIdSegment(value) {
1381
1509
  return value.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
@@ -1474,6 +1602,7 @@ function readMadmaxDetachedActiveRecord(recordPath) {
1474
1602
  tmux_session_name: parsed.tmux_session_name,
1475
1603
  ...(typeof parsed.session_id === "string" ? { session_id: parsed.session_id } : {}),
1476
1604
  ...(typeof parsed.tmux_pane_id === "string" ? { tmux_pane_id: parsed.tmux_pane_id } : {}),
1605
+ ...(typeof parsed.worktree_cwd === "string" ? { worktree_cwd: parsed.worktree_cwd } : {}),
1477
1606
  };
1478
1607
  }
1479
1608
  catch {
@@ -1607,6 +1736,43 @@ export function withMadmaxDetachedContextLock(runsRoot, contextKey, run, options
1607
1736
  }
1608
1737
  throw new MadmaxDetachedGuardError(`timed out waiting for madmax detached launch context lock: ${lockPath} (${lastDiagnostic})`);
1609
1738
  }
1739
+ function readMadmaxRunMetadata(runRoot) {
1740
+ try {
1741
+ const parsed = JSON.parse(readFileSync(join(runRoot, ".omxbox-run.json"), "utf-8"));
1742
+ return {
1743
+ ...(typeof parsed.cwd === "string" ? { cwd: parsed.cwd } : {}),
1744
+ ...(typeof parsed.detached_launch_context === "string"
1745
+ ? { detached_launch_context: parsed.detached_launch_context }
1746
+ : {}),
1747
+ };
1748
+ }
1749
+ catch {
1750
+ return null;
1751
+ }
1752
+ }
1753
+ function resolveInheritedMadmaxRoot(env) {
1754
+ const root = env.OMX_ROOT?.trim() || env.OMX_STATE_ROOT?.trim();
1755
+ return root || undefined;
1756
+ }
1757
+ function madmaxInheritedContextMatchesLaunch(cwd, launchArgs, env) {
1758
+ if (env.OMXBOX_ACTIVE !== "1")
1759
+ return false;
1760
+ const context = env[OMX_MADMAX_DETACHED_CONTEXT_ENV]?.trim();
1761
+ if (!context)
1762
+ return false;
1763
+ const inheritedRoot = resolveInheritedMadmaxRoot(env);
1764
+ if (!inheritedRoot)
1765
+ return false;
1766
+ const metadata = readMadmaxRunMetadata(inheritedRoot);
1767
+ if (!metadata)
1768
+ return false;
1769
+ if (metadata.cwd && metadata.cwd !== inheritedRoot)
1770
+ return false;
1771
+ if (metadata.detached_launch_context !== context)
1772
+ return false;
1773
+ const expectedContext = buildMadmaxDetachedLaunchContextKey(cwd, [...launchArgs], inheritedRoot);
1774
+ return expectedContext === context;
1775
+ }
1610
1776
  function isMadmaxDetachedGuardEnabled(env) {
1611
1777
  return env.OMXBOX_ACTIVE === "1" && typeof env[OMX_MADMAX_DETACHED_CONTEXT_ENV] === "string";
1612
1778
  }
@@ -1651,7 +1817,7 @@ export function createMadmaxIsolatedRoot(sourceCwd, argv, env = process.env) {
1651
1817
  return runDir;
1652
1818
  }
1653
1819
  function activateMadmaxIsolationIfNeeded(command, launchArgs, cwd, env = process.env) {
1654
- if (!shouldAutoIsolateMadmaxLaunch(command, launchArgs, env))
1820
+ if (!shouldAutoIsolateMadmaxLaunch(command, launchArgs, env, cwd))
1655
1821
  return;
1656
1822
  const runDir = createMadmaxIsolatedRoot(cwd, launchArgs, env);
1657
1823
  env.OMX_ROOT = runDir;
@@ -2066,6 +2232,7 @@ export async function launchWithAuthHotswap(args) {
2066
2232
  }
2067
2233
  }
2068
2234
  }
2235
+ clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2069
2236
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2070
2237
  try {
2071
2238
  await maybeCheckAndPromptUpdate(cwd);
@@ -2165,6 +2332,14 @@ export async function launchWithHud(args) {
2165
2332
  }
2166
2333
  }
2167
2334
  }
2335
+ const madmaxWorktreeRuntimeContext = captureMadmaxWorktreeRuntimeContext({
2336
+ originalLaunchArgs: args,
2337
+ worktreeEnabled: Boolean(parsedWorktree.mode.enabled && ensuredLaunchWorktree?.enabled),
2338
+ sourceCwd: launchCwd,
2339
+ worktreeCwd: ensuredLaunchWorktree?.enabled ? ensuredLaunchWorktree.worktreePath : undefined,
2340
+ env: process.env,
2341
+ });
2342
+ clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2168
2343
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2169
2344
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2170
2345
  try {
@@ -2195,14 +2370,14 @@ export async function launchWithHud(args) {
2195
2370
  catch {
2196
2371
  // Non-fatal: repair failure must not block launch
2197
2372
  }
2198
- const resumePrepared = normalizedArgs[0] === "resume"
2373
+ const resumePrepared = isResumeCodexLaunch(normalizedArgs)
2199
2374
  ? await prepareResumeCodexHomeForLaunch(launchCwd, sessionId, normalizedArgs, process.env)
2200
2375
  : null;
2201
2376
  if (resumePrepared) {
2202
2377
  normalizedArgs = resumePrepared.args;
2203
2378
  }
2204
2379
  const preparedCodexHome = resumePrepared?.prepared ?? await prepareCodexHomeForLaunch(launchCwd, sessionId, process.env, {
2205
- includeHistoryArtifacts: normalizedArgs[0] === "resume",
2380
+ includeHistoryArtifacts: isResumeCodexLaunch(normalizedArgs),
2206
2381
  });
2207
2382
  const codexHomeOverride = preparedCodexHome.codexHomeOverride;
2208
2383
  const sqliteHomeOverride = preparedCodexHome.sqliteHomeOverride;
@@ -2221,7 +2396,7 @@ export async function launchWithHud(args) {
2221
2396
  const notifyTempContractRaw = notifyTempResult.contract.active
2222
2397
  ? serializeNotifyTempContract(notifyTempResult.contract)
2223
2398
  : null;
2224
- const launchResult = runCodex(cwd, normalizedArgs, sessionId, workerSparkModel, codexHomeOverride, sqliteHomeOverride, notifyTempContractRaw, effectiveExplicitLaunchPolicy, projectLocalCodexHomeForCleanup, preparedCodexHome.runtimeCodexHomeForCleanup);
2399
+ const launchResult = runCodex(cwd, normalizedArgs, sessionId, workerSparkModel, codexHomeOverride, sqliteHomeOverride, notifyTempContractRaw, effectiveExplicitLaunchPolicy, projectLocalCodexHomeForCleanup, preparedCodexHome.runtimeCodexHomeForCleanup, madmaxWorktreeRuntimeContext);
2225
2400
  postLaunchHandledExternally = launchResult.postLaunchHandledExternally;
2226
2401
  }
2227
2402
  finally {
@@ -2264,6 +2439,7 @@ export async function execWithOverlay(args) {
2264
2439
  }
2265
2440
  }
2266
2441
  }
2442
+ clearInheritedMadmaxRootForDisposableWorktreeLaunch(parsedWorktree.remainingArgs);
2267
2443
  applyDisposableWorktreeOmxRootForLaunch(ensuredLaunchWorktree);
2268
2444
  const sessionId = `omx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2269
2445
  try {
@@ -2982,7 +3158,7 @@ export function withTmuxExtendedKeys(cwd, run, execFileSyncImpl = (file, tmuxArg
2982
3158
  releaseTmuxExtendedKeysLease(cwd, leaseHandle, execFileSyncImpl);
2983
3159
  }
2984
3160
  }
2985
- export function buildDetachedSessionBootstrapSteps(sessionName, cwd, codexCmd, hudCmd, workerLaunchArgs, codexHomeOverride, notifyTempContractRaw, nativeWindows = false, sessionId, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, omxRootOverride, env = process.env, sqliteHomeOverride, parentEnvFilePath) {
3161
+ export function buildDetachedSessionBootstrapSteps(sessionName, cwd, codexCmd, hudCmd, workerLaunchArgs, codexHomeOverride, notifyTempContractRaw, nativeWindows = false, sessionId, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, omxRootOverride, env = process.env, sqliteHomeOverride, parentEnvFilePath, inheritedWorkerModel) {
2986
3162
  const detachedLeaderCmd = nativeWindows
2987
3163
  ? "powershell.exe"
2988
3164
  : buildDetachedSessionLeaderCommand(cwd, sessionName, codexCmd, sessionId, codexHomeOverride, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, parentEnvFilePath);
@@ -3013,17 +3189,19 @@ export function buildDetachedSessionBootstrapSteps(sessionName, cwd, codexCmd, h
3013
3189
  sessionName,
3014
3190
  "-c",
3015
3191
  cwd,
3016
- ...(workerLaunchArgs
3017
- ? ["-e", `${TEAM_WORKER_LAUNCH_ARGS_ENV}=${workerLaunchArgs}`]
3018
- : []),
3192
+ ...(workerLaunchArgs ? ["-e", `${TEAM_WORKER_LAUNCH_ARGS_ENV}=${workerLaunchArgs}`] : []),
3019
3193
  ...Object.entries(hudRuntimeEnv).map(([key, value]) => ["-e", `${key}=${value}`]).flat(),
3020
3194
  ...(codexHomeOverride ? ["-e", `CODEX_HOME=${codexHomeOverride}`] : []),
3021
3195
  ...(sqliteHomeOverride ? ["-e", `${CODEX_SQLITE_HOME_ENV}=${sqliteHomeOverride}`] : []),
3022
3196
  ...(env.OMXBOX_ACTIVE ? ["-e", `OMXBOX_ACTIVE=${env.OMXBOX_ACTIVE}`] : []),
3023
3197
  ...(env.OMX_SOURCE_CWD ? ["-e", `OMX_SOURCE_CWD=${env.OMX_SOURCE_CWD}`] : []),
3198
+ ...(env[OMX_MADMAX_DETACHED_CONTEXT_ENV]
3199
+ ? ["-e", `${OMX_MADMAX_DETACHED_CONTEXT_ENV}=${env[OMX_MADMAX_DETACHED_CONTEXT_ENV]}`]
3200
+ : []),
3024
3201
  ...(notifyTempContractRaw
3025
3202
  ? ["-e", `${OMX_NOTIFY_TEMP_CONTRACT_ENV}=${notifyTempContractRaw}`]
3026
3203
  : []),
3204
+ ...(inheritedWorkerModel ? ["-e", `${TEAM_WORKER_INHERITED_MODEL_ENV}=${inheritedWorkerModel}`] : []),
3027
3205
  detachedLeaderCmd,
3028
3206
  ];
3029
3207
  const splitCaptureArgs = [
@@ -3606,42 +3784,59 @@ ${launchAppendix}${dirtyWorktreeGuidance}`
3606
3784
  * runCodex: Launch Codex CLI (blocks until exit).
3607
3785
  * All 3 paths (new tmux, existing tmux, no tmux) block via execSync/execFileSync.
3608
3786
  */
3609
- function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, sqliteHomeOverride, notifyTempContractRaw, explicitLaunchPolicy, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup) {
3787
+ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, sqliteHomeOverride, notifyTempContractRaw, explicitLaunchPolicy, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, runtimeContext) {
3610
3788
  const launchArgs = injectModelInstructionsBypassArgs(cwd, args, process.env, sessionModelInstructionsPath(cwd, sessionId));
3611
3789
  const nativeWindows = isNativeWindows();
3612
3790
  const omxBin = resolveOmxCliEntryPath({ argv1: process.argv[1], cwd, env: process.env });
3613
3791
  if (!omxBin) {
3614
3792
  throw new Error("Unable to resolve OMX launcher path for tmux HUD bootstrap");
3615
3793
  }
3616
- const omxRootOverride = resolveOmxRootForLaunch(cwd, process.env);
3794
+ const runtimeEnvOverlay = buildMadmaxWorktreeRuntimeEnvOverlay(runtimeContext);
3795
+ const omxRootOverride = runtimeContext?.omxRoot ?? resolveOmxRootForLaunch(cwd, process.env);
3617
3796
  const currentPaneId = process.env.TMUX_PANE;
3618
- const hudRuntimeRoot = resolveHudRuntimeRootForLaunch(cwd, process.env);
3619
- const hudEnvArgs = Object.entries(buildHudRuntimeEnv({
3620
- sessionId,
3621
- leaderPaneId: currentPaneId,
3622
- ...hudRuntimeRoot,
3623
- }).env).map(([key, value]) => `${key}=${value}`);
3797
+ const hudRuntimeRoot = runtimeContext
3798
+ ? { omxRoot: runtimeContext.omxRoot, rootSource: 'omx-root-env' }
3799
+ : resolveHudRuntimeRootForLaunch(cwd, process.env);
3800
+ const hudRuntimeEnv = {
3801
+ ...buildHudRuntimeEnv({
3802
+ sessionId,
3803
+ leaderPaneId: currentPaneId,
3804
+ ...hudRuntimeRoot,
3805
+ }).env,
3806
+ ...runtimeEnvOverlay,
3807
+ };
3808
+ const hudEnvArgs = Object.entries(hudRuntimeEnv).map(([key, value]) => `${key}=${value}`);
3624
3809
  const hudCmd = nativeWindows
3625
3810
  ? buildWindowsPromptCommand("node", [omxBin, "hud", "--watch"])
3626
3811
  : buildTmuxPaneCommand("env", [...hudEnvArgs, "node", omxBin, "hud", "--watch"]);
3627
3812
  const inheritLeaderFlags = process.env[TEAM_INHERIT_LEADER_FLAGS_ENV] !== "0";
3813
+ const inheritedWorkerLaunchArgs = inheritLeaderFlags
3814
+ ? collectInheritableTeamWorkerArgsShared(launchArgs)
3815
+ : [];
3816
+ const inheritedWorkerModel = parseTeamWorkerLaunchArgs(inheritedWorkerLaunchArgs).modelOverride ?? undefined;
3628
3817
  const workerLaunchArgs = resolveTeamWorkerLaunchArgsEnv(process.env[TEAM_WORKER_LAUNCH_ARGS_ENV], launchArgs, inheritLeaderFlags, workerDefaultModel);
3629
3818
  const codexBaseEnv = prependOmxRuntimeCommandShimToEnv(cwd, {
3630
3819
  ...stripHermesMcpBridgeEnv(process.env),
3631
3820
  ...(codexHomeOverride ? { CODEX_HOME: codexHomeOverride } : {}),
3632
3821
  ...(sqliteHomeOverride ? { [CODEX_SQLITE_HOME_ENV]: sqliteHomeOverride } : {}),
3633
3822
  ...(omxRootOverride ? { OMX_ROOT: omxRootOverride } : {}),
3823
+ ...runtimeEnvOverlay,
3634
3824
  }, omxBin);
3635
3825
  const codexEnvWithSession = {
3636
3826
  ...codexBaseEnv,
3637
3827
  ...buildHudRuntimeEnv({ sessionId }).env,
3638
3828
  };
3639
3829
  const codexEnv = workerLaunchArgs
3640
- ? { ...codexEnvWithSession, [TEAM_WORKER_LAUNCH_ARGS_ENV]: workerLaunchArgs }
3830
+ ? {
3831
+ ...codexEnvWithSession,
3832
+ [TEAM_WORKER_LAUNCH_ARGS_ENV]: workerLaunchArgs,
3833
+ ...(inheritedWorkerModel ? { [TEAM_WORKER_INHERITED_MODEL_ENV]: inheritedWorkerModel } : {}),
3834
+ }
3641
3835
  : codexEnvWithSession;
3642
3836
  const codexEnvWithNotify = notifyTempContractRaw
3643
3837
  ? { ...codexEnv, [OMX_NOTIFY_TEMP_CONTRACT_ENV]: notifyTempContractRaw }
3644
3838
  : codexEnv;
3839
+ const runtimeHookEnv = { ...process.env, ...runtimeEnvOverlay };
3645
3840
  const { launchPolicy } = resolveTmuxAwareLaunchPolicy(explicitLaunchPolicy, nativeWindows);
3646
3841
  if (isCodexVersionRequest(launchArgs)) {
3647
3842
  runCodexBlocking(cwd, launchArgs, codexEnvWithNotify);
@@ -3679,6 +3874,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3679
3874
  cwd,
3680
3875
  sessionId,
3681
3876
  omxRootOverride,
3877
+ baseEnv: runtimeHookEnv,
3682
3878
  });
3683
3879
  }
3684
3880
  catch (err) {
@@ -3705,6 +3901,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3705
3901
  cwd,
3706
3902
  sessionId,
3707
3903
  omxRootOverride,
3904
+ baseEnv: runtimeHookEnv,
3708
3905
  });
3709
3906
  }
3710
3907
  catch (err) {
@@ -3771,7 +3968,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3771
3968
  : null;
3772
3969
  const sessionName = buildDetachedTmuxSessionName(cwd, sessionId);
3773
3970
  const launchDetachedSession = () => {
3774
- const contextKey = process.env[OMX_MADMAX_DETACHED_CONTEXT_ENV]?.trim();
3971
+ const contextKey = runtimeContext?.madmaxDetachedContext ?? process.env[OMX_MADMAX_DETACHED_CONTEXT_ENV]?.trim();
3775
3972
  const runsRoot = resolveMadmaxRunsRoot(process.env);
3776
3973
  const activeRecordPath = contextKey
3777
3974
  ? madmaxDetachedActiveRecordPath(runsRoot, contextKey)
@@ -3836,7 +4033,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3836
4033
  if (!nativeWindows) {
3837
4034
  detachedParentEnvFilePath = writeDetachedSessionParentEnvFile(cwd, sessionId, codexEnvWithNotify);
3838
4035
  }
3839
- const bootstrapSteps = buildDetachedSessionBootstrapSteps(sessionName, cwd, codexCmd, hudCmd, workerLaunchArgs, codexHomeOverride, notifyTempContractRaw, nativeWindows, sessionId, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, omxRootOverride, process.env, sqliteHomeOverride, detachedParentEnvFilePath);
4036
+ const bootstrapSteps = buildDetachedSessionBootstrapSteps(sessionName, cwd, codexCmd, hudCmd, workerLaunchArgs, codexHomeOverride, notifyTempContractRaw, nativeWindows, sessionId, projectLocalCodexHomeForCleanup, runtimeCodexHomeForCleanup, omxRootOverride, runtimeHookEnv, sqliteHomeOverride, detachedParentEnvFilePath, inheritedWorkerModel);
3840
4037
  for (const step of bootstrapSteps) {
3841
4038
  const output = execTmuxFileSync(step.args, {
3842
4039
  stdio: "pipe",
@@ -3853,9 +4050,10 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3853
4050
  version: 1,
3854
4051
  context_key: contextKey,
3855
4052
  created_at: new Date().toISOString(),
3856
- source_cwd: process.env.OMX_SOURCE_CWD || cwd,
4053
+ source_cwd: runtimeContext?.sourceCwd ?? process.env.OMX_SOURCE_CWD ?? cwd,
4054
+ ...(runtimeContext?.worktreeCwd ? { worktree_cwd: runtimeContext.worktreeCwd } : {}),
3857
4055
  argv: args,
3858
- run_dir: process.env.OMX_ROOT || cwd,
4056
+ run_dir: runtimeContext?.omxRoot ?? process.env.OMX_ROOT ?? cwd,
3859
4057
  tmux_session_name: sessionName,
3860
4058
  session_id: sessionId,
3861
4059
  tmux_pane_id: leaderPaneId,
@@ -3924,6 +4122,7 @@ function runCodex(cwd, args, sessionId, workerDefaultModel, codexHomeOverride, s
3924
4122
  sessionId,
3925
4123
  omxBin,
3926
4124
  omxRootOverride,
4125
+ baseEnv: runtimeHookEnv,
3927
4126
  });
3928
4127
  }
3929
4128
  }
@@ -4663,6 +4862,7 @@ async function listHookVisibleRunDirStateRefs(cwd) {
4663
4862
  return;
4664
4863
  const record = raw;
4665
4864
  const sourceCwd = typeof record.source_cwd === "string" ? record.source_cwd.trim() : "";
4865
+ const worktreeCwd = typeof record.worktree_cwd === "string" ? record.worktree_cwd.trim() : "";
4666
4866
  const runDir = typeof record.run_dir === "string"
4667
4867
  ? record.run_dir.trim()
4668
4868
  : typeof record.cwd === "string"
@@ -4671,7 +4871,8 @@ async function listHookVisibleRunDirStateRefs(cwd) {
4671
4871
  if (!sourceCwd || !runDir)
4672
4872
  return;
4673
4873
  try {
4674
- if (canonicalizePathForRunDirMatch(sourceCwd) !== canonicalCwd)
4874
+ if (canonicalizePathForRunDirMatch(sourceCwd) !== canonicalCwd &&
4875
+ (!worktreeCwd || canonicalizePathForRunDirMatch(worktreeCwd) !== canonicalCwd))
4675
4876
  return;
4676
4877
  const resolvedRunDir = resolve(runDir);
4677
4878
  if (resolvedRunDir !== canonicalRunsRoot