oh-my-codex 0.21.0 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -1
- package/README.md +4 -2
- package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.d.ts +2 -0
- package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.d.ts.map +1 -0
- package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.js +592 -0
- package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.js.map +1 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js +270 -33
- package/dist/cli/__tests__/detached-leader-teardown.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +133 -5
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +543 -2
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/issue-windows-cancel-identity.test.d.ts +2 -0
- package/dist/cli/__tests__/issue-windows-cancel-identity.test.d.ts.map +1 -0
- package/dist/cli/__tests__/issue-windows-cancel-identity.test.js +17 -0
- package/dist/cli/__tests__/issue-windows-cancel-identity.test.js.map +1 -0
- package/dist/cli/__tests__/launch-fallback.test.js +15 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +20 -0
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-cache-stale-lock.test.d.ts +2 -0
- package/dist/cli/__tests__/plugin-cache-stale-lock.test.d.ts.map +1 -0
- package/dist/cli/__tests__/plugin-cache-stale-lock.test.js +76 -0
- package/dist/cli/__tests__/plugin-cache-stale-lock.test.js.map +1 -0
- package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.d.ts +2 -0
- package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.d.ts.map +1 -0
- package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.js +1662 -0
- package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.js.map +1 -0
- package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.d.ts +2 -0
- package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.d.ts.map +1 -0
- package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.js +522 -0
- package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan-advisory.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-advisory.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-advisory.test.js +301 -0
- package/dist/cli/__tests__/ralplan-advisory.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +39 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +81 -6
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +423 -4
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +60 -3
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +9 -0
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +4 -0
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +71 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +30 -4
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +57 -8
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +113 -7
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1850 -185
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/native-assets.d.ts +2 -1
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +7 -7
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +89 -4
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +2135 -118
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralplan.d.ts +2 -1
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +149 -9
- package/dist/cli/ralplan.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +7 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +9 -10
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/update-worker.js +9 -0
- package/dist/cli/update-worker.js.map +1 -1
- package/dist/cli/update.d.ts +1 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +9 -0
- package/dist/cli/update.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +118 -0
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +74 -4
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +74 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/ralplan-advisory-keyword.test.d.ts +2 -0
- package/dist/hooks/__tests__/ralplan-advisory-keyword.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/ralplan-advisory-keyword.test.js +250 -0
- package/dist/hooks/__tests__/ralplan-advisory-keyword.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +10 -1
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +8 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +130 -9
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/session.d.ts +5 -0
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +17 -3
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +16 -1
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +134 -7
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +57 -0
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/session-attached.test.d.ts +2 -0
- package/dist/hud/__tests__/session-attached.test.d.ts.map +1 -0
- package/dist/hud/__tests__/session-attached.test.js +82 -0
- package/dist/hud/__tests__/session-attached.test.js.map +1 -0
- package/dist/hud/__tests__/state.test.js +94 -2
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux-split-realtmux.test.js +169 -2
- package/dist/hud/__tests__/tmux-split-realtmux.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +104 -22
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/__tests__/types.test.js +9 -0
- package/dist/hud/__tests__/types.test.js.map +1 -1
- package/dist/hud/__tests__/watch-detached.test.d.ts +2 -0
- package/dist/hud/__tests__/watch-detached.test.d.ts.map +1 -0
- package/dist/hud/__tests__/watch-detached.test.js +383 -0
- package/dist/hud/__tests__/watch-detached.test.js.map +1 -0
- package/dist/hud/__tests__/watch-realtmux.test.d.ts +2 -0
- package/dist/hud/__tests__/watch-realtmux.test.d.ts.map +1 -0
- package/dist/hud/__tests__/watch-realtmux.test.js +322 -0
- package/dist/hud/__tests__/watch-realtmux.test.js.map +1 -0
- package/dist/hud/index.d.ts +3 -0
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +98 -20
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +68 -24
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +20 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/session-attached.d.ts +15 -0
- package/dist/hud/session-attached.d.ts.map +1 -0
- package/dist/hud/session-attached.js +47 -0
- package/dist/hud/session-attached.js.map +1 -0
- package/dist/hud/state.d.ts +9 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +140 -3
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +4 -0
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +86 -23
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +20 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +3 -0
- package/dist/hud/types.js.map +1 -1
- package/dist/modes/base.d.ts +15 -2
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +105 -16
- package/dist/modes/base.js.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.js +2 -2
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/ralplan/__tests__/advisory-activation.test.d.ts +2 -0
- package/dist/ralplan/__tests__/advisory-activation.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/advisory-activation.test.js +700 -0
- package/dist/ralplan/__tests__/advisory-activation.test.js.map +1 -0
- package/dist/ralplan/__tests__/advisory-detached-transition.test.d.ts +2 -0
- package/dist/ralplan/__tests__/advisory-detached-transition.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/advisory-detached-transition.test.js +88 -0
- package/dist/ralplan/__tests__/advisory-detached-transition.test.js.map +1 -0
- package/dist/ralplan/__tests__/advisory.test.d.ts +2 -0
- package/dist/ralplan/__tests__/advisory.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/advisory.test.js +1087 -0
- package/dist/ralplan/__tests__/advisory.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +416 -7
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/advisory-activation-verifier.d.ts +19 -0
- package/dist/ralplan/advisory-activation-verifier.d.ts.map +1 -0
- package/dist/ralplan/advisory-activation-verifier.js +77 -0
- package/dist/ralplan/advisory-activation-verifier.js.map +1 -0
- package/dist/ralplan/advisory-activation.d.ts +34 -0
- package/dist/ralplan/advisory-activation.d.ts.map +1 -0
- package/dist/ralplan/advisory-activation.js +205 -0
- package/dist/ralplan/advisory-activation.js.map +1 -0
- package/dist/ralplan/advisory-contract.d.ts +103 -0
- package/dist/ralplan/advisory-contract.d.ts.map +1 -0
- package/dist/ralplan/advisory-contract.js +83 -0
- package/dist/ralplan/advisory-contract.js.map +1 -0
- package/dist/ralplan/advisory-detached-transition.d.ts +11 -0
- package/dist/ralplan/advisory-detached-transition.d.ts.map +1 -0
- package/dist/ralplan/advisory-detached-transition.js +21 -0
- package/dist/ralplan/advisory-detached-transition.js.map +1 -0
- package/dist/ralplan/advisory-evidence.d.ts +91 -0
- package/dist/ralplan/advisory-evidence.d.ts.map +1 -0
- package/dist/ralplan/advisory-evidence.js +393 -0
- package/dist/ralplan/advisory-evidence.js.map +1 -0
- package/dist/ralplan/advisory-lifecycle-validation.d.ts +11 -0
- package/dist/ralplan/advisory-lifecycle-validation.d.ts.map +1 -0
- package/dist/ralplan/advisory-lifecycle-validation.js +72 -0
- package/dist/ralplan/advisory-lifecycle-validation.js.map +1 -0
- package/dist/ralplan/advisory-postconditions.d.ts +3 -0
- package/dist/ralplan/advisory-postconditions.d.ts.map +1 -0
- package/dist/ralplan/advisory-postconditions.js +33 -0
- package/dist/ralplan/advisory-postconditions.js.map +1 -0
- package/dist/ralplan/advisory-recovery-journal.d.ts +56 -0
- package/dist/ralplan/advisory-recovery-journal.d.ts.map +1 -0
- package/dist/ralplan/advisory-recovery-journal.js +136 -0
- package/dist/ralplan/advisory-recovery-journal.js.map +1 -0
- package/dist/ralplan/advisory-storage.d.ts +24 -0
- package/dist/ralplan/advisory-storage.d.ts.map +1 -0
- package/dist/ralplan/advisory-storage.js +106 -0
- package/dist/ralplan/advisory-storage.js.map +1 -0
- package/dist/ralplan/advisory.d.ts +99 -0
- package/dist/ralplan/advisory.d.ts.map +1 -0
- package/dist/ralplan/advisory.js +914 -0
- package/dist/ralplan/advisory.js.map +1 -0
- package/dist/ralplan/documented-leader-preflight.d.ts +8 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -1
- package/dist/ralplan/documented-leader-preflight.js +60 -2
- package/dist/ralplan/documented-leader-preflight.js.map +1 -1
- package/dist/ralplan/runtime-advisory-lifecycle.d.ts +74 -0
- package/dist/ralplan/runtime-advisory-lifecycle.d.ts.map +1 -0
- package/dist/ralplan/runtime-advisory-lifecycle.js +352 -0
- package/dist/ralplan/runtime-advisory-lifecycle.js.map +1 -0
- package/dist/ralplan/runtime-contract.d.ts +126 -0
- package/dist/ralplan/runtime-contract.d.ts.map +1 -0
- package/dist/ralplan/runtime-contract.js +2 -0
- package/dist/ralplan/runtime-contract.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +6 -109
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +174 -56
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.js +26 -0
- package/dist/scripts/__tests__/postinstall.test.js.map +1 -1
- package/dist/scripts/__tests__/ralplan-advisory-hook.test.d.ts +2 -0
- package/dist/scripts/__tests__/ralplan-advisory-hook.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/ralplan-advisory-hook.test.js +299 -0
- package/dist/scripts/__tests__/ralplan-advisory-hook.test.js.map +1 -0
- package/dist/scripts/__tests__/smoke-packed-install.test.js +102 -8
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +20 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +226 -15
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/postinstall.d.ts +7 -0
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +40 -0
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +21 -5
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +157 -57
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/state/__tests__/mode-binding-lease.test.d.ts +2 -0
- package/dist/state/__tests__/mode-binding-lease.test.d.ts.map +1 -0
- package/dist/state/__tests__/mode-binding-lease.test.js +498 -0
- package/dist/state/__tests__/mode-binding-lease.test.js.map +1 -0
- package/dist/state/__tests__/operations.test.js +1 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/pinned-atomic-file.test.d.ts +2 -0
- package/dist/state/__tests__/pinned-atomic-file.test.d.ts.map +1 -0
- package/dist/state/__tests__/pinned-atomic-file.test.js +438 -0
- package/dist/state/__tests__/pinned-atomic-file.test.js.map +1 -0
- package/dist/state/__tests__/skill-active-exact-session-transaction.test.d.ts +2 -0
- package/dist/state/__tests__/skill-active-exact-session-transaction.test.d.ts.map +1 -0
- package/dist/state/__tests__/skill-active-exact-session-transaction.test.js +179 -0
- package/dist/state/__tests__/skill-active-exact-session-transaction.test.js.map +1 -0
- package/dist/state/__tests__/skill-active.test.js +29 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/mode-binding-lease-helper.d.ts +2 -0
- package/dist/state/mode-binding-lease-helper.d.ts.map +1 -0
- package/dist/state/mode-binding-lease-helper.js +623 -0
- package/dist/state/mode-binding-lease-helper.js.map +1 -0
- package/dist/state/mode-binding-lease.d.ts +25 -0
- package/dist/state/mode-binding-lease.d.ts.map +1 -0
- package/dist/state/mode-binding-lease.js +380 -0
- package/dist/state/mode-binding-lease.js.map +1 -0
- package/dist/state/operations.d.ts +29 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +203 -122
- package/dist/state/operations.js.map +1 -1
- package/dist/state/pinned-atomic-file-darwin-client.d.ts +34 -0
- package/dist/state/pinned-atomic-file-darwin-client.d.ts.map +1 -0
- package/dist/state/pinned-atomic-file-darwin-client.js +174 -0
- package/dist/state/pinned-atomic-file-darwin-client.js.map +1 -0
- package/dist/state/pinned-atomic-file-darwin-helper.d.ts +2 -0
- package/dist/state/pinned-atomic-file-darwin-helper.d.ts.map +1 -0
- package/dist/state/pinned-atomic-file-darwin-helper.js +275 -0
- package/dist/state/pinned-atomic-file-darwin-helper.js.map +1 -0
- package/dist/state/pinned-atomic-file-darwin-janitor.d.ts +2 -0
- package/dist/state/pinned-atomic-file-darwin-janitor.d.ts.map +1 -0
- package/dist/state/pinned-atomic-file-darwin-janitor.js +272 -0
- package/dist/state/pinned-atomic-file-darwin-janitor.js.map +1 -0
- package/dist/state/pinned-atomic-file.d.ts +29 -0
- package/dist/state/pinned-atomic-file.d.ts.map +1 -0
- package/dist/state/pinned-atomic-file.js +536 -0
- package/dist/state/pinned-atomic-file.js.map +1 -0
- package/dist/state/process-identity.d.ts +30 -0
- package/dist/state/process-identity.d.ts.map +1 -0
- package/dist/state/process-identity.js +99 -0
- package/dist/state/process-identity.js.map +1 -0
- 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 +82 -5
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +1 -1
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +109 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +10 -1
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.js +20 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -1
- package/dist/utils/file-durability.d.ts +1 -1
- package/dist/utils/file-durability.d.ts.map +1 -1
- package/dist/utils/file-durability.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +12 -4
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/ci-trusted-publish.test.d.ts +2 -0
- package/dist/verification/__tests__/ci-trusted-publish.test.d.ts.map +1 -0
- package/dist/verification/__tests__/ci-trusted-publish.test.js +205 -0
- package/dist/verification/__tests__/ci-trusted-publish.test.js.map +1 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +10 -5
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/publish-npm-manual-retired.test.d.ts +2 -0
- package/dist/verification/__tests__/publish-npm-manual-retired.test.d.ts.map +1 -0
- package/dist/verification/__tests__/publish-npm-manual-retired.test.js +22 -0
- package/dist/verification/__tests__/publish-npm-manual-retired.test.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +10 -1
- package/plugins/oh-my-codex/skills/team/SKILL.md +2 -0
- package/skills/doctor/SKILL.md +1 -1
- package/skills/omx-setup/SKILL.md +1 -1
- package/skills/ralplan/SKILL.md +10 -1
- package/skills/team/SKILL.md +2 -0
- package/src/scripts/__tests__/postinstall.test.ts +28 -0
- package/src/scripts/__tests__/ralplan-advisory-hook.test.ts +320 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +120 -7
- package/src/scripts/codex-native-hook.ts +220 -10
- package/src/scripts/postinstall.ts +46 -0
- package/src/scripts/smoke-packed-install.ts +175 -70
|
@@ -53,6 +53,8 @@ import {
|
|
|
53
53
|
assertCodexBatchWriteResult,
|
|
54
54
|
assertGeneratedTrustMatchesCodex,
|
|
55
55
|
managedCodexHooksByEvent,
|
|
56
|
+
assertNativeHookAdvisoryPreToolUse,
|
|
57
|
+
listPersistedStateFiles,
|
|
56
58
|
} from '../smoke-packed-install.js';
|
|
57
59
|
import { parseNativeSubagentResultDisposition } from '../../leader/contract.js';
|
|
58
60
|
|
|
@@ -1106,7 +1108,7 @@ test('packed install smoke covers directive activation and terminal false-activa
|
|
|
1106
1108
|
{ name: 'compact-explicit-negation', prompt: '$ralplan,$autopilot are prohibited', expectedSkill: null, expectedStopBlock: false },
|
|
1107
1109
|
{ name: 'compact-implicit-negation', prompt: 'Autopilot mode،deep interview are prohibited.', expectedSkill: null, expectedStopBlock: false },
|
|
1108
1110
|
{ name: 'doc-clause-local-prefix', prompt: '$ralplan; $autopilot is documented in the guide.', expectedSkill: 'ralplan', expectedStopBlock: true },
|
|
1109
|
-
{ name: 'doc-chain-described', prompt: 'use $ralplan is the workflow command; autopilot mode is documented in the guide; $team execute it', expectedSkill: 'team', expectedStopBlock:
|
|
1111
|
+
{ name: 'doc-chain-described', prompt: 'use $ralplan is the workflow command; autopilot mode is documented in the guide; $team execute it', expectedSkill: 'team', expectedStopBlock: true, insideTmux: true },
|
|
1110
1112
|
{ name: 'doc-chain-workflow', prompt: 'use $ralplan is the workflow command; autopilot mode is workflow documentation; use $ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
|
|
1111
1113
|
{ name: 'ref-inline-explicit', prompt: '[docs]: $ralplan\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
1112
1114
|
{ name: 'ref-inline-prompts', prompt: '[docs]: /prompts:architect\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
@@ -1132,10 +1134,10 @@ test('packed install smoke covers directive activation and terminal false-activa
|
|
|
1132
1134
|
{ name: 'neg-fw-dot-reopen', prompt: 'Do not run $ralplan. use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
1133
1135
|
{ name: 'neg-greek-q-reopen', prompt: 'Do not run $ralplan; use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
1134
1136
|
{ name: 'unicode-attached-contrast', prompt: 'Do not use deep interview яbut use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
|
|
1135
|
-
{ name: 'prefix-list-followup', prompt: 'Do not run $ralplan, $autopilot; use $team execute it', expectedSkill: 'team', expectedStopBlock:
|
|
1137
|
+
{ name: 'prefix-list-followup', prompt: 'Do not run $ralplan, $autopilot; use $team execute it', expectedSkill: 'team', expectedStopBlock: true, insideTmux: true },
|
|
1136
1138
|
{ name: 'mixed-postposed-chain', prompt: '$ralplan, autopilot mode, $team are prohibited.', expectedSkill: null, expectedStopBlock: false },
|
|
1137
|
-
{ name: 'implicit-first-doc-chain', prompt: 'Autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock:
|
|
1138
|
-
{ name: 'both-mixed-doc-followup', prompt: 'Both autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock:
|
|
1139
|
+
{ name: 'implicit-first-doc-chain', prompt: 'Autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock: true, insideTmux: true },
|
|
1140
|
+
{ name: 'both-mixed-doc-followup', prompt: 'Both autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock: true, insideTmux: true },
|
|
1139
1141
|
{ name: 'doc-semicolon-preserves-earlier', prompt: 'Use autopilot mode; use $ralplan is the workflow command.', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
1140
1142
|
{ name: 'doc-independent-comma', prompt: 'Use autopilot mode, and $ralplan is documented in the guide.', expectedSkill: 'autopilot', expectedStopBlock: true },
|
|
1141
1143
|
{ name: 'reference-unclosed-quote-destination', prompt: '[docs]: "target\n$autopilot build it', expectedSkill: null, expectedStopBlock: false },
|
|
@@ -1183,14 +1185,14 @@ test('packed install smoke covers directive activation and terminal false-activa
|
|
|
1183
1185
|
{ name: 'percent-suffix', prompt: '$ralplan%docs', expectedSkill: null, expectedStopBlock: false },
|
|
1184
1186
|
{ name: 'fullwidth-percent-suffix', prompt: '$ralplan%docs', expectedSkill: null, expectedStopBlock: false },
|
|
1185
1187
|
{ name: 'g1a-ordered-multi-skill', prompt: '$ralplan, $autopilot; $team', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: ['autopilot', 'team'], expectedActiveSkills: ['ralplan'], insideTmux: true },
|
|
1186
|
-
{ name: 'g1c-duplicate-alias', prompt: '$autopilot $oh-my-codex:autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true, expectedDeferredSkills: [], expectedActiveSkills: [] },
|
|
1188
|
+
{ name: 'g1c-duplicate-alias', prompt: '$autopilot $oh-my-codex:autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true, expectedDeferredSkills: [], expectedActiveSkills: ['autopilot'] },
|
|
1187
1189
|
{ name: 'b3-longer-valid-fence', prompt: '```text\n$autopilot build it\n````\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
|
|
1188
1190
|
{ name: 'b4-shorter-invalid-fence', prompt: '````text\n$autopilot build it\n```\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
|
|
1189
1191
|
{ name: 'b5-different-marker-invalid-fence', prompt: '```text\n$autopilot build it\n~~~\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
|
|
1190
1192
|
]);
|
|
1191
1193
|
});
|
|
1192
1194
|
|
|
1193
|
-
test('packed regression workflow expectations require active
|
|
1195
|
+
test('packed regression workflow expectations require active supported skills and failed retired ralph receipts', () => {
|
|
1194
1196
|
assert.doesNotThrow(() => assertPackedRegressionWorkflowState(
|
|
1195
1197
|
{ name: 'active-ralplan', expectedSkill: 'ralplan' },
|
|
1196
1198
|
{ active: true, skill: 'ralplan' },
|
|
@@ -1203,11 +1205,26 @@ test('packed regression workflow expectations require active Autopilot and Ralpl
|
|
|
1203
1205
|
{ name: 'failed-autopilot', expectedSkill: 'autopilot' },
|
|
1204
1206
|
{ active: false, skill: 'autopilot', phase: 'failed', active_skills: [] },
|
|
1205
1207
|
), /persisted unexpected workflow state/);
|
|
1208
|
+
assert.doesNotThrow(() => assertPackedRegressionWorkflowState(
|
|
1209
|
+
{ name: 'retired-ralph', expectedSkill: 'ralph' },
|
|
1210
|
+
{
|
|
1211
|
+
active: false,
|
|
1212
|
+
skill: 'ralph',
|
|
1213
|
+
phase: 'failed',
|
|
1214
|
+
transition_error: 'Skill "$ralph" has been removed. Use "$ultragoal" instead. The `omx ralph` CLI and ralph persistence runtime are unaffected.',
|
|
1215
|
+
active_skills: [],
|
|
1216
|
+
},
|
|
1217
|
+
));
|
|
1218
|
+
assert.throws(() => assertPackedRegressionWorkflowState(
|
|
1219
|
+
{ name: 'active-retired-ralph', expectedSkill: 'ralph' },
|
|
1220
|
+
{ active: true, skill: 'ralph', phase: 'executing' },
|
|
1221
|
+
), /unexpected retired ralph state/);
|
|
1206
1222
|
});
|
|
1207
1223
|
|
|
1208
|
-
test('packed regression Stop expectations keep active
|
|
1224
|
+
test('packed regression Stop expectations keep active workflows blocked but retired ralph terminal', () => {
|
|
1209
1225
|
assert.equal(shouldPackedRegressionStopBlock({ expectedSkill: 'ralplan', expectedStopBlock: true }), true);
|
|
1210
1226
|
assert.equal(shouldPackedRegressionStopBlock({ expectedSkill: 'autopilot', expectedStopBlock: true }), true);
|
|
1227
|
+
assert.equal(shouldPackedRegressionStopBlock({ expectedSkill: 'ralph', expectedStopBlock: true }), false);
|
|
1211
1228
|
});
|
|
1212
1229
|
|
|
1213
1230
|
test('packed regression environment clears inherited Team routing state', () => {
|
|
@@ -1695,3 +1712,99 @@ test('ensureRepoDependencies falls back to npm ci when no reusable node_modules
|
|
|
1695
1712
|
await rm(root, { recursive: true, force: true });
|
|
1696
1713
|
}
|
|
1697
1714
|
});
|
|
1715
|
+
test('assertNativeHookAdvisoryPreToolUse accepts the two documented advisory shapes', () => {
|
|
1716
|
+
// Empty no-op: the hook intentionally produced no advisory content (#3497).
|
|
1717
|
+
assertNativeHookAdvisoryPreToolUse('advisory-empty', {});
|
|
1718
|
+
|
|
1719
|
+
// Documented advisory context with the PreToolUse event name.
|
|
1720
|
+
assertNativeHookAdvisoryPreToolUse('advisory-context', {
|
|
1721
|
+
systemMessage: 'advisory guidance',
|
|
1722
|
+
hookSpecificOutput: {
|
|
1723
|
+
hookEventName: 'PreToolUse',
|
|
1724
|
+
additionalContext: 'advisory guidance',
|
|
1725
|
+
},
|
|
1726
|
+
});
|
|
1727
|
+
|
|
1728
|
+
// systemMessage alone, without a hookSpecificOutput envelope, is also advisory.
|
|
1729
|
+
assertNativeHookAdvisoryPreToolUse('advisory-system-message', { systemMessage: 'guidance only' });
|
|
1730
|
+
});
|
|
1731
|
+
|
|
1732
|
+
test('assertNativeHookAdvisoryPreToolUse rejects outputs that would hide a regression', () => {
|
|
1733
|
+
const rejections: Array<[string, Record<string, unknown>, RegExp]> = [
|
|
1734
|
+
['hard block', { decision: 'block', reason: 'nope' }, /hard block/],
|
|
1735
|
+
['stopped continuation', { continue: false }, /stopped continuation/],
|
|
1736
|
+
['stopReason', { stopReason: 'native_hook_stdin_parse_error' }, /emitted stopReason/],
|
|
1737
|
+
['permission deny', {
|
|
1738
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny' },
|
|
1739
|
+
}, /permissionDecision "deny"/],
|
|
1740
|
+
['permission allow', {
|
|
1741
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' },
|
|
1742
|
+
}, /permissionDecision "allow"/],
|
|
1743
|
+
['wrong event name', {
|
|
1744
|
+
systemMessage: 'x',
|
|
1745
|
+
hookSpecificOutput: { hookEventName: 'Stop', additionalContext: 'x' },
|
|
1746
|
+
}, /hookSpecificOutput names "Stop"/],
|
|
1747
|
+
['non-string system message', { systemMessage: 1 }, /malformed systemMessage/],
|
|
1748
|
+
['empty system message', { systemMessage: '' }, /malformed systemMessage/],
|
|
1749
|
+
['empty envelope', { hookSpecificOutput: {} }, /malformed PreToolUse advisory envelope/],
|
|
1750
|
+
['system message plus empty envelope', {
|
|
1751
|
+
systemMessage: 'x',
|
|
1752
|
+
hookSpecificOutput: {},
|
|
1753
|
+
}, /malformed PreToolUse advisory envelope/],
|
|
1754
|
+
['envelope without event name', {
|
|
1755
|
+
systemMessage: 'x',
|
|
1756
|
+
hookSpecificOutput: { additionalContext: 'x' },
|
|
1757
|
+
}, /malformed PreToolUse advisory envelope/],
|
|
1758
|
+
['envelope without context', {
|
|
1759
|
+
systemMessage: 'x',
|
|
1760
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse' },
|
|
1761
|
+
}, /malformed PreToolUse advisory envelope/],
|
|
1762
|
+
['mismatched envelope content', {
|
|
1763
|
+
systemMessage: 'x',
|
|
1764
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: 'y' },
|
|
1765
|
+
}, /does not mirror systemMessage/],
|
|
1766
|
+
['unexpected top-level field', { systemMessage: 'x', reason: 'stray' }, /unexpected top-level field "reason"/],
|
|
1767
|
+
['unexpected hook field', {
|
|
1768
|
+
systemMessage: 'x',
|
|
1769
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecisionReason: 'stray' },
|
|
1770
|
+
}, /emitted unexpected field "permissionDecisionReason"/],
|
|
1771
|
+
['malformed hookSpecificOutput', { hookSpecificOutput: 'nope' }, /malformed hookSpecificOutput/],
|
|
1772
|
+
['array hookSpecificOutput', { hookSpecificOutput: [] }, /malformed hookSpecificOutput/],
|
|
1773
|
+
];
|
|
1774
|
+
for (const [label, output, pattern] of rejections) {
|
|
1775
|
+
assert.throws(
|
|
1776
|
+
() => assertNativeHookAdvisoryPreToolUse(`probe-${label}`, output),
|
|
1777
|
+
pattern,
|
|
1778
|
+
`${label} must be rejected`,
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
|
|
1783
|
+
test('listPersistedStateFiles permits empty state directory bootstrap but detects persisted artifacts', async () => {
|
|
1784
|
+
const root = await mkdtemp(join(tmpdir(), 'omx-packed-state-artifacts-'));
|
|
1785
|
+
try {
|
|
1786
|
+
const stateRoot = join(root, '.omx', 'state');
|
|
1787
|
+
await mkdir(join(stateRoot, 'sessions', 'nested'), { recursive: true });
|
|
1788
|
+
assert.deepEqual(listPersistedStateFiles(stateRoot), []);
|
|
1789
|
+
|
|
1790
|
+
const persistedFile = join(stateRoot, 'sessions', 'nested', 'skill-active-state.json');
|
|
1791
|
+
await writeFile(persistedFile, '{}\n');
|
|
1792
|
+
assert.deepEqual(listPersistedStateFiles(stateRoot), [persistedFile]);
|
|
1793
|
+
await rm(persistedFile);
|
|
1794
|
+
|
|
1795
|
+
const symlinkPath = join(stateRoot, 'sessions', 'state-link');
|
|
1796
|
+
await symlink(join(root, 'missing-target'), symlinkPath);
|
|
1797
|
+
assert.deepEqual(listPersistedStateFiles(stateRoot), [symlinkPath]);
|
|
1798
|
+
await rm(symlinkPath);
|
|
1799
|
+
|
|
1800
|
+
const rootLink = join(root, 'state-link');
|
|
1801
|
+
await symlink(stateRoot, rootLink);
|
|
1802
|
+
assert.deepEqual(listPersistedStateFiles(rootLink), [rootLink]);
|
|
1803
|
+
|
|
1804
|
+
const rootFile = join(root, 'state-file');
|
|
1805
|
+
await writeFile(rootFile, '{}\n');
|
|
1806
|
+
assert.deepEqual(listPersistedStateFiles(rootFile), [rootFile]);
|
|
1807
|
+
} finally {
|
|
1808
|
+
await rm(root, { recursive: true, force: true });
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import { accessSync, closeSync, constants as fsConstants, existsSync, lstatSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync } from "fs";
|
|
3
|
-
import { appendFile, lstat, mkdir, open, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
|
|
3
|
+
import { appendFile, lstat, mkdir, open, readFile, readdir, realpath, stat, unlink, writeFile } from "fs/promises";
|
|
4
4
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "path";
|
|
5
5
|
import { createHash } from "crypto";
|
|
6
6
|
|
|
@@ -32,6 +32,12 @@ import {
|
|
|
32
32
|
} from "../subagents/tracker.js";
|
|
33
33
|
|
|
34
34
|
import { readRoleRoutingMarker, writeRoleRoutingMarker } from "../subagents/role-routing-marker.js";
|
|
35
|
+
import {
|
|
36
|
+
readCurrentRalplanAdvisory,
|
|
37
|
+
reconcileRalplanAdvisory,
|
|
38
|
+
observeRalplanAdvisoryPrompt,
|
|
39
|
+
} from "../ralplan/advisory.js";
|
|
40
|
+
import { activateOrResumeRalplanAdvisory } from "../ralplan/advisory-activation.js";
|
|
35
41
|
import {
|
|
36
42
|
resolveCanonicalTeamStateRoot,
|
|
37
43
|
resolveWorkerTeamStateRootPath,
|
|
@@ -57,6 +63,7 @@ import {
|
|
|
57
63
|
readUsableSessionState,
|
|
58
64
|
reconcileNativeSessionStart,
|
|
59
65
|
resolveSessionPointerContext,
|
|
66
|
+
sessionOwnerFileIdentityMatches,
|
|
60
67
|
type SessionStartOptions,
|
|
61
68
|
writeNativeSessionOwner,
|
|
62
69
|
type SessionState
|
|
@@ -210,6 +217,9 @@ interface NativeHookDispatchOptions {
|
|
|
210
217
|
/** @internal Scoped deterministic SessionStart durability seam for native-hook tests. */
|
|
211
218
|
sessionStartOptions?: Pick<SessionStartOptions, 'platform' | 'regularFileSync'>;
|
|
212
219
|
reconcileHudForPromptSubmitFn?: typeof reconcileHudForPromptSubmit;
|
|
220
|
+
/** @internal Deterministic Advisory reconciliation failure seam for hook tests. */
|
|
221
|
+
reconcileRalplanAdvisoryFn?: typeof reconcileRalplanAdvisory;
|
|
222
|
+
/** @internal Deterministic Advisory detect/read race seam for native-hook tests. */
|
|
213
223
|
}
|
|
214
224
|
|
|
215
225
|
export interface NativeHookDispatchResult {
|
|
@@ -3735,7 +3745,11 @@ function hookCancelIdentity(stats: { dev: number; ino: number; mode: number; uid
|
|
|
3735
3745
|
return { dev: stats.dev, ino: stats.ino, mode: stats.mode, uid: stats.uid, size: stats.size, mtimeMs: stats.mtimeMs };
|
|
3736
3746
|
}
|
|
3737
3747
|
function hookCancelIdentityMatches(left: HookCancelTargetIdentity, right: HookCancelTargetIdentity): boolean {
|
|
3738
|
-
return left
|
|
3748
|
+
return sessionOwnerFileIdentityMatches(left, right, hookCancelPlatform())
|
|
3749
|
+
&& left.mode === right.mode
|
|
3750
|
+
&& left.uid === right.uid
|
|
3751
|
+
&& left.size === right.size
|
|
3752
|
+
&& left.mtimeMs === right.mtimeMs;
|
|
3739
3753
|
}
|
|
3740
3754
|
function hookCancelTargetMatches(left: HookCancelTargetIdentity, right: HookCancelTargetIdentity): boolean {
|
|
3741
3755
|
return left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid;
|
|
@@ -5552,6 +5566,7 @@ const NATIVE_CODEX_GOAL_READ_TOOL_NAMES = new Set([
|
|
|
5552
5566
|
"get_goal",
|
|
5553
5567
|
"functions.get_goal",
|
|
5554
5568
|
"functionsget_goal",
|
|
5569
|
+
"mcp__omx_goal__get_goal",
|
|
5555
5570
|
]);
|
|
5556
5571
|
const NATIVE_CODEX_GOAL_LIFECYCLE_TOOL_NAMES = new Set([
|
|
5557
5572
|
"create_goal",
|
|
@@ -5560,6 +5575,8 @@ const NATIVE_CODEX_GOAL_LIFECYCLE_TOOL_NAMES = new Set([
|
|
|
5560
5575
|
"functions.update_goal",
|
|
5561
5576
|
"functionscreate_goal",
|
|
5562
5577
|
"functionsupdate_goal",
|
|
5578
|
+
"mcp__omx_goal__create_goal",
|
|
5579
|
+
"mcp__omx_goal__update_goal",
|
|
5563
5580
|
]);
|
|
5564
5581
|
|
|
5565
5582
|
function canonicalizeNativeCodexGoalToolName(name: string): string {
|
|
@@ -10133,6 +10150,111 @@ function directOmxCancelCommandHasTrustedExecutionContext(command: string, cwd:
|
|
|
10133
10150
|
return omxOrGjcExecutionContextIsTrusted(command, cwd, ["omx"]);
|
|
10134
10151
|
}
|
|
10135
10152
|
|
|
10153
|
+
export type RalplanAdvisoryStateDetection =
|
|
10154
|
+
| { status: "normal"; root: string }
|
|
10155
|
+
| { status: "missing"; root: string; reason: "advisory_binding_without_state_root" }
|
|
10156
|
+
| { status: "unreadable"; root: string; reason: string }
|
|
10157
|
+
| { status: "none"; root: string };
|
|
10158
|
+
|
|
10159
|
+
async function sessionHasAdvisoryBinding(cwd: string, sessionId: string): Promise<boolean> {
|
|
10160
|
+
const path = join(getBaseStateDir(cwd), "sessions", sessionId, "ralplan-state.json");
|
|
10161
|
+
let handle: Awaited<ReturnType<typeof open>>;
|
|
10162
|
+
try {
|
|
10163
|
+
handle = await open(path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
10164
|
+
} catch (error) {
|
|
10165
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
|
|
10166
|
+
throw error;
|
|
10167
|
+
}
|
|
10168
|
+
try {
|
|
10169
|
+
const info = await handle.stat();
|
|
10170
|
+
if (!info.isFile() || info.nlink !== 1 || info.size > 1024 * 1024) throw new Error("ralplan_advisory_binding_file_invalid");
|
|
10171
|
+
const value = JSON.parse((await handle.readFile()).toString("utf8")) as unknown;
|
|
10172
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("ralplan_advisory_binding_json_invalid");
|
|
10173
|
+
return (value as Record<string, unknown>).workflow_variant === "advisory";
|
|
10174
|
+
} finally {
|
|
10175
|
+
await handle.close();
|
|
10176
|
+
}
|
|
10177
|
+
}
|
|
10178
|
+
|
|
10179
|
+
export async function detectRalplanAdvisoryState(cwd: string, sessionId: string): Promise<RalplanAdvisoryStateDetection> {
|
|
10180
|
+
let canonicalCwd: string;
|
|
10181
|
+
try { canonicalCwd = await realpath(cwd); }
|
|
10182
|
+
catch (error) {
|
|
10183
|
+
const root = join(getBaseStateDir(cwd), "sessions", sessionId, "ralplan-advisory");
|
|
10184
|
+
return { status: "unreadable", root, reason: `cwd_realpath_${(error as NodeJS.ErrnoException).code ?? "failed"}` };
|
|
10185
|
+
}
|
|
10186
|
+
const root = join(getBaseStateDir(canonicalCwd), "sessions", sessionId, "ralplan-advisory");
|
|
10187
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(sessionId)) {
|
|
10188
|
+
return { status: "unreadable", root, reason: "session_id_invalid" };
|
|
10189
|
+
}
|
|
10190
|
+
try {
|
|
10191
|
+
const info = await lstat(root);
|
|
10192
|
+
let canonical: string;
|
|
10193
|
+
try { canonical = await realpath(root); }
|
|
10194
|
+
catch (error) { return { status: "unreadable", root, reason: `state_root_realpath_${(error as NodeJS.ErrnoException).code ?? "failed"}` }; }
|
|
10195
|
+
if (!info.isDirectory()) return { status: "unreadable", root, reason: "state_root_not_canonical_directory" };
|
|
10196
|
+
if (canonical !== root) return { status: "unreadable", root, reason: "state_root_not_canonical" };
|
|
10197
|
+
return { status: "normal", root };
|
|
10198
|
+
} catch (error) {
|
|
10199
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
10200
|
+
return { status: "unreadable", root, reason: `state_root_lstat_${(error as NodeJS.ErrnoException).code ?? "failed"}` };
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10203
|
+
try {
|
|
10204
|
+
return await sessionHasAdvisoryBinding(canonicalCwd, sessionId)
|
|
10205
|
+
? { status: "missing", root, reason: "advisory_binding_without_state_root" }
|
|
10206
|
+
: { status: "none", root };
|
|
10207
|
+
} catch (error) {
|
|
10208
|
+
return { status: "unreadable", root, reason: `binding_${(error as NodeJS.ErrnoException).code ?? "invalid"}` };
|
|
10209
|
+
}
|
|
10210
|
+
}
|
|
10211
|
+
|
|
10212
|
+
export function buildRalplanAdvisoryRoutingObservation(
|
|
10213
|
+
intent: string,
|
|
10214
|
+
projection: Awaited<ReturnType<typeof readCurrentRalplanAdvisory>>,
|
|
10215
|
+
binding: Record<string, unknown> | null,
|
|
10216
|
+
): string | null {
|
|
10217
|
+
if (intent !== "execute" || !projection) return null;
|
|
10218
|
+
if (projection.corruption) {
|
|
10219
|
+
return `Ralplan Advisory evidence is not a valid lifecycle projection (${projection.corruption}); this non-authoritative diagnostic does not grant or deny host tool permission.`;
|
|
10220
|
+
}
|
|
10221
|
+
const fence = projection.fence;
|
|
10222
|
+
if (!fence) return "Ralplan Advisory planning has not reached a terminal lifecycle state; no automatic execution handoff was created.";
|
|
10223
|
+
const matchingAdvisoryBinding = binding?.workflow_variant === "advisory"
|
|
10224
|
+
&& binding.advisory_generation_id === projection.activation.generation_id;
|
|
10225
|
+
const conflictingWorkflow = binding?.active === true && !matchingAdvisoryBinding;
|
|
10226
|
+
if (conflictingWorkflow) return null;
|
|
10227
|
+
if (fence.state === "pending_closeout") {
|
|
10228
|
+
return "Ralplan Advisory closeout is still pending; no automatic execution handoff was created.";
|
|
10229
|
+
}
|
|
10230
|
+
if (fence.state === "recovery_required") {
|
|
10231
|
+
return "Ralplan Advisory evidence requires lifecycle recovery; no automatic execution handoff was created.";
|
|
10232
|
+
}
|
|
10233
|
+
if (fence.state === "abandoned") {
|
|
10234
|
+
return `Ralplan Advisory ended as ${fence.outcome ?? "abandoned"}, not as an approved planning result; later instructions follow normal host rules.`;
|
|
10235
|
+
}
|
|
10236
|
+
const lifecycle = projection.journal?.terminal_mode_updates?.ralplan_review_lifecycle;
|
|
10237
|
+
const lifecycleRecord = lifecycle && typeof lifecycle === "object" && !Array.isArray(lifecycle)
|
|
10238
|
+
? lifecycle as Record<string, unknown>
|
|
10239
|
+
: null;
|
|
10240
|
+
const complete = fence.state === "closed" && fence.outcome === "approved" && fence.integrity_status === "proven"
|
|
10241
|
+
&& projection.journal?.phase === "committed" && projection.journal.outcome === "approved"
|
|
10242
|
+
&& lifecycleRecord?.complete === true
|
|
10243
|
+
&& lifecycleRecord.sequence_valid === true
|
|
10244
|
+
&& lifecycleRecord.iteration === fence.iteration
|
|
10245
|
+
&& lifecycleRecord.iteration_id === fence.iteration_id
|
|
10246
|
+
&& lifecycleRecord.plan_manifest_sha256 === fence.plan_manifest_sha256
|
|
10247
|
+
&& lifecycleRecord.architect_review_sha256 === fence.architect_review_sha256
|
|
10248
|
+
&& lifecycleRecord.critic_review_sha256 === fence.critic_review_sha256
|
|
10249
|
+
&& lifecycleRecord.evidence_bundle_sha256 === fence.evidence_bundle_sha256
|
|
10250
|
+
&& lifecycleRecord.evidence_scope === "local_runtime"
|
|
10251
|
+
&& lifecycleRecord.host_observable === false
|
|
10252
|
+
&& lifecycleRecord.host_verified === false;
|
|
10253
|
+
return complete
|
|
10254
|
+
? "Ralplan Advisory planning is complete and its byte-bound evidence remains auditable. This execution request is a non-authoritative routing observation only; no local Advisory file or classifier grants tool permission or an automatic execution handoff."
|
|
10255
|
+
: "Ralplan Advisory does not contain a complete approved and proven planning lifecycle; no automatic execution handoff was created.";
|
|
10256
|
+
}
|
|
10257
|
+
|
|
10136
10258
|
function isCommandResolutionSensitiveEnvironmentName(name: string): boolean {
|
|
10137
10259
|
// Variables that redirect where the shell resolves the executable itself.
|
|
10138
10260
|
// A leading PATH/PATHEXT override can point a bare `omx`/`rtk` at an
|
|
@@ -21769,6 +21891,7 @@ export async function dispatchCodexNativeHook(
|
|
|
21769
21891
|
): Promise<NativeHookDispatchResult> {
|
|
21770
21892
|
const hookEventName = readHookEventName(payload);
|
|
21771
21893
|
const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
|
|
21894
|
+
const reconcileAdvisory = options.reconcileRalplanAdvisoryFn ?? reconcileRalplanAdvisory;
|
|
21772
21895
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
21773
21896
|
// #3497 / C1 boundary: documented-leader PreToolUse hard gate removed.
|
|
21774
21897
|
if (hookEventName === "PreToolUse" && safeString(payload.tool_name).trim() === "Bash") {
|
|
@@ -21820,6 +21943,7 @@ export async function dispatchCodexNativeHook(
|
|
|
21820
21943
|
let goalWorkflowAdditionalContext: string | null = null;
|
|
21821
21944
|
let ultragoalSteeringAdditionalContext: string | null = null;
|
|
21822
21945
|
let teamNoticeAdditionalContext: string | null = null;
|
|
21946
|
+
let advisoryAdditionalContext: string | null = null;
|
|
21823
21947
|
let teamNoticeTargetKey: string | null = null;
|
|
21824
21948
|
let promptClassification: KeywordInputClassification | null = null;
|
|
21825
21949
|
|
|
@@ -22183,13 +22307,84 @@ export async function dispatchCodexNativeHook(
|
|
|
22183
22307
|
(isSubagentSessionStart || isSubagentStop)
|
|
22184
22308
|
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
22185
22309
|
|
|
22310
|
+
const advisoryStateDetection = canonicalSessionId
|
|
22311
|
+
&& (hookEventName === "SessionStart" || hookEventName === "Stop" || hookEventName === "UserPromptSubmit")
|
|
22312
|
+
? await detectRalplanAdvisoryState(policyCwd, canonicalSessionId)
|
|
22313
|
+
: null;
|
|
22314
|
+
if ((hookEventName === "SessionStart" || hookEventName === "Stop") && canonicalSessionId
|
|
22315
|
+
&& advisoryStateDetection?.status === "normal") {
|
|
22316
|
+
try {
|
|
22317
|
+
const reconciledAdvisory = await reconcileAdvisory(policyCwd, canonicalSessionId);
|
|
22318
|
+
if (reconciledAdvisory?.corruption === "live_session_binding_conflict"
|
|
22319
|
+
|| reconciledAdvisory?.corruption === "live_session_binding_unreadable") {
|
|
22320
|
+
throw new Error(reconciledAdvisory.corruption);
|
|
22321
|
+
}
|
|
22322
|
+
} catch (error) {
|
|
22323
|
+
const diagnostic = `Ralplan Advisory lifecycle reconciliation reported a non-authoritative diagnostic: ${error instanceof Error ? error.message : String(error)}. It does not grant or deny host tool permission.`;
|
|
22324
|
+
if (hookEventName === "SessionStart") {
|
|
22325
|
+
advisoryAdditionalContext = diagnostic;
|
|
22326
|
+
} else {
|
|
22327
|
+
await appendToLog(cwd, {
|
|
22328
|
+
event: "ralplan_advisory_reconciliation_diagnostic",
|
|
22329
|
+
hook_event_name: "Stop",
|
|
22330
|
+
session_id: canonicalSessionId,
|
|
22331
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
22332
|
+
non_authoritative: true,
|
|
22333
|
+
timestamp: new Date().toISOString(),
|
|
22334
|
+
}).catch(() => {});
|
|
22335
|
+
}
|
|
22336
|
+
}
|
|
22337
|
+
}
|
|
22338
|
+
|
|
22186
22339
|
if (hookEventName === "UserPromptSubmit") {
|
|
22187
22340
|
const prompt = readPromptText(payload);
|
|
22188
|
-
|
|
22189
|
-
|
|
22341
|
+
const advisoryThreadKind = promptTurnContext?.status === "authorized"
|
|
22342
|
+
&& promptTurnContext.authorization.targetRelation !== "explicit-independent"
|
|
22343
|
+
&& promptTurnContext.authorization.thread.kind === "root-or-drift"
|
|
22344
|
+
? "root-or-drift" : "unknown";
|
|
22345
|
+
if (!isSubagentPromptSubmit) promptClassification = classifyKeywordInput(prompt);
|
|
22346
|
+
if (canonicalSessionId && !isSubagentPromptSubmit && advisoryStateDetection?.status === "normal") {
|
|
22347
|
+
try {
|
|
22348
|
+
await activateOrResumeRalplanAdvisory({
|
|
22349
|
+
cwd: policyCwd, sessionId: canonicalSessionId, rootThreadId: threadId,
|
|
22350
|
+
activationTurnId: turnId, prompt, resumeOnly: true, producer: "native", threadKind: advisoryThreadKind,
|
|
22351
|
+
});
|
|
22352
|
+
const advisory = await observeRalplanAdvisoryPrompt({
|
|
22353
|
+
cwd: policyCwd,
|
|
22354
|
+
sessionId: canonicalSessionId,
|
|
22355
|
+
turnId,
|
|
22356
|
+
threadId,
|
|
22357
|
+
prompt,
|
|
22358
|
+
producer: "native",
|
|
22359
|
+
threadKind: promptTurnContext?.status === "authorized"
|
|
22360
|
+
&& promptTurnContext.authorization.targetRelation !== "explicit-independent"
|
|
22361
|
+
? "root-or-drift" : "unknown",
|
|
22362
|
+
isSubagentPromptSubmit,
|
|
22363
|
+
markedContinuation: payload.continuation === true
|
|
22364
|
+
|| payload.is_continuation === true
|
|
22365
|
+
|| safeString(payload.source).toLowerCase().includes("continuation"),
|
|
22366
|
+
synthetic: payload.synthetic === true
|
|
22367
|
+
|| payload.auto_nudge === true
|
|
22368
|
+
|| safeString(payload.source).toLowerCase().includes("nudge"),
|
|
22369
|
+
reservedInput: promptClassification?.reservedInput ?? null,
|
|
22370
|
+
});
|
|
22371
|
+
if ((advisory.intent === "replan" || advisory.intent === "new_advisory")
|
|
22372
|
+
&& advisory.projection?.activation) {
|
|
22373
|
+
const activated = await activateOrResumeRalplanAdvisory({
|
|
22374
|
+
cwd: policyCwd, sessionId: canonicalSessionId, rootThreadId: threadId,
|
|
22375
|
+
activationTurnId: turnId, prompt, producer: "native", threadKind: advisoryThreadKind,
|
|
22376
|
+
predecessorGenerationId: advisory.projection.activation.generation_id,
|
|
22377
|
+
});
|
|
22378
|
+
if (activated) advisory.projection = activated.projection;
|
|
22379
|
+
}
|
|
22380
|
+
const advisoryBinding = await readModeStateForSession("ralplan", canonicalSessionId, policyCwd);
|
|
22381
|
+
advisoryAdditionalContext = buildRalplanAdvisoryRoutingObservation(advisory.intent, advisory.projection, advisoryBinding);
|
|
22382
|
+
} catch (error) {
|
|
22383
|
+
advisoryAdditionalContext = `Ralplan Advisory lifecycle reconciliation reported a non-authoritative diagnostic: ${error instanceof Error ? error.message : String(error)}. It does not grant or deny host tool permission.`;
|
|
22384
|
+
}
|
|
22190
22385
|
}
|
|
22191
22386
|
if (!isSubagentPromptSubmit) {
|
|
22192
|
-
|
|
22387
|
+
teamNoticeTargetKey = parseTeamNoticeLedgerPrompt(prompt);
|
|
22193
22388
|
}
|
|
22194
22389
|
goalWorkflowAdditionalContext = allowGlobalSideEffects
|
|
22195
22390
|
? await buildCompletedGoalCleanupPromptWarning(cwd, prompt).catch(() => null)
|
|
@@ -22198,13 +22393,26 @@ export async function dispatchCodexNativeHook(
|
|
|
22198
22393
|
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects && allowGlobalSideEffects
|
|
22199
22394
|
? await applyUserPromptUltragoalSteering(cwd, prompt).catch((error) => `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${error instanceof Error ? error.message : String(error)}`)
|
|
22200
22395
|
: null;
|
|
22201
|
-
|
|
22396
|
+
// An explicit independent payload session is safe to seed in its own
|
|
22397
|
+
// session-scoped state even when global side effects (HUD/root mirrors) are
|
|
22398
|
+
// suppressed because a stale selected pointer exists.
|
|
22399
|
+
let suppressActivationSeeding = !allowImplicitSessionSideEffects
|
|
22400
|
+
|| (!allowGlobalSideEffects
|
|
22401
|
+
&& promptTurnContext?.status !== "authorized");
|
|
22202
22402
|
if (promptTurnContext?.status === "authorized") {
|
|
22203
22403
|
sessionIdForState = promptTurnContext.authorization.targetSessionId;
|
|
22204
22404
|
} else if (prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects) {
|
|
22205
22405
|
const rawHookSessionId = canonicalSessionId || nativeSessionId;
|
|
22206
22406
|
const normalizedHookSessionId = normalizeSessionId(rawHookSessionId);
|
|
22207
|
-
|
|
22407
|
+
// An explicit payload session must win over a stale selected pointer.
|
|
22408
|
+
// Preserve the pointer only for its authenticated session/native alias;
|
|
22409
|
+
// otherwise seed state in the payload's session rather than silently
|
|
22410
|
+
// mutating the selected session.
|
|
22411
|
+
const explicitHookSessionId = currentSessionState
|
|
22412
|
+
&& normalizedHookSessionId
|
|
22413
|
+
&& payloadMatchesSessionPointer(normalizedHookSessionId, currentSessionState)
|
|
22414
|
+
? undefined
|
|
22415
|
+
: normalizedHookSessionId;
|
|
22208
22416
|
if (rawHookSessionId && !normalizedHookSessionId) {
|
|
22209
22417
|
suppressActivationSeeding = true;
|
|
22210
22418
|
} else {
|
|
@@ -22378,7 +22586,8 @@ export async function dispatchCodexNativeHook(
|
|
|
22378
22586
|
allowTeamWorkerSideEffects: false,
|
|
22379
22587
|
});
|
|
22380
22588
|
}
|
|
22381
|
-
if (hookEventName === "UserPromptSubmit" && !isSubagentPromptSubmit && teamNoticeTargetKey
|
|
22589
|
+
if (hookEventName === "UserPromptSubmit" && !isSubagentPromptSubmit && teamNoticeTargetKey
|
|
22590
|
+
&& allowGlobalSideEffects) {
|
|
22382
22591
|
const reconciled = await reconcileTeamNoticeLedger({ stateRoot: stateDir, targetKey: teamNoticeTargetKey }).catch(() => null);
|
|
22383
22592
|
if (!reconciled || reconciled.context.length === 0) {
|
|
22384
22593
|
teamNoticeAdditionalContext = "OMX invalidated this queued Team wake immediately before model input because no active source-proven Team notices remain. Do not infer or reference a removed Team from the generic wake.";
|
|
@@ -22411,16 +22620,17 @@ export async function dispatchCodexNativeHook(
|
|
|
22411
22620
|
buildWikiPreCompactContext({ cwd });
|
|
22412
22621
|
} else if ((hookEventName === "SessionStart" && !skipCanonicalSessionStartContext) || hookEventName === "UserPromptSubmit") {
|
|
22413
22622
|
const additionalContext = hookEventName === "SessionStart"
|
|
22414
|
-
? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId, {
|
|
22623
|
+
? [await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId, {
|
|
22415
22624
|
hookEventName,
|
|
22416
22625
|
payload,
|
|
22417
22626
|
canonicalSessionId,
|
|
22418
22627
|
nativeSessionId: resolvedNativeSessionId || nativeSessionId,
|
|
22419
|
-
})
|
|
22628
|
+
}), advisoryAdditionalContext].filter((entry): entry is string => Boolean(entry)).join("\n\n") || null
|
|
22420
22629
|
: isSubagentPromptSubmit
|
|
22421
22630
|
? null
|
|
22422
22631
|
: [
|
|
22423
22632
|
teamNoticeAdditionalContext,
|
|
22633
|
+
advisoryAdditionalContext,
|
|
22424
22634
|
promptClassification ? buildAdditionalContextMessage(promptClassification, skillState, cwd, payload) : null,
|
|
22425
22635
|
ultragoalSteeringAdditionalContext,
|
|
22426
22636
|
goalWorkflowAdditionalContext,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
writeUserInstallStamp,
|
|
9
9
|
} from './postinstall-advisory.js';
|
|
10
10
|
import { getPackageRoot } from "../utils/package.js";
|
|
11
|
+
import { hydrateNativeBinary } from "../cli/native-assets.js";
|
|
11
12
|
|
|
12
13
|
type PostinstallStatus =
|
|
13
14
|
| "noop-local"
|
|
@@ -24,10 +25,40 @@ interface PostinstallDependencies {
|
|
|
24
25
|
env: NodeJS.ProcessEnv;
|
|
25
26
|
getCurrentVersion: () => Promise<string | null>;
|
|
26
27
|
log: (message: string) => void;
|
|
28
|
+
hydrateRuntime: () => Promise<string | undefined>;
|
|
27
29
|
readStamp: () => Promise<UserInstallStamp | null>;
|
|
28
30
|
writeStamp: (stamp: UserInstallStamp) => Promise<void>;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
const RUNTIME_HYDRATION_TIMEOUT_MS = 15_000;
|
|
34
|
+
|
|
35
|
+
export async function hydrateOmxRuntimeNonFatal(options: {
|
|
36
|
+
packageRoot?: string;
|
|
37
|
+
env?: NodeJS.ProcessEnv;
|
|
38
|
+
log?: (message: string) => void;
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
} = {}): Promise<string | undefined> {
|
|
41
|
+
const log = options.log ?? ((message: string) => console.log(message));
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? RUNTIME_HYDRATION_TIMEOUT_MS);
|
|
44
|
+
timer.unref?.();
|
|
45
|
+
try {
|
|
46
|
+
const runtimePath = await hydrateNativeBinary("omx-runtime", {
|
|
47
|
+
packageRoot: options.packageRoot,
|
|
48
|
+
env: options.env,
|
|
49
|
+
signal: controller.signal,
|
|
50
|
+
});
|
|
51
|
+
if (runtimePath) log(`[omx] Hydrated omx-runtime for this platform: ${runtimePath}`);
|
|
52
|
+
else log("[omx] omx-runtime was not available for this platform; native runtime features remain disabled.");
|
|
53
|
+
return runtimePath;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
log(`[omx] omx-runtime hydration failed non-fatally: ${error instanceof Error ? error.message : String(error)}`);
|
|
56
|
+
return undefined;
|
|
57
|
+
} finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
31
62
|
function stripLeadingV(version: string): string {
|
|
32
63
|
return version.trim().replace(/^v/i, "");
|
|
33
64
|
}
|
|
@@ -55,6 +86,7 @@ const defaultDependencies: PostinstallDependencies = {
|
|
|
55
86
|
env: process.env,
|
|
56
87
|
getCurrentVersion,
|
|
57
88
|
log: (message) => console.log(message),
|
|
89
|
+
hydrateRuntime: () => hydrateOmxRuntimeNonFatal(),
|
|
58
90
|
readStamp: () => readUserInstallStamp(),
|
|
59
91
|
writeStamp: (stamp) => writeUserInstallStamp(stamp),
|
|
60
92
|
};
|
|
@@ -75,6 +107,20 @@ export async function runPostinstall(
|
|
|
75
107
|
}
|
|
76
108
|
|
|
77
109
|
const currentStampVersion = stripLeadingV(currentVersion);
|
|
110
|
+
try {
|
|
111
|
+
const runtimePath = await resolved.hydrateRuntime();
|
|
112
|
+
if (runtimePath) {
|
|
113
|
+
resolved.log(`[omx] Hydrated omx-runtime for this platform: ${runtimePath}`);
|
|
114
|
+
} else {
|
|
115
|
+
resolved.log(
|
|
116
|
+
"[omx] omx-runtime was not available for this platform; native runtime features remain disabled.",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
resolved.log(
|
|
121
|
+
`[omx] omx-runtime hydration failed non-fatally: ${error instanceof Error ? error.message : String(error)}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
78
124
|
const existingStamp = await resolved.readStamp();
|
|
79
125
|
if (!isInstallVersionBump(currentVersion, existingStamp)) {
|
|
80
126
|
return { status: "noop-same-version", version: currentStampVersion };
|