oh-my-codex 0.17.2 → 0.18.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.
- package/Cargo.lock +13 -5
- package/Cargo.toml +2 -1
- package/README.md +1 -0
- package/crates/omx-api/Cargo.toml +19 -0
- package/crates/omx-api/src/lib.rs +2940 -0
- package/crates/omx-api/src/main.rs +10 -0
- package/crates/omx-api/tests/cli.rs +558 -0
- package/crates/omx-explore/src/main.rs +4 -0
- package/crates/omx-sparkshell/src/codex_bridge.rs +437 -123
- package/crates/omx-sparkshell/src/exec.rs +4 -0
- package/crates/omx-sparkshell/src/main.rs +738 -29
- package/crates/omx-sparkshell/src/prompt.rs +25 -3
- package/crates/omx-sparkshell/src/redaction.rs +241 -0
- package/crates/omx-sparkshell/tests/execution.rs +479 -238
- package/dist/cli/__tests__/api.test.d.ts +2 -0
- package/dist/cli/__tests__/api.test.d.ts.map +1 -0
- package/dist/cli/__tests__/api.test.js +175 -0
- package/dist/cli/__tests__/api.test.js.map +1 -0
- package/dist/cli/__tests__/ask.test.js +72 -5
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js +14 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +51 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +23 -0
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +123 -5
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +76 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +4 -3
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +45 -22
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +2 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +138 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +8 -2
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +5 -0
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/version-sync-contract.test.js +4 -0
- package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/api.d.ts +26 -0
- package/dist/cli/api.d.ts.map +1 -0
- package/dist/cli/api.js +153 -0
- package/dist/cli/api.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +39 -4
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts +2 -0
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +43 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +10 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +128 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/native-assets.d.ts +2 -1
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +1 -0
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +6 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +20 -3
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +90 -0
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts +2 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.js +27 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +11 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +6 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +4 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +1 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +2 -2
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +23 -18
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +7 -6
- package/dist/hud/tmux.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +75 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +3 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +71 -2
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +737 -26
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js +183 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +4 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/build-api.d.ts +2 -0
- package/dist/scripts/build-api.d.ts.map +1 -0
- package/dist/scripts/build-api.js +44 -0
- package/dist/scripts/build-api.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +208 -8
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +89 -24
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +88 -0
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +27 -9
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +26 -11
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +1 -0
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +38 -0
- package/dist/scripts/notify-hook/team-tmux-guard.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 +27 -14
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/run-provider-advisor.js +9 -3
- package/dist/scripts/run-provider-advisor.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +1 -1
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +2 -0
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +2 -2
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +153 -25
- package/dist/team/__tests__/tmux-session.test.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 +55 -10
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/utils/__tests__/agents-md.test.js +45 -1
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts +2 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +19 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +85 -10
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +1 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/package.json +4 -3
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +83 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +1 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
- package/prompts/researcher.md +15 -10
- package/skills/best-practice-research/SKILL.md +83 -0
- package/skills/deep-interview/SKILL.md +1 -0
- package/skills/ralplan/SKILL.md +1 -1
- package/src/scripts/__tests__/codex-native-hook.test.ts +810 -4
- package/src/scripts/__tests__/notify-dispatcher.test.ts +223 -1
- package/src/scripts/__tests__/smoke-packed-install.test.ts +8 -2
- package/src/scripts/build-api.ts +48 -0
- package/src/scripts/codex-native-hook.ts +262 -10
- package/src/scripts/codex-native-pre-post.ts +103 -24
- package/src/scripts/notify-dispatcher.ts +97 -0
- package/src/scripts/notify-hook/team-dispatch.ts +27 -8
- package/src/scripts/notify-hook/team-leader-nudge.ts +25 -11
- package/src/scripts/notify-hook/team-tmux-guard.ts +42 -0
- package/src/scripts/notify-hook/team-worker-stop.ts +24 -13
- package/src/scripts/run-provider-advisor.ts +11 -3
- package/src/scripts/smoke-packed-install.ts +2 -0
- package/templates/catalog-manifest.json +7 -0
|
@@ -6,7 +6,7 @@ import { PassThrough } from 'node:stream';
|
|
|
6
6
|
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { tmpdir } from 'os';
|
|
9
|
-
import { buildClientAttachedReconcileHookName, assertTeamWorkerCliBinaryAvailable, buildWorkerProcessLaunchSpec, buildReconcileHudResizeArgs, buildRegisterClientAttachedReconcileArgs, buildRegisterResizeHookArgs, buildResizeHookName, buildResizeHookTarget, buildScheduleDelayedHudResizeArgs, buildUnregisterClientAttachedReconcileArgs, buildUnregisterResizeHookArgs, buildWorkerStartupCommand, buildHudPaneTarget, chooseTeamLeaderPaneId, createTeamSession, enableMouseScrolling, isMsysOrGitBash, isNativeWindows, isTmuxAvailable, restoreStandaloneHudPane, translatePathForMsys, isWsl2, isWorkerAlive, killWorker, killWorkerByPaneId, teardownWorkerPanes, listTeamSessions, resolveTeamWorkerCli, resolveTeamWorkerLaunchMode, resolveWorkerCliForSend, resolveTeamWorkerCliPlan, buildWorkerSubmitPlan, sanitizeTeamName, shouldAttemptAdaptiveRetry, sendToWorker, sendToWorkerStdin, sleepFractionalSeconds, translateWorkerLaunchArgsForCli, waitForWorkerReady, waitForWorkerReadyAsync, paneIsBootstrapping, classifyWorkerStartupInjectSafety, checkWorkerStartupInjectSafety, dismissTrustPromptIfPresent, evaluateStartupDirectTriggerSafetyCapture, mitigateCopyModeUnderlineArtifacts, } from '../tmux-session.js';
|
|
9
|
+
import { buildClientAttachedReconcileHookName, assertTeamWorkerCliBinaryAvailable, buildWorkerProcessLaunchSpec, buildReconcileHudResizeArgs, buildRegisterClientAttachedReconcileArgs, buildRegisterResizeHookArgs, buildResizeHookName, buildResizeHookTarget, buildScheduleDelayedHudResizeArgs, buildUnregisterClientAttachedReconcileArgs, buildUnregisterResizeHookArgs, buildWorkerStartupCommand, shouldSourceTeamWorkerShellRc, buildHudPaneTarget, chooseTeamLeaderPaneId, createTeamSession, enableMouseScrolling, isMsysOrGitBash, isNativeWindows, isTmuxAvailable, restoreStandaloneHudPane, translatePathForMsys, isWsl2, isWorkerAlive, killWorker, killWorkerByPaneId, teardownWorkerPanes, listTeamSessions, resolveTeamWorkerCli, resolveTeamWorkerLaunchMode, resolveWorkerCliForSend, resolveTeamWorkerCliPlan, buildWorkerSubmitPlan, sanitizeTeamName, shouldAttemptAdaptiveRetry, sendToWorker, sendToWorkerStdin, sleepFractionalSeconds, translateWorkerLaunchArgsForCli, waitForWorkerReady, waitForWorkerReadyAsync, paneIsBootstrapping, classifyWorkerStartupInjectSafety, checkWorkerStartupInjectSafety, dismissTrustPromptIfPresent, evaluateStartupDirectTriggerSafetyCapture, mitigateCopyModeUnderlineArtifacts, } from '../tmux-session.js';
|
|
10
10
|
import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../../hud/constants.js';
|
|
11
11
|
import * as tmuxSessionModule from '../tmux-session.js';
|
|
12
12
|
import { OMX_ENTRY_PATH_ENV, OMX_STARTUP_CWD_ENV } from '../../utils/paths.js';
|
|
@@ -133,18 +133,19 @@ describe('HUD resize hook command builders', () => {
|
|
|
133
133
|
assert.equal(buildHudPaneTarget('%41'), '%41');
|
|
134
134
|
assert.equal(buildHudPaneTarget('41'), '%41');
|
|
135
135
|
});
|
|
136
|
-
it('buildRegisterResizeHookArgs uses window target and numeric
|
|
136
|
+
it('buildRegisterResizeHookArgs uses window target and numeric window-resized hook slot', () => {
|
|
137
137
|
const args = buildRegisterResizeHookArgs('my-session:0', 'omx_resize_team_session_0_1', '%1');
|
|
138
138
|
assert.equal(args[0], 'set-hook');
|
|
139
|
-
assert.equal(args[1], '-
|
|
140
|
-
assert.equal(args[2], '
|
|
141
|
-
assert.
|
|
142
|
-
assert.
|
|
139
|
+
assert.equal(args[1], '-w');
|
|
140
|
+
assert.equal(args[2], '-t');
|
|
141
|
+
assert.equal(args[3], 'my-session:0');
|
|
142
|
+
assert.match(args[4] ?? '', /^window-resized\[\d+\]$/);
|
|
143
|
+
assert.equal(args[5], `run-shell -b 'tmux resize-pane -t %1 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true; sleep ${HUD_RESIZE_RECONCILE_DELAY_SECONDS}; tmux resize-pane -t %1 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true'`);
|
|
143
144
|
});
|
|
144
145
|
it('buildUnregisterResizeHookArgs removes the exact numeric hook slot', () => {
|
|
145
146
|
const registered = buildRegisterResizeHookArgs('my-session:0', 'omx_resize_team_session_0_1', '%1');
|
|
146
147
|
const unregistered = buildUnregisterResizeHookArgs('my-session:0', 'omx_resize_team_session_0_1');
|
|
147
|
-
assert.deepEqual(unregistered, ['set-hook', '-u', '-t', 'my-session:0', registered[
|
|
148
|
+
assert.deepEqual(unregistered, ['set-hook', '-u', '-w', '-t', 'my-session:0', registered[4]]);
|
|
148
149
|
});
|
|
149
150
|
it('buildClientAttachedReconcileHookName normalizes all segments into collision-safe tokens', () => {
|
|
150
151
|
const name = buildClientAttachedReconcileHookName('Team A', 'Session:Main', '0', '%12');
|
|
@@ -169,7 +170,7 @@ describe('HUD resize hook command builders', () => {
|
|
|
169
170
|
const longName = 'omx_resize_' + 'a'.repeat(200);
|
|
170
171
|
const resizeArgs = buildRegisterResizeHookArgs('sess:0', longName, '%1');
|
|
171
172
|
const attachedArgs = buildRegisterClientAttachedReconcileArgs('sess:0', longName, '%1');
|
|
172
|
-
const resizeSlot = resizeArgs[
|
|
173
|
+
const resizeSlot = resizeArgs[4] ?? '';
|
|
173
174
|
const attachedSlot = attachedArgs[3] ?? '';
|
|
174
175
|
const resizeIndex = Number((resizeSlot.match(/\[(\d+)\]/) ?? [])[1]);
|
|
175
176
|
const attachedIndex = Number((attachedSlot.match(/\[(\d+)\]/) ?? [])[1]);
|
|
@@ -182,7 +183,7 @@ describe('HUD resize hook command builders', () => {
|
|
|
182
183
|
const name = 'omx_resize_team_session_0_1';
|
|
183
184
|
const a = buildRegisterResizeHookArgs('s:0', name, '%1');
|
|
184
185
|
const b = buildRegisterResizeHookArgs('s:0', name, '%1');
|
|
185
|
-
assert.equal(a[
|
|
186
|
+
assert.equal(a[4], b[4]);
|
|
186
187
|
const c = buildRegisterClientAttachedReconcileArgs('s:0', name, '%1');
|
|
187
188
|
const d = buildRegisterClientAttachedReconcileArgs('s:0', name, '%1');
|
|
188
189
|
assert.equal(c[3], d[3]);
|
|
@@ -209,8 +210,8 @@ describe('HUD resize hook command builders', () => {
|
|
|
209
210
|
const resizeArgs = buildRegisterResizeHookArgs('my-session:0', 'omx_resize_team_session_0_1', '%1');
|
|
210
211
|
const delayedArgs = buildScheduleDelayedHudResizeArgs('%1');
|
|
211
212
|
const reconcileArgs = buildReconcileHudResizeArgs('%1');
|
|
212
|
-
assert.match(resizeArgs[
|
|
213
|
-
assert.doesNotMatch(resizeArgs[
|
|
213
|
+
assert.match(resizeArgs[5] ?? '', new RegExp(escapeRegExp(tmuxPath)));
|
|
214
|
+
assert.doesNotMatch(resizeArgs[5] ?? '', /^run-shell -b 'tmux resize-pane/);
|
|
214
215
|
assert.match(delayedArgs[2] ?? '', new RegExp(escapeRegExp(tmuxPath)));
|
|
215
216
|
assert.doesNotMatch(delayedArgs[2] ?? '', /sleep \d+; tmux resize-pane/);
|
|
216
217
|
assert.match(reconcileArgs[1] ?? '', new RegExp(escapeRegExp(tmuxPath)));
|
|
@@ -480,6 +481,51 @@ esac
|
|
|
480
481
|
assert.ok(enterCount >= 4, `expected repeated submit nudges before failing closed on stuck queued banner:\n${log}`);
|
|
481
482
|
});
|
|
482
483
|
});
|
|
484
|
+
it('does not confirm delivery while a wrapped hyphenated trigger remains as an unsent draft', async () => {
|
|
485
|
+
const trigger = 'Read .omx/state/team/team-x/workers/worker-1/inbox.md';
|
|
486
|
+
await withMockTmuxFixture('omx-tmux-codex-wrapped-trigger-draft-', (logPath) => `#!/bin/sh
|
|
487
|
+
set -eu
|
|
488
|
+
state_dir="$(dirname "${logPath}")"
|
|
489
|
+
text_sent_file="$state_dir/text-sent"
|
|
490
|
+
printf '%s\n' "$*" >> "${logPath}"
|
|
491
|
+
case "$1" in
|
|
492
|
+
capture-pane)
|
|
493
|
+
if [ -f "$text_sent_file" ]; then
|
|
494
|
+
cat <<'EOF'
|
|
495
|
+
${READY_HELPER_CAPTURE}
|
|
496
|
+
|
|
497
|
+
› Read .omx/state/team/team-x/workers/worker-
|
|
498
|
+
1/inbox.md
|
|
499
|
+
EOF
|
|
500
|
+
else
|
|
501
|
+
cat <<'EOF'
|
|
502
|
+
${READY_HELPER_CAPTURE}
|
|
503
|
+
EOF
|
|
504
|
+
fi
|
|
505
|
+
exit 0
|
|
506
|
+
;;
|
|
507
|
+
send-keys)
|
|
508
|
+
if [ "\${4:-}" = "-l" ] && [ "\${6:-}" = "${trigger}" ]; then
|
|
509
|
+
: > "$text_sent_file"
|
|
510
|
+
fi
|
|
511
|
+
exit 0
|
|
512
|
+
;;
|
|
513
|
+
*)
|
|
514
|
+
exit 0
|
|
515
|
+
;;
|
|
516
|
+
esac
|
|
517
|
+
`, async ({ logPath }) => {
|
|
518
|
+
await assert.rejects(() => sendToWorker('omx-team-x', 1, trigger), /submit_failed/);
|
|
519
|
+
const log = await readFile(logPath, 'utf-8');
|
|
520
|
+
const enterCount = (log.match(/send-keys -t omx-team-x:1 C-m/g) || []).length;
|
|
521
|
+
assert.ok(enterCount >= 4, `expected repeated submit nudges before failing on the still-visible wrapped draft:\n${log}`);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
describe('sendToWorker adaptive retry matching', () => {
|
|
526
|
+
it('recognizes hyphen-wrapped trigger drafts as still visible', () => {
|
|
527
|
+
assert.equal(shouldAttemptAdaptiveRetry('auto', true, true, `${READY_HELPER_CAPTURE}\n\n› Read .omx/state/team/team-x/workers/worker-\n 1/inbox.md`, 'Read .omx/state/team/team-x/workers/worker-1/inbox.md'), true);
|
|
528
|
+
});
|
|
483
529
|
});
|
|
484
530
|
describe('startup direct trigger safety', () => {
|
|
485
531
|
it('classifies ready panes as safe and blocks trust, bypass, bootstrapping, and active-task captures', () => {
|
|
@@ -781,7 +827,7 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
781
827
|
delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
782
828
|
}
|
|
783
829
|
});
|
|
784
|
-
it('uses zsh
|
|
830
|
+
it('uses zsh without sourcing ~/.zshrc by default and keeps non-login exec semantics', () => {
|
|
785
831
|
const prevShell = process.env.SHELL;
|
|
786
832
|
process.env.SHELL = '/bin/zsh';
|
|
787
833
|
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
@@ -791,7 +837,7 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
791
837
|
assert.match(cmd, /OMX_TEAM_WORKER=alpha\/worker-2/);
|
|
792
838
|
assert.match(cmd, /'\/bin\/zsh' -c/);
|
|
793
839
|
assert.doesNotMatch(cmd, /'\/bin\/zsh' -lc\b/);
|
|
794
|
-
assert.
|
|
840
|
+
assert.doesNotMatch(cmd, /source ~\/\.zshrc/);
|
|
795
841
|
assert.match(cmd, /exec .*codex/);
|
|
796
842
|
}
|
|
797
843
|
finally {
|
|
@@ -814,7 +860,7 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
814
860
|
const cmd = withMockedExistsSync((candidate) => candidate === '/opt/homebrew/bin/zsh', () => buildWorkerStartupCommand('alpha', 2));
|
|
815
861
|
assert.match(cmd, /'\/opt\/homebrew\/bin\/zsh' -c/);
|
|
816
862
|
assert.doesNotMatch(cmd, /'\/bin\/sh' -c/);
|
|
817
|
-
assert.
|
|
863
|
+
assert.doesNotMatch(cmd, /source ~\/\.zshrc/);
|
|
818
864
|
}
|
|
819
865
|
finally {
|
|
820
866
|
if (typeof prevShell === 'string')
|
|
@@ -836,7 +882,7 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
836
882
|
const cmd = withMockedExistsSync((candidate) => candidate === '/opt/local/bin/zsh', () => buildWorkerStartupCommand('alpha', 2));
|
|
837
883
|
assert.match(cmd, /'\/opt\/local\/bin\/zsh' -c/);
|
|
838
884
|
assert.doesNotMatch(cmd, /'\/bin\/sh' -c/);
|
|
839
|
-
assert.
|
|
885
|
+
assert.doesNotMatch(cmd, /source ~\/\.zshrc/);
|
|
840
886
|
}
|
|
841
887
|
finally {
|
|
842
888
|
if (typeof prevShell === 'string')
|
|
@@ -849,14 +895,14 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
849
895
|
delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
850
896
|
}
|
|
851
897
|
});
|
|
852
|
-
it('
|
|
898
|
+
it('prevents issue #2358 bash rc fan-out by default and preserves launch args', () => {
|
|
853
899
|
const prevShell = process.env.SHELL;
|
|
854
900
|
process.env.SHELL = '/bin/bash';
|
|
855
901
|
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
856
902
|
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
|
|
857
903
|
try {
|
|
858
904
|
const cmd = buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5']);
|
|
859
|
-
assert.
|
|
905
|
+
assert.doesNotMatch(cmd, /source ~\/\.bashrc/);
|
|
860
906
|
assert.match(cmd, /exec .*codex/);
|
|
861
907
|
assert.match(cmd, /--model/);
|
|
862
908
|
assert.match(cmd, /gpt-5/);
|
|
@@ -872,6 +918,37 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
872
918
|
delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
873
919
|
}
|
|
874
920
|
});
|
|
921
|
+
it('sources worker shell rc files only when explicitly opted in', () => {
|
|
922
|
+
const prevShell = process.env.SHELL;
|
|
923
|
+
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
924
|
+
const prevSourceRc = process.env.OMX_TMUX_SOURCE_SHELL_RC;
|
|
925
|
+
process.env.SHELL = '/bin/bash';
|
|
926
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
|
|
927
|
+
try {
|
|
928
|
+
delete process.env.OMX_TMUX_SOURCE_SHELL_RC;
|
|
929
|
+
assert.equal(shouldSourceTeamWorkerShellRc(process.env), false);
|
|
930
|
+
assert.doesNotMatch(buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5']), /source ~\/\.bashrc/);
|
|
931
|
+
process.env.OMX_TMUX_SOURCE_SHELL_RC = '1';
|
|
932
|
+
assert.equal(shouldSourceTeamWorkerShellRc(process.env), true);
|
|
933
|
+
assert.match(buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5']), /source ~\/\.bashrc/);
|
|
934
|
+
delete process.env.OMX_TMUX_SOURCE_SHELL_RC;
|
|
935
|
+
assert.match(buildWorkerStartupCommand('alpha', 1, ['--model', 'gpt-5'], process.cwd(), { OMX_TMUX_SOURCE_SHELL_RC: '1' }), /source ~\/\.bashrc/, 'per-worker explicit opt-in should be honored');
|
|
936
|
+
}
|
|
937
|
+
finally {
|
|
938
|
+
if (typeof prevShell === 'string')
|
|
939
|
+
process.env.SHELL = prevShell;
|
|
940
|
+
else
|
|
941
|
+
delete process.env.SHELL;
|
|
942
|
+
if (typeof prevBypass === 'string')
|
|
943
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
|
|
944
|
+
else
|
|
945
|
+
delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
946
|
+
if (typeof prevSourceRc === 'string')
|
|
947
|
+
process.env.OMX_TMUX_SOURCE_SHELL_RC = prevSourceRc;
|
|
948
|
+
else
|
|
949
|
+
delete process.env.OMX_TMUX_SOURCE_SHELL_RC;
|
|
950
|
+
}
|
|
951
|
+
});
|
|
875
952
|
it('injects canonical team state env vars when provided', () => {
|
|
876
953
|
const prevShell = process.env.SHELL;
|
|
877
954
|
process.env.SHELL = '/bin/bash';
|
|
@@ -1191,18 +1268,56 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
1191
1268
|
delete process.env.OMX_MODEL_INSTRUCTIONS_FILE;
|
|
1192
1269
|
}
|
|
1193
1270
|
});
|
|
1194
|
-
it('
|
|
1271
|
+
it('does not synthesize absent first-party OMX MCP server tables for Codex team workers', async () => {
|
|
1195
1272
|
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
1196
1273
|
const prevCompat = process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1197
|
-
process.env.
|
|
1198
|
-
|
|
1274
|
+
const prevCodexHome = process.env.CODEX_HOME;
|
|
1275
|
+
const codexHome = await mkdtemp(join(tmpdir(), 'omx-team-no-mcp-config-'));
|
|
1199
1276
|
try {
|
|
1277
|
+
await writeFile(join(codexHome, 'config.toml'), '[mcp_servers.gitnexus]\ncommand = "gitnexus"\n');
|
|
1278
|
+
process.env.CODEX_HOME = codexHome;
|
|
1279
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
|
|
1280
|
+
delete process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1281
|
+
const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project', {}, 'codex');
|
|
1282
|
+
for (const server of ['omx_state', 'omx_memory', 'omx_code_intel', 'omx_trace', 'omx_wiki', 'omx_hermes']) {
|
|
1283
|
+
assert.doesNotMatch(cmd, new RegExp(`mcp_servers\\.${server}\\.enabled=false`));
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
finally {
|
|
1287
|
+
await rm(codexHome, { recursive: true, force: true });
|
|
1288
|
+
if (typeof prevBypass === 'string')
|
|
1289
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
|
|
1290
|
+
else
|
|
1291
|
+
delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
1292
|
+
if (typeof prevCompat === 'string')
|
|
1293
|
+
process.env.OMX_TEAM_WORKER_MCP_COMPAT = prevCompat;
|
|
1294
|
+
else
|
|
1295
|
+
delete process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1296
|
+
if (typeof prevCodexHome === 'string')
|
|
1297
|
+
process.env.CODEX_HOME = prevCodexHome;
|
|
1298
|
+
else
|
|
1299
|
+
delete process.env.CODEX_HOME;
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
it('disables configured first-party OMX MCP compatibility servers for Codex team workers by default', async () => {
|
|
1303
|
+
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
1304
|
+
const prevCompat = process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1305
|
+
const prevCodexHome = process.env.CODEX_HOME;
|
|
1306
|
+
const codexHome = await mkdtemp(join(tmpdir(), 'omx-team-mcp-config-'));
|
|
1307
|
+
try {
|
|
1308
|
+
await writeFile(join(codexHome, 'config.toml'), ['omx_state', 'omx_memory', 'omx_code_intel', 'omx_trace', 'omx_wiki', 'omx_hermes']
|
|
1309
|
+
.map((server) => `[mcp_servers.${server}]\ncommand = "omx"\nargs = ["mcp-serve", "${server}"]\n`)
|
|
1310
|
+
.join('\n'));
|
|
1311
|
+
process.env.CODEX_HOME = codexHome;
|
|
1312
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
|
|
1313
|
+
delete process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1200
1314
|
const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project', {}, 'codex');
|
|
1201
1315
|
for (const server of ['omx_state', 'omx_memory', 'omx_code_intel', 'omx_trace', 'omx_wiki', 'omx_hermes']) {
|
|
1202
1316
|
assert.match(cmd, new RegExp(`mcp_servers\\.${server}\\.enabled=false`));
|
|
1203
1317
|
}
|
|
1204
1318
|
}
|
|
1205
1319
|
finally {
|
|
1320
|
+
await rm(codexHome, { recursive: true, force: true });
|
|
1206
1321
|
if (typeof prevBypass === 'string')
|
|
1207
1322
|
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
|
|
1208
1323
|
else
|
|
@@ -1211,18 +1326,27 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
1211
1326
|
process.env.OMX_TEAM_WORKER_MCP_COMPAT = prevCompat;
|
|
1212
1327
|
else
|
|
1213
1328
|
delete process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1329
|
+
if (typeof prevCodexHome === 'string')
|
|
1330
|
+
process.env.CODEX_HOME = prevCodexHome;
|
|
1331
|
+
else
|
|
1332
|
+
delete process.env.CODEX_HOME;
|
|
1214
1333
|
}
|
|
1215
1334
|
});
|
|
1216
|
-
it('preserves explicit team-worker MCP compatibility opt-in', () => {
|
|
1335
|
+
it('preserves explicit team-worker MCP compatibility opt-in', async () => {
|
|
1217
1336
|
const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
|
|
1218
1337
|
const prevCompat = process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1219
|
-
process.env.
|
|
1220
|
-
|
|
1338
|
+
const prevCodexHome = process.env.CODEX_HOME;
|
|
1339
|
+
const codexHome = await mkdtemp(join(tmpdir(), 'omx-team-mcp-compat-'));
|
|
1221
1340
|
try {
|
|
1341
|
+
await writeFile(join(codexHome, 'config.toml'), '[mcp_servers.omx_state]\ncommand = "omx"\n');
|
|
1342
|
+
process.env.CODEX_HOME = codexHome;
|
|
1343
|
+
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
|
|
1344
|
+
process.env.OMX_TEAM_WORKER_MCP_COMPAT = '1';
|
|
1222
1345
|
const cmd = buildWorkerStartupCommand('alpha', 1, [], '/tmp/project', {}, 'codex');
|
|
1223
1346
|
assert.doesNotMatch(cmd, /mcp_servers\.omx_state\.enabled=false/);
|
|
1224
1347
|
}
|
|
1225
1348
|
finally {
|
|
1349
|
+
await rm(codexHome, { recursive: true, force: true });
|
|
1226
1350
|
if (typeof prevBypass === 'string')
|
|
1227
1351
|
process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
|
|
1228
1352
|
else
|
|
@@ -1231,6 +1355,10 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
1231
1355
|
process.env.OMX_TEAM_WORKER_MCP_COMPAT = prevCompat;
|
|
1232
1356
|
else
|
|
1233
1357
|
delete process.env.OMX_TEAM_WORKER_MCP_COMPAT;
|
|
1358
|
+
if (typeof prevCodexHome === 'string')
|
|
1359
|
+
process.env.CODEX_HOME = prevCodexHome;
|
|
1360
|
+
else
|
|
1361
|
+
delete process.env.CODEX_HOME;
|
|
1234
1362
|
}
|
|
1235
1363
|
});
|
|
1236
1364
|
it('does not inject model_instructions_file override when disabled', () => {
|
|
@@ -1712,7 +1840,7 @@ describe('buildWorkerStartupCommand', () => {
|
|
|
1712
1840
|
try {
|
|
1713
1841
|
const cmd = withMockedExistsSync((candidate) => candidate === '/opt/custom/fish' || candidate === '/bin/bash', () => buildWorkerStartupCommand('alpha', 1, [], process.cwd()));
|
|
1714
1842
|
assert.match(cmd, /\/bin\/bash\b/, 'must fall back to bash when zsh is unavailable');
|
|
1715
|
-
assert.
|
|
1843
|
+
assert.doesNotMatch(cmd, /\.bashrc/, 'must not source bash rc file for bash fallback by default');
|
|
1716
1844
|
assert.doesNotMatch(cmd, /fish/, 'must not launch unsupported fish shell');
|
|
1717
1845
|
}
|
|
1718
1846
|
finally {
|
|
@@ -3039,7 +3167,7 @@ esac
|
|
|
3039
3167
|
assert.equal(session.resizeHookTarget, null);
|
|
3040
3168
|
const tmuxLog = await readFile(logPath, 'utf-8');
|
|
3041
3169
|
assert.match(tmuxLog, new RegExp(`resize-pane -t %3 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
|
|
3042
|
-
assert.doesNotMatch(tmuxLog, /set-hook -t leader:0
|
|
3170
|
+
assert.doesNotMatch(tmuxLog, /set-hook -w -t leader:0 window-resized\[\d+\]/);
|
|
3043
3171
|
assert.doesNotMatch(tmuxLog, /set-hook -t leader:0 client-attached\[\d+\]/);
|
|
3044
3172
|
assert.doesNotMatch(tmuxLog, /run-shell -b sleep \d+; tmux resize-pane -t %3 -y \d+ >/);
|
|
3045
3173
|
assert.doesNotMatch(tmuxLog, /run-shell tmux resize-pane -t %3 -y \d+ >/);
|