oh-my-codex 0.19.1 → 0.20.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 +6 -6
- package/Cargo.toml +1 -1
- package/README.md +3 -1
- package/crates/omx-api/src/lib.rs +3 -3
- package/crates/omx-api/tests/cli.rs +4 -4
- package/crates/omx-explore/src/main.rs +4 -4
- package/crates/omx-sparkshell/src/codex_bridge.rs +2 -2
- package/dist/agents/__tests__/definitions.test.js +3 -3
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +71 -42
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +3 -3
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -2
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +7 -5
- package/dist/agents/native-config.js.map +1 -1
- package/dist/autopilot/__tests__/planner-routing.test.js +19 -12
- package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +151 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/planner-routing.d.ts.map +1 -1
- package/dist/autopilot/planner-routing.js +4 -2
- package/dist/autopilot/planner-routing.js.map +1 -1
- package/dist/autopilot/ralplan-gate.d.ts +1 -0
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +38 -2
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/autoresearch/runtime.d.ts +2 -0
- package/dist/autoresearch/runtime.d.ts.map +1 -1
- package/dist/autoresearch/runtime.js +8 -0
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/__tests__/lockfile.test.d.ts +2 -0
- package/dist/capabilities/__tests__/lockfile.test.d.ts.map +1 -0
- package/dist/capabilities/__tests__/lockfile.test.js +115 -0
- package/dist/capabilities/__tests__/lockfile.test.js.map +1 -0
- package/dist/capabilities/lockfile.d.ts +102 -0
- package/dist/capabilities/lockfile.d.ts.map +1 -0
- package/dist/capabilities/lockfile.js +334 -0
- package/dist/capabilities/lockfile.js.map +1 -0
- package/dist/cli/__tests__/agents.test.js +5 -5
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.d.ts +2 -0
- package/dist/cli/__tests__/capabilities.test.d.ts.map +1 -0
- package/dist/cli/__tests__/capabilities.test.js +135 -0
- package/dist/cli/__tests__/capabilities.test.js.map +1 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js +237 -6
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js +9 -9
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +1 -1
- package/dist/cli/__tests__/doctor-spark-routing.test.js +22 -6
- package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +53 -18
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +3 -3
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +95 -6
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +46 -18
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +3 -3
- package/dist/cli/__tests__/setup-refresh.test.js +29 -7
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +4 -4
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/agents.js +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/capabilities.d.ts +3 -0
- package/dist/cli/capabilities.d.ts.map +1 -0
- package/dist/cli/capabilities.js +118 -0
- package/dist/cli/capabilities.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +9 -4
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +7 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +77 -19
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +1 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +31 -0
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +7 -4
- package/dist/cli/setup.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +23 -23
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +9 -9
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +51 -26
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/models.d.ts +16 -6
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +19 -8
- package/dist/config/models.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +12 -4
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +2 -2
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/tmux-hook-engine.test.js +2 -2
- package/dist/leader/__tests__/contract.test.js +108 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +26 -0
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +170 -0
- package/dist/leader/contract.js.map +1 -1
- package/dist/modes/base.d.ts +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +27 -1
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts +2 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +1 -0
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.d.ts +5 -1
- package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
- package/dist/pipeline/stages/ultragoal.js +14 -4
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +132 -0
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +17 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +97 -1
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +412 -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 +238 -12
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +450 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +14 -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 +72 -11
- package/dist/state/operations.js.map +1 -1
- package/dist/state/terminal-normalization.d.ts +8 -0
- package/dist/state/terminal-normalization.d.ts.map +1 -0
- package/dist/state/terminal-normalization.js +127 -0
- package/dist/state/terminal-normalization.js.map +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +3 -1
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/team/__tests__/delegation-policy.test.js +2 -2
- package/dist/team/__tests__/delegation-policy.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +25 -25
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +28 -28
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +7 -7
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js +5 -5
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +12 -12
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +57 -9
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +3 -3
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/model-contract.d.ts +1 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +11 -0
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +2 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +6 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +68 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +5 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +41 -9
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/agents-model-table.test.js +7 -7
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/dist/utils/__tests__/worktree-tool-context.test.d.ts +2 -0
- package/dist/utils/__tests__/worktree-tool-context.test.d.ts.map +1 -0
- package/dist/utils/__tests__/worktree-tool-context.test.js +118 -0
- package/dist/utils/__tests__/worktree-tool-context.test.js.map +1 -0
- package/dist/utils/worktree-tool-context.d.ts +25 -0
- package/dist/utils/worktree-tool-context.d.ts.map +1 -0
- package/dist/utils/worktree-tool-context.js +116 -0
- package/dist/utils/worktree-tool-context.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +96 -10
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +5 -5
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +2 -2
- package/prompts/prometheus-strict-metis.md +1 -1
- package/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/skills/code-review/SKILL.md +1 -1
- package/skills/ecomode/references/agent-tiers.md +1 -1
- package/skills/omx-setup/SKILL.md +5 -5
- package/skills/prometheus-strict/SKILL.md +3 -3
- package/skills/ralplan/SKILL.md +1 -1
- package/skills/team/SKILL.md +1 -1
- package/skills/ultrawork/references/agent-tiers.md +2 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +477 -0
- package/src/scripts/codex-native-hook.ts +272 -11
|
@@ -610,6 +610,58 @@ describe('state operations directory initialization', () => {
|
|
|
610
610
|
await rm(wd, { recursive: true, force: true });
|
|
611
611
|
}
|
|
612
612
|
});
|
|
613
|
+
it('normalizes terminal deep-interview snapshots by releasing stale locks', async () => {
|
|
614
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-di-terminal-normalize-'));
|
|
615
|
+
try {
|
|
616
|
+
const completedAt = '2026-07-09T00:00:00.000Z';
|
|
617
|
+
const writeResponse = await executeStateOperation('state_write', {
|
|
618
|
+
workingDirectory: wd,
|
|
619
|
+
mode: 'deep-interview',
|
|
620
|
+
active: false,
|
|
621
|
+
current_phase: 'cancelled',
|
|
622
|
+
completed_at: completedAt,
|
|
623
|
+
input_lock: {
|
|
624
|
+
active: true,
|
|
625
|
+
owner: 'question-round',
|
|
626
|
+
},
|
|
627
|
+
approval_lock: {
|
|
628
|
+
status: 'pending',
|
|
629
|
+
reviewer: 'user',
|
|
630
|
+
},
|
|
631
|
+
question_enforcement: {
|
|
632
|
+
obligation_id: 'obligation-stale',
|
|
633
|
+
source: 'omx-question',
|
|
634
|
+
status: 'pending',
|
|
635
|
+
lifecycle_outcome: 'askuserQuestion',
|
|
636
|
+
requested_at: '2026-07-08T23:59:00.000Z',
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
assert.equal(writeResponse.isError, undefined);
|
|
640
|
+
const readResponse = await executeStateOperation('state_read', {
|
|
641
|
+
workingDirectory: wd,
|
|
642
|
+
mode: 'deep-interview',
|
|
643
|
+
});
|
|
644
|
+
const readBody = readResponse.payload;
|
|
645
|
+
const inputLock = readBody.input_lock;
|
|
646
|
+
const approvalLock = readBody.approval_lock;
|
|
647
|
+
const questionEnforcement = readBody.question_enforcement;
|
|
648
|
+
assert.equal(readBody.active, false);
|
|
649
|
+
assert.equal(readBody.current_phase, 'cancelled');
|
|
650
|
+
assert.equal(readBody.completed_at, completedAt);
|
|
651
|
+
assert.equal(readBody.run_outcome, 'cancelled');
|
|
652
|
+
assert.equal(inputLock.active, false);
|
|
653
|
+
assert.equal(inputLock.status, 'released');
|
|
654
|
+
assert.equal(inputLock.released_at, completedAt);
|
|
655
|
+
assert.equal(approvalLock.active, false);
|
|
656
|
+
assert.equal(approvalLock.status, 'released');
|
|
657
|
+
assert.equal(inputLock.release_reason, 'terminal_state_normalization');
|
|
658
|
+
assert.equal(questionEnforcement.status, 'cleared');
|
|
659
|
+
assert.equal(questionEnforcement.clear_reason, 'abort');
|
|
660
|
+
}
|
|
661
|
+
finally {
|
|
662
|
+
await rm(wd, { recursive: true, force: true });
|
|
663
|
+
}
|
|
664
|
+
});
|
|
613
665
|
it('writes and reads autoresearch state', async () => {
|
|
614
666
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autoresearch-'));
|
|
615
667
|
try {
|
|
@@ -1096,6 +1148,285 @@ describe('state operations directory initialization', () => {
|
|
|
1096
1148
|
await rm(wd, { recursive: true, force: true });
|
|
1097
1149
|
}
|
|
1098
1150
|
});
|
|
1151
|
+
it('allows ralplan unsupported native non-clean recovery without tracker-backed consensus', async () => {
|
|
1152
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-unsupported-recovery-'));
|
|
1153
|
+
try {
|
|
1154
|
+
const sessionId = 'sess-ralplan-unsupported-recovery';
|
|
1155
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1156
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1157
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1158
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1159
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1160
|
+
mode: 'ralplan',
|
|
1161
|
+
active: true,
|
|
1162
|
+
current_phase: 'planning',
|
|
1163
|
+
session_id: sessionId,
|
|
1164
|
+
}, null, 2));
|
|
1165
|
+
const response = await executeStateOperation('state_write', {
|
|
1166
|
+
workingDirectory: wd,
|
|
1167
|
+
session_id: sessionId,
|
|
1168
|
+
mode: 'ralplan',
|
|
1169
|
+
active: false,
|
|
1170
|
+
current_phase: 'blocked',
|
|
1171
|
+
native_subagent_support: {
|
|
1172
|
+
status: 'unsupported',
|
|
1173
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1174
|
+
source: 'post_tool_failure',
|
|
1175
|
+
},
|
|
1176
|
+
});
|
|
1177
|
+
assert.equal(response.isError, undefined);
|
|
1178
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1179
|
+
assert.equal(state.active, false);
|
|
1180
|
+
assert.equal(state.current_phase, 'blocked');
|
|
1181
|
+
assert.equal(state.ralplan_consensus_gate, undefined);
|
|
1182
|
+
}
|
|
1183
|
+
finally {
|
|
1184
|
+
await rm(wd, { recursive: true, force: true });
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
it('rejects ralplan clean complete without tracker-backed native consensus after unsupported recovery support', async () => {
|
|
1188
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-clean-still-strict-'));
|
|
1189
|
+
try {
|
|
1190
|
+
const sessionId = 'sess-ralplan-clean-still-strict';
|
|
1191
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1192
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1193
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1194
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1195
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1196
|
+
mode: 'ralplan',
|
|
1197
|
+
active: true,
|
|
1198
|
+
current_phase: 'planning',
|
|
1199
|
+
session_id: sessionId,
|
|
1200
|
+
native_subagent_support: {
|
|
1201
|
+
status: 'unsupported',
|
|
1202
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1203
|
+
source: 'post_tool_failure',
|
|
1204
|
+
},
|
|
1205
|
+
}, null, 2));
|
|
1206
|
+
const response = await executeStateOperation('state_write', {
|
|
1207
|
+
workingDirectory: wd,
|
|
1208
|
+
session_id: sessionId,
|
|
1209
|
+
mode: 'ralplan',
|
|
1210
|
+
active: false,
|
|
1211
|
+
current_phase: 'complete',
|
|
1212
|
+
status: 'complete',
|
|
1213
|
+
});
|
|
1214
|
+
assert.equal(response.isError, true);
|
|
1215
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1216
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1217
|
+
assert.equal(state.active, true);
|
|
1218
|
+
assert.equal(state.current_phase, 'planning');
|
|
1219
|
+
}
|
|
1220
|
+
finally {
|
|
1221
|
+
await rm(wd, { recursive: true, force: true });
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
it('rejects ralplan clean complete with unsupported evidence even when native consensus is valid', async () => {
|
|
1225
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-clean-unsupported-valid-consensus-deny-'));
|
|
1226
|
+
try {
|
|
1227
|
+
const sessionId = 'sess-ralplan-clean-unsupported-valid-consensus-deny';
|
|
1228
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1229
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1230
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1231
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1232
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1233
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1234
|
+
mode: 'ralplan',
|
|
1235
|
+
active: true,
|
|
1236
|
+
current_phase: 'planning',
|
|
1237
|
+
session_id: sessionId,
|
|
1238
|
+
}, null, 2));
|
|
1239
|
+
const response = await executeStateOperation('state_write', {
|
|
1240
|
+
workingDirectory: wd,
|
|
1241
|
+
session_id: sessionId,
|
|
1242
|
+
mode: 'ralplan',
|
|
1243
|
+
active: false,
|
|
1244
|
+
current_phase: 'complete',
|
|
1245
|
+
status: 'complete',
|
|
1246
|
+
native_subagent_support: {
|
|
1247
|
+
status: 'unsupported',
|
|
1248
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1249
|
+
source: 'post_tool_failure',
|
|
1250
|
+
},
|
|
1251
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
1252
|
+
});
|
|
1253
|
+
assert.equal(response.isError, true);
|
|
1254
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1255
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1256
|
+
assert.equal(state.active, true);
|
|
1257
|
+
assert.equal(state.current_phase, 'planning');
|
|
1258
|
+
}
|
|
1259
|
+
finally {
|
|
1260
|
+
await rm(wd, { recursive: true, force: true });
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
it('rejects ralplan clean complete with handoff-artifact unsupported evidence', async () => {
|
|
1264
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-clean-handoff-unsupported-deny-'));
|
|
1265
|
+
try {
|
|
1266
|
+
const sessionId = 'sess-ralplan-clean-handoff-unsupported-deny';
|
|
1267
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1268
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1269
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1270
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1271
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1272
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1273
|
+
mode: 'ralplan',
|
|
1274
|
+
active: true,
|
|
1275
|
+
current_phase: 'planning',
|
|
1276
|
+
session_id: sessionId,
|
|
1277
|
+
}, null, 2));
|
|
1278
|
+
const response = await executeStateOperation('state_write', {
|
|
1279
|
+
workingDirectory: wd,
|
|
1280
|
+
session_id: sessionId,
|
|
1281
|
+
mode: 'ralplan',
|
|
1282
|
+
active: false,
|
|
1283
|
+
current_phase: 'complete',
|
|
1284
|
+
status: 'complete',
|
|
1285
|
+
handoff_artifacts: {
|
|
1286
|
+
ralplan: {
|
|
1287
|
+
native_subagent_support: {
|
|
1288
|
+
status: 'unsupported',
|
|
1289
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1290
|
+
source: 'post_tool_failure',
|
|
1291
|
+
},
|
|
1292
|
+
},
|
|
1293
|
+
},
|
|
1294
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
1295
|
+
});
|
|
1296
|
+
assert.equal(response.isError, true);
|
|
1297
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1298
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1299
|
+
assert.equal(state.active, true);
|
|
1300
|
+
assert.equal(state.current_phase, 'planning');
|
|
1301
|
+
}
|
|
1302
|
+
finally {
|
|
1303
|
+
await rm(wd, { recursive: true, force: true });
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
it('rejects ralplan clean complete with nested handoff-artifact unsupported evidence', async () => {
|
|
1307
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-clean-nested-handoff-unsupported-deny-'));
|
|
1308
|
+
try {
|
|
1309
|
+
const sessionId = 'sess-ralplan-clean-nested-handoff-unsupported-deny';
|
|
1310
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1311
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1312
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1313
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1314
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1315
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1316
|
+
mode: 'ralplan',
|
|
1317
|
+
active: true,
|
|
1318
|
+
current_phase: 'planning',
|
|
1319
|
+
session_id: sessionId,
|
|
1320
|
+
}, null, 2));
|
|
1321
|
+
const response = await executeStateOperation('state_write', {
|
|
1322
|
+
workingDirectory: wd,
|
|
1323
|
+
session_id: sessionId,
|
|
1324
|
+
mode: 'ralplan',
|
|
1325
|
+
active: false,
|
|
1326
|
+
current_phase: 'complete',
|
|
1327
|
+
status: 'complete',
|
|
1328
|
+
state: {
|
|
1329
|
+
handoff_artifacts: {
|
|
1330
|
+
ralplan: {
|
|
1331
|
+
native_subagent_support: {
|
|
1332
|
+
status: 'unsupported',
|
|
1333
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1334
|
+
source: 'post_tool_failure',
|
|
1335
|
+
},
|
|
1336
|
+
},
|
|
1337
|
+
},
|
|
1338
|
+
},
|
|
1339
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
1340
|
+
});
|
|
1341
|
+
assert.equal(response.isError, true);
|
|
1342
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1343
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1344
|
+
assert.equal(state.active, true);
|
|
1345
|
+
assert.equal(state.current_phase, 'planning');
|
|
1346
|
+
}
|
|
1347
|
+
finally {
|
|
1348
|
+
await rm(wd, { recursive: true, force: true });
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
it('rejects ralplan clean complete with handoff-root unsupported evidence', async () => {
|
|
1352
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-clean-handoff-root-unsupported-deny-'));
|
|
1353
|
+
try {
|
|
1354
|
+
const sessionId = 'sess-ralplan-clean-handoff-root-unsupported-deny';
|
|
1355
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1356
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1357
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1358
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1359
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1360
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1361
|
+
mode: 'ralplan',
|
|
1362
|
+
active: true,
|
|
1363
|
+
current_phase: 'planning',
|
|
1364
|
+
session_id: sessionId,
|
|
1365
|
+
}, null, 2));
|
|
1366
|
+
const response = await executeStateOperation('state_write', {
|
|
1367
|
+
workingDirectory: wd,
|
|
1368
|
+
session_id: sessionId,
|
|
1369
|
+
mode: 'ralplan',
|
|
1370
|
+
active: false,
|
|
1371
|
+
current_phase: 'complete',
|
|
1372
|
+
status: 'complete',
|
|
1373
|
+
handoff_artifacts: {
|
|
1374
|
+
native_subagent_support: {
|
|
1375
|
+
status: 'unsupported',
|
|
1376
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1377
|
+
source: 'post_tool_failure',
|
|
1378
|
+
},
|
|
1379
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
1380
|
+
},
|
|
1381
|
+
});
|
|
1382
|
+
assert.equal(response.isError, true);
|
|
1383
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1384
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1385
|
+
assert.equal(state.active, true);
|
|
1386
|
+
assert.equal(state.current_phase, 'planning');
|
|
1387
|
+
}
|
|
1388
|
+
finally {
|
|
1389
|
+
await rm(wd, { recursive: true, force: true });
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
it('rejects ralplan clean status alias with unsupported evidence even when native consensus is valid', async () => {
|
|
1393
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-status-alias-unsupported-deny-'));
|
|
1394
|
+
try {
|
|
1395
|
+
const sessionId = 'sess-ralplan-status-alias-unsupported-deny';
|
|
1396
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
1397
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1398
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1399
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1400
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd }, null, 2));
|
|
1401
|
+
await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
|
|
1402
|
+
mode: 'ralplan',
|
|
1403
|
+
active: true,
|
|
1404
|
+
current_phase: 'planning',
|
|
1405
|
+
session_id: sessionId,
|
|
1406
|
+
}, null, 2));
|
|
1407
|
+
const response = await executeStateOperation('state_write', {
|
|
1408
|
+
workingDirectory: wd,
|
|
1409
|
+
session_id: sessionId,
|
|
1410
|
+
mode: 'ralplan',
|
|
1411
|
+
active: false,
|
|
1412
|
+
status: 'complete',
|
|
1413
|
+
native_subagent_support: {
|
|
1414
|
+
status: 'unsupported',
|
|
1415
|
+
reason: 'multi_agent_v1_unavailable',
|
|
1416
|
+
source: 'post_tool_failure',
|
|
1417
|
+
},
|
|
1418
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
1419
|
+
});
|
|
1420
|
+
assert.equal(response.isError, true);
|
|
1421
|
+
assert.match(String(response.payload.error ?? ''), /Cannot complete ralplan cleanly while native subagent support is unavailable/);
|
|
1422
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8'));
|
|
1423
|
+
assert.equal(state.active, true);
|
|
1424
|
+
assert.equal(state.current_phase, 'planning');
|
|
1425
|
+
}
|
|
1426
|
+
finally {
|
|
1427
|
+
await rm(wd, { recursive: true, force: true });
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1099
1430
|
it('normalizes currentPhase before gating ralplan terminal writes', async () => {
|
|
1100
1431
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-current-phase-alias-'));
|
|
1101
1432
|
try {
|
|
@@ -3329,6 +3660,40 @@ describe('state operations directory initialization', () => {
|
|
|
3329
3660
|
await rm(wd, { recursive: true, force: true });
|
|
3330
3661
|
}
|
|
3331
3662
|
});
|
|
3663
|
+
it('allows Autopilot ralplan unsupported native non-clean recovery', async () => {
|
|
3664
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-unsupported-recovery-'));
|
|
3665
|
+
try {
|
|
3666
|
+
await withOmxRootEnv(wd, async () => {
|
|
3667
|
+
const sessionId = 'sess-autopilot-ralplan-unsupported-recovery';
|
|
3668
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
3669
|
+
await mkdir(sessionDir, { recursive: true });
|
|
3670
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
3671
|
+
active: true,
|
|
3672
|
+
mode: 'autopilot',
|
|
3673
|
+
current_phase: 'ralplan',
|
|
3674
|
+
}, null, 2));
|
|
3675
|
+
const response = await executeStateOperation('state_write', {
|
|
3676
|
+
workingDirectory: wd,
|
|
3677
|
+
session_id: sessionId,
|
|
3678
|
+
mode: 'autopilot',
|
|
3679
|
+
active: false,
|
|
3680
|
+
current_phase: 'blocked',
|
|
3681
|
+
native_subagent_support: {
|
|
3682
|
+
status: 'unsupported',
|
|
3683
|
+
reason: 'multi_agent_v1_unavailable',
|
|
3684
|
+
source: 'post_tool_failure',
|
|
3685
|
+
},
|
|
3686
|
+
});
|
|
3687
|
+
assert.equal(response.isError, undefined);
|
|
3688
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
3689
|
+
assert.equal(state.active, false);
|
|
3690
|
+
assert.equal(state.current_phase, 'blocked');
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
finally {
|
|
3694
|
+
await rm(wd, { recursive: true, force: true });
|
|
3695
|
+
}
|
|
3696
|
+
});
|
|
3332
3697
|
it('denies Autopilot ralplan to ultragoal self-write with codex_exec consensus evidence', async () => {
|
|
3333
3698
|
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-native-deny-'));
|
|
3334
3699
|
try {
|
|
@@ -3367,6 +3732,91 @@ describe('state operations directory initialization', () => {
|
|
|
3367
3732
|
await rm(wd, { recursive: true, force: true });
|
|
3368
3733
|
}
|
|
3369
3734
|
});
|
|
3735
|
+
it('denies Autopilot ralplan to ultragoal when unsupported native evidence is present', async () => {
|
|
3736
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-unsupported-ultragoal-deny-'));
|
|
3737
|
+
try {
|
|
3738
|
+
await withOmxRootEnv(wd, async () => {
|
|
3739
|
+
const sessionId = 'sess-autopilot-ralplan-unsupported-ultragoal-deny';
|
|
3740
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
3741
|
+
await mkdir(sessionDir, { recursive: true });
|
|
3742
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
3743
|
+
active: true,
|
|
3744
|
+
mode: 'autopilot',
|
|
3745
|
+
current_phase: 'ralplan',
|
|
3746
|
+
native_subagent_support: {
|
|
3747
|
+
status: 'unsupported',
|
|
3748
|
+
reason: 'native_subagents_unsupported',
|
|
3749
|
+
source: 'post_tool_failure',
|
|
3750
|
+
},
|
|
3751
|
+
}, null, 2));
|
|
3752
|
+
const response = await executeStateOperation('state_write', {
|
|
3753
|
+
workingDirectory: wd,
|
|
3754
|
+
session_id: sessionId,
|
|
3755
|
+
mode: 'autopilot',
|
|
3756
|
+
active: true,
|
|
3757
|
+
current_phase: 'ultragoal',
|
|
3758
|
+
native_subagent_support: {
|
|
3759
|
+
status: 'unsupported',
|
|
3760
|
+
reason: 'native_subagents_unsupported',
|
|
3761
|
+
source: 'post_tool_failure',
|
|
3762
|
+
},
|
|
3763
|
+
});
|
|
3764
|
+
assert.equal(response.isError, true);
|
|
3765
|
+
assert.match(String(response.payload.error || ''), /Cannot transition ralplan -> ultragoal/i);
|
|
3766
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
3767
|
+
assert.equal(state.current_phase, 'ralplan');
|
|
3768
|
+
});
|
|
3769
|
+
}
|
|
3770
|
+
finally {
|
|
3771
|
+
await rm(wd, { recursive: true, force: true });
|
|
3772
|
+
}
|
|
3773
|
+
});
|
|
3774
|
+
it('denies Autopilot ralplan to ultragoal with unsupported evidence even when native consensus is valid', async () => {
|
|
3775
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-autopilot-ralplan-unsupported-valid-consensus-deny-'));
|
|
3776
|
+
try {
|
|
3777
|
+
await withOmxRootEnv(wd, async () => {
|
|
3778
|
+
const sessionId = 'sess-autopilot-ralplan-unsupported-valid-consensus-deny';
|
|
3779
|
+
const sessionDir = join(wd, '.omx', 'state', 'sessions', sessionId);
|
|
3780
|
+
await mkdir(sessionDir, { recursive: true });
|
|
3781
|
+
await writeNativeSubagentTracking(wd, sessionId);
|
|
3782
|
+
await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
3783
|
+
active: true,
|
|
3784
|
+
mode: 'autopilot',
|
|
3785
|
+
current_phase: 'ralplan',
|
|
3786
|
+
native_subagent_support: {
|
|
3787
|
+
status: 'unsupported',
|
|
3788
|
+
reason: 'multi_agent_v1_unavailable',
|
|
3789
|
+
source: 'post_tool_failure',
|
|
3790
|
+
},
|
|
3791
|
+
state: {
|
|
3792
|
+
handoff_artifacts: {
|
|
3793
|
+
ralplan: {
|
|
3794
|
+
plan_path: '.omx/plans/prd.md',
|
|
3795
|
+
test_spec_path: '.omx/plans/test-spec.md',
|
|
3796
|
+
},
|
|
3797
|
+
ralplan_consensus_gate: ralplanConsensusGate(sessionId, 'native_subagent'),
|
|
3798
|
+
},
|
|
3799
|
+
},
|
|
3800
|
+
}, null, 2));
|
|
3801
|
+
const response = await executeStateOperation('state_write', {
|
|
3802
|
+
workingDirectory: wd,
|
|
3803
|
+
session_id: sessionId,
|
|
3804
|
+
mode: 'autopilot',
|
|
3805
|
+
active: true,
|
|
3806
|
+
current_phase: 'ultragoal',
|
|
3807
|
+
});
|
|
3808
|
+
assert.equal(response.isError, true);
|
|
3809
|
+
const error = String(response.payload.error || '');
|
|
3810
|
+
assert.match(error, /terminalize non-clean/);
|
|
3811
|
+
assert.match(error, /blocked\/cancelled\/failed/);
|
|
3812
|
+
const state = JSON.parse(await readFile(join(sessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
3813
|
+
assert.equal(state.current_phase, 'ralplan');
|
|
3814
|
+
});
|
|
3815
|
+
}
|
|
3816
|
+
finally {
|
|
3817
|
+
await rm(wd, { recursive: true, force: true });
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3370
3820
|
for (const { lane, architectVerdict, criticVerdict } of [
|
|
3371
3821
|
{ lane: 'architect', architectVerdict: 'iterate', criticVerdict: 'approve' },
|
|
3372
3822
|
{ lane: 'critic', architectVerdict: 'approve', criticVerdict: 'iterate' },
|