oh-my-codex 0.20.1 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +10 -1
- package/dist/adapt/__tests__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
- package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
- package/dist/auth/__tests__/hotswap.test.js +183 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +17 -4
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +4 -4
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/lockfile.js.map +1 -1
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/skill-mirror.js.map +1 -1
- package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +650 -15
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +216 -11
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +49 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +84 -12
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +128 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +8 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +187 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +129 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +6 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +2261 -14
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-preferences.test.js +79 -0
- package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
- package/dist/cli/__tests__/setup-refresh.test.js +33 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +46 -3
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +37 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +61 -1
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +1771 -24
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +58 -0
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/adapt.js.map +1 -1
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/ask.d.ts +1 -1
- package/dist/cli/ask.d.ts.map +1 -1
- package/dist/cli/ask.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/capabilities.js.map +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +594 -130
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +11 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +108 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/mission.js.map +1 -1
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +18 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +239 -0
- package/dist/cli/native-hook-claim-journal.js.map +1 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +14 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +203 -0
- package/dist/cli/ralplan.js.map +1 -0
- package/dist/cli/setup-preferences.d.ts +11 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +32 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +53 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1401 -398
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +2 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +5 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +34 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +8 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +944 -95
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +5 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +1287 -11
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +850 -32
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -1
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +124 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2142 -265
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +21 -16
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +991 -137
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +2 -2
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js.map +1 -1
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/config/team-mode.d.ts.map +1 -1
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
- package/dist/document-refresh/enforcer.js.map +1 -1
- package/dist/exec/followup.js.map +1 -1
- package/dist/goal-workflows/artifacts.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +1372 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +14 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +669 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -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 +142 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +8 -1
- 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.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +532 -11
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +5 -5
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/code-simplifier/index.js.map +1 -1
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/events.js.map +1 -1
- package/dist/hooks/extensibility/loader.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
- package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +33 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2228 -119
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts +12 -0
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +41 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-session-provenance.d.ts +87 -0
- package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
- package/dist/hooks/prompt-session-provenance.js +180 -0
- package/dist/hooks/prompt-session-provenance.js.map +1 -0
- package/dist/hooks/session.d.ts +139 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1239 -317
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +103 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +26 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +109 -3
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +98 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +58 -58
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/hermes-server.d.ts +70 -70
- package/dist/mcp/hermes-server.d.ts.map +1 -1
- package/dist/mcp/lifecycle-telemetry.js.map +1 -1
- package/dist/mcp/memory-server.d.ts +34 -34
- package/dist/mcp/memory-server.d.ts.map +1 -1
- package/dist/mcp/memory-server.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +14 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +96 -20
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +47 -47
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.d.ts +4 -4
- package/dist/mcp/trace-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +23 -23
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +53 -1
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -5
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/index.d.ts +4 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +3 -9
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.js.map +1 -1
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/notifications/tmux-detector.js.map +1 -1
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/openclaw/config.js.map +1 -1
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +8 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/planning/artifact-names.js.map +1 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/state.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/events.js.map +1 -1
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js.map +1 -1
- package/dist/question/ui.js.map +1 -1
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +403 -8
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +112 -14
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +3 -3
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +155 -60
- package/dist/ralplan/consensus-gate.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 +1 -2
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/process-tree.js.map +1 -1
- package/dist/runtime/run-loop.js.map +1 -1
- package/dist/runtime/run-outcome.d.ts +3 -3
- package/dist/runtime/run-outcome.d.ts.map +1 -1
- package/dist/runtime/run-outcome.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +4121 -592
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +205 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +175 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +848 -4
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
- package/dist/scripts/build-api.js.map +1 -1
- package/dist/scripts/build-explore-harness.js.map +1 -1
- package/dist/scripts/build-sparkshell.js.map +1 -1
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +689 -156
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
- package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
- package/dist/scripts/notify-fallback-delivery.js +419 -0
- package/dist/scripts/notify-fallback-delivery.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +136 -30
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +39 -13
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +122 -12
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +17 -0
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +73 -11
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -4
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +2 -2
- package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +25 -16
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +15 -13
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts +24 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +266 -90
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +879 -2
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +1528 -7
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/test-reply-listener-live.js.map +1 -1
- package/dist/scripts/test-sparkshell.js.map +1 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/session-history/friction.js.map +1 -1
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/sidecar/index.js.map +1 -1
- package/dist/sidecar/render.js.map +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +64 -15
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +19 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +61 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +49 -55
- package/dist/state/operations.js.map +1 -1
- package/dist/state/paths.d.ts +1 -1
- package/dist/state/paths.d.ts.map +1 -1
- package/dist/state/paths.js +1 -1
- package/dist/state/paths.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +43 -4
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +20 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +2 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js +988 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +273 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +1550 -10
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/adapted-role-binding.d.ts +17 -0
- package/dist/subagents/adapted-role-binding.d.ts.map +1 -0
- package/dist/subagents/adapted-role-binding.js +75 -0
- package/dist/subagents/adapted-role-binding.js.map +1 -0
- package/dist/subagents/role-routing-marker.d.ts +10 -0
- package/dist/subagents/role-routing-marker.d.ts.map +1 -0
- package/dist/subagents/role-routing-marker.js +136 -0
- package/dist/subagents/role-routing-marker.js.map +1 -0
- package/dist/subagents/tracker.d.ts +172 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +1077 -61
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +231 -1
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +401 -1
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +181 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +434 -4
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/api-interop.d.ts +2 -2
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +5 -5
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/goal-workflow.js.map +1 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/model-contract.d.ts +20 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +267 -30
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/pane-status.js.map +1 -1
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/reminder-intents.d.ts +1 -1
- package/dist/team/reminder-intents.d.ts.map +1 -1
- package/dist/team/reminder-intents.js.map +1 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +83 -52
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +9 -7
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +69 -28
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.js.map +1 -1
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/events.js.map +1 -1
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-identity.d.ts.map +1 -1
- package/dist/team/team-identity.js.map +1 -1
- package/dist/team/tmux-session.d.ts +2 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +90 -42
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/package.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/repo-deps.js.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/verification/verifier.js.map +1 -1
- package/dist/visual/constants.d.ts +1 -1
- package/dist/visual/constants.d.ts.map +1 -1
- package/dist/vscode/__tests__/index.test.js.map +1 -1
- package/dist/vscode/index.js.map +1 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +2 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +4 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -2
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +4 -2
- package/skills/ralplan/SKILL.md +5 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +17522 -10630
- package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
- package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +215 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +193 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +991 -4
- package/src/scripts/codex-native-hook.ts +779 -159
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +132 -40
- package/src/scripts/notify-hook/auto-nudge.ts +43 -12
- package/src/scripts/notify-hook/managed-tmux.ts +149 -12
- package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
- package/src/scripts/notify-hook/state-io.ts +100 -13
- package/src/scripts/notify-hook/tmux-injection.ts +38 -21
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +335 -90
- package/src/scripts/smoke-packed-install.ts +1829 -6
|
@@ -17,22 +17,45 @@ import {
|
|
|
17
17
|
} from "../state/skill-active.js";
|
|
18
18
|
import {
|
|
19
19
|
isTrustedSubagentThread,
|
|
20
|
+
OMX_ADAPTED_PROVENANCE,
|
|
21
|
+
attestLeaderThread,
|
|
20
22
|
readSubagentSessionSummary,
|
|
21
23
|
readSubagentSessionLedger,
|
|
22
24
|
readSubagentTrackingState,
|
|
25
|
+
readSubagentTrackingStateStrict,
|
|
26
|
+
recordSubagentTurn,
|
|
23
27
|
recordSubagentTurnForSession,
|
|
28
|
+
resolveInstalledRoleName,
|
|
24
29
|
} from "../subagents/tracker.js";
|
|
30
|
+
import {
|
|
31
|
+
bindAndPublishAdaptedRole,
|
|
32
|
+
NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_TTL_MS,
|
|
33
|
+
recoverAdaptedRoleBindings,
|
|
34
|
+
} from "../subagents/adapted-role-binding.js";
|
|
35
|
+
import { readRoleRoutingMarker, writeRoleRoutingMarker } from "../subagents/role-routing-marker.js";
|
|
25
36
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
26
37
|
import { inferTerminalLifecycleOutcome } from "../runtime/run-outcome.js";
|
|
27
38
|
import {
|
|
39
|
+
appendPromptSessionProvenanceRejection,
|
|
28
40
|
appendToLog,
|
|
41
|
+
isSessionPointerLaunchAbort,
|
|
29
42
|
isSessionStale,
|
|
30
43
|
isSessionStateUsable,
|
|
44
|
+
normalizeSessionId,
|
|
45
|
+
readSessionPointer,
|
|
31
46
|
readSessionState,
|
|
32
47
|
readUsableSessionState,
|
|
33
48
|
reconcileNativeSessionStart,
|
|
49
|
+
resolveSessionPointerContext,
|
|
34
50
|
type SessionState,
|
|
35
51
|
} from "../hooks/session.js";
|
|
52
|
+
import {
|
|
53
|
+
evaluateResolvedPromptTurn,
|
|
54
|
+
extractSelectedTargetOwnerEvidence,
|
|
55
|
+
preflightSelectedTargetOwner,
|
|
56
|
+
type PromptThreadFacts,
|
|
57
|
+
type ResolvedPromptTurnContext,
|
|
58
|
+
} from "../hooks/prompt-session-provenance.js";
|
|
36
59
|
import {
|
|
37
60
|
appendTeamEvent,
|
|
38
61
|
readTeamLeaderAttention,
|
|
@@ -42,13 +65,20 @@ import {
|
|
|
42
65
|
writeTeamLeaderAttention,
|
|
43
66
|
writeTeamPhase,
|
|
44
67
|
} from "../team/state.js";
|
|
45
|
-
import {
|
|
68
|
+
import { omxNotepadPath, resolveProjectMemoryPath } from "../utils/paths.js";
|
|
46
69
|
import { findGitLayout } from "../utils/git-layout.js";
|
|
47
|
-
import { getBaseStateDir, getStateFilePath, getStatePath, getAuthoritativeActiveStatePaths } from "../mcp/state-paths.js";
|
|
48
70
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
71
|
+
getAuthoritativeActiveStatePaths,
|
|
72
|
+
getBaseStateDir,
|
|
73
|
+
getStateFilePath,
|
|
74
|
+
getStatePath,
|
|
75
|
+
resolveWritableStateScope,
|
|
76
|
+
WRITABLE_STATE_SCOPE_ERRORS,
|
|
77
|
+
} from "../mcp/state-paths.js";
|
|
78
|
+
import {
|
|
79
|
+
classifyKeywordInput,
|
|
51
80
|
recordSkillActivation,
|
|
81
|
+
type KeywordInputClassification,
|
|
52
82
|
type SkillActiveState,
|
|
53
83
|
} from "../hooks/keyword-detector.js";
|
|
54
84
|
import { buildDeepInterviewConfigInstruction } from "../hooks/deep-interview-config-instruction.js";
|
|
@@ -59,6 +89,7 @@ import {
|
|
|
59
89
|
normalizeAutoNudgeSignatureText,
|
|
60
90
|
resolveEffectiveAutoNudgeResponse,
|
|
61
91
|
} from "./notify-hook/auto-nudge.js";
|
|
92
|
+
import { probeActualTmuxInstanceEvidence, tmuxEvidenceBindsCandidate } from "./notify-hook/managed-tmux.js";
|
|
62
93
|
import {
|
|
63
94
|
SLOPPY_FALLBACK_GROUNDING_PATTERNS,
|
|
64
95
|
SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS,
|
|
@@ -89,7 +120,6 @@ import {
|
|
|
89
120
|
onSessionStart as buildWikiSessionStartContext,
|
|
90
121
|
} from "../wiki/lifecycle.js";
|
|
91
122
|
import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
|
|
92
|
-
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
93
123
|
import { deriveAutopilotChildPhase, normalizeAutopilotPhase } from "../autopilot/fsm.js";
|
|
94
124
|
import {
|
|
95
125
|
CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES,
|
|
@@ -98,9 +128,13 @@ import {
|
|
|
98
128
|
NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE,
|
|
99
129
|
actionKindForConductorArtifact,
|
|
100
130
|
authorizeConductorAction,
|
|
131
|
+
buildRoleRoutingUnavailableGuidance,
|
|
101
132
|
buildUnsupportedNativeSubagentGuidance,
|
|
102
133
|
classifyConductorArtifactKind,
|
|
134
|
+
isNativeSubagentSpawnToolName,
|
|
135
|
+
isRoleRoutingUnavailableEvidence,
|
|
103
136
|
isUnsupportedNativeSubagentEvidence,
|
|
137
|
+
parseRoleIntentCorrelationToken,
|
|
104
138
|
resolveNativeSubagentSupportStatus,
|
|
105
139
|
type NativeSubagentUnsupportedReason,
|
|
106
140
|
} from "../leader/contract.js";
|
|
@@ -208,9 +242,6 @@ const RALPH_LIVE_RISK_PATTERNS = [
|
|
|
208
242
|
/\b(?:database|db|terraform|kubectl|kubernetes|aws|gcp|azure|external|destructive)\b/i,
|
|
209
243
|
/\b(?:telegram|vps|service|restart|send|notify|notification|notifications|cron)\b/i,
|
|
210
244
|
] as const;
|
|
211
|
-
const KNOWN_TYPED_AGENT_ROLES = new Set(Object.keys(AGENT_DEFINITIONS));
|
|
212
|
-
let installedTypedAgentRoleNamesCacheKey = "";
|
|
213
|
-
let installedTypedAgentRoleNamesCache: Set<string> = new Set();
|
|
214
245
|
const RALPH_TASK_TEXT_FIELDS = [
|
|
215
246
|
"task_description",
|
|
216
247
|
"taskDescription",
|
|
@@ -236,6 +267,19 @@ function safeString(value: unknown): string {
|
|
|
236
267
|
return typeof value === "string" ? value : "";
|
|
237
268
|
}
|
|
238
269
|
|
|
270
|
+
async function resolveVerifiedOwnerOmxSessionId(): Promise<string | undefined> {
|
|
271
|
+
const candidate = normalizeSessionId(process.env.OMX_SESSION_ID);
|
|
272
|
+
if (!candidate) return undefined;
|
|
273
|
+
const evidence = await probeActualTmuxInstanceEvidence(process.env.TMUX_PANE);
|
|
274
|
+
return tmuxEvidenceBindsCandidate(evidence, candidate) ? candidate : undefined;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function isImplicitWritableScopeFailure(error: unknown): boolean {
|
|
278
|
+
return error instanceof Error
|
|
279
|
+
&& (error.message === WRITABLE_STATE_SCOPE_ERRORS.unboundEnvironment
|
|
280
|
+
|| error.message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession);
|
|
281
|
+
}
|
|
282
|
+
|
|
239
283
|
function safeObject(value: unknown): Record<string, unknown> {
|
|
240
284
|
return value && typeof value === "object" ? value as Record<string, unknown> : {};
|
|
241
285
|
}
|
|
@@ -331,8 +375,10 @@ interface NativeSubagentSessionStartMetadata {
|
|
|
331
375
|
parentThreadId: string;
|
|
332
376
|
agentNickname?: string;
|
|
333
377
|
agentRole?: string;
|
|
378
|
+
correlationToken?: string;
|
|
334
379
|
}
|
|
335
380
|
|
|
381
|
+
|
|
336
382
|
function readBoundedFirstLineSync(path: string): string {
|
|
337
383
|
const fd = openSync(path, "r");
|
|
338
384
|
try {
|
|
@@ -361,6 +407,20 @@ function readBoundedFirstLineSync(path: string): string {
|
|
|
361
407
|
}
|
|
362
408
|
}
|
|
363
409
|
|
|
410
|
+
function selectAuthoritativeTaskName(
|
|
411
|
+
threadSpawn: unknown,
|
|
412
|
+
subagent: unknown,
|
|
413
|
+
payload: unknown,
|
|
414
|
+
): { present: boolean; value: unknown } {
|
|
415
|
+
for (const obj of [threadSpawn, subagent, payload]) {
|
|
416
|
+
if (obj && typeof obj === "object" && "task_name" in obj) {
|
|
417
|
+
return { present: true, value: (obj as Record<string, unknown>).task_name };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return { present: false, value: undefined };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
364
424
|
function readNativeSubagentSessionStartMetadata(transcriptPath: string): NativeSubagentSessionStartMetadata | null {
|
|
365
425
|
const normalizedPath = transcriptPath.trim();
|
|
366
426
|
if (!normalizedPath) return null;
|
|
@@ -378,18 +438,44 @@ function readNativeSubagentSessionStartMetadata(transcriptPath: string): NativeS
|
|
|
378
438
|
const parentThreadId = safeString(threadSpawn.parent_thread_id).trim();
|
|
379
439
|
if (!parentThreadId) return null;
|
|
380
440
|
|
|
381
|
-
const
|
|
382
|
-
|
|
441
|
+
const agentNicknameCarrierValues = [
|
|
442
|
+
threadSpawn.agent_nickname ?? threadSpawn.agentNickname,
|
|
443
|
+
subagent.agent_nickname ?? subagent.agentNickname,
|
|
444
|
+
payload.agent_nickname ?? payload.agentNickname,
|
|
445
|
+
];
|
|
446
|
+
const agentNickname = safeString(agentNicknameCarrierValues[0]).trim();
|
|
447
|
+
const authoritativeTaskName = selectAuthoritativeTaskName(threadSpawn, subagent, payload);
|
|
448
|
+
const correlationToken = authoritativeTaskName.present
|
|
449
|
+
? parseRoleIntentCorrelationToken(authoritativeTaskName.value)
|
|
450
|
+
: undefined;
|
|
451
|
+
const agentRole = safeString(
|
|
452
|
+
threadSpawn.agent_role
|
|
453
|
+
?? threadSpawn.agentRole
|
|
454
|
+
?? threadSpawn.agent_type
|
|
455
|
+
?? threadSpawn.agentType
|
|
456
|
+
?? payload.agent_role
|
|
457
|
+
?? payload.agentRole
|
|
458
|
+
?? payload.agent_type
|
|
459
|
+
?? payload.agentType,
|
|
460
|
+
).trim();
|
|
383
461
|
return {
|
|
384
462
|
parentThreadId,
|
|
385
463
|
...(agentNickname ? { agentNickname } : {}),
|
|
386
464
|
...(agentRole ? { agentRole } : {}),
|
|
465
|
+
...(correlationToken ? { correlationToken } : {}),
|
|
387
466
|
};
|
|
467
|
+
|
|
388
468
|
} catch {
|
|
389
469
|
return null;
|
|
390
470
|
}
|
|
391
471
|
}
|
|
392
472
|
|
|
473
|
+
function reportRoleRoutingBindingFailure(error: unknown): void {
|
|
474
|
+
console.error(
|
|
475
|
+
`[omx] SECURITY: native adapted role binding did not complete; retained binding will be recovered: ${error instanceof Error ? error.message : String(error)}`,
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
|
|
393
479
|
async function recordNativeSubagentSessionStart(
|
|
394
480
|
cwd: string,
|
|
395
481
|
canonicalSessionId: string,
|
|
@@ -399,25 +485,79 @@ async function recordNativeSubagentSessionStart(
|
|
|
399
485
|
): Promise<void> {
|
|
400
486
|
const parentThreadId = metadata.parentThreadId.trim();
|
|
401
487
|
const childThreadId = childSessionId.trim();
|
|
488
|
+
const correlationSessionId = canonicalSessionId.trim() || parentThreadId;
|
|
402
489
|
const trackingSessionIds = [...new Set([
|
|
403
490
|
canonicalSessionId.trim(),
|
|
404
491
|
parentThreadId,
|
|
405
492
|
].filter(Boolean))];
|
|
406
|
-
|
|
407
|
-
|
|
493
|
+
let adaptedRoleIntent: {
|
|
494
|
+
role: string;
|
|
495
|
+
provenanceKind: typeof OMX_ADAPTED_PROVENANCE;
|
|
496
|
+
} | null = null;
|
|
497
|
+
|
|
498
|
+
if (!metadata.agentRole && correlationSessionId && parentThreadId) {
|
|
499
|
+
try {
|
|
500
|
+
const bound = bindAndPublishAdaptedRole(
|
|
501
|
+
cwd,
|
|
502
|
+
getBaseStateDir(cwd),
|
|
503
|
+
{
|
|
504
|
+
correlationSessionId,
|
|
505
|
+
parentThreadId,
|
|
506
|
+
correlationToken: metadata.correlationToken,
|
|
507
|
+
},
|
|
508
|
+
(state, intent) => {
|
|
509
|
+
let next = state;
|
|
510
|
+
for (const sessionId of trackingSessionIds) {
|
|
511
|
+
if (parentThreadId && parentThreadId !== childThreadId) {
|
|
512
|
+
next = recordSubagentTurn(next, {
|
|
513
|
+
sessionId,
|
|
514
|
+
threadId: parentThreadId,
|
|
515
|
+
kind: "leader",
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
next = recordSubagentTurn(next, {
|
|
519
|
+
sessionId,
|
|
520
|
+
threadId: childThreadId,
|
|
521
|
+
kind: "subagent",
|
|
522
|
+
...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
|
|
523
|
+
mode: intent.role,
|
|
524
|
+
role: intent.role,
|
|
525
|
+
provenanceKind: intent.provenanceKind,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
return next;
|
|
529
|
+
},
|
|
530
|
+
);
|
|
531
|
+
adaptedRoleIntent = bound ? { role: bound.role, provenanceKind: OMX_ADAPTED_PROVENANCE } : null;
|
|
532
|
+
} catch (error) {
|
|
533
|
+
reportRoleRoutingBindingFailure(error);
|
|
534
|
+
throw error;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (!adaptedRoleIntent) {
|
|
539
|
+
for (const sessionId of trackingSessionIds) {
|
|
540
|
+
if (parentThreadId && parentThreadId !== childThreadId) {
|
|
541
|
+
await recordSubagentTurnForSession(cwd, {
|
|
542
|
+
sessionId,
|
|
543
|
+
threadId: parentThreadId,
|
|
544
|
+
kind: "leader",
|
|
545
|
+
}).catch(() => {});
|
|
546
|
+
}
|
|
408
547
|
await recordSubagentTurnForSession(cwd, {
|
|
409
548
|
sessionId,
|
|
410
|
-
threadId:
|
|
411
|
-
kind:
|
|
549
|
+
threadId: childThreadId,
|
|
550
|
+
kind: "subagent",
|
|
551
|
+
...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
|
|
552
|
+
mode: metadata.agentRole,
|
|
412
553
|
}).catch(() => {});
|
|
413
554
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}).catch(() => {});
|
|
555
|
+
refreshNativeSubagentRoleRoutingMarker(
|
|
556
|
+
cwd,
|
|
557
|
+
getBaseStateDir(cwd),
|
|
558
|
+
correlationSessionId,
|
|
559
|
+
parentThreadId,
|
|
560
|
+
);
|
|
421
561
|
}
|
|
422
562
|
await appendToLog(cwd, {
|
|
423
563
|
event: "subagent_session_start",
|
|
@@ -523,6 +663,32 @@ async function isNativeSubagentHook(
|
|
|
523
663
|
));
|
|
524
664
|
}
|
|
525
665
|
|
|
666
|
+
async function readNativePromptThreadFacts(
|
|
667
|
+
cwd: string,
|
|
668
|
+
nativeSessionId: string,
|
|
669
|
+
threadId: string,
|
|
670
|
+
currentSessionState?: SessionState | null,
|
|
671
|
+
): Promise<PromptThreadFacts | undefined> {
|
|
672
|
+
const candidateIds = [nativeSessionId, threadId].map((value) => value.trim()).filter(Boolean);
|
|
673
|
+
if (candidateIds.length === 0) return undefined;
|
|
674
|
+
const currentNativeIds = new Set([
|
|
675
|
+
safeString(currentSessionState?.native_session_id).trim(),
|
|
676
|
+
safeString(currentSessionState?.codex_session_id).trim(),
|
|
677
|
+
safeString(currentSessionState?.owner_codex_session_id).trim(),
|
|
678
|
+
].filter(Boolean));
|
|
679
|
+
const currentTargetAnchored = Boolean(nativeSessionId && currentNativeIds.has(nativeSessionId));
|
|
680
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
681
|
+
if (!trackingState) return currentTargetAnchored ? { currentTargetAnchored: true, rootOrDrift: true } : undefined;
|
|
682
|
+
const roots = Object.values(trackingState.sessions).flatMap((session) => (
|
|
683
|
+
candidateIds.some((candidate) => isTrustedSubagentThread(session, candidate))
|
|
684
|
+
? [session.session_id]
|
|
685
|
+
: []
|
|
686
|
+
));
|
|
687
|
+
return roots.length > 0 || currentTargetAnchored
|
|
688
|
+
? { trackerRootOwnerSessionIds: roots, currentTargetAnchored, rootOrDrift: currentTargetAnchored }
|
|
689
|
+
: undefined;
|
|
690
|
+
}
|
|
691
|
+
|
|
526
692
|
function shouldSuppressSubagentLifecycleHookDispatch(): boolean {
|
|
527
693
|
const config = getNotificationConfig();
|
|
528
694
|
if (config?.includeChildAgents === true) return false;
|
|
@@ -690,8 +856,8 @@ function readPromptText(payload: CodexHookPayload): string {
|
|
|
690
856
|
payload.userPrompt,
|
|
691
857
|
];
|
|
692
858
|
for (const candidate of candidates) {
|
|
693
|
-
const value = safeString(candidate)
|
|
694
|
-
if (value) return value;
|
|
859
|
+
const value = safeString(candidate);
|
|
860
|
+
if (value.trim()) return value;
|
|
695
861
|
}
|
|
696
862
|
return "";
|
|
697
863
|
}
|
|
@@ -2175,25 +2341,29 @@ function buildTeamHelpInstruction(cwd: string, payload?: CodexHookPayload): stri
|
|
|
2175
2341
|
}).teamHelpInstruction;
|
|
2176
2342
|
}
|
|
2177
2343
|
|
|
2344
|
+
function isNativeOutsideTmuxUserPrompt(cwd: string, payload: CodexHookPayload, sessionId?: string): boolean {
|
|
2345
|
+
const environment = resolveExecutionEnvironment(cwd, {
|
|
2346
|
+
hookEventName: "UserPromptSubmit",
|
|
2347
|
+
payload,
|
|
2348
|
+
canonicalSessionId: sessionId ?? "",
|
|
2349
|
+
nativeSessionId: safeString(payload.session_id ?? payload.sessionId).trim(),
|
|
2350
|
+
});
|
|
2351
|
+
return environment.launcher === "native" && environment.transport === "outside-tmux";
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2178
2354
|
function buildNativeOutsideTmuxTeamPromptBlockState(
|
|
2179
|
-
|
|
2355
|
+
classification: KeywordInputClassification,
|
|
2180
2356
|
cwd: string,
|
|
2181
2357
|
payload: CodexHookPayload,
|
|
2182
2358
|
sessionId?: string,
|
|
2183
2359
|
threadId?: string,
|
|
2184
2360
|
turnId?: string,
|
|
2185
2361
|
): SkillActiveState | null {
|
|
2186
|
-
|
|
2187
|
-
const match =
|
|
2362
|
+
const teamMode = readTeamModeConfig(cwd);
|
|
2363
|
+
const match = classification.matches.filter((entry) => teamMode.enabled || entry.skill !== "team")[0] ?? null;
|
|
2188
2364
|
if (match?.skill !== "team") return null;
|
|
2189
2365
|
|
|
2190
|
-
|
|
2191
|
-
hookEventName: "UserPromptSubmit",
|
|
2192
|
-
payload,
|
|
2193
|
-
canonicalSessionId: sessionId ?? "",
|
|
2194
|
-
nativeSessionId: safeString(payload.session_id ?? payload.sessionId).trim(),
|
|
2195
|
-
});
|
|
2196
|
-
if (!(environment.launcher === "native" && environment.transport === "outside-tmux")) return null;
|
|
2366
|
+
if (!isNativeOutsideTmuxUserPrompt(cwd, payload, sessionId)) return null;
|
|
2197
2367
|
|
|
2198
2368
|
const nowIso = new Date().toISOString();
|
|
2199
2369
|
return {
|
|
@@ -2229,13 +2399,19 @@ function buildAutopilotPromptActivationNote(
|
|
|
2229
2399
|
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
2230
2400
|
payload: options.payload,
|
|
2231
2401
|
persistedSupportBlocker: readJsonSyncIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
2402
|
+
persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, {
|
|
2403
|
+
cwd: options.cwd,
|
|
2404
|
+
sessionId: options.sessionId ?? "",
|
|
2405
|
+
}),
|
|
2232
2406
|
persistedCapacityBlocker: readJsonSyncIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
2233
2407
|
cwd: options.cwd,
|
|
2234
2408
|
sessionId: options.sessionId,
|
|
2235
2409
|
});
|
|
2236
2410
|
const conductorGuidance = nativeSubagentSupport.status === "unsupported"
|
|
2237
2411
|
? buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)
|
|
2238
|
-
:
|
|
2412
|
+
: nativeSubagentSupport.status === "role_routing_unavailable"
|
|
2413
|
+
? buildRoleRoutingUnavailableGuidance(nativeSubagentSupport)
|
|
2414
|
+
: `${LEADER_CONDUCTOR_BLOCK} ${LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE}`;
|
|
2239
2415
|
return [
|
|
2240
2416
|
`Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal${teamHandoff} -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).`,
|
|
2241
2417
|
"Start/resume at current_phase=deep-interview unless the task is clear and bounded; if deep-interview is intentionally skipped, persist and state an explicit deep_interview_gate.skip_reason before moving to ralplan.",
|
|
@@ -2258,30 +2434,40 @@ function formatExecutionHandoffList(cwd: string): string {
|
|
|
2258
2434
|
}
|
|
2259
2435
|
|
|
2260
2436
|
function buildAdditionalContextMessage(
|
|
2261
|
-
|
|
2437
|
+
classification: KeywordInputClassification,
|
|
2262
2438
|
skillState?: SkillActiveState | null,
|
|
2263
2439
|
cwd: string = process.cwd(),
|
|
2264
2440
|
payload?: CodexHookPayload,
|
|
2265
2441
|
): string | null {
|
|
2442
|
+
const prompt = classification.originalText;
|
|
2266
2443
|
if (!prompt) return null;
|
|
2267
2444
|
const promptPriorityMessage = buildPromptPriorityMessage(prompt);
|
|
2268
2445
|
if (payload && isTypedAgentRolePayload(payload)) {
|
|
2269
2446
|
return promptPriorityMessage;
|
|
2270
2447
|
}
|
|
2271
2448
|
const teamMode = readTeamModeConfig(cwd);
|
|
2272
|
-
const matches =
|
|
2449
|
+
const matches = classification.matches.filter((entry) => teamMode.enabled || entry.skill !== "team");
|
|
2273
2450
|
const match = matches[0] ?? null;
|
|
2274
2451
|
if (!match) {
|
|
2452
|
+
const markedQuestionAnswer = classification.reservedInput === "omx-question-answered";
|
|
2275
2453
|
const continuedSkill = safeString(skillState?.skill).trim();
|
|
2276
|
-
|
|
2454
|
+
const eligibleMarkedContinuation = markedQuestionAnswer
|
|
2455
|
+
&& skillState?.active === true
|
|
2456
|
+
&& (continuedSkill === "autopilot" || continuedSkill === "deep-interview");
|
|
2457
|
+
const eligibleOrdinaryContinuation = classification.reservedInput === null
|
|
2458
|
+
&& !classification.hasExplicitLikeInvocation
|
|
2459
|
+
&& skillState?.active === true
|
|
2460
|
+
&& Boolean(continuedSkill);
|
|
2461
|
+
if (!eligibleMarkedContinuation && !eligibleOrdinaryContinuation) return promptPriorityMessage;
|
|
2277
2462
|
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
2278
2463
|
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
2279
2464
|
: null;
|
|
2280
2465
|
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
2281
|
-
const markedQuestionAnswer = /^\s*\[omx question answered\]/i.test(prompt);
|
|
2282
2466
|
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
2283
2467
|
return [
|
|
2284
|
-
|
|
2468
|
+
markedQuestionAnswer
|
|
2469
|
+
? `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}"; workflow-like tokens inside the marked omx question answer are treated as answer text, not a new workflow activation.`
|
|
2470
|
+
: `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
|
|
2285
2471
|
promptPriorityMessage,
|
|
2286
2472
|
skillState?.initialized_mode && skillState.initialized_state_path
|
|
2287
2473
|
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
@@ -2295,29 +2481,6 @@ function buildAdditionalContextMessage(
|
|
|
2295
2481
|
const detectedKeywordMessage = matches.length > 1
|
|
2296
2482
|
? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
|
|
2297
2483
|
: `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
|
|
2298
|
-
const continuedSkill = safeString(skillState?.skill).trim();
|
|
2299
|
-
if (
|
|
2300
|
-
continuedSkill
|
|
2301
|
-
&& continuedSkill !== match.skill
|
|
2302
|
-
&& /^\s*\[omx question answered\]/i.test(prompt)
|
|
2303
|
-
) {
|
|
2304
|
-
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
2305
|
-
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
2306
|
-
: null;
|
|
2307
|
-
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
2308
|
-
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
2309
|
-
return [
|
|
2310
|
-
`OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}"; workflow-like tokens inside the marked omx question answer are treated as answer text, not a new workflow activation.`,
|
|
2311
|
-
promptPriorityMessage,
|
|
2312
|
-
skillState?.initialized_mode && skillState.initialized_state_path
|
|
2313
|
-
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
2314
|
-
: null,
|
|
2315
|
-
deepInterviewPromptActivationNote,
|
|
2316
|
-
deepInterviewConfigPromptActivationNote,
|
|
2317
|
-
autopilotPromptActivationNote,
|
|
2318
|
-
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
2319
|
-
].filter(Boolean).join(" ");
|
|
2320
|
-
}
|
|
2321
2484
|
const activeSkills = Array.isArray(skillState?.active_skills)
|
|
2322
2485
|
? skillState.active_skills.map((entry) => entry.skill)
|
|
2323
2486
|
: [];
|
|
@@ -3161,33 +3324,68 @@ function readPayloadAgentRole(payload: CodexHookPayload): string {
|
|
|
3161
3324
|
).trim().toLowerCase();
|
|
3162
3325
|
}
|
|
3163
3326
|
|
|
3164
|
-
function
|
|
3165
|
-
const
|
|
3166
|
-
if (
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
}
|
|
3175
|
-
} catch {
|
|
3176
|
-
// Ignore missing or unreadable agent directories; built-in definitions remain authoritative.
|
|
3177
|
-
}
|
|
3178
|
-
}
|
|
3179
|
-
|
|
3180
|
-
installedTypedAgentRoleNamesCacheKey = cacheKey;
|
|
3181
|
-
installedTypedAgentRoleNamesCache = installedRoleNames;
|
|
3182
|
-
return installedTypedAgentRoleNamesCache;
|
|
3327
|
+
function readRequestedSpawnRole(payload: CodexHookPayload): string {
|
|
3328
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
3329
|
+
if (!isNativeSubagentSpawnToolName(toolName)) return "";
|
|
3330
|
+
const toolInput = safeObject(payload.tool_input);
|
|
3331
|
+
return safeString(
|
|
3332
|
+
toolInput.agent_role
|
|
3333
|
+
?? toolInput.agentRole
|
|
3334
|
+
?? toolInput.agent_type
|
|
3335
|
+
?? toolInput.agentType,
|
|
3336
|
+
).trim().toLowerCase();
|
|
3183
3337
|
}
|
|
3184
3338
|
|
|
3185
3339
|
function isTypedAgentRolePayload(payload: CodexHookPayload): boolean {
|
|
3186
3340
|
const agentRole = readPayloadAgentRole(payload);
|
|
3187
|
-
return agentRole !== "" && (
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3341
|
+
return agentRole !== "" && resolveInstalledRoleName(agentRole) !== null;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
// #3181: detect a runtime-set native subagent PreToolUse. The runtime sets
|
|
3345
|
+
// source.subagent.thread_spawn (not agent-controlled tool arguments), so the mere
|
|
3346
|
+
// STRUCTURAL PRESENCE of that carrier — even if its parent id is blank, malformed, or
|
|
3347
|
+
// null — marks a child/subagent turn that must never be attested as the session leader.
|
|
3348
|
+
// This is a negative security decision, so it fails closed on any present carrier rather
|
|
3349
|
+
// than requiring a well-formed parent id.
|
|
3350
|
+
function hasSubagentThreadSpawnProvenance(payload: CodexHookPayload): boolean {
|
|
3351
|
+
const source = payload.source;
|
|
3352
|
+
if (!source || typeof source !== "object") return false;
|
|
3353
|
+
const subagent = (source as Record<string, unknown>).subagent;
|
|
3354
|
+
if (!subagent || typeof subagent !== "object") return false;
|
|
3355
|
+
return Object.prototype.hasOwnProperty.call(subagent, "thread_spawn");
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3358
|
+
// #3181: positive counter-evidence guard. A thread durably tracked as a subagent in ANY
|
|
3359
|
+
// session must never be attested as a leader, even if the current payload lacks typed-role
|
|
3360
|
+
// or thread_spawn provenance. This closes the source-less/untyped child escalation where a
|
|
3361
|
+
// child recorded at its SessionStart later self-promotes via a source-less PreToolUse.
|
|
3362
|
+
async function isThreadTrackedAsSubagent(cwd: string, threadId: string): Promise<boolean> {
|
|
3363
|
+
const id = threadId.trim();
|
|
3364
|
+
if (!id) return false;
|
|
3365
|
+
// Strict read: an unreadable/corrupt tracker fails closed (treated as "is a subagent")
|
|
3366
|
+
// so corrupt evidence cannot let a source-less child reconcile/attest as leader.
|
|
3367
|
+
const read = await readSubagentTrackingStateStrict(cwd);
|
|
3368
|
+
if (!read.ok) return true;
|
|
3369
|
+
for (const session of Object.values(read.state.sessions)) {
|
|
3370
|
+
if (session.threads?.[id]?.kind === "subagent") return true;
|
|
3371
|
+
}
|
|
3372
|
+
return false;
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
function buildNativeUnknownRolePreToolUseOutput(
|
|
3376
|
+
payload: CodexHookPayload,
|
|
3377
|
+
): Record<string, unknown> | null {
|
|
3378
|
+
const requestedRole = readRequestedSpawnRole(payload);
|
|
3379
|
+
if (!requestedRole || resolveInstalledRoleName(requestedRole) !== null) return null;
|
|
3380
|
+
return {
|
|
3381
|
+
decision: "block",
|
|
3382
|
+
reason: "Native typed-subagent dispatch denied: supplied agent_type/agent_role is unknown or not installed.",
|
|
3383
|
+
hookSpecificOutput: {
|
|
3384
|
+
hookEventName: "PreToolUse",
|
|
3385
|
+
additionalContext:
|
|
3386
|
+
"Use an installed OMX role for native agent_type/agent_role dispatch. On a role-routing-unavailable surface, record a validated OMX adapted role intent before spawning without fabricating agent_type.",
|
|
3387
|
+
},
|
|
3388
|
+
};
|
|
3191
3389
|
}
|
|
3192
3390
|
|
|
3193
3391
|
function readPayloadTurnId(payload: CodexHookPayload): string {
|
|
@@ -3288,6 +3486,27 @@ async function recordNativeSubagentSupportBlocker(
|
|
|
3288
3486
|
}, null, 2));
|
|
3289
3487
|
}
|
|
3290
3488
|
|
|
3489
|
+
|
|
3490
|
+
function refreshNativeSubagentRoleRoutingMarker(
|
|
3491
|
+
cwd: string,
|
|
3492
|
+
stateDir: string,
|
|
3493
|
+
sessionId: string,
|
|
3494
|
+
parentThreadId?: string,
|
|
3495
|
+
): void {
|
|
3496
|
+
const marker = readRoleRoutingMarker(stateDir, {
|
|
3497
|
+
cwd,
|
|
3498
|
+
sessionId,
|
|
3499
|
+
...(parentThreadId ? { parentThreadId } : {}),
|
|
3500
|
+
});
|
|
3501
|
+
if (!marker) return;
|
|
3502
|
+
const nowMs = Date.now();
|
|
3503
|
+
writeRoleRoutingMarker(stateDir, {
|
|
3504
|
+
...marker,
|
|
3505
|
+
observed_at: new Date(nowMs).toISOString(),
|
|
3506
|
+
expires_at: new Date(nowMs + NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_TTL_MS).toISOString(),
|
|
3507
|
+
});
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3291
3510
|
function summarizeCapacityFailure(text: string): string {
|
|
3292
3511
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
3293
3512
|
if (!normalized) return "agent thread limit reached";
|
|
@@ -3387,12 +3606,14 @@ async function resolveInternalSessionIdForPayload(
|
|
|
3387
3606
|
cwd: string,
|
|
3388
3607
|
payloadSessionId: string,
|
|
3389
3608
|
stateDir?: string,
|
|
3609
|
+
pointerSessionState?: SessionState | null,
|
|
3610
|
+
allowUnboundPayloadFallback = true,
|
|
3390
3611
|
): Promise<string> {
|
|
3391
|
-
const currentSession = stateDir
|
|
3612
|
+
const currentSession = pointerSessionState ?? (stateDir
|
|
3392
3613
|
? await readUsableSessionStateFromStateDir(cwd, stateDir)
|
|
3393
|
-
: await readUsableSessionState(cwd);
|
|
3614
|
+
: await readUsableSessionState(cwd));
|
|
3394
3615
|
const canonicalSessionId = safeString(currentSession?.session_id).trim();
|
|
3395
|
-
if (!canonicalSessionId) return payloadSessionId;
|
|
3616
|
+
if (!canonicalSessionId) return allowUnboundPayloadFallback ? payloadSessionId : "";
|
|
3396
3617
|
|
|
3397
3618
|
const nativeSessionId = safeString(currentSession?.native_session_id).trim();
|
|
3398
3619
|
const ownerOmxSessionId = safeString(currentSession?.owner_omx_session_id).trim();
|
|
@@ -3400,7 +3621,7 @@ async function resolveInternalSessionIdForPayload(
|
|
|
3400
3621
|
if (payloadSessionId === canonicalSessionId) return canonicalSessionId;
|
|
3401
3622
|
if (nativeSessionId && payloadSessionId === nativeSessionId) return canonicalSessionId;
|
|
3402
3623
|
if (ownerOmxSessionId && payloadSessionId === ownerOmxSessionId) return canonicalSessionId;
|
|
3403
|
-
return payloadSessionId;
|
|
3624
|
+
return allowUnboundPayloadFallback ? payloadSessionId : "";
|
|
3404
3625
|
}
|
|
3405
3626
|
|
|
3406
3627
|
async function readRootSessionStateFromStateDir(stateDir: string): Promise<SessionState | null> {
|
|
@@ -3521,14 +3742,6 @@ const RALPLAN_EXECUTION_HANDOFF_SKILLS = new Set([
|
|
|
3521
3742
|
"ultraqa",
|
|
3522
3743
|
]);
|
|
3523
3744
|
|
|
3524
|
-
function isActiveDeepInterviewPhase(state: Record<string, unknown> | null): boolean {
|
|
3525
|
-
if (!state || state.active !== true) return false;
|
|
3526
|
-
const mode = safeString(state.mode).trim();
|
|
3527
|
-
if (mode && mode !== "deep-interview") return false;
|
|
3528
|
-
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
3529
|
-
if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing")) return false;
|
|
3530
|
-
return true;
|
|
3531
|
-
}
|
|
3532
3745
|
|
|
3533
3746
|
function isInactiveCompletedDeepInterviewPhase(state: Record<string, unknown> | null): boolean {
|
|
3534
3747
|
if (!state || state.active !== false) return false;
|
|
@@ -6816,6 +7029,128 @@ function isCompleteRalplanTerminalWritePayload(
|
|
|
6816
7029
|
return true;
|
|
6817
7030
|
}
|
|
6818
7031
|
|
|
7032
|
+
function hasUnquotedShellControlOrRedirection(command: string): boolean {
|
|
7033
|
+
let quote: "'" | '"' | null = null;
|
|
7034
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
7035
|
+
const char = command[index] ?? "";
|
|
7036
|
+
if (char === "\\" && quote !== "'") {
|
|
7037
|
+
index += 1;
|
|
7038
|
+
continue;
|
|
7039
|
+
}
|
|
7040
|
+
if (char === "'" || char === '"') {
|
|
7041
|
+
quote = quote === char ? null : quote ?? char;
|
|
7042
|
+
continue;
|
|
7043
|
+
}
|
|
7044
|
+
if (!quote && ";&|()<>\n\r".includes(char)) return true;
|
|
7045
|
+
}
|
|
7046
|
+
return false;
|
|
7047
|
+
}
|
|
7048
|
+
|
|
7049
|
+
function suppliedSessionAliasesMatch(payload: Record<string, unknown>, sessionId: string): boolean {
|
|
7050
|
+
return [
|
|
7051
|
+
payload.session_id,
|
|
7052
|
+
payload.owner_omx_session_id,
|
|
7053
|
+
payload.codex_session_id,
|
|
7054
|
+
payload.owner_codex_session_id,
|
|
7055
|
+
].filter((value) => value !== undefined)
|
|
7056
|
+
.every((value) => safeString(value).trim() === sessionId);
|
|
7057
|
+
}
|
|
7058
|
+
|
|
7059
|
+
function hasOnlyFinishedExplicitOutcomes(payload: Record<string, unknown>): boolean {
|
|
7060
|
+
const values = [
|
|
7061
|
+
payload.lifecycle_outcome,
|
|
7062
|
+
payload.lifecycleOutcome,
|
|
7063
|
+
payload.terminal_outcome,
|
|
7064
|
+
payload.terminalOutcome,
|
|
7065
|
+
payload.run_outcome,
|
|
7066
|
+
payload.runOutcome,
|
|
7067
|
+
].filter((value) => value !== undefined);
|
|
7068
|
+
return values.every((value) => inferTerminalLifecycleOutcome(
|
|
7069
|
+
{ lifecycle_outcome: value },
|
|
7070
|
+
{ includeQuestionEnforcement: false },
|
|
7071
|
+
) === "finished");
|
|
7072
|
+
}
|
|
7073
|
+
|
|
7074
|
+
function isCompleteDeepInterviewTerminalWritePayload(
|
|
7075
|
+
payload: Record<string, unknown>,
|
|
7076
|
+
activeState: Record<string, unknown>,
|
|
7077
|
+
sessionId: string,
|
|
7078
|
+
): boolean {
|
|
7079
|
+
if (!sessionId) return false;
|
|
7080
|
+
const activeMode = safeString(activeState.mode).trim().toLowerCase();
|
|
7081
|
+
if (activeMode && activeMode !== "deep-interview") return false;
|
|
7082
|
+
const activeSessionId = safeString(
|
|
7083
|
+
activeState.session_id
|
|
7084
|
+
?? activeState.owner_omx_session_id
|
|
7085
|
+
?? activeState.codex_session_id
|
|
7086
|
+
?? activeState.owner_codex_session_id,
|
|
7087
|
+
).trim();
|
|
7088
|
+
if (activeSessionId && activeSessionId !== sessionId) return false;
|
|
7089
|
+
|
|
7090
|
+
const mode = safeString(payload.mode).trim().toLowerCase();
|
|
7091
|
+
const phase = safeString(payload.current_phase ?? payload.currentPhase).trim().toLowerCase();
|
|
7092
|
+
const payloadSessionId = safeString(payload.session_id).trim();
|
|
7093
|
+
if (!hasOnlyFinishedExplicitOutcomes(payload)) return false;
|
|
7094
|
+
return mode === "deep-interview"
|
|
7095
|
+
&& payload.active === false
|
|
7096
|
+
&& phase === "complete"
|
|
7097
|
+
&& payloadSessionId === sessionId
|
|
7098
|
+
&& inferTerminalLifecycleOutcome(payload, { includeQuestionEnforcement: false }) === "finished";
|
|
7099
|
+
}
|
|
7100
|
+
|
|
7101
|
+
function isAllowedDeepInterviewTerminalStateWriteCommand(
|
|
7102
|
+
cwd: string,
|
|
7103
|
+
command: string,
|
|
7104
|
+
activeState: Record<string, unknown>,
|
|
7105
|
+
sessionId: string,
|
|
7106
|
+
): boolean {
|
|
7107
|
+
const rawWords = tokenizeShellWords(normalizeShellLineContinuations(command).trim());
|
|
7108
|
+
if (rawWords[0] !== "omx") return false;
|
|
7109
|
+
const canonicalCommand = canonicalizeOmxStateTransportCommand(command);
|
|
7110
|
+
if (hasUnquotedShellControlOrRedirection(command)) return false;
|
|
7111
|
+
if (hasUnsafeUnquotedHeredocExpansion(canonicalCommand)) return false;
|
|
7112
|
+
if (hasUnquotedShellSubstitution(canonicalCommand)) return false;
|
|
7113
|
+
if (splitStateScanSegments(canonicalCommand).length !== 1) return false;
|
|
7114
|
+
if (sourcesFileWrittenEarlierInSameCommand(cwd, canonicalCommand)) return false;
|
|
7115
|
+
if (findUnquotedOmxStateCommandIndexes(canonicalCommand, "clear").length > 0) return false;
|
|
7116
|
+
if (hasDynamicNestedShellExecution(canonicalCommand)) return false;
|
|
7117
|
+
if (extractDeepInterviewCommandWriteTargets(command).length > 0) return false;
|
|
7118
|
+
|
|
7119
|
+
const operations = collectOmxStateCommandOperations(command, "write");
|
|
7120
|
+
if (operations.length !== 1) return false;
|
|
7121
|
+
const operation = operations[0];
|
|
7122
|
+
if (!operation || operation.nested || operation.commandPrefix.trim() || hasPriorExecutableCommand(operation.prefix)) return false;
|
|
7123
|
+
const inlineInputCount = operation.args.filter((arg) => arg === "--input" || arg.startsWith("--input=")).length;
|
|
7124
|
+
if (inlineInputCount !== 1 || operation.args.some((arg) => arg === "--input-file" || arg.startsWith("--input-file="))) return false;
|
|
7125
|
+
const inlineInput = readStateWriteFlagValue(operation.args, "--input");
|
|
7126
|
+
let rawPayload: Record<string, unknown> | null = null;
|
|
7127
|
+
try {
|
|
7128
|
+
rawPayload = inlineInput ? safeObject(JSON.parse(inlineInput)) : null;
|
|
7129
|
+
} catch {
|
|
7130
|
+
rawPayload = null;
|
|
7131
|
+
}
|
|
7132
|
+
const nestedState = safeObject(rawPayload?.state);
|
|
7133
|
+
if (
|
|
7134
|
+
!rawPayload
|
|
7135
|
+
|| "workingDirectory" in rawPayload
|
|
7136
|
+
|| !suppliedSessionAliasesMatch(rawPayload, sessionId)
|
|
7137
|
+
|| !hasOnlyFinishedExplicitOutcomes(rawPayload)
|
|
7138
|
+
|| (nestedState && (
|
|
7139
|
+
"mode" in nestedState
|
|
7140
|
+
|| "session_id" in nestedState
|
|
7141
|
+
|| "workingDirectory" in nestedState
|
|
7142
|
+
|| "active" in nestedState
|
|
7143
|
+
|| "current_phase" in nestedState
|
|
7144
|
+
|| "currentPhase" in nestedState
|
|
7145
|
+
|| !suppliedSessionAliasesMatch(nestedState, sessionId)
|
|
7146
|
+
|| !hasOnlyFinishedExplicitOutcomes(nestedState)
|
|
7147
|
+
))
|
|
7148
|
+
) return false;
|
|
7149
|
+
|
|
7150
|
+
const payload = readStateWriteInputPayload(cwd, canonicalCommand, command);
|
|
7151
|
+
return payload ? isCompleteDeepInterviewTerminalWritePayload(payload, activeState, sessionId) : false;
|
|
7152
|
+
}
|
|
7153
|
+
|
|
6819
7154
|
function isAllowedRalplanTerminalStateWriteCommand(
|
|
6820
7155
|
cwd: string,
|
|
6821
7156
|
command: string,
|
|
@@ -6854,10 +7189,56 @@ function commandEndsPlanningPhase(cwd: string, command: string): boolean {
|
|
|
6854
7189
|
return payload ? isPlanningPhaseDeactivationPayload(payload) : true;
|
|
6855
7190
|
}
|
|
6856
7191
|
|
|
6857
|
-
function isAllowedDeepInterviewBashWrite(
|
|
7192
|
+
function isAllowedDeepInterviewBashWrite(
|
|
7193
|
+
cwd: string,
|
|
7194
|
+
command: string,
|
|
7195
|
+
activeState?: Record<string, unknown>,
|
|
7196
|
+
sessionId = "",
|
|
7197
|
+
): boolean {
|
|
7198
|
+
const stateWriteOperations = collectOmxStateCommandOperations(command, "write");
|
|
7199
|
+
const hasUnsafeRuntimeStateWrite = (words: string[]): boolean => {
|
|
7200
|
+
const stateWordIndex = words.indexOf("state");
|
|
7201
|
+
const writeWordIndex = stateWordIndex >= 0 ? words.indexOf("write", stateWordIndex + 1) : -1;
|
|
7202
|
+
if (writeWordIndex <= stateWordIndex) return false;
|
|
7203
|
+
const hasRuntimeBeforeState = words.slice(0, stateWordIndex).some((word) => {
|
|
7204
|
+
const base = shellWordBaseName(word);
|
|
7205
|
+
return isNodeInterpreterCommandWord(base) || base === "bun" || base === "tsx";
|
|
7206
|
+
});
|
|
7207
|
+
if (!hasRuntimeBeforeState) return false;
|
|
7208
|
+
|
|
7209
|
+
const inlineInput = readStateWriteFlagValue(words, "--input");
|
|
7210
|
+
let payload: Record<string, unknown> | null = null;
|
|
7211
|
+
try {
|
|
7212
|
+
const parsed = inlineInput ? safeObject(JSON.parse(inlineInput)) : null;
|
|
7213
|
+
const modeOverride = readStateWriteFlagValue(words, "--mode");
|
|
7214
|
+
payload = parsed
|
|
7215
|
+
? normalizeStateWriteClassificationPayload(modeOverride ? { ...parsed, mode: modeOverride } : parsed)
|
|
7216
|
+
: null;
|
|
7217
|
+
} catch {
|
|
7218
|
+
payload = null;
|
|
7219
|
+
}
|
|
7220
|
+
return (!payload && stateWriteOperations.length === 0)
|
|
7221
|
+
|| Boolean(payload && (
|
|
7222
|
+
safeString(payload.mode).trim().toLowerCase() !== "deep-interview"
|
|
7223
|
+
|| isPlanningPhaseDeactivationPayload(payload)
|
|
7224
|
+
));
|
|
7225
|
+
};
|
|
7226
|
+
const rawCommand = normalizeShellLineContinuations(command).trim();
|
|
7227
|
+
if ([rawCommand, canonicalizeOmxStateTransportCommand(rawCommand)]
|
|
7228
|
+
.some((candidate) => hasUnsafeRuntimeStateWrite(tokenizeShellWords(candidate)))) return false;
|
|
7229
|
+
if (stateWriteOperations.some((operation) => operation.nested)) return false;
|
|
6858
7230
|
if (isAllowedDeepInterviewRalplanHandoffCommand(cwd, command)) return true;
|
|
6859
7231
|
if (hasDeepInterviewRalplanHandoffStateMutation(cwd, command)) return false;
|
|
6860
|
-
if (commandEndsPlanningPhase(cwd, command))
|
|
7232
|
+
if (commandEndsPlanningPhase(cwd, command)) {
|
|
7233
|
+
return activeState
|
|
7234
|
+
? isAllowedDeepInterviewTerminalStateWriteCommand(cwd, command, activeState, sessionId)
|
|
7235
|
+
: false;
|
|
7236
|
+
}
|
|
7237
|
+
if (stateWriteOperations.length > 0) {
|
|
7238
|
+
const canonicalCommand = canonicalizeOmxStateTransportCommand(command);
|
|
7239
|
+
const payload = readStateWriteInputPayload(cwd, canonicalCommand, command);
|
|
7240
|
+
if (!payload || safeString(payload.mode).trim().toLowerCase() !== "deep-interview") return false;
|
|
7241
|
+
}
|
|
6861
7242
|
if (commandHasUntargetedPlanningForbiddenIntent(command)) return false;
|
|
6862
7243
|
if (firstPlanningTmpScriptExecutionTarget(cwd, command)) return false;
|
|
6863
7244
|
if (!commandHasDeepInterviewWriteIntent(command)) return true;
|
|
@@ -6882,13 +7263,11 @@ async function readActiveDeepInterviewStateForPreToolUse(
|
|
|
6882
7263
|
const modeState = sessionId
|
|
6883
7264
|
? await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir)
|
|
6884
7265
|
: await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
if (hasActiveDeepInterviewSkill) return modeState;
|
|
6891
|
-
}
|
|
7266
|
+
const hasActiveDeepInterviewSkill = listActiveSkills(canonicalState).some((entry) => (
|
|
7267
|
+
entry.skill === "deep-interview"
|
|
7268
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)
|
|
7269
|
+
));
|
|
7270
|
+
if (hasActiveDeepInterviewSkill && modeState?.active === true) return modeState;
|
|
6892
7271
|
if (isInactiveCompletedDeepInterviewPhase(modeState)) return null;
|
|
6893
7272
|
|
|
6894
7273
|
const autopilotState = sessionId
|
|
@@ -7129,7 +7508,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(
|
|
|
7129
7508
|
let blockedDetail = "implementation/write tools are blocked until an explicit handoff workflow is activated";
|
|
7130
7509
|
|
|
7131
7510
|
if (toolName === "Bash") {
|
|
7132
|
-
blocked = !isAllowedDeepInterviewBashWrite(cwd, command);
|
|
7511
|
+
blocked = !isAllowedDeepInterviewBashWrite(cwd, command, activeState, sessionId);
|
|
7133
7512
|
if (blocked) {
|
|
7134
7513
|
blockedDetail = buildDeepInterviewBashBlockedDetail(cwd, command);
|
|
7135
7514
|
}
|
|
@@ -7298,6 +7677,11 @@ async function hasTrustedTypedSubagentProvenanceForPreToolUse(
|
|
|
7298
7677
|
if (!session) return false;
|
|
7299
7678
|
|
|
7300
7679
|
const payloadThreadId = readPayloadThreadId(payload);
|
|
7680
|
+
const trackedPayloadThread = payloadThreadId ? session.threads[payloadThreadId] : undefined;
|
|
7681
|
+
const hasTrackedAdaptedTypedRole = payloadThreadId !== ""
|
|
7682
|
+
&& isTrustedSubagentThread(session, payloadThreadId)
|
|
7683
|
+
&& trackedPayloadThread?.provenance_kind === OMX_ADAPTED_PROVENANCE
|
|
7684
|
+
&& resolveInstalledRoleName(trackedPayloadThread.role ?? "") !== null;
|
|
7301
7685
|
|
|
7302
7686
|
// Resolve the Main-root leader THREAD identity from the tracker's leader_thread_id
|
|
7303
7687
|
// plus the canonical session's native_session_id (the leader's native thread). Only
|
|
@@ -7330,9 +7714,13 @@ async function hasTrustedTypedSubagentProvenanceForPreToolUse(
|
|
|
7330
7714
|
|
|
7331
7715
|
// Planning boundary guards (ralplan, deep-interview) still require a recognized typed
|
|
7332
7716
|
// agent role, so an untyped collaboration.spawn_agent child cannot write before an
|
|
7333
|
-
// execution handoff/approval.
|
|
7334
|
-
//
|
|
7335
|
-
if (
|
|
7717
|
+
// execution handoff/approval. A tracker-recorded OMX-adapted child is the equivalent
|
|
7718
|
+
// of a typed role only when its own persisted role is installed and validated.
|
|
7719
|
+
if (
|
|
7720
|
+
options.allowUntypedProvenance !== true
|
|
7721
|
+
&& !isTypedAgentRolePayload(payload)
|
|
7722
|
+
&& !hasTrackedAdaptedTypedRole
|
|
7723
|
+
) {
|
|
7336
7724
|
return false;
|
|
7337
7725
|
}
|
|
7338
7726
|
|
|
@@ -8242,6 +8630,10 @@ export async function buildConductorPreToolUseWriteGuardOutput(
|
|
|
8242
8630
|
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
8243
8631
|
payload,
|
|
8244
8632
|
persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
8633
|
+
persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, {
|
|
8634
|
+
cwd,
|
|
8635
|
+
sessionId: resolvedSessionId || readPayloadSessionId(payload),
|
|
8636
|
+
}),
|
|
8245
8637
|
persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
8246
8638
|
cwd,
|
|
8247
8639
|
sessionId: resolvedSessionId || readPayloadSessionId(payload),
|
|
@@ -8276,6 +8668,9 @@ export async function buildConductorPreToolUseWriteGuardOutput(
|
|
|
8276
8668
|
const unsupportedNativeGuidance = isUnsupportedNativeSubagentEvidence(nativeSubagentSupport)
|
|
8277
8669
|
? ` ${buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)} Treat the active conductor workflow as blocked/cancelled for native delegation recovery; do not call multi_agent_v1.close_agent.`
|
|
8278
8670
|
: "";
|
|
8671
|
+
const roleRoutingUnavailableGuidance = isRoleRoutingUnavailableEvidence(nativeSubagentSupport)
|
|
8672
|
+
? ` ${buildRoleRoutingUnavailableGuidance(nativeSubagentSupport)}`
|
|
8673
|
+
: "";
|
|
8279
8674
|
return {
|
|
8280
8675
|
decision: "block",
|
|
8281
8676
|
reason: `Main-root Conductor mode is active (${activeState.mode} phase: ${formatPhase(activeState.phase, "active")}); direct plan/code writes are blocked and must be delegated; ${blockedDetail}.`,
|
|
@@ -8286,11 +8681,12 @@ export async function buildConductorPreToolUseWriteGuardOutput(
|
|
|
8286
8681
|
+ "Use specialized agents for source edits and plan/spec authorship. "
|
|
8287
8682
|
+ `Main-root Conductor may write only orchestration metadata/transport/ledger artifacts under ${CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES.join(", ")}; path location alone is not authorization for substantive deliverables. `
|
|
8288
8683
|
+ unsupportedNativeGuidance
|
|
8684
|
+
+ roleRoutingUnavailableGuidance
|
|
8289
8685
|
+ " Autopilot rework and typed subagent/worker lanes are exempt from this guard.",
|
|
8290
8686
|
},
|
|
8291
8687
|
};
|
|
8292
|
-
}
|
|
8293
8688
|
|
|
8689
|
+
}
|
|
8294
8690
|
function isInPlaceEditorCommand(word: string, commandName: string): boolean {
|
|
8295
8691
|
if (commandName === "sed") return word === "--in-place" || /^--in-place(?:=.+)?$/.test(word) || /^-[^-\s]*i(?:.*)?$/.test(word);
|
|
8296
8692
|
if (commandName === "perl") return word === "-i" || word === "-pi" || /^-pi(?:\..+)?$/.test(word) || /^-p.*i(?:\..+)?$/.test(word);
|
|
@@ -9376,14 +9772,15 @@ async function buildStopHookOutput(
|
|
|
9376
9772
|
payload: CodexHookPayload,
|
|
9377
9773
|
cwd: string,
|
|
9378
9774
|
stateDir: string,
|
|
9379
|
-
options: { skipRalphStopBlock?: boolean } = {},
|
|
9775
|
+
options: { skipAutoNudge?: boolean; skipRalphStopBlock?: boolean; canonicalSessionId?: string } = {},
|
|
9380
9776
|
): Promise<Record<string, unknown> | null> {
|
|
9381
9777
|
if (isStopExempt(payload)) {
|
|
9382
9778
|
return null;
|
|
9383
9779
|
}
|
|
9384
9780
|
|
|
9385
9781
|
const sessionId = readPayloadSessionId(payload);
|
|
9386
|
-
const canonicalSessionId =
|
|
9782
|
+
const canonicalSessionId = options.canonicalSessionId
|
|
9783
|
+
?? await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
9387
9784
|
const threadId = readPayloadThreadId(payload);
|
|
9388
9785
|
const suppressParentWorkflowStop = shouldSuppressParentWorkflowStopForSideConversation(payload);
|
|
9389
9786
|
if (canonicalSessionId) {
|
|
@@ -9434,7 +9831,7 @@ async function buildStopHookOutput(
|
|
|
9434
9831
|
}
|
|
9435
9832
|
const ralphState = options.skipRalphStopBlock === true
|
|
9436
9833
|
? null
|
|
9437
|
-
: await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
9834
|
+
: await readActiveRalphState(cwd, stateDir, sessionId || canonicalSessionId, ralphOwnerContext);
|
|
9438
9835
|
if (!ralphState) {
|
|
9439
9836
|
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
9440
9837
|
if (autoresearchState) {
|
|
@@ -9618,7 +10015,8 @@ async function buildStopHookOutput(
|
|
|
9618
10015
|
const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
|
|
9619
10016
|
|
|
9620
10017
|
if (
|
|
9621
|
-
|
|
10018
|
+
options.skipAutoNudge !== true
|
|
10019
|
+
&& autoNudgeConfig.enabled
|
|
9622
10020
|
&& detectNativeStopStallPattern(lastAssistantMessage, autoNudgeConfig.patterns, autoNudgePhase)
|
|
9623
10021
|
) {
|
|
9624
10022
|
const effectiveResponse = resolveEffectiveAutoNudgeResponse(autoNudgeConfig.response);
|
|
@@ -9695,13 +10093,39 @@ async function buildStopHookOutput(
|
|
|
9695
10093
|
);
|
|
9696
10094
|
}
|
|
9697
10095
|
|
|
10096
|
+
async function preflightNativePromptTarget(
|
|
10097
|
+
stateDir: string,
|
|
10098
|
+
context: ResolvedPromptTurnContext,
|
|
10099
|
+
): Promise<ResolvedPromptTurnContext> {
|
|
10100
|
+
if (context.status !== "authorized") return context;
|
|
10101
|
+
const targetDir = join(stateDir, "sessions", context.authorization.targetSessionId);
|
|
10102
|
+
const evidence: Array<{ ownerCodexSessionId?: unknown; targetSessionId?: unknown }> = [];
|
|
10103
|
+
let filenames: string[];
|
|
10104
|
+
try {
|
|
10105
|
+
filenames = await readdir(targetDir);
|
|
10106
|
+
} catch (error) {
|
|
10107
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return context;
|
|
10108
|
+
return preflightSelectedTargetOwner(context, [{ ownerCodexSessionId: {} }], "native", new Date().toISOString());
|
|
10109
|
+
}
|
|
10110
|
+
for (const filename of filenames) {
|
|
10111
|
+
if (!filename.endsWith("-state.json") && filename !== SKILL_ACTIVE_STATE_FILE) continue;
|
|
10112
|
+
try {
|
|
10113
|
+
const value = JSON.parse(await readFile(join(targetDir, filename), "utf8")) as unknown;
|
|
10114
|
+
evidence.push(...extractSelectedTargetOwnerEvidence(value));
|
|
10115
|
+
} catch {
|
|
10116
|
+
evidence.push({ ownerCodexSessionId: {} });
|
|
10117
|
+
}
|
|
10118
|
+
}
|
|
10119
|
+
return preflightSelectedTargetOwner(context, evidence, "native", new Date().toISOString());
|
|
10120
|
+
}
|
|
10121
|
+
|
|
9698
10122
|
export async function dispatchCodexNativeHook(
|
|
9699
10123
|
payload: CodexHookPayload,
|
|
9700
10124
|
options: NativeHookDispatchOptions = {},
|
|
9701
10125
|
): Promise<NativeHookDispatchResult> {
|
|
9702
10126
|
const hookEventName = readHookEventName(payload);
|
|
9703
10127
|
const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
|
|
9704
|
-
if (hookEventName === "
|
|
10128
|
+
if (hookEventName === "PostCompact" && process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE === "1") {
|
|
9705
10129
|
return {
|
|
9706
10130
|
hookEventName,
|
|
9707
10131
|
omxEventName: mapCodexHookEventToOmxEvent(hookEventName),
|
|
@@ -9709,24 +10133,71 @@ export async function dispatchCodexNativeHook(
|
|
|
9709
10133
|
outputJson: null,
|
|
9710
10134
|
};
|
|
9711
10135
|
}
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
10136
|
+
try {
|
|
10137
|
+
recoverAdaptedRoleBindings(cwd, getBaseStateDir(cwd));
|
|
10138
|
+
} catch {
|
|
10139
|
+
// Recovery is best-effort for unrelated hook events.
|
|
10140
|
+
}
|
|
10141
|
+
if (hookEventName === "Stop" && !hasNativeStopRuntimeSurface(cwd)) {
|
|
10142
|
+
return {
|
|
10143
|
+
hookEventName,
|
|
10144
|
+
omxEventName: mapCodexHookEventToOmxEvent(hookEventName),
|
|
10145
|
+
skillState: null,
|
|
10146
|
+
outputJson: null,
|
|
10147
|
+
};
|
|
9717
10148
|
}
|
|
10149
|
+
// Native hooks must use the exact pointer root selected for this dispatch.
|
|
10150
|
+
const pointerContext = resolveSessionPointerContext(cwd);
|
|
10151
|
+
const stateDir = pointerContext.baseStateDir;
|
|
9718
10152
|
|
|
9719
10153
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
9720
10154
|
let skillState: SkillActiveState | null = null;
|
|
9721
10155
|
let triageAdditionalContext: string | null = null;
|
|
9722
10156
|
let goalWorkflowAdditionalContext: string | null = null;
|
|
9723
10157
|
let ultragoalSteeringAdditionalContext: string | null = null;
|
|
10158
|
+
let promptClassification: KeywordInputClassification | null = null;
|
|
9724
10159
|
|
|
9725
10160
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
9726
10161
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
9727
10162
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
9728
|
-
const
|
|
10163
|
+
const pointer = await readSessionPointer(pointerContext);
|
|
10164
|
+
const currentSessionState = pointer.status === "usable" ? pointer.state ?? null : null;
|
|
10165
|
+
let promptTurnContext: ResolvedPromptTurnContext | null = hookEventName === "UserPromptSubmit"
|
|
10166
|
+
? evaluateResolvedPromptTurn({
|
|
10167
|
+
producer: "native",
|
|
10168
|
+
payloadSessionId: payload.session_id ?? payload.sessionId,
|
|
10169
|
+
ownerEnvSessionId: undefined,
|
|
10170
|
+
selectedPointer: pointer,
|
|
10171
|
+
threadFacts: await readNativePromptThreadFacts(cwd, nativeSessionId, threadId, currentSessionState),
|
|
10172
|
+
nowIso: new Date().toISOString(),
|
|
10173
|
+
})
|
|
10174
|
+
: null;
|
|
10175
|
+
if (promptTurnContext) {
|
|
10176
|
+
promptTurnContext = await preflightNativePromptTarget(stateDir, promptTurnContext);
|
|
10177
|
+
}
|
|
10178
|
+
if (promptTurnContext?.status === "rejected") {
|
|
10179
|
+
await appendPromptSessionProvenanceRejection(pointerContext, promptTurnContext.diagnostic).catch(() => {});
|
|
10180
|
+
return { hookEventName, omxEventName, skillState: null, outputJson: null };
|
|
10181
|
+
}
|
|
10182
|
+
if (promptTurnContext?.status === "suppressed-target-child") {
|
|
10183
|
+
return { hookEventName, omxEventName, skillState: null, outputJson: null };
|
|
10184
|
+
}
|
|
10185
|
+
if (hookEventName !== "Stop") {
|
|
10186
|
+
await mkdir(stateDir, { recursive: true });
|
|
10187
|
+
}
|
|
10188
|
+
let allowImplicitSessionSideEffects = pointer.status === "usable" || pointer.status === "absent" || promptTurnContext?.status === "authorized";
|
|
10189
|
+
let stopAuthorizationFailure: { stopReason: string; reason: string } | null = allowImplicitSessionSideEffects
|
|
10190
|
+
? null
|
|
10191
|
+
: {
|
|
10192
|
+
stopReason: "session_pointer_unusable",
|
|
10193
|
+
reason: `OMX cannot authorize Stop while the selected session pointer is ${pointer.status}; repair the pointer evidence before continuing.`,
|
|
10194
|
+
};
|
|
9729
10195
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
10196
|
+
if (promptTurnContext?.status === "authorized") {
|
|
10197
|
+
canonicalSessionId = promptTurnContext.authorization.targetSessionId;
|
|
10198
|
+
}
|
|
10199
|
+
const allowPromptGlobalSideEffects = promptTurnContext?.status !== "authorized"
|
|
10200
|
+
|| promptTurnContext.authorization.globalSideEffects === "allow";
|
|
9730
10201
|
let resolvedNativeSessionId = nativeSessionId;
|
|
9731
10202
|
let skipCanonicalSessionStartContext = false;
|
|
9732
10203
|
let isSubagentSessionStart = false;
|
|
@@ -9786,23 +10257,61 @@ export async function dispatchCodexNativeHook(
|
|
|
9786
10257
|
);
|
|
9787
10258
|
}
|
|
9788
10259
|
} else {
|
|
9789
|
-
const
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
10260
|
+
const ownerOmxSessionId = await resolveVerifiedOwnerOmxSessionId();
|
|
10261
|
+
try {
|
|
10262
|
+
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
10263
|
+
context: pointerContext,
|
|
10264
|
+
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
10265
|
+
...(ownerOmxSessionId
|
|
10266
|
+
? { ownerOmxSessionId, ownerAliasVerified: true }
|
|
10267
|
+
: {}),
|
|
10268
|
+
});
|
|
10269
|
+
canonicalSessionId = safeString(sessionState.session_id).trim();
|
|
10270
|
+
resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
10271
|
+
allowImplicitSessionSideEffects = true;
|
|
10272
|
+
stopAuthorizationFailure = null;
|
|
10273
|
+
// #3181: leader attestation is intentionally NOT performed here. This branch is
|
|
10274
|
+
// reached whenever readNativeSubagentSessionStartMetadata() returns null, which
|
|
10275
|
+
// conflates a genuine root start with an unreadable/malformed child transcript, so
|
|
10276
|
+
// it cannot positively classify a leader (a legitimate leader may also carry no
|
|
10277
|
+
// transcript). Leader attestation is performed only on the strictly-gated fresh
|
|
10278
|
+
// leader PreToolUse path below, which fires before the first in-turn role-intent
|
|
10279
|
+
// write. Fail closed here rather than risk a false-leader adoption.
|
|
10280
|
+
} catch (error) {
|
|
10281
|
+
if (!isSessionPointerLaunchAbort(error)) throw error;
|
|
10282
|
+
canonicalSessionId = "";
|
|
10283
|
+
resolvedNativeSessionId = nativeSessionId;
|
|
10284
|
+
skipCanonicalSessionStartContext = true;
|
|
10285
|
+
allowImplicitSessionSideEffects = false;
|
|
10286
|
+
stopAuthorizationFailure = {
|
|
10287
|
+
stopReason: "session_pointer_unusable",
|
|
10288
|
+
reason: `OMX cannot authorize Stop while the selected session pointer is ${pointer.status}; repair the pointer evidence before continuing.`,
|
|
10289
|
+
};
|
|
10290
|
+
}
|
|
9794
10291
|
}
|
|
9795
10292
|
} else if (!canonicalSessionId) {
|
|
9796
10293
|
canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
9797
10294
|
}
|
|
9798
10295
|
|
|
9799
10296
|
if (hookEventName === "Stop") {
|
|
9800
|
-
const
|
|
10297
|
+
const stopPayloadSessionId = readPayloadSessionId(payload);
|
|
9801
10298
|
const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(
|
|
9802
10299
|
cwd,
|
|
9803
|
-
|
|
10300
|
+
stopPayloadSessionId,
|
|
10301
|
+
undefined,
|
|
10302
|
+
currentSessionState,
|
|
10303
|
+
pointer.status === "absent",
|
|
9804
10304
|
);
|
|
9805
|
-
if (stopCanonicalSessionId) {
|
|
10305
|
+
if (stopPayloadSessionId && !stopCanonicalSessionId) {
|
|
10306
|
+
canonicalSessionId = "";
|
|
10307
|
+
allowImplicitSessionSideEffects = false;
|
|
10308
|
+
if (!stopAuthorizationFailure) {
|
|
10309
|
+
stopAuthorizationFailure = {
|
|
10310
|
+
stopReason: "session_scope_unmatched",
|
|
10311
|
+
reason: `OMX cannot authorize Stop for unmatched session id ${stopPayloadSessionId}; the selected session pointer remains authoritative.`,
|
|
10312
|
+
};
|
|
10313
|
+
}
|
|
10314
|
+
} else if (stopCanonicalSessionId) {
|
|
9806
10315
|
canonicalSessionId = stopCanonicalSessionId;
|
|
9807
10316
|
}
|
|
9808
10317
|
if (canonicalSessionId && safeString(currentSessionState?.session_id).trim() === canonicalSessionId) {
|
|
@@ -9811,8 +10320,8 @@ export async function dispatchCodexNativeHook(
|
|
|
9811
10320
|
}
|
|
9812
10321
|
}
|
|
9813
10322
|
|
|
9814
|
-
|
|
9815
|
-
|
|
10323
|
+
let eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
10324
|
+
let sessionIdForState: string | null = canonicalSessionId || null;
|
|
9816
10325
|
let outputJson: Record<string, unknown> | null = null;
|
|
9817
10326
|
const typedAgentRolePayload = isTypedAgentRolePayload(payload);
|
|
9818
10327
|
const isSubagentPromptSubmit = hookEventName === "UserPromptSubmit"
|
|
@@ -9841,36 +10350,81 @@ export async function dispatchCodexNativeHook(
|
|
|
9841
10350
|
)),
|
|
9842
10351
|
)).some(Boolean)
|
|
9843
10352
|
: false;
|
|
10353
|
+
if (isSubagentStop && stopAuthorizationFailure?.stopReason === "session_scope_unmatched") {
|
|
10354
|
+
canonicalSessionId = normalizeSessionId(readPayloadSessionId(payload)) ?? "";
|
|
10355
|
+
allowImplicitSessionSideEffects = true;
|
|
10356
|
+
stopAuthorizationFailure = null;
|
|
10357
|
+
eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
10358
|
+
sessionIdForState = canonicalSessionId || null;
|
|
10359
|
+
}
|
|
9844
10360
|
const suppressNoisySubagentLifecycleDispatch =
|
|
9845
10361
|
(isSubagentSessionStart || isSubagentStop)
|
|
9846
10362
|
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
9847
10363
|
|
|
9848
10364
|
if (hookEventName === "UserPromptSubmit") {
|
|
9849
10365
|
const prompt = readPromptText(payload);
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
10366
|
+
if (!isSubagentPromptSubmit) {
|
|
10367
|
+
promptClassification = classifyKeywordInput(prompt);
|
|
10368
|
+
}
|
|
10369
|
+
goalWorkflowAdditionalContext = allowPromptGlobalSideEffects
|
|
10370
|
+
? await buildCompletedGoalCleanupPromptWarning(cwd, prompt).catch(() => null)
|
|
10371
|
+
?? await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null)
|
|
10372
|
+
: null;
|
|
10373
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects && allowPromptGlobalSideEffects
|
|
9853
10374
|
? 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)}`)
|
|
9854
10375
|
: null;
|
|
9855
|
-
|
|
10376
|
+
let suppressActivationSeeding = !allowImplicitSessionSideEffects;
|
|
10377
|
+
if (promptTurnContext?.status === "authorized") {
|
|
10378
|
+
sessionIdForState = promptTurnContext.authorization.targetSessionId;
|
|
10379
|
+
} else if (prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects) {
|
|
10380
|
+
const rawHookSessionId = canonicalSessionId || nativeSessionId;
|
|
10381
|
+
const normalizedHookSessionId = normalizeSessionId(rawHookSessionId);
|
|
10382
|
+
const explicitHookSessionId = currentSessionState ? undefined : normalizedHookSessionId;
|
|
10383
|
+
if (rawHookSessionId && !normalizedHookSessionId) {
|
|
10384
|
+
suppressActivationSeeding = true;
|
|
10385
|
+
} else {
|
|
10386
|
+
try {
|
|
10387
|
+
const writableScope = await resolveWritableStateScope(cwd, explicitHookSessionId);
|
|
10388
|
+
sessionIdForState = writableScope.sessionId ?? null;
|
|
10389
|
+
} catch (error) {
|
|
10390
|
+
if (!isImplicitWritableScopeFailure(error)) throw error;
|
|
10391
|
+
suppressActivationSeeding = true;
|
|
10392
|
+
}
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
if (prompt && promptClassification && !isSubagentPromptSubmit && !suppressActivationSeeding) {
|
|
9856
10396
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(
|
|
9857
|
-
|
|
10397
|
+
promptClassification,
|
|
9858
10398
|
cwd,
|
|
9859
10399
|
payload,
|
|
9860
|
-
sessionIdForState,
|
|
10400
|
+
sessionIdForState || undefined,
|
|
9861
10401
|
threadId || undefined,
|
|
9862
10402
|
turnId || undefined,
|
|
9863
10403
|
) ?? await recordSkillActivation({
|
|
9864
10404
|
stateDir,
|
|
9865
10405
|
sourceCwd: cwd,
|
|
9866
10406
|
text: prompt,
|
|
9867
|
-
|
|
10407
|
+
classification: promptClassification,
|
|
10408
|
+
allowSecondaryTeam: !isNativeOutsideTmuxUserPrompt(cwd, payload, sessionIdForState || undefined),
|
|
10409
|
+
sessionId: sessionIdForState || undefined,
|
|
9868
10410
|
threadId,
|
|
9869
10411
|
turnId,
|
|
10412
|
+
resolvedPromptTurnContext: promptTurnContext ?? undefined,
|
|
10413
|
+
onProvenanceRejected: async (diagnostic) => {
|
|
10414
|
+
await appendPromptSessionProvenanceRejection(pointerContext, diagnostic).catch(() => {});
|
|
10415
|
+
},
|
|
9870
10416
|
});
|
|
9871
10417
|
}
|
|
9872
10418
|
// --- Triage classifier (advisory-only, non-keyword prompts) ---
|
|
9873
|
-
if (
|
|
10419
|
+
if (
|
|
10420
|
+
prompt
|
|
10421
|
+
&& skillState === null
|
|
10422
|
+
&& !isSubagentPromptSubmit
|
|
10423
|
+
&& allowPromptGlobalSideEffects
|
|
10424
|
+
&& promptClassification?.reservedInput === null
|
|
10425
|
+
&& promptClassification.hasExplicitLikeInvocation === false
|
|
10426
|
+
&& promptClassification.matches.length === 0
|
|
10427
|
+
) {
|
|
9874
10428
|
try {
|
|
9875
10429
|
if (readTriageConfig().enabled) {
|
|
9876
10430
|
const normalized = prompt.trim().toLowerCase();
|
|
@@ -9899,7 +10453,9 @@ export async function dispatchCodexNativeHook(
|
|
|
9899
10453
|
},
|
|
9900
10454
|
suppress_followup: true,
|
|
9901
10455
|
};
|
|
9902
|
-
|
|
10456
|
+
if (!suppressActivationSeeding) {
|
|
10457
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
10458
|
+
}
|
|
9903
10459
|
} else if (decision.lane === "LIGHT") {
|
|
9904
10460
|
if (decision.destination === "explore") {
|
|
9905
10461
|
triageAdditionalContext =
|
|
@@ -9928,7 +10484,9 @@ export async function dispatchCodexNativeHook(
|
|
|
9928
10484
|
},
|
|
9929
10485
|
suppress_followup: true,
|
|
9930
10486
|
};
|
|
9931
|
-
|
|
10487
|
+
if (!suppressActivationSeeding) {
|
|
10488
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
10489
|
+
}
|
|
9932
10490
|
}
|
|
9933
10491
|
}
|
|
9934
10492
|
// lane === "PASS": no context, no state write
|
|
@@ -9942,7 +10500,7 @@ export async function dispatchCodexNativeHook(
|
|
|
9942
10500
|
const skipHudReconcileForDoctorSmoke = process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE === "1";
|
|
9943
10501
|
const skipHudReconcileForTeamWorkerPane = !isSubagentPromptSubmit
|
|
9944
10502
|
&& await isConfirmedTeamWorkerPromptSubmitPane(cwd).catch(() => false);
|
|
9945
|
-
if (!skipHudReconcileForDoctorSmoke && !skipHudReconcileForTeamWorkerPane) {
|
|
10503
|
+
if (allowImplicitSessionSideEffects && allowPromptGlobalSideEffects && !skipHudReconcileForDoctorSmoke && !skipHudReconcileForTeamWorkerPane) {
|
|
9946
10504
|
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
9947
10505
|
const hudSessionId = resolveHudReconcileSessionId(
|
|
9948
10506
|
currentSessionState,
|
|
@@ -9959,7 +10517,7 @@ export async function dispatchCodexNativeHook(
|
|
|
9959
10517
|
}
|
|
9960
10518
|
}
|
|
9961
10519
|
|
|
9962
|
-
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
10520
|
+
if (omxEventName && allowImplicitSessionSideEffects && allowPromptGlobalSideEffects && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
9963
10521
|
const baseContext = buildBaseContext(cwd, payload, hookEventName!, canonicalSessionId);
|
|
9964
10522
|
if (resolvedNativeSessionId) {
|
|
9965
10523
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -10000,12 +10558,14 @@ export async function dispatchCodexNativeHook(
|
|
|
10000
10558
|
})
|
|
10001
10559
|
: isSubagentPromptSubmit
|
|
10002
10560
|
? null
|
|
10003
|
-
:
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10561
|
+
: promptClassification
|
|
10562
|
+
? [
|
|
10563
|
+
buildAdditionalContextMessage(promptClassification, skillState, cwd, payload),
|
|
10564
|
+
ultragoalSteeringAdditionalContext,
|
|
10565
|
+
goalWorkflowAdditionalContext,
|
|
10566
|
+
triageAdditionalContext,
|
|
10567
|
+
].filter((entry): entry is string => Boolean(entry)).join("\n\n") || null
|
|
10568
|
+
: null;
|
|
10009
10569
|
if (additionalContext) {
|
|
10010
10570
|
outputJson = {
|
|
10011
10571
|
hookSpecificOutput: {
|
|
@@ -10015,12 +10575,55 @@ export async function dispatchCodexNativeHook(
|
|
|
10015
10575
|
};
|
|
10016
10576
|
}
|
|
10017
10577
|
} else if (hookEventName === "PreToolUse") {
|
|
10578
|
+
// #3181 Phase-1 (PreToolUse): this hook fires before the shell tool call that runs
|
|
10579
|
+
// the first in-turn `omx ralplan role-intent write`. On a fresh App/outside-tmux
|
|
10580
|
+
// turn where SessionStart did not establish the pointer, reconcile the canonical
|
|
10581
|
+
// pointer and attest the leader here so the first command can bootstrap. Strictly
|
|
10582
|
+
// gated to a fresh (absent-pointer) LEADER turn: no canonical session yet, a present
|
|
10583
|
+
// native session id, a leader-shaped thread (absent or equal to the native session
|
|
10584
|
+
// id), and no subagent/typed-role provenance. Best-effort; never blocks PreToolUse.
|
|
10585
|
+
if (
|
|
10586
|
+
allowImplicitSessionSideEffects
|
|
10587
|
+
&& !canonicalSessionId
|
|
10588
|
+
&& nativeSessionId
|
|
10589
|
+
&& readPayloadAgentRole(payload) === ""
|
|
10590
|
+
&& !hasSubagentThreadSpawnProvenance(payload)
|
|
10591
|
+
) {
|
|
10592
|
+
const preToolUseLeaderThreadId = readPayloadThreadId(payload);
|
|
10593
|
+
if (
|
|
10594
|
+
preToolUseLeaderThreadId
|
|
10595
|
+
&& preToolUseLeaderThreadId === nativeSessionId
|
|
10596
|
+
&& !(await isThreadTrackedAsSubagent(cwd, nativeSessionId))
|
|
10597
|
+
) {
|
|
10598
|
+
try {
|
|
10599
|
+
const ownerOmxSessionId = await resolveVerifiedOwnerOmxSessionId();
|
|
10600
|
+
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
10601
|
+
context: pointerContext,
|
|
10602
|
+
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
10603
|
+
...(ownerOmxSessionId ? { ownerOmxSessionId, ownerAliasVerified: true } : {}),
|
|
10604
|
+
});
|
|
10605
|
+
const bootstrapSessionId = safeString(sessionState.session_id).trim();
|
|
10606
|
+
const bootstrapLeaderThreadId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
10607
|
+
if (bootstrapSessionId && bootstrapLeaderThreadId) {
|
|
10608
|
+
canonicalSessionId = bootstrapSessionId;
|
|
10609
|
+
attestLeaderThread(cwd, {
|
|
10610
|
+
sessionId: bootstrapSessionId,
|
|
10611
|
+
leaderThreadId: bootstrapLeaderThreadId,
|
|
10612
|
+
source: 'native-pretooluse',
|
|
10613
|
+
});
|
|
10614
|
+
}
|
|
10615
|
+
} catch {
|
|
10616
|
+
// Best-effort bootstrap; PreToolUse must never fail on this.
|
|
10617
|
+
}
|
|
10618
|
+
}
|
|
10619
|
+
}
|
|
10018
10620
|
const payloadSessionId = readPayloadSessionId(payload);
|
|
10019
10621
|
const rootPointerConflict = await readLiveRootSessionPointerConflict(stateDir, payloadSessionId);
|
|
10020
10622
|
const preToolUseSessionId = payloadSessionId
|
|
10021
10623
|
? await resolveInternalSessionIdForPayload(cwd, payloadSessionId, stateDir)
|
|
10022
10624
|
: "";
|
|
10023
|
-
outputJson =
|
|
10625
|
+
outputJson = buildNativeUnknownRolePreToolUseOutput(payload)
|
|
10626
|
+
?? await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
10024
10627
|
?? await buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
10025
10628
|
?? await buildPlanningRootPointerConflictPreToolUseOutput(payload, cwd, stateDir, rootPointerConflict)
|
|
10026
10629
|
?? await buildConductorPreToolUseWriteGuardOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
@@ -10028,17 +10631,34 @@ export async function dispatchCodexNativeHook(
|
|
|
10028
10631
|
?? buildMalformedPreToolUseBlockTestOutput(payload)
|
|
10029
10632
|
?? buildNativePreToolUseOutput(payload);
|
|
10030
10633
|
} else if (hookEventName === "PostToolUse") {
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10634
|
+
if (allowImplicitSessionSideEffects) {
|
|
10635
|
+
await recordNativeSubagentCapacityBlocker(cwd, stateDir, payload).catch(() => {});
|
|
10636
|
+
await recordNativeSubagentSupportBlocker(cwd, stateDir, payload).catch(() => {});
|
|
10637
|
+
if (detectMcpTransportFailure(payload)) {
|
|
10638
|
+
await markTeamTransportFailure(cwd, payload);
|
|
10639
|
+
}
|
|
10640
|
+
await handleTeamWorkerPostToolUseSuccess(payload, cwd);
|
|
10035
10641
|
}
|
|
10036
10642
|
outputJson = buildNativePostToolUseOutput(payload);
|
|
10037
|
-
await handleTeamWorkerPostToolUseSuccess(payload, cwd);
|
|
10038
10643
|
} else if (hookEventName === "Stop") {
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10644
|
+
if (allowImplicitSessionSideEffects) {
|
|
10645
|
+
outputJson = await buildStopHookOutput(payload, cwd, stateDir, {
|
|
10646
|
+
canonicalSessionId: canonicalSessionId || undefined,
|
|
10647
|
+
skipRalphStopBlock: isSubagentStop,
|
|
10648
|
+
skipAutoNudge: isSubagentStop,
|
|
10649
|
+
}) ?? await buildCompletedGoalCleanupStopOutput(payload, cwd);
|
|
10650
|
+
} else {
|
|
10651
|
+
const failure = stopAuthorizationFailure ?? {
|
|
10652
|
+
stopReason: "session_pointer_unusable",
|
|
10653
|
+
reason: "OMX cannot authorize Stop without a writable session authority.",
|
|
10654
|
+
};
|
|
10655
|
+
outputJson = {
|
|
10656
|
+
decision: "block",
|
|
10657
|
+
stopReason: failure.stopReason,
|
|
10658
|
+
reason: failure.reason,
|
|
10659
|
+
systemMessage: failure.reason,
|
|
10660
|
+
};
|
|
10661
|
+
}
|
|
10042
10662
|
}
|
|
10043
10663
|
|
|
10044
10664
|
return {
|