oh-my-codex 0.18.9 → 0.18.10
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.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +4 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts +2 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts.map +1 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.js +215 -0
- package/dist/autopilot/__tests__/deep-interview-gate.test.js.map +1 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js +148 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/deep-interview-gate.d.ts.map +1 -1
- package/dist/autopilot/deep-interview-gate.js +140 -0
- package/dist/autopilot/deep-interview-gate.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +36 -3
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-feature-probe.test.d.ts +2 -0
- package/dist/cli/__tests__/codex-feature-probe.test.d.ts.map +1 -0
- package/dist/cli/__tests__/codex-feature-probe.test.js +46 -0
- package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +251 -5
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +19 -5
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +19 -6
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +6 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-packaging.test.js +45 -2
- package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -1
- package/dist/cli/__tests__/team-decompose.test.js +10 -5
- package/dist/cli/__tests__/team-decompose.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +45 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +75 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +25 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +5 -2
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +25 -9
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/index.d.ts +28 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +149 -88
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +9 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +4 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +43 -4
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +29 -0
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +1 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +15 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +16 -0
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +14 -5
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +2 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +112 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.d.ts +2 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.d.ts.map +1 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.js +16 -0
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -0
- package/dist/hooks/extensibility/plugin-runner.js +2 -4
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +23 -2
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +266 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +118 -7
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/index.d.ts +6 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +12 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts +6 -2
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +58 -28
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/tmux.d.ts +14 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +129 -15
- package/dist/hud/tmux.js.map +1 -1
- package/dist/ralplan/consensus-gate.js +9 -1
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +168 -15
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +115 -1
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +74 -11
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +54 -21
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/run-test-files.js +218 -160
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +463 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/team/__tests__/delivery-log.test.js +18 -0
- package/dist/team/__tests__/delivery-log.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +48 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +107 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js +14 -2
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +1 -0
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +54 -1
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/delivery-log.d.ts +1 -1
- package/dist/team/delivery-log.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +4 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
- package/dist/team/repo-aware-decomposition.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +78 -9
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts +1 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +16 -5
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/ultragoal-context.d.ts +12 -0
- package/dist/team/ultragoal-context.d.ts.map +1 -1
- package/dist/team/ultragoal-context.js +32 -8
- package/dist/team/ultragoal-context.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +23 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +4 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/toml.d.ts +4 -0
- package/dist/utils/toml.d.ts.map +1 -0
- package/dist/utils/toml.js +75 -0
- package/dist/utils/toml.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +34 -0
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +32 -17
- package/skills/autopilot/SKILL.md +3 -0
- package/skills/deep-interview/SKILL.md +34 -0
- package/skills/ultrawork/SKILL.md +32 -17
- package/src/scripts/__tests__/codex-native-hook.test.ts +216 -26
- package/src/scripts/__tests__/run-test-files.test.ts +138 -2
- package/src/scripts/codex-native-hook.ts +80 -10
- package/src/scripts/notify-hook/team-worker-stop.ts +58 -18
- package/src/scripts/run-test-files.ts +229 -150
- package/templates/AGENTS.md +40 -199
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { afterEach, describe, it, mock } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, utimesSync } from "node:fs";
|
|
4
|
-
import { chmod, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { chmod, lstat, mkdir, mkdtemp, readFile, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import { delimiter, dirname, join } from "node:path";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { once } from "node:events";
|
|
9
9
|
import TOML from "@iarna/toml";
|
|
10
|
-
import { HELP, normalizeCodexLaunchArgs, buildTmuxShellCommand, buildTmuxPaneCommand, shouldSourceTmuxPaneShellRc, buildWindowsPromptCommand, buildTmuxSessionName, resolveCliInvocation, resolveUpdateChannelArg, commandOwnsLocalHelp, resolveCodexLaunchPolicy, resolveEffectiveLeaderLaunchPolicyOverride, resolveEnvLaunchPolicyOverride, resolveLeaderLaunchPolicyOverride, classifyCodexExecFailure, resolveSignalExitCode, parseTmuxPaneSnapshot, findHudWatchPaneIds, buildHudPaneCleanupTargets, readTopLevelTomlString, upsertTopLevelTomlString, collectInheritableTeamWorkerArgs, resolveTeamWorkerLaunchArgsEnv, injectModelInstructionsBypassArgs, resolveWorkerSparkModel, resolveSetupInstallModeArg, resolveSetupMcpModeArg, resolveSetupScopeArg, resolveSetupTeamModeArg, resolveLaunchConfigRepairOptions, readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, shouldAutoIsolateMadmaxLaunch, createMadmaxIsolatedRoot, buildMadmaxDetachedLaunchContextKey, withMadmaxDetachedContextLock, resolveOmxRootForLaunch, resolveDisposableWorktreeOmxRootForLaunch, prepareCodexHomeForLaunch, persistProjectLaunchRuntimeAuthState, persistProjectLaunchRuntimeProjectTrustState, runtimeCodexHomePath, buildDetachedSessionBootstrapSteps, buildDetachedTmuxSessionName, buildDetachedSessionFinalizeSteps, shouldAttachDetachedTmuxSession, buildDetachedSessionRollbackSteps, detectDetachedSessionWindowIndex, resolveNotifyTempContract, buildNotifyTempStartupMessages, buildNotifyFallbackWatcherEnv, shouldEnableNotifyFallbackWatcher, reapStaleNotifyFallbackWatcher, cleanupLaunchOrphanedMcpProcesses, reapPostLaunchOrphanedMcpProcesses, cleanupPostLaunchModeStateFiles, resolveBackgroundHelperLaunchMode, shouldDetachBackgroundHelper, resolveNotifyFallbackWatcherScript, resolveHookDerivedWatcherScript, resolveNotifyHookScript, buildDetachedWindowsBootstrapScript, acquireTmuxExtendedKeysLease, resolveNativeSessionName, releaseTmuxExtendedKeysLease, withTmuxExtendedKeys, serializeDetachedSessionParentEnv, CODEX_SQLITE_HOME_ENV, DETACHED_TMUX_HISTORY_LIMIT, } from "../index.js";
|
|
10
|
+
import { HELP, normalizeCodexLaunchArgs, buildTmuxShellCommand, buildTmuxPaneCommand, shouldSourceTmuxPaneShellRc, buildWindowsPromptCommand, buildTmuxSessionName, resolveCliInvocation, resolveUpdateChannelArg, commandOwnsLocalHelp, resolveCodexLaunchPolicy, resolveEffectiveLeaderLaunchPolicyOverride, resolveEnvLaunchPolicyOverride, resolveLeaderLaunchPolicyOverride, classifyCodexExecFailure, resolveSignalExitCode, parseTmuxPaneSnapshot, findHudWatchPaneIds, buildHudPaneCleanupTargets, readTopLevelTomlString, upsertTopLevelTomlString, collectInheritableTeamWorkerArgs, resolveTeamWorkerLaunchArgsEnv, injectModelInstructionsBypassArgs, resolveWorkerSparkModel, resolveSetupInstallModeArg, resolveSetupMcpModeArg, resolveSetupScopeArg, resolveSetupTeamModeArg, resolveLaunchConfigRepairOptions, readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, shouldAutoIsolateMadmaxLaunch, createMadmaxIsolatedRoot, buildMadmaxDetachedLaunchContextKey, withMadmaxDetachedContextLock, resolveOmxRootForLaunch, resolveDisposableWorktreeOmxRootForLaunch, prepareCodexHomeForLaunch, persistProjectLaunchRuntimeAuthState, persistProjectLaunchRuntimeProjectTrustState, runtimeCodexHomePath, buildDetachedSessionBootstrapSteps, buildDetachedTmuxSessionName, buildDetachedSessionFinalizeSteps, shouldAttachDetachedTmuxSession, buildDetachedSessionRollbackSteps, detectDetachedSessionWindowIndex, resolveNotifyTempContract, buildNotifyTempStartupMessages, buildNotifyFallbackWatcherEnv, shouldEnableNotifyFallbackWatcher, reapStaleNotifyFallbackWatcher, cleanupLaunchOrphanedMcpProcesses, reapPostLaunchOrphanedMcpProcesses, cleanupPostLaunchModeStateFiles, resolveBackgroundHelperLaunchMode, shouldDetachBackgroundHelper, resolveNotifyFallbackWatcherScript, resolveHookDerivedWatcherScript, resolveNotifyHookScript, buildDetachedWindowsBootstrapScript, acquireTmuxExtendedKeysLease, resolveNativeSessionName, releaseTmuxExtendedKeysLease, withTmuxExtendedKeys, serializeDetachedSessionParentEnv, buildInsideTmuxHudHookEnv, registerInsideTmuxHudResizeHook, buildDetachedHudHookEnv, registerDetachedHudLayoutReconcileHook, ensureOmxRuntimeCommandShim, omxRuntimeCommandShimPath, prependOmxRuntimeCommandShimToEnv, CODEX_SQLITE_HOME_ENV, DETACHED_TMUX_HISTORY_LIMIT, } from "../index.js";
|
|
11
11
|
import { mergeConfig, repairConfigIfNeeded } from "../../config/generator.js";
|
|
12
12
|
import { ensureReusableNodeModules } from "../../utils/repo-deps.js";
|
|
13
13
|
import { readAllState } from "../../hud/state.js";
|
|
@@ -1937,7 +1937,19 @@ describe("tmux HUD pane helpers", () => {
|
|
|
1937
1937
|
"-t",
|
|
1938
1938
|
"%leader",
|
|
1939
1939
|
"-F",
|
|
1940
|
-
|
|
1940
|
+
[
|
|
1941
|
+
"#{pane_id}",
|
|
1942
|
+
"#{pane_current_command}",
|
|
1943
|
+
"#{pane_left}",
|
|
1944
|
+
"#{pane_top}",
|
|
1945
|
+
"#{pane_width}",
|
|
1946
|
+
"#{pane_height}",
|
|
1947
|
+
"#{pane_bottom}",
|
|
1948
|
+
"#{window_width}",
|
|
1949
|
+
"#{window_height}",
|
|
1950
|
+
"#{pane_start_command}",
|
|
1951
|
+
"#{pane_current_path}",
|
|
1952
|
+
].join("\x1f"),
|
|
1941
1953
|
]);
|
|
1942
1954
|
});
|
|
1943
1955
|
it("createHudWatchPane splits from the emitting pane target when provided", () => {
|
|
@@ -2076,6 +2088,134 @@ describe("detached tmux new-session sequencing", () => {
|
|
|
2076
2088
|
assert.match(envScript, /export IS_GAJAE_SLOP_GENERATOR='1'/);
|
|
2077
2089
|
assert.doesNotMatch(envScript, /not-a-shell-name/);
|
|
2078
2090
|
});
|
|
2091
|
+
it("creates a repo-local omx command shim for launched Codex sessions", async () => {
|
|
2092
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-"));
|
|
2093
|
+
try {
|
|
2094
|
+
const shimDir = ensureOmxRuntimeCommandShim(cwd, "/repo/dist/cli/omx.js", "/usr/local/bin/node");
|
|
2095
|
+
const shimPath = omxRuntimeCommandShimPath(cwd);
|
|
2096
|
+
assert.equal(shimDir, dirname(shimPath));
|
|
2097
|
+
assert.equal(existsSync(shimPath), true);
|
|
2098
|
+
assert.equal(await readFile(shimPath, "utf-8"), [
|
|
2099
|
+
"#!/bin/sh",
|
|
2100
|
+
`exec '/usr/local/bin/node' '/repo/dist/cli/omx.js' "$@"`,
|
|
2101
|
+
"",
|
|
2102
|
+
].join("\n"));
|
|
2103
|
+
assert.equal((await stat(shimPath)).mode & 0o700, 0o700);
|
|
2104
|
+
}
|
|
2105
|
+
finally {
|
|
2106
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
it("prepends the repo-local omx shim before global PATH entries", async () => {
|
|
2110
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-env-"));
|
|
2111
|
+
try {
|
|
2112
|
+
const env = prependOmxRuntimeCommandShimToEnv(cwd, {
|
|
2113
|
+
PATH: "/opt/homebrew/bin:/usr/bin",
|
|
2114
|
+
OMX_ENTRY_PATH: "/opt/homebrew/lib/node_modules/oh-my-codex/dist/cli/omx.js",
|
|
2115
|
+
}, "/repo/dist/cli/omx.js", "/usr/local/bin/node");
|
|
2116
|
+
const shimDir = dirname(omxRuntimeCommandShimPath(cwd));
|
|
2117
|
+
assert.equal(env.PATH, `${shimDir}${delimiter}/opt/homebrew/bin:/usr/bin`);
|
|
2118
|
+
assert.equal(env.OMX_ENTRY_PATH, "/repo/dist/cli/omx.js");
|
|
2119
|
+
assert.equal(env.OMX_STARTUP_CWD, cwd);
|
|
2120
|
+
}
|
|
2121
|
+
finally {
|
|
2122
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
2125
|
+
it("executes the repo-local omx shim before a stale global omx with misleading success output", async () => {
|
|
2126
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-exec-"));
|
|
2127
|
+
try {
|
|
2128
|
+
const fakeGlobalBin = join(cwd, "fake-global-bin");
|
|
2129
|
+
const fakeLocalBin = join(cwd, "fake local's $() ; bin");
|
|
2130
|
+
await mkdir(fakeGlobalBin);
|
|
2131
|
+
await mkdir(fakeLocalBin);
|
|
2132
|
+
const globalMarker = join(cwd, "GLOBAL_CALLED");
|
|
2133
|
+
const localMarker = join(cwd, "LOCAL_CALLED");
|
|
2134
|
+
const fakeGlobalOmx = join(fakeGlobalBin, "omx");
|
|
2135
|
+
const fakeNode = join(fakeLocalBin, "node runner");
|
|
2136
|
+
const localOmxEntry = join(fakeLocalBin, "omx entry's $() ;.js");
|
|
2137
|
+
await writeFile(fakeGlobalOmx, `#!/bin/sh
|
|
2138
|
+
printf 'global-called\\n' > "${globalMarker}"
|
|
2139
|
+
printf '{"success":true,"source":"global"}\\n'
|
|
2140
|
+
exit 0
|
|
2141
|
+
`);
|
|
2142
|
+
await chmod(fakeGlobalOmx, 0o755);
|
|
2143
|
+
await writeFile(fakeNode, `#!/bin/sh
|
|
2144
|
+
printf '%s\\n' "$@" > "${localMarker}"
|
|
2145
|
+
printf '{"success":true,"source":"local"}\\n'
|
|
2146
|
+
exit 0
|
|
2147
|
+
`);
|
|
2148
|
+
await chmod(fakeNode, 0o755);
|
|
2149
|
+
const env = prependOmxRuntimeCommandShimToEnv(cwd, { PATH: `${fakeGlobalBin}${delimiter}/usr/bin:/bin` }, localOmxEntry, fakeNode);
|
|
2150
|
+
const { execFileSync } = await import("node:child_process");
|
|
2151
|
+
const output = execFileSync("omx", ["team", "status", "hud-check"], {
|
|
2152
|
+
cwd,
|
|
2153
|
+
env,
|
|
2154
|
+
encoding: "utf-8",
|
|
2155
|
+
});
|
|
2156
|
+
assert.match(output, /"source":"local"/);
|
|
2157
|
+
assert.equal(existsSync(globalMarker), false);
|
|
2158
|
+
assert.deepEqual((await readFile(localMarker, "utf-8")).trim().split("\n"), [
|
|
2159
|
+
localOmxEntry,
|
|
2160
|
+
"team",
|
|
2161
|
+
"status",
|
|
2162
|
+
"hud-check",
|
|
2163
|
+
]);
|
|
2164
|
+
}
|
|
2165
|
+
finally {
|
|
2166
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
it("overwrites stale runtime shim contents and permissions", async () => {
|
|
2170
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-stale-"));
|
|
2171
|
+
try {
|
|
2172
|
+
const shimPath = omxRuntimeCommandShimPath(cwd);
|
|
2173
|
+
await mkdir(dirname(shimPath), { recursive: true });
|
|
2174
|
+
await writeFile(shimPath, "#!/bin/sh\necho stale-global\n");
|
|
2175
|
+
await chmod(shimPath, 0o600);
|
|
2176
|
+
ensureOmxRuntimeCommandShim(cwd, "/repo/dist/cli/omx.js", "/usr/local/bin/node");
|
|
2177
|
+
assert.equal(await readFile(shimPath, "utf-8"), [
|
|
2178
|
+
"#!/bin/sh",
|
|
2179
|
+
`exec '/usr/local/bin/node' '/repo/dist/cli/omx.js' "$@"`,
|
|
2180
|
+
"",
|
|
2181
|
+
].join("\n"));
|
|
2182
|
+
assert.equal((await stat(shimPath)).mode & 0o777, 0o700);
|
|
2183
|
+
}
|
|
2184
|
+
finally {
|
|
2185
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2186
|
+
}
|
|
2187
|
+
});
|
|
2188
|
+
it("replaces a stale runtime shim symlink without following it", async () => {
|
|
2189
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-symlink-"));
|
|
2190
|
+
try {
|
|
2191
|
+
if (process.platform === "win32")
|
|
2192
|
+
return;
|
|
2193
|
+
const shimPath = omxRuntimeCommandShimPath(cwd);
|
|
2194
|
+
const externalTarget = join(cwd, "outside-target");
|
|
2195
|
+
await mkdir(dirname(shimPath), { recursive: true });
|
|
2196
|
+
await writeFile(externalTarget, "do not overwrite\n");
|
|
2197
|
+
await symlink(externalTarget, shimPath);
|
|
2198
|
+
ensureOmxRuntimeCommandShim(cwd, "/repo/dist/cli/omx.js", "/usr/local/bin/node");
|
|
2199
|
+
assert.equal(await readFile(externalTarget, "utf-8"), "do not overwrite\n");
|
|
2200
|
+
assert.equal((await lstat(shimPath)).isSymbolicLink(), false);
|
|
2201
|
+
assert.match(await readFile(shimPath, "utf-8"), /\/repo\/dist\/cli\/omx\.js/);
|
|
2202
|
+
}
|
|
2203
|
+
finally {
|
|
2204
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2205
|
+
}
|
|
2206
|
+
});
|
|
2207
|
+
it("throws when the runtime shim bin path is not a directory", async () => {
|
|
2208
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-runtime-command-shim-file-"));
|
|
2209
|
+
try {
|
|
2210
|
+
const shimPath = omxRuntimeCommandShimPath(cwd);
|
|
2211
|
+
await mkdir(dirname(dirname(shimPath)), { recursive: true });
|
|
2212
|
+
await writeFile(dirname(shimPath), "not a directory\n");
|
|
2213
|
+
assert.throws(() => ensureOmxRuntimeCommandShim(cwd, "/repo/dist/cli/omx.js", "/usr/local/bin/node"), /not a directory/);
|
|
2214
|
+
}
|
|
2215
|
+
finally {
|
|
2216
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2217
|
+
}
|
|
2218
|
+
});
|
|
2079
2219
|
it("keeps detached tmux bootstrap bounded when no interactive parent env file is requested", () => {
|
|
2080
2220
|
const steps = buildDetachedSessionBootstrapSteps("omx-demo", "/tmp/project", "'codex' '--model' 'gpt-5'", "'node' '/tmp/omx.js' 'hud' '--watch'", null, undefined, null, false, "sess-detached-managed", undefined, undefined, undefined, { CUSTOM_LLM_API_KEY: "fake-provider-key" });
|
|
2081
2221
|
const newSession = steps.find((step) => step.name === "new-session");
|
|
@@ -2105,7 +2245,113 @@ describe("detached tmux new-session sequencing", () => {
|
|
|
2105
2245
|
});
|
|
2106
2246
|
it("runCodex registers a HUD resize hook immediately for inside-tmux launches", async () => {
|
|
2107
2247
|
const source = await readFile(join(repoRoot, 'src', 'cli', 'index.ts'), 'utf-8');
|
|
2108
|
-
assert.match(source, /
|
|
2248
|
+
assert.match(source, /registerInsideTmuxHudResizeHook\(\{\s*hudPaneId,\s*currentPaneId,\s*cwd,\s*sessionId,\s*omxRootOverride,\s*\}\)/);
|
|
2249
|
+
assert.match(source, /if \(currentPaneId\) \{\s*unregisterHudResizeHook\(currentPaneId\);\s*\}/);
|
|
2250
|
+
});
|
|
2251
|
+
it("buildInsideTmuxHudHookEnv tags hook commands with session, owner, leader, and local root", () => {
|
|
2252
|
+
const env = buildInsideTmuxHudHookEnv({ PATH: "/bin" }, "sess-a", "%leader", "/repo");
|
|
2253
|
+
assert.equal(env.PATH, "/bin");
|
|
2254
|
+
assert.equal(env.OMX_SESSION_ID, "sess-a");
|
|
2255
|
+
assert.equal(env.OMX_TMUX_HUD_OWNER, "1");
|
|
2256
|
+
assert.equal(env.OMX_TMUX_HUD_LEADER_PANE, "%leader");
|
|
2257
|
+
assert.equal(env.OMX_ROOT, "/repo");
|
|
2258
|
+
});
|
|
2259
|
+
it("registerInsideTmuxHudResizeHook forwards cwd and env to hook registration", () => {
|
|
2260
|
+
const calls = [];
|
|
2261
|
+
const result = registerInsideTmuxHudResizeHook({
|
|
2262
|
+
hudPaneId: "%hud",
|
|
2263
|
+
currentPaneId: "%leader",
|
|
2264
|
+
cwd: "/repo",
|
|
2265
|
+
sessionId: "sess-a",
|
|
2266
|
+
omxRootOverride: "/repo",
|
|
2267
|
+
baseEnv: { PATH: "/bin" },
|
|
2268
|
+
register: (hudPaneId, leaderPaneId, heightLines, options) => {
|
|
2269
|
+
calls.push({ hudPaneId, leaderPaneId, heightLines, cwd: options?.cwd, env: options?.env });
|
|
2270
|
+
return true;
|
|
2271
|
+
},
|
|
2272
|
+
});
|
|
2273
|
+
assert.equal(result, true);
|
|
2274
|
+
assert.deepEqual(calls, [{
|
|
2275
|
+
hudPaneId: "%hud",
|
|
2276
|
+
leaderPaneId: "%leader",
|
|
2277
|
+
heightLines: HUD_TMUX_HEIGHT_LINES,
|
|
2278
|
+
cwd: "/repo",
|
|
2279
|
+
env: {
|
|
2280
|
+
PATH: "/bin",
|
|
2281
|
+
OMX_SESSION_ID: "sess-a",
|
|
2282
|
+
OMX_TMUX_HUD_OWNER: "1",
|
|
2283
|
+
OMX_TMUX_HUD_LEADER_PANE: "%leader",
|
|
2284
|
+
OMX_ROOT: "/repo",
|
|
2285
|
+
},
|
|
2286
|
+
}]);
|
|
2287
|
+
assert.equal(registerInsideTmuxHudResizeHook({
|
|
2288
|
+
hudPaneId: null,
|
|
2289
|
+
currentPaneId: "%leader",
|
|
2290
|
+
cwd: "/repo",
|
|
2291
|
+
sessionId: "sess-a",
|
|
2292
|
+
register: () => {
|
|
2293
|
+
throw new Error("should not register without a HUD pane");
|
|
2294
|
+
},
|
|
2295
|
+
}), false);
|
|
2296
|
+
});
|
|
2297
|
+
it("buildDetachedHudHookEnv preserves tmux targeting and local launcher identity", () => {
|
|
2298
|
+
const env = buildDetachedHudHookEnv({ PATH: "/bin" }, "sess-a", "%leader", "/tmp/tmux.sock,123,7", "/repo/dist/cli/omx.js", "/repo");
|
|
2299
|
+
assert.equal(env.PATH, "/bin");
|
|
2300
|
+
assert.equal(env.TMUX, "/tmp/tmux.sock,123,7");
|
|
2301
|
+
assert.equal(env.TMUX_PANE, "%leader");
|
|
2302
|
+
assert.equal(env.OMX_SESSION_ID, "sess-a");
|
|
2303
|
+
assert.equal(env.OMX_TMUX_HUD_OWNER, "1");
|
|
2304
|
+
assert.equal(env.OMX_ROOT, "/repo");
|
|
2305
|
+
assert.equal(env.OMX_ENTRY_PATH, "/repo/dist/cli/omx.js");
|
|
2306
|
+
});
|
|
2307
|
+
it("registerDetachedHudLayoutReconcileHook reads TMUX from the detached leader pane before registering", () => {
|
|
2308
|
+
const calls = [];
|
|
2309
|
+
const readTargets = [];
|
|
2310
|
+
const result = registerDetachedHudLayoutReconcileHook({
|
|
2311
|
+
hudPaneId: "%hud",
|
|
2312
|
+
detachedLeaderPaneId: "%leader",
|
|
2313
|
+
cwd: "/repo",
|
|
2314
|
+
sessionId: "sess-a",
|
|
2315
|
+
omxBin: "/repo/dist/cli/omx.js",
|
|
2316
|
+
omxRootOverride: "/repo",
|
|
2317
|
+
baseEnv: { PATH: "/bin" },
|
|
2318
|
+
readTmuxEnvValue: (targetPaneId) => {
|
|
2319
|
+
readTargets.push(targetPaneId);
|
|
2320
|
+
return "/tmp/tmux.sock,123,7";
|
|
2321
|
+
},
|
|
2322
|
+
register: (hudPaneId, leaderPaneId, heightLines, options) => {
|
|
2323
|
+
calls.push({ hudPaneId, leaderPaneId, heightLines, cwd: options?.cwd, env: options?.env });
|
|
2324
|
+
return true;
|
|
2325
|
+
},
|
|
2326
|
+
});
|
|
2327
|
+
assert.equal(result, true);
|
|
2328
|
+
assert.deepEqual(readTargets, ["%leader"]);
|
|
2329
|
+
assert.deepEqual(calls, [{
|
|
2330
|
+
hudPaneId: "%hud",
|
|
2331
|
+
leaderPaneId: "%leader",
|
|
2332
|
+
heightLines: HUD_TMUX_HEIGHT_LINES,
|
|
2333
|
+
cwd: "/repo",
|
|
2334
|
+
env: {
|
|
2335
|
+
PATH: "/bin",
|
|
2336
|
+
TMUX: "/tmp/tmux.sock,123,7",
|
|
2337
|
+
TMUX_PANE: "%leader",
|
|
2338
|
+
OMX_SESSION_ID: "sess-a",
|
|
2339
|
+
OMX_TMUX_HUD_OWNER: "1",
|
|
2340
|
+
OMX_ROOT: "/repo",
|
|
2341
|
+
OMX_ENTRY_PATH: "/repo/dist/cli/omx.js",
|
|
2342
|
+
},
|
|
2343
|
+
}]);
|
|
2344
|
+
assert.equal(registerDetachedHudLayoutReconcileHook({
|
|
2345
|
+
hudPaneId: "%hud",
|
|
2346
|
+
detachedLeaderPaneId: "%leader",
|
|
2347
|
+
cwd: "/repo",
|
|
2348
|
+
sessionId: "sess-a",
|
|
2349
|
+
omxBin: "/repo/dist/cli/omx.js",
|
|
2350
|
+
readTmuxEnvValue: () => undefined,
|
|
2351
|
+
register: () => {
|
|
2352
|
+
throw new Error("should not register without TMUX");
|
|
2353
|
+
},
|
|
2354
|
+
}), false);
|
|
2109
2355
|
});
|
|
2110
2356
|
it("buildDetachedSessionBootstrapSteps starts native Windows detached sessions with powershell", () => {
|
|
2111
2357
|
const hudCmd = buildWindowsPromptCommand("node", [
|