oh-my-codex 0.20.0 → 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 +27 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js +83 -78
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +56 -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 +735 -14
- 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 +131 -5
- 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 +2264 -17
- 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 +168 -5
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +73 -6
- 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 +2067 -26
- 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 +20 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +636 -161
- 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 +1403 -400
- 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 +947 -99
- 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 +1049 -135
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +28 -49
- 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 +40 -26
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1159 -288
- 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 +146 -2
- 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 +131 -7
- 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 +5414 -801
- 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 +825 -172
- 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/__tests__/agents-md.test.js +16 -0
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +4 -3
- package/dist/utils/agents-md.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 +20497 -12377
- 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 +918 -172
- 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
|
@@ -6,18 +6,22 @@ import { pathToFileURL } from "url";
|
|
|
6
6
|
import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
7
|
import { redactAuthSecrets } from "../auth/redact.js";
|
|
8
8
|
import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
9
|
-
import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentSessionLedger, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
9
|
+
import { isTrustedSubagentThread, OMX_ADAPTED_PROVENANCE, attestLeaderThread, readSubagentSessionSummary, readSubagentSessionLedger, readSubagentTrackingState, readSubagentTrackingStateStrict, recordSubagentTurn, recordSubagentTurnForSession, resolveInstalledRoleName, } from "../subagents/tracker.js";
|
|
10
|
+
import { bindAndPublishAdaptedRole, NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_TTL_MS, recoverAdaptedRoleBindings, } from "../subagents/adapted-role-binding.js";
|
|
11
|
+
import { readRoleRoutingMarker, writeRoleRoutingMarker } from "../subagents/role-routing-marker.js";
|
|
10
12
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
11
13
|
import { inferTerminalLifecycleOutcome } from "../runtime/run-outcome.js";
|
|
12
|
-
import { appendToLog, isSessionStale, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
14
|
+
import { appendPromptSessionProvenanceRejection, appendToLog, isSessionPointerLaunchAbort, isSessionStale, isSessionStateUsable, normalizeSessionId, readSessionPointer, readSessionState, readUsableSessionState, reconcileNativeSessionStart, resolveSessionPointerContext, } from "../hooks/session.js";
|
|
15
|
+
import { evaluateResolvedPromptTurn, extractSelectedTargetOwnerEvidence, preflightSelectedTargetOwner, } from "../hooks/prompt-session-provenance.js";
|
|
13
16
|
import { appendTeamEvent, readTeamLeaderAttention, readTeamConfig, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
|
|
14
|
-
import {
|
|
17
|
+
import { omxNotepadPath, resolveProjectMemoryPath } from "../utils/paths.js";
|
|
15
18
|
import { findGitLayout } from "../utils/git-layout.js";
|
|
16
|
-
import { getBaseStateDir, getStateFilePath, getStatePath,
|
|
17
|
-
import {
|
|
19
|
+
import { getAuthoritativeActiveStatePaths, getBaseStateDir, getStateFilePath, getStatePath, resolveWritableStateScope, WRITABLE_STATE_SCOPE_ERRORS, } from "../mcp/state-paths.js";
|
|
20
|
+
import { classifyKeywordInput, recordSkillActivation, } from "../hooks/keyword-detector.js";
|
|
18
21
|
import { buildDeepInterviewConfigInstruction } from "../hooks/deep-interview-config-instruction.js";
|
|
19
22
|
import { readTeamModeConfig } from "../config/team-mode.js";
|
|
20
23
|
import { detectNativeStopStallPattern, loadAutoNudgeConfig, normalizeAutoNudgeSignatureText, resolveEffectiveAutoNudgeResponse, } from "./notify-hook/auto-nudge.js";
|
|
24
|
+
import { probeActualTmuxInstanceEvidence, tmuxEvidenceBindsCandidate } from "./notify-hook/managed-tmux.js";
|
|
21
25
|
import { SLOPPY_FALLBACK_GROUNDING_PATTERNS, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS, SLOPPY_FALLBACK_PHRASE_PATTERNS, buildNativePostToolUseOutput, buildNativePreToolUseOutput, commandInvokesApplyPatch, detectMcpTransportFailure, hasAnyPattern, } from "./codex-native-pre-post.js";
|
|
22
26
|
import { handleTeamWorkerPostToolUseSuccess } from "./notify-hook/team-worker-posttooluse.js";
|
|
23
27
|
import { maybeNudgeLeaderForAllowedWorkerStop } from "./notify-hook/team-worker-stop.js";
|
|
@@ -29,9 +33,8 @@ import { getNotificationConfig, getVerbosity } from "../notifications/config.js"
|
|
|
29
33
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
30
34
|
import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
|
|
31
35
|
import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
|
|
32
|
-
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
33
36
|
import { deriveAutopilotChildPhase, normalizeAutopilotPhase } from "../autopilot/fsm.js";
|
|
34
|
-
import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE, actionKindForConductorArtifact, authorizeConductorAction, buildUnsupportedNativeSubagentGuidance, classifyConductorArtifactKind, isUnsupportedNativeSubagentEvidence, resolveNativeSubagentSupportStatus, } from "../leader/contract.js";
|
|
37
|
+
import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE, actionKindForConductorArtifact, authorizeConductorAction, buildRoleRoutingUnavailableGuidance, buildUnsupportedNativeSubagentGuidance, classifyConductorArtifactKind, isNativeSubagentSpawnToolName, isRoleRoutingUnavailableEvidence, isUnsupportedNativeSubagentEvidence, parseRoleIntentCorrelationToken, resolveNativeSubagentSupportStatus, } from "../leader/contract.js";
|
|
35
38
|
import { readRunState } from "../runtime/run-state.js";
|
|
36
39
|
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
37
40
|
import { buildCodexGoalTerminalCleanupNotice, } from "../goal-workflows/codex-goal-snapshot.js";
|
|
@@ -42,7 +45,7 @@ import { readTriageConfig } from "../hooks/triage-config.js";
|
|
|
42
45
|
import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignature, } from "../hooks/triage-state.js";
|
|
43
46
|
import { isPendingDeepInterviewQuestionEnforcement, reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords, } from "../question/deep-interview.js";
|
|
44
47
|
import { readAutopilotDeepInterviewQuestionWaitState } from "../question/autopilot-wait.js";
|
|
45
|
-
import {
|
|
48
|
+
import { evaluateFinalHandoffDocumentRefresh, isFinalHandoffDocumentRefreshCandidate, } from "../document-refresh/enforcer.js";
|
|
46
49
|
import { buildExecFollowupStopOutput } from "../exec/followup.js";
|
|
47
50
|
import { MAX_NATIVE_STDIN_JSON_BYTES, extractRawCodexHookEventName, } from "./hook-payload-guard.js";
|
|
48
51
|
const TERMINAL_MODE_PHASES = new Set(["complete", "completed", "failed", "cancelled"]);
|
|
@@ -89,9 +92,6 @@ const RALPH_LIVE_RISK_PATTERNS = [
|
|
|
89
92
|
/\b(?:database|db|terraform|kubectl|kubernetes|aws|gcp|azure|external|destructive)\b/i,
|
|
90
93
|
/\b(?:telegram|vps|service|restart|send|notify|notification|notifications|cron)\b/i,
|
|
91
94
|
];
|
|
92
|
-
const KNOWN_TYPED_AGENT_ROLES = new Set(Object.keys(AGENT_DEFINITIONS));
|
|
93
|
-
let installedTypedAgentRoleNamesCacheKey = "";
|
|
94
|
-
let installedTypedAgentRoleNamesCache = new Set();
|
|
95
95
|
const RALPH_TASK_TEXT_FIELDS = [
|
|
96
96
|
"task_description",
|
|
97
97
|
"taskDescription",
|
|
@@ -115,6 +115,18 @@ const MAX_SESSION_META_LINE_BYTES = 256 * 1024;
|
|
|
115
115
|
function safeString(value) {
|
|
116
116
|
return typeof value === "string" ? value : "";
|
|
117
117
|
}
|
|
118
|
+
async function resolveVerifiedOwnerOmxSessionId() {
|
|
119
|
+
const candidate = normalizeSessionId(process.env.OMX_SESSION_ID);
|
|
120
|
+
if (!candidate)
|
|
121
|
+
return undefined;
|
|
122
|
+
const evidence = await probeActualTmuxInstanceEvidence(process.env.TMUX_PANE);
|
|
123
|
+
return tmuxEvidenceBindsCandidate(evidence, candidate) ? candidate : undefined;
|
|
124
|
+
}
|
|
125
|
+
function isImplicitWritableScopeFailure(error) {
|
|
126
|
+
return error instanceof Error
|
|
127
|
+
&& (error.message === WRITABLE_STATE_SCOPE_ERRORS.unboundEnvironment
|
|
128
|
+
|| error.message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession);
|
|
129
|
+
}
|
|
118
130
|
function safeObject(value) {
|
|
119
131
|
return value && typeof value === "object" ? value : {};
|
|
120
132
|
}
|
|
@@ -219,6 +231,14 @@ function readBoundedFirstLineSync(path) {
|
|
|
219
231
|
closeSync(fd);
|
|
220
232
|
}
|
|
221
233
|
}
|
|
234
|
+
function selectAuthoritativeTaskName(threadSpawn, subagent, payload) {
|
|
235
|
+
for (const obj of [threadSpawn, subagent, payload]) {
|
|
236
|
+
if (obj && typeof obj === "object" && "task_name" in obj) {
|
|
237
|
+
return { present: true, value: obj.task_name };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { present: false, value: undefined };
|
|
241
|
+
}
|
|
222
242
|
function readNativeSubagentSessionStartMetadata(transcriptPath) {
|
|
223
243
|
const normalizedPath = transcriptPath.trim();
|
|
224
244
|
if (!normalizedPath)
|
|
@@ -237,40 +257,100 @@ function readNativeSubagentSessionStartMetadata(transcriptPath) {
|
|
|
237
257
|
const parentThreadId = safeString(threadSpawn.parent_thread_id).trim();
|
|
238
258
|
if (!parentThreadId)
|
|
239
259
|
return null;
|
|
240
|
-
const
|
|
241
|
-
|
|
260
|
+
const agentNicknameCarrierValues = [
|
|
261
|
+
threadSpawn.agent_nickname ?? threadSpawn.agentNickname,
|
|
262
|
+
subagent.agent_nickname ?? subagent.agentNickname,
|
|
263
|
+
payload.agent_nickname ?? payload.agentNickname,
|
|
264
|
+
];
|
|
265
|
+
const agentNickname = safeString(agentNicknameCarrierValues[0]).trim();
|
|
266
|
+
const authoritativeTaskName = selectAuthoritativeTaskName(threadSpawn, subagent, payload);
|
|
267
|
+
const correlationToken = authoritativeTaskName.present
|
|
268
|
+
? parseRoleIntentCorrelationToken(authoritativeTaskName.value)
|
|
269
|
+
: undefined;
|
|
270
|
+
const agentRole = safeString(threadSpawn.agent_role
|
|
271
|
+
?? threadSpawn.agentRole
|
|
272
|
+
?? threadSpawn.agent_type
|
|
273
|
+
?? threadSpawn.agentType
|
|
274
|
+
?? payload.agent_role
|
|
275
|
+
?? payload.agentRole
|
|
276
|
+
?? payload.agent_type
|
|
277
|
+
?? payload.agentType).trim();
|
|
242
278
|
return {
|
|
243
279
|
parentThreadId,
|
|
244
280
|
...(agentNickname ? { agentNickname } : {}),
|
|
245
281
|
...(agentRole ? { agentRole } : {}),
|
|
282
|
+
...(correlationToken ? { correlationToken } : {}),
|
|
246
283
|
};
|
|
247
284
|
}
|
|
248
285
|
catch {
|
|
249
286
|
return null;
|
|
250
287
|
}
|
|
251
288
|
}
|
|
289
|
+
function reportRoleRoutingBindingFailure(error) {
|
|
290
|
+
console.error(`[omx] SECURITY: native adapted role binding did not complete; retained binding will be recovered: ${error instanceof Error ? error.message : String(error)}`);
|
|
291
|
+
}
|
|
252
292
|
async function recordNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
|
|
253
293
|
const parentThreadId = metadata.parentThreadId.trim();
|
|
254
294
|
const childThreadId = childSessionId.trim();
|
|
295
|
+
const correlationSessionId = canonicalSessionId.trim() || parentThreadId;
|
|
255
296
|
const trackingSessionIds = [...new Set([
|
|
256
297
|
canonicalSessionId.trim(),
|
|
257
298
|
parentThreadId,
|
|
258
299
|
].filter(Boolean))];
|
|
259
|
-
|
|
260
|
-
|
|
300
|
+
let adaptedRoleIntent = null;
|
|
301
|
+
if (!metadata.agentRole && correlationSessionId && parentThreadId) {
|
|
302
|
+
try {
|
|
303
|
+
const bound = bindAndPublishAdaptedRole(cwd, getBaseStateDir(cwd), {
|
|
304
|
+
correlationSessionId,
|
|
305
|
+
parentThreadId,
|
|
306
|
+
correlationToken: metadata.correlationToken,
|
|
307
|
+
}, (state, intent) => {
|
|
308
|
+
let next = state;
|
|
309
|
+
for (const sessionId of trackingSessionIds) {
|
|
310
|
+
if (parentThreadId && parentThreadId !== childThreadId) {
|
|
311
|
+
next = recordSubagentTurn(next, {
|
|
312
|
+
sessionId,
|
|
313
|
+
threadId: parentThreadId,
|
|
314
|
+
kind: "leader",
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
next = recordSubagentTurn(next, {
|
|
318
|
+
sessionId,
|
|
319
|
+
threadId: childThreadId,
|
|
320
|
+
kind: "subagent",
|
|
321
|
+
...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
|
|
322
|
+
mode: intent.role,
|
|
323
|
+
role: intent.role,
|
|
324
|
+
provenanceKind: intent.provenanceKind,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return next;
|
|
328
|
+
});
|
|
329
|
+
adaptedRoleIntent = bound ? { role: bound.role, provenanceKind: OMX_ADAPTED_PROVENANCE } : null;
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
reportRoleRoutingBindingFailure(error);
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (!adaptedRoleIntent) {
|
|
337
|
+
for (const sessionId of trackingSessionIds) {
|
|
338
|
+
if (parentThreadId && parentThreadId !== childThreadId) {
|
|
339
|
+
await recordSubagentTurnForSession(cwd, {
|
|
340
|
+
sessionId,
|
|
341
|
+
threadId: parentThreadId,
|
|
342
|
+
kind: "leader",
|
|
343
|
+
}).catch(() => { });
|
|
344
|
+
}
|
|
261
345
|
await recordSubagentTurnForSession(cwd, {
|
|
262
346
|
sessionId,
|
|
263
|
-
threadId:
|
|
264
|
-
kind:
|
|
347
|
+
threadId: childThreadId,
|
|
348
|
+
kind: "subagent",
|
|
349
|
+
...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
|
|
350
|
+
mode: metadata.agentRole,
|
|
265
351
|
}).catch(() => { });
|
|
266
352
|
}
|
|
267
|
-
|
|
268
|
-
sessionId,
|
|
269
|
-
threadId: childThreadId,
|
|
270
|
-
kind: 'subagent',
|
|
271
|
-
...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
|
|
272
|
-
mode: metadata.agentRole,
|
|
273
|
-
}).catch(() => { });
|
|
353
|
+
refreshNativeSubagentRoleRoutingMarker(cwd, getBaseStateDir(cwd), correlationSessionId, parentThreadId);
|
|
274
354
|
}
|
|
275
355
|
await appendToLog(cwd, {
|
|
276
356
|
event: "subagent_session_start",
|
|
@@ -349,6 +429,26 @@ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, th
|
|
|
349
429
|
return false;
|
|
350
430
|
return Object.values(trackingState.sessions).some((session) => (candidateIds.some((id) => isTrustedSubagentThread(session, id))));
|
|
351
431
|
}
|
|
432
|
+
async function readNativePromptThreadFacts(cwd, nativeSessionId, threadId, currentSessionState) {
|
|
433
|
+
const candidateIds = [nativeSessionId, threadId].map((value) => value.trim()).filter(Boolean);
|
|
434
|
+
if (candidateIds.length === 0)
|
|
435
|
+
return undefined;
|
|
436
|
+
const currentNativeIds = new Set([
|
|
437
|
+
safeString(currentSessionState?.native_session_id).trim(),
|
|
438
|
+
safeString(currentSessionState?.codex_session_id).trim(),
|
|
439
|
+
safeString(currentSessionState?.owner_codex_session_id).trim(),
|
|
440
|
+
].filter(Boolean));
|
|
441
|
+
const currentTargetAnchored = Boolean(nativeSessionId && currentNativeIds.has(nativeSessionId));
|
|
442
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
443
|
+
if (!trackingState)
|
|
444
|
+
return currentTargetAnchored ? { currentTargetAnchored: true, rootOrDrift: true } : undefined;
|
|
445
|
+
const roots = Object.values(trackingState.sessions).flatMap((session) => (candidateIds.some((candidate) => isTrustedSubagentThread(session, candidate))
|
|
446
|
+
? [session.session_id]
|
|
447
|
+
: []));
|
|
448
|
+
return roots.length > 0 || currentTargetAnchored
|
|
449
|
+
? { trackerRootOwnerSessionIds: roots, currentTargetAnchored, rootOrDrift: currentTargetAnchored }
|
|
450
|
+
: undefined;
|
|
451
|
+
}
|
|
352
452
|
function shouldSuppressSubagentLifecycleHookDispatch() {
|
|
353
453
|
const config = getNotificationConfig();
|
|
354
454
|
if (config?.includeChildAgents === true)
|
|
@@ -494,8 +594,8 @@ function readPromptText(payload) {
|
|
|
494
594
|
payload.userPrompt,
|
|
495
595
|
];
|
|
496
596
|
for (const candidate of candidates) {
|
|
497
|
-
const value = safeString(candidate)
|
|
498
|
-
if (value)
|
|
597
|
+
const value = safeString(candidate);
|
|
598
|
+
if (value.trim())
|
|
499
599
|
return value;
|
|
500
600
|
}
|
|
501
601
|
return "";
|
|
@@ -1759,19 +1859,21 @@ function buildTeamHelpInstruction(cwd, payload) {
|
|
|
1759
1859
|
nativeSessionId: safeString(payload?.session_id ?? payload?.sessionId).trim(),
|
|
1760
1860
|
}).teamHelpInstruction;
|
|
1761
1861
|
}
|
|
1762
|
-
function
|
|
1763
|
-
if (!readTeamModeConfig(cwd).enabled)
|
|
1764
|
-
return null;
|
|
1765
|
-
const match = detectPrimaryKeyword(prompt);
|
|
1766
|
-
if (match?.skill !== "team")
|
|
1767
|
-
return null;
|
|
1862
|
+
function isNativeOutsideTmuxUserPrompt(cwd, payload, sessionId) {
|
|
1768
1863
|
const environment = resolveExecutionEnvironment(cwd, {
|
|
1769
1864
|
hookEventName: "UserPromptSubmit",
|
|
1770
1865
|
payload,
|
|
1771
1866
|
canonicalSessionId: sessionId ?? "",
|
|
1772
1867
|
nativeSessionId: safeString(payload.session_id ?? payload.sessionId).trim(),
|
|
1773
1868
|
});
|
|
1774
|
-
|
|
1869
|
+
return environment.launcher === "native" && environment.transport === "outside-tmux";
|
|
1870
|
+
}
|
|
1871
|
+
function buildNativeOutsideTmuxTeamPromptBlockState(classification, cwd, payload, sessionId, threadId, turnId) {
|
|
1872
|
+
const teamMode = readTeamModeConfig(cwd);
|
|
1873
|
+
const match = classification.matches.filter((entry) => teamMode.enabled || entry.skill !== "team")[0] ?? null;
|
|
1874
|
+
if (match?.skill !== "team")
|
|
1875
|
+
return null;
|
|
1876
|
+
if (!isNativeOutsideTmuxUserPrompt(cwd, payload, sessionId))
|
|
1775
1877
|
return null;
|
|
1776
1878
|
const nowIso = new Date().toISOString();
|
|
1777
1879
|
return {
|
|
@@ -1803,13 +1905,19 @@ function buildAutopilotPromptActivationNote(skillState, options = {}) {
|
|
|
1803
1905
|
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
1804
1906
|
payload: options.payload,
|
|
1805
1907
|
persistedSupportBlocker: readJsonSyncIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
1908
|
+
persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, {
|
|
1909
|
+
cwd: options.cwd,
|
|
1910
|
+
sessionId: options.sessionId ?? "",
|
|
1911
|
+
}),
|
|
1806
1912
|
persistedCapacityBlocker: readJsonSyncIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
1807
1913
|
cwd: options.cwd,
|
|
1808
1914
|
sessionId: options.sessionId,
|
|
1809
1915
|
});
|
|
1810
1916
|
const conductorGuidance = nativeSubagentSupport.status === "unsupported"
|
|
1811
1917
|
? buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)
|
|
1812
|
-
:
|
|
1918
|
+
: nativeSubagentSupport.status === "role_routing_unavailable"
|
|
1919
|
+
? buildRoleRoutingUnavailableGuidance(nativeSubagentSupport)
|
|
1920
|
+
: `${LEADER_CONDUCTOR_BLOCK} ${LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE}`;
|
|
1813
1921
|
return [
|
|
1814
1922
|
`Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal${teamHandoff} -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).`,
|
|
1815
1923
|
"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.",
|
|
@@ -1829,7 +1937,8 @@ function formatExecutionHandoffList(cwd) {
|
|
|
1829
1937
|
? "`$ultragoal`, `$team`, or `$ralph`"
|
|
1830
1938
|
: "`$ultragoal` or `$ralph`";
|
|
1831
1939
|
}
|
|
1832
|
-
function buildAdditionalContextMessage(
|
|
1940
|
+
function buildAdditionalContextMessage(classification, skillState, cwd = process.cwd(), payload) {
|
|
1941
|
+
const prompt = classification.originalText;
|
|
1833
1942
|
if (!prompt)
|
|
1834
1943
|
return null;
|
|
1835
1944
|
const promptPriorityMessage = buildPromptPriorityMessage(prompt);
|
|
@@ -1837,20 +1946,29 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1837
1946
|
return promptPriorityMessage;
|
|
1838
1947
|
}
|
|
1839
1948
|
const teamMode = readTeamModeConfig(cwd);
|
|
1840
|
-
const matches =
|
|
1949
|
+
const matches = classification.matches.filter((entry) => teamMode.enabled || entry.skill !== "team");
|
|
1841
1950
|
const match = matches[0] ?? null;
|
|
1842
1951
|
if (!match) {
|
|
1952
|
+
const markedQuestionAnswer = classification.reservedInput === "omx-question-answered";
|
|
1843
1953
|
const continuedSkill = safeString(skillState?.skill).trim();
|
|
1844
|
-
|
|
1954
|
+
const eligibleMarkedContinuation = markedQuestionAnswer
|
|
1955
|
+
&& skillState?.active === true
|
|
1956
|
+
&& (continuedSkill === "autopilot" || continuedSkill === "deep-interview");
|
|
1957
|
+
const eligibleOrdinaryContinuation = classification.reservedInput === null
|
|
1958
|
+
&& !classification.hasExplicitLikeInvocation
|
|
1959
|
+
&& skillState?.active === true
|
|
1960
|
+
&& Boolean(continuedSkill);
|
|
1961
|
+
if (!eligibleMarkedContinuation && !eligibleOrdinaryContinuation)
|
|
1845
1962
|
return promptPriorityMessage;
|
|
1846
1963
|
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
1847
1964
|
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
1848
1965
|
: null;
|
|
1849
1966
|
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1850
|
-
const markedQuestionAnswer = /^\s*\[omx question answered\]/i.test(prompt);
|
|
1851
1967
|
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
1852
1968
|
return [
|
|
1853
|
-
|
|
1969
|
+
markedQuestionAnswer
|
|
1970
|
+
? `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.`
|
|
1971
|
+
: `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
|
|
1854
1972
|
promptPriorityMessage,
|
|
1855
1973
|
skillState?.initialized_mode && skillState.initialized_state_path
|
|
1856
1974
|
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
@@ -1864,27 +1982,6 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1864
1982
|
const detectedKeywordMessage = matches.length > 1
|
|
1865
1983
|
? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
|
|
1866
1984
|
: `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
|
|
1867
|
-
const continuedSkill = safeString(skillState?.skill).trim();
|
|
1868
|
-
if (continuedSkill
|
|
1869
|
-
&& continuedSkill !== match.skill
|
|
1870
|
-
&& /^\s*\[omx question answered\]/i.test(prompt)) {
|
|
1871
|
-
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
1872
|
-
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
1873
|
-
: null;
|
|
1874
|
-
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1875
|
-
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
1876
|
-
return [
|
|
1877
|
-
`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.`,
|
|
1878
|
-
promptPriorityMessage,
|
|
1879
|
-
skillState?.initialized_mode && skillState.initialized_state_path
|
|
1880
|
-
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1881
|
-
: null,
|
|
1882
|
-
deepInterviewPromptActivationNote,
|
|
1883
|
-
deepInterviewConfigPromptActivationNote,
|
|
1884
|
-
autopilotPromptActivationNote,
|
|
1885
|
-
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
1886
|
-
].filter(Boolean).join(" ");
|
|
1887
|
-
}
|
|
1888
1985
|
const activeSkills = Array.isArray(skillState?.active_skills)
|
|
1889
1986
|
? skillState.active_skills.map((entry) => entry.skill)
|
|
1890
1987
|
: [];
|
|
@@ -2252,8 +2349,6 @@ async function buildModeBasedStopOutput(mode, cwd, sessionId) {
|
|
|
2252
2349
|
reason: `OMX ${mode} is still active (phase: ${phase}; ${diagnostic}); continue the task and gather fresh verification evidence before stopping.`,
|
|
2253
2350
|
stopReason: `${mode}_${phase}`,
|
|
2254
2351
|
systemMessage,
|
|
2255
|
-
statePath,
|
|
2256
|
-
canonicalDisagreement,
|
|
2257
2352
|
};
|
|
2258
2353
|
}
|
|
2259
2354
|
export function looksLikeGoalCompletionPrompt(text) {
|
|
@@ -2629,31 +2724,66 @@ function readPayloadAgentRole(payload) {
|
|
|
2629
2724
|
?? threadSpawn?.agent_type
|
|
2630
2725
|
?? threadSpawn?.agentType).trim().toLowerCase();
|
|
2631
2726
|
}
|
|
2632
|
-
function
|
|
2633
|
-
const
|
|
2634
|
-
if (
|
|
2635
|
-
return
|
|
2636
|
-
const
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
continue;
|
|
2642
|
-
installedRoleNames.add(entry.name.slice(0, -5).trim().toLowerCase());
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
catch {
|
|
2646
|
-
// Ignore missing or unreadable agent directories; built-in definitions remain authoritative.
|
|
2647
|
-
}
|
|
2648
|
-
}
|
|
2649
|
-
installedTypedAgentRoleNamesCacheKey = cacheKey;
|
|
2650
|
-
installedTypedAgentRoleNamesCache = installedRoleNames;
|
|
2651
|
-
return installedTypedAgentRoleNamesCache;
|
|
2727
|
+
function readRequestedSpawnRole(payload) {
|
|
2728
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
2729
|
+
if (!isNativeSubagentSpawnToolName(toolName))
|
|
2730
|
+
return "";
|
|
2731
|
+
const toolInput = safeObject(payload.tool_input);
|
|
2732
|
+
return safeString(toolInput.agent_role
|
|
2733
|
+
?? toolInput.agentRole
|
|
2734
|
+
?? toolInput.agent_type
|
|
2735
|
+
?? toolInput.agentType).trim().toLowerCase();
|
|
2652
2736
|
}
|
|
2653
2737
|
function isTypedAgentRolePayload(payload) {
|
|
2654
2738
|
const agentRole = readPayloadAgentRole(payload);
|
|
2655
|
-
return agentRole !== "" && (
|
|
2656
|
-
|
|
2739
|
+
return agentRole !== "" && resolveInstalledRoleName(agentRole) !== null;
|
|
2740
|
+
}
|
|
2741
|
+
// #3181: detect a runtime-set native subagent PreToolUse. The runtime sets
|
|
2742
|
+
// source.subagent.thread_spawn (not agent-controlled tool arguments), so the mere
|
|
2743
|
+
// STRUCTURAL PRESENCE of that carrier — even if its parent id is blank, malformed, or
|
|
2744
|
+
// null — marks a child/subagent turn that must never be attested as the session leader.
|
|
2745
|
+
// This is a negative security decision, so it fails closed on any present carrier rather
|
|
2746
|
+
// than requiring a well-formed parent id.
|
|
2747
|
+
function hasSubagentThreadSpawnProvenance(payload) {
|
|
2748
|
+
const source = payload.source;
|
|
2749
|
+
if (!source || typeof source !== "object")
|
|
2750
|
+
return false;
|
|
2751
|
+
const subagent = source.subagent;
|
|
2752
|
+
if (!subagent || typeof subagent !== "object")
|
|
2753
|
+
return false;
|
|
2754
|
+
return Object.prototype.hasOwnProperty.call(subagent, "thread_spawn");
|
|
2755
|
+
}
|
|
2756
|
+
// #3181: positive counter-evidence guard. A thread durably tracked as a subagent in ANY
|
|
2757
|
+
// session must never be attested as a leader, even if the current payload lacks typed-role
|
|
2758
|
+
// or thread_spawn provenance. This closes the source-less/untyped child escalation where a
|
|
2759
|
+
// child recorded at its SessionStart later self-promotes via a source-less PreToolUse.
|
|
2760
|
+
async function isThreadTrackedAsSubagent(cwd, threadId) {
|
|
2761
|
+
const id = threadId.trim();
|
|
2762
|
+
if (!id)
|
|
2763
|
+
return false;
|
|
2764
|
+
// Strict read: an unreadable/corrupt tracker fails closed (treated as "is a subagent")
|
|
2765
|
+
// so corrupt evidence cannot let a source-less child reconcile/attest as leader.
|
|
2766
|
+
const read = await readSubagentTrackingStateStrict(cwd);
|
|
2767
|
+
if (!read.ok)
|
|
2768
|
+
return true;
|
|
2769
|
+
for (const session of Object.values(read.state.sessions)) {
|
|
2770
|
+
if (session.threads?.[id]?.kind === "subagent")
|
|
2771
|
+
return true;
|
|
2772
|
+
}
|
|
2773
|
+
return false;
|
|
2774
|
+
}
|
|
2775
|
+
function buildNativeUnknownRolePreToolUseOutput(payload) {
|
|
2776
|
+
const requestedRole = readRequestedSpawnRole(payload);
|
|
2777
|
+
if (!requestedRole || resolveInstalledRoleName(requestedRole) !== null)
|
|
2778
|
+
return null;
|
|
2779
|
+
return {
|
|
2780
|
+
decision: "block",
|
|
2781
|
+
reason: "Native typed-subagent dispatch denied: supplied agent_type/agent_role is unknown or not installed.",
|
|
2782
|
+
hookSpecificOutput: {
|
|
2783
|
+
hookEventName: "PreToolUse",
|
|
2784
|
+
additionalContext: "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.",
|
|
2785
|
+
},
|
|
2786
|
+
};
|
|
2657
2787
|
}
|
|
2658
2788
|
function readPayloadTurnId(payload) {
|
|
2659
2789
|
return safeString(payload.turn_id ?? payload.turnId).trim();
|
|
@@ -2738,6 +2868,21 @@ async function recordNativeSubagentSupportBlocker(cwd, stateDir, payload) {
|
|
|
2738
2868
|
cwd,
|
|
2739
2869
|
}, null, 2));
|
|
2740
2870
|
}
|
|
2871
|
+
function refreshNativeSubagentRoleRoutingMarker(cwd, stateDir, sessionId, parentThreadId) {
|
|
2872
|
+
const marker = readRoleRoutingMarker(stateDir, {
|
|
2873
|
+
cwd,
|
|
2874
|
+
sessionId,
|
|
2875
|
+
...(parentThreadId ? { parentThreadId } : {}),
|
|
2876
|
+
});
|
|
2877
|
+
if (!marker)
|
|
2878
|
+
return;
|
|
2879
|
+
const nowMs = Date.now();
|
|
2880
|
+
writeRoleRoutingMarker(stateDir, {
|
|
2881
|
+
...marker,
|
|
2882
|
+
observed_at: new Date(nowMs).toISOString(),
|
|
2883
|
+
expires_at: new Date(nowMs + NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_TTL_MS).toISOString(),
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2741
2886
|
function summarizeCapacityFailure(text) {
|
|
2742
2887
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
2743
2888
|
if (!normalized)
|
|
@@ -2826,13 +2971,13 @@ async function buildNativeSubagentCapacityCloseGuardOutput(payload, cwd, stateDi
|
|
|
2826
2971
|
},
|
|
2827
2972
|
};
|
|
2828
2973
|
}
|
|
2829
|
-
async function resolveInternalSessionIdForPayload(cwd, payloadSessionId, stateDir) {
|
|
2830
|
-
const currentSession = stateDir
|
|
2974
|
+
async function resolveInternalSessionIdForPayload(cwd, payloadSessionId, stateDir, pointerSessionState, allowUnboundPayloadFallback = true) {
|
|
2975
|
+
const currentSession = pointerSessionState ?? (stateDir
|
|
2831
2976
|
? await readUsableSessionStateFromStateDir(cwd, stateDir)
|
|
2832
|
-
: await readUsableSessionState(cwd);
|
|
2977
|
+
: await readUsableSessionState(cwd));
|
|
2833
2978
|
const canonicalSessionId = safeString(currentSession?.session_id).trim();
|
|
2834
2979
|
if (!canonicalSessionId)
|
|
2835
|
-
return payloadSessionId;
|
|
2980
|
+
return allowUnboundPayloadFallback ? payloadSessionId : "";
|
|
2836
2981
|
const nativeSessionId = safeString(currentSession?.native_session_id).trim();
|
|
2837
2982
|
const ownerOmxSessionId = safeString(currentSession?.owner_omx_session_id).trim();
|
|
2838
2983
|
if (!payloadSessionId)
|
|
@@ -2843,7 +2988,7 @@ async function resolveInternalSessionIdForPayload(cwd, payloadSessionId, stateDi
|
|
|
2843
2988
|
return canonicalSessionId;
|
|
2844
2989
|
if (ownerOmxSessionId && payloadSessionId === ownerOmxSessionId)
|
|
2845
2990
|
return canonicalSessionId;
|
|
2846
|
-
return payloadSessionId;
|
|
2991
|
+
return allowUnboundPayloadFallback ? payloadSessionId : "";
|
|
2847
2992
|
}
|
|
2848
2993
|
async function readRootSessionStateFromStateDir(stateDir) {
|
|
2849
2994
|
const sessionPath = join(stateDir, "session.json");
|
|
@@ -2947,17 +3092,6 @@ const RALPLAN_EXECUTION_HANDOFF_SKILLS = new Set([
|
|
|
2947
3092
|
"ultrawork",
|
|
2948
3093
|
"ultraqa",
|
|
2949
3094
|
]);
|
|
2950
|
-
function isActiveDeepInterviewPhase(state) {
|
|
2951
|
-
if (!state || state.active !== true)
|
|
2952
|
-
return false;
|
|
2953
|
-
const mode = safeString(state.mode).trim();
|
|
2954
|
-
if (mode && mode !== "deep-interview")
|
|
2955
|
-
return false;
|
|
2956
|
-
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
2957
|
-
if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing"))
|
|
2958
|
-
return false;
|
|
2959
|
-
return true;
|
|
2960
|
-
}
|
|
2961
3095
|
function isInactiveCompletedDeepInterviewPhase(state) {
|
|
2962
3096
|
if (!state || state.active !== false)
|
|
2963
3097
|
return false;
|
|
@@ -3065,8 +3199,13 @@ function isAllowedPlanningArtifactPath(cwd, rawPath, allowedPrefixes) {
|
|
|
3065
3199
|
function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
|
|
3066
3200
|
return isAllowedPlanningArtifactPath(cwd, rawPath, DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES);
|
|
3067
3201
|
}
|
|
3202
|
+
function isAllowedRalplanDraftPath(cwd, rawPath) {
|
|
3203
|
+
const relativePath = normalizePlanningArtifactRelativePath(cwd, rawPath);
|
|
3204
|
+
return relativePath !== null && /^\.omx\/drafts\/[^/]+\.md$/.test(relativePath);
|
|
3205
|
+
}
|
|
3068
3206
|
function isAllowedRalplanArtifactPath(cwd, rawPath) {
|
|
3069
|
-
return
|
|
3207
|
+
return isAllowedRalplanDraftPath(cwd, rawPath)
|
|
3208
|
+
|| isAllowedPlanningArtifactPath(cwd, rawPath, RALPLAN_ALLOWED_WRITE_PREFIXES);
|
|
3070
3209
|
}
|
|
3071
3210
|
function shellTokenizeLiteralCommand(command) {
|
|
3072
3211
|
const tokens = [];
|
|
@@ -3274,9 +3413,73 @@ function resolveCommandRedirectTarget(target, assignments) {
|
|
|
3274
3413
|
const resolved = assignments.get(safeString(variableMatch[1]));
|
|
3275
3414
|
return resolved !== undefined ? resolved : target;
|
|
3276
3415
|
}
|
|
3416
|
+
// Masks redirect metacharacters (`<`/`>`) that appear INSIDE shell quotes so a
|
|
3417
|
+
// quoted regex/source value (e.g. `gh issue create --body '...>{1,2}...'` or
|
|
3418
|
+
// `omx state write --input '{"reason":"a>b"}'`) is not misread as a redirect
|
|
3419
|
+
// write target. Escaped quotes at the top level (`\'`, `\"`) are literal
|
|
3420
|
+
// characters and must NOT open a span, and `$'...'` ANSI-C quoting processes
|
|
3421
|
+
// backslash escapes (so `\'` does not close it) — otherwise a genuine `>`
|
|
3422
|
+
// redirect could be masked behind a false span and its write missed. Only
|
|
3423
|
+
// characters inside a real quoted span are masked; unquoted redirect operators
|
|
3424
|
+
// survive intact. Unterminated/ambiguous quoting fails closed: the original
|
|
3425
|
+
// command is returned unmasked so genuine redirects stay visible to the scan.
|
|
3426
|
+
function maskQuotedRedirectMetacharsForCommandScan(command) {
|
|
3427
|
+
let masked = "";
|
|
3428
|
+
// null = unquoted; "'" = single quotes (no escapes); '"' = double quotes
|
|
3429
|
+
// (backslash escapes); "$'" = ANSI-C $'...' (backslash escapes, incl. \').
|
|
3430
|
+
let quote = null;
|
|
3431
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
3432
|
+
const char = command[index] ?? "";
|
|
3433
|
+
if (quote === null) {
|
|
3434
|
+
// A backslash escapes the next character at the top level, so an escaped
|
|
3435
|
+
// quote is a literal char and must not open a quoted span.
|
|
3436
|
+
if (char === "\\") {
|
|
3437
|
+
masked += char;
|
|
3438
|
+
const next = command[index + 1];
|
|
3439
|
+
if (next !== undefined) {
|
|
3440
|
+
masked += next;
|
|
3441
|
+
index += 1;
|
|
3442
|
+
}
|
|
3443
|
+
continue;
|
|
3444
|
+
}
|
|
3445
|
+
if (char === "$" && command[index + 1] === "'") {
|
|
3446
|
+
quote = "$'";
|
|
3447
|
+
masked += "$'";
|
|
3448
|
+
index += 1;
|
|
3449
|
+
continue;
|
|
3450
|
+
}
|
|
3451
|
+
if (char === "'" || char === "\"")
|
|
3452
|
+
quote = char;
|
|
3453
|
+
masked += char;
|
|
3454
|
+
continue;
|
|
3455
|
+
}
|
|
3456
|
+
if ((quote === "\"" || quote === "$'") && char === "\\") {
|
|
3457
|
+
// Escapes inside double/ANSI-C spans keep the backslash and its escaped
|
|
3458
|
+
// char (masking a redirect metachar so quoted data cannot be a false
|
|
3459
|
+
// target); the escaped char never closes the span.
|
|
3460
|
+
masked += char;
|
|
3461
|
+
const next = command[index + 1];
|
|
3462
|
+
if (next !== undefined) {
|
|
3463
|
+
masked += next === "<" || next === ">" ? "_" : next;
|
|
3464
|
+
index += 1;
|
|
3465
|
+
}
|
|
3466
|
+
continue;
|
|
3467
|
+
}
|
|
3468
|
+
const closesSpan = quote === "$'" ? char === "'" : char === quote;
|
|
3469
|
+
if (closesSpan) {
|
|
3470
|
+
quote = null;
|
|
3471
|
+
masked += char;
|
|
3472
|
+
continue;
|
|
3473
|
+
}
|
|
3474
|
+
masked += char === "<" || char === ">" ? "_" : char;
|
|
3475
|
+
}
|
|
3476
|
+
if (quote !== null)
|
|
3477
|
+
return command;
|
|
3478
|
+
return masked;
|
|
3479
|
+
}
|
|
3277
3480
|
function extractDeepInterviewCommandRedirectTargets(command) {
|
|
3278
3481
|
const targets = [];
|
|
3279
|
-
const commandOutsideHeredocBodies = stripHeredocBodiesForCommandScan(command);
|
|
3482
|
+
const commandOutsideHeredocBodies = maskQuotedRedirectMetacharsForCommandScan(stripHeredocBodiesForCommandScan(command));
|
|
3280
3483
|
for (const match of commandOutsideHeredocBodies.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
3281
3484
|
const candidate = safeString(match[2]).trim();
|
|
3282
3485
|
if (candidate && !isNullDeviceRedirectTarget(candidate))
|
|
@@ -3388,7 +3591,7 @@ function findGitSubcommandIndex(words, startIndex) {
|
|
|
3388
3591
|
}
|
|
3389
3592
|
return null;
|
|
3390
3593
|
}
|
|
3391
|
-
function commandHasDeepInterviewWriteIntent(command) {
|
|
3594
|
+
function commandHasDeepInterviewWriteIntent(command, depth = 0) {
|
|
3392
3595
|
return commandInvokesApplyPatch(command)
|
|
3393
3596
|
|| extractDeepInterviewCommandRedirectTargets(command).length > 0
|
|
3394
3597
|
|| /\btee\s+(?:-a\s+)?[^\s&|;]+/.test(command)
|
|
@@ -3399,7 +3602,17 @@ function commandHasDeepInterviewWriteIntent(command) {
|
|
|
3399
3602
|
|| extractConductorBashMutations(command).length > 0
|
|
3400
3603
|
|| extractConductorInterpreterWrites(command).length > 0
|
|
3401
3604
|
|| commandHasDestructiveGitSubcommand(command)
|
|
3402
|
-
|| commandHasPackageInstallIntent(command)
|
|
3605
|
+
|| commandHasPackageInstallIntent(command)
|
|
3606
|
+
// Recurse into wrapped shells (`bash -lc "cat > f"`, `eval`, `env`) and
|
|
3607
|
+
// command substitutions so a real redirect INSIDE a nested command string
|
|
3608
|
+
// is still classified as write intent. This is required because quoted
|
|
3609
|
+
// redirect metacharacters are now masked at the outer scan (#3119): the
|
|
3610
|
+
// mask removes false positives from quoted DATA values while nested-command
|
|
3611
|
+
// recursion re-detects genuine redirects, preserving fail-closed blocking.
|
|
3612
|
+
// The depth guard mirrors evaluateConductorBashWrite's nesting bound;
|
|
3613
|
+
// extractors return strict substrings, so recursion always terminates.
|
|
3614
|
+
|| (depth < CONDUCTOR_BASH_MAX_NESTING_DEPTH && (extractNestedShellCommandStringsForStateScan(command).some((nested) => commandHasDeepInterviewWriteIntent(nested, depth + 1))
|
|
3615
|
+
|| extractNestedCommandSubstitutionStringsForStateScan(command).some((nested) => commandHasDeepInterviewWriteIntent(nested, depth + 1))));
|
|
3403
3616
|
}
|
|
3404
3617
|
function extractDeepInterviewCommandWriteTargets(command) {
|
|
3405
3618
|
const assignments = extractCommandLiteralAssignments(command);
|
|
@@ -6173,6 +6386,121 @@ function isCompleteRalplanTerminalWritePayload(payload, activeState, sessionId)
|
|
|
6173
6386
|
return false;
|
|
6174
6387
|
return true;
|
|
6175
6388
|
}
|
|
6389
|
+
function hasUnquotedShellControlOrRedirection(command) {
|
|
6390
|
+
let quote = null;
|
|
6391
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
6392
|
+
const char = command[index] ?? "";
|
|
6393
|
+
if (char === "\\" && quote !== "'") {
|
|
6394
|
+
index += 1;
|
|
6395
|
+
continue;
|
|
6396
|
+
}
|
|
6397
|
+
if (char === "'" || char === '"') {
|
|
6398
|
+
quote = quote === char ? null : quote ?? char;
|
|
6399
|
+
continue;
|
|
6400
|
+
}
|
|
6401
|
+
if (!quote && ";&|()<>\n\r".includes(char))
|
|
6402
|
+
return true;
|
|
6403
|
+
}
|
|
6404
|
+
return false;
|
|
6405
|
+
}
|
|
6406
|
+
function suppliedSessionAliasesMatch(payload, sessionId) {
|
|
6407
|
+
return [
|
|
6408
|
+
payload.session_id,
|
|
6409
|
+
payload.owner_omx_session_id,
|
|
6410
|
+
payload.codex_session_id,
|
|
6411
|
+
payload.owner_codex_session_id,
|
|
6412
|
+
].filter((value) => value !== undefined)
|
|
6413
|
+
.every((value) => safeString(value).trim() === sessionId);
|
|
6414
|
+
}
|
|
6415
|
+
function hasOnlyFinishedExplicitOutcomes(payload) {
|
|
6416
|
+
const values = [
|
|
6417
|
+
payload.lifecycle_outcome,
|
|
6418
|
+
payload.lifecycleOutcome,
|
|
6419
|
+
payload.terminal_outcome,
|
|
6420
|
+
payload.terminalOutcome,
|
|
6421
|
+
payload.run_outcome,
|
|
6422
|
+
payload.runOutcome,
|
|
6423
|
+
].filter((value) => value !== undefined);
|
|
6424
|
+
return values.every((value) => inferTerminalLifecycleOutcome({ lifecycle_outcome: value }, { includeQuestionEnforcement: false }) === "finished");
|
|
6425
|
+
}
|
|
6426
|
+
function isCompleteDeepInterviewTerminalWritePayload(payload, activeState, sessionId) {
|
|
6427
|
+
if (!sessionId)
|
|
6428
|
+
return false;
|
|
6429
|
+
const activeMode = safeString(activeState.mode).trim().toLowerCase();
|
|
6430
|
+
if (activeMode && activeMode !== "deep-interview")
|
|
6431
|
+
return false;
|
|
6432
|
+
const activeSessionId = safeString(activeState.session_id
|
|
6433
|
+
?? activeState.owner_omx_session_id
|
|
6434
|
+
?? activeState.codex_session_id
|
|
6435
|
+
?? activeState.owner_codex_session_id).trim();
|
|
6436
|
+
if (activeSessionId && activeSessionId !== sessionId)
|
|
6437
|
+
return false;
|
|
6438
|
+
const mode = safeString(payload.mode).trim().toLowerCase();
|
|
6439
|
+
const phase = safeString(payload.current_phase ?? payload.currentPhase).trim().toLowerCase();
|
|
6440
|
+
const payloadSessionId = safeString(payload.session_id).trim();
|
|
6441
|
+
if (!hasOnlyFinishedExplicitOutcomes(payload))
|
|
6442
|
+
return false;
|
|
6443
|
+
return mode === "deep-interview"
|
|
6444
|
+
&& payload.active === false
|
|
6445
|
+
&& phase === "complete"
|
|
6446
|
+
&& payloadSessionId === sessionId
|
|
6447
|
+
&& inferTerminalLifecycleOutcome(payload, { includeQuestionEnforcement: false }) === "finished";
|
|
6448
|
+
}
|
|
6449
|
+
function isAllowedDeepInterviewTerminalStateWriteCommand(cwd, command, activeState, sessionId) {
|
|
6450
|
+
const rawWords = tokenizeShellWords(normalizeShellLineContinuations(command).trim());
|
|
6451
|
+
if (rawWords[0] !== "omx")
|
|
6452
|
+
return false;
|
|
6453
|
+
const canonicalCommand = canonicalizeOmxStateTransportCommand(command);
|
|
6454
|
+
if (hasUnquotedShellControlOrRedirection(command))
|
|
6455
|
+
return false;
|
|
6456
|
+
if (hasUnsafeUnquotedHeredocExpansion(canonicalCommand))
|
|
6457
|
+
return false;
|
|
6458
|
+
if (hasUnquotedShellSubstitution(canonicalCommand))
|
|
6459
|
+
return false;
|
|
6460
|
+
if (splitStateScanSegments(canonicalCommand).length !== 1)
|
|
6461
|
+
return false;
|
|
6462
|
+
if (sourcesFileWrittenEarlierInSameCommand(cwd, canonicalCommand))
|
|
6463
|
+
return false;
|
|
6464
|
+
if (findUnquotedOmxStateCommandIndexes(canonicalCommand, "clear").length > 0)
|
|
6465
|
+
return false;
|
|
6466
|
+
if (hasDynamicNestedShellExecution(canonicalCommand))
|
|
6467
|
+
return false;
|
|
6468
|
+
if (extractDeepInterviewCommandWriteTargets(command).length > 0)
|
|
6469
|
+
return false;
|
|
6470
|
+
const operations = collectOmxStateCommandOperations(command, "write");
|
|
6471
|
+
if (operations.length !== 1)
|
|
6472
|
+
return false;
|
|
6473
|
+
const operation = operations[0];
|
|
6474
|
+
if (!operation || operation.nested || operation.commandPrefix.trim() || hasPriorExecutableCommand(operation.prefix))
|
|
6475
|
+
return false;
|
|
6476
|
+
const inlineInputCount = operation.args.filter((arg) => arg === "--input" || arg.startsWith("--input=")).length;
|
|
6477
|
+
if (inlineInputCount !== 1 || operation.args.some((arg) => arg === "--input-file" || arg.startsWith("--input-file=")))
|
|
6478
|
+
return false;
|
|
6479
|
+
const inlineInput = readStateWriteFlagValue(operation.args, "--input");
|
|
6480
|
+
let rawPayload = null;
|
|
6481
|
+
try {
|
|
6482
|
+
rawPayload = inlineInput ? safeObject(JSON.parse(inlineInput)) : null;
|
|
6483
|
+
}
|
|
6484
|
+
catch {
|
|
6485
|
+
rawPayload = null;
|
|
6486
|
+
}
|
|
6487
|
+
const nestedState = safeObject(rawPayload?.state);
|
|
6488
|
+
if (!rawPayload
|
|
6489
|
+
|| "workingDirectory" in rawPayload
|
|
6490
|
+
|| !suppliedSessionAliasesMatch(rawPayload, sessionId)
|
|
6491
|
+
|| !hasOnlyFinishedExplicitOutcomes(rawPayload)
|
|
6492
|
+
|| (nestedState && ("mode" in nestedState
|
|
6493
|
+
|| "session_id" in nestedState
|
|
6494
|
+
|| "workingDirectory" in nestedState
|
|
6495
|
+
|| "active" in nestedState
|
|
6496
|
+
|| "current_phase" in nestedState
|
|
6497
|
+
|| "currentPhase" in nestedState
|
|
6498
|
+
|| !suppliedSessionAliasesMatch(nestedState, sessionId)
|
|
6499
|
+
|| !hasOnlyFinishedExplicitOutcomes(nestedState))))
|
|
6500
|
+
return false;
|
|
6501
|
+
const payload = readStateWriteInputPayload(cwd, canonicalCommand, command);
|
|
6502
|
+
return payload ? isCompleteDeepInterviewTerminalWritePayload(payload, activeState, sessionId) : false;
|
|
6503
|
+
}
|
|
6176
6504
|
function isAllowedRalplanTerminalStateWriteCommand(cwd, command, activeState, sessionId) {
|
|
6177
6505
|
const canonicalCommand = canonicalizeOmxStateTransportCommand(command);
|
|
6178
6506
|
if (hasUnsafeUnquotedHeredocExpansion(canonicalCommand))
|
|
@@ -6218,13 +6546,56 @@ function commandEndsPlanningPhase(cwd, command) {
|
|
|
6218
6546
|
const payload = readStateWriteInputPayload(cwd, canonicalCommand, command);
|
|
6219
6547
|
return payload ? isPlanningPhaseDeactivationPayload(payload) : true;
|
|
6220
6548
|
}
|
|
6221
|
-
function isAllowedDeepInterviewBashWrite(cwd, command) {
|
|
6549
|
+
function isAllowedDeepInterviewBashWrite(cwd, command, activeState, sessionId = "") {
|
|
6550
|
+
const stateWriteOperations = collectOmxStateCommandOperations(command, "write");
|
|
6551
|
+
const hasUnsafeRuntimeStateWrite = (words) => {
|
|
6552
|
+
const stateWordIndex = words.indexOf("state");
|
|
6553
|
+
const writeWordIndex = stateWordIndex >= 0 ? words.indexOf("write", stateWordIndex + 1) : -1;
|
|
6554
|
+
if (writeWordIndex <= stateWordIndex)
|
|
6555
|
+
return false;
|
|
6556
|
+
const hasRuntimeBeforeState = words.slice(0, stateWordIndex).some((word) => {
|
|
6557
|
+
const base = shellWordBaseName(word);
|
|
6558
|
+
return isNodeInterpreterCommandWord(base) || base === "bun" || base === "tsx";
|
|
6559
|
+
});
|
|
6560
|
+
if (!hasRuntimeBeforeState)
|
|
6561
|
+
return false;
|
|
6562
|
+
const inlineInput = readStateWriteFlagValue(words, "--input");
|
|
6563
|
+
let payload = null;
|
|
6564
|
+
try {
|
|
6565
|
+
const parsed = inlineInput ? safeObject(JSON.parse(inlineInput)) : null;
|
|
6566
|
+
const modeOverride = readStateWriteFlagValue(words, "--mode");
|
|
6567
|
+
payload = parsed
|
|
6568
|
+
? normalizeStateWriteClassificationPayload(modeOverride ? { ...parsed, mode: modeOverride } : parsed)
|
|
6569
|
+
: null;
|
|
6570
|
+
}
|
|
6571
|
+
catch {
|
|
6572
|
+
payload = null;
|
|
6573
|
+
}
|
|
6574
|
+
return (!payload && stateWriteOperations.length === 0)
|
|
6575
|
+
|| Boolean(payload && (safeString(payload.mode).trim().toLowerCase() !== "deep-interview"
|
|
6576
|
+
|| isPlanningPhaseDeactivationPayload(payload)));
|
|
6577
|
+
};
|
|
6578
|
+
const rawCommand = normalizeShellLineContinuations(command).trim();
|
|
6579
|
+
if ([rawCommand, canonicalizeOmxStateTransportCommand(rawCommand)]
|
|
6580
|
+
.some((candidate) => hasUnsafeRuntimeStateWrite(tokenizeShellWords(candidate))))
|
|
6581
|
+
return false;
|
|
6582
|
+
if (stateWriteOperations.some((operation) => operation.nested))
|
|
6583
|
+
return false;
|
|
6222
6584
|
if (isAllowedDeepInterviewRalplanHandoffCommand(cwd, command))
|
|
6223
6585
|
return true;
|
|
6224
6586
|
if (hasDeepInterviewRalplanHandoffStateMutation(cwd, command))
|
|
6225
6587
|
return false;
|
|
6226
|
-
if (commandEndsPlanningPhase(cwd, command))
|
|
6227
|
-
return
|
|
6588
|
+
if (commandEndsPlanningPhase(cwd, command)) {
|
|
6589
|
+
return activeState
|
|
6590
|
+
? isAllowedDeepInterviewTerminalStateWriteCommand(cwd, command, activeState, sessionId)
|
|
6591
|
+
: false;
|
|
6592
|
+
}
|
|
6593
|
+
if (stateWriteOperations.length > 0) {
|
|
6594
|
+
const canonicalCommand = canonicalizeOmxStateTransportCommand(command);
|
|
6595
|
+
const payload = readStateWriteInputPayload(cwd, canonicalCommand, command);
|
|
6596
|
+
if (!payload || safeString(payload.mode).trim().toLowerCase() !== "deep-interview")
|
|
6597
|
+
return false;
|
|
6598
|
+
}
|
|
6228
6599
|
if (commandHasUntargetedPlanningForbiddenIntent(command))
|
|
6229
6600
|
return false;
|
|
6230
6601
|
if (firstPlanningTmpScriptExecutionTarget(cwd, command))
|
|
@@ -6247,12 +6618,10 @@ async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionI
|
|
|
6247
6618
|
const modeState = sessionId
|
|
6248
6619
|
? await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir)
|
|
6249
6620
|
: await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
return modeState;
|
|
6255
|
-
}
|
|
6621
|
+
const hasActiveDeepInterviewSkill = listActiveSkills(canonicalState).some((entry) => (entry.skill === "deep-interview"
|
|
6622
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
6623
|
+
if (hasActiveDeepInterviewSkill && modeState?.active === true)
|
|
6624
|
+
return modeState;
|
|
6256
6625
|
if (isInactiveCompletedDeepInterviewPhase(modeState))
|
|
6257
6626
|
return null;
|
|
6258
6627
|
const autopilotState = sessionId
|
|
@@ -6399,7 +6768,7 @@ function buildDeepInterviewBashBlockedDetail(cwd, command) {
|
|
|
6399
6768
|
}
|
|
6400
6769
|
async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
|
|
6401
6770
|
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
|
|
6402
|
-
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
6771
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, stateDir, sessionId))
|
|
6403
6772
|
return null;
|
|
6404
6773
|
const threadId = readPayloadThreadId(payload);
|
|
6405
6774
|
const activeState = await readActiveRalplanStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
@@ -6450,7 +6819,7 @@ async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, reso
|
|
|
6450
6819
|
hookSpecificOutput: {
|
|
6451
6820
|
hookEventName: "PreToolUse",
|
|
6452
6821
|
additionalContext: `${planningModeDescription}. `
|
|
6453
|
-
+ "Write only planning artifacts under `.omx/context/`, `.omx/plans/`, `.omx/specs/`, `.omx/tmp/`, required `.omx/state/` files, or tracker metadata under `.beads/`. "
|
|
6822
|
+
+ "Write only planning artifacts under `.omx/context/`, `.omx/plans/`, `.omx/specs/`, `.omx/tmp/`, required `.omx/state/` files, Markdown drafts under `.omx/drafts/*.md`, or tracker metadata under `.beads/`. "
|
|
6454
6823
|
+ "Do not edit implementation files or run implementation-focused writes from planning phases. "
|
|
6455
6824
|
+ `To execute, first process an explicit handoff such as ${formatExecutionHandoffList(cwd)}, which must emit terminal planning state before implementation begins.`,
|
|
6456
6825
|
},
|
|
@@ -6458,7 +6827,7 @@ async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, reso
|
|
|
6458
6827
|
}
|
|
6459
6828
|
async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
|
|
6460
6829
|
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
|
|
6461
|
-
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
6830
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, stateDir, sessionId))
|
|
6462
6831
|
return null;
|
|
6463
6832
|
const threadId = readPayloadThreadId(payload);
|
|
6464
6833
|
const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
@@ -6470,7 +6839,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir
|
|
|
6470
6839
|
let blocked = false;
|
|
6471
6840
|
let blockedDetail = "implementation/write tools are blocked until an explicit handoff workflow is activated";
|
|
6472
6841
|
if (toolName === "Bash") {
|
|
6473
|
-
blocked = !isAllowedDeepInterviewBashWrite(cwd, command);
|
|
6842
|
+
blocked = !isAllowedDeepInterviewBashWrite(cwd, command, activeState, sessionId);
|
|
6474
6843
|
if (blocked) {
|
|
6475
6844
|
blockedDetail = buildDeepInterviewBashBlockedDetail(cwd, command);
|
|
6476
6845
|
}
|
|
@@ -6576,18 +6945,71 @@ async function buildPlanningRootPointerConflictPreToolUseOutput(payload, cwd, st
|
|
|
6576
6945
|
}
|
|
6577
6946
|
return blocked ? buildRalplanRootPointerConflictBlock(ralplanState) : null;
|
|
6578
6947
|
}
|
|
6579
|
-
async function hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId) {
|
|
6948
|
+
async function hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, stateDir, sessionId, options = {}) {
|
|
6580
6949
|
if (hasTeamWorkerEnvironment())
|
|
6581
6950
|
return true;
|
|
6582
|
-
if (!isTypedAgentRolePayload(payload))
|
|
6583
|
-
return false;
|
|
6584
6951
|
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
6585
6952
|
const session = trackingState?.sessions?.[sessionId];
|
|
6586
6953
|
if (!session)
|
|
6587
6954
|
return false;
|
|
6588
6955
|
const payloadThreadId = readPayloadThreadId(payload);
|
|
6956
|
+
const trackedPayloadThread = payloadThreadId ? session.threads[payloadThreadId] : undefined;
|
|
6957
|
+
const hasTrackedAdaptedTypedRole = payloadThreadId !== ""
|
|
6958
|
+
&& isTrustedSubagentThread(session, payloadThreadId)
|
|
6959
|
+
&& trackedPayloadThread?.provenance_kind === OMX_ADAPTED_PROVENANCE
|
|
6960
|
+
&& resolveInstalledRoleName(trackedPayloadThread.role ?? "") !== null;
|
|
6961
|
+
// Resolve the Main-root leader THREAD identity from the tracker's leader_thread_id
|
|
6962
|
+
// plus the canonical session's native_session_id (the leader's native thread). Only
|
|
6963
|
+
// genuine leader-thread identifiers may anchor the leader: owner_*_session_id are
|
|
6964
|
+
// session-level ids, not thread anchors, so they must NOT populate this set — their
|
|
6965
|
+
// mere presence would make it non-empty and suppress the fail-closed guard below
|
|
6966
|
+
// without ever excluding the leader thread (#3117 P4). The native_session_id anchor is
|
|
6967
|
+
// honored only when the root session pointer provably maps to the sessionId under
|
|
6968
|
+
// evaluation, so a stale/foreign session.json cannot supply another session's leader
|
|
6969
|
+
// anchor (#3117 P3); the tracker alone is insufficient because it can omit
|
|
6970
|
+
// leader_thread_id or corruptly label the leader kind:"subagent" (#3117 P2).
|
|
6971
|
+
const sessionState = await readRootSessionStateFromStateDir(stateDir).catch(() => null);
|
|
6972
|
+
const trackerLeaderThreadId = safeString(session.leader_thread_id).trim();
|
|
6973
|
+
const leaderIdentityAnchors = new Set();
|
|
6974
|
+
if (trackerLeaderThreadId)
|
|
6975
|
+
leaderIdentityAnchors.add(trackerLeaderThreadId);
|
|
6976
|
+
if (sessionState && sessionId && payloadMatchesSessionPointer(sessionId, sessionState)) {
|
|
6977
|
+
const nativeSessionId = safeString(sessionState.native_session_id).trim();
|
|
6978
|
+
if (nativeSessionId)
|
|
6979
|
+
leaderIdentityAnchors.add(nativeSessionId);
|
|
6980
|
+
}
|
|
6981
|
+
// Leader self-guard: the Main-root Conductor is never a delegated executor. Block it
|
|
6982
|
+
// ahead of every trust path, even when tracker or payload provenance is (possibly
|
|
6983
|
+
// corruptly) attached to the leader thread.
|
|
6984
|
+
if (payloadThreadId && leaderIdentityAnchors.has(payloadThreadId))
|
|
6985
|
+
return false;
|
|
6986
|
+
// Fail closed: without an authoritative leader anchor we cannot affirm the payload is
|
|
6987
|
+
// a non-leader delegated performer rather than a mislabeled leader, so we refuse trust
|
|
6988
|
+
// instead of inferring it from a corrupt tracker kind:"subagent" alone (#3117 P2).
|
|
6989
|
+
if (leaderIdentityAnchors.size === 0)
|
|
6990
|
+
return false;
|
|
6991
|
+
// Planning boundary guards (ralplan, deep-interview) still require a recognized typed
|
|
6992
|
+
// agent role, so an untyped collaboration.spawn_agent child cannot write before an
|
|
6993
|
+
// execution handoff/approval. A tracker-recorded OMX-adapted child is the equivalent
|
|
6994
|
+
// of a typed role only when its own persisted role is installed and validated.
|
|
6995
|
+
if (options.allowUntypedProvenance !== true
|
|
6996
|
+
&& !isTypedAgentRolePayload(payload)
|
|
6997
|
+
&& !hasTrackedAdaptedTypedRole) {
|
|
6998
|
+
return false;
|
|
6999
|
+
}
|
|
7000
|
+
// Tracker-backed provenance: the payload's own thread is a recorded, non-leader
|
|
7001
|
+
// subagent for this session — the non-spoofable anchor that lets native
|
|
7002
|
+
// collaboration.spawn_agent children/descendants edit under the Conductor guard even
|
|
7003
|
+
// without a recognized typed role (#3116). subagent-tracking.json is derived from
|
|
7004
|
+
// child SessionStart transcript metadata, not the live tool-call payload.
|
|
6589
7005
|
if (payloadThreadId && isTrustedSubagentThread(session, payloadThreadId))
|
|
6590
7006
|
return true;
|
|
7007
|
+
// Runtime-attached spawn provenance: trust a genuine spawned subagent turn whose
|
|
7008
|
+
// declared parent maps to this session's leader or a tracked thread. parentThreadId
|
|
7009
|
+
// comes from the runtime-set source.subagent.thread_spawn (not agent-controlled tool
|
|
7010
|
+
// arguments); an absent parent is rejected, the leader self-guard above blocks the
|
|
7011
|
+
// main root, and cross-session parents fail because they are not in this session's
|
|
7012
|
+
// tracked threads (#3116).
|
|
6591
7013
|
const source = safeObject(payload.source);
|
|
6592
7014
|
const subagent = safeObject(source.subagent);
|
|
6593
7015
|
const threadSpawn = safeObject(subagent.thread_spawn);
|
|
@@ -6597,10 +7019,7 @@ async function hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sess
|
|
|
6597
7019
|
?? threadSpawn.leaderThreadId).trim();
|
|
6598
7020
|
if (!parentThreadId)
|
|
6599
7021
|
return false;
|
|
6600
|
-
|
|
6601
|
-
if (payloadThreadId && leaderThreadId && payloadThreadId === leaderThreadId)
|
|
6602
|
-
return false;
|
|
6603
|
-
return leaderThreadId === parentThreadId || parentThreadId in session.threads;
|
|
7022
|
+
return leaderIdentityAnchors.has(parentThreadId) || parentThreadId in session.threads;
|
|
6604
7023
|
}
|
|
6605
7024
|
function isActiveConductorModeState(state, mode, sessionId) {
|
|
6606
7025
|
if (!state || state.active !== true)
|
|
@@ -6627,7 +7046,7 @@ async function readActiveMainRootConductorStateForPreToolUse(payload, cwd, state
|
|
|
6627
7046
|
const threadId = readPayloadThreadId(payload);
|
|
6628
7047
|
if (!sessionId)
|
|
6629
7048
|
return null;
|
|
6630
|
-
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
7049
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, stateDir, sessionId, { allowUntypedProvenance: true }))
|
|
6631
7050
|
return null;
|
|
6632
7051
|
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
6633
7052
|
if (!canonicalState)
|
|
@@ -7445,6 +7864,10 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7445
7864
|
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
7446
7865
|
payload,
|
|
7447
7866
|
persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
7867
|
+
persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, {
|
|
7868
|
+
cwd,
|
|
7869
|
+
sessionId: resolvedSessionId || readPayloadSessionId(payload),
|
|
7870
|
+
}),
|
|
7448
7871
|
persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
7449
7872
|
cwd,
|
|
7450
7873
|
sessionId: resolvedSessionId || readPayloadSessionId(payload),
|
|
@@ -7478,6 +7901,9 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7478
7901
|
const unsupportedNativeGuidance = isUnsupportedNativeSubagentEvidence(nativeSubagentSupport)
|
|
7479
7902
|
? ` ${buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)} Treat the active conductor workflow as blocked/cancelled for native delegation recovery; do not call multi_agent_v1.close_agent.`
|
|
7480
7903
|
: "";
|
|
7904
|
+
const roleRoutingUnavailableGuidance = isRoleRoutingUnavailableEvidence(nativeSubagentSupport)
|
|
7905
|
+
? ` ${buildRoleRoutingUnavailableGuidance(nativeSubagentSupport)}`
|
|
7906
|
+
: "";
|
|
7481
7907
|
return {
|
|
7482
7908
|
decision: "block",
|
|
7483
7909
|
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}.`,
|
|
@@ -7487,6 +7913,7 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7487
7913
|
+ "Use specialized agents for source edits and plan/spec authorship. "
|
|
7488
7914
|
+ `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. `
|
|
7489
7915
|
+ unsupportedNativeGuidance
|
|
7916
|
+
+ roleRoutingUnavailableGuidance
|
|
7490
7917
|
+ " Autopilot rework and typed subagent/worker lanes are exempt from this guard.",
|
|
7491
7918
|
},
|
|
7492
7919
|
};
|
|
@@ -8304,7 +8731,8 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8304
8731
|
return null;
|
|
8305
8732
|
}
|
|
8306
8733
|
const sessionId = readPayloadSessionId(payload);
|
|
8307
|
-
const canonicalSessionId =
|
|
8734
|
+
const canonicalSessionId = options.canonicalSessionId
|
|
8735
|
+
?? await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
8308
8736
|
const threadId = readPayloadThreadId(payload);
|
|
8309
8737
|
const suppressParentWorkflowStop = shouldSuppressParentWorkflowStopForSideConversation(payload);
|
|
8310
8738
|
if (canonicalSessionId) {
|
|
@@ -8348,7 +8776,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8348
8776
|
}
|
|
8349
8777
|
const ralphState = options.skipRalphStopBlock === true
|
|
8350
8778
|
? null
|
|
8351
|
-
: await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
8779
|
+
: await readActiveRalphState(cwd, stateDir, sessionId || canonicalSessionId, ralphOwnerContext);
|
|
8352
8780
|
if (!ralphState) {
|
|
8353
8781
|
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
8354
8782
|
if (autoresearchState) {
|
|
@@ -8429,7 +8857,8 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8429
8857
|
return ordinaryNoProgressOutput;
|
|
8430
8858
|
const autoNudgeConfig = await loadAutoNudgeConfig();
|
|
8431
8859
|
const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
|
|
8432
|
-
if (
|
|
8860
|
+
if (options.skipAutoNudge !== true
|
|
8861
|
+
&& autoNudgeConfig.enabled
|
|
8433
8862
|
&& detectNativeStopStallPattern(lastAssistantMessage, autoNudgeConfig.patterns, autoNudgePhase)) {
|
|
8434
8863
|
const effectiveResponse = resolveEffectiveAutoNudgeResponse(autoNudgeConfig.response);
|
|
8435
8864
|
return await returnPersistentStopBlock(payload, stateDir, "auto-nudge", lastAssistantMessage, {
|
|
@@ -8447,7 +8876,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8447
8876
|
if (isFinalHandoffDocumentRefreshCandidate(lastAssistantMessage)) {
|
|
8448
8877
|
const documentRefreshWarning = evaluateFinalHandoffDocumentRefresh(cwd, lastAssistantMessage);
|
|
8449
8878
|
if (documentRefreshWarning) {
|
|
8450
|
-
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, "document-refresh-stop", documentRefreshWarning.triggeringPaths.join("|"), canonicalSessionId),
|
|
8879
|
+
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, "document-refresh-stop", documentRefreshWarning.triggeringPaths.join("|"), canonicalSessionId), { systemMessage: documentRefreshWarning.message }, canonicalSessionId, { allowRepeatDuringStopHook: false });
|
|
8451
8880
|
}
|
|
8452
8881
|
}
|
|
8453
8882
|
return null;
|
|
@@ -8463,10 +8892,37 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8463
8892
|
systemMessage,
|
|
8464
8893
|
}, canonicalSessionId);
|
|
8465
8894
|
}
|
|
8895
|
+
async function preflightNativePromptTarget(stateDir, context) {
|
|
8896
|
+
if (context.status !== "authorized")
|
|
8897
|
+
return context;
|
|
8898
|
+
const targetDir = join(stateDir, "sessions", context.authorization.targetSessionId);
|
|
8899
|
+
const evidence = [];
|
|
8900
|
+
let filenames;
|
|
8901
|
+
try {
|
|
8902
|
+
filenames = await readdir(targetDir);
|
|
8903
|
+
}
|
|
8904
|
+
catch (error) {
|
|
8905
|
+
if (error.code === "ENOENT")
|
|
8906
|
+
return context;
|
|
8907
|
+
return preflightSelectedTargetOwner(context, [{ ownerCodexSessionId: {} }], "native", new Date().toISOString());
|
|
8908
|
+
}
|
|
8909
|
+
for (const filename of filenames) {
|
|
8910
|
+
if (!filename.endsWith("-state.json") && filename !== SKILL_ACTIVE_STATE_FILE)
|
|
8911
|
+
continue;
|
|
8912
|
+
try {
|
|
8913
|
+
const value = JSON.parse(await readFile(join(targetDir, filename), "utf8"));
|
|
8914
|
+
evidence.push(...extractSelectedTargetOwnerEvidence(value));
|
|
8915
|
+
}
|
|
8916
|
+
catch {
|
|
8917
|
+
evidence.push({ ownerCodexSessionId: {} });
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
return preflightSelectedTargetOwner(context, evidence, "native", new Date().toISOString());
|
|
8921
|
+
}
|
|
8466
8922
|
export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
8467
8923
|
const hookEventName = readHookEventName(payload);
|
|
8468
8924
|
const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
|
|
8469
|
-
if (hookEventName === "
|
|
8925
|
+
if (hookEventName === "PostCompact" && process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE === "1") {
|
|
8470
8926
|
return {
|
|
8471
8927
|
hookEventName,
|
|
8472
8928
|
omxEventName: mapCodexHookEventToOmxEvent(hookEventName),
|
|
@@ -8474,22 +8930,70 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8474
8930
|
outputJson: null,
|
|
8475
8931
|
};
|
|
8476
8932
|
}
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8933
|
+
try {
|
|
8934
|
+
recoverAdaptedRoleBindings(cwd, getBaseStateDir(cwd));
|
|
8935
|
+
}
|
|
8936
|
+
catch {
|
|
8937
|
+
// Recovery is best-effort for unrelated hook events.
|
|
8938
|
+
}
|
|
8939
|
+
if (hookEventName === "Stop" && !hasNativeStopRuntimeSurface(cwd)) {
|
|
8940
|
+
return {
|
|
8941
|
+
hookEventName,
|
|
8942
|
+
omxEventName: mapCodexHookEventToOmxEvent(hookEventName),
|
|
8943
|
+
skillState: null,
|
|
8944
|
+
outputJson: null,
|
|
8945
|
+
};
|
|
8482
8946
|
}
|
|
8947
|
+
// Native hooks must use the exact pointer root selected for this dispatch.
|
|
8948
|
+
const pointerContext = resolveSessionPointerContext(cwd);
|
|
8949
|
+
const stateDir = pointerContext.baseStateDir;
|
|
8483
8950
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
8484
8951
|
let skillState = null;
|
|
8485
8952
|
let triageAdditionalContext = null;
|
|
8486
8953
|
let goalWorkflowAdditionalContext = null;
|
|
8487
8954
|
let ultragoalSteeringAdditionalContext = null;
|
|
8955
|
+
let promptClassification = null;
|
|
8488
8956
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
8489
8957
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
8490
8958
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
8491
|
-
const
|
|
8959
|
+
const pointer = await readSessionPointer(pointerContext);
|
|
8960
|
+
const currentSessionState = pointer.status === "usable" ? pointer.state ?? null : null;
|
|
8961
|
+
let promptTurnContext = hookEventName === "UserPromptSubmit"
|
|
8962
|
+
? evaluateResolvedPromptTurn({
|
|
8963
|
+
producer: "native",
|
|
8964
|
+
payloadSessionId: payload.session_id ?? payload.sessionId,
|
|
8965
|
+
ownerEnvSessionId: undefined,
|
|
8966
|
+
selectedPointer: pointer,
|
|
8967
|
+
threadFacts: await readNativePromptThreadFacts(cwd, nativeSessionId, threadId, currentSessionState),
|
|
8968
|
+
nowIso: new Date().toISOString(),
|
|
8969
|
+
})
|
|
8970
|
+
: null;
|
|
8971
|
+
if (promptTurnContext) {
|
|
8972
|
+
promptTurnContext = await preflightNativePromptTarget(stateDir, promptTurnContext);
|
|
8973
|
+
}
|
|
8974
|
+
if (promptTurnContext?.status === "rejected") {
|
|
8975
|
+
await appendPromptSessionProvenanceRejection(pointerContext, promptTurnContext.diagnostic).catch(() => { });
|
|
8976
|
+
return { hookEventName, omxEventName, skillState: null, outputJson: null };
|
|
8977
|
+
}
|
|
8978
|
+
if (promptTurnContext?.status === "suppressed-target-child") {
|
|
8979
|
+
return { hookEventName, omxEventName, skillState: null, outputJson: null };
|
|
8980
|
+
}
|
|
8981
|
+
if (hookEventName !== "Stop") {
|
|
8982
|
+
await mkdir(stateDir, { recursive: true });
|
|
8983
|
+
}
|
|
8984
|
+
let allowImplicitSessionSideEffects = pointer.status === "usable" || pointer.status === "absent" || promptTurnContext?.status === "authorized";
|
|
8985
|
+
let stopAuthorizationFailure = allowImplicitSessionSideEffects
|
|
8986
|
+
? null
|
|
8987
|
+
: {
|
|
8988
|
+
stopReason: "session_pointer_unusable",
|
|
8989
|
+
reason: `OMX cannot authorize Stop while the selected session pointer is ${pointer.status}; repair the pointer evidence before continuing.`,
|
|
8990
|
+
};
|
|
8492
8991
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
8992
|
+
if (promptTurnContext?.status === "authorized") {
|
|
8993
|
+
canonicalSessionId = promptTurnContext.authorization.targetSessionId;
|
|
8994
|
+
}
|
|
8995
|
+
const allowPromptGlobalSideEffects = promptTurnContext?.status !== "authorized"
|
|
8996
|
+
|| promptTurnContext.authorization.globalSideEffects === "allow";
|
|
8493
8997
|
let resolvedNativeSessionId = nativeSessionId;
|
|
8494
8998
|
let skipCanonicalSessionStartContext = false;
|
|
8495
8999
|
let isSubagentSessionStart = false;
|
|
@@ -8528,20 +9032,58 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8528
9032
|
}
|
|
8529
9033
|
}
|
|
8530
9034
|
else {
|
|
8531
|
-
const
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
9035
|
+
const ownerOmxSessionId = await resolveVerifiedOwnerOmxSessionId();
|
|
9036
|
+
try {
|
|
9037
|
+
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
9038
|
+
context: pointerContext,
|
|
9039
|
+
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
9040
|
+
...(ownerOmxSessionId
|
|
9041
|
+
? { ownerOmxSessionId, ownerAliasVerified: true }
|
|
9042
|
+
: {}),
|
|
9043
|
+
});
|
|
9044
|
+
canonicalSessionId = safeString(sessionState.session_id).trim();
|
|
9045
|
+
resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
9046
|
+
allowImplicitSessionSideEffects = true;
|
|
9047
|
+
stopAuthorizationFailure = null;
|
|
9048
|
+
// #3181: leader attestation is intentionally NOT performed here. This branch is
|
|
9049
|
+
// reached whenever readNativeSubagentSessionStartMetadata() returns null, which
|
|
9050
|
+
// conflates a genuine root start with an unreadable/malformed child transcript, so
|
|
9051
|
+
// it cannot positively classify a leader (a legitimate leader may also carry no
|
|
9052
|
+
// transcript). Leader attestation is performed only on the strictly-gated fresh
|
|
9053
|
+
// leader PreToolUse path below, which fires before the first in-turn role-intent
|
|
9054
|
+
// write. Fail closed here rather than risk a false-leader adoption.
|
|
9055
|
+
}
|
|
9056
|
+
catch (error) {
|
|
9057
|
+
if (!isSessionPointerLaunchAbort(error))
|
|
9058
|
+
throw error;
|
|
9059
|
+
canonicalSessionId = "";
|
|
9060
|
+
resolvedNativeSessionId = nativeSessionId;
|
|
9061
|
+
skipCanonicalSessionStartContext = true;
|
|
9062
|
+
allowImplicitSessionSideEffects = false;
|
|
9063
|
+
stopAuthorizationFailure = {
|
|
9064
|
+
stopReason: "session_pointer_unusable",
|
|
9065
|
+
reason: `OMX cannot authorize Stop while the selected session pointer is ${pointer.status}; repair the pointer evidence before continuing.`,
|
|
9066
|
+
};
|
|
9067
|
+
}
|
|
8536
9068
|
}
|
|
8537
9069
|
}
|
|
8538
9070
|
else if (!canonicalSessionId) {
|
|
8539
9071
|
canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
8540
9072
|
}
|
|
8541
9073
|
if (hookEventName === "Stop") {
|
|
8542
|
-
const
|
|
8543
|
-
const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd,
|
|
8544
|
-
if (stopCanonicalSessionId) {
|
|
9074
|
+
const stopPayloadSessionId = readPayloadSessionId(payload);
|
|
9075
|
+
const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd, stopPayloadSessionId, undefined, currentSessionState, pointer.status === "absent");
|
|
9076
|
+
if (stopPayloadSessionId && !stopCanonicalSessionId) {
|
|
9077
|
+
canonicalSessionId = "";
|
|
9078
|
+
allowImplicitSessionSideEffects = false;
|
|
9079
|
+
if (!stopAuthorizationFailure) {
|
|
9080
|
+
stopAuthorizationFailure = {
|
|
9081
|
+
stopReason: "session_scope_unmatched",
|
|
9082
|
+
reason: `OMX cannot authorize Stop for unmatched session id ${stopPayloadSessionId}; the selected session pointer remains authoritative.`,
|
|
9083
|
+
};
|
|
9084
|
+
}
|
|
9085
|
+
}
|
|
9086
|
+
else if (stopCanonicalSessionId) {
|
|
8545
9087
|
canonicalSessionId = stopCanonicalSessionId;
|
|
8546
9088
|
}
|
|
8547
9089
|
if (canonicalSessionId && safeString(currentSessionState?.session_id).trim() === canonicalSessionId) {
|
|
@@ -8549,8 +9091,8 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8549
9091
|
safeString(currentSessionState?.native_session_id).trim() || resolvedNativeSessionId;
|
|
8550
9092
|
}
|
|
8551
9093
|
}
|
|
8552
|
-
|
|
8553
|
-
|
|
9094
|
+
let eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
9095
|
+
let sessionIdForState = canonicalSessionId || null;
|
|
8554
9096
|
let outputJson = null;
|
|
8555
9097
|
const typedAgentRolePayload = isTypedAgentRolePayload(payload);
|
|
8556
9098
|
const isSubagentPromptSubmit = hookEventName === "UserPromptSubmit"
|
|
@@ -8565,27 +9107,74 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8565
9107
|
? safeString(currentSessionState?.native_session_id).trim()
|
|
8566
9108
|
: "")))).some(Boolean)
|
|
8567
9109
|
: false;
|
|
9110
|
+
if (isSubagentStop && stopAuthorizationFailure?.stopReason === "session_scope_unmatched") {
|
|
9111
|
+
canonicalSessionId = normalizeSessionId(readPayloadSessionId(payload)) ?? "";
|
|
9112
|
+
allowImplicitSessionSideEffects = true;
|
|
9113
|
+
stopAuthorizationFailure = null;
|
|
9114
|
+
eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
9115
|
+
sessionIdForState = canonicalSessionId || null;
|
|
9116
|
+
}
|
|
8568
9117
|
const suppressNoisySubagentLifecycleDispatch = (isSubagentSessionStart || isSubagentStop)
|
|
8569
9118
|
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
8570
9119
|
if (hookEventName === "UserPromptSubmit") {
|
|
8571
9120
|
const prompt = readPromptText(payload);
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
9121
|
+
if (!isSubagentPromptSubmit) {
|
|
9122
|
+
promptClassification = classifyKeywordInput(prompt);
|
|
9123
|
+
}
|
|
9124
|
+
goalWorkflowAdditionalContext = allowPromptGlobalSideEffects
|
|
9125
|
+
? await buildCompletedGoalCleanupPromptWarning(cwd, prompt).catch(() => null)
|
|
9126
|
+
?? await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null)
|
|
9127
|
+
: null;
|
|
9128
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects && allowPromptGlobalSideEffects
|
|
8575
9129
|
? 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)}`)
|
|
8576
9130
|
: null;
|
|
8577
|
-
|
|
8578
|
-
|
|
9131
|
+
let suppressActivationSeeding = !allowImplicitSessionSideEffects;
|
|
9132
|
+
if (promptTurnContext?.status === "authorized") {
|
|
9133
|
+
sessionIdForState = promptTurnContext.authorization.targetSessionId;
|
|
9134
|
+
}
|
|
9135
|
+
else if (prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects) {
|
|
9136
|
+
const rawHookSessionId = canonicalSessionId || nativeSessionId;
|
|
9137
|
+
const normalizedHookSessionId = normalizeSessionId(rawHookSessionId);
|
|
9138
|
+
const explicitHookSessionId = currentSessionState ? undefined : normalizedHookSessionId;
|
|
9139
|
+
if (rawHookSessionId && !normalizedHookSessionId) {
|
|
9140
|
+
suppressActivationSeeding = true;
|
|
9141
|
+
}
|
|
9142
|
+
else {
|
|
9143
|
+
try {
|
|
9144
|
+
const writableScope = await resolveWritableStateScope(cwd, explicitHookSessionId);
|
|
9145
|
+
sessionIdForState = writableScope.sessionId ?? null;
|
|
9146
|
+
}
|
|
9147
|
+
catch (error) {
|
|
9148
|
+
if (!isImplicitWritableScopeFailure(error))
|
|
9149
|
+
throw error;
|
|
9150
|
+
suppressActivationSeeding = true;
|
|
9151
|
+
}
|
|
9152
|
+
}
|
|
9153
|
+
}
|
|
9154
|
+
if (prompt && promptClassification && !isSubagentPromptSubmit && !suppressActivationSeeding) {
|
|
9155
|
+
skillState = buildNativeOutsideTmuxTeamPromptBlockState(promptClassification, cwd, payload, sessionIdForState || undefined, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
|
|
8579
9156
|
stateDir,
|
|
8580
9157
|
sourceCwd: cwd,
|
|
8581
9158
|
text: prompt,
|
|
8582
|
-
|
|
9159
|
+
classification: promptClassification,
|
|
9160
|
+
allowSecondaryTeam: !isNativeOutsideTmuxUserPrompt(cwd, payload, sessionIdForState || undefined),
|
|
9161
|
+
sessionId: sessionIdForState || undefined,
|
|
8583
9162
|
threadId,
|
|
8584
9163
|
turnId,
|
|
9164
|
+
resolvedPromptTurnContext: promptTurnContext ?? undefined,
|
|
9165
|
+
onProvenanceRejected: async (diagnostic) => {
|
|
9166
|
+
await appendPromptSessionProvenanceRejection(pointerContext, diagnostic).catch(() => { });
|
|
9167
|
+
},
|
|
8585
9168
|
});
|
|
8586
9169
|
}
|
|
8587
9170
|
// --- Triage classifier (advisory-only, non-keyword prompts) ---
|
|
8588
|
-
if (prompt
|
|
9171
|
+
if (prompt
|
|
9172
|
+
&& skillState === null
|
|
9173
|
+
&& !isSubagentPromptSubmit
|
|
9174
|
+
&& allowPromptGlobalSideEffects
|
|
9175
|
+
&& promptClassification?.reservedInput === null
|
|
9176
|
+
&& promptClassification.hasExplicitLikeInvocation === false
|
|
9177
|
+
&& promptClassification.matches.length === 0) {
|
|
8589
9178
|
try {
|
|
8590
9179
|
if (readTriageConfig().enabled) {
|
|
8591
9180
|
const normalized = prompt.trim().toLowerCase();
|
|
@@ -8614,7 +9203,9 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8614
9203
|
},
|
|
8615
9204
|
suppress_followup: true,
|
|
8616
9205
|
};
|
|
8617
|
-
|
|
9206
|
+
if (!suppressActivationSeeding) {
|
|
9207
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
9208
|
+
}
|
|
8618
9209
|
}
|
|
8619
9210
|
else if (decision.lane === "LIGHT") {
|
|
8620
9211
|
if (decision.destination === "explore") {
|
|
@@ -8647,7 +9238,9 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8647
9238
|
},
|
|
8648
9239
|
suppress_followup: true,
|
|
8649
9240
|
};
|
|
8650
|
-
|
|
9241
|
+
if (!suppressActivationSeeding) {
|
|
9242
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
9243
|
+
}
|
|
8651
9244
|
}
|
|
8652
9245
|
}
|
|
8653
9246
|
// lane === "PASS": no context, no state write
|
|
@@ -8662,14 +9255,14 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8662
9255
|
const skipHudReconcileForDoctorSmoke = process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE === "1";
|
|
8663
9256
|
const skipHudReconcileForTeamWorkerPane = !isSubagentPromptSubmit
|
|
8664
9257
|
&& await isConfirmedTeamWorkerPromptSubmitPane(cwd).catch(() => false);
|
|
8665
|
-
if (!skipHudReconcileForDoctorSmoke && !skipHudReconcileForTeamWorkerPane) {
|
|
9258
|
+
if (allowImplicitSessionSideEffects && allowPromptGlobalSideEffects && !skipHudReconcileForDoctorSmoke && !skipHudReconcileForTeamWorkerPane) {
|
|
8666
9259
|
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
8667
9260
|
const hudSessionId = resolveHudReconcileSessionId(currentSessionState, canonicalSessionId, sessionIdForState);
|
|
8668
9261
|
const hudSessionIds = resolveHudReconcileSessionIds(currentSessionState, canonicalSessionId, sessionIdForState, nativeSessionId);
|
|
8669
9262
|
await reconcileHudForPromptSubmitFn(cwd, { sessionId: hudSessionId, sessionIds: hudSessionIds }).catch(() => { });
|
|
8670
9263
|
}
|
|
8671
9264
|
}
|
|
8672
|
-
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
9265
|
+
if (omxEventName && allowImplicitSessionSideEffects && allowPromptGlobalSideEffects && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
8673
9266
|
const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
|
|
8674
9267
|
if (resolvedNativeSessionId) {
|
|
8675
9268
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -8706,12 +9299,14 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8706
9299
|
})
|
|
8707
9300
|
: isSubagentPromptSubmit
|
|
8708
9301
|
? null
|
|
8709
|
-
:
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
9302
|
+
: promptClassification
|
|
9303
|
+
? [
|
|
9304
|
+
buildAdditionalContextMessage(promptClassification, skillState, cwd, payload),
|
|
9305
|
+
ultragoalSteeringAdditionalContext,
|
|
9306
|
+
goalWorkflowAdditionalContext,
|
|
9307
|
+
triageAdditionalContext,
|
|
9308
|
+
].filter((entry) => Boolean(entry)).join("\n\n") || null
|
|
9309
|
+
: null;
|
|
8715
9310
|
if (additionalContext) {
|
|
8716
9311
|
outputJson = {
|
|
8717
9312
|
hookSpecificOutput: {
|
|
@@ -8722,12 +9317,52 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8722
9317
|
}
|
|
8723
9318
|
}
|
|
8724
9319
|
else if (hookEventName === "PreToolUse") {
|
|
9320
|
+
// #3181 Phase-1 (PreToolUse): this hook fires before the shell tool call that runs
|
|
9321
|
+
// the first in-turn `omx ralplan role-intent write`. On a fresh App/outside-tmux
|
|
9322
|
+
// turn where SessionStart did not establish the pointer, reconcile the canonical
|
|
9323
|
+
// pointer and attest the leader here so the first command can bootstrap. Strictly
|
|
9324
|
+
// gated to a fresh (absent-pointer) LEADER turn: no canonical session yet, a present
|
|
9325
|
+
// native session id, a leader-shaped thread (absent or equal to the native session
|
|
9326
|
+
// id), and no subagent/typed-role provenance. Best-effort; never blocks PreToolUse.
|
|
9327
|
+
if (allowImplicitSessionSideEffects
|
|
9328
|
+
&& !canonicalSessionId
|
|
9329
|
+
&& nativeSessionId
|
|
9330
|
+
&& readPayloadAgentRole(payload) === ""
|
|
9331
|
+
&& !hasSubagentThreadSpawnProvenance(payload)) {
|
|
9332
|
+
const preToolUseLeaderThreadId = readPayloadThreadId(payload);
|
|
9333
|
+
if (preToolUseLeaderThreadId
|
|
9334
|
+
&& preToolUseLeaderThreadId === nativeSessionId
|
|
9335
|
+
&& !(await isThreadTrackedAsSubagent(cwd, nativeSessionId))) {
|
|
9336
|
+
try {
|
|
9337
|
+
const ownerOmxSessionId = await resolveVerifiedOwnerOmxSessionId();
|
|
9338
|
+
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
9339
|
+
context: pointerContext,
|
|
9340
|
+
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
9341
|
+
...(ownerOmxSessionId ? { ownerOmxSessionId, ownerAliasVerified: true } : {}),
|
|
9342
|
+
});
|
|
9343
|
+
const bootstrapSessionId = safeString(sessionState.session_id).trim();
|
|
9344
|
+
const bootstrapLeaderThreadId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
9345
|
+
if (bootstrapSessionId && bootstrapLeaderThreadId) {
|
|
9346
|
+
canonicalSessionId = bootstrapSessionId;
|
|
9347
|
+
attestLeaderThread(cwd, {
|
|
9348
|
+
sessionId: bootstrapSessionId,
|
|
9349
|
+
leaderThreadId: bootstrapLeaderThreadId,
|
|
9350
|
+
source: 'native-pretooluse',
|
|
9351
|
+
});
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9354
|
+
catch {
|
|
9355
|
+
// Best-effort bootstrap; PreToolUse must never fail on this.
|
|
9356
|
+
}
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
8725
9359
|
const payloadSessionId = readPayloadSessionId(payload);
|
|
8726
9360
|
const rootPointerConflict = await readLiveRootSessionPointerConflict(stateDir, payloadSessionId);
|
|
8727
9361
|
const preToolUseSessionId = payloadSessionId
|
|
8728
9362
|
? await resolveInternalSessionIdForPayload(cwd, payloadSessionId, stateDir)
|
|
8729
9363
|
: "";
|
|
8730
|
-
outputJson =
|
|
9364
|
+
outputJson = buildNativeUnknownRolePreToolUseOutput(payload)
|
|
9365
|
+
?? await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
8731
9366
|
?? await buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
8732
9367
|
?? await buildPlanningRootPointerConflictPreToolUseOutput(payload, cwd, stateDir, rootPointerConflict)
|
|
8733
9368
|
?? await buildConductorPreToolUseWriteGuardOutput(payload, cwd, stateDir, preToolUseSessionId)
|
|
@@ -8736,18 +9371,36 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8736
9371
|
?? buildNativePreToolUseOutput(payload);
|
|
8737
9372
|
}
|
|
8738
9373
|
else if (hookEventName === "PostToolUse") {
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
9374
|
+
if (allowImplicitSessionSideEffects) {
|
|
9375
|
+
await recordNativeSubagentCapacityBlocker(cwd, stateDir, payload).catch(() => { });
|
|
9376
|
+
await recordNativeSubagentSupportBlocker(cwd, stateDir, payload).catch(() => { });
|
|
9377
|
+
if (detectMcpTransportFailure(payload)) {
|
|
9378
|
+
await markTeamTransportFailure(cwd, payload);
|
|
9379
|
+
}
|
|
9380
|
+
await handleTeamWorkerPostToolUseSuccess(payload, cwd);
|
|
8743
9381
|
}
|
|
8744
9382
|
outputJson = buildNativePostToolUseOutput(payload);
|
|
8745
|
-
await handleTeamWorkerPostToolUseSuccess(payload, cwd);
|
|
8746
9383
|
}
|
|
8747
9384
|
else if (hookEventName === "Stop") {
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
9385
|
+
if (allowImplicitSessionSideEffects) {
|
|
9386
|
+
outputJson = await buildStopHookOutput(payload, cwd, stateDir, {
|
|
9387
|
+
canonicalSessionId: canonicalSessionId || undefined,
|
|
9388
|
+
skipRalphStopBlock: isSubagentStop,
|
|
9389
|
+
skipAutoNudge: isSubagentStop,
|
|
9390
|
+
}) ?? await buildCompletedGoalCleanupStopOutput(payload, cwd);
|
|
9391
|
+
}
|
|
9392
|
+
else {
|
|
9393
|
+
const failure = stopAuthorizationFailure ?? {
|
|
9394
|
+
stopReason: "session_pointer_unusable",
|
|
9395
|
+
reason: "OMX cannot authorize Stop without a writable session authority.",
|
|
9396
|
+
};
|
|
9397
|
+
outputJson = {
|
|
9398
|
+
decision: "block",
|
|
9399
|
+
stopReason: failure.stopReason,
|
|
9400
|
+
reason: failure.reason,
|
|
9401
|
+
systemMessage: failure.reason,
|
|
9402
|
+
};
|
|
9403
|
+
}
|
|
8751
9404
|
}
|
|
8752
9405
|
return {
|
|
8753
9406
|
hookEventName,
|