oh-my-codex 0.13.2 → 0.14.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 +5 -5
- package/Cargo.toml +1 -1
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts +2 -0
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +1 -0
- package/dist/autoresearch/__tests__/skill-validation.test.js +91 -0
- package/dist/autoresearch/__tests__/skill-validation.test.js.map +1 -0
- package/dist/autoresearch/skill-validation.d.ts +13 -0
- package/dist/autoresearch/skill-validation.d.ts.map +1 -0
- package/dist/autoresearch/skill-validation.js +165 -0
- package/dist/autoresearch/skill-validation.js.map +1 -0
- package/dist/catalog/__tests__/schema.test.js +6 -0
- package/dist/catalog/__tests__/schema.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +236 -273
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js +64 -653
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +7 -0
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +2 -1
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.d.ts +2 -0
- package/dist/cli/__tests__/question.test.d.ts.map +1 -0
- package/dist/cli/__tests__/question.test.js +113 -0
- package/dist/cli/__tests__/question.test.js.map +1 -0
- package/dist/cli/__tests__/session-search-help.test.js +1 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -0
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.d.ts +24 -7
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +189 -130
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch.d.ts +3 -2
- package/dist/cli/autoresearch.d.ts.map +1 -1
- package/dist/cli/autoresearch.js +29 -305
- package/dist/cli/autoresearch.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +43 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +8 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/question.d.ts +3 -0
- package/dist/cli/question.d.ts.map +1 -0
- package/dist/cli/question.js +182 -0
- package/dist/cli/question.js.map +1 -0
- package/dist/hooks/__tests__/analyze-routing-contract.test.js +22 -13
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +3 -3
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +2 -2
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +22 -5
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +2 -2
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +308 -17
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +570 -2
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +717 -16
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +25 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +894 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +34 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +132 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +22 -4
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +4 -2
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +1 -0
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +4 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +28 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +5 -4
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-team-routing.test.js +2 -2
- package/dist/hooks/__tests__/prompt-team-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/triage-config.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-config.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-config.test.js +211 -0
- package/dist/hooks/__tests__/triage-config.test.js.map +1 -0
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-heuristic.test.js +230 -0
- package/dist/hooks/__tests__/triage-heuristic.test.js.map +1 -0
- package/dist/hooks/__tests__/triage-state.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-state.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-state.test.js +426 -0
- package/dist/hooks/__tests__/triage-state.test.js.map +1 -0
- package/dist/hooks/keyword-detector.d.ts +26 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +97 -26
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +16 -9
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +28 -1
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/triage-config.d.ts +33 -0
- package/dist/hooks/triage-config.d.ts.map +1 -0
- package/dist/hooks/triage-config.js +87 -0
- package/dist/hooks/triage-config.js.map +1 -0
- package/dist/hooks/triage-heuristic.d.ts +20 -0
- package/dist/hooks/triage-heuristic.d.ts.map +1 -0
- package/dist/hooks/triage-heuristic.js +210 -0
- package/dist/hooks/triage-heuristic.js.map +1 -0
- package/dist/hooks/triage-state.d.ts +63 -0
- package/dist/hooks/triage-state.d.ts.map +1 -0
- package/dist/hooks/triage-state.js +138 -0
- package/dist/hooks/triage-state.js.map +1 -0
- package/dist/hud/__tests__/reconcile.test.js +20 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts +1 -0
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +2 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +1 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/state-server.d.ts +8 -0
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +4 -0
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/__tests__/base-ralph-contract.test.js +15 -0
- package/dist/modes/__tests__/base-ralph-contract.test.js.map +1 -1
- package/dist/modes/base.d.ts +1 -0
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +22 -6
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/index.test.js +78 -0
- package/dist/notifications/__tests__/index.test.js.map +1 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +39 -22
- package/dist/notifications/index.js.map +1 -1
- package/dist/openclaw/index.d.ts +5 -3
- package/dist/openclaw/index.d.ts.map +1 -1
- package/dist/openclaw/index.js +5 -3
- package/dist/openclaw/index.js.map +1 -1
- package/dist/question/__tests__/client.test.d.ts +2 -0
- package/dist/question/__tests__/client.test.d.ts.map +1 -0
- package/dist/question/__tests__/client.test.js +70 -0
- package/dist/question/__tests__/client.test.js.map +1 -0
- package/dist/question/__tests__/deep-interview.test.d.ts +2 -0
- package/dist/question/__tests__/deep-interview.test.d.ts.map +1 -0
- package/dist/question/__tests__/deep-interview.test.js +108 -0
- package/dist/question/__tests__/deep-interview.test.js.map +1 -0
- package/dist/question/__tests__/policy.test.d.ts +2 -0
- package/dist/question/__tests__/policy.test.d.ts.map +1 -0
- package/dist/question/__tests__/policy.test.js +107 -0
- package/dist/question/__tests__/policy.test.js.map +1 -0
- package/dist/question/__tests__/renderer.test.d.ts +2 -0
- package/dist/question/__tests__/renderer.test.d.ts.map +1 -0
- package/dist/question/__tests__/renderer.test.js +88 -0
- package/dist/question/__tests__/renderer.test.js.map +1 -0
- package/dist/question/__tests__/state.test.d.ts +2 -0
- package/dist/question/__tests__/state.test.d.ts.map +1 -0
- package/dist/question/__tests__/state.test.js +55 -0
- package/dist/question/__tests__/state.test.js.map +1 -0
- package/dist/question/__tests__/types.test.d.ts +2 -0
- package/dist/question/__tests__/types.test.d.ts.map +1 -0
- package/dist/question/__tests__/types.test.js +44 -0
- package/dist/question/__tests__/types.test.js.map +1 -0
- package/dist/question/__tests__/ui.test.d.ts +2 -0
- package/dist/question/__tests__/ui.test.d.ts.map +1 -0
- package/dist/question/__tests__/ui.test.js +169 -0
- package/dist/question/__tests__/ui.test.js.map +1 -0
- package/dist/question/client.d.ts +54 -0
- package/dist/question/client.d.ts.map +1 -0
- package/dist/question/client.js +77 -0
- package/dist/question/client.js.map +1 -0
- package/dist/question/deep-interview.d.ts +27 -0
- package/dist/question/deep-interview.d.ts.map +1 -0
- package/dist/question/deep-interview.js +101 -0
- package/dist/question/deep-interview.js.map +1 -0
- package/dist/question/policy.d.ts +18 -0
- package/dist/question/policy.d.ts.map +1 -0
- package/dist/question/policy.js +77 -0
- package/dist/question/policy.js.map +1 -0
- package/dist/question/renderer.d.ts +18 -0
- package/dist/question/renderer.d.ts.map +1 -0
- package/dist/question/renderer.js +128 -0
- package/dist/question/renderer.js.map +1 -0
- package/dist/question/state.d.ts +19 -0
- package/dist/question/state.d.ts.map +1 -0
- package/dist/question/state.js +108 -0
- package/dist/question/state.js.map +1 -0
- package/dist/question/types.d.ts +66 -0
- package/dist/question/types.d.ts.map +1 -0
- package/dist/question/types.js +82 -0
- package/dist/question/types.js.map +1 -0
- package/dist/question/ui.d.ts +38 -0
- package/dist/question/ui.d.ts.map +1 -0
- package/dist/question/ui.js +321 -0
- package/dist/question/ui.js.map +1 -0
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralph/contract.js +4 -1
- package/dist/ralph/contract.js.map +1 -1
- package/dist/ralplan/runtime.js +1 -1
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/run-loop.test.d.ts +2 -0
- package/dist/runtime/__tests__/run-loop.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/run-loop.test.js +35 -0
- package/dist/runtime/__tests__/run-loop.test.js.map +1 -0
- package/dist/runtime/__tests__/run-outcome.test.d.ts +2 -0
- package/dist/runtime/__tests__/run-outcome.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/run-outcome.test.js +64 -0
- package/dist/runtime/__tests__/run-outcome.test.js.map +1 -0
- package/dist/runtime/run-loop.d.ts +41 -0
- package/dist/runtime/run-loop.d.ts.map +1 -0
- package/dist/runtime/run-loop.js +46 -0
- package/dist/runtime/run-loop.js.map +1 -0
- package/dist/runtime/run-outcome.d.ts +28 -0
- package/dist/runtime/run-outcome.d.ts.map +1 -0
- package/dist/runtime/run-outcome.js +136 -0
- package/dist/runtime/run-outcome.js.map +1 -0
- package/dist/runtime/run-state.d.ts +36 -0
- package/dist/runtime/run-state.d.ts.map +1 -0
- package/dist/runtime/run-state.js +110 -0
- package/dist/runtime/run-state.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +1128 -85
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +2 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +199 -11
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +81 -2
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +27 -0
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +83 -20
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +64 -38
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook.js +15 -5
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/sync-prompt-guidance-fragments.js +5 -0
- package/dist/scripts/sync-prompt-guidance-fragments.js.map +1 -1
- package/dist/state/__tests__/operations-ralph-phase.test.js +21 -0
- package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +11 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +15 -0
- package/dist/state/operations.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +14 -1
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +3 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/followup-planner.test.js +15 -0
- package/dist/team/__tests__/followup-planner.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js +41 -0
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/followup-planner.d.ts.map +1 -1
- package/dist/team/followup-planner.js +31 -9
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/role-router.d.ts.map +1 -1
- package/dist/team/role-router.js +73 -0
- package/dist/team/role-router.js.map +1 -1
- package/package.json +3 -2
- package/prompts/dependency-expert.md +3 -0
- package/prompts/executor.md +5 -0
- package/prompts/explore.md +2 -0
- package/prompts/planner.md +5 -0
- package/prompts/product-analyst.md +8 -8
- package/prompts/researcher.md +78 -30
- package/prompts/verifier.md +4 -0
- package/skills/autoresearch/SKILL.md +68 -0
- package/skills/deep-interview/SKILL.md +10 -9
- package/skills/help/SKILL.md +3 -1
- package/skills/ralplan/SKILL.md +1 -0
- package/skills/team/SKILL.md +1 -0
- package/skills/ultrawork/SKILL.md +1 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +1495 -188
- package/src/scripts/codex-native-hook.ts +235 -19
- package/src/scripts/notify-fallback-watcher.ts +92 -2
- package/src/scripts/notify-hook/auto-nudge.ts +89 -20
- package/src/scripts/notify-hook/managed-tmux.ts +70 -31
- package/src/scripts/notify-hook/ralph-session-resume.ts +1 -1
- package/src/scripts/notify-hook.ts +23 -5
- package/src/scripts/sync-prompt-guidance-fragments.ts +4 -0
- package/templates/AGENTS.md +48 -37
- package/templates/catalog-manifest.json +7 -0
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
6
6
|
import { dirname, join } from 'node:path';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { normalizeAutoresearchCodexArgs, parseAutoresearchArgs } from '../autoresearch.js';
|
|
10
|
-
function withMockedTty(fn) {
|
|
11
|
-
const descriptor = Object.getOwnPropertyDescriptor(process.stdin, 'isTTY');
|
|
12
|
-
Object.defineProperty(process.stdin, 'isTTY', { configurable: true, value: true });
|
|
13
|
-
return fn().finally(() => {
|
|
14
|
-
if (descriptor) {
|
|
15
|
-
Object.defineProperty(process.stdin, 'isTTY', descriptor);
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
Object.defineProperty(process.stdin, 'isTTY', { configurable: true, value: false });
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
9
|
+
import { AUTORESEARCH_DEPRECATION_MESSAGE, autoresearchCommand, normalizeAutoresearchCodexArgs, parseAutoresearchArgs, } from '../autoresearch.js';
|
|
22
10
|
function runOmx(cwd, argv, envOverrides = {}) {
|
|
23
11
|
const testDir = dirname(fileURLToPath(import.meta.url));
|
|
24
12
|
const repoRoot = join(testDir, '..', '..', '..');
|
|
25
13
|
const omxBin = join(repoRoot, 'dist', 'cli', 'omx.js');
|
|
26
|
-
const
|
|
14
|
+
const result = spawnSync(process.execPath, [omxBin, ...argv], {
|
|
27
15
|
cwd,
|
|
28
16
|
encoding: 'utf-8',
|
|
29
17
|
env: {
|
|
@@ -34,7 +22,7 @@ function runOmx(cwd, argv, envOverrides = {}) {
|
|
|
34
22
|
...envOverrides,
|
|
35
23
|
},
|
|
36
24
|
});
|
|
37
|
-
return { status:
|
|
25
|
+
return { status: result.status, stdout: result.stdout || '', stderr: result.stderr || '', error: result.error?.message };
|
|
38
26
|
}
|
|
39
27
|
async function initRepo() {
|
|
40
28
|
const raw = await mkdtemp(join(tmpdir(), 'omx-autoresearch-test-'));
|
|
@@ -47,11 +35,6 @@ async function initRepo() {
|
|
|
47
35
|
execFileSync('git', ['commit', '-m', 'init'], { cwd, stdio: 'ignore' });
|
|
48
36
|
return cwd;
|
|
49
37
|
}
|
|
50
|
-
async function installFakePs(fakeBin) {
|
|
51
|
-
const fakePsPath = join(fakeBin, 'ps');
|
|
52
|
-
await writeFile(fakePsPath, '#!/bin/sh\nexit 0\n', 'utf-8');
|
|
53
|
-
execFileSync('chmod', ['+x', fakePsPath], { stdio: 'ignore' });
|
|
54
|
-
}
|
|
55
38
|
describe('normalizeAutoresearchCodexArgs', () => {
|
|
56
39
|
it('adds sandbox bypass by default for autoresearch workers', () => {
|
|
57
40
|
assert.deepEqual(normalizeAutoresearchCodexArgs(['--model', 'gpt-5']), ['--model', 'gpt-5', '--dangerously-bypass-approvals-and-sandbox']);
|
|
@@ -63,57 +46,7 @@ describe('normalizeAutoresearchCodexArgs', () => {
|
|
|
63
46
|
assert.deepEqual(normalizeAutoresearchCodexArgs(['--madmax']), ['--dangerously-bypass-approvals-and-sandbox']);
|
|
64
47
|
});
|
|
65
48
|
});
|
|
66
|
-
describe('
|
|
67
|
-
it('documents autoresearch in top-level help', async () => {
|
|
68
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-help-'));
|
|
69
|
-
try {
|
|
70
|
-
const result = runOmx(cwd, ['--help']);
|
|
71
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
72
|
-
assert.match(result.stdout, /omx autoresearch\s+Launch thin-supervisor autoresearch with keep\/discard\/reset parity/i);
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
75
|
-
await rm(cwd, { recursive: true, force: true });
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
it('routes autoresearch --help to command-local help', async () => {
|
|
79
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-local-help-'));
|
|
80
|
-
try {
|
|
81
|
-
const result = runOmx(cwd, ['autoresearch', '--help']);
|
|
82
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
83
|
-
assert.match(result.stdout, /Usage:[\s\S]*omx autoresearch run <mission-dir>/i);
|
|
84
|
-
assert.match(result.stdout, /omx autoresearch init/i);
|
|
85
|
-
assert.match(result.stdout, /--topic\/\.\.\./i);
|
|
86
|
-
assert.match(result.stdout, /deep-interview/i);
|
|
87
|
-
assert.match(result.stdout, /human entrypoint/i);
|
|
88
|
-
assert.doesNotMatch(result.stdout, /oh-my-codex \(omx\) - Multi-agent orchestration for Codex CLI/i);
|
|
89
|
-
}
|
|
90
|
-
finally {
|
|
91
|
-
await rm(cwd, { recursive: true, force: true });
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
it('documents --resume in command-local help', async () => {
|
|
95
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-resume-help-'));
|
|
96
|
-
try {
|
|
97
|
-
const result = runOmx(cwd, ['autoresearch', '--help']);
|
|
98
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
99
|
-
assert.match(result.stdout, /--resume <run-id>/i);
|
|
100
|
-
assert.match(result.stdout, /run-tagged/i);
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
await rm(cwd, { recursive: true, force: true });
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
it('fails fast when mission dir is missing', async () => {
|
|
107
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-missing-arg-'));
|
|
108
|
-
try {
|
|
109
|
-
const result = runOmx(cwd, ['autoresearch']);
|
|
110
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
111
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /mission-dir|Usage:\s*omx autoresearch <mission-dir>/i);
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
await rm(cwd, { recursive: true, force: true });
|
|
115
|
-
}
|
|
116
|
-
});
|
|
49
|
+
describe('parseAutoresearchArgs', () => {
|
|
117
50
|
it('treats top-level topic/evaluator flags as seeded deep-interview input', () => {
|
|
118
51
|
const parsed = parseAutoresearchArgs(['--topic', 'Improve docs', '--evaluator', 'node eval.js', '--slug', 'docs-run']);
|
|
119
52
|
assert.equal(parsed.guided, true);
|
|
@@ -129,7 +62,7 @@ describe('omx autoresearch', () => {
|
|
|
129
62
|
assert.equal(flagged.guided, true);
|
|
130
63
|
assert.deepEqual(flagged.initArgs, ['--topic', 'Ship feature']);
|
|
131
64
|
});
|
|
132
|
-
it('parses explicit run subcommand without breaking bare mission-dir
|
|
65
|
+
it('parses explicit run subcommand without breaking bare mission-dir parsing', () => {
|
|
133
66
|
const runParsed = parseAutoresearchArgs(['run', 'missions/demo', '--model', 'gpt-5']);
|
|
134
67
|
assert.equal(runParsed.runSubcommand, true);
|
|
135
68
|
assert.equal(runParsed.missionDir, 'missions/demo');
|
|
@@ -139,606 +72,84 @@ describe('omx autoresearch', () => {
|
|
|
139
72
|
assert.equal(bareParsed.missionDir, 'missions/demo');
|
|
140
73
|
assert.deepEqual(bareParsed.codexArgs, ['--model', 'gpt-5']);
|
|
141
74
|
});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
147
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
148
|
-
if [ "$1" = "exec" ]; then
|
|
149
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
150
|
-
head_commit=$(git rev-parse HEAD)
|
|
151
|
-
cat >"$candidate_file" <<'EOF'
|
|
152
|
-
{
|
|
153
|
-
"status": "abort",
|
|
154
|
-
"candidate_commit": null,
|
|
155
|
-
"base_commit": "HEAD_PLACEHOLDER",
|
|
156
|
-
"description": "stop after guided handoff",
|
|
157
|
-
"notes": ["fake codex exec"],
|
|
158
|
-
"created_at": "2026-03-18T00:00:00.000Z"
|
|
159
|
-
}
|
|
160
|
-
EOF
|
|
161
|
-
perl -0pi -e "s/HEAD_PLACEHOLDER/$head_commit/g" "$candidate_file"
|
|
162
|
-
exit 0
|
|
163
|
-
fi
|
|
164
|
-
mkdir -p "$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch"
|
|
165
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/deep-interview-autoresearch-test-launch.md" <<'EOF'
|
|
166
|
-
# Deep Interview Autoresearch Draft — test-launch
|
|
167
|
-
|
|
168
|
-
## Mission Draft
|
|
169
|
-
Investigate flaky onboarding behavior
|
|
170
|
-
|
|
171
|
-
## Evaluator Draft
|
|
172
|
-
node scripts/eval.js
|
|
173
|
-
|
|
174
|
-
## Keep Policy
|
|
175
|
-
score_improvement
|
|
176
|
-
|
|
177
|
-
## Session Slug
|
|
178
|
-
test-launch
|
|
179
|
-
|
|
180
|
-
## Seed Inputs
|
|
181
|
-
- topic: (none)
|
|
182
|
-
- evaluator: (none)
|
|
183
|
-
- keep_policy: (none)
|
|
184
|
-
- slug: (none)
|
|
185
|
-
|
|
186
|
-
## Launch Readiness
|
|
187
|
-
Launch-ready: yes
|
|
188
|
-
- Evaluator command is concrete and can be compiled into sandbox.md
|
|
189
|
-
|
|
190
|
-
## Confirmation Bridge
|
|
191
|
-
- refine further
|
|
192
|
-
- launch
|
|
193
|
-
EOF
|
|
194
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/mission.md" <<'EOF'
|
|
195
|
-
# Mission
|
|
196
|
-
|
|
197
|
-
Investigate flaky onboarding behavior
|
|
198
|
-
EOF
|
|
199
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/sandbox.md" <<'EOF'
|
|
200
|
-
---
|
|
201
|
-
evaluator:
|
|
202
|
-
command: node scripts/eval.js
|
|
203
|
-
format: json
|
|
204
|
-
keep_policy: score_improvement
|
|
205
|
-
---
|
|
206
|
-
EOF
|
|
207
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/result.json" <<'EOF'
|
|
208
|
-
{
|
|
209
|
-
"kind": "omx.autoresearch.deep-interview/v1",
|
|
210
|
-
"compileTarget": {
|
|
211
|
-
"topic": "Investigate flaky onboarding behavior",
|
|
212
|
-
"evaluatorCommand": "node scripts/eval.js",
|
|
213
|
-
"keepPolicy": "score_improvement",
|
|
214
|
-
"slug": "test-launch",
|
|
215
|
-
"repoRoot": "${repo}"
|
|
216
|
-
},
|
|
217
|
-
"draftArtifactPath": "${repo}/.omx/specs/deep-interview-autoresearch-test-launch.md",
|
|
218
|
-
"missionArtifactPath": "${repo}/.omx/specs/autoresearch-test-launch/mission.md",
|
|
219
|
-
"sandboxArtifactPath": "${repo}/.omx/specs/autoresearch-test-launch/sandbox.md",
|
|
220
|
-
"launchReady": true,
|
|
221
|
-
"blockedReasons": []
|
|
222
|
-
}
|
|
223
|
-
EOF
|
|
224
|
-
touch -t 202603180000 "$OMX_TEST_REPO_ROOT/.omx/specs/deep-interview-autoresearch-test-launch.md"
|
|
225
|
-
touch -t 202603180000 "$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/mission.md"
|
|
226
|
-
touch -t 202603180000 "$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/sandbox.md"
|
|
227
|
-
touch -t 202603180000 "$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/result.json"
|
|
228
|
-
`, 'utf-8');
|
|
229
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
230
|
-
await installFakePs(fakeBin);
|
|
231
|
-
const result = runOmx(repo, ['autoresearch', '--topic', 'Investigate flaky onboarding behavior', '--evaluator', 'node scripts/eval.js', '--slug', 'test-launch'], {
|
|
232
|
-
PATH: `${fakeBin}:${process.env.PATH || ''}`,
|
|
233
|
-
OMX_TEST_REPO_ROOT: repo,
|
|
234
|
-
});
|
|
235
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
236
|
-
const missionContent = await readFile(join(repo, 'missions', 'test-launch', 'mission.md'), 'utf-8');
|
|
237
|
-
const sandboxContent = await readFile(join(repo, 'missions', 'test-launch', 'sandbox.md'), 'utf-8');
|
|
238
|
-
assert.match(missionContent, /Investigate flaky onboarding behavior/);
|
|
239
|
-
assert.match(sandboxContent, /command: node scripts\/eval\.js/);
|
|
240
|
-
}
|
|
241
|
-
finally {
|
|
242
|
-
await rm(repo, { recursive: true, force: true });
|
|
243
|
-
await rm(fakeBin, { recursive: true, force: true });
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
it('launches interactive deep-interview intake, materializes mission files, and then prefers split-pane handoff', async () => {
|
|
247
|
-
const repo = await initRepo();
|
|
248
|
-
const fakeBin = await mkdtemp(join(tmpdir(), 'omx-autoresearch-deep-interview-bin-'));
|
|
75
|
+
});
|
|
76
|
+
describe('omx autoresearch hard deprecation', () => {
|
|
77
|
+
it('documents autoresearch as deprecated in top-level help', async () => {
|
|
78
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-help-'));
|
|
249
79
|
try {
|
|
250
|
-
const
|
|
251
|
-
const tmuxLog = join(repo, 'guided-tmux.log');
|
|
252
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
253
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
254
|
-
printf '%s\n' "$*" >>"${codexLog}"
|
|
255
|
-
if [ "$1" = "exec" ]; then
|
|
256
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
257
|
-
head_commit=$(git rev-parse HEAD)
|
|
258
|
-
cat >"$candidate_file" <<'EOF'
|
|
259
|
-
{
|
|
260
|
-
"status": "abort",
|
|
261
|
-
"candidate_commit": null,
|
|
262
|
-
"base_commit": "HEAD_PLACEHOLDER",
|
|
263
|
-
"description": "stop after guided handoff",
|
|
264
|
-
"notes": ["fake codex exec"],
|
|
265
|
-
"created_at": "2026-03-18T00:00:00.000Z"
|
|
266
|
-
}
|
|
267
|
-
EOF
|
|
268
|
-
perl -0pi -e "s/HEAD_PLACEHOLDER/$head_commit/g" "$candidate_file"
|
|
269
|
-
exit 0
|
|
270
|
-
fi
|
|
271
|
-
mkdir -p "$OMX_TEST_REPO_ROOT/.omx/specs/deep-int"
|
|
272
|
-
mkdir -p "$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch"
|
|
273
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/deep-interview-autoresearch-test-launch.md" <<'EOF'
|
|
274
|
-
# Deep Interview Autoresearch Draft — test-launch
|
|
275
|
-
|
|
276
|
-
## Mission Draft
|
|
277
|
-
Investigate flaky onboarding behavior
|
|
278
|
-
|
|
279
|
-
## Evaluator Draft
|
|
280
|
-
node scripts/eval.js
|
|
281
|
-
|
|
282
|
-
## Keep Policy
|
|
283
|
-
score_improvement
|
|
284
|
-
|
|
285
|
-
## Session Slug
|
|
286
|
-
test-launch
|
|
287
|
-
|
|
288
|
-
## Seed Inputs
|
|
289
|
-
- topic: (none)
|
|
290
|
-
- evaluator: (none)
|
|
291
|
-
- keep_policy: (none)
|
|
292
|
-
- slug: (none)
|
|
293
|
-
|
|
294
|
-
## Launch Readiness
|
|
295
|
-
Launch-ready: yes
|
|
296
|
-
- Evaluator command is concrete and can be compiled into sandbox.md
|
|
297
|
-
|
|
298
|
-
## Confirmation Bridge
|
|
299
|
-
- refine further
|
|
300
|
-
- launch
|
|
301
|
-
EOF
|
|
302
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/mission.md" <<'EOF'
|
|
303
|
-
# Mission
|
|
304
|
-
|
|
305
|
-
Investigate flaky onboarding behavior
|
|
306
|
-
EOF
|
|
307
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/sandbox.md" <<'EOF'
|
|
308
|
-
---
|
|
309
|
-
evaluator:
|
|
310
|
-
command: node scripts/eval.js
|
|
311
|
-
format: json
|
|
312
|
-
keep_policy: score_improvement
|
|
313
|
-
---
|
|
314
|
-
EOF
|
|
315
|
-
cat >"$OMX_TEST_REPO_ROOT/.omx/specs/autoresearch-test-launch/result.json" <<'EOF'
|
|
316
|
-
{
|
|
317
|
-
"kind": "omx.autoresearch.deep-interview/v1",
|
|
318
|
-
"compileTarget": {
|
|
319
|
-
"topic": "Investigate flaky onboarding behavior",
|
|
320
|
-
"evaluatorCommand": "node scripts/eval.js",
|
|
321
|
-
"keepPolicy": "score_improvement",
|
|
322
|
-
"slug": "test-launch",
|
|
323
|
-
"repoRoot": "${repo}"
|
|
324
|
-
},
|
|
325
|
-
"draftArtifactPath": "${repo}/.omx/specs/deep-interview-autoresearch-test-launch.md",
|
|
326
|
-
"missionArtifactPath": "${repo}/.omx/specs/autoresearch-test-launch/mission.md",
|
|
327
|
-
"sandboxArtifactPath": "${repo}/.omx/specs/autoresearch-test-launch/sandbox.md",
|
|
328
|
-
"launchReady": true,
|
|
329
|
-
"blockedReasons": []
|
|
330
|
-
}
|
|
331
|
-
EOF
|
|
332
|
-
`, 'utf-8');
|
|
333
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
334
|
-
await installFakePs(fakeBin);
|
|
335
|
-
const fakeTmuxPath = join(fakeBin, 'tmux');
|
|
336
|
-
await writeFile(fakeTmuxPath, `#!/bin/sh
|
|
337
|
-
printf '%s\n' "$*" >>"${tmuxLog}"
|
|
338
|
-
case "$1" in
|
|
339
|
-
-V)
|
|
340
|
-
printf 'tmux 3.4\n'
|
|
341
|
-
exit 0
|
|
342
|
-
;;
|
|
343
|
-
display-message)
|
|
344
|
-
case "$*" in
|
|
345
|
-
*"#{pane_id}"*) printf '%%42\n' ;;
|
|
346
|
-
*"#{pane_current_path}"*) printf '%s\n' "$OMX_TEST_REPO_ROOT" ;;
|
|
347
|
-
*"#S"*) printf 'devsession\n' ;;
|
|
348
|
-
*) printf 'devsession\n' ;;
|
|
349
|
-
esac
|
|
350
|
-
exit 0
|
|
351
|
-
;;
|
|
352
|
-
list-panes)
|
|
353
|
-
exit 0
|
|
354
|
-
;;
|
|
355
|
-
split-window)
|
|
356
|
-
last=""
|
|
357
|
-
for arg in "$@"; do
|
|
358
|
-
last="$arg"
|
|
359
|
-
done
|
|
360
|
-
printf '%%2\n'
|
|
361
|
-
if printf '%s' "$last" | grep -q 'autoresearch '; then
|
|
362
|
-
/bin/sh -lc "$last"
|
|
363
|
-
fi
|
|
364
|
-
exit 0
|
|
365
|
-
;;
|
|
366
|
-
attach-session|set-option|set-hook|kill-session|kill-pane)
|
|
367
|
-
exit 0
|
|
368
|
-
;;
|
|
369
|
-
*)
|
|
370
|
-
exit 0
|
|
371
|
-
;;
|
|
372
|
-
esac
|
|
373
|
-
`, 'utf-8');
|
|
374
|
-
execFileSync('chmod', ['+x', fakeTmuxPath], { stdio: 'ignore' });
|
|
375
|
-
const result = runOmx(repo, ['autoresearch', '--topic', 'Investigate flaky onboarding behavior', '--evaluator', 'node scripts/eval.js', '--slug', 'test-launch'], {
|
|
376
|
-
PATH: `${fakeBin}:${process.env.PATH || ''}`,
|
|
377
|
-
OMX_TEST_REPO_ROOT: repo,
|
|
378
|
-
TMUX: '/tmp/fake-tmux,12345,0',
|
|
379
|
-
TMUX_PANE: '%42',
|
|
380
|
-
});
|
|
80
|
+
const result = runOmx(cwd, ['--help']);
|
|
381
81
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
382
|
-
|
|
383
|
-
const tmuxOutput = await readFile(tmuxLog, 'utf-8');
|
|
384
|
-
assert.match(codexArgs, /\$deep-interview --autoresearch/);
|
|
385
|
-
assert.match(tmuxOutput, /split-window -h -t %42 -d -P -F #\{pane_id\} -c/);
|
|
386
|
-
const missionContent = await readFile(join(repo, 'missions', 'test-launch', 'mission.md'), 'utf-8');
|
|
387
|
-
const sandboxContent = await readFile(join(repo, 'missions', 'test-launch', 'sandbox.md'), 'utf-8');
|
|
388
|
-
assert.match(missionContent, /Investigate flaky onboarding behavior/);
|
|
389
|
-
assert.match(sandboxContent, /command: node scripts\/eval\.js/);
|
|
82
|
+
assert.match(result.stdout, /omx autoresearch\s+\[DEPRECATED\] Use \$autoresearch; direct CLI launch removed/i);
|
|
390
83
|
}
|
|
391
84
|
finally {
|
|
392
|
-
await rm(
|
|
393
|
-
await rm(fakeBin, { recursive: true, force: true });
|
|
85
|
+
await rm(cwd, { recursive: true, force: true });
|
|
394
86
|
}
|
|
395
87
|
});
|
|
396
|
-
it('
|
|
397
|
-
const
|
|
398
|
-
const fakeBin = await mkdtemp(join(tmpdir(), 'omx-autoresearch-run-split-bin-'));
|
|
88
|
+
it('routes autoresearch --help to local deprecation help', async () => {
|
|
89
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-local-help-'));
|
|
399
90
|
try {
|
|
400
|
-
const
|
|
401
|
-
const tmuxLog = join(repo, 'tmux.log');
|
|
402
|
-
await mkdir(missionDir, { recursive: true });
|
|
403
|
-
await mkdir(join(repo, 'scripts'), { recursive: true });
|
|
404
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\nSplit pane launch.\n', 'utf-8');
|
|
405
|
-
await writeFile(join(missionDir, 'sandbox.md'), '---\nevaluator:\n command: node scripts/eval.js\n format: json\n keep_policy: pass_only\n---\nStay inside the mission boundary.\n', 'utf-8');
|
|
406
|
-
await writeFile(join(repo, 'scripts', 'eval.js'), "process.stdout.write(JSON.stringify({ pass: true }));\n", 'utf-8');
|
|
407
|
-
execFileSync('git', ['add', '.'], { cwd: repo, stdio: 'ignore' });
|
|
408
|
-
execFileSync('git', ['commit', '-m', 'add autoresearch mission'], { cwd: repo, stdio: 'ignore' });
|
|
409
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
410
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
411
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
412
|
-
head_commit=$(git rev-parse HEAD)
|
|
413
|
-
cat >"$candidate_file" <<'EOF'
|
|
414
|
-
{
|
|
415
|
-
"status": "abort",
|
|
416
|
-
"candidate_commit": null,
|
|
417
|
-
"base_commit": "HEAD_PLACEHOLDER",
|
|
418
|
-
"description": "stop after split launch",
|
|
419
|
-
"notes": ["fake codex exec"],
|
|
420
|
-
"created_at": "2026-03-18T00:00:00.000Z"
|
|
421
|
-
}
|
|
422
|
-
EOF
|
|
423
|
-
perl -0pi -e "s/HEAD_PLACEHOLDER/$head_commit/g" "$candidate_file"
|
|
424
|
-
`, 'utf-8');
|
|
425
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
426
|
-
await installFakePs(fakeBin);
|
|
427
|
-
const fakeTmuxPath = join(fakeBin, 'tmux');
|
|
428
|
-
await writeFile(fakeTmuxPath, `#!/bin/sh
|
|
429
|
-
printf '%s\n' "$*" >>"${tmuxLog}"
|
|
430
|
-
case "$1" in
|
|
431
|
-
-V)
|
|
432
|
-
printf 'tmux 3.4\n'
|
|
433
|
-
exit 0
|
|
434
|
-
;;
|
|
435
|
-
display-message)
|
|
436
|
-
case "$*" in
|
|
437
|
-
*"#{pane_id}"*) printf '%%9\n' ;;
|
|
438
|
-
*"#{pane_current_path}"*) printf '${repo}\n' ;;
|
|
439
|
-
*"#S"*) printf 'devsess\n' ;;
|
|
440
|
-
*) printf '0\n' ;;
|
|
441
|
-
esac
|
|
442
|
-
exit 0
|
|
443
|
-
;;
|
|
444
|
-
list-panes)
|
|
445
|
-
printf '%%9\tzsh\tomx autoresearch\n'
|
|
446
|
-
exit 0
|
|
447
|
-
;;
|
|
448
|
-
split-window)
|
|
449
|
-
last=""
|
|
450
|
-
for arg in "$@"; do
|
|
451
|
-
last="$arg"
|
|
452
|
-
done
|
|
453
|
-
if printf '%s' "$last" | grep -q 'hud --watch'; then
|
|
454
|
-
printf '%%3\n'
|
|
455
|
-
exit 0
|
|
456
|
-
fi
|
|
457
|
-
printf '%%2\n'
|
|
458
|
-
/bin/sh -lc "$last"
|
|
459
|
-
exit 0
|
|
460
|
-
;;
|
|
461
|
-
set-option|select-pane)
|
|
462
|
-
exit 0
|
|
463
|
-
;;
|
|
464
|
-
*)
|
|
465
|
-
exit 0
|
|
466
|
-
;;
|
|
467
|
-
esac
|
|
468
|
-
`, 'utf-8');
|
|
469
|
-
execFileSync('chmod', ['+x', fakeTmuxPath], { stdio: 'ignore' });
|
|
470
|
-
const result = runOmx(repo, ['autoresearch', 'run', missionDir, '--model', 'gpt-5'], {
|
|
471
|
-
PATH: `${fakeBin}:${process.env.PATH || ''}`,
|
|
472
|
-
OMX_TEST_REPO_ROOT: repo,
|
|
473
|
-
TMUX: '/tmp/fake-tmux,12345,0',
|
|
474
|
-
TMUX_PANE: '%9',
|
|
475
|
-
});
|
|
91
|
+
const result = runOmx(cwd, ['autoresearch', '--help']);
|
|
476
92
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
477
|
-
|
|
478
|
-
assert.match(
|
|
479
|
-
assert.match(
|
|
480
|
-
assert.
|
|
93
|
+
assert.match(result.stdout, /hard-deprecated legacy command surface/i);
|
|
94
|
+
assert.match(result.stdout, /\$deep-interview --autoresearch/i);
|
|
95
|
+
assert.match(result.stdout, /\$autoresearch/i);
|
|
96
|
+
assert.match(result.stdout, /prompt-architect-artifact/i);
|
|
97
|
+
assert.doesNotMatch(result.stdout, /oh-my-codex \(omx\) - Multi-agent orchestration for Codex CLI/i);
|
|
481
98
|
}
|
|
482
99
|
finally {
|
|
483
|
-
await rm(
|
|
484
|
-
await rm(fakeBin, { recursive: true, force: true });
|
|
100
|
+
await rm(cwd, { recursive: true, force: true });
|
|
485
101
|
}
|
|
486
102
|
});
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
103
|
+
for (const argv of [
|
|
104
|
+
['autoresearch'],
|
|
105
|
+
['autoresearch', 'init'],
|
|
106
|
+
['autoresearch', 'run', 'missions/demo'],
|
|
107
|
+
['autoresearch', 'missions/demo'],
|
|
108
|
+
['autoresearch', '--resume', 'run-123'],
|
|
109
|
+
['autoresearch', '--topic', 'Flaky onboarding'],
|
|
110
|
+
]) {
|
|
111
|
+
it(`fails legacy invocation: omx ${argv.join(' ')}`, async () => {
|
|
112
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-fail-'));
|
|
113
|
+
try {
|
|
114
|
+
const result = runOmx(cwd, argv);
|
|
115
|
+
assert.notEqual(result.status, 0);
|
|
116
|
+
const output = `${result.stdout}\n${result.stderr}`;
|
|
117
|
+
assert.match(output, /hard-deprecated/i);
|
|
118
|
+
assert.match(output, /\$autoresearch/i);
|
|
119
|
+
assert.match(output, /Direct CLI launch, resume, run, bare mission-dir aliases, and tmux split-pane launch are no longer supported/i);
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
await rm(cwd, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
it('never invokes codex or tmux on the deprecated path', async () => {
|
|
127
|
+
const cwd = await initRepo();
|
|
128
|
+
const fakeBin = await mkdtemp(join(tmpdir(), 'omx-autoresearch-noexec-bin-'));
|
|
129
|
+
const codexLog = join(cwd, 'codex.log');
|
|
130
|
+
const tmuxLog = join(cwd, 'tmux.log');
|
|
490
131
|
try {
|
|
491
|
-
|
|
492
|
-
await
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
await writeFile(join(repo, 'scripts', 'eval.js'), "process.stdout.write(JSON.stringify({ pass: true }));\n", 'utf-8');
|
|
497
|
-
execFileSync('git', ['add', '.'], { cwd: repo, stdio: 'ignore' });
|
|
498
|
-
execFileSync('git', ['commit', '-m', 'add autoresearch mission'], { cwd: repo, stdio: 'ignore' });
|
|
499
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
500
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
501
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
502
|
-
head_commit=$(git rev-parse HEAD)
|
|
503
|
-
cat >"$candidate_file" <<'EOF'
|
|
504
|
-
{
|
|
505
|
-
"status": "abort",
|
|
506
|
-
"candidate_commit": null,
|
|
507
|
-
"base_commit": "HEAD_PLACEHOLDER",
|
|
508
|
-
"description": "stop after foreground fallback",
|
|
509
|
-
"notes": ["fake codex exec"],
|
|
510
|
-
"created_at": "2026-03-18T00:00:00.000Z"
|
|
511
|
-
}
|
|
512
|
-
EOF
|
|
513
|
-
perl -0pi -e "s/HEAD_PLACEHOLDER/$head_commit/g" "$candidate_file"
|
|
514
|
-
`, 'utf-8');
|
|
515
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
516
|
-
await installFakePs(fakeBin);
|
|
517
|
-
const fakeTmuxPath = join(fakeBin, 'tmux');
|
|
518
|
-
await writeFile(fakeTmuxPath, `#!/bin/sh
|
|
519
|
-
case "$1" in
|
|
520
|
-
-V)
|
|
521
|
-
printf 'tmux 3.4\n'
|
|
522
|
-
exit 0
|
|
523
|
-
;;
|
|
524
|
-
display-message)
|
|
525
|
-
case "$*" in
|
|
526
|
-
*"#{pane_id}"*) printf '%%9\n' ;;
|
|
527
|
-
*"#{pane_current_path}"*) printf '${repo}\n' ;;
|
|
528
|
-
*"#S"*) printf 'devsess\n' ;;
|
|
529
|
-
*) printf '0\n' ;;
|
|
530
|
-
esac
|
|
531
|
-
exit 0
|
|
532
|
-
;;
|
|
533
|
-
list-panes)
|
|
534
|
-
printf '%%9\tzsh\tomx autoresearch\n'
|
|
535
|
-
exit 0
|
|
536
|
-
;;
|
|
537
|
-
split-window)
|
|
538
|
-
exit 1
|
|
539
|
-
;;
|
|
540
|
-
set-option|select-pane)
|
|
541
|
-
exit 0
|
|
542
|
-
;;
|
|
543
|
-
*)
|
|
544
|
-
exit 0
|
|
545
|
-
;;
|
|
546
|
-
esac
|
|
547
|
-
`, 'utf-8');
|
|
548
|
-
execFileSync('chmod', ['+x', fakeTmuxPath], { stdio: 'ignore' });
|
|
549
|
-
const result = runOmx(repo, ['autoresearch', 'run', missionDir], {
|
|
132
|
+
await writeFile(join(fakeBin, 'codex'), `#!/bin/sh\necho codex >> ${JSON.stringify(codexLog)}\nexit 99\n`, 'utf-8');
|
|
133
|
+
await writeFile(join(fakeBin, 'tmux'), `#!/bin/sh\necho tmux >> ${JSON.stringify(tmuxLog)}\nexit 99\n`, 'utf-8');
|
|
134
|
+
execFileSync('chmod', ['+x', join(fakeBin, 'codex')], { stdio: 'ignore' });
|
|
135
|
+
execFileSync('chmod', ['+x', join(fakeBin, 'tmux')], { stdio: 'ignore' });
|
|
136
|
+
const result = runOmx(cwd, ['autoresearch', 'run', 'missions/demo'], {
|
|
550
137
|
PATH: `${fakeBin}:${process.env.PATH || ''}`,
|
|
551
|
-
OMX_TEST_REPO_ROOT: repo,
|
|
552
|
-
TMUX: '/tmp/fake-tmux,12345,0',
|
|
553
|
-
TMUX_PANE: '%9',
|
|
554
138
|
});
|
|
555
|
-
assert.
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
.filter(d => d.isDirectory())
|
|
559
|
-
.map(d => d.name);
|
|
560
|
-
assert.ok(runId);
|
|
561
|
-
}
|
|
562
|
-
finally {
|
|
563
|
-
await rm(repo, { recursive: true, force: true });
|
|
564
|
-
await rm(fakeBin, { recursive: true, force: true });
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
it('rejects mission directories outside a git repo', async () => {
|
|
568
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-autoresearch-outside-git-'));
|
|
569
|
-
try {
|
|
570
|
-
await writeFile(join(cwd, 'mission.md'), '# Mission\n', 'utf-8');
|
|
571
|
-
await writeFile(join(cwd, 'sandbox.md'), '---\nevaluator:\n command: node eval.js\n---\n', 'utf-8');
|
|
572
|
-
const result = runOmx(cwd, ['autoresearch', cwd]);
|
|
573
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
574
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /git repo|git repository|inside a git repo/i);
|
|
139
|
+
assert.notEqual(result.status, 0);
|
|
140
|
+
assert.equal(existsSync(codexLog), false);
|
|
141
|
+
assert.equal(existsSync(tmuxLog), false);
|
|
575
142
|
}
|
|
576
143
|
finally {
|
|
577
144
|
await rm(cwd, { recursive: true, force: true });
|
|
578
|
-
}
|
|
579
|
-
});
|
|
580
|
-
it('rejects missing mission.md inside an in-repo mission dir', async () => {
|
|
581
|
-
const repo = await initRepo();
|
|
582
|
-
try {
|
|
583
|
-
const missionDir = join(repo, 'missions', 'demo');
|
|
584
|
-
await mkdir(missionDir, { recursive: true });
|
|
585
|
-
await writeFile(join(missionDir, 'sandbox.md'), '---\nevaluator:\n command: node eval.js\n---\n', 'utf-8');
|
|
586
|
-
const result = runOmx(repo, ['autoresearch', missionDir]);
|
|
587
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
588
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /mission\.md/i);
|
|
589
|
-
}
|
|
590
|
-
finally {
|
|
591
|
-
await rm(repo, { recursive: true, force: true });
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
it('rejects missing sandbox.md inside an in-repo mission dir', async () => {
|
|
595
|
-
const repo = await initRepo();
|
|
596
|
-
try {
|
|
597
|
-
const missionDir = join(repo, 'missions', 'demo');
|
|
598
|
-
await mkdir(missionDir, { recursive: true });
|
|
599
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\n', 'utf-8');
|
|
600
|
-
const result = runOmx(repo, ['autoresearch', missionDir]);
|
|
601
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
602
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /sandbox\.md/i);
|
|
603
|
-
}
|
|
604
|
-
finally {
|
|
605
|
-
await rm(repo, { recursive: true, force: true });
|
|
606
|
-
}
|
|
607
|
-
});
|
|
608
|
-
it('rejects sandbox.md without evaluator frontmatter', async () => {
|
|
609
|
-
const repo = await initRepo();
|
|
610
|
-
try {
|
|
611
|
-
const missionDir = join(repo, 'missions', 'demo');
|
|
612
|
-
await mkdir(missionDir, { recursive: true });
|
|
613
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\n', 'utf-8');
|
|
614
|
-
await writeFile(join(missionDir, 'sandbox.md'), 'No frontmatter here.\n', 'utf-8');
|
|
615
|
-
const result = runOmx(repo, ['autoresearch', missionDir]);
|
|
616
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
617
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /frontmatter|evaluator/i);
|
|
618
|
-
}
|
|
619
|
-
finally {
|
|
620
|
-
await rm(repo, { recursive: true, force: true });
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
|
-
it('rejects autoresearch launch when root ralph mode is already active', async () => {
|
|
624
|
-
const repo = await initRepo();
|
|
625
|
-
try {
|
|
626
|
-
const missionDir = join(repo, 'missions', 'demo');
|
|
627
|
-
await mkdir(missionDir, { recursive: true });
|
|
628
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\n', 'utf-8');
|
|
629
|
-
await writeFile(join(missionDir, 'sandbox.md'), '---\nevaluator:\n command: node eval.js\n format: json\n---\nStay inside the mission boundary.\n', 'utf-8');
|
|
630
|
-
await mkdir(join(repo, '.omx', 'state'), { recursive: true });
|
|
631
|
-
await writeFile(join(repo, '.omx', 'state', 'ralph-state.json'), JSON.stringify({
|
|
632
|
-
active: true,
|
|
633
|
-
mode: 'ralph',
|
|
634
|
-
iteration: 0,
|
|
635
|
-
max_iterations: 50,
|
|
636
|
-
current_phase: 'executing',
|
|
637
|
-
task_description: 'existing root ralph lane',
|
|
638
|
-
started_at: '2026-03-14T00:00:00.000Z',
|
|
639
|
-
}, null, 2), 'utf-8');
|
|
640
|
-
const result = runOmx(repo, ['autoresearch', missionDir]);
|
|
641
|
-
assert.notEqual(result.status, 0, result.stderr || result.stdout);
|
|
642
|
-
assert.match(`${result.stderr}\n${result.stdout}`, /Cannot start autoresearch: ralph is already active/i);
|
|
643
|
-
const worktreesRoot = join(repo, '.omx', 'worktrees');
|
|
644
|
-
assert.equal(existsSync(worktreesRoot), false, 'expected launch to abort before creating autoresearch worktree');
|
|
645
|
-
}
|
|
646
|
-
finally {
|
|
647
|
-
await rm(repo, { recursive: true, force: true });
|
|
648
|
-
}
|
|
649
|
-
});
|
|
650
|
-
it('launches codex exec for autoresearch turns without shelling out to cat', async () => {
|
|
651
|
-
const repo = await initRepo();
|
|
652
|
-
const fakeBin = await mkdtemp(join(tmpdir(), 'omx-autoresearch-fake-bin-'));
|
|
653
|
-
try {
|
|
654
|
-
const missionDir = join(repo, 'missions', 'demo');
|
|
655
|
-
await mkdir(missionDir, { recursive: true });
|
|
656
|
-
await mkdir(join(repo, 'scripts'), { recursive: true });
|
|
657
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\nWrite a noop candidate artifact.\n', 'utf-8');
|
|
658
|
-
await writeFile(join(missionDir, 'sandbox.md'), '---\nevaluator:\n command: node scripts/eval.js\n format: json\n keep_policy: pass_only\n---\nStay inside the mission boundary.\n', 'utf-8');
|
|
659
|
-
await writeFile(join(repo, 'scripts', 'eval.js'), "process.stdout.write(JSON.stringify({ pass: true }));\n", 'utf-8');
|
|
660
|
-
execFileSync('git', ['add', '.'], { cwd: repo, stdio: 'ignore' });
|
|
661
|
-
execFileSync('git', ['commit', '-m', 'add autoresearch mission'], { cwd: repo, stdio: 'ignore' });
|
|
662
|
-
const fakeCatPath = join(fakeBin, 'cat');
|
|
663
|
-
await writeFile(fakeCatPath, `#!/bin/sh
|
|
664
|
-
printf 'unexpected cat invocation\\n' >&2
|
|
665
|
-
exit 97
|
|
666
|
-
`, 'utf-8');
|
|
667
|
-
execFileSync('chmod', ['+x', fakeCatPath], { stdio: 'ignore' });
|
|
668
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
669
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
670
|
-
printf 'fake-codex:%s\\n' "$*" >&2
|
|
671
|
-
while IFS= read -r _; do
|
|
672
|
-
:
|
|
673
|
-
done
|
|
674
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
675
|
-
head_commit=$(git rev-parse HEAD)
|
|
676
|
-
printf '{\\n "status": "abort",\\n "candidate_commit": null,\\n "base_commit": "%s",\\n "description": "stop after first exec",\\n "notes": ["fake codex exec"],\\n "created_at": "2026-03-15T00:00:00.000Z"\\n}\\n' "$head_commit" >"$candidate_file"
|
|
677
|
-
`, 'utf-8');
|
|
678
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
679
|
-
await installFakePs(fakeBin);
|
|
680
|
-
const result = runOmx(repo, ['autoresearch', missionDir, '--dangerously-bypass-approvals-and-sandbox'], { PATH: `${fakeBin}:${process.env.PATH || ''}`, OMX_TEST_REPO_ROOT: repo });
|
|
681
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
682
|
-
assert.match(result.stderr, /fake-codex:exec --dangerously-bypass-approvals-and-sandbox -/);
|
|
683
|
-
}
|
|
684
|
-
finally {
|
|
685
|
-
await rm(repo, { recursive: true, force: true });
|
|
686
145
|
await rm(fakeBin, { recursive: true, force: true });
|
|
687
146
|
}
|
|
688
147
|
});
|
|
689
|
-
it('
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
await mkdir(missionDir, { recursive: true });
|
|
695
|
-
await mkdir(join(repo, 'scripts'), { recursive: true });
|
|
696
|
-
await writeFile(join(missionDir, 'mission.md'), '# Mission\nKeep returning noop.\n', 'utf-8');
|
|
697
|
-
await writeFile(join(missionDir, 'sandbox.md'), '---\nevaluator:\n command: node scripts/eval.js\n format: json\n keep_policy: pass_only\n---\nStay inside the mission boundary.\n', 'utf-8');
|
|
698
|
-
await writeFile(join(repo, 'scripts', 'eval.js'), "process.stdout.write(JSON.stringify({ pass: true }));\n", 'utf-8');
|
|
699
|
-
execFileSync('git', ['add', '.'], { cwd: repo, stdio: 'ignore' });
|
|
700
|
-
execFileSync('git', ['commit', '-m', 'add autoresearch noop mission'], { cwd: repo, stdio: 'ignore' });
|
|
701
|
-
const fakeCodexPath = join(fakeBin, 'codex');
|
|
702
|
-
await writeFile(fakeCodexPath, `#!/bin/sh
|
|
703
|
-
cat >/dev/null
|
|
704
|
-
candidate_file=$(find "$OMX_TEST_REPO_ROOT/.omx/logs/autoresearch" -name candidate.json | head -n 1)
|
|
705
|
-
head_commit=$(git rev-parse HEAD)
|
|
706
|
-
cat >"$candidate_file" <<EOF
|
|
707
|
-
{
|
|
708
|
-
"status": "noop",
|
|
709
|
-
"candidate_commit": null,
|
|
710
|
-
"base_commit": "$head_commit",
|
|
711
|
-
"description": "noop from fake codex exec",
|
|
712
|
-
"notes": ["fake noop"],
|
|
713
|
-
"created_at": "2026-03-15T00:00:00.000Z"
|
|
714
|
-
}
|
|
715
|
-
EOF
|
|
716
|
-
`, 'utf-8');
|
|
717
|
-
execFileSync('chmod', ['+x', fakeCodexPath], { stdio: 'ignore' });
|
|
718
|
-
await installFakePs(fakeBin);
|
|
719
|
-
const result = runOmx(repo, ['autoresearch', missionDir, '--dangerously-bypass-approvals-and-sandbox'], { PATH: `${fakeBin}:${process.env.PATH || ''}`, OMX_TEST_REPO_ROOT: repo });
|
|
720
|
-
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
721
|
-
const state = JSON.parse(await readFile(join(repo, '.omx', 'state', 'autoresearch-state.json'), 'utf-8'));
|
|
722
|
-
assert.equal(state.active, false);
|
|
723
|
-
const logsRoot = join(repo, '.omx', 'logs', 'autoresearch');
|
|
724
|
-
const [runId] = readdirSync(logsRoot, { withFileTypes: true })
|
|
725
|
-
.filter(d => d.isDirectory())
|
|
726
|
-
.map(d => d.name);
|
|
727
|
-
assert.ok(runId);
|
|
728
|
-
const manifest = JSON.parse(await readFile(join(logsRoot, runId, 'manifest.json'), 'utf-8'));
|
|
729
|
-
assert.equal(manifest.status, 'stopped');
|
|
730
|
-
assert.equal(manifest.stop_reason, 'repeated noop limit reached (3)');
|
|
731
|
-
assert.match(manifest.completed_at || '', /^\d{4}-\d{2}-\d{2}T/);
|
|
732
|
-
const ledger = JSON.parse(await readFile(join(logsRoot, runId, 'iteration-ledger.json'), 'utf-8'));
|
|
733
|
-
assert.deepEqual(ledger.entries.map((entry) => entry.decision), ['baseline', 'noop', 'noop', 'noop']);
|
|
734
|
-
const resumeResult = runOmx(repo, ['autoresearch', '--resume', runId]);
|
|
735
|
-
assert.notEqual(resumeResult.status, 0, resumeResult.stderr || resumeResult.stdout);
|
|
736
|
-
assert.match(`${resumeResult.stderr}\n${resumeResult.stdout}`, /autoresearch_resume_terminal_run/i);
|
|
737
|
-
}
|
|
738
|
-
finally {
|
|
739
|
-
await rm(repo, { recursive: true, force: true });
|
|
740
|
-
await rm(fakeBin, { recursive: true, force: true });
|
|
741
|
-
}
|
|
148
|
+
it('throws the same deprecation guidance from the command entrypoint', async () => {
|
|
149
|
+
await assert.rejects(async () => autoresearchCommand(['run', 'missions/demo']), (error) => {
|
|
150
|
+
assert.match(String(error), new RegExp(AUTORESEARCH_DEPRECATION_MESSAGE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
151
|
+
return true;
|
|
152
|
+
});
|
|
742
153
|
});
|
|
743
154
|
});
|
|
744
155
|
//# sourceMappingURL=autoresearch.test.js.map
|