oh-my-codex 0.18.1 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +4 -2
- package/dist/agents/__tests__/definitions.test.js +14 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +19 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +30 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +4 -0
- package/dist/agents/native-config.js.map +1 -1
- package/dist/catalog/__tests__/generator.test.js +4 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +61 -5
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +161 -21
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +51 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +2 -2
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +178 -7
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +7 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +143 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +3 -3
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +1 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2 -4
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +14 -0
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +100 -1
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +3 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +45 -2
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +17 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +170 -15
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
- package/dist/hooks/keyword-detector.d.ts +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +28 -6
- 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 +1 -0
- 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 +11 -0
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +22 -0
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +121 -10
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +84 -0
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +51 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +69 -23
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/index.d.ts +1 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +8 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +6 -3
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +26 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +2 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +62 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +10 -3
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +59 -10
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +22 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +63 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +410 -4
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +29 -2
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +41 -6
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +43 -10
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/ui.d.ts +12 -0
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +83 -46
- package/dist/question/ui.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +200 -10
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -0
- package/dist/ralplan/consensus-gate.js +212 -0
- package/dist/ralplan/consensus-gate.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +25 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +144 -8
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +626 -7
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +57 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +2 -2
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +214 -34
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +188 -4
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/run-test-files.js +13 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +6 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +7 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +4 -3
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +36 -44
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +58 -18
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +10 -20
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +15 -6
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +50 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +28 -2
- package/dist/ultragoal/artifacts.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/skills/autopilot/SKILL.md +16 -4
- package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/plan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +18 -3
- package/prompts/prometheus-strict-metis.md +274 -0
- package/prompts/prometheus-strict-momus.md +82 -0
- package/prompts/prometheus-strict-oracle.md +107 -0
- package/prompts/researcher.md +22 -3
- package/skills/autopilot/SKILL.md +16 -4
- package/skills/autoresearch/SKILL.md +4 -0
- package/skills/autoresearch-goal/SKILL.md +1 -1
- package/skills/best-practice-research/SKILL.md +1 -1
- package/skills/pipeline/SKILL.md +1 -1
- package/skills/plan/SKILL.md +1 -1
- package/skills/prometheus-strict/README.md +35 -0
- package/skills/prometheus-strict/SKILL.md +219 -0
- package/skills/ralplan/SKILL.md +18 -3
- package/src/scripts/__tests__/codex-native-hook.test.ts +769 -8
- package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
- package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
- package/src/scripts/__tests__/run-test-files.test.ts +67 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +2 -2
- package/src/scripts/codex-native-hook.ts +237 -30
- package/src/scripts/notify-dispatcher.ts +202 -4
- package/src/scripts/run-test-files.ts +13 -0
- package/templates/catalog-manifest.json +22 -0
|
@@ -194,6 +194,11 @@ describe('keyword detector team compatibility', () => {
|
|
|
194
194
|
assert.equal(detectPrimaryKeyword('cleanup stale deep-interview state after session clear'), null);
|
|
195
195
|
assert.equal(detectPrimaryKeyword('remove the stale deep interview lock from .omx/state'), null);
|
|
196
196
|
});
|
|
197
|
+
it('does not trigger deep-interview from casual discussion mentions', () => {
|
|
198
|
+
assert.equal(detectPrimaryKeyword('the deep interview report is useful context for the next plan'), null);
|
|
199
|
+
assert.equal(detectPrimaryKeyword('we already did a deep interview and should not reactivate it'), null);
|
|
200
|
+
assert.equal(detectPrimaryKeyword('this interview transcript says implementation is ready'), null);
|
|
201
|
+
});
|
|
197
202
|
it('maps "gather requirements" to deep-interview skill', () => {
|
|
198
203
|
const match = detectPrimaryKeyword('let us gather requirements first');
|
|
199
204
|
assert.ok(match);
|
|
@@ -285,6 +290,13 @@ describe('explicit skill-name invocation requirement', () => {
|
|
|
285
290
|
it('does not trigger ralplan from bare skill-name usage', () => {
|
|
286
291
|
assert.equal(detectPrimaryKeyword('please do ralplan first'), null);
|
|
287
292
|
});
|
|
293
|
+
it('detects explicit prometheus-strict invocation only', () => {
|
|
294
|
+
const match = detectPrimaryKeyword('please run $prometheus-strict before implementation');
|
|
295
|
+
assert.ok(match);
|
|
296
|
+
assert.equal(match.skill, 'prometheus-strict');
|
|
297
|
+
assert.equal(match.keyword.toLowerCase(), '$prometheus-strict');
|
|
298
|
+
assert.equal(detectPrimaryKeyword('please use prometheus-strict planning here'), null);
|
|
299
|
+
});
|
|
288
300
|
});
|
|
289
301
|
describe('keyword registry coverage', () => {
|
|
290
302
|
it('includes key team aliases in runtime keyword registry', () => {
|
|
@@ -304,6 +316,7 @@ describe('keyword registry coverage', () => {
|
|
|
304
316
|
assert.ok(registryKeywords.has('wiki lint'));
|
|
305
317
|
assert.ok(registryKeywords.has('$autoresearch'));
|
|
306
318
|
assert.ok(registryKeywords.has('$ultragoal'));
|
|
319
|
+
assert.ok(registryKeywords.has('$prometheus-strict'));
|
|
307
320
|
assert.ok(registryKeywords.has('ultragoal'));
|
|
308
321
|
});
|
|
309
322
|
});
|
|
@@ -398,7 +411,7 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
398
411
|
await rm(root, { recursive: true, force: true });
|
|
399
412
|
}
|
|
400
413
|
});
|
|
401
|
-
it('writes skill-active-state.json with
|
|
414
|
+
it('writes skill-active-state.json with deep-interview phase when autopilot keyword activates', async () => {
|
|
402
415
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-state-'));
|
|
403
416
|
const stateDir = join(cwd, '.omx', 'state');
|
|
404
417
|
try {
|
|
@@ -413,11 +426,11 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
413
426
|
});
|
|
414
427
|
assert.ok(result);
|
|
415
428
|
assert.equal(result.skill, 'autopilot');
|
|
416
|
-
assert.equal(result.phase, '
|
|
429
|
+
assert.equal(result.phase, 'deep-interview');
|
|
417
430
|
assert.equal(result.active, true);
|
|
418
431
|
assert.deepEqual(result.active_skills, [{
|
|
419
432
|
skill: 'autopilot',
|
|
420
|
-
phase: '
|
|
433
|
+
phase: 'deep-interview',
|
|
421
434
|
active: true,
|
|
422
435
|
activated_at: '2026-02-25T00:00:00.000Z',
|
|
423
436
|
updated_at: '2026-02-25T00:00:00.000Z',
|
|
@@ -439,7 +452,27 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
439
452
|
assert.equal(modeState.review_cycle, 0);
|
|
440
453
|
assert.equal(modeState.max_iterations, 10);
|
|
441
454
|
assert.deepEqual(modeState.state.phase_cycle, ['deep-interview', 'ralplan', 'ultragoal', 'code-review', 'ultraqa']);
|
|
442
|
-
assert.deepEqual(modeState.state.
|
|
455
|
+
assert.deepEqual(modeState.state.deep_interview_gate, {
|
|
456
|
+
status: 'required',
|
|
457
|
+
skip_reason: null,
|
|
458
|
+
rationale: 'Autopilot starts at the deep-interview gate by default; clear bounded tasks may skip only with an explicit persisted skip reason.',
|
|
459
|
+
});
|
|
460
|
+
assert.deepEqual(modeState.state.handoff_artifacts, {
|
|
461
|
+
deep_interview: null,
|
|
462
|
+
ralplan: null,
|
|
463
|
+
ralplan_consensus_gate: {
|
|
464
|
+
required: true,
|
|
465
|
+
sequence: ['architect-review', 'critic-review'],
|
|
466
|
+
planning_artifacts_are_not_consensus: true,
|
|
467
|
+
required_review_roles: ['architect', 'critic'],
|
|
468
|
+
ralplan_architect_review: null,
|
|
469
|
+
ralplan_critic_review: null,
|
|
470
|
+
complete: false,
|
|
471
|
+
},
|
|
472
|
+
ultragoal: null,
|
|
473
|
+
code_review: null,
|
|
474
|
+
ultraqa: null,
|
|
475
|
+
});
|
|
443
476
|
assert.equal(modeState.state.review_verdict, null);
|
|
444
477
|
assert.equal(modeState.state.qa_verdict, null);
|
|
445
478
|
assert.equal(modeState.state.return_to_ralplan_reason, null);
|
|
@@ -792,18 +825,56 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
792
825
|
}, null, 2));
|
|
793
826
|
const result = await recordSkillActivation({
|
|
794
827
|
stateDir,
|
|
795
|
-
text: '$
|
|
828
|
+
text: '$ultragoal turn the clarified spec into goals',
|
|
796
829
|
sessionId: 'sess-handoff',
|
|
797
830
|
nowIso: '2026-04-10T00:00:00.000Z',
|
|
798
831
|
});
|
|
799
832
|
assert.equal(result?.transition_error, undefined);
|
|
800
|
-
assert.equal(result?.
|
|
833
|
+
assert.equal(result?.skill, 'ultragoal');
|
|
834
|
+
assert.equal(result?.initialized_mode, 'ultragoal');
|
|
835
|
+
assert.equal(result?.initialized_state_path, '.omx/state/sessions/sess-handoff/ultragoal-state.json');
|
|
836
|
+
assert.equal(result?.transition_message, 'mode transiting: deep-interview -> ultragoal');
|
|
801
837
|
const completed = JSON.parse(await readFile(join(stateDir, 'sessions', 'sess-handoff', 'deep-interview-state.json'), 'utf-8'));
|
|
802
838
|
assert.equal(completed.active, false);
|
|
803
839
|
assert.equal(completed.current_phase, 'completed');
|
|
804
840
|
assert.equal(completed.question_enforcement?.status, 'cleared');
|
|
805
841
|
assert.equal(completed.question_enforcement?.clear_reason, 'handoff');
|
|
806
842
|
assert.ok(completed.question_enforcement?.cleared_at);
|
|
843
|
+
const ultragoal = JSON.parse(await readFile(join(stateDir, 'sessions', 'sess-handoff', 'ultragoal-state.json'), 'utf-8'));
|
|
844
|
+
assert.equal(ultragoal.active, true);
|
|
845
|
+
assert.equal(ultragoal.mode, 'ultragoal');
|
|
846
|
+
assert.equal(ultragoal.current_phase, 'planning');
|
|
847
|
+
}
|
|
848
|
+
finally {
|
|
849
|
+
await rm(cwd, { recursive: true, force: true });
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
it('keeps ralplan as an allowlisted deep-interview forward handoff', async () => {
|
|
853
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-ralplan-handoff-'));
|
|
854
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
855
|
+
try {
|
|
856
|
+
await mkdir(join(stateDir, 'sessions', 'sess-ralplan-handoff'), { recursive: true });
|
|
857
|
+
await writeFile(join(stateDir, 'sessions', 'sess-ralplan-handoff', SKILL_ACTIVE_STATE_FILE), JSON.stringify({
|
|
858
|
+
version: 1,
|
|
859
|
+
active: true,
|
|
860
|
+
skill: 'deep-interview',
|
|
861
|
+
phase: 'planning',
|
|
862
|
+
session_id: 'sess-ralplan-handoff',
|
|
863
|
+
active_skills: [{ skill: 'deep-interview', phase: 'planning', active: true, session_id: 'sess-ralplan-handoff' }],
|
|
864
|
+
}, null, 2));
|
|
865
|
+
await writeFile(join(stateDir, 'sessions', 'sess-ralplan-handoff', 'deep-interview-state.json'), JSON.stringify({ active: true, mode: 'deep-interview', current_phase: 'intent-first' }, null, 2));
|
|
866
|
+
const result = await recordSkillActivation({
|
|
867
|
+
stateDir,
|
|
868
|
+
text: '$ralplan implement the approved contract',
|
|
869
|
+
sessionId: 'sess-ralplan-handoff',
|
|
870
|
+
nowIso: '2026-04-10T00:00:00.000Z',
|
|
871
|
+
});
|
|
872
|
+
assert.equal(result?.transition_error, undefined);
|
|
873
|
+
assert.equal(result?.skill, 'ralplan');
|
|
874
|
+
assert.equal(result?.transition_message, 'mode transiting: deep-interview -> ralplan');
|
|
875
|
+
const completed = JSON.parse(await readFile(join(stateDir, 'sessions', 'sess-ralplan-handoff', 'deep-interview-state.json'), 'utf-8'));
|
|
876
|
+
assert.equal(completed.active, false);
|
|
877
|
+
assert.equal(completed.current_phase, 'completed');
|
|
807
878
|
}
|
|
808
879
|
finally {
|
|
809
880
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1151,7 +1222,7 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
1151
1222
|
await rm(cwd, { recursive: true, force: true });
|
|
1152
1223
|
}
|
|
1153
1224
|
});
|
|
1154
|
-
it('records ultragoal as a prompt skill
|
|
1225
|
+
it('records ultragoal as a prompt skill with first-class mode state', async () => {
|
|
1155
1226
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-state-ultragoal-'));
|
|
1156
1227
|
const stateDir = join(cwd, '.omx', 'state');
|
|
1157
1228
|
try {
|
|
@@ -1163,9 +1234,12 @@ describe('keyword detector skill-active-state lifecycle', () => {
|
|
|
1163
1234
|
assert.ok(result);
|
|
1164
1235
|
assert.equal(result.skill, 'ultragoal');
|
|
1165
1236
|
assert.equal(result.keyword, '$ultragoal');
|
|
1166
|
-
assert.equal(result.initialized_mode,
|
|
1167
|
-
assert.equal(result.initialized_state_path,
|
|
1168
|
-
|
|
1237
|
+
assert.equal(result.initialized_mode, 'ultragoal');
|
|
1238
|
+
assert.equal(result.initialized_state_path, '.omx/state/ultragoal-state.json');
|
|
1239
|
+
const modeState = JSON.parse(await readFile(join(stateDir, 'ultragoal-state.json'), 'utf-8'));
|
|
1240
|
+
assert.equal(modeState.active, true);
|
|
1241
|
+
assert.equal(modeState.mode, 'ultragoal');
|
|
1242
|
+
assert.equal(modeState.current_phase, 'planning');
|
|
1169
1243
|
}
|
|
1170
1244
|
finally {
|
|
1171
1245
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1696,7 +1770,7 @@ describe('isUnderspecifiedForExecution', () => {
|
|
|
1696
1770
|
});
|
|
1697
1771
|
});
|
|
1698
1772
|
describe('applyRalplanGate', () => {
|
|
1699
|
-
it('
|
|
1773
|
+
it('gates short team follow-up when only PRD/test-spec artifacts exist', async () => {
|
|
1700
1774
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-followup-'));
|
|
1701
1775
|
try {
|
|
1702
1776
|
const plansDir = join(cwd, '.omx', 'plans');
|
|
@@ -1704,20 +1778,32 @@ describe('applyRalplanGate', () => {
|
|
|
1704
1778
|
await writeFile(join(plansDir, 'prd-issue-831.md'), '# Approved plan\n\nLaunch hint: omx team 3:executor "Execute approved issue 831 plan"\n');
|
|
1705
1779
|
await writeFile(join(plansDir, 'test-spec-issue-831.md'), '# Test spec\n');
|
|
1706
1780
|
const result = applyRalplanGate(['team'], 'team', { cwd });
|
|
1707
|
-
assert.equal(result.gateApplied,
|
|
1708
|
-
assert.deepEqual(result.keywords, ['
|
|
1781
|
+
assert.equal(result.gateApplied, true);
|
|
1782
|
+
assert.deepEqual(result.keywords, ['ralplan']);
|
|
1709
1783
|
}
|
|
1710
1784
|
finally {
|
|
1711
1785
|
await rm(cwd, { recursive: true, force: true });
|
|
1712
1786
|
}
|
|
1713
1787
|
});
|
|
1714
|
-
it('does not re-enter ralplan for a short approved
|
|
1788
|
+
it('does not re-enter ralplan for a short approved team follow-up with durable consensus', async () => {
|
|
1715
1789
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-followup-ko-'));
|
|
1716
1790
|
try {
|
|
1717
1791
|
const plansDir = join(cwd, '.omx', 'plans');
|
|
1792
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
1718
1793
|
await mkdir(plansDir, { recursive: true });
|
|
1794
|
+
await mkdir(stateDir, { recursive: true });
|
|
1719
1795
|
await writeFile(join(plansDir, 'prd-issue-831.md'), '# Approved plan\n\nLaunch hint: omx team 3:executor "Execute approved issue 831 plan"\n');
|
|
1720
1796
|
await writeFile(join(plansDir, 'test-spec-issue-831.md'), '# Test spec\n');
|
|
1797
|
+
await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
|
|
1798
|
+
current_phase: 'complete',
|
|
1799
|
+
planning_complete: true,
|
|
1800
|
+
ralplan_consensus_gate: {
|
|
1801
|
+
complete: true,
|
|
1802
|
+
sequence: ['architect-review', 'critic-review'],
|
|
1803
|
+
ralplan_architect_review: { agent_role: 'architect', verdict: 'approve', iteration: 1 },
|
|
1804
|
+
ralplan_critic_review: { agent_role: 'critic', verdict: 'approve', iteration: 1 },
|
|
1805
|
+
},
|
|
1806
|
+
}));
|
|
1721
1807
|
const result = applyRalplanGate(['team'], 'team으로 해줘', { cwd });
|
|
1722
1808
|
assert.equal(result.gateApplied, false);
|
|
1723
1809
|
assert.deepEqual(result.keywords, ['team']);
|
|
@@ -1726,13 +1812,25 @@ describe('applyRalplanGate', () => {
|
|
|
1726
1812
|
await rm(cwd, { recursive: true, force: true });
|
|
1727
1813
|
}
|
|
1728
1814
|
});
|
|
1729
|
-
it('does not re-enter ralplan for a short approved ralph follow-up', async () => {
|
|
1815
|
+
it('does not re-enter ralplan for a short approved ralph follow-up with durable consensus', async () => {
|
|
1730
1816
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-followup-ralph-'));
|
|
1731
1817
|
try {
|
|
1732
1818
|
const plansDir = join(cwd, '.omx', 'plans');
|
|
1819
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
1733
1820
|
await mkdir(plansDir, { recursive: true });
|
|
1821
|
+
await mkdir(stateDir, { recursive: true });
|
|
1734
1822
|
await writeFile(join(plansDir, 'prd-issue-832.md'), '# Approved plan\n\nLaunch hint: omx ralph "Execute approved issue 832 plan"\n');
|
|
1735
1823
|
await writeFile(join(plansDir, 'test-spec-issue-832.md'), '# Test spec\n');
|
|
1824
|
+
await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
|
|
1825
|
+
current_phase: 'complete',
|
|
1826
|
+
planning_complete: true,
|
|
1827
|
+
ralplan_consensus_gate: {
|
|
1828
|
+
complete: true,
|
|
1829
|
+
sequence: ['architect-review', 'critic-review'],
|
|
1830
|
+
ralplan_architect_review: { agent_role: 'architect', verdict: 'approve', iteration: 1 },
|
|
1831
|
+
ralplan_critic_review: { agent_role: 'critic', verdict: 'approve', iteration: 1 },
|
|
1832
|
+
},
|
|
1833
|
+
}));
|
|
1736
1834
|
const result = applyRalplanGate(['ralph'], 'ralph please', { cwd, priorSkill: 'ralplan' });
|
|
1737
1835
|
assert.equal(result.gateApplied, false);
|
|
1738
1836
|
assert.deepEqual(result.keywords, ['ralph']);
|
|
@@ -1741,6 +1839,63 @@ describe('applyRalplanGate', () => {
|
|
|
1741
1839
|
await rm(cwd, { recursive: true, force: true });
|
|
1742
1840
|
}
|
|
1743
1841
|
});
|
|
1842
|
+
it('ignores ambient OMX_ROOT consensus state for local PRD/test-spec-only follow-up gating', async () => {
|
|
1843
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-local-'));
|
|
1844
|
+
const ambientRoot = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-ambient-'));
|
|
1845
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1846
|
+
try {
|
|
1847
|
+
const plansDir = join(cwd, '.omx', 'plans');
|
|
1848
|
+
await mkdir(plansDir, { recursive: true });
|
|
1849
|
+
await writeFile(join(plansDir, 'prd-local.md'), '# Plan\n');
|
|
1850
|
+
await writeFile(join(plansDir, 'test-spec-local.md'), '# Test spec\n');
|
|
1851
|
+
const ambientStateDir = join(ambientRoot, '.omx', 'state');
|
|
1852
|
+
await mkdir(ambientStateDir, { recursive: true });
|
|
1853
|
+
await writeFile(join(ambientStateDir, 'ralplan-state.json'), JSON.stringify({
|
|
1854
|
+
current_phase: 'complete',
|
|
1855
|
+
planning_complete: true,
|
|
1856
|
+
ralplan_consensus_gate: {
|
|
1857
|
+
complete: true,
|
|
1858
|
+
ralplan_architect_review: { agent_role: 'architect', verdict: 'approve', iteration: 1 },
|
|
1859
|
+
ralplan_critic_review: { agent_role: 'critic', verdict: 'approve', iteration: 1 },
|
|
1860
|
+
},
|
|
1861
|
+
}));
|
|
1862
|
+
process.env.OMX_ROOT = ambientRoot;
|
|
1863
|
+
const result = applyRalplanGate(['team'], 'team', { cwd });
|
|
1864
|
+
assert.equal(result.gateApplied, true);
|
|
1865
|
+
assert.deepEqual(result.keywords, ['ralplan']);
|
|
1866
|
+
}
|
|
1867
|
+
finally {
|
|
1868
|
+
if (previousOmxRoot === undefined)
|
|
1869
|
+
delete process.env.OMX_ROOT;
|
|
1870
|
+
else
|
|
1871
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1872
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1873
|
+
await rm(ambientRoot, { recursive: true, force: true });
|
|
1874
|
+
}
|
|
1875
|
+
});
|
|
1876
|
+
it('gates short follow-up when local state only has latest verdict fields', async () => {
|
|
1877
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-keyword-gate-latest-only-'));
|
|
1878
|
+
try {
|
|
1879
|
+
const plansDir = join(cwd, '.omx', 'plans');
|
|
1880
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
1881
|
+
await mkdir(plansDir, { recursive: true });
|
|
1882
|
+
await mkdir(stateDir, { recursive: true });
|
|
1883
|
+
await writeFile(join(plansDir, 'prd-local.md'), '# Plan\n\nLaunch hint: omx team 3:executor "Execute approved local plan"\n');
|
|
1884
|
+
await writeFile(join(plansDir, 'test-spec-local.md'), '# Test spec\n');
|
|
1885
|
+
await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
|
|
1886
|
+
current_phase: 'complete',
|
|
1887
|
+
planning_complete: true,
|
|
1888
|
+
latest_architect_verdict: 'approve',
|
|
1889
|
+
latest_critic_verdict: 'approve',
|
|
1890
|
+
}));
|
|
1891
|
+
const result = applyRalplanGate(['team'], 'team', { cwd });
|
|
1892
|
+
assert.equal(result.gateApplied, true);
|
|
1893
|
+
assert.deepEqual(result.keywords, ['ralplan']);
|
|
1894
|
+
}
|
|
1895
|
+
finally {
|
|
1896
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1744
1899
|
it('redirects underspecified execution keywords to ralplan', () => {
|
|
1745
1900
|
const result = applyRalplanGate(['ralph'], 'ralph fix this');
|
|
1746
1901
|
assert.equal(result.gateApplied, true);
|