oh-my-codex 0.16.3 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +5 -5
- package/Cargo.toml +1 -1
- package/README.md +3 -3
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.js +27 -0
- package/dist/cli/__tests__/cleanup.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +101 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +131 -2
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +47 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +2 -2
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +272 -26
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +85 -3
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +1 -1
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +108 -0
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +69 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +54 -8
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/cleanup.d.ts.map +1 -1
- package/dist/cli/cleanup.js +8 -4
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +9 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -0
- package/dist/cli/codex-feature-probe.js +28 -0
- package/dist/cli/codex-feature-probe.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +152 -17
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +9 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +135 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +8 -8
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +3 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +88 -0
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +21 -0
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +4 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +7 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +5 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +114 -44
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +64 -5
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +2 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +12 -3
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
- package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
- package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
- package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +7 -0
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +70 -9
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +116 -11
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts +21 -0
- package/dist/config/codex-feature-flags.d.ts.map +1 -0
- package/dist/config/codex-feature-flags.js +56 -0
- package/dist/config/codex-feature-flags.js.map +1 -0
- package/dist/config/codex-hooks.d.ts +2 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +25 -3
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +11 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +221 -123
- package/dist/config/generator.js.map +1 -1
- package/dist/config/omx-first-party-mcp.d.ts +3 -1
- package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
- package/dist/config/omx-first-party-mcp.js +2 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
- package/dist/hooks/agents-overlay.js +2 -2
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +7 -5
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +164 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +61 -0
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +166 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +23 -2
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +22 -0
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +57 -26
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/artifacts.test.js +533 -4
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.js +524 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
- package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
- package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
- package/dist/planning/__tests__/markdown-structure.test.js +459 -0
- package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
- package/dist/planning/artifacts.d.ts +1 -1
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +227 -28
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +25 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -1
- package/dist/planning/context-pack-status.js +272 -31
- package/dist/planning/context-pack-status.js.map +1 -1
- package/dist/planning/markdown-structure.d.ts +20 -0
- package/dist/planning/markdown-structure.d.ts.map +1 -0
- package/dist/planning/markdown-structure.js +137 -0
- package/dist/planning/markdown-structure.js.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.js +121 -0
- package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
- package/dist/ralph/completion-audit.d.ts +8 -0
- package/dist/ralph/completion-audit.d.ts.map +1 -0
- package/dist/ralph/completion-audit.js +99 -0
- package/dist/ralph/completion-audit.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +220 -13
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +133 -54
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +4 -2
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +30 -1
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/notify-hook.js +3 -1
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +102 -27
- 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 +9 -3
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +7 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +25 -8
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +22 -15
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +3 -3
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +39 -0
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +5 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +497 -2
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +3 -0
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +43 -0
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +4 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +2 -6
- package/dist/team/state.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +124 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +44 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +197 -13
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/wiki/lifecycle.js +1 -1
- package/dist/wiki/lifecycle.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/.mcp.json +5 -5
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
- package/skills/analyze/SKILL.md +0 -2
- package/skills/ask-claude/SKILL.md +5 -3
- package/skills/ask-gemini/SKILL.md +5 -3
- package/skills/autopilot/SKILL.md +2 -2
- package/skills/code-review/SKILL.md +1 -3
- package/skills/deep-interview/SKILL.md +5 -7
- package/skills/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +4 -26
- package/skills/git-master/SKILL.md +2 -4
- package/skills/omx-setup/SKILL.md +3 -3
- package/skills/pipeline/SKILL.md +3 -3
- package/skills/plan/SKILL.md +3 -6
- package/skills/ralph/SKILL.md +9 -10
- package/skills/swarm/SKILL.md +5 -3
- package/skills/tdd/SKILL.md +95 -1
- package/skills/ultragoal/SKILL.md +36 -3
- package/skills/ultraqa/SKILL.md +21 -24
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +231 -13
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +160 -43
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +40 -1
- package/src/scripts/notify-hook.ts +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-audit.test.d.ts","sourceRoot":"","sources":["../../../src/ralph/__tests__/completion-audit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join, relative } from 'node:path';
|
|
4
|
+
import { test } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { evaluateRalphCompletionAuditEvidence } from '../completion-audit.js';
|
|
7
|
+
test('rejects absolute completion-audit paths', async () => {
|
|
8
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-absolute-'));
|
|
9
|
+
try {
|
|
10
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: '/etc/hosts' }, cwd);
|
|
11
|
+
assert.equal(result.complete, false);
|
|
12
|
+
assert.equal(result.reason, 'missing_completion_audit');
|
|
13
|
+
assert.equal(result.source, 'missing');
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
await rm(cwd, { recursive: true, force: true });
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
test('rejects non-JSON completion-audit artifacts', async () => {
|
|
20
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-non-json-'));
|
|
21
|
+
try {
|
|
22
|
+
await writeFile(join(cwd, 'audit.md'), 'passed with checklist and tests', 'utf-8');
|
|
23
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: 'audit.md' }, cwd);
|
|
24
|
+
assert.equal(result.complete, false);
|
|
25
|
+
assert.equal(result.reason, 'missing_completion_audit');
|
|
26
|
+
assert.equal(result.source, 'missing');
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(cwd, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
test('rejects completion-audit artifacts outside the workspace', async () => {
|
|
33
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-traversal-'));
|
|
34
|
+
const outside = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-outside-'));
|
|
35
|
+
try {
|
|
36
|
+
await writeFile(join(outside, 'audit.json'), JSON.stringify({
|
|
37
|
+
passed: true,
|
|
38
|
+
prompt_to_artifact_checklist: ['mapped'],
|
|
39
|
+
verification_evidence: ['tested'],
|
|
40
|
+
}), 'utf-8');
|
|
41
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: relative(cwd, join(outside, 'audit.json')) }, cwd);
|
|
42
|
+
assert.equal(result.complete, false);
|
|
43
|
+
assert.equal(result.reason, 'missing_completion_audit');
|
|
44
|
+
assert.equal(result.source, 'missing');
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await rm(cwd, { recursive: true, force: true });
|
|
48
|
+
await rm(outside, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
test('rejects completion-audit symlinks that resolve outside the workspace', async () => {
|
|
52
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-symlink-cwd-'));
|
|
53
|
+
const outside = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-symlink-outside-'));
|
|
54
|
+
try {
|
|
55
|
+
await writeFile(join(outside, 'audit.json'), JSON.stringify({
|
|
56
|
+
passed: true,
|
|
57
|
+
prompt_to_artifact_checklist: ['mapped'],
|
|
58
|
+
verification_evidence: ['tested'],
|
|
59
|
+
}), 'utf-8');
|
|
60
|
+
await symlink(join(outside, 'audit.json'), join(cwd, 'audit.json'));
|
|
61
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: 'audit.json' }, cwd);
|
|
62
|
+
assert.equal(result.complete, false);
|
|
63
|
+
assert.equal(result.reason, 'missing_completion_audit');
|
|
64
|
+
assert.equal(result.source, 'missing');
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await rm(cwd, { recursive: true, force: true });
|
|
68
|
+
await rm(outside, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
test('rejects malformed and empty completion-audit JSON artifacts', async () => {
|
|
72
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-invalid-json-'));
|
|
73
|
+
try {
|
|
74
|
+
await writeFile(join(cwd, 'empty.json'), '', 'utf-8');
|
|
75
|
+
await writeFile(join(cwd, 'invalid.json'), '{not json', 'utf-8');
|
|
76
|
+
for (const path of ['empty.json', 'invalid.json']) {
|
|
77
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: path }, cwd);
|
|
78
|
+
assert.equal(result.complete, false);
|
|
79
|
+
assert.equal(result.reason, 'missing_completion_audit');
|
|
80
|
+
assert.equal(result.source, 'missing');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await rm(cwd, { recursive: true, force: true });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
test('requires explicit passed=true in completion-audit evidence', async () => {
|
|
88
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-explicit-pass-'));
|
|
89
|
+
try {
|
|
90
|
+
await writeFile(join(cwd, 'audit.json'), JSON.stringify({
|
|
91
|
+
status: 'passed',
|
|
92
|
+
prompt_to_artifact_checklist: ['mapped'],
|
|
93
|
+
verification_evidence: ['tested'],
|
|
94
|
+
}), 'utf-8');
|
|
95
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: 'audit.json' }, cwd);
|
|
96
|
+
assert.equal(result.complete, false);
|
|
97
|
+
assert.equal(result.reason, 'completion_audit_not_passing');
|
|
98
|
+
assert.equal(result.source, 'artifact');
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await rm(cwd, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
test('accepts structured relative JSON completion-audit artifacts with evidence', async () => {
|
|
105
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ralph-audit-valid-json-'));
|
|
106
|
+
try {
|
|
107
|
+
await writeFile(join(cwd, 'audit.json'), JSON.stringify({
|
|
108
|
+
passed: true,
|
|
109
|
+
prompt_to_artifact_checklist: ['mapped prompt to artifact'],
|
|
110
|
+
verification_evidence: ['node --test dist/ralph/__tests__/completion-audit.test.js'],
|
|
111
|
+
}), 'utf-8');
|
|
112
|
+
const result = evaluateRalphCompletionAuditEvidence({ completion_audit_path: 'audit.json' }, cwd);
|
|
113
|
+
assert.equal(result.complete, true);
|
|
114
|
+
assert.equal(result.reason, 'completion_audit_passed');
|
|
115
|
+
assert.equal(result.source, 'artifact');
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await rm(cwd, { recursive: true, force: true });
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=completion-audit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-audit.test.js","sourceRoot":"","sources":["../../../src/ralph/__tests__/completion-audit.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,oCAAoC,EAAE,MAAM,wBAAwB,CAAC;AAE9E,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;IACzD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAElG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;IAC7D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,iCAAiC,EAAE,OAAO,CAAC,CAAC;QAEnF,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC;QAEhG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;IAC1E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,MAAM,SAAS,CACb,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAC3B,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,IAAI;YACZ,4BAA4B,EAAE,CAAC,QAAQ,CAAC;YACxC,qBAAqB,EAAE,CAAC,QAAQ,CAAC;SAClC,CAAC,EACF,OAAO,CACR,CAAC;QAEF,MAAM,MAAM,GAAG,oCAAoC,CACjD,EAAE,qBAAqB,EAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,EACrE,GAAG,CACJ,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;IACtF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,8BAA8B,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,kCAAkC,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC;QACH,MAAM,SAAS,CACb,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAC3B,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,IAAI;YACZ,4BAA4B,EAAE,CAAC,QAAQ,CAAC;YACxC,qBAAqB,EAAE,CAAC,QAAQ,CAAC;SAClC,CAAC,EACF,OAAO,CACR,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;QAEpE,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAElG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;IAC7E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,+BAA+B,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;QAEjE,KAAK,MAAM,IAAI,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAE1F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;IAC5E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAC,CAAC;IAC5E,IAAI,CAAC;QACH,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EACvB,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,QAAQ;YAChB,4BAA4B,EAAE,CAAC,QAAQ,CAAC;YACxC,qBAAqB,EAAE,CAAC,QAAQ,CAAC;SAClC,CAAC,EACF,OAAO,CACR,CAAC;QAEF,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAElG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;IAC3F,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,6BAA6B,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EACvB,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,IAAI;YACZ,4BAA4B,EAAE,CAAC,2BAA2B,CAAC;YAC3D,qBAAqB,EAAE,CAAC,2DAA2D,CAAC;SACrF,CAAC,EACF,OAAO,CACR,CAAC;QAEF,MAAM,MAAM,GAAG,oCAAoC,CAAC,EAAE,qBAAqB,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAElG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface RalphCompletionAuditResult {
|
|
2
|
+
complete: boolean;
|
|
3
|
+
reason: string;
|
|
4
|
+
source: 'state' | 'artifact' | 'missing';
|
|
5
|
+
}
|
|
6
|
+
export declare function evaluateRalphCompletionAuditEvidence(state: Record<string, unknown>, cwd: string): RalphCompletionAuditResult;
|
|
7
|
+
export declare function isRalphCompletePhase(value: unknown): boolean;
|
|
8
|
+
//# sourceMappingURL=completion-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-audit.d.ts","sourceRoot":"","sources":["../../src/ralph/completion-audit.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1C;AAgED,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,EAAE,MAAM,GACV,0BAA0B,CA+B5B;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG5D"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { extname, isAbsolute, relative, resolve } from 'node:path';
|
|
3
|
+
const JSON_EXTENSION = '.json';
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function safeString(value) {
|
|
8
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
9
|
+
}
|
|
10
|
+
function hasPassingVerdict(value) {
|
|
11
|
+
return value.passed === true;
|
|
12
|
+
}
|
|
13
|
+
function isInsideDirectory(parent, child) {
|
|
14
|
+
const childRelativePath = relative(parent, child);
|
|
15
|
+
return childRelativePath === '' || (!childRelativePath.startsWith('..') && !isAbsolute(childRelativePath));
|
|
16
|
+
}
|
|
17
|
+
function hasSubstantiveValue(value) {
|
|
18
|
+
if (typeof value === 'string')
|
|
19
|
+
return value.trim().length > 0;
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return value.length > 0;
|
|
22
|
+
if (isRecord(value))
|
|
23
|
+
return Object.keys(value).length > 0;
|
|
24
|
+
return value === true;
|
|
25
|
+
}
|
|
26
|
+
function readAuditArtifact(cwd, rawPath) {
|
|
27
|
+
const auditPath = safeString(rawPath);
|
|
28
|
+
if (!auditPath)
|
|
29
|
+
return null;
|
|
30
|
+
if (isAbsolute(auditPath))
|
|
31
|
+
return null;
|
|
32
|
+
const root = resolve(cwd);
|
|
33
|
+
const resolvedPath = resolve(root, auditPath);
|
|
34
|
+
if (!isInsideDirectory(root, resolvedPath))
|
|
35
|
+
return null;
|
|
36
|
+
if (!existsSync(resolvedPath))
|
|
37
|
+
return null;
|
|
38
|
+
if (extname(resolvedPath) !== JSON_EXTENSION)
|
|
39
|
+
return null;
|
|
40
|
+
const rootRealPath = realpathSync(root);
|
|
41
|
+
const artifactRealPath = realpathSync(resolvedPath);
|
|
42
|
+
if (!isInsideDirectory(rootRealPath, artifactRealPath))
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const content = readFileSync(resolvedPath, 'utf-8').trim();
|
|
46
|
+
if (!content)
|
|
47
|
+
return null;
|
|
48
|
+
const parsed = JSON.parse(content);
|
|
49
|
+
return isRecord(parsed) ? parsed : null;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function selectAuditCandidate(state, cwd) {
|
|
56
|
+
for (const key of ['completion_audit', 'completionAudit', 'completion_audit_evidence', 'completionAuditEvidence']) {
|
|
57
|
+
if (isRecord(state[key]))
|
|
58
|
+
return { audit: state[key], source: 'state' };
|
|
59
|
+
}
|
|
60
|
+
for (const key of ['completion_audit_path', 'completionAuditPath', 'completion_audit_evidence_path', 'completionAuditEvidencePath']) {
|
|
61
|
+
const artifact = readAuditArtifact(cwd, state[key]);
|
|
62
|
+
if (artifact)
|
|
63
|
+
return { audit: artifact, source: 'artifact' };
|
|
64
|
+
}
|
|
65
|
+
return { audit: null, source: 'missing' };
|
|
66
|
+
}
|
|
67
|
+
export function evaluateRalphCompletionAuditEvidence(state, cwd) {
|
|
68
|
+
const { audit, source } = selectAuditCandidate(state, cwd);
|
|
69
|
+
if (!audit) {
|
|
70
|
+
return { complete: false, reason: 'missing_completion_audit', source };
|
|
71
|
+
}
|
|
72
|
+
if (!hasPassingVerdict(audit)) {
|
|
73
|
+
return { complete: false, reason: 'completion_audit_not_passing', source };
|
|
74
|
+
}
|
|
75
|
+
const checklist = audit.prompt_to_artifact_checklist
|
|
76
|
+
?? audit.promptToArtifactChecklist
|
|
77
|
+
?? audit.checklist
|
|
78
|
+
?? audit.requirements_checklist
|
|
79
|
+
?? audit.requirementsChecklist;
|
|
80
|
+
if (!hasSubstantiveValue(checklist)) {
|
|
81
|
+
return { complete: false, reason: 'missing_completion_checklist', source };
|
|
82
|
+
}
|
|
83
|
+
const evidence = audit.verification_evidence
|
|
84
|
+
?? audit.verificationEvidence
|
|
85
|
+
?? audit.evidence
|
|
86
|
+
?? audit.validation_evidence
|
|
87
|
+
?? audit.validationEvidence
|
|
88
|
+
?? audit.commands
|
|
89
|
+
?? audit.tests;
|
|
90
|
+
if (!hasSubstantiveValue(evidence)) {
|
|
91
|
+
return { complete: false, reason: 'missing_verification_evidence', source };
|
|
92
|
+
}
|
|
93
|
+
return { complete: true, reason: 'completion_audit_passed', source };
|
|
94
|
+
}
|
|
95
|
+
export function isRalphCompletePhase(value) {
|
|
96
|
+
const phase = safeString(value).toLowerCase();
|
|
97
|
+
return phase === 'complete' || phase === 'completed';
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=completion-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-audit.js","sourceRoot":"","sources":["../../src/ralph/completion-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ import { writeSessionStart } from "../../hooks/session.js";
|
|
|
14
14
|
import { resetTriageConfigCache } from "../../hooks/triage-config.js";
|
|
15
15
|
import { executeStateOperation } from "../../state/operations.js";
|
|
16
16
|
import { OMX_TMUX_HUD_OWNER_ENV } from "../../hud/reconcile.js";
|
|
17
|
+
import { readAllState } from "../../hud/state.js";
|
|
17
18
|
import { writePage } from "../../wiki/storage.js";
|
|
18
19
|
import { WIKI_SCHEMA_VERSION } from "../../wiki/types.js";
|
|
19
20
|
function nativeHookScriptPath() {
|
|
@@ -183,7 +184,7 @@ describe("codex native hook config", () => {
|
|
|
183
184
|
"Stop",
|
|
184
185
|
]);
|
|
185
186
|
const sessionStart = config.hooks.SessionStart[0];
|
|
186
|
-
assert.equal(sessionStart.matcher, "startup|resume");
|
|
187
|
+
assert.equal(sessionStart.matcher, "startup|resume|clear");
|
|
187
188
|
assert.equal(sessionStart.hooks?.[0]?.statusMessage, undefined);
|
|
188
189
|
const preToolUse = config.hooks.PreToolUse[0];
|
|
189
190
|
assert.equal(preToolUse.matcher, "Bash");
|
|
@@ -962,7 +963,7 @@ describe("codex native hook dispatch", () => {
|
|
|
962
963
|
assert.equal(result.omxEventName, "keyword-detector");
|
|
963
964
|
assert.equal(result.skillState?.skill, "ralplan");
|
|
964
965
|
assert.ok(result.outputJson, "UserPromptSubmit should emit developer context");
|
|
965
|
-
assert.match(JSON.stringify(result.outputJson), /
|
|
966
|
+
assert.match(JSON.stringify(result.outputJson), /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
966
967
|
assert.equal(existsSync(join(cwd, ".omx", "state", "skill-active-state.json")), false, "session-scoped keyword activation should not write root skill-active-state.json");
|
|
967
968
|
const statePath = join(cwd, ".omx", "state", "sessions", "sess-1", "skill-active-state.json");
|
|
968
969
|
assert.equal(existsSync(statePath), true);
|
|
@@ -976,6 +977,114 @@ describe("codex native hook dispatch", () => {
|
|
|
976
977
|
await rm(cwd, { recursive: true, force: true });
|
|
977
978
|
}
|
|
978
979
|
});
|
|
980
|
+
it("records boxed keyword activation mode detail and skill state under OMX_ROOT", async () => {
|
|
981
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-boxed-"));
|
|
982
|
+
const cwd = join(root, "source");
|
|
983
|
+
const omxRoot = join(root, "box");
|
|
984
|
+
const sessionId = "sess-boxed-ralplan";
|
|
985
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
986
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
987
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
988
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
989
|
+
try {
|
|
990
|
+
await mkdir(cwd, { recursive: true });
|
|
991
|
+
process.env.OMX_ROOT = omxRoot;
|
|
992
|
+
delete process.env.OMX_STATE_ROOT;
|
|
993
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
994
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
995
|
+
const result = await dispatchCodexNativeHook({
|
|
996
|
+
hook_event_name: "UserPromptSubmit",
|
|
997
|
+
cwd,
|
|
998
|
+
session_id: sessionId,
|
|
999
|
+
thread_id: "thread-boxed",
|
|
1000
|
+
turn_id: "turn-boxed",
|
|
1001
|
+
prompt: "$ralplan implement issue #1307",
|
|
1002
|
+
}, { cwd });
|
|
1003
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1004
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1005
|
+
const boxedSessionDir = join(omxRoot, ".omx", "state", "sessions", sessionId);
|
|
1006
|
+
assert.equal(existsSync(join(boxedSessionDir, "skill-active-state.json")), true);
|
|
1007
|
+
assert.equal(existsSync(join(boxedSessionDir, "ralplan-state.json")), true);
|
|
1008
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1009
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1010
|
+
const hudState = await readAllState(cwd);
|
|
1011
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1012
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
if (typeof previousOmxRoot === "string")
|
|
1016
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1017
|
+
else
|
|
1018
|
+
delete process.env.OMX_ROOT;
|
|
1019
|
+
if (typeof previousOmxStateRoot === "string")
|
|
1020
|
+
process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1021
|
+
else
|
|
1022
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1023
|
+
if (typeof previousTeamStateRoot === "string")
|
|
1024
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1025
|
+
else
|
|
1026
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1027
|
+
if (typeof previousOmxSessionId === "string")
|
|
1028
|
+
process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1029
|
+
else
|
|
1030
|
+
delete process.env.OMX_SESSION_ID;
|
|
1031
|
+
await rm(root, { recursive: true, force: true });
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
it("records native keyword activation mode detail and skill state under OMX_TEAM_STATE_ROOT", async () => {
|
|
1035
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-team-root-"));
|
|
1036
|
+
const cwd = join(root, "source");
|
|
1037
|
+
const teamStateRoot = join(root, "team-state");
|
|
1038
|
+
const sessionId = "sess-team-root-ralplan";
|
|
1039
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1040
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
1041
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
1042
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
1043
|
+
try {
|
|
1044
|
+
await mkdir(cwd, { recursive: true });
|
|
1045
|
+
delete process.env.OMX_ROOT;
|
|
1046
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1047
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
1048
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
1049
|
+
const result = await dispatchCodexNativeHook({
|
|
1050
|
+
hook_event_name: "UserPromptSubmit",
|
|
1051
|
+
cwd,
|
|
1052
|
+
session_id: sessionId,
|
|
1053
|
+
thread_id: "thread-team-root",
|
|
1054
|
+
turn_id: "turn-team-root",
|
|
1055
|
+
prompt: "$ralplan implement issue #1307",
|
|
1056
|
+
}, { cwd });
|
|
1057
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1058
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1059
|
+
const teamSessionDir = join(teamStateRoot, "sessions", sessionId);
|
|
1060
|
+
assert.equal(existsSync(join(teamSessionDir, "skill-active-state.json")), true);
|
|
1061
|
+
assert.equal(existsSync(join(teamSessionDir, "ralplan-state.json")), true);
|
|
1062
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1063
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1064
|
+
const hudState = await readAllState(cwd);
|
|
1065
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1066
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1067
|
+
}
|
|
1068
|
+
finally {
|
|
1069
|
+
if (typeof previousOmxRoot === "string")
|
|
1070
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1071
|
+
else
|
|
1072
|
+
delete process.env.OMX_ROOT;
|
|
1073
|
+
if (typeof previousOmxStateRoot === "string")
|
|
1074
|
+
process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1075
|
+
else
|
|
1076
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1077
|
+
if (typeof previousTeamStateRoot === "string")
|
|
1078
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1079
|
+
else
|
|
1080
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1081
|
+
if (typeof previousOmxSessionId === "string")
|
|
1082
|
+
process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1083
|
+
else
|
|
1084
|
+
delete process.env.OMX_SESSION_ID;
|
|
1085
|
+
await rm(root, { recursive: true, force: true });
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
979
1088
|
it("warns completion-like prompts when active goal workflows need Codex snapshot reconciliation", async () => {
|
|
980
1089
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-goal-warning-"));
|
|
981
1090
|
try {
|
|
@@ -1188,7 +1297,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1188
1297
|
assert.equal(result.skillState?.skill, "ralplan");
|
|
1189
1298
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1190
1299
|
assert.match(message, /\$oh-my-codex:ralplan" -> ralplan/);
|
|
1191
|
-
assert.match(message, /
|
|
1300
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1192
1301
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-plugin-1", "ralplan-state.json")), true);
|
|
1193
1302
|
}
|
|
1194
1303
|
finally {
|
|
@@ -1362,7 +1471,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1362
1471
|
assert.equal(result.skillState?.skill, "ralph");
|
|
1363
1472
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1364
1473
|
assert.match(message, /\$ralph" -> ralph/);
|
|
1365
|
-
assert.match(message, /
|
|
1474
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1366
1475
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1367
1476
|
assert.match(message, /Use `omx ralph --prd \.\.\.` only when you explicitly want the PRD-gated CLI startup path\./);
|
|
1368
1477
|
}
|
|
@@ -1386,7 +1495,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1386
1495
|
assert.equal(result.skillState?.skill, "ralph");
|
|
1387
1496
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1388
1497
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
1389
|
-
assert.match(message, /
|
|
1498
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1390
1499
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1391
1500
|
}
|
|
1392
1501
|
finally {
|
|
@@ -1455,7 +1564,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1455
1564
|
assert.equal(result.skillState?.skill, "deep-interview");
|
|
1456
1565
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1457
1566
|
assert.match(message, /\$deep-interview" -> deep-interview/);
|
|
1458
|
-
assert.match(message, /
|
|
1567
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1459
1568
|
assert.match(message, /Deep-interview is active, but this session is not attached to tmux/);
|
|
1460
1569
|
assert.match(message, /Do not invoke `omx question`, `omx hud`, or `omx team`/);
|
|
1461
1570
|
assert.match(message, /native structured question tool when available/);
|
|
@@ -1845,8 +1954,11 @@ export async function onHookEvent(event) {
|
|
|
1845
1954
|
}, { cwd });
|
|
1846
1955
|
assert.match(JSON.stringify(denied.outputJson), /denied workflow keyword/i);
|
|
1847
1956
|
assert.match(JSON.stringify(denied.outputJson), /Unsupported workflow overlap: team \+ autopilot\./);
|
|
1848
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
1849
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
1957
|
+
assert.match(JSON.stringify(denied.outputJson), /omx state clear --input/);
|
|
1958
|
+
assert.match(JSON.stringify(denied.outputJson), /mode\\":\\"<mode>/);
|
|
1959
|
+
assert.match(JSON.stringify(denied.outputJson), /--json/);
|
|
1960
|
+
assert.match(JSON.stringify(denied.outputJson), /explicit MCP compatibility is enabled/);
|
|
1961
|
+
assert.match(JSON.stringify(denied.outputJson), /`omx_state\.\*` tools/);
|
|
1850
1962
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-deny-1", "autopilot-state.json")), false);
|
|
1851
1963
|
}
|
|
1852
1964
|
finally {
|
|
@@ -1905,7 +2017,7 @@ export async function onHookEvent(event) {
|
|
|
1905
2017
|
assert.match(message, /\$ralph" -> ralph/);
|
|
1906
2018
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
1907
2019
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
1908
|
-
assert.match(message, /
|
|
2020
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1909
2021
|
assert.doesNotMatch(message, /Use the durable OMX team runtime via `omx team \.\.\.`/);
|
|
1910
2022
|
}
|
|
1911
2023
|
finally {
|
|
@@ -1930,7 +2042,7 @@ export async function onHookEvent(event) {
|
|
|
1930
2042
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
1931
2043
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
1932
2044
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
1933
|
-
assert.match(message, /
|
|
2045
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1934
2046
|
}
|
|
1935
2047
|
finally {
|
|
1936
2048
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -3700,7 +3812,7 @@ exit 0
|
|
|
3700
3812
|
assert.equal(output?.decision, "block");
|
|
3701
3813
|
assert.equal(output?.reason, "The MCP tool appears to have lost its transport/server connection. Preserve state, debug the transport failure, and use OMX CLI/file-backed fallbacks instead of retrying blindly.");
|
|
3702
3814
|
const additionalContext = String(output?.hookSpecificOutput?.additionalContext ?? "");
|
|
3703
|
-
assert.match(additionalContext, /omx state
|
|
3815
|
+
assert.match(additionalContext, /omx state write --input/);
|
|
3704
3816
|
assert.match(additionalContext, /plain Node stdio processes/i);
|
|
3705
3817
|
assert.match(additionalContext, /read-stall-state/);
|
|
3706
3818
|
assert.match(additionalContext, /OMX_MCP_TRANSPORT_DEBUG=1/);
|
|
@@ -3870,7 +3982,7 @@ exit 0
|
|
|
3870
3982
|
assert.match(String(result.outputJson?.reason || ""), /lost its transport\/server connection/);
|
|
3871
3983
|
const hookSpecificOutput = result.outputJson?.hookSpecificOutput;
|
|
3872
3984
|
assert.equal(hookSpecificOutput?.hookEventName, "PostToolUse");
|
|
3873
|
-
assert.match(String(hookSpecificOutput?.additionalContext || ""), /Retry via CLI parity with `omx state
|
|
3985
|
+
assert.match(String(hookSpecificOutput?.additionalContext || ""), /Retry via CLI parity with `omx state write --input '\{\}' --json`\./);
|
|
3874
3986
|
assert.match(String(hookSpecificOutput?.additionalContext || ""), /omx team api read-stall-state/);
|
|
3875
3987
|
const phase = JSON.parse(await readFile(join(cwd, ".omx", "state", "team", "mcp-transport-dead-team", "phase.json"), "utf-8"));
|
|
3876
3988
|
assert.equal(phase.current_phase, "failed");
|
|
@@ -3928,7 +4040,7 @@ exit 0
|
|
|
3928
4040
|
reason: "The MCP tool appears to have lost its transport/server connection. Preserve state, debug the transport failure, and use OMX CLI/file-backed fallbacks instead of retrying blindly.",
|
|
3929
4041
|
hookSpecificOutput: {
|
|
3930
4042
|
hookEventName: "PostToolUse",
|
|
3931
|
-
additionalContext: "Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state
|
|
4043
|
+
additionalContext: "Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state write --input '{\"mode\":\"team\",\"active\":true}' --json`. OMX MCP servers are plain Node stdio processes, so they still shut down when stdin/transport closes. If this happened during team runtime, inspect first with `omx team status <team>` or `omx team api read-stall-state --input '{\"team_name\":\"<team>\"}' --json`, and only force cleanup after capturing needed state. For root-cause debugging, rerun with `OMX_MCP_TRANSPORT_DEBUG=1` to log why the stdio transport closed.",
|
|
3932
4044
|
},
|
|
3933
4045
|
});
|
|
3934
4046
|
const phase = await readTeamPhase("transport-team", cwd);
|
|
@@ -5093,6 +5205,38 @@ exit 0
|
|
|
5093
5205
|
await rm(cwd, { recursive: true, force: true });
|
|
5094
5206
|
}
|
|
5095
5207
|
});
|
|
5208
|
+
it("ignores stale source-root team Stop fallback when OMX_TEAM_STATE_ROOT is authoritative", async () => {
|
|
5209
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-stale-source-root-"));
|
|
5210
|
+
const teamStateRoot = join(cwd, "shared-team-state");
|
|
5211
|
+
const priorTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
5212
|
+
try {
|
|
5213
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
5214
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
5215
|
+
await mkdir(join(teamStateRoot, "team", "stale-source-team"), { recursive: true });
|
|
5216
|
+
await writeJson(join(cwd, ".omx", "state", "team-state.json"), {
|
|
5217
|
+
active: true,
|
|
5218
|
+
team_name: "stale-source-team",
|
|
5219
|
+
current_phase: "team-exec",
|
|
5220
|
+
});
|
|
5221
|
+
await writeJson(join(teamStateRoot, "team", "stale-source-team", "phase.json"), {
|
|
5222
|
+
current_phase: "team-exec",
|
|
5223
|
+
});
|
|
5224
|
+
const result = await dispatchCodexNativeHook({
|
|
5225
|
+
hook_event_name: "Stop",
|
|
5226
|
+
cwd,
|
|
5227
|
+
session_id: "sess-stale-source-team",
|
|
5228
|
+
}, { cwd });
|
|
5229
|
+
assert.equal(result.omxEventName, "stop");
|
|
5230
|
+
assert.equal(result.outputJson, null);
|
|
5231
|
+
}
|
|
5232
|
+
finally {
|
|
5233
|
+
if (typeof priorTeamStateRoot === "string")
|
|
5234
|
+
process.env.OMX_TEAM_STATE_ROOT = priorTeamStateRoot;
|
|
5235
|
+
else
|
|
5236
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
5237
|
+
await rm(cwd, { recursive: true, force: true });
|
|
5238
|
+
}
|
|
5239
|
+
});
|
|
5096
5240
|
it("returns Stop continuation output from canonical team state rooted via OMX_TEAM_STATE_ROOT", async () => {
|
|
5097
5241
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-env-root-"));
|
|
5098
5242
|
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
@@ -5984,6 +6128,69 @@ exit 0
|
|
|
5984
6128
|
await rm(cwd, { recursive: true, force: true });
|
|
5985
6129
|
}
|
|
5986
6130
|
});
|
|
6131
|
+
it("blocks Codex App Stop when Ralph is marked complete without completion-audit evidence", async () => {
|
|
6132
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-missing-"));
|
|
6133
|
+
try {
|
|
6134
|
+
const sessionId = "sess-ralph-complete-missing";
|
|
6135
|
+
const statePath = join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json");
|
|
6136
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
6137
|
+
await writeJson(statePath, {
|
|
6138
|
+
active: false,
|
|
6139
|
+
mode: "ralph",
|
|
6140
|
+
current_phase: "complete",
|
|
6141
|
+
session_id: sessionId,
|
|
6142
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
6143
|
+
});
|
|
6144
|
+
const result = await dispatchCodexNativeHook({
|
|
6145
|
+
hook_event_name: "Stop",
|
|
6146
|
+
cwd,
|
|
6147
|
+
session_id: sessionId,
|
|
6148
|
+
last_assistant_message: "Done. Ralph complete.",
|
|
6149
|
+
}, { cwd });
|
|
6150
|
+
assert.equal(result.omxEventName, "stop");
|
|
6151
|
+
assert.match(String(result.outputJson?.reason), /Ralph completion audit is missing required evidence/);
|
|
6152
|
+
assert.equal(result.outputJson?.stopReason, "ralph_completion_audit_missing_completion_audit");
|
|
6153
|
+
const reopened = JSON.parse(await readFile(statePath, "utf-8"));
|
|
6154
|
+
assert.equal(reopened.active, true);
|
|
6155
|
+
assert.equal(reopened.current_phase, "verifying");
|
|
6156
|
+
assert.equal(reopened.completion_audit_gate, "blocked");
|
|
6157
|
+
assert.equal(reopened.completion_audit_missing_reason, "missing_completion_audit");
|
|
6158
|
+
assert.equal(typeof reopened.completed_at, "undefined");
|
|
6159
|
+
}
|
|
6160
|
+
finally {
|
|
6161
|
+
await rm(cwd, { recursive: true, force: true });
|
|
6162
|
+
}
|
|
6163
|
+
});
|
|
6164
|
+
it("allows Codex App Stop when complete Ralph state carries checklist and verification evidence", async () => {
|
|
6165
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-present-"));
|
|
6166
|
+
try {
|
|
6167
|
+
const sessionId = "sess-ralph-complete-present";
|
|
6168
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
6169
|
+
await writeJson(join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json"), {
|
|
6170
|
+
active: false,
|
|
6171
|
+
mode: "ralph",
|
|
6172
|
+
current_phase: "complete",
|
|
6173
|
+
session_id: sessionId,
|
|
6174
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
6175
|
+
completion_audit: {
|
|
6176
|
+
passed: true,
|
|
6177
|
+
prompt_to_artifact_checklist: ["issue #2260 fixed", "tests added"],
|
|
6178
|
+
verification_evidence: ["node --test dist/scripts/__tests__/codex-native-hook.test.js"],
|
|
6179
|
+
},
|
|
6180
|
+
});
|
|
6181
|
+
const result = await dispatchCodexNativeHook({
|
|
6182
|
+
hook_event_name: "Stop",
|
|
6183
|
+
cwd,
|
|
6184
|
+
session_id: sessionId,
|
|
6185
|
+
last_assistant_message: "Done with completion audit evidence recorded.",
|
|
6186
|
+
}, { cwd });
|
|
6187
|
+
assert.equal(result.omxEventName, "stop");
|
|
6188
|
+
assert.equal(result.outputJson, null);
|
|
6189
|
+
}
|
|
6190
|
+
finally {
|
|
6191
|
+
await rm(cwd, { recursive: true, force: true });
|
|
6192
|
+
}
|
|
6193
|
+
});
|
|
5987
6194
|
it("returns Stop continuation output while Ralph is active without an explicit session pin", async () => {
|
|
5988
6195
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-"));
|
|
5989
6196
|
try {
|