oh-my-codex 0.20.3 → 0.21.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 +35 -18
- package/Cargo.toml +1 -1
- package/README.md +22 -19
- package/crates/omx-runtime/Cargo.toml +3 -0
- package/crates/omx-runtime/src/main.rs +390 -0
- package/crates/omx-runtime/tests/execution.rs +264 -0
- package/dist/adapt/__tests__/herdr-target.test.d.ts +2 -0
- package/dist/adapt/__tests__/herdr-target.test.d.ts.map +1 -0
- package/dist/adapt/__tests__/herdr-target.test.js +72 -0
- package/dist/adapt/__tests__/herdr-target.test.js.map +1 -0
- package/dist/adapt/contracts.d.ts +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/adapt/contracts.js +1 -1
- package/dist/adapt/contracts.js.map +1 -1
- package/dist/adapt/herdr/__tests__/authority.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/authority.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/authority.test.js +49 -0
- package/dist/adapt/herdr/__tests__/authority.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js +176 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js +45 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js +130 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js +54 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js +104 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js +46 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.js +160 -0
- package/dist/adapt/herdr/__tests__/transport.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js +118 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js.map +1 -0
- package/dist/adapt/herdr/authority.d.ts +34 -0
- package/dist/adapt/herdr/authority.d.ts.map +1 -0
- package/dist/adapt/herdr/authority.js +71 -0
- package/dist/adapt/herdr/authority.js.map +1 -0
- package/dist/adapt/herdr/bridge.d.ts +84 -0
- package/dist/adapt/herdr/bridge.d.ts.map +1 -0
- package/dist/adapt/herdr/bridge.js +222 -0
- package/dist/adapt/herdr/bridge.js.map +1 -0
- package/dist/adapt/herdr/sanitize.d.ts +20 -0
- package/dist/adapt/herdr/sanitize.d.ts.map +1 -0
- package/dist/adapt/herdr/sanitize.js +70 -0
- package/dist/adapt/herdr/sanitize.js.map +1 -0
- package/dist/adapt/herdr/semantic.d.ts +67 -0
- package/dist/adapt/herdr/semantic.d.ts.map +1 -0
- package/dist/adapt/herdr/semantic.js +170 -0
- package/dist/adapt/herdr/semantic.js.map +1 -0
- package/dist/adapt/herdr/seq-store.d.ts +32 -0
- package/dist/adapt/herdr/seq-store.d.ts.map +1 -0
- package/dist/adapt/herdr/seq-store.js +126 -0
- package/dist/adapt/herdr/seq-store.js.map +1 -0
- package/dist/adapt/herdr/team-map.d.ts +30 -0
- package/dist/adapt/herdr/team-map.d.ts.map +1 -0
- package/dist/adapt/herdr/team-map.js +37 -0
- package/dist/adapt/herdr/team-map.js.map +1 -0
- package/dist/adapt/herdr/transport.d.ts +115 -0
- package/dist/adapt/herdr/transport.d.ts.map +1 -0
- package/dist/adapt/herdr/transport.js +260 -0
- package/dist/adapt/herdr/transport.js.map +1 -0
- package/dist/adapt/herdr/wiring.d.ts +24 -0
- package/dist/adapt/herdr/wiring.d.ts.map +1 -0
- package/dist/adapt/herdr/wiring.js +62 -0
- package/dist/adapt/herdr/wiring.js.map +1 -0
- package/dist/adapt/herdr.d.ts +19 -0
- package/dist/adapt/herdr.d.ts.map +1 -0
- package/dist/adapt/herdr.js +115 -0
- package/dist/adapt/herdr.js.map +1 -0
- package/dist/adapt/index.d.ts +4 -0
- package/dist/adapt/index.d.ts.map +1 -1
- package/dist/adapt/index.js +48 -0
- package/dist/adapt/index.js.map +1 -1
- package/dist/adapt/registry.d.ts.map +1 -1
- package/dist/adapt/registry.js +11 -0
- package/dist/adapt/registry.js.map +1 -1
- package/dist/agents/__tests__/definitions.test.js +0 -27
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +3 -8
- 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 +0 -41
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/policy.d.ts.map +1 -1
- package/dist/agents/policy.js +0 -1
- package/dist/agents/policy.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.js +60 -1
- package/dist/auth/__tests__/hotswap.test.js.map +1 -1
- package/dist/auth/__tests__/storage.test.js +33 -1
- package/dist/auth/__tests__/storage.test.js.map +1 -1
- package/dist/auth/hotswap.d.ts +16 -2
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +22 -7
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/storage.js +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/completion-gate-advisory.test.d.ts +2 -0
- package/dist/autopilot/__tests__/completion-gate-advisory.test.d.ts.map +1 -0
- package/dist/autopilot/__tests__/completion-gate-advisory.test.js +383 -0
- package/dist/autopilot/__tests__/completion-gate-advisory.test.js.map +1 -0
- package/dist/autopilot/completion-gate.d.ts +6 -1
- package/dist/autopilot/completion-gate.d.ts.map +1 -1
- package/dist/autopilot/completion-gate.js +247 -7
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/catalog/__tests__/generator.test.js +15 -10
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +13 -7
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
- package/dist/catalog/__tests__/schema.test.js +3 -5
- package/dist/catalog/__tests__/schema.test.js.map +1 -1
- package/dist/catalog/schema.js +1 -1
- package/dist/catalog/schema.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js +4 -23
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js +61 -24
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +3 -1
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autopilot.test.d.ts +2 -0
- package/dist/cli/__tests__/autopilot.test.d.ts.map +1 -0
- package/dist/cli/__tests__/autopilot.test.js +143 -0
- package/dist/cli/__tests__/autopilot.test.js.map +1 -0
- package/dist/cli/__tests__/codex-feature-probe.test.js +66 -1
- package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +76 -4
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts +2 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts.map +1 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js +473 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js +103 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js +206 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-team.test.js +85 -0
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +38 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +75 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +621 -460
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +1125 -143
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +4 -3
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-assets.test.js +398 -16
- package/dist/cli/__tests__/native-assets.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +53 -5
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +5 -8
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js +4 -18
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +4 -30
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +4 -15
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +2 -2
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +57 -57
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js +56 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +131 -14
- package/dist/cli/__tests__/ralplan.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +1153 -43
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +65 -3
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +57 -55
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +34 -0
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +258 -26
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +3 -6
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +180 -21
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +93 -41
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +45 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +161 -2
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +73 -28
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +749 -177
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +32 -2
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/api.d.ts.map +1 -1
- package/dist/cli/api.js +9 -10
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/autopilot.d.ts +8 -0
- package/dist/cli/autopilot.d.ts.map +1 -0
- package/dist/cli/autopilot.js +160 -0
- package/dist/cli/autopilot.js.map +1 -0
- package/dist/cli/codex-feature-probe.d.ts +16 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +44 -0
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +7 -4
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +29 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +433 -19
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +231 -12
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2354 -724
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.d.ts.map +1 -1
- package/dist/cli/mcp-parity.js +7 -3
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/native-assets.d.ts +26 -1
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +448 -51
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +8 -4
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +30 -8
- package/dist/cli/native-hook-claim-journal.js.map +1 -1
- package/dist/cli/package-manager-ownership.d.ts +69 -0
- package/dist/cli/package-manager-ownership.d.ts.map +1 -0
- package/dist/cli/package-manager-ownership.js +338 -0
- package/dist/cli/package-manager-ownership.js.map +1 -0
- 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 +123 -55
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.js +2 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +6 -2
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +134 -34
- package/dist/cli/ralplan.js.map +1 -1
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +38 -1
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +15 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +27 -1
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +6 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +425 -215
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +52 -9
- package/dist/cli/sparkshell.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 +10 -7
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +27 -28
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update-worker.d.ts +2 -0
- package/dist/cli/update-worker.d.ts.map +1 -0
- package/dist/cli/update-worker.js +142 -0
- package/dist/cli/update-worker.js.map +1 -0
- package/dist/cli/update.d.ts +16 -23
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +212 -241
- package/dist/cli/update.js.map +1 -1
- package/dist/compat/__tests__/upgrade-from-0-20.test.d.ts +2 -0
- package/dist/compat/__tests__/upgrade-from-0-20.test.d.ts.map +1 -0
- package/dist/compat/__tests__/upgrade-from-0-20.test.js +109 -0
- package/dist/compat/__tests__/upgrade-from-0-20.test.js.map +1 -0
- package/dist/compat/upgrade-from-0-20.d.ts +64 -0
- package/dist/compat/upgrade-from-0-20.d.ts.map +1 -0
- package/dist/compat/upgrade-from-0-20.js +276 -0
- package/dist/compat/upgrade-from-0-20.js.map +1 -0
- package/dist/config/__tests__/generator-idempotent.test.js +173 -29
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +3 -1
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +25 -3
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +113 -35
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +25 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +2 -0
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +3 -1
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js +24 -31
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +66 -135
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +47 -106
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js +16 -18
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +2 -14
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +56 -234
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +1 -3
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js +18 -16
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +24 -20
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts +2 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js +164 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js.map +1 -0
- package/dist/hooks/__tests__/issue-3497-hook-simplification.test.d.ts +2 -0
- package/dist/hooks/__tests__/issue-3497-hook-simplification.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/issue-3497-hook-simplification.test.js +169 -0
- package/dist/hooks/__tests__/issue-3497-hook-simplification.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +226 -858
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +176 -14
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +1 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +33 -21
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +27 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +10 -118
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +14 -904
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +7 -0
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +5 -5
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +7 -7
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +11 -8
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +7 -6
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +2 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +1 -0
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js +19 -21
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +23 -3
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +23 -28
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js +9 -8
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +3656 -656
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +13 -22
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +3 -13
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/sunset-routing-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/sunset-routing-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/sunset-routing-contract.test.js +172 -0
- package/dist/hooks/__tests__/sunset-routing-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +2 -2
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/tmux-hook-engine.test.js +18 -3
- package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js +20 -17
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js +17 -18
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +1 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +108 -2
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js +151 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +20 -3
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner.js +1 -0
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
- package/dist/hooks/extensibility/runtime.js.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.js +2 -2
- package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.js +55 -15
- package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -1
- package/dist/hooks/extensibility/sdk.d.ts +1 -0
- package/dist/hooks/extensibility/sdk.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk.js +1 -1
- package/dist/hooks/extensibility/sdk.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +7 -0
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +6 -47
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +156 -268
- 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 +14 -26
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/native/capability-warnings.d.ts +16 -0
- package/dist/hooks/native/capability-warnings.d.ts.map +1 -0
- package/dist/hooks/native/capability-warnings.js +40 -0
- package/dist/hooks/native/capability-warnings.js.map +1 -0
- package/dist/hooks/native/index.d.ts +17 -0
- package/dist/hooks/native/index.d.ts.map +1 -0
- package/dist/hooks/native/index.js +17 -0
- package/dist/hooks/native/index.js.map +1 -0
- package/dist/hooks/native/pre-tool-use-advisory.d.ts +17 -0
- package/dist/hooks/native/pre-tool-use-advisory.d.ts.map +1 -0
- package/dist/hooks/native/pre-tool-use-advisory.js +112 -0
- package/dist/hooks/native/pre-tool-use-advisory.js.map +1 -0
- package/dist/hooks/native/types.d.ts +30 -0
- package/dist/hooks/native/types.d.ts.map +1 -0
- package/dist/hooks/native/types.js +22 -0
- package/dist/hooks/native/types.js.map +1 -0
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +46 -93
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/session.d.ts +197 -18
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1939 -271
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/sunset-stub.d.ts +17 -0
- package/dist/hooks/sunset-stub.d.ts.map +1 -0
- package/dist/hooks/sunset-stub.js +125 -0
- package/dist/hooks/sunset-stub.js.map +1 -0
- package/dist/hud/__tests__/hud-tmux-injection.test.js +6 -6
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +26 -16
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +83 -78
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +36 -31
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux-split-realtmux.test.d.ts +2 -0
- package/dist/hud/__tests__/tmux-split-realtmux.test.d.ts.map +1 -0
- package/dist/hud/__tests__/tmux-split-realtmux.test.js +112 -0
- package/dist/hud/__tests__/tmux-split-realtmux.test.js.map +1 -0
- package/dist/hud/__tests__/tmux.test.js +217 -198
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/tmux.d.ts +43 -4
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +1025 -139
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +71 -34
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +1 -6
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +25 -24
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/hermes-bridge.test.js +17 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +4 -4
- package/dist/mcp/__tests__/state-paths.test.js +735 -4
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server-ralph-phase.test.js +29 -4
- package/dist/mcp/__tests__/state-server-ralph-phase.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server-schema.test.js +13 -3
- package/dist/mcp/__tests__/state-server-schema.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +11 -1033
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/trace-server.test.js +2 -2
- package/dist/mcp/__tests__/trace-server.test.js.map +1 -1
- package/dist/mcp/hermes-bridge.d.ts.map +1 -1
- package/dist/mcp/hermes-bridge.js +2 -2
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +78 -4
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +543 -40
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +68 -97
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +116 -67
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/__tests__/base-autopilot-gates.test.js +1 -168
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js +1 -85
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js +1 -35
- package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +10 -158
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/base.d.ts +6 -6
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +116 -90
- package/dist/modes/base.js.map +1 -1
- package/dist/native-assets/archive.d.ts +17 -0
- package/dist/native-assets/archive.d.ts.map +1 -0
- package/dist/native-assets/archive.js +238 -0
- package/dist/native-assets/archive.js.map +1 -0
- package/dist/native-assets/policy.d.ts +42 -0
- package/dist/native-assets/policy.d.ts.map +1 -0
- package/dist/native-assets/policy.js +155 -0
- package/dist/native-assets/policy.js.map +1 -0
- package/dist/notifications/__tests__/formatter.test.js +8 -0
- package/dist/notifications/__tests__/formatter.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js +8 -0
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/formatter.js +1 -1
- package/dist/notifications/formatter.js.map +1 -1
- package/dist/notifications/template-engine.js +1 -1
- package/dist/notifications/template-engine.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +0 -21
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/question/autopilot-wait.d.ts.map +1 -1
- package/dist/question/autopilot-wait.js +2 -2
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/deep-interview.d.ts +1 -2
- package/dist/question/deep-interview.d.ts.map +1 -1
- package/dist/question/deep-interview.js +4 -4
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +328 -39
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +56 -821
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +15 -8
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -1
- package/dist/ralplan/documented-leader-preflight.js +356 -54
- package/dist/ralplan/documented-leader-preflight.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +2 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +145 -163
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +45 -0
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/run-state.d.ts +5 -1
- package/dist/runtime/run-state.d.ts.map +1 -1
- package/dist/runtime/run-state.js +15 -8
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +12490 -19414
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/docs-site-contract.test.js +2 -2
- package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -1
- package/dist/scripts/__tests__/generated-artifact-drift.test.d.ts +2 -0
- package/dist/scripts/__tests__/generated-artifact-drift.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/generated-artifact-drift.test.js +84 -0
- package/dist/scripts/__tests__/generated-artifact-drift.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js +235 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js +188 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js +207 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js +156 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js +191 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js +40 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3481-conductor-deadlock.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3481-conductor-deadlock.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3481-conductor-deadlock.test.js +63 -0
- package/dist/scripts/__tests__/issue-3481-conductor-deadlock.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3486-pretooluse-lock-regression.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3486-pretooluse-lock-regression.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3486-pretooluse-lock-regression.test.js +65 -0
- package/dist/scripts/__tests__/issue-3486-pretooluse-lock-regression.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3536-external-team-state-root.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3536-external-team-state-root.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3536-external-team-state-root.test.js +189 -0
- package/dist/scripts/__tests__/issue-3536-external-team-state-root.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +26 -0
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js +23 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.js +19 -1
- package/dist/scripts/__tests__/postinstall.test.js.map +1 -1
- package/dist/scripts/__tests__/prompt-inventory.test.js +54 -1
- package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -1
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +2 -2
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +46 -60
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +60 -25
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +168 -20
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts +2 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js +235 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +51 -2
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +3648 -1332
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts +9 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +33 -22
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js +80 -51
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +28 -39
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +2 -48
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +1 -0
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +5 -0
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +8 -5
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +32 -3
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +3 -2
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +23 -3
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +45 -5
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +1 -0
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +4 -1
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +71 -124
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall-advisory.d.ts +14 -0
- package/dist/scripts/postinstall-advisory.d.ts.map +1 -0
- package/dist/scripts/postinstall-advisory.js +49 -0
- package/dist/scripts/postinstall-advisory.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +1 -1
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.d.ts +39 -0
- package/dist/scripts/prompt-inventory.d.ts.map +1 -1
- package/dist/scripts/prompt-inventory.js +108 -3
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/run-compiled-ci.js +2 -0
- package/dist/scripts/run-compiled-ci.js.map +1 -1
- package/dist/scripts/run-test-files.js +1 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +32 -1
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +407 -60
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +16 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/sync-prompt-guidance-fragments.js +62 -20
- package/dist/scripts/sync-prompt-guidance-fragments.js.map +1 -1
- package/dist/scripts/tmux-hook-engine.d.ts +1 -1
- package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
- package/dist/scripts/tmux-hook-engine.js +3 -3
- package/dist/scripts/tmux-hook-engine.js.map +1 -1
- package/dist/scripts/verify-capabilities-lock.d.ts +3 -0
- package/dist/scripts/verify-capabilities-lock.d.ts.map +1 -0
- package/dist/scripts/verify-capabilities-lock.js +22 -0
- package/dist/scripts/verify-capabilities-lock.js.map +1 -0
- package/dist/scripts/verify-native-release-assets.js +37 -23
- package/dist/scripts/verify-native-release-assets.js.map +1 -1
- package/dist/state/__tests__/authority-decreasing.test.d.ts +2 -0
- package/dist/state/__tests__/authority-decreasing.test.d.ts.map +1 -0
- package/dist/state/__tests__/authority-decreasing.test.js +78 -0
- package/dist/state/__tests__/authority-decreasing.test.js.map +1 -0
- package/dist/state/__tests__/handoff-carrier.test.d.ts +2 -0
- package/dist/state/__tests__/handoff-carrier.test.d.ts.map +1 -0
- package/dist/state/__tests__/handoff-carrier.test.js +96 -0
- package/dist/state/__tests__/handoff-carrier.test.js.map +1 -0
- package/dist/state/__tests__/mode-state-context.test.js +12 -5
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +870 -2517
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/single-writer-invariant.test.d.ts +2 -0
- package/dist/state/__tests__/single-writer-invariant.test.d.ts.map +1 -0
- package/dist/state/__tests__/single-writer-invariant.test.js +342 -0
- package/dist/state/__tests__/single-writer-invariant.test.js.map +1 -0
- package/dist/state/__tests__/skill-active.test.js +400 -2
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/stale-state-neutralization.test.d.ts +2 -0
- package/dist/state/__tests__/stale-state-neutralization.test.d.ts.map +1 -0
- package/dist/state/__tests__/stale-state-neutralization.test.js +84 -0
- package/dist/state/__tests__/stale-state-neutralization.test.js.map +1 -0
- package/dist/state/__tests__/workflow-transition.test.js +20 -33
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/handoff-carrier.d.ts +46 -0
- package/dist/state/handoff-carrier.d.ts.map +1 -0
- package/dist/state/handoff-carrier.js +85 -0
- package/dist/state/handoff-carrier.js.map +1 -0
- package/dist/state/mode-state-context.d.ts +3 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +27 -13
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/namespace-owners.d.ts +34 -0
- package/dist/state/namespace-owners.d.ts.map +1 -0
- package/dist/state/namespace-owners.js +127 -0
- package/dist/state/namespace-owners.js.map +1 -0
- package/dist/state/operations.d.ts +9 -4
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +194 -235
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +18 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +421 -31
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +3 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +11 -31
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -27
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +9 -790
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +27 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
- package/dist/subagents/__tests__/tracker.test.js +837 -1048
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +64 -60
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +809 -358
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +1 -0
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +6 -7
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +104 -3
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/notice-ledger.test.d.ts +2 -0
- package/dist/team/__tests__/notice-ledger.test.d.ts.map +1 -0
- package/dist/team/__tests__/notice-ledger.test.js +131 -0
- package/dist/team/__tests__/notice-ledger.test.js.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts +2 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js +410 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js.map +1 -0
- package/dist/team/__tests__/phase-controller.test.js +20 -0
- package/dist/team/__tests__/phase-controller.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +725 -59
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +269 -245
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +117 -2
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +1 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +1093 -101
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js +159 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js.map +1 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts +69 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js +242 -15
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +177 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +11 -13
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/__tests__/worker-provenance.test.d.ts +2 -0
- package/dist/team/__tests__/worker-provenance.test.d.ts.map +1 -0
- package/dist/team/__tests__/worker-provenance.test.js +251 -0
- package/dist/team/__tests__/worker-provenance.test.js.map +1 -0
- package/dist/team/__tests__/worker-runtime-identity.test.js +45 -72
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +14 -8
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/mcp-comm.d.ts.map +1 -1
- package/dist/team/mcp-comm.js +3 -8
- package/dist/team/mcp-comm.js.map +1 -1
- package/dist/team/notice-ledger.d.ts +54 -0
- package/dist/team/notice-ledger.d.ts.map +1 -0
- package/dist/team/notice-ledger.js +259 -0
- package/dist/team/notice-ledger.js.map +1 -0
- package/dist/team/phase-controller.d.ts.map +1 -1
- package/dist/team/phase-controller.js +2 -0
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/runtime.d.ts +3 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +314 -142
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +161 -91
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/monitor.d.ts +10 -0
- package/dist/team/state/monitor.d.ts.map +1 -1
- package/dist/team/state/monitor.js +13 -0
- package/dist/team/state/monitor.js.map +1 -1
- package/dist/team/state/types.d.ts +15 -0
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state-root.d.ts +12 -0
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +177 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +19 -0
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +47 -1
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-ops.d.ts +1 -0
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +1 -0
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/tmux-session.d.ts +42 -4
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +572 -196
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/ultragoal-context.d.ts +1 -0
- package/dist/team/ultragoal-context.d.ts.map +1 -1
- package/dist/team/ultragoal-context.js +2 -0
- package/dist/team/ultragoal-context.js.map +1 -1
- package/dist/team/worker-provenance.d.ts +35 -0
- package/dist/team/worker-provenance.d.ts.map +1 -0
- package/dist/team/worker-provenance.js +213 -0
- package/dist/team/worker-provenance.js.map +1 -0
- package/dist/ultragoal/__tests__/artifacts.test.js +1053 -2
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +89 -59
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +36 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +267 -51
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/__tests__/url-reader.test.js +14 -0
- package/dist/url-reader/__tests__/url-reader.test.js.map +1 -1
- package/dist/url-reader/index.js +5 -3
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.js +58 -1
- package/dist/utils/__tests__/file-durability.test.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +21 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/__tests__/version.test.js +17 -0
- package/dist/utils/__tests__/version.test.js.map +1 -1
- package/dist/utils/file-durability.d.ts +10 -0
- package/dist/utils/file-durability.d.ts.map +1 -1
- package/dist/utils/file-durability.js +34 -4
- package/dist/utils/file-durability.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -6
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js +2 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +49 -4
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +60 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/native-release-manifest.test.js +157 -4
- package/dist/verification/__tests__/native-release-manifest.test.js.map +1 -1
- package/package.json +17 -6
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +81 -17
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +60 -135
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +35 -111
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +72 -163
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +33 -392
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +66 -256
- package/plugins/oh-my-codex/skills/configure-notifications/SKILL.md +30 -216
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +11 -10
- package/plugins/oh-my-codex/skills/design/SKILL.md +32 -132
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +56 -177
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +35 -116
- package/plugins/oh-my-codex/skills/plan/SKILL.md +45 -228
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +20 -22
- package/plugins/oh-my-codex/skills/skill/SKILL.md +82 -807
- package/plugins/oh-my-codex/skills/team/SKILL.md +32 -520
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +47 -150
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +75 -252
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +33 -111
- package/plugins/oh-my-codex/skills/worker/SKILL.md +40 -113
- package/prompts/analyst.md +27 -107
- package/prompts/api-reviewer.md +17 -84
- package/prompts/architect.md +31 -70
- package/prompts/code-reviewer.md +18 -107
- package/prompts/code-simplifier.md +32 -110
- package/prompts/critic.md +32 -54
- package/prompts/dependency-expert.md +37 -107
- package/prompts/designer.md +40 -107
- package/prompts/executor.md +26 -75
- package/prompts/information-architect.md +51 -200
- package/prompts/performance-reviewer.md +17 -81
- package/prompts/planner.md +33 -76
- package/prompts/product-analyst.md +65 -280
- package/prompts/product-manager.md +48 -216
- package/prompts/qa-tester.md +33 -104
- package/prompts/quality-reviewer.md +17 -93
- package/prompts/quality-strategist.md +31 -255
- package/prompts/researcher.md +32 -89
- package/prompts/security-reviewer.md +12 -98
- package/prompts/test-engineer.md +29 -110
- package/prompts/ux-researcher.md +46 -300
- package/prompts/verifier.md +23 -51
- package/skills/ai-slop-cleaner/SKILL.md +60 -135
- package/skills/analyze/SKILL.md +35 -111
- package/skills/autopilot/SKILL.md +72 -163
- package/skills/autoresearch-goal/SKILL.md +6 -31
- package/skills/cancel/SKILL.md +33 -392
- package/skills/code-review/SKILL.md +66 -256
- package/skills/configure-notifications/SKILL.md +30 -216
- package/skills/deep-interview/SKILL.md +11 -10
- package/skills/design/SKILL.md +32 -132
- package/skills/doctor/SKILL.md +56 -177
- package/skills/omx-setup/SKILL.md +35 -116
- package/skills/pipeline/SKILL.md +6 -89
- package/skills/plan/SKILL.md +45 -228
- package/skills/ralph/SKILL.md +6 -290
- package/skills/ralplan/SKILL.md +20 -22
- package/skills/skill/SKILL.md +82 -807
- package/skills/team/SKILL.md +32 -520
- package/skills/ultragoal/SKILL.md +47 -150
- package/skills/ultraqa/SKILL.md +75 -252
- package/skills/ultrawork/SKILL.md +6 -182
- package/skills/visual-ralph/SKILL.md +33 -111
- package/skills/worker/SKILL.md +40 -113
- package/src/scripts/__tests__/codex-native-hook.test.ts +18888 -28799
- package/src/scripts/__tests__/docs-site-contract.test.ts +2 -2
- package/src/scripts/__tests__/generated-artifact-drift.test.ts +97 -0
- package/src/scripts/__tests__/issue-3293-callsite-parity.test.ts +197 -0
- package/src/scripts/__tests__/issue-3293-cancel-transaction.test.ts +189 -0
- package/src/scripts/__tests__/issue-3293-hook-owned-cancel.test.ts +186 -0
- package/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts +177 -0
- package/src/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.ts +201 -0
- package/src/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.ts +43 -0
- package/src/scripts/__tests__/issue-3481-conductor-deadlock.test.ts +77 -0
- package/src/scripts/__tests__/issue-3486-pretooluse-lock-regression.test.ts +95 -0
- package/src/scripts/__tests__/issue-3536-external-team-state-root.test.ts +216 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +29 -0
- package/src/scripts/__tests__/notify-tmux-injection.test.ts +26 -1
- package/src/scripts/__tests__/postinstall.test.ts +23 -1
- package/src/scripts/__tests__/prompt-inventory.test.ts +62 -1
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +1 -2
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +49 -59
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +61 -27
- package/src/scripts/__tests__/smoke-packed-install.test.ts +223 -23
- package/src/scripts/__tests__/verify-native-release-assets.test.ts +240 -0
- package/src/scripts/codex-native-hook.ts +3618 -1383
- package/src/scripts/codex-native-pre-post.ts +50 -24
- package/src/scripts/generate-native-release-manifest.ts +83 -79
- package/src/scripts/notify-fallback-watcher.ts +38 -38
- package/src/scripts/notify-hook/auto-nudge.ts +1 -0
- package/src/scripts/notify-hook/state-io.ts +11 -0
- package/src/scripts/notify-hook/team-dispatch.ts +8 -5
- package/src/scripts/notify-hook/team-leader-nudge.ts +32 -4
- package/src/scripts/notify-hook/team-tmux-guard.ts +3 -1
- package/src/scripts/notify-hook/team-worker-stop.ts +23 -4
- package/src/scripts/notify-hook/team-worker.ts +43 -5
- package/src/scripts/notify-hook/tmux-injection.ts +5 -1
- package/src/scripts/notify-hook.ts +76 -124
- package/src/scripts/postinstall-advisory.ts +67 -0
- package/src/scripts/postinstall.ts +1 -1
- package/src/scripts/prompt-inventory.ts +142 -3
- package/src/scripts/run-compiled-ci.ts +2 -0
- package/src/scripts/run-test-files.ts +1 -0
- package/src/scripts/smoke-packed-install.ts +440 -59
- package/src/scripts/sync-plugin-mirror.ts +17 -1
- package/src/scripts/sync-prompt-guidance-fragments.ts +59 -22
- package/src/scripts/tmux-hook-engine.ts +3 -3
- package/src/scripts/verify-capabilities-lock.ts +23 -0
- package/src/scripts/verify-native-release-assets.ts +39 -31
- package/templates/AGENTS.md +45 -9
- package/templates/catalog-manifest.json +6 -146
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts +0 -2
- package/dist/autopilot/__tests__/deep-interview-gate.test.d.ts.map +0 -1
- package/dist/autopilot/__tests__/deep-interview-gate.test.js +0 -215
- package/dist/autopilot/__tests__/deep-interview-gate.test.js.map +0 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.d.ts +0 -2
- package/dist/autopilot/__tests__/ralplan-gate.test.d.ts.map +0 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +0 -1361
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +0 -1
- package/dist/autopilot/deep-interview-gate.d.ts +0 -18
- package/dist/autopilot/deep-interview-gate.d.ts.map +0 -1
- package/dist/autopilot/deep-interview-gate.js +0 -396
- package/dist/autopilot/deep-interview-gate.js.map +0 -1
- package/dist/autopilot/ralplan-gate.d.ts +0 -18
- package/dist/autopilot/ralplan-gate.d.ts.map +0 -1
- package/dist/autopilot/ralplan-gate.js +0 -148
- package/dist/autopilot/ralplan-gate.js.map +0 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +0 -2
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +0 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +0 -320
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +0 -1
- package/dist/pipeline/__tests__/orchestrator.test.d.ts +0 -2
- package/dist/pipeline/__tests__/orchestrator.test.d.ts.map +0 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +0 -770
- package/dist/pipeline/__tests__/orchestrator.test.js.map +0 -1
- package/dist/pipeline/__tests__/stages.test.d.ts +0 -2
- package/dist/pipeline/__tests__/stages.test.d.ts.map +0 -1
- package/dist/pipeline/__tests__/stages.test.js +0 -1778
- package/dist/pipeline/__tests__/stages.test.js.map +0 -1
- package/dist/pipeline/index.d.ts +0 -25
- package/dist/pipeline/index.d.ts.map +0 -1
- package/dist/pipeline/index.js +0 -17
- package/dist/pipeline/index.js.map +0 -1
- package/dist/pipeline/orchestrator.d.ts +0 -52
- package/dist/pipeline/orchestrator.d.ts.map +0 -1
- package/dist/pipeline/orchestrator.js +0 -399
- package/dist/pipeline/orchestrator.js.map +0 -1
- package/dist/pipeline/review-verdict.d.ts +0 -3
- package/dist/pipeline/review-verdict.d.ts.map +0 -1
- package/dist/pipeline/review-verdict.js +0 -14
- package/dist/pipeline/review-verdict.js.map +0 -1
- package/dist/pipeline/stages/code-review.d.ts +0 -35
- package/dist/pipeline/stages/code-review.d.ts.map +0 -1
- package/dist/pipeline/stages/code-review.js +0 -55
- package/dist/pipeline/stages/code-review.js.map +0 -1
- package/dist/pipeline/stages/deep-interview.d.ts +0 -15
- package/dist/pipeline/stages/deep-interview.d.ts.map +0 -1
- package/dist/pipeline/stages/deep-interview.js +0 -32
- package/dist/pipeline/stages/deep-interview.js.map +0 -1
- package/dist/pipeline/stages/ralph-verify.d.ts +0 -53
- package/dist/pipeline/stages/ralph-verify.d.ts.map +0 -1
- package/dist/pipeline/stages/ralph-verify.js +0 -89
- package/dist/pipeline/stages/ralph-verify.js.map +0 -1
- package/dist/pipeline/stages/ralplan.d.ts +0 -27
- package/dist/pipeline/stages/ralplan.d.ts.map +0 -1
- package/dist/pipeline/stages/ralplan.js +0 -152
- package/dist/pipeline/stages/ralplan.js.map +0 -1
- package/dist/pipeline/stages/team-exec.d.ts +0 -52
- package/dist/pipeline/stages/team-exec.d.ts.map +0 -1
- package/dist/pipeline/stages/team-exec.js +0 -266
- package/dist/pipeline/stages/team-exec.js.map +0 -1
- package/dist/pipeline/stages/ultragoal.d.ts +0 -23
- package/dist/pipeline/stages/ultragoal.d.ts.map +0 -1
- package/dist/pipeline/stages/ultragoal.js +0 -53
- package/dist/pipeline/stages/ultragoal.js.map +0 -1
- package/dist/pipeline/stages/ultraqa.d.ts +0 -33
- package/dist/pipeline/stages/ultraqa.d.ts.map +0 -1
- package/dist/pipeline/stages/ultraqa.js +0 -49
- package/dist/pipeline/stages/ultraqa.js.map +0 -1
- package/dist/pipeline/types.d.ts +0 -124
- package/dist/pipeline/types.d.ts.map +0 -1
- package/dist/pipeline/types.js +0 -8
- package/dist/pipeline/types.js.map +0 -1
- package/dist/ralplan/__tests__/consensus-gate.test.d.ts +0 -2
- package/dist/ralplan/__tests__/consensus-gate.test.d.ts.map +0 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +0 -1455
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +0 -1
- package/dist/ralplan/consensus-gate.d.ts +0 -62
- package/dist/ralplan/consensus-gate.d.ts.map +0 -1
- package/dist/ralplan/consensus-gate.js +0 -760
- package/dist/ralplan/consensus-gate.js.map +0 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +0 -25
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +0 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +0 -377
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +0 -1
- package/dist/state/__tests__/planning-gate.test.d.ts +0 -2
- package/dist/state/__tests__/planning-gate.test.d.ts.map +0 -1
- package/dist/state/__tests__/planning-gate.test.js +0 -629
- package/dist/state/__tests__/planning-gate.test.js.map +0 -1
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +0 -39
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +0 -97
- package/plugins/oh-my-codex/skills/prometheus-strict/README.md +0 -35
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +0 -219
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +0 -298
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +0 -190
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +0 -62
- package/prompts/prometheus-strict-metis.md +0 -274
- package/prompts/prometheus-strict-momus.md +0 -82
- package/prompts/prometheus-strict-oracle.md +0 -107
- package/prompts/scholastic.md +0 -11
- package/prompts/sisyphus-lite.md +0 -111
- package/skills/ask-claude/SKILL.md +0 -12
- package/skills/ask-gemini/SKILL.md +0 -12
- package/skills/build-fix/SKILL.md +0 -10
- package/skills/deepsearch/SKILL.md +0 -10
- package/skills/ecomode/SKILL.md +0 -114
- package/skills/ecomode/references/agent-tiers.md +0 -61
- package/skills/frontend-ui-ux/SKILL.md +0 -16
- package/skills/help/SKILL.md +0 -10
- package/skills/note/SKILL.md +0 -10
- package/skills/prometheus-strict/README.md +0 -35
- package/skills/prometheus-strict/SKILL.md +0 -219
- package/skills/ralph-init/SKILL.md +0 -10
- package/skills/review/SKILL.md +0 -10
- package/skills/security-review/SKILL.md +0 -10
- package/skills/swarm/SKILL.md +0 -12
- package/skills/tdd/SKILL.md +0 -104
- package/skills/trace/SKILL.md +0 -10
- package/skills/visual-verdict/SKILL.md +0 -10
- package/skills/web-clone/SKILL.md +0 -357
- package/src/scripts/notify-hook/ralph-session-resume.ts +0 -466
|
@@ -1,33 +1,109 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdir, mkdtemp, rm,
|
|
4
|
-
import { existsSync } from 'fs';
|
|
3
|
+
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from 'fs/promises';
|
|
4
|
+
import { existsSync, realpathSync } from 'fs';
|
|
5
5
|
import { dirname, join } from 'path';
|
|
6
|
-
import { tmpdir } from 'os';
|
|
6
|
+
import { tmpdir as osTmpdir } from 'os';
|
|
7
7
|
import { spawnSync } from 'child_process';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { readModeState } from '../../modes/base.js';
|
|
10
|
+
import { readSkillActiveState } from '../../state/skill-active.js';
|
|
11
|
+
import { recordSkillActivation } from '../../hooks/keyword-detector.js';
|
|
12
|
+
import { cancelModesForTest } from '../index.js';
|
|
13
|
+
const tmpdir = () => realpathSync(osTmpdir());
|
|
14
|
+
async function createFakeCodexBin(root, output) {
|
|
15
|
+
const binDir = join(root, 'bin');
|
|
16
|
+
await mkdir(binDir, { recursive: true });
|
|
17
|
+
await writeFile(join(binDir, 'codex'), `#!/bin/sh\nprintf '%s\\n' '${output}'\n`);
|
|
18
|
+
await chmod(join(binDir, 'codex'), 0o755);
|
|
19
|
+
return binDir;
|
|
20
|
+
}
|
|
9
21
|
const testDir = dirname(fileURLToPath(import.meta.url));
|
|
10
22
|
const repoRoot = join(testDir, '..', '..', '..');
|
|
11
23
|
const omxBin = join(repoRoot, 'dist', 'cli', 'omx.js');
|
|
24
|
+
function cleanOmxEnv(overrides = {}) {
|
|
25
|
+
const env = { ...process.env };
|
|
26
|
+
for (const name of [
|
|
27
|
+
'OMX_ROOT',
|
|
28
|
+
'OMX_STATE_ROOT',
|
|
29
|
+
'OMX_TEAM_STATE_ROOT',
|
|
30
|
+
'OMX_SESSION_ID',
|
|
31
|
+
'CODEX_SESSION_ID',
|
|
32
|
+
'SESSION_ID',
|
|
33
|
+
'OMX_RUNS_DIR',
|
|
34
|
+
]) {
|
|
35
|
+
delete env[name];
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...env,
|
|
39
|
+
...(overrides.FAKE_TMUX_SESSION_NAME ? {
|
|
40
|
+
FAKE_TMUX_PANE_PID: '4242',
|
|
41
|
+
FAKE_TMUX_INTERNAL_SESSION_ID: '$1',
|
|
42
|
+
FAKE_TMUX_SESSION_CREATED: '100',
|
|
43
|
+
} : {}),
|
|
44
|
+
...overrides,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
12
47
|
function runOmx(cwd, ...args) {
|
|
13
48
|
return spawnSync(process.execPath, [omxBin, ...args], {
|
|
14
49
|
cwd,
|
|
15
50
|
encoding: 'utf-8',
|
|
51
|
+
env: cleanOmxEnv(),
|
|
16
52
|
});
|
|
17
53
|
}
|
|
18
54
|
function runOmxWithEnv(cwd, env, ...args) {
|
|
19
55
|
return spawnSync(process.execPath, [omxBin, ...args], {
|
|
20
56
|
cwd,
|
|
21
57
|
encoding: 'utf-8',
|
|
22
|
-
env:
|
|
58
|
+
env: cleanOmxEnv(env),
|
|
23
59
|
});
|
|
24
60
|
}
|
|
61
|
+
async function createFakeTmuxBin(root) {
|
|
62
|
+
const binDir = join(root, 'bin');
|
|
63
|
+
const tmuxPath = join(binDir, 'tmux');
|
|
64
|
+
await mkdir(binDir, { recursive: true });
|
|
65
|
+
await writeFile(tmuxPath, `#!/bin/sh
|
|
66
|
+
case "$1" in
|
|
67
|
+
list-panes)
|
|
68
|
+
count=0
|
|
69
|
+
if [ -n "$FAKE_TMUX_COUNTER_FILE" ] && [ -f "$FAKE_TMUX_COUNTER_FILE" ]; then count=$(cat "$FAKE_TMUX_COUNTER_FILE"); fi
|
|
70
|
+
count=$((count + 1))
|
|
71
|
+
if [ -n "$FAKE_TMUX_COUNTER_FILE" ]; then printf '%s' "$count" > "$FAKE_TMUX_COUNTER_FILE"; fi
|
|
72
|
+
created="$FAKE_TMUX_SESSION_CREATED"
|
|
73
|
+
if [ "$FAKE_TMUX_REPLACE_AFTER_FIRST" = "1" ] && [ "$count" -gt 1 ]; then created=$((created + 1)); fi
|
|
74
|
+
printf '%%42\\t0\\t%s\\t%s\\t%s\\t%s\\t%s\\n' "$FAKE_TMUX_PANE_PID" "$FAKE_TMUX_SESSION_NAME" "$FAKE_TMUX_INTERNAL_SESSION_ID" "$created" "$FAKE_OMX_SESSION_ID"
|
|
75
|
+
;;
|
|
76
|
+
*) exit 1 ;;
|
|
77
|
+
esac
|
|
78
|
+
`);
|
|
79
|
+
await chmod(tmuxPath, 0o755);
|
|
80
|
+
return binDir;
|
|
81
|
+
}
|
|
82
|
+
async function writeActiveRunRecord(options) {
|
|
83
|
+
const activeDir = join(options.runsRoot, 'active-detached');
|
|
84
|
+
await mkdir(activeDir, { recursive: true });
|
|
85
|
+
await writeFile(join(activeDir, `${options.contextKey}.json`), JSON.stringify({
|
|
86
|
+
version: 1,
|
|
87
|
+
context_key: options.contextKey,
|
|
88
|
+
created_at: '2026-07-19T00:00:00.000Z',
|
|
89
|
+
source_cwd: options.sourceCwd,
|
|
90
|
+
...(options.worktreeCwd ? { worktree_cwd: options.worktreeCwd } : {}),
|
|
91
|
+
argv: ['--madmax'],
|
|
92
|
+
run_dir: options.runDir,
|
|
93
|
+
tmux_session_name: options.tmuxSessionName,
|
|
94
|
+
session_id: options.sessionId,
|
|
95
|
+
tmux_pane_id: '%42',
|
|
96
|
+
tmux_internal_session_id: '$1',
|
|
97
|
+
tmux_session_created: '100',
|
|
98
|
+
tmux_pane_pid: 4242,
|
|
99
|
+
}, null, 2));
|
|
100
|
+
}
|
|
25
101
|
describe('CLI session-scoped state parity', () => {
|
|
26
102
|
it('status and cancel include session-scoped states', async () => {
|
|
27
103
|
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-session-scope-'));
|
|
28
104
|
try {
|
|
29
105
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
30
|
-
await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({ session_id: 'sess1' }));
|
|
106
|
+
await writeFile(join(wd, '.omx', 'state', 'session.json'), JSON.stringify({ session_id: 'sess1', cwd: wd, state_root: join(wd, '.omx', 'state') }));
|
|
31
107
|
const scopedDir = join(wd, '.omx', 'state', 'sessions', 'sess1');
|
|
32
108
|
await mkdir(scopedDir, { recursive: true });
|
|
33
109
|
await writeFile(join(scopedDir, 'team-state.json'), JSON.stringify({
|
|
@@ -60,15 +136,14 @@ describe('CLI session-scoped state parity', () => {
|
|
|
60
136
|
const ralphPath = join(sessionDir, 'ralph-state.json');
|
|
61
137
|
const nativeStopPath = join(sessionDir, 'native-stop-state.json');
|
|
62
138
|
await mkdir(sessionDir, { recursive: true });
|
|
63
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }));
|
|
139
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
64
140
|
await writeFile(ralphPath, JSON.stringify({ active: true, current_phase: 'executing' }));
|
|
65
141
|
await writeFile(nativeStopPath, JSON.stringify({
|
|
66
142
|
sessions: { [sessionId]: { last_signature: 'ralph-stop|pending' } },
|
|
67
143
|
}));
|
|
68
144
|
const cancelResult = runOmxWithEnv(wd, { OMX_SESSION_ID: 'unmatched-session' }, 'cancel', '--force');
|
|
69
|
-
assert.
|
|
70
|
-
assert.match(cancelResult.stderr, /OMX_SESSION_ID
|
|
71
|
-
assert.match(cancelResult.stdout, /No active modes to cancel\./);
|
|
145
|
+
assert.notEqual(cancelResult.status, 0);
|
|
146
|
+
assert.match(cancelResult.stderr, /OMX_SESSION_ID does not match the live session recorded in session\.json/);
|
|
72
147
|
assert.deepEqual(JSON.parse(await readFile(ralphPath, 'utf-8')), { active: true, current_phase: 'executing' });
|
|
73
148
|
assert.deepEqual(JSON.parse(await readFile(nativeStopPath, 'utf-8')), { sessions: { [sessionId]: { last_signature: 'ralph-stop|pending' } } });
|
|
74
149
|
}
|
|
@@ -76,6 +151,660 @@ describe('CLI session-scoped state parity', () => {
|
|
|
76
151
|
await rm(wd, { recursive: true, force: true });
|
|
77
152
|
}
|
|
78
153
|
});
|
|
154
|
+
it('ignores ambient Codex session aliases that do not own writable cancellation', async () => {
|
|
155
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-codex-session-mismatch-'));
|
|
156
|
+
try {
|
|
157
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
158
|
+
const ownerSession = 'owner-session';
|
|
159
|
+
const foreignSession = 'foreign-codex-session';
|
|
160
|
+
const ownerPath = join(stateDir, 'sessions', ownerSession, 'ralplan-state.json');
|
|
161
|
+
const foreignPath = join(stateDir, 'sessions', foreignSession, 'team-state.json');
|
|
162
|
+
const ownerState = JSON.stringify({ active: true, mode: 'ralplan', current_phase: 'executing' }, null, 2);
|
|
163
|
+
const foreignState = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
164
|
+
await mkdir(dirname(ownerPath), { recursive: true });
|
|
165
|
+
await mkdir(dirname(foreignPath), { recursive: true });
|
|
166
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: ownerSession, cwd: wd, state_root: stateDir }));
|
|
167
|
+
await writeFile(ownerPath, ownerState);
|
|
168
|
+
await writeFile(foreignPath, foreignState);
|
|
169
|
+
for (const environmentName of ['CODEX_SESSION_ID', 'SESSION_ID']) {
|
|
170
|
+
await writeFile(ownerPath, ownerState);
|
|
171
|
+
const cancelResult = runOmxWithEnv(wd, { [environmentName]: foreignSession }, 'cancel');
|
|
172
|
+
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
173
|
+
assert.match(cancelResult.stdout, /Cancelled: ralplan/);
|
|
174
|
+
assert.doesNotMatch(cancelResult.stdout, /Cancelled: team/);
|
|
175
|
+
assert.equal(JSON.parse(await readFile(ownerPath, 'utf-8')).active, false);
|
|
176
|
+
assert.equal(await readFile(foreignPath, 'utf-8'), foreignState);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
await rm(wd, { recursive: true, force: true });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
it('keeps root cancellation authoritative despite ambient session aliases', async () => {
|
|
184
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-root-ambient-session-'));
|
|
185
|
+
try {
|
|
186
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
187
|
+
const foreignSession = 'foreign-ambient-session';
|
|
188
|
+
const rootPath = join(stateDir, 'team-state.json');
|
|
189
|
+
const foreignPath = join(stateDir, 'sessions', foreignSession, 'ralplan-state.json');
|
|
190
|
+
const rootState = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
191
|
+
const foreignState = JSON.stringify({ active: true, mode: 'ralplan', current_phase: 'executing' }, null, 2);
|
|
192
|
+
await mkdir(dirname(foreignPath), { recursive: true });
|
|
193
|
+
await writeFile(rootPath, rootState);
|
|
194
|
+
await writeFile(foreignPath, foreignState);
|
|
195
|
+
for (const environmentName of ['CODEX_SESSION_ID', 'SESSION_ID']) {
|
|
196
|
+
await writeFile(rootPath, rootState);
|
|
197
|
+
const cancelResult = runOmxWithEnv(wd, { [environmentName]: foreignSession }, 'cancel');
|
|
198
|
+
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
199
|
+
assert.match(cancelResult.stdout, /Cancelled: team/);
|
|
200
|
+
assert.doesNotMatch(cancelResult.stdout, /Cancelled: ralplan/);
|
|
201
|
+
assert.equal(JSON.parse(await readFile(rootPath, 'utf-8')).active, false);
|
|
202
|
+
assert.equal(await readFile(foreignPath, 'utf-8'), foreignState);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
await rm(wd, { recursive: true, force: true });
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
it('rejects unsupported cancellation flags before mutation', async () => {
|
|
210
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-flags-'));
|
|
211
|
+
try {
|
|
212
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
213
|
+
const statePath = join(stateDir, 'team-state.json');
|
|
214
|
+
const state = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
215
|
+
await mkdir(stateDir, { recursive: true });
|
|
216
|
+
await writeFile(statePath, state);
|
|
217
|
+
for (const args of [['--all'], ['--unknown'], ['--force', '--all']]) {
|
|
218
|
+
const result = runOmx(wd, 'cancel', ...args);
|
|
219
|
+
assert.notEqual(result.status, 0);
|
|
220
|
+
assert.equal(await readFile(statePath, 'utf-8'), state);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
await rm(wd, { recursive: true, force: true });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
it('rejects symlinked ordinary-scope state targets', async () => {
|
|
228
|
+
if (process.platform === 'win32')
|
|
229
|
+
return;
|
|
230
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-root-symlink-'));
|
|
231
|
+
const outside = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-root-symlink-outside-'));
|
|
232
|
+
try {
|
|
233
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
234
|
+
const outsidePath = join(outside, 'team-state.json');
|
|
235
|
+
const state = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
236
|
+
await mkdir(stateDir, { recursive: true });
|
|
237
|
+
await writeFile(outsidePath, state);
|
|
238
|
+
await symlink(outsidePath, join(stateDir, 'team-state.json'));
|
|
239
|
+
const result = runOmx(wd, 'cancel');
|
|
240
|
+
assert.notEqual(result.status, 0);
|
|
241
|
+
assert.match(result.stderr, /non-regular state target/);
|
|
242
|
+
assert.equal(await readFile(outsidePath, 'utf-8'), state);
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
await rm(wd, { recursive: true, force: true });
|
|
246
|
+
await rm(outside, { recursive: true, force: true });
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
it('rejects symlinked session authority directories', async () => {
|
|
250
|
+
if (process.platform === 'win32')
|
|
251
|
+
return;
|
|
252
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-session-root-symlink-'));
|
|
253
|
+
const outside = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-session-root-outside-'));
|
|
254
|
+
try {
|
|
255
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
256
|
+
const sessionId = 'session-root-link';
|
|
257
|
+
const outsidePath = join(outside, 'ralplan-state.json');
|
|
258
|
+
const state = JSON.stringify({ active: true, mode: 'ralplan', session_id: sessionId, current_phase: 'executing' }, null, 2);
|
|
259
|
+
await mkdir(join(stateDir, 'sessions'), { recursive: true });
|
|
260
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
261
|
+
await writeFile(outsidePath, state);
|
|
262
|
+
await symlink(outside, join(stateDir, 'sessions', sessionId), 'dir');
|
|
263
|
+
const result = runOmx(wd, 'cancel');
|
|
264
|
+
assert.notEqual(result.status, 0);
|
|
265
|
+
assert.match(result.stderr, /symlinked authority component|unusable/);
|
|
266
|
+
assert.equal(await readFile(outsidePath, 'utf-8'), state);
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
await rm(wd, { recursive: true, force: true });
|
|
270
|
+
await rm(outside, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
it('denies contradictory selected session state transaction-wide', async () => {
|
|
274
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-contradictory-'));
|
|
275
|
+
try {
|
|
276
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
277
|
+
const sessionId = 'sess-contradictory';
|
|
278
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
279
|
+
const contradictoryPath = join(sessionDir, 'ralplan-state.json');
|
|
280
|
+
const validPath = join(sessionDir, 'autopilot-state.json');
|
|
281
|
+
const contradictory = JSON.stringify({ active: true, mode: 'team', session_id: 'foreign', current_phase: 'team-exec' }, null, 2);
|
|
282
|
+
const valid = JSON.stringify({ active: true, mode: 'autopilot', session_id: sessionId, current_phase: 'executing' }, null, 2);
|
|
283
|
+
await mkdir(sessionDir, { recursive: true });
|
|
284
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
285
|
+
await writeFile(contradictoryPath, contradictory);
|
|
286
|
+
await writeFile(validPath, valid);
|
|
287
|
+
const result = runOmx(wd, 'cancel');
|
|
288
|
+
assert.notEqual(result.status, 0);
|
|
289
|
+
assert.match(result.stderr, /contradictory mode state/);
|
|
290
|
+
assert.equal(await readFile(contradictoryPath, 'utf-8'), contradictory);
|
|
291
|
+
assert.equal(await readFile(validPath, 'utf-8'), valid);
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
await rm(wd, { recursive: true, force: true });
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
it('fails closed when owned session state is malformed', async () => {
|
|
298
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-malformed-owner-'));
|
|
299
|
+
try {
|
|
300
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
301
|
+
const sessionId = 'malformed-owner';
|
|
302
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
303
|
+
const malformedPath = join(sessionDir, 'ralplan-state.json');
|
|
304
|
+
const teamPath = join(stateDir, 'team-state.json');
|
|
305
|
+
const malformedState = '{"active":true';
|
|
306
|
+
const rootTeamState = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
307
|
+
await mkdir(sessionDir, { recursive: true });
|
|
308
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
309
|
+
await writeFile(malformedPath, malformedState);
|
|
310
|
+
await writeFile(teamPath, rootTeamState);
|
|
311
|
+
const cancelResult = runOmx(wd, 'cancel');
|
|
312
|
+
assert.notEqual(cancelResult.status, 0);
|
|
313
|
+
assert.match(cancelResult.stderr, /Refusing partial cancellation/);
|
|
314
|
+
assert.doesNotMatch(cancelResult.stdout, /Cancelled: team/);
|
|
315
|
+
assert.equal(await readFile(malformedPath, 'utf-8'), malformedState);
|
|
316
|
+
assert.equal(await readFile(teamPath, 'utf-8'), rootTeamState);
|
|
317
|
+
}
|
|
318
|
+
finally {
|
|
319
|
+
await rm(wd, { recursive: true, force: true });
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
it('denies wrong-typed and nested ownership contradictions transaction-wide', async () => {
|
|
323
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-owner-evidence-'));
|
|
324
|
+
try {
|
|
325
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
326
|
+
const sessionId = 'owner-evidence-session';
|
|
327
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
328
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
329
|
+
const modePath = join(sessionDir, 'autopilot-state.json');
|
|
330
|
+
const skillState = JSON.stringify({ active: true, skill: 'autopilot', owner_codex_session_id: 42, active_skills: [{ skill: 'autopilot', active: true, owner_codex_session_id: 'foreign-owner' }] }, null, 2);
|
|
331
|
+
const modeState = JSON.stringify({ active: true, mode: 'autopilot', session_id: sessionId }, null, 2);
|
|
332
|
+
await mkdir(sessionDir, { recursive: true });
|
|
333
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
334
|
+
await writeFile(skillPath, skillState);
|
|
335
|
+
await writeFile(modePath, modeState);
|
|
336
|
+
const result = runOmx(wd, 'cancel');
|
|
337
|
+
assert.notEqual(result.status, 0);
|
|
338
|
+
assert.match(result.stderr, /contradictory owner_codex_session_id/);
|
|
339
|
+
assert.equal(await readFile(skillPath, 'utf-8'), skillState);
|
|
340
|
+
assert.equal(await readFile(modePath, 'utf-8'), modeState);
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
await rm(wd, { recursive: true, force: true });
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
it('keeps root Team compatibility state read-only when current-session Ralplan owns cancellation', async () => {
|
|
347
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-cross-mode-scope-'));
|
|
348
|
+
try {
|
|
349
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
350
|
+
const sessionId = 'sess-ralplan-owner';
|
|
351
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
352
|
+
const ralplanPath = join(sessionDir, 'ralplan-state.json');
|
|
353
|
+
const teamPath = join(stateDir, 'team-state.json');
|
|
354
|
+
const skillActivePath = join(stateDir, 'skill-active-state.json');
|
|
355
|
+
const nativeStopPath = join(stateDir, 'native-stop-state.json');
|
|
356
|
+
const ralplanState = JSON.stringify({
|
|
357
|
+
active: true,
|
|
358
|
+
mode: 'ralplan',
|
|
359
|
+
current_phase: 'executing',
|
|
360
|
+
}, null, 2);
|
|
361
|
+
const rootTeamState = JSON.stringify({
|
|
362
|
+
active: true,
|
|
363
|
+
mode: 'team',
|
|
364
|
+
current_phase: 'team-exec',
|
|
365
|
+
}, null, 2);
|
|
366
|
+
const rootSkillActiveState = JSON.stringify({
|
|
367
|
+
version: 1,
|
|
368
|
+
active: true,
|
|
369
|
+
skill: 'team',
|
|
370
|
+
phase: 'team-exec',
|
|
371
|
+
active_skills: [{ skill: 'team', phase: 'team-exec', active: true }],
|
|
372
|
+
}, null, 2);
|
|
373
|
+
const rootNativeStopState = JSON.stringify({
|
|
374
|
+
sessions: { [sessionId]: { last_signature: 'team-stop|pending' } },
|
|
375
|
+
}, null, 2);
|
|
376
|
+
await mkdir(sessionDir, { recursive: true });
|
|
377
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
378
|
+
await writeFile(ralplanPath, ralplanState);
|
|
379
|
+
await writeFile(teamPath, rootTeamState);
|
|
380
|
+
await writeFile(skillActivePath, rootSkillActiveState);
|
|
381
|
+
await writeFile(nativeStopPath, rootNativeStopState);
|
|
382
|
+
const cancelResult = runOmx(wd, 'cancel');
|
|
383
|
+
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
384
|
+
assert.match(cancelResult.stdout, /Cancelled: ralplan/);
|
|
385
|
+
assert.doesNotMatch(cancelResult.stdout, /Cancelled: team/);
|
|
386
|
+
assert.equal(JSON.parse(await readFile(ralplanPath, 'utf-8')).active, false);
|
|
387
|
+
assert.equal(await readFile(teamPath, 'utf-8'), rootTeamState);
|
|
388
|
+
assert.equal(await readFile(skillActivePath, 'utf-8'), rootSkillActiveState);
|
|
389
|
+
assert.equal(await readFile(nativeStopPath, 'utf-8'), rootNativeStopState);
|
|
390
|
+
await writeFile(ralplanPath, ralplanState);
|
|
391
|
+
const forceResult = runOmx(wd, 'cancel', '--force');
|
|
392
|
+
assert.equal(forceResult.status, 0, forceResult.stderr || forceResult.stdout);
|
|
393
|
+
assert.match(forceResult.stdout, /Cancelled: ralplan/);
|
|
394
|
+
assert.doesNotMatch(forceResult.stdout, /Cancelled: team/);
|
|
395
|
+
assert.equal(JSON.parse(await readFile(ralplanPath, 'utf-8')).active, false);
|
|
396
|
+
assert.equal(await readFile(teamPath, 'utf-8'), rootTeamState);
|
|
397
|
+
assert.equal(await readFile(skillActivePath, 'utf-8'), rootSkillActiveState);
|
|
398
|
+
assert.equal(await readFile(nativeStopPath, 'utf-8'), rootNativeStopState);
|
|
399
|
+
}
|
|
400
|
+
finally {
|
|
401
|
+
await rm(wd, { recursive: true, force: true });
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
it('replaces only a stale top-level skill owner under complete current native authority', async () => {
|
|
405
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-stale-skill-owner-'));
|
|
406
|
+
try {
|
|
407
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
408
|
+
const sessionId = 'current-session';
|
|
409
|
+
const nativeSessionId = 'current-native-owner';
|
|
410
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
411
|
+
const pointer = JSON.stringify({
|
|
412
|
+
session_id: sessionId,
|
|
413
|
+
native_session_id: nativeSessionId,
|
|
414
|
+
cwd: wd,
|
|
415
|
+
state_root: stateDir,
|
|
416
|
+
platform: process.platform,
|
|
417
|
+
}, null, 2);
|
|
418
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
419
|
+
const ralplanPath = join(sessionDir, 'ralplan-state.json');
|
|
420
|
+
const rootSkillPath = join(stateDir, 'skill-active-state.json');
|
|
421
|
+
const rootSkill = JSON.stringify({ active: true, skill: 'team' }, null, 2);
|
|
422
|
+
await mkdir(sessionDir, { recursive: true });
|
|
423
|
+
await writeFile(join(stateDir, 'session.json'), pointer);
|
|
424
|
+
await mkdir(join(stateDir, 'sessions', nativeSessionId), { recursive: true });
|
|
425
|
+
await writeFile(join(stateDir, 'sessions', nativeSessionId, 'session-owner.json'), JSON.stringify({
|
|
426
|
+
session_id: nativeSessionId,
|
|
427
|
+
native_session_id: nativeSessionId,
|
|
428
|
+
cwd: wd,
|
|
429
|
+
platform: process.platform,
|
|
430
|
+
}, null, 2));
|
|
431
|
+
await writeFile(skillPath, JSON.stringify({
|
|
432
|
+
active: true,
|
|
433
|
+
skill: 'ralplan',
|
|
434
|
+
owner_codex_session_id: 'stale-native-owner',
|
|
435
|
+
active_skills: [{ skill: 'ralplan', active: true, owner_codex_session_id: nativeSessionId }],
|
|
436
|
+
}, null, 2));
|
|
437
|
+
await writeFile(ralplanPath, JSON.stringify({ active: true, mode: 'ralplan' }, null, 2));
|
|
438
|
+
await writeFile(rootSkillPath, rootSkill);
|
|
439
|
+
const descendantCwd = join(wd, 'packages', 'app');
|
|
440
|
+
await mkdir(descendantCwd, { recursive: true });
|
|
441
|
+
const result = runOmxWithEnv(descendantCwd, { OMX_ROOT: wd }, 'cancel');
|
|
442
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
443
|
+
const skill = JSON.parse(await readFile(skillPath, 'utf-8'));
|
|
444
|
+
assert.equal(skill.owner_codex_session_id, nativeSessionId);
|
|
445
|
+
assert.equal(skill.active_skills[0].owner_codex_session_id, nativeSessionId);
|
|
446
|
+
assert.equal(skill.active, false);
|
|
447
|
+
assert.equal(await readFile(rootSkillPath, 'utf-8'), rootSkill);
|
|
448
|
+
const repeat = runOmx(wd, 'cancel');
|
|
449
|
+
assert.equal(repeat.status, 0, repeat.stderr || repeat.stdout);
|
|
450
|
+
assert.equal(JSON.parse(await readFile(skillPath, 'utf-8')).owner_codex_session_id, nativeSessionId);
|
|
451
|
+
const malformedNestedSkill = JSON.stringify({
|
|
452
|
+
active: true,
|
|
453
|
+
skill: 'ralplan',
|
|
454
|
+
owner_codex_session_id: nativeSessionId,
|
|
455
|
+
active_skills: [{ skill: 'ralplan', active: 'true', owner_codex_session_id: nativeSessionId }],
|
|
456
|
+
}, null, 2);
|
|
457
|
+
await writeFile(skillPath, malformedNestedSkill);
|
|
458
|
+
const malformedNestedResult = runOmx(wd, 'cancel');
|
|
459
|
+
assert.notEqual(malformedNestedResult.status, 0);
|
|
460
|
+
assert.match(malformedNestedResult.stderr, /malformed active/);
|
|
461
|
+
assert.equal(await readFile(skillPath, 'utf-8'), malformedNestedSkill);
|
|
462
|
+
const fieldSwappedSkill = JSON.stringify({
|
|
463
|
+
active: true,
|
|
464
|
+
skill: 'ralplan',
|
|
465
|
+
session_id: nativeSessionId,
|
|
466
|
+
owner_codex_session_id: nativeSessionId,
|
|
467
|
+
active_skills: [{ skill: 'ralplan', active: true, session_id: nativeSessionId, owner_codex_session_id: nativeSessionId }],
|
|
468
|
+
}, null, 2);
|
|
469
|
+
await writeFile(skillPath, fieldSwappedSkill);
|
|
470
|
+
const fieldSwappedResult = runOmx(wd, 'cancel');
|
|
471
|
+
assert.notEqual(fieldSwappedResult.status, 0);
|
|
472
|
+
assert.match(fieldSwappedResult.stderr, /contradictory session_id/);
|
|
473
|
+
assert.equal(await readFile(skillPath, 'utf-8'), fieldSwappedSkill);
|
|
474
|
+
const inactiveStaleSkill = JSON.stringify({
|
|
475
|
+
active: false,
|
|
476
|
+
skill: 'ralplan',
|
|
477
|
+
owner_codex_session_id: 'stale-native-owner',
|
|
478
|
+
active_skills: [{ skill: 'ralplan', active: false, owner_codex_session_id: nativeSessionId }],
|
|
479
|
+
}, null, 2);
|
|
480
|
+
await writeFile(skillPath, inactiveStaleSkill);
|
|
481
|
+
const noActiveResult = runOmx(wd, 'cancel');
|
|
482
|
+
assert.equal(noActiveResult.status, 0, noActiveResult.stderr || noActiveResult.stdout);
|
|
483
|
+
assert.match(noActiveResult.stdout, /No active modes to cancel/);
|
|
484
|
+
assert.equal(await readFile(skillPath, 'utf-8'), inactiveStaleSkill);
|
|
485
|
+
const displacedDir = join(stateDir, 'sessions', 'stale-native-owner');
|
|
486
|
+
await mkdir(displacedDir, { recursive: true });
|
|
487
|
+
await writeFile(join(displacedDir, 'session-owner.json'), JSON.stringify({
|
|
488
|
+
session_id: 'stale-native-owner',
|
|
489
|
+
native_session_id: 'stale-native-owner',
|
|
490
|
+
cwd: wd,
|
|
491
|
+
platform: process.platform,
|
|
492
|
+
}, null, 2));
|
|
493
|
+
const liveDisplacedSkill = JSON.stringify({
|
|
494
|
+
active: true,
|
|
495
|
+
skill: 'ralplan',
|
|
496
|
+
owner_codex_session_id: 'stale-native-owner',
|
|
497
|
+
active_skills: [{ skill: 'ralplan', active: true, owner_codex_session_id: nativeSessionId }],
|
|
498
|
+
}, null, 2);
|
|
499
|
+
const activeRalplan = JSON.stringify({ active: true, mode: 'ralplan' }, null, 2);
|
|
500
|
+
await writeFile(skillPath, liveDisplacedSkill);
|
|
501
|
+
await writeFile(ralplanPath, activeRalplan);
|
|
502
|
+
const liveDisplaced = runOmx(wd, 'cancel');
|
|
503
|
+
assert.notEqual(liveDisplaced.status, 0);
|
|
504
|
+
assert.match(liveDisplaced.stderr, /non-stale displaced owner evidence/);
|
|
505
|
+
assert.equal(await readFile(skillPath, 'utf-8'), liveDisplacedSkill);
|
|
506
|
+
assert.equal(await readFile(ralplanPath, 'utf-8'), activeRalplan);
|
|
507
|
+
}
|
|
508
|
+
finally {
|
|
509
|
+
await rm(wd, { recursive: true, force: true });
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
it('preserves active Team skill entries while cancelling Ralph', async () => {
|
|
513
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-ralph-team-peer-'));
|
|
514
|
+
try {
|
|
515
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
516
|
+
const sessionId = 'canonical-session';
|
|
517
|
+
const nativeSessionId = 'native-session';
|
|
518
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
519
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
520
|
+
const ralphPath = join(sessionDir, 'ralph-state.json');
|
|
521
|
+
const teamPath = join(sessionDir, 'team-state.json');
|
|
522
|
+
const teamState = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
523
|
+
await mkdir(sessionDir, { recursive: true });
|
|
524
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({
|
|
525
|
+
session_id: sessionId,
|
|
526
|
+
native_session_id: nativeSessionId,
|
|
527
|
+
cwd: wd,
|
|
528
|
+
state_root: stateDir,
|
|
529
|
+
}, null, 2));
|
|
530
|
+
await mkdir(join(stateDir, 'sessions', nativeSessionId), { recursive: true });
|
|
531
|
+
await writeFile(join(stateDir, 'sessions', nativeSessionId, 'session-owner.json'), JSON.stringify({
|
|
532
|
+
session_id: nativeSessionId,
|
|
533
|
+
native_session_id: nativeSessionId,
|
|
534
|
+
cwd: wd,
|
|
535
|
+
}, null, 2));
|
|
536
|
+
await writeFile(skillPath, JSON.stringify({
|
|
537
|
+
active: true,
|
|
538
|
+
skill: 'ralph',
|
|
539
|
+
phase: 'executing',
|
|
540
|
+
session_id: sessionId,
|
|
541
|
+
owner_codex_session_id: nativeSessionId,
|
|
542
|
+
active_skills: [
|
|
543
|
+
{ skill: 'ralph', phase: 'executing', session_id: sessionId, owner_codex_session_id: nativeSessionId },
|
|
544
|
+
{ skill: 'team', phase: 'team-exec', session_id: sessionId, owner_codex_session_id: nativeSessionId },
|
|
545
|
+
],
|
|
546
|
+
}, null, 2));
|
|
547
|
+
await writeFile(ralphPath, JSON.stringify({ active: true, mode: 'ralph' }, null, 2));
|
|
548
|
+
await writeFile(teamPath, teamState);
|
|
549
|
+
const result = runOmx(wd, 'cancel');
|
|
550
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
551
|
+
const skill = JSON.parse(await readFile(skillPath, 'utf-8'));
|
|
552
|
+
assert.equal(skill.active, true);
|
|
553
|
+
assert.equal(skill.skill, 'team');
|
|
554
|
+
assert.equal(skill.phase, 'team-exec');
|
|
555
|
+
assert.equal(skill.current_phase, 'team-exec');
|
|
556
|
+
assert.deepEqual(skill.active_skills.map((entry) => [entry.skill, entry.active]), [
|
|
557
|
+
['ralph', false],
|
|
558
|
+
['team', undefined],
|
|
559
|
+
]);
|
|
560
|
+
assert.equal(JSON.parse(await readFile(ralphPath, 'utf-8')).active, false);
|
|
561
|
+
assert.equal(await readFile(teamPath, 'utf-8'), teamState);
|
|
562
|
+
}
|
|
563
|
+
finally {
|
|
564
|
+
await rm(wd, { recursive: true, force: true });
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
it('preserves a legacy top-level Team marker while cancelling Ralph', async () => {
|
|
568
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-legacy-team-ralph-'));
|
|
569
|
+
try {
|
|
570
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
571
|
+
const sessionId = 'legacy-team-ralph-session';
|
|
572
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
573
|
+
await mkdir(sessionDir, { recursive: true });
|
|
574
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
575
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
576
|
+
const teamPath = join(sessionDir, 'team-state.json');
|
|
577
|
+
const ralphPath = join(sessionDir, 'ralph-state.json');
|
|
578
|
+
const legacyTeamSkill = JSON.stringify({ active: true, skill: 'team', phase: 'team-exec', session_id: sessionId, active_skills: [{ skill: 'code-review', active: false }] }, null, 2);
|
|
579
|
+
const activeTeam = JSON.stringify({ active: true, mode: 'team', session_id: sessionId }, null, 2);
|
|
580
|
+
await writeFile(skillPath, legacyTeamSkill);
|
|
581
|
+
await writeFile(teamPath, activeTeam);
|
|
582
|
+
await writeFile(ralphPath, JSON.stringify({ active: true, mode: 'ralph', session_id: sessionId }, null, 2));
|
|
583
|
+
const result = runOmx(wd, 'cancel');
|
|
584
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
585
|
+
assert.equal(await readFile(skillPath, 'utf-8'), legacyTeamSkill);
|
|
586
|
+
assert.equal(await readFile(teamPath, 'utf-8'), activeTeam);
|
|
587
|
+
assert.equal(JSON.parse(await readFile(ralphPath, 'utf-8')).active, false);
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
await rm(wd, { recursive: true, force: true });
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
it('cancels valid skill-active-only workflow names without a duplicate allowlist', async () => {
|
|
594
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-skill-only-name-'));
|
|
595
|
+
try {
|
|
596
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
597
|
+
const sessionId = 'skill-only-name-session';
|
|
598
|
+
const nativeSessionId = 'skill-only-name-native';
|
|
599
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
600
|
+
await mkdir(sessionDir, { recursive: true });
|
|
601
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, native_session_id: nativeSessionId, cwd: wd, state_root: stateDir }));
|
|
602
|
+
const nativeOwnerDir = join(stateDir, 'sessions', nativeSessionId);
|
|
603
|
+
await mkdir(nativeOwnerDir, { recursive: true });
|
|
604
|
+
await writeFile(join(nativeOwnerDir, 'session-owner.json'), JSON.stringify({
|
|
605
|
+
session_id: nativeSessionId,
|
|
606
|
+
native_session_id: nativeSessionId,
|
|
607
|
+
cwd: wd,
|
|
608
|
+
platform: process.platform,
|
|
609
|
+
}));
|
|
610
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
611
|
+
await writeFile(skillPath, JSON.stringify({
|
|
612
|
+
active: true,
|
|
613
|
+
skill: 'code-review',
|
|
614
|
+
session_id: sessionId,
|
|
615
|
+
active_skills: [{ skill: 'code-review', active: true, session_id: sessionId, owner_codex_session_id: nativeSessionId }],
|
|
616
|
+
}, null, 2));
|
|
617
|
+
const result = runOmx(wd, 'cancel');
|
|
618
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
619
|
+
const skill = JSON.parse(await readFile(skillPath, 'utf-8'));
|
|
620
|
+
assert.equal(skill.active, false);
|
|
621
|
+
assert.equal(skill.active_skills[0].active, false);
|
|
622
|
+
}
|
|
623
|
+
finally {
|
|
624
|
+
await rm(wd, { recursive: true, force: true });
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
it('preserves mode-only cancellation without creating a skill marker', async () => {
|
|
628
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-mode-only-'));
|
|
629
|
+
try {
|
|
630
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
631
|
+
const sessionId = 'mode-only-session';
|
|
632
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
633
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
634
|
+
const modePath = join(sessionDir, 'ralplan-state.json');
|
|
635
|
+
await mkdir(sessionDir, { recursive: true });
|
|
636
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
637
|
+
await writeFile(modePath, JSON.stringify({ active: true, mode: 'ralplan', session_id: sessionId }, null, 2));
|
|
638
|
+
const result = runOmx(wd, 'cancel');
|
|
639
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
640
|
+
assert.match(result.stdout, /Cancelled: ralplan/);
|
|
641
|
+
assert.equal(existsSync(skillPath), false);
|
|
642
|
+
assert.equal(JSON.parse(await readFile(modePath, 'utf-8')).active, false);
|
|
643
|
+
const repeat = runOmx(wd, 'cancel');
|
|
644
|
+
assert.equal(repeat.status, 0, repeat.stderr || repeat.stdout);
|
|
645
|
+
assert.equal(existsSync(skillPath), false);
|
|
646
|
+
}
|
|
647
|
+
finally {
|
|
648
|
+
await rm(wd, { recursive: true, force: true });
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
it('reports rollback restoration failures without false cancellation success', async () => {
|
|
652
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-rollback-failure-'));
|
|
653
|
+
try {
|
|
654
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
655
|
+
const sessionId = 'rollback-session';
|
|
656
|
+
const nativeSessionId = 'rollback-native';
|
|
657
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
658
|
+
const modePath = join(sessionDir, 'ralplan-state.json');
|
|
659
|
+
const skillPath = join(sessionDir, 'skill-active-state.json');
|
|
660
|
+
const modeState = JSON.stringify({ active: true, mode: 'ralplan', session_id: sessionId }, null, 2);
|
|
661
|
+
const skillState = JSON.stringify({
|
|
662
|
+
active: true,
|
|
663
|
+
skill: 'ralplan',
|
|
664
|
+
session_id: sessionId,
|
|
665
|
+
owner_codex_session_id: nativeSessionId,
|
|
666
|
+
active_skills: [{ skill: 'ralplan', active: true, session_id: sessionId, owner_codex_session_id: nativeSessionId }],
|
|
667
|
+
}, null, 2);
|
|
668
|
+
await mkdir(sessionDir, { recursive: true });
|
|
669
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, native_session_id: nativeSessionId, cwd: wd, state_root: stateDir }));
|
|
670
|
+
await mkdir(join(stateDir, 'sessions', nativeSessionId), { recursive: true });
|
|
671
|
+
await writeFile(join(stateDir, 'sessions', nativeSessionId, 'session-owner.json'), JSON.stringify({
|
|
672
|
+
session_id: nativeSessionId,
|
|
673
|
+
native_session_id: nativeSessionId,
|
|
674
|
+
cwd: wd,
|
|
675
|
+
}));
|
|
676
|
+
await writeFile(modePath, modeState);
|
|
677
|
+
await writeFile(skillPath, skillState);
|
|
678
|
+
const errors = [];
|
|
679
|
+
const logs = [];
|
|
680
|
+
const previousError = console.error;
|
|
681
|
+
const previousLog = console.log;
|
|
682
|
+
const previousExitCode = process.exitCode;
|
|
683
|
+
const previousStderrWrite = process.stderr.write;
|
|
684
|
+
console.error = (...args) => { errors.push(args.map(String).join(' ')); };
|
|
685
|
+
console.log = (...args) => { logs.push(args.map(String).join(' ')); };
|
|
686
|
+
process.stderr.write = ((chunk) => {
|
|
687
|
+
errors.push(String(chunk));
|
|
688
|
+
return true;
|
|
689
|
+
});
|
|
690
|
+
try {
|
|
691
|
+
await cancelModesForTest(wd, [], {
|
|
692
|
+
writeFailureMode: 'skill-active',
|
|
693
|
+
rollbackFailureMode: 'ralplan',
|
|
694
|
+
});
|
|
695
|
+
assert.equal(process.exitCode, 1);
|
|
696
|
+
}
|
|
697
|
+
finally {
|
|
698
|
+
console.error = previousError;
|
|
699
|
+
console.log = previousLog;
|
|
700
|
+
process.stderr.write = previousStderrWrite;
|
|
701
|
+
process.exitCode = previousExitCode;
|
|
702
|
+
}
|
|
703
|
+
assert.match(errors.join('\n'), /cancellation_rollback_failed:1:ralplan/);
|
|
704
|
+
assert.doesNotMatch(logs.join('\n'), /Cancelled:/);
|
|
705
|
+
assert.equal(await readFile(skillPath, 'utf-8'), skillState);
|
|
706
|
+
assert.equal(JSON.parse(await readFile(modePath, 'utf-8')).active, false);
|
|
707
|
+
}
|
|
708
|
+
finally {
|
|
709
|
+
await rm(wd, { recursive: true, force: true });
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
it('fails Ralplan preflight without mutating unproven session state', async () => {
|
|
713
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-ralplan-preflight-scope-'));
|
|
714
|
+
const codexBin = await createFakeCodexBin(wd, 'codex-cli 0.147.0');
|
|
715
|
+
try {
|
|
716
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
717
|
+
const sessionId = 'sess-unproven-owner';
|
|
718
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
719
|
+
const ralplanPath = join(sessionDir, 'ralplan-state.json');
|
|
720
|
+
const ralplanState = JSON.stringify({
|
|
721
|
+
active: true,
|
|
722
|
+
mode: 'ralplan',
|
|
723
|
+
current_phase: 'starting',
|
|
724
|
+
}, null, 2);
|
|
725
|
+
await mkdir(sessionDir, { recursive: true });
|
|
726
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
727
|
+
await writeFile(ralplanPath, ralplanState);
|
|
728
|
+
const preflightResult = runOmxWithEnv(wd, { PATH: `${codexBin}:${process.env.PATH}` }, 'ralplan', 'preflight', '--json');
|
|
729
|
+
assert.equal(preflightResult.status, 1, preflightResult.stderr || preflightResult.stdout);
|
|
730
|
+
assert.deepEqual(JSON.parse(preflightResult.stdout), {
|
|
731
|
+
ok: false,
|
|
732
|
+
reason: 'unsupported_documented_leader_proof',
|
|
733
|
+
diagnostics: {
|
|
734
|
+
probe_status: 'ok',
|
|
735
|
+
detected_version: '0.147.0',
|
|
736
|
+
documented_root_identity: { status: 'unknown' },
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
assert.equal(await readFile(ralplanPath, 'utf-8'), ralplanState);
|
|
740
|
+
}
|
|
741
|
+
finally {
|
|
742
|
+
await rm(wd, { recursive: true, force: true });
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
it('keeps exact-owner routing-only Ralplan active after preflight denial', async () => {
|
|
746
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-ralplan-preflight-owner-'));
|
|
747
|
+
const codexBin = await createFakeCodexBin(wd, 'codex-cli 0.147.0');
|
|
748
|
+
try {
|
|
749
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
750
|
+
const sessionId = 'sess-proven-owner';
|
|
751
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
752
|
+
const ralplanPath = join(sessionDir, 'ralplan-state.json');
|
|
753
|
+
const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
|
|
754
|
+
const rootTeamPath = join(stateDir, 'team-state.json');
|
|
755
|
+
const rootSkillPath = join(stateDir, 'skill-active-state.json');
|
|
756
|
+
const rootStopPath = join(stateDir, 'native-stop-state.json');
|
|
757
|
+
const rootTeam = JSON.stringify({ active: true, mode: 'team', current_phase: 'team-exec' }, null, 2);
|
|
758
|
+
const rootSkill = JSON.stringify({ active: true, skill: 'team', phase: 'team-exec' }, null, 2);
|
|
759
|
+
const rootStop = JSON.stringify({ sessions: { foreign: { pending: true } } }, null, 2);
|
|
760
|
+
await mkdir(sessionDir, { recursive: true });
|
|
761
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
762
|
+
const activated = await recordSkillActivation({
|
|
763
|
+
stateDir,
|
|
764
|
+
sourceCwd: wd,
|
|
765
|
+
text: '$ralplan continue issue #3212',
|
|
766
|
+
sessionId,
|
|
767
|
+
threadId: 'thread-preflight-owner',
|
|
768
|
+
turnId: 'turn-preflight-owner',
|
|
769
|
+
nowIso: '2026-07-19T00:00:00.000Z',
|
|
770
|
+
});
|
|
771
|
+
assert.ok(activated);
|
|
772
|
+
const ralplanState = await readFile(ralplanPath, 'utf-8');
|
|
773
|
+
const sessionSkillState = await readFile(sessionSkillPath, 'utf-8');
|
|
774
|
+
await writeFile(rootTeamPath, rootTeam);
|
|
775
|
+
await writeFile(rootSkillPath, rootSkill);
|
|
776
|
+
await writeFile(rootStopPath, rootStop);
|
|
777
|
+
const sessionEntries = await readdir(sessionDir);
|
|
778
|
+
const preflightResult = runOmxWithEnv(wd, { OMX_SESSION_ID: sessionId, PATH: `${codexBin}:${process.env.PATH}` }, 'ralplan', 'preflight', '--json');
|
|
779
|
+
assert.equal(preflightResult.status, 1, preflightResult.stderr || preflightResult.stdout);
|
|
780
|
+
assert.deepEqual(JSON.parse(preflightResult.stdout), {
|
|
781
|
+
ok: false,
|
|
782
|
+
reason: 'unsupported_documented_leader_proof',
|
|
783
|
+
diagnostics: {
|
|
784
|
+
probe_status: 'ok',
|
|
785
|
+
detected_version: '0.147.0',
|
|
786
|
+
documented_root_identity: { status: 'unknown' },
|
|
787
|
+
},
|
|
788
|
+
});
|
|
789
|
+
assert.equal(await readFile(ralplanPath, 'utf-8'), ralplanState);
|
|
790
|
+
assert.equal(await readFile(sessionSkillPath, 'utf-8'), sessionSkillState);
|
|
791
|
+
const [state, skillState] = await Promise.all([
|
|
792
|
+
readModeState('ralplan', wd),
|
|
793
|
+
readSkillActiveState(sessionSkillPath),
|
|
794
|
+
]);
|
|
795
|
+
assert.equal(state?.active, true);
|
|
796
|
+
assert.equal(skillState?.active, true);
|
|
797
|
+
const postPreflightEntries = await readdir(sessionDir);
|
|
798
|
+
assert.deepEqual(postPreflightEntries, sessionEntries);
|
|
799
|
+
assert.equal(postPreflightEntries.some((name) => name.startsWith('.ralplan-neutralization-')), false);
|
|
800
|
+
assert.equal(await readFile(rootTeamPath, 'utf-8'), rootTeam);
|
|
801
|
+
assert.equal(await readFile(rootSkillPath, 'utf-8'), rootSkill);
|
|
802
|
+
assert.equal(await readFile(rootStopPath, 'utf-8'), rootStop);
|
|
803
|
+
}
|
|
804
|
+
finally {
|
|
805
|
+
await rm(wd, { recursive: true, force: true });
|
|
806
|
+
}
|
|
807
|
+
});
|
|
79
808
|
it('status does not report a root fallback mode as active after current-session clear', async () => {
|
|
80
809
|
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-session-clear-fallback-'));
|
|
81
810
|
try {
|
|
@@ -83,7 +812,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
83
812
|
const sessionId = 'sess-clear';
|
|
84
813
|
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
85
814
|
await mkdir(sessionDir, { recursive: true });
|
|
86
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }));
|
|
815
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
87
816
|
await writeFile(join(stateDir, 'deep-interview-state.json'), JSON.stringify({
|
|
88
817
|
active: true,
|
|
89
818
|
mode: 'deep-interview',
|
|
@@ -106,17 +835,367 @@ describe('CLI session-scoped state parity', () => {
|
|
|
106
835
|
await rm(wd, { recursive: true, force: true });
|
|
107
836
|
}
|
|
108
837
|
});
|
|
838
|
+
it('does not cancel a foreign hook-visible run-dir from session-owned scope', async () => {
|
|
839
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-cancel-foreign-owner-'));
|
|
840
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-cancel-foreign-runs-'));
|
|
841
|
+
try {
|
|
842
|
+
const ownerSessionId = 'sess-canonical-owner';
|
|
843
|
+
const foreignSessionId = 'sess-foreign-run';
|
|
844
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
845
|
+
const runDir = join(runsRoot, 'run-foreign-session');
|
|
846
|
+
const runStateDir = join(runDir, '.omx', 'state');
|
|
847
|
+
const foreignSessionDir = join(runStateDir, 'sessions', foreignSessionId);
|
|
848
|
+
const foreignStatePath = join(foreignSessionDir, 'autopilot-state.json');
|
|
849
|
+
const foreignState = JSON.stringify({
|
|
850
|
+
active: true,
|
|
851
|
+
mode: 'autopilot',
|
|
852
|
+
current_phase: 'deep-interview',
|
|
853
|
+
}, null, 2);
|
|
854
|
+
await mkdir(join(stateDir, 'sessions', ownerSessionId), { recursive: true });
|
|
855
|
+
await mkdir(foreignSessionDir, { recursive: true });
|
|
856
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: ownerSessionId }));
|
|
857
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: foreignSessionId }));
|
|
858
|
+
await writeFile(foreignStatePath, foreignState);
|
|
859
|
+
await writeFile(join(runsRoot, 'registry.jsonl'), `${JSON.stringify({
|
|
860
|
+
source_cwd: wd,
|
|
861
|
+
run_dir: runDir,
|
|
862
|
+
})}\n`);
|
|
863
|
+
const cancelResult = runOmxWithEnv(wd, { OMX_RUNS_DIR: runsRoot }, 'cancel');
|
|
864
|
+
assert.notEqual(cancelResult.status, 0);
|
|
865
|
+
assert.match(cancelResult.stderr, /session\.json is present but unusable/);
|
|
866
|
+
assert.doesNotMatch(cancelResult.stdout, /Cancelled: autopilot/);
|
|
867
|
+
assert.equal(await readFile(foreignStatePath, 'utf-8'), foreignState);
|
|
868
|
+
}
|
|
869
|
+
finally {
|
|
870
|
+
await rm(wd, { recursive: true, force: true });
|
|
871
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
it('keeps stale registry-only run state read-only during root cancellation', async () => {
|
|
875
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-stale-registry-'));
|
|
876
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-stale-runs-'));
|
|
877
|
+
try {
|
|
878
|
+
const sessionId = 'sess-stale-registry';
|
|
879
|
+
const runDir = join(runsRoot, 'run-stale-registry');
|
|
880
|
+
const runStateDir = join(runDir, '.omx', 'state');
|
|
881
|
+
const statePath = join(runStateDir, 'sessions', sessionId, 'autopilot-state.json');
|
|
882
|
+
const state = JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'deep-interview' }, null, 2);
|
|
883
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
884
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
885
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId }));
|
|
886
|
+
await writeFile(statePath, state);
|
|
887
|
+
await writeFile(join(runsRoot, 'registry.jsonl'), `${JSON.stringify({ source_cwd: wd, run_dir: runDir })}\n`);
|
|
888
|
+
const cancelResult = runOmxWithEnv(wd, { OMX_RUNS_DIR: runsRoot }, 'cancel');
|
|
889
|
+
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
890
|
+
assert.match(cancelResult.stdout, /No active modes to cancel\./);
|
|
891
|
+
assert.equal(await readFile(statePath, 'utf-8'), state);
|
|
892
|
+
}
|
|
893
|
+
finally {
|
|
894
|
+
await rm(wd, { recursive: true, force: true });
|
|
895
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
it('rejects a live run record whose run directory escapes through a symlink', async () => {
|
|
899
|
+
if (process.platform === 'win32')
|
|
900
|
+
return;
|
|
901
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-symlink-owner-'));
|
|
902
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-symlink-runs-'));
|
|
903
|
+
const outsideRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-symlink-outside-'));
|
|
904
|
+
try {
|
|
905
|
+
const sessionId = 'sess-symlink-escape';
|
|
906
|
+
const tmuxSessionName = 'omx-symlink-run';
|
|
907
|
+
const linkRunDir = join(runsRoot, 'linked-run');
|
|
908
|
+
const outsideStateDir = join(outsideRoot, '.omx', 'state');
|
|
909
|
+
const statePath = join(outsideStateDir, 'sessions', sessionId, 'autopilot-state.json');
|
|
910
|
+
const state = JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'deep-interview' }, null, 2);
|
|
911
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
912
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
913
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
914
|
+
await writeFile(join(outsideStateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: outsideStateDir }));
|
|
915
|
+
await writeFile(statePath, state);
|
|
916
|
+
await symlink(outsideRoot, linkRunDir, 'dir');
|
|
917
|
+
await writeActiveRunRecord({
|
|
918
|
+
runsRoot,
|
|
919
|
+
contextKey: 'symlink-run-context',
|
|
920
|
+
sourceCwd: wd,
|
|
921
|
+
runDir: linkRunDir,
|
|
922
|
+
sessionId,
|
|
923
|
+
tmuxSessionName,
|
|
924
|
+
});
|
|
925
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
926
|
+
OMX_RUNS_DIR: runsRoot,
|
|
927
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
928
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
929
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
930
|
+
}, 'cancel');
|
|
931
|
+
assert.notEqual(cancelResult.status, 0);
|
|
932
|
+
assert.match(cancelResult.stderr, /detached run authority is invalid/);
|
|
933
|
+
assert.equal(await readFile(statePath, 'utf-8'), state);
|
|
934
|
+
}
|
|
935
|
+
finally {
|
|
936
|
+
await rm(wd, { recursive: true, force: true });
|
|
937
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
938
|
+
await rm(outsideRoot, { recursive: true, force: true });
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
it('rejects nested session-directory and state-file symlink escapes', async () => {
|
|
942
|
+
if (process.platform === 'win32')
|
|
943
|
+
return;
|
|
944
|
+
for (const kind of ['session-dir', 'state-file']) {
|
|
945
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-cli-nested-${kind}-owner-`));
|
|
946
|
+
const runsRoot = await mkdtemp(join(tmpdir(), `omx-cli-nested-${kind}-runs-`));
|
|
947
|
+
const outsideRoot = await mkdtemp(join(tmpdir(), `omx-cli-nested-${kind}-outside-`));
|
|
948
|
+
try {
|
|
949
|
+
const sessionId = `sess-nested-${kind}`;
|
|
950
|
+
const tmuxSessionName = `omx-nested-${kind}`;
|
|
951
|
+
const runDir = join(runsRoot, `run-nested-${kind}`);
|
|
952
|
+
const stateDir = join(runDir, '.omx', 'state');
|
|
953
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
954
|
+
const outsideStatePath = join(outsideRoot, 'autopilot-state.json');
|
|
955
|
+
const state = JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'executing' }, null, 2);
|
|
956
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
957
|
+
await mkdir(join(stateDir, 'sessions'), { recursive: true });
|
|
958
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
959
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
960
|
+
await writeFile(outsideStatePath, state);
|
|
961
|
+
if (kind === 'session-dir') {
|
|
962
|
+
await symlink(outsideRoot, sessionDir, 'dir');
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
await mkdir(sessionDir, { recursive: true });
|
|
966
|
+
await symlink(outsideStatePath, join(sessionDir, 'autopilot-state.json'));
|
|
967
|
+
}
|
|
968
|
+
await writeActiveRunRecord({ runsRoot, contextKey: `nested-${kind}`, sourceCwd: wd, runDir, sessionId, tmuxSessionName });
|
|
969
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
970
|
+
OMX_RUNS_DIR: runsRoot,
|
|
971
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
972
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
973
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
974
|
+
}, 'cancel');
|
|
975
|
+
assert.notEqual(cancelResult.status, 0);
|
|
976
|
+
assert.match(cancelResult.stderr, /detached run (?:state )?authority is invalid/);
|
|
977
|
+
assert.equal(await readFile(outsideStatePath, 'utf-8'), state);
|
|
978
|
+
}
|
|
979
|
+
finally {
|
|
980
|
+
await rm(wd, { recursive: true, force: true });
|
|
981
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
982
|
+
await rm(outsideRoot, { recursive: true, force: true });
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
it('revalidates frozen tmux incarnation immediately before mutation', async () => {
|
|
987
|
+
if (process.platform === 'win32')
|
|
988
|
+
return;
|
|
989
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-toctou-owner-'));
|
|
990
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-toctou-runs-'));
|
|
991
|
+
try {
|
|
992
|
+
const sessionId = 'sess-run-toctou';
|
|
993
|
+
const tmuxSessionName = 'omx-run-toctou';
|
|
994
|
+
const runDir = join(runsRoot, 'run-toctou');
|
|
995
|
+
const stateDir = join(runDir, '.omx', 'state');
|
|
996
|
+
const statePath = join(stateDir, 'sessions', sessionId, 'autopilot-state.json');
|
|
997
|
+
const state = JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'executing' }, null, 2);
|
|
998
|
+
const counterPath = join(wd, 'tmux-count');
|
|
999
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
1000
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
1001
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
1002
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
1003
|
+
await writeFile(statePath, state);
|
|
1004
|
+
await writeActiveRunRecord({ runsRoot, contextKey: 'toctou-run', sourceCwd: wd, runDir, sessionId, tmuxSessionName });
|
|
1005
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
1006
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1007
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1008
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1009
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
1010
|
+
FAKE_TMUX_COUNTER_FILE: counterPath,
|
|
1011
|
+
FAKE_TMUX_REPLACE_AFTER_FIRST: '1',
|
|
1012
|
+
}, 'cancel');
|
|
1013
|
+
assert.notEqual(cancelResult.status, 0);
|
|
1014
|
+
assert.match(cancelResult.stderr, /detached run authority changed/);
|
|
1015
|
+
assert.equal(await readFile(statePath, 'utf-8'), state);
|
|
1016
|
+
}
|
|
1017
|
+
finally {
|
|
1018
|
+
await rm(wd, { recursive: true, force: true });
|
|
1019
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
it('denies the entire run transaction when one candidate state is malformed', async () => {
|
|
1023
|
+
if (process.platform === 'win32')
|
|
1024
|
+
return;
|
|
1025
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-malformed-owner-'));
|
|
1026
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-malformed-runs-'));
|
|
1027
|
+
try {
|
|
1028
|
+
const sessionId = 'sess-run-malformed';
|
|
1029
|
+
const tmuxSessionName = 'omx-run-malformed';
|
|
1030
|
+
const runDir = join(runsRoot, 'run-malformed');
|
|
1031
|
+
const stateDir = join(runDir, '.omx', 'state');
|
|
1032
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1033
|
+
const validPath = join(sessionDir, 'ralplan-state.json');
|
|
1034
|
+
const malformedPath = join(sessionDir, 'autopilot-state.json');
|
|
1035
|
+
const validState = JSON.stringify({ active: true, mode: 'ralplan', current_phase: 'executing' }, null, 2);
|
|
1036
|
+
const malformedState = '{"active":true';
|
|
1037
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
1038
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1039
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
1040
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
1041
|
+
await writeFile(validPath, validState);
|
|
1042
|
+
await writeFile(malformedPath, malformedState);
|
|
1043
|
+
await writeActiveRunRecord({ runsRoot, contextKey: 'malformed-run', sourceCwd: wd, runDir, sessionId, tmuxSessionName });
|
|
1044
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
1045
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1046
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1047
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1048
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
1049
|
+
}, 'cancel');
|
|
1050
|
+
assert.notEqual(cancelResult.status, 0);
|
|
1051
|
+
assert.match(cancelResult.stderr, /Refusing partial cancellation/);
|
|
1052
|
+
assert.equal(await readFile(validPath, 'utf-8'), validState);
|
|
1053
|
+
assert.equal(await readFile(malformedPath, 'utf-8'), malformedState);
|
|
1054
|
+
}
|
|
1055
|
+
finally {
|
|
1056
|
+
await rm(wd, { recursive: true, force: true });
|
|
1057
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
it('uses the authorized run session for force native-stop cleanup', async () => {
|
|
1061
|
+
if (process.platform === 'win32')
|
|
1062
|
+
return;
|
|
1063
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-force-owner-'));
|
|
1064
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-force-runs-'));
|
|
1065
|
+
try {
|
|
1066
|
+
const sessionId = 'sess-run-force';
|
|
1067
|
+
const tmuxSessionName = 'omx-run-force';
|
|
1068
|
+
const runDir = join(runsRoot, 'run-force');
|
|
1069
|
+
const stateDir = join(runDir, '.omx', 'state');
|
|
1070
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1071
|
+
const modePath = join(sessionDir, 'autopilot-state.json');
|
|
1072
|
+
const stopPath = join(sessionDir, 'native-stop-state.json');
|
|
1073
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
1074
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1075
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
1076
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
1077
|
+
await writeFile(modePath, JSON.stringify({ active: true, mode: 'autopilot', current_phase: 'executing' }));
|
|
1078
|
+
await writeFile(stopPath, JSON.stringify({ sessions: { [sessionId]: { pending: true }, foreign: { pending: true } } }, null, 2));
|
|
1079
|
+
await writeActiveRunRecord({ runsRoot, contextKey: 'force-run', sourceCwd: wd, runDir, sessionId, tmuxSessionName });
|
|
1080
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
1081
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1082
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1083
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1084
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
1085
|
+
}, 'cancel', '--force');
|
|
1086
|
+
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
1087
|
+
assert.match(cancelResult.stdout, /Cancelled: autopilot/);
|
|
1088
|
+
const stopState = JSON.parse(await readFile(stopPath, 'utf-8'));
|
|
1089
|
+
assert.deepEqual(stopState.sessions, { foreign: { pending: true } });
|
|
1090
|
+
}
|
|
1091
|
+
finally {
|
|
1092
|
+
await rm(wd, { recursive: true, force: true });
|
|
1093
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
it('issue #3550: bound detached-launch pointer lets ambient OMX_SESSION_ID cancel exact-session ralph state while a foreign session cannot', async () => {
|
|
1097
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cancel-3550-detached-root-'));
|
|
1098
|
+
try {
|
|
1099
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1100
|
+
const omxLaunchId = 'omx-3550-launch';
|
|
1101
|
+
const codexRootId = 'codex-root-3550';
|
|
1102
|
+
const canonicalDir = join(stateDir, 'sessions', omxLaunchId);
|
|
1103
|
+
const ralphPath = join(canonicalDir, 'ralph-state.json');
|
|
1104
|
+
const ralphState = JSON.stringify({ active: true, current_phase: 'executing' }, null, 2);
|
|
1105
|
+
await mkdir(canonicalDir, { recursive: true });
|
|
1106
|
+
// Post-SessionStart state on current dev: the detached launch pointer has
|
|
1107
|
+
// rebound to the native Codex root UUID while keeping the OMX owner alias.
|
|
1108
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({
|
|
1109
|
+
session_id: omxLaunchId,
|
|
1110
|
+
native_session_id: codexRootId,
|
|
1111
|
+
owner_omx_session_id: omxLaunchId,
|
|
1112
|
+
cwd: wd,
|
|
1113
|
+
state_root: stateDir,
|
|
1114
|
+
}));
|
|
1115
|
+
await writeFile(ralphPath, ralphState);
|
|
1116
|
+
const foreignCancel = runOmxWithEnv(wd, { OMX_SESSION_ID: 'omx-foreign-session-3550' }, 'cancel', '--force');
|
|
1117
|
+
assert.notEqual(foreignCancel.status, 0);
|
|
1118
|
+
assert.match(foreignCancel.stderr, /OMX_SESSION_ID does not match the live session recorded in session\.json/);
|
|
1119
|
+
assert.equal(await readFile(ralphPath, 'utf-8'), ralphState);
|
|
1120
|
+
const boundCancel = runOmxWithEnv(wd, { OMX_SESSION_ID: omxLaunchId }, 'cancel', '--force');
|
|
1121
|
+
assert.equal(boundCancel.status, 0, boundCancel.stderr || boundCancel.stdout);
|
|
1122
|
+
assert.match(boundCancel.stdout, /Cancelled: ralph/);
|
|
1123
|
+
const updated = JSON.parse(await readFile(ralphPath, 'utf-8'));
|
|
1124
|
+
assert.equal(updated.active, false);
|
|
1125
|
+
assert.equal(updated.current_phase, 'cancelled');
|
|
1126
|
+
}
|
|
1127
|
+
finally {
|
|
1128
|
+
await rm(wd, { recursive: true, force: true });
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
it('fails closed when multiple live run records match the same root', async () => {
|
|
1132
|
+
if (process.platform === 'win32')
|
|
1133
|
+
return;
|
|
1134
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-duplicate-owner-'));
|
|
1135
|
+
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-duplicate-runs-'));
|
|
1136
|
+
try {
|
|
1137
|
+
const sessionId = 'sess-duplicate-live';
|
|
1138
|
+
const tmuxSessionName = 'omx-duplicate-run';
|
|
1139
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
1140
|
+
const states = [];
|
|
1141
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
1142
|
+
for (const [index, mode] of ['autopilot', 'ralplan'].entries()) {
|
|
1143
|
+
const runDir = join(runsRoot, `run-duplicate-${index}`);
|
|
1144
|
+
const runStateDir = join(runDir, '.omx', 'state');
|
|
1145
|
+
const statePath = join(runStateDir, 'sessions', sessionId, `${mode}-state.json`);
|
|
1146
|
+
const content = JSON.stringify({ active: true, mode, current_phase: 'executing' }, null, 2);
|
|
1147
|
+
await mkdir(dirname(statePath), { recursive: true });
|
|
1148
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: runStateDir }));
|
|
1149
|
+
await writeFile(statePath, content);
|
|
1150
|
+
await writeActiveRunRecord({
|
|
1151
|
+
runsRoot,
|
|
1152
|
+
contextKey: `duplicate-run-context-${index}`,
|
|
1153
|
+
sourceCwd: wd,
|
|
1154
|
+
runDir,
|
|
1155
|
+
sessionId,
|
|
1156
|
+
tmuxSessionName,
|
|
1157
|
+
});
|
|
1158
|
+
states.push({ path: statePath, content });
|
|
1159
|
+
}
|
|
1160
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
1161
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1162
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1163
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1164
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
1165
|
+
}, 'cancel');
|
|
1166
|
+
assert.notEqual(cancelResult.status, 0);
|
|
1167
|
+
assert.match(cancelResult.stderr, /No active modes|multiple|authority/i);
|
|
1168
|
+
for (const state of states) {
|
|
1169
|
+
assert.equal(await readFile(state.path, 'utf-8'), state.content);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
finally {
|
|
1173
|
+
await rm(wd, { recursive: true, force: true });
|
|
1174
|
+
await rm(runsRoot, { recursive: true, force: true });
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
109
1177
|
it('cancels hook-visible run-dir session state when worktree state list-active is empty', async () => {
|
|
110
1178
|
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-cancel-worktree-'));
|
|
111
1179
|
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-cancel-runs-'));
|
|
112
1180
|
try {
|
|
1181
|
+
if (process.platform === 'win32')
|
|
1182
|
+
return;
|
|
113
1183
|
const sessionId = 'sess-run-dir-cancel';
|
|
1184
|
+
const tmuxSessionName = 'omx-live-run';
|
|
114
1185
|
const runDir = join(runsRoot, 'run-20260610121751-b6c4');
|
|
115
1186
|
const runStateDir = join(runDir, '.omx', 'state');
|
|
116
1187
|
const runSessionDir = join(runStateDir, 'sessions', sessionId);
|
|
1188
|
+
const fakeBin = await createFakeTmuxBin(wd);
|
|
1189
|
+
const rootAutopilotPath = join(runStateDir, 'autopilot-state.json');
|
|
1190
|
+
const rootAutopilotState = JSON.stringify({
|
|
1191
|
+
active: true,
|
|
1192
|
+
mode: 'autopilot',
|
|
1193
|
+
current_phase: 'stale-root-copy',
|
|
1194
|
+
}, null, 2);
|
|
117
1195
|
await mkdir(runSessionDir, { recursive: true });
|
|
118
1196
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
119
|
-
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1197
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: runStateDir }, null, 2));
|
|
1198
|
+
await writeFile(rootAutopilotPath, rootAutopilotState);
|
|
120
1199
|
await writeFile(join(runSessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
121
1200
|
active: true,
|
|
122
1201
|
mode: 'autopilot',
|
|
@@ -130,18 +1209,23 @@ describe('CLI session-scoped state parity', () => {
|
|
|
130
1209
|
session_id: sessionId,
|
|
131
1210
|
active_skills: [{ skill: 'autopilot', phase: 'deep-interview', active: true, session_id: sessionId }],
|
|
132
1211
|
}, null, 2));
|
|
133
|
-
await
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
})
|
|
1212
|
+
await writeActiveRunRecord({
|
|
1213
|
+
runsRoot,
|
|
1214
|
+
contextKey: 'live-run-context',
|
|
1215
|
+
sourceCwd: wd,
|
|
1216
|
+
runDir,
|
|
1217
|
+
sessionId,
|
|
1218
|
+
tmuxSessionName,
|
|
1219
|
+
});
|
|
141
1220
|
const listResult = runOmx(wd, 'state', 'list-active', '--json');
|
|
142
1221
|
assert.equal(listResult.status, 0, listResult.stderr || listResult.stdout);
|
|
143
1222
|
assert.deepEqual(JSON.parse(listResult.stdout), { active_modes: [] });
|
|
144
|
-
const cancelResult = runOmxWithEnv(wd, {
|
|
1223
|
+
const cancelResult = runOmxWithEnv(wd, {
|
|
1224
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1225
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1226
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1227
|
+
FAKE_TMUX_SESSION_NAME: tmuxSessionName,
|
|
1228
|
+
}, 'cancel');
|
|
145
1229
|
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
146
1230
|
assert.match(cancelResult.stdout, /Cancelled: autopilot/);
|
|
147
1231
|
assert.doesNotMatch(cancelResult.stdout, /No active modes to cancel/);
|
|
@@ -149,6 +1233,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
149
1233
|
assert.equal(autopilot.active, false);
|
|
150
1234
|
assert.equal(autopilot.current_phase, 'cancelled');
|
|
151
1235
|
assert.ok(typeof autopilot.completed_at === 'string' && autopilot.completed_at.length > 0);
|
|
1236
|
+
assert.equal(await readFile(rootAutopilotPath, 'utf-8'), rootAutopilotState);
|
|
152
1237
|
const skillActive = JSON.parse(await readFile(join(runSessionDir, 'skill-active-state.json'), 'utf-8'));
|
|
153
1238
|
assert.equal(skillActive.active, false);
|
|
154
1239
|
assert.equal(skillActive.current_phase, 'cancelled');
|
|
@@ -173,7 +1258,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
173
1258
|
const runSessionDir = join(runStateDir, 'sessions', sessionId);
|
|
174
1259
|
await mkdir(runSessionDir, { recursive: true });
|
|
175
1260
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
176
|
-
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1261
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: runStateDir }, null, 2));
|
|
177
1262
|
await writeFile(join(runSessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
178
1263
|
active: true,
|
|
179
1264
|
mode: 'autopilot',
|
|
@@ -205,35 +1290,39 @@ describe('CLI session-scoped state parity', () => {
|
|
|
205
1290
|
const worktree = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-worktree-alias-wt-'));
|
|
206
1291
|
const runsRoot = await mkdtemp(join(tmpdir(), 'omx-cli-run-dir-worktree-alias-runs-'));
|
|
207
1292
|
try {
|
|
1293
|
+
if (process.platform === 'win32')
|
|
1294
|
+
return;
|
|
208
1295
|
const sessionId = 'sess-run-dir-worktree-alias';
|
|
209
1296
|
const runDir = join(runsRoot, 'run-20260610121751-a11a');
|
|
210
1297
|
const runStateDir = join(runDir, '.omx', 'state');
|
|
211
1298
|
const runSessionDir = join(runStateDir, 'sessions', sessionId);
|
|
1299
|
+
const fakeBin = await createFakeTmuxBin(worktree);
|
|
212
1300
|
await mkdir(runSessionDir, { recursive: true });
|
|
213
1301
|
await mkdir(join(worktree, '.omx', 'state'), { recursive: true });
|
|
214
|
-
await
|
|
215
|
-
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1302
|
+
await writeFile(join(runStateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: runStateDir }, null, 2));
|
|
216
1303
|
await writeFile(join(runSessionDir, 'autopilot-state.json'), JSON.stringify({
|
|
217
1304
|
active: true,
|
|
218
1305
|
mode: 'autopilot',
|
|
219
1306
|
current_phase: 'deep-interview',
|
|
220
1307
|
}, null, 2));
|
|
221
|
-
await
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
session_id: sessionId,
|
|
231
|
-
tmux_pane_id: '%42',
|
|
232
|
-
})}\n`);
|
|
1308
|
+
await writeActiveRunRecord({
|
|
1309
|
+
runsRoot,
|
|
1310
|
+
contextKey: 'ctx-worktree-alias',
|
|
1311
|
+
sourceCwd: wd,
|
|
1312
|
+
worktreeCwd: worktree,
|
|
1313
|
+
runDir,
|
|
1314
|
+
sessionId,
|
|
1315
|
+
tmuxSessionName: 'omx-detached',
|
|
1316
|
+
});
|
|
233
1317
|
const statusResult = runOmxWithEnv(worktree, { OMX_RUNS_DIR: runsRoot }, 'status');
|
|
234
1318
|
assert.equal(statusResult.status, 0, statusResult.stderr || statusResult.stdout);
|
|
235
1319
|
assert.match(statusResult.stdout, /autopilot: ACTIVE \(phase: deep-interview\)/);
|
|
236
|
-
const cancelResult = runOmxWithEnv(worktree, {
|
|
1320
|
+
const cancelResult = runOmxWithEnv(worktree, {
|
|
1321
|
+
OMX_RUNS_DIR: runsRoot,
|
|
1322
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
1323
|
+
FAKE_OMX_SESSION_ID: sessionId,
|
|
1324
|
+
FAKE_TMUX_SESSION_NAME: 'omx-detached',
|
|
1325
|
+
}, 'cancel');
|
|
237
1326
|
assert.equal(cancelResult.status, 0, cancelResult.stderr || cancelResult.stdout);
|
|
238
1327
|
assert.match(cancelResult.stdout, /Cancelled: autopilot/);
|
|
239
1328
|
const autopilot = JSON.parse(await readFile(join(runSessionDir, 'autopilot-state.json'), 'utf-8'));
|
|
@@ -251,7 +1340,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
251
1340
|
try {
|
|
252
1341
|
const stateDir = join(wd, '.omx', 'state');
|
|
253
1342
|
await mkdir(stateDir, { recursive: true });
|
|
254
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: 'sess-stale-autopilot' }, null, 2));
|
|
1343
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: 'sess-stale-autopilot', cwd: wd, state_root: stateDir }, null, 2));
|
|
255
1344
|
const currentAutopilotPath = join(stateDir, 'current-autopilot.json');
|
|
256
1345
|
const currentAutopilot = {
|
|
257
1346
|
active: true,
|
|
@@ -281,7 +1370,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
281
1370
|
const sessionId = 'sess-stale-autopilot-inactive';
|
|
282
1371
|
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
283
1372
|
await mkdir(sessionDir, { recursive: true });
|
|
284
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1373
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }, null, 2));
|
|
285
1374
|
const currentAutopilotPath = join(stateDir, 'current-autopilot.json');
|
|
286
1375
|
const currentAutopilot = {
|
|
287
1376
|
active: true,
|
|
@@ -313,7 +1402,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
313
1402
|
const sessionId = 'sess-active-autopilot';
|
|
314
1403
|
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
315
1404
|
await mkdir(sessionDir, { recursive: true });
|
|
316
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1405
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }, null, 2));
|
|
317
1406
|
await writeFile(join(stateDir, 'current-autopilot.json'), JSON.stringify({
|
|
318
1407
|
active: true,
|
|
319
1408
|
current_phase: 'complete',
|
|
@@ -389,7 +1478,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
389
1478
|
const ultragoalDir = join(wd, '.omx', 'ultragoal');
|
|
390
1479
|
await mkdir(sessionDir, { recursive: true });
|
|
391
1480
|
await mkdir(ultragoalDir, { recursive: true });
|
|
392
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }));
|
|
1481
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
393
1482
|
await writeFile(join(sessionDir, 'ultragoal-state.json'), JSON.stringify({
|
|
394
1483
|
active: true,
|
|
395
1484
|
mode: 'ultragoal',
|
|
@@ -425,7 +1514,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
425
1514
|
const sessionId = 'sess-link';
|
|
426
1515
|
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
427
1516
|
await mkdir(sessionDir, { recursive: true });
|
|
428
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }));
|
|
1517
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
429
1518
|
await writeFile(join(sessionDir, 'ralph-state.json'), JSON.stringify({
|
|
430
1519
|
active: true,
|
|
431
1520
|
iteration: 2,
|
|
@@ -454,6 +1543,27 @@ describe('CLI session-scoped state parity', () => {
|
|
|
454
1543
|
await rm(wd, { recursive: true, force: true });
|
|
455
1544
|
}
|
|
456
1545
|
});
|
|
1546
|
+
it('cancels linked ecomode before Ralph', async () => {
|
|
1547
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-ralph-ecomode-link-'));
|
|
1548
|
+
try {
|
|
1549
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
1550
|
+
const sessionId = 'sess-ecomode-link';
|
|
1551
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
1552
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1553
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }));
|
|
1554
|
+
await writeFile(join(sessionDir, 'ralph-state.json'), JSON.stringify({ active: true, mode: 'ralph', session_id: sessionId, current_phase: 'executing', linked_ecomode: true }));
|
|
1555
|
+
await writeFile(join(sessionDir, 'ecomode-state.json'), JSON.stringify({ active: true, mode: 'ecomode', session_id: sessionId, current_phase: 'executing' }));
|
|
1556
|
+
const result = runOmx(wd, 'cancel');
|
|
1557
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
1558
|
+
assert.match(result.stdout, /Cancelled: ecomode/);
|
|
1559
|
+
assert.match(result.stdout, /Cancelled: ralph/);
|
|
1560
|
+
assert.equal(JSON.parse(await readFile(join(sessionDir, 'ecomode-state.json'), 'utf-8')).active, false);
|
|
1561
|
+
assert.equal(JSON.parse(await readFile(join(sessionDir, 'ralph-state.json'), 'utf-8')).active, false);
|
|
1562
|
+
}
|
|
1563
|
+
finally {
|
|
1564
|
+
await rm(wd, { recursive: true, force: true });
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
457
1567
|
it('does not mutate unrelated sessions when cancelling current session mode', async () => {
|
|
458
1568
|
const wd = await mkdtemp(join(tmpdir(), 'omx-cli-cross-session-'));
|
|
459
1569
|
try {
|
|
@@ -462,7 +1572,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
462
1572
|
const sessionB = join(stateDir, 'sessions', 'sessB');
|
|
463
1573
|
await mkdir(sessionA, { recursive: true });
|
|
464
1574
|
await mkdir(sessionB, { recursive: true });
|
|
465
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: 'sessA' }));
|
|
1575
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: 'sessA', cwd: wd, state_root: stateDir }));
|
|
466
1576
|
await writeFile(join(sessionA, 'ralph-state.json'), JSON.stringify({
|
|
467
1577
|
active: true,
|
|
468
1578
|
current_phase: 'executing',
|
|
@@ -494,7 +1604,7 @@ describe('CLI session-scoped state parity', () => {
|
|
|
494
1604
|
const sessionId = 'sess-stale-autopilot-mirror';
|
|
495
1605
|
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
496
1606
|
await mkdir(sessionDir, { recursive: true });
|
|
497
|
-
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId }, null, 2));
|
|
1607
|
+
await writeFile(join(stateDir, 'session.json'), JSON.stringify({ session_id: sessionId, cwd: wd, state_root: stateDir }, null, 2));
|
|
498
1608
|
await writeFile(join(stateDir, 'autopilot-state.json'), JSON.stringify({
|
|
499
1609
|
active: false,
|
|
500
1610
|
mode: 'autopilot',
|