oh-my-codex 0.18.11 → 0.18.13
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 +9 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +668 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.d.ts +10 -0
- package/dist/autopilot/completion-gate.d.ts.map +1 -0
- package/dist/autopilot/completion-gate.js +154 -0
- package/dist/autopilot/completion-gate.js.map +1 -0
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +42 -21
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +46 -3
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +35 -0
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +317 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +120 -2
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +217 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +101 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +3 -2
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js +64 -2
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +289 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +290 -17
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +74 -0
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +45 -0
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +93 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +157 -3
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/version-sync-contract.test.js +2 -0
- package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +90 -12
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +13 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +439 -46
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.d.ts +6 -0
- package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -0
- package/dist/cli/project-runtime-codex-homes.js +27 -0
- package/dist/cli/project-runtime-codex-homes.js.map +1 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +8 -1
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -2
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +482 -126
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +79 -8
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/update.d.ts +1 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +42 -10
- package/dist/cli/update.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +73 -29
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +14 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +54 -51
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1 -1
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/best-practice-research-skill.test.js +12 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -1
- package/dist/hud/__tests__/authority.test.js +45 -12
- package/dist/hud/__tests__/authority.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +95 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +6 -6
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +2 -2
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/authority.d.ts.map +1 -1
- package/dist/hud/authority.js +17 -2
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/index.js +1 -4
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +42 -0
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +6 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +5 -4
- package/dist/hud/tmux.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +31 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +1 -0
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +32 -0
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/modes/__tests__/base-autopilot-gates.test.d.ts +2 -0
- package/dist/modes/__tests__/base-autopilot-gates.test.d.ts.map +1 -0
- package/dist/modes/__tests__/base-autopilot-gates.test.js +154 -0
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -0
- package/dist/modes/base.d.ts +4 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +71 -1
- package/dist/modes/base.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +144 -3
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +109 -0
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +11 -4
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/code-review.d.ts +2 -0
- package/dist/pipeline/stages/code-review.d.ts.map +1 -1
- package/dist/pipeline/stages/code-review.js +2 -0
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.d.ts +3 -0
- package/dist/pipeline/stages/ultraqa.d.ts.map +1 -1
- package/dist/pipeline/stages/ultraqa.js +3 -0
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.d.ts +2 -0
- package/dist/ralplan/__tests__/consensus-gate.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/consensus-gate.test.js +631 -0
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -0
- package/dist/ralplan/consensus-gate.d.ts +9 -1
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +287 -65
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +481 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +145 -25
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts +1 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +130 -0
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/session-history/__tests__/search.test.js +166 -0
- package/dist/session-history/__tests__/search.test.js.map +1 -1
- package/dist/session-history/search.d.ts +7 -0
- package/dist/session-history/search.d.ts.map +1 -1
- package/dist/session-history/search.js +83 -24
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/collector.test.js +60 -0
- package/dist/sidecar/__tests__/collector.test.js.map +1 -1
- package/dist/sidecar/collector.d.ts.map +1 -1
- package/dist/sidecar/collector.js +3 -6
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +622 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +82 -0
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +31 -9
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +41 -1
- package/dist/state/skill-active.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +81 -57
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/runtime.js +4 -4
- package/dist/team/runtime.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/__tests__/version.test.js +27 -0
- package/dist/utils/__tests__/version.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/version.d.ts.map +1 -1
- package/dist/utils/version.js +7 -2
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +4 -2
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +71 -3
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +53 -2
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +6 -1
- package/skills/best-practice-research/SKILL.md +6 -1
- package/src/scripts/__tests__/codex-native-hook.test.ts +615 -0
- package/src/scripts/codex-native-hook.ts +162 -32
- package/src/scripts/codex-native-pre-post.ts +137 -0
|
@@ -587,6 +587,68 @@ describe('state operations directory initialization', () => {
|
|
|
587
587
|
await rm(wd, { recursive: true, force: true });
|
|
588
588
|
}
|
|
589
589
|
});
|
|
590
|
+
it('does not list a mode active when terminal canonical visibility contradicts an active detail state', async () => {
|
|
591
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-terminal-canonical-wins-'));
|
|
592
|
+
try {
|
|
593
|
+
const sessionId = 'sess-terminal-visible';
|
|
594
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
595
|
+
await mkdir(sessionDir, { recursive: true });
|
|
596
|
+
await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
597
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
598
|
+
active: true,
|
|
599
|
+
current_phase: 'deep-interview',
|
|
600
|
+
}, null, 2));
|
|
601
|
+
await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify({
|
|
602
|
+
version: 1,
|
|
603
|
+
active: false,
|
|
604
|
+
skill: 'autopilot',
|
|
605
|
+
phase: 'complete',
|
|
606
|
+
completed_at: '2026-06-09T00:00:00.000Z',
|
|
607
|
+
session_id: sessionId,
|
|
608
|
+
active_skills: [{ skill: 'autopilot', phase: 'deep-interview', active: true, session_id: sessionId }],
|
|
609
|
+
}, null, 2));
|
|
610
|
+
const response = await executeStateOperation('state_list_active', {
|
|
611
|
+
workingDirectory: wd,
|
|
612
|
+
session_id: sessionId,
|
|
613
|
+
});
|
|
614
|
+
assert.deepEqual(response.payload, { active_modes: [] });
|
|
615
|
+
const detailState = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
616
|
+
assert.equal(detailState.active, true);
|
|
617
|
+
assert.equal(detailState.current_phase, 'deep-interview');
|
|
618
|
+
}
|
|
619
|
+
finally {
|
|
620
|
+
await rm(wd, { recursive: true, force: true });
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
it('uses the implicit current session canonical state when filtering list-active', async () => {
|
|
624
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-terminal-canonical-implicit-'));
|
|
625
|
+
try {
|
|
626
|
+
const sessionId = 'sess-terminal-implicit';
|
|
627
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
628
|
+
await mkdir(sessionDir, { recursive: true });
|
|
629
|
+
await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
630
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
631
|
+
active: true,
|
|
632
|
+
current_phase: 'deep-interview',
|
|
633
|
+
}, null, 2));
|
|
634
|
+
await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify({
|
|
635
|
+
version: 1,
|
|
636
|
+
active: false,
|
|
637
|
+
skill: 'autopilot',
|
|
638
|
+
phase: 'complete',
|
|
639
|
+
completed_at: '2026-06-09T00:00:00.000Z',
|
|
640
|
+
session_id: sessionId,
|
|
641
|
+
active_skills: [{ skill: 'autopilot', phase: 'deep-interview', active: true, session_id: sessionId }],
|
|
642
|
+
}, null, 2));
|
|
643
|
+
const response = await executeStateOperation('state_list_active', {
|
|
644
|
+
workingDirectory: wd,
|
|
645
|
+
});
|
|
646
|
+
assert.deepEqual(response.payload, { active_modes: [] });
|
|
647
|
+
}
|
|
648
|
+
finally {
|
|
649
|
+
await rm(wd, { recursive: true, force: true });
|
|
650
|
+
}
|
|
651
|
+
});
|
|
590
652
|
it('syncs canonical skill-active state for tracked mode writes and clears', async () => {
|
|
591
653
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-canonical-'));
|
|
592
654
|
try {
|
|
@@ -1881,6 +1943,54 @@ describe('state operations directory initialization', () => {
|
|
|
1881
1943
|
await rm(wd, { recursive: true, force: true });
|
|
1882
1944
|
}
|
|
1883
1945
|
});
|
|
1946
|
+
for (const { lane, architectVerdict, criticVerdict } of [
|
|
1947
|
+
{ lane: 'architect', architectVerdict: 'iterate', criticVerdict: 'approve' },
|
|
1948
|
+
{ lane: 'critic', architectVerdict: 'approve', criticVerdict: 'iterate' },
|
|
1949
|
+
]) {
|
|
1950
|
+
it(`denies Autopilot ralplan to ultragoal self-write when ${lane} verdict is iterate despite complete consensus flag`, async () => {
|
|
1951
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-ralplan-${lane}-iterate-deny-`));
|
|
1952
|
+
try {
|
|
1953
|
+
await withOmxRootEnv(wd, async () => {
|
|
1954
|
+
const sessionId = `sess-autopilot-ralplan-${lane}-iterate-deny`;
|
|
1955
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
1956
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1957
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1958
|
+
const consensusGate = ralplanConsensusGate(sessionId, 'native_subagent');
|
|
1959
|
+
consensusGate.ralplan_architect_review.verdict = architectVerdict;
|
|
1960
|
+
consensusGate.ralplan_critic_review.verdict = criticVerdict;
|
|
1961
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
1962
|
+
active: true,
|
|
1963
|
+
mode: 'autopilot',
|
|
1964
|
+
current_phase: 'ralplan',
|
|
1965
|
+
state: {
|
|
1966
|
+
handoff_artifacts: {
|
|
1967
|
+
ralplan: {
|
|
1968
|
+
plan_path: '.omx/plans/prd.md',
|
|
1969
|
+
test_spec_path: '.omx/plans/test-spec.md',
|
|
1970
|
+
},
|
|
1971
|
+
ralplan_consensus_gate: consensusGate,
|
|
1972
|
+
},
|
|
1973
|
+
},
|
|
1974
|
+
}, null, 2));
|
|
1975
|
+
const response = await executeStateOperation('state_write', {
|
|
1976
|
+
workingDirectory: wd,
|
|
1977
|
+
session_id: sessionId,
|
|
1978
|
+
mode: 'autopilot',
|
|
1979
|
+
active: true,
|
|
1980
|
+
current_phase: 'ultragoal',
|
|
1981
|
+
});
|
|
1982
|
+
assert.equal(response.isError, true);
|
|
1983
|
+
const error = String(response.payload.error || '');
|
|
1984
|
+
assert.match(error, new RegExp(`${lane}.*verdict=iterate`, 'i'));
|
|
1985
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
1986
|
+
assert.equal(state.current_phase, 'ralplan');
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
finally {
|
|
1990
|
+
await rm(wd, { recursive: true, force: true });
|
|
1991
|
+
}
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1884
1994
|
it('explains when native ralplan reviews are not present in subagent tracking', async () => {
|
|
1885
1995
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-native-missing-tracker-'));
|
|
1886
1996
|
try {
|
|
@@ -1989,6 +2099,518 @@ describe('state operations directory initialization', () => {
|
|
|
1989
2099
|
await rm(wd, { recursive: true, force: true });
|
|
1990
2100
|
}
|
|
1991
2101
|
});
|
|
2102
|
+
it('denies Autopilot implementation-phase completion before the code-review gate', async () => {
|
|
2103
|
+
for (const phase of ['ultragoal', 'team', 'ralph']) {
|
|
2104
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-${phase}-complete-deny-`));
|
|
2105
|
+
try {
|
|
2106
|
+
await withOmxRootEnv(wd, async () => {
|
|
2107
|
+
const sessionId = `sess-autopilot-${phase}-complete-deny`;
|
|
2108
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2109
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2110
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2111
|
+
active: true,
|
|
2112
|
+
mode: 'autopilot',
|
|
2113
|
+
current_phase: phase,
|
|
2114
|
+
state: { handoff_artifacts: { ultragoal: { verification: 'passed' } } },
|
|
2115
|
+
}, null, 2));
|
|
2116
|
+
const response = await executeStateOperation('state_write', {
|
|
2117
|
+
workingDirectory: wd,
|
|
2118
|
+
session_id: sessionId,
|
|
2119
|
+
mode: 'autopilot',
|
|
2120
|
+
active: false,
|
|
2121
|
+
current_phase: 'complete',
|
|
2122
|
+
state: {
|
|
2123
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2124
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/1' },
|
|
2125
|
+
},
|
|
2126
|
+
});
|
|
2127
|
+
assert.equal(response.isError, true);
|
|
2128
|
+
assert.match(String(response.payload.error || ''), /Cannot complete Autopilot before code-review gate/i);
|
|
2129
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2130
|
+
assert.equal(state.active, true);
|
|
2131
|
+
assert.equal(state.current_phase, phase);
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
finally {
|
|
2135
|
+
await rm(wd, { recursive: true, force: true });
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
});
|
|
2139
|
+
it('denies Autopilot implementation-phase skip directly to ultraqa', async () => {
|
|
2140
|
+
for (const phase of ['ultragoal', 'team', 'ralph']) {
|
|
2141
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-${phase}-ultraqa-skip-deny-`));
|
|
2142
|
+
try {
|
|
2143
|
+
await withOmxRootEnv(wd, async () => {
|
|
2144
|
+
const sessionId = `sess-autopilot-${phase}-ultraqa-skip-deny`;
|
|
2145
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2146
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2147
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2148
|
+
active: true,
|
|
2149
|
+
mode: 'autopilot',
|
|
2150
|
+
current_phase: phase,
|
|
2151
|
+
state: { handoff_artifacts: { ultragoal: { verification: 'passed' } } },
|
|
2152
|
+
}, null, 2));
|
|
2153
|
+
const response = await executeStateOperation('state_write', {
|
|
2154
|
+
workingDirectory: wd,
|
|
2155
|
+
session_id: sessionId,
|
|
2156
|
+
mode: 'autopilot',
|
|
2157
|
+
active: true,
|
|
2158
|
+
current_phase: 'ultraqa',
|
|
2159
|
+
});
|
|
2160
|
+
assert.equal(response.isError, true);
|
|
2161
|
+
assert.match(String(response.payload.error || ''), /Cannot skip Autopilot code-review gate/i);
|
|
2162
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2163
|
+
assert.equal(state.active, true);
|
|
2164
|
+
assert.equal(state.current_phase, phase);
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
finally {
|
|
2168
|
+
await rm(wd, { recursive: true, force: true });
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
it('denies Autopilot code-review completion before the ultraqa gate', async () => {
|
|
2173
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-code-review-complete-deny-'));
|
|
2174
|
+
try {
|
|
2175
|
+
await withOmxRootEnv(wd, async () => {
|
|
2176
|
+
const sessionId = 'sess-autopilot-code-review-complete-deny';
|
|
2177
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2178
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2179
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2180
|
+
active: true,
|
|
2181
|
+
mode: 'autopilot',
|
|
2182
|
+
current_phase: 'code-review',
|
|
2183
|
+
state: {
|
|
2184
|
+
handoff_artifacts: { code_review: { source: 'native-subagent' } },
|
|
2185
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2186
|
+
},
|
|
2187
|
+
}, null, 2));
|
|
2188
|
+
const response = await executeStateOperation('state_write', {
|
|
2189
|
+
workingDirectory: wd,
|
|
2190
|
+
session_id: sessionId,
|
|
2191
|
+
mode: 'autopilot',
|
|
2192
|
+
active: false,
|
|
2193
|
+
current_phase: 'complete',
|
|
2194
|
+
state: {
|
|
2195
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2196
|
+
qa_verdict: { clean: true, skipped: false },
|
|
2197
|
+
},
|
|
2198
|
+
});
|
|
2199
|
+
assert.equal(response.isError, true);
|
|
2200
|
+
assert.match(String(response.payload.error || ''), /Cannot complete Autopilot before ultraqa gate/i);
|
|
2201
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2202
|
+
assert.equal(state.active, true);
|
|
2203
|
+
assert.equal(state.current_phase, 'code-review');
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
finally {
|
|
2207
|
+
await rm(wd, { recursive: true, force: true });
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
2210
|
+
it('denies Autopilot ultraqa completion without clean review and QA evidence', async () => {
|
|
2211
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ultraqa-complete-evidence-deny-'));
|
|
2212
|
+
try {
|
|
2213
|
+
await withOmxRootEnv(wd, async () => {
|
|
2214
|
+
const sessionId = 'sess-autopilot-ultraqa-complete-evidence-deny';
|
|
2215
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2216
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2217
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2218
|
+
active: true,
|
|
2219
|
+
mode: 'autopilot',
|
|
2220
|
+
current_phase: 'ultraqa',
|
|
2221
|
+
state: {
|
|
2222
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2223
|
+
qa_verdict: null,
|
|
2224
|
+
},
|
|
2225
|
+
}, null, 2));
|
|
2226
|
+
const response = await executeStateOperation('state_write', {
|
|
2227
|
+
workingDirectory: wd,
|
|
2228
|
+
session_id: sessionId,
|
|
2229
|
+
mode: 'autopilot',
|
|
2230
|
+
active: false,
|
|
2231
|
+
current_phase: 'complete',
|
|
2232
|
+
state: {
|
|
2233
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2234
|
+
},
|
|
2235
|
+
});
|
|
2236
|
+
assert.equal(response.isError, true);
|
|
2237
|
+
assert.match(String(response.payload.error || ''), /without clean code-review and ultraqa verdict evidence/i);
|
|
2238
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2239
|
+
assert.equal(state.active, true);
|
|
2240
|
+
assert.equal(state.current_phase, 'ultraqa');
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
finally {
|
|
2244
|
+
await rm(wd, { recursive: true, force: true });
|
|
2245
|
+
}
|
|
2246
|
+
});
|
|
2247
|
+
it('denies Autopilot implementation and code-review terminalization via inactive ultraqa phase', async () => {
|
|
2248
|
+
for (const phase of ['ultragoal', 'team', 'ralph', 'code-review']) {
|
|
2249
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-${phase}-inactive-ultraqa-deny-`));
|
|
2250
|
+
try {
|
|
2251
|
+
await withOmxRootEnv(wd, async () => {
|
|
2252
|
+
const sessionId = `sess-autopilot-${phase}-inactive-ultraqa-deny`;
|
|
2253
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2254
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2255
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({ active: true, mode: 'autopilot', current_phase: phase }, null, 2));
|
|
2256
|
+
const response = await executeStateOperation('state_write', {
|
|
2257
|
+
workingDirectory: wd,
|
|
2258
|
+
session_id: sessionId,
|
|
2259
|
+
mode: 'autopilot',
|
|
2260
|
+
active: false,
|
|
2261
|
+
current_phase: 'ultraqa',
|
|
2262
|
+
state: {
|
|
2263
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2264
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/3' },
|
|
2265
|
+
},
|
|
2266
|
+
});
|
|
2267
|
+
assert.equal(response.isError, true);
|
|
2268
|
+
assert.match(String(response.payload.error || ''), /Cannot (complete|skip) Autopilot/i);
|
|
2269
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2270
|
+
assert.equal(state.active, true);
|
|
2271
|
+
assert.equal(state.current_phase, phase);
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
finally {
|
|
2275
|
+
await rm(wd, { recursive: true, force: true });
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
it('denies Autopilot ultraqa completion when review and QA provenance are swapped', async () => {
|
|
2280
|
+
const cases = [
|
|
2281
|
+
{
|
|
2282
|
+
name: 'swapped-stage',
|
|
2283
|
+
review_verdict: { stage: 'ultraqa', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.ultraqa.artifacts.qa_verdict' },
|
|
2284
|
+
qa_verdict: { stage: 'code-review', clean: true, skipped: false, artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.code-review.artifacts.review_verdict' },
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
name: 'swapped-artifact-path',
|
|
2288
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.ultraqa.artifacts.qa_verdict' },
|
|
2289
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.code-review.artifacts.review_verdict' },
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
name: 'review-uses-ultraqa-provenance',
|
|
2293
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/ultraqa/qa-verdict.json' },
|
|
2294
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, artifact_path: '.omx/qa/qa-verdict.json' },
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
name: 'qa-uses-code-review-provenance',
|
|
2298
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2299
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, artifact_path: '.omx/reviews/code-review.json' },
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
name: 'shared-neutral-provenance',
|
|
2303
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/evidence/shared.json' },
|
|
2304
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, artifact_path: '.omx/evidence/shared.json' },
|
|
2305
|
+
},
|
|
2306
|
+
];
|
|
2307
|
+
for (const testCase of cases) {
|
|
2308
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-ultraqa-${testCase.name}-deny-`));
|
|
2309
|
+
try {
|
|
2310
|
+
await withOmxRootEnv(wd, async () => {
|
|
2311
|
+
const sessionId = `sess-autopilot-ultraqa-${testCase.name}-deny`;
|
|
2312
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2313
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2314
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'ultraqa' }, null, 2));
|
|
2315
|
+
const response = await executeStateOperation('state_write', {
|
|
2316
|
+
workingDirectory: wd,
|
|
2317
|
+
session_id: sessionId,
|
|
2318
|
+
mode: 'autopilot',
|
|
2319
|
+
active: false,
|
|
2320
|
+
current_phase: 'complete',
|
|
2321
|
+
state: {
|
|
2322
|
+
review_verdict: testCase.review_verdict,
|
|
2323
|
+
qa_verdict: testCase.qa_verdict,
|
|
2324
|
+
},
|
|
2325
|
+
});
|
|
2326
|
+
assert.equal(response.isError, true);
|
|
2327
|
+
assert.match(String(response.payload.error || ''), /without clean code-review and ultraqa verdict evidence/i);
|
|
2328
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2329
|
+
assert.equal(state.active, true);
|
|
2330
|
+
assert.equal(state.current_phase, 'ultraqa');
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
finally {
|
|
2334
|
+
await rm(wd, { recursive: true, force: true });
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
});
|
|
2338
|
+
it('denies Autopilot ultraqa completion with self-attested clean verdicts but no durable provenance', async () => {
|
|
2339
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ultraqa-self-attested-deny-'));
|
|
2340
|
+
try {
|
|
2341
|
+
await withOmxRootEnv(wd, async () => {
|
|
2342
|
+
const sessionId = 'sess-autopilot-ultraqa-self-attested-deny';
|
|
2343
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2344
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2345
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2346
|
+
active: true,
|
|
2347
|
+
mode: 'autopilot',
|
|
2348
|
+
current_phase: 'ultraqa',
|
|
2349
|
+
state: {
|
|
2350
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2351
|
+
qa_verdict: { clean: true, skipped: false },
|
|
2352
|
+
},
|
|
2353
|
+
}, null, 2));
|
|
2354
|
+
const response = await executeStateOperation('state_write', {
|
|
2355
|
+
workingDirectory: wd,
|
|
2356
|
+
session_id: sessionId,
|
|
2357
|
+
mode: 'autopilot',
|
|
2358
|
+
active: false,
|
|
2359
|
+
current_phase: 'complete',
|
|
2360
|
+
state: {
|
|
2361
|
+
review_verdict: { recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true },
|
|
2362
|
+
qa_verdict: { clean: true, skipped: false },
|
|
2363
|
+
},
|
|
2364
|
+
});
|
|
2365
|
+
assert.equal(response.isError, true);
|
|
2366
|
+
assert.match(String(response.payload.error || ''), /without clean code-review and ultraqa verdict evidence/i);
|
|
2367
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2368
|
+
assert.equal(state.active, true);
|
|
2369
|
+
assert.equal(state.current_phase, 'ultraqa');
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
finally {
|
|
2373
|
+
await rm(wd, { recursive: true, force: true });
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
it('denies Autopilot ultraqa skipped completion without durable QA provenance', async () => {
|
|
2377
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ultraqa-skipped-no-provenance-deny-'));
|
|
2378
|
+
try {
|
|
2379
|
+
await withOmxRootEnv(wd, async () => {
|
|
2380
|
+
const sessionId = 'sess-autopilot-ultraqa-skipped-no-provenance-deny';
|
|
2381
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2382
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2383
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'ultraqa' }, null, 2));
|
|
2384
|
+
const response = await executeStateOperation('state_write', {
|
|
2385
|
+
workingDirectory: wd,
|
|
2386
|
+
session_id: sessionId,
|
|
2387
|
+
mode: 'autopilot',
|
|
2388
|
+
active: false,
|
|
2389
|
+
current_phase: 'complete',
|
|
2390
|
+
state: {
|
|
2391
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2392
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: true, reason: 'Docs-only change; QA not applicable.' },
|
|
2393
|
+
},
|
|
2394
|
+
});
|
|
2395
|
+
assert.equal(response.isError, true);
|
|
2396
|
+
assert.match(String(response.payload.error || ''), /without clean code-review and ultraqa verdict evidence/i);
|
|
2397
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2398
|
+
assert.equal(state.active, true);
|
|
2399
|
+
assert.equal(state.current_phase, 'ultraqa');
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
finally {
|
|
2403
|
+
await rm(wd, { recursive: true, force: true });
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2406
|
+
it('denies Autopilot completion from an unknown active phase', async () => {
|
|
2407
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-unknown-phase-complete-deny-'));
|
|
2408
|
+
try {
|
|
2409
|
+
await withOmxRootEnv(wd, async () => {
|
|
2410
|
+
const sessionId = 'sess-autopilot-unknown-phase-complete-deny';
|
|
2411
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2412
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2413
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2414
|
+
active: true,
|
|
2415
|
+
mode: 'autopilot',
|
|
2416
|
+
current_phase: 'bogus',
|
|
2417
|
+
}, null, 2));
|
|
2418
|
+
const response = await executeStateOperation('state_write', {
|
|
2419
|
+
workingDirectory: wd,
|
|
2420
|
+
session_id: sessionId,
|
|
2421
|
+
mode: 'autopilot',
|
|
2422
|
+
active: false,
|
|
2423
|
+
current_phase: 'complete',
|
|
2424
|
+
completed_at: '2026-06-09T14:40:00.000Z',
|
|
2425
|
+
state: {
|
|
2426
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2427
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/5' },
|
|
2428
|
+
},
|
|
2429
|
+
});
|
|
2430
|
+
assert.equal(response.isError, true);
|
|
2431
|
+
assert.match(String(response.payload.error || ''), /unknown active phase/i);
|
|
2432
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2433
|
+
assert.equal(state.active, true);
|
|
2434
|
+
assert.equal(state.current_phase, 'bogus');
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
finally {
|
|
2438
|
+
await rm(wd, { recursive: true, force: true });
|
|
2439
|
+
}
|
|
2440
|
+
});
|
|
2441
|
+
it('denies Autopilot completion from an unknown active phase when persisted state omits mode', async () => {
|
|
2442
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-unknown-phase-no-mode-complete-deny-'));
|
|
2443
|
+
try {
|
|
2444
|
+
await withOmxRootEnv(wd, async () => {
|
|
2445
|
+
const sessionId = 'sess-autopilot-unknown-phase-no-mode-complete-deny';
|
|
2446
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2447
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2448
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2449
|
+
active: true,
|
|
2450
|
+
current_phase: 'bogus',
|
|
2451
|
+
}, null, 2));
|
|
2452
|
+
const response = await executeStateOperation('state_write', {
|
|
2453
|
+
workingDirectory: wd,
|
|
2454
|
+
session_id: sessionId,
|
|
2455
|
+
mode: 'autopilot',
|
|
2456
|
+
active: false,
|
|
2457
|
+
current_phase: 'complete',
|
|
2458
|
+
completed_at: '2026-06-09T14:45:00.000Z',
|
|
2459
|
+
state: {
|
|
2460
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2461
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/6' },
|
|
2462
|
+
},
|
|
2463
|
+
});
|
|
2464
|
+
assert.equal(response.isError, true);
|
|
2465
|
+
assert.match(String(response.payload.error || ''), /unknown active phase/i);
|
|
2466
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2467
|
+
assert.equal(state.active, true);
|
|
2468
|
+
assert.equal(state.current_phase, 'bogus');
|
|
2469
|
+
assert.equal(Object.prototype.hasOwnProperty.call(state, 'mode'), false);
|
|
2470
|
+
});
|
|
2471
|
+
}
|
|
2472
|
+
finally {
|
|
2473
|
+
await rm(wd, { recursive: true, force: true });
|
|
2474
|
+
}
|
|
2475
|
+
});
|
|
2476
|
+
it('does not persist user-supplied trustedPipelineProgress from Autopilot state_write', async () => {
|
|
2477
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-trusted-field-strip-'));
|
|
2478
|
+
try {
|
|
2479
|
+
await withOmxRootEnv(wd, async () => {
|
|
2480
|
+
const sessionId = 'sess-autopilot-trusted-field-strip';
|
|
2481
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2482
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2483
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2484
|
+
active: true,
|
|
2485
|
+
current_phase: 'ultraqa',
|
|
2486
|
+
}, null, 2));
|
|
2487
|
+
const response = await executeStateOperation('state_write', {
|
|
2488
|
+
workingDirectory: wd,
|
|
2489
|
+
session_id: sessionId,
|
|
2490
|
+
mode: 'autopilot',
|
|
2491
|
+
active: true,
|
|
2492
|
+
current_phase: 'ultraqa',
|
|
2493
|
+
trustedPipelineProgress: true,
|
|
2494
|
+
state: {
|
|
2495
|
+
trustedPipelineProgress: true,
|
|
2496
|
+
},
|
|
2497
|
+
});
|
|
2498
|
+
assert.equal(response.isError, undefined);
|
|
2499
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2500
|
+
assert.equal(Object.prototype.hasOwnProperty.call(state, 'trustedPipelineProgress'), false);
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
finally {
|
|
2504
|
+
await rm(wd, { recursive: true, force: true });
|
|
2505
|
+
}
|
|
2506
|
+
});
|
|
2507
|
+
it('allows Autopilot state_write cancellation from gated phases without clean review and QA evidence', async () => {
|
|
2508
|
+
for (const phase of ['deep-interview', 'ralplan', 'ultragoal', 'code-review']) {
|
|
2509
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-state-ops-autopilot-${phase}-cancel-allow-`));
|
|
2510
|
+
try {
|
|
2511
|
+
await withOmxRootEnv(wd, async () => {
|
|
2512
|
+
const sessionId = `sess-autopilot-${phase}-cancel-allow`;
|
|
2513
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2514
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2515
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2516
|
+
active: true,
|
|
2517
|
+
current_phase: phase,
|
|
2518
|
+
}, null, 2));
|
|
2519
|
+
const response = await executeStateOperation('state_write', {
|
|
2520
|
+
workingDirectory: wd,
|
|
2521
|
+
session_id: sessionId,
|
|
2522
|
+
mode: 'autopilot',
|
|
2523
|
+
active: false,
|
|
2524
|
+
current_phase: 'cancelled',
|
|
2525
|
+
completed_at: '2026-06-09T16:30:00.000Z',
|
|
2526
|
+
});
|
|
2527
|
+
assert.equal(response.isError, undefined);
|
|
2528
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2529
|
+
assert.equal(state.active, false);
|
|
2530
|
+
assert.equal(state.current_phase, 'cancelled');
|
|
2531
|
+
assert.equal(state.run_outcome, 'cancelled');
|
|
2532
|
+
assert.equal(state.completed_at, '2026-06-09T16:30:00.000Z');
|
|
2533
|
+
});
|
|
2534
|
+
}
|
|
2535
|
+
finally {
|
|
2536
|
+
await rm(wd, { recursive: true, force: true });
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
});
|
|
2540
|
+
it('allows Autopilot ultraqa completion with clean review and QA evidence', async () => {
|
|
2541
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ultraqa-complete-allow-'));
|
|
2542
|
+
try {
|
|
2543
|
+
await withOmxRootEnv(wd, async () => {
|
|
2544
|
+
const sessionId = 'sess-autopilot-ultraqa-complete-allow';
|
|
2545
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2546
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2547
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
2548
|
+
active: true,
|
|
2549
|
+
mode: 'autopilot',
|
|
2550
|
+
current_phase: 'ultraqa',
|
|
2551
|
+
state: {
|
|
2552
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2553
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/1' },
|
|
2554
|
+
},
|
|
2555
|
+
}, null, 2));
|
|
2556
|
+
const response = await executeStateOperation('state_write', {
|
|
2557
|
+
workingDirectory: wd,
|
|
2558
|
+
session_id: sessionId,
|
|
2559
|
+
mode: 'autopilot',
|
|
2560
|
+
active: false,
|
|
2561
|
+
current_phase: 'complete',
|
|
2562
|
+
completed_at: '2026-06-09T14:30:00.000Z',
|
|
2563
|
+
state: {
|
|
2564
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2565
|
+
qa_verdict: { stage: 'ultraqa', clean: true, skipped: false, url: 'https://github.com/Yeachan-Heo/oh-my-codex/actions/runs/1' },
|
|
2566
|
+
},
|
|
2567
|
+
});
|
|
2568
|
+
assert.equal(response.isError, undefined);
|
|
2569
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2570
|
+
assert.equal(state.active, false);
|
|
2571
|
+
assert.equal(state.current_phase, 'complete');
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
finally {
|
|
2575
|
+
await rm(wd, { recursive: true, force: true });
|
|
2576
|
+
}
|
|
2577
|
+
});
|
|
2578
|
+
it('allows Autopilot ultraqa skipped completion with reason and durable QA provenance', async () => {
|
|
2579
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ultraqa-skipped-allow-'));
|
|
2580
|
+
try {
|
|
2581
|
+
await withOmxRootEnv(wd, async () => {
|
|
2582
|
+
const sessionId = 'sess-autopilot-ultraqa-skipped-allow';
|
|
2583
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
2584
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2585
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'ultraqa' }, null, 2));
|
|
2586
|
+
const response = await executeStateOperation('state_write', {
|
|
2587
|
+
workingDirectory: wd,
|
|
2588
|
+
session_id: sessionId,
|
|
2589
|
+
mode: 'autopilot',
|
|
2590
|
+
active: false,
|
|
2591
|
+
current_phase: 'complete',
|
|
2592
|
+
completed_at: '2026-06-09T14:35:00.000Z',
|
|
2593
|
+
state: {
|
|
2594
|
+
review_verdict: { stage: 'code-review', recommendation: 'APPROVE', architectural_status: 'CLEAR', clean: true, artifact_path: '.omx/reviews/code-review.json' },
|
|
2595
|
+
qa_verdict: {
|
|
2596
|
+
stage: 'ultraqa',
|
|
2597
|
+
clean: true,
|
|
2598
|
+
skipped: true,
|
|
2599
|
+
reason: 'Docs-only change; QA not applicable.',
|
|
2600
|
+
artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.ultraqa.artifacts.qa_verdict',
|
|
2601
|
+
},
|
|
2602
|
+
},
|
|
2603
|
+
});
|
|
2604
|
+
assert.equal(response.isError, undefined);
|
|
2605
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
2606
|
+
assert.equal(state.active, false);
|
|
2607
|
+
assert.equal(state.current_phase, 'complete');
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
finally {
|
|
2611
|
+
await rm(wd, { recursive: true, force: true });
|
|
2612
|
+
}
|
|
2613
|
+
});
|
|
1992
2614
|
it('allows Autopilot ralplan to ultragoal self-write with tracker-backed native consensus evidence', async () => {
|
|
1993
2615
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-native-allow-'));
|
|
1994
2616
|
try {
|