oh-my-codex 0.20.1 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +10 -1
- package/dist/adapt/__tests__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
- package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
- package/dist/auth/__tests__/hotswap.test.js +183 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +17 -4
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +4 -4
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/lockfile.js.map +1 -1
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/skill-mirror.js.map +1 -1
- package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +650 -15
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +216 -11
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +49 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +84 -12
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +128 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +8 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +187 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +129 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +6 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +2261 -14
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-preferences.test.js +79 -0
- package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
- package/dist/cli/__tests__/setup-refresh.test.js +33 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +46 -3
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +37 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +61 -1
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +1771 -24
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +58 -0
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/adapt.js.map +1 -1
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/ask.d.ts +1 -1
- package/dist/cli/ask.d.ts.map +1 -1
- package/dist/cli/ask.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/capabilities.js.map +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +594 -130
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +11 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +108 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/mission.js.map +1 -1
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +18 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +239 -0
- package/dist/cli/native-hook-claim-journal.js.map +1 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +14 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +203 -0
- package/dist/cli/ralplan.js.map +1 -0
- package/dist/cli/setup-preferences.d.ts +11 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +32 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +53 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1401 -398
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +2 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +5 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +34 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +8 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +944 -95
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +5 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +1287 -11
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +850 -32
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -1
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +124 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2142 -265
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +21 -16
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +991 -137
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +2 -2
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js.map +1 -1
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/config/team-mode.d.ts.map +1 -1
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
- package/dist/document-refresh/enforcer.js.map +1 -1
- package/dist/exec/followup.js.map +1 -1
- package/dist/goal-workflows/artifacts.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +1372 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +14 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +669 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +8 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +532 -11
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +5 -5
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/code-simplifier/index.js.map +1 -1
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/events.js.map +1 -1
- package/dist/hooks/extensibility/loader.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
- package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +33 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2228 -119
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts +12 -0
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +41 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-session-provenance.d.ts +87 -0
- package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
- package/dist/hooks/prompt-session-provenance.js +180 -0
- package/dist/hooks/prompt-session-provenance.js.map +1 -0
- package/dist/hooks/session.d.ts +139 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1239 -317
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +103 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +26 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +109 -3
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +98 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +58 -58
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/hermes-server.d.ts +70 -70
- package/dist/mcp/hermes-server.d.ts.map +1 -1
- package/dist/mcp/lifecycle-telemetry.js.map +1 -1
- package/dist/mcp/memory-server.d.ts +34 -34
- package/dist/mcp/memory-server.d.ts.map +1 -1
- package/dist/mcp/memory-server.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +14 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +96 -20
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +47 -47
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.d.ts +4 -4
- package/dist/mcp/trace-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +23 -23
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +53 -1
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -5
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/index.d.ts +4 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +3 -9
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.js.map +1 -1
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/notifications/tmux-detector.js.map +1 -1
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/openclaw/config.js.map +1 -1
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +8 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/planning/artifact-names.js.map +1 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/state.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/events.js.map +1 -1
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js.map +1 -1
- package/dist/question/ui.js.map +1 -1
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +403 -8
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +112 -14
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +3 -3
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +155 -60
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +2 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +1 -2
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/process-tree.js.map +1 -1
- package/dist/runtime/run-loop.js.map +1 -1
- package/dist/runtime/run-outcome.d.ts +3 -3
- package/dist/runtime/run-outcome.d.ts.map +1 -1
- package/dist/runtime/run-outcome.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +4121 -592
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +205 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +175 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +848 -4
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
- package/dist/scripts/build-api.js.map +1 -1
- package/dist/scripts/build-explore-harness.js.map +1 -1
- package/dist/scripts/build-sparkshell.js.map +1 -1
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +689 -156
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
- package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
- package/dist/scripts/notify-fallback-delivery.js +419 -0
- package/dist/scripts/notify-fallback-delivery.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +136 -30
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +39 -13
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +122 -12
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +17 -0
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +73 -11
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -4
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +2 -2
- package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +25 -16
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +15 -13
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts +24 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +266 -90
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +879 -2
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +1528 -7
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/test-reply-listener-live.js.map +1 -1
- package/dist/scripts/test-sparkshell.js.map +1 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/session-history/friction.js.map +1 -1
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/sidecar/index.js.map +1 -1
- package/dist/sidecar/render.js.map +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +64 -15
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +19 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +61 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +49 -55
- package/dist/state/operations.js.map +1 -1
- package/dist/state/paths.d.ts +1 -1
- package/dist/state/paths.d.ts.map +1 -1
- package/dist/state/paths.js +1 -1
- package/dist/state/paths.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +43 -4
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +20 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +2 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js +988 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +273 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +1550 -10
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/adapted-role-binding.d.ts +17 -0
- package/dist/subagents/adapted-role-binding.d.ts.map +1 -0
- package/dist/subagents/adapted-role-binding.js +75 -0
- package/dist/subagents/adapted-role-binding.js.map +1 -0
- package/dist/subagents/role-routing-marker.d.ts +10 -0
- package/dist/subagents/role-routing-marker.d.ts.map +1 -0
- package/dist/subagents/role-routing-marker.js +136 -0
- package/dist/subagents/role-routing-marker.js.map +1 -0
- package/dist/subagents/tracker.d.ts +172 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +1077 -61
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +231 -1
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +401 -1
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +181 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +434 -4
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/api-interop.d.ts +2 -2
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +5 -5
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/goal-workflow.js.map +1 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/model-contract.d.ts +20 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +267 -30
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/pane-status.js.map +1 -1
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/reminder-intents.d.ts +1 -1
- package/dist/team/reminder-intents.d.ts.map +1 -1
- package/dist/team/reminder-intents.js.map +1 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +83 -52
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +9 -7
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +69 -28
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.js.map +1 -1
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/events.js.map +1 -1
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-identity.d.ts.map +1 -1
- package/dist/team/team-identity.js.map +1 -1
- package/dist/team/tmux-session.d.ts +2 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +90 -42
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/package.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/repo-deps.js.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/verification/verifier.js.map +1 -1
- package/dist/visual/constants.d.ts +1 -1
- package/dist/visual/constants.d.ts.map +1 -1
- package/dist/vscode/__tests__/index.test.js.map +1 -1
- package/dist/vscode/index.js.map +1 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +2 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +4 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -2
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +4 -2
- package/skills/ralplan/SKILL.md +5 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +17522 -10630
- package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
- package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +215 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +193 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +991 -4
- package/src/scripts/codex-native-hook.ts +779 -159
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +132 -40
- package/src/scripts/notify-hook/auto-nudge.ts +43 -12
- package/src/scripts/notify-hook/managed-tmux.ts +149 -12
- package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
- package/src/scripts/notify-hook/state-io.ts +100 -13
- package/src/scripts/notify-hook/tmux-injection.ts +38 -21
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +335 -90
- package/src/scripts/smoke-packed-install.ts +1829 -6
|
@@ -6,6 +6,9 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { buildTmuxSessionName } from '../../cli/index.js';
|
|
9
|
+
import { classifyKeywordInput, recordSkillActivation } from '../keyword-detector.js';
|
|
10
|
+
import { recordNotifySkillActivation, recordNotifySkillActivationNonFatal } from '../../scripts/notify-hook.js';
|
|
11
|
+
import { normalizeSkillActiveState } from '../../scripts/notify-hook/auto-nudge.js';
|
|
9
12
|
const NOTIFY_HOOK_SCRIPT = new URL('../../../dist/scripts/notify-hook.js', import.meta.url);
|
|
10
13
|
const DEEP_INTERVIEW_BLOCKED_APPROVAL_INPUTS = ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should'];
|
|
11
14
|
const NEXT_I_SHOULD_RESPONSE = 'Next I should update the focused tests.';
|
|
@@ -18,6 +21,17 @@ const INHERITED_OMX_ENV_KEYS = [
|
|
|
18
21
|
'OMX_STARTUP_CWD',
|
|
19
22
|
'OMX_ENTRY_PATH',
|
|
20
23
|
];
|
|
24
|
+
describe('notify lifecycle owner normalization', () => {
|
|
25
|
+
it('preserves the stored Codex owner for lifecycle authorization checks', () => {
|
|
26
|
+
const state = normalizeSkillActiveState({
|
|
27
|
+
skill: 'ralph',
|
|
28
|
+
active: true,
|
|
29
|
+
phase: 'executing',
|
|
30
|
+
owner_codex_session_id: 'codex-owner-a',
|
|
31
|
+
});
|
|
32
|
+
assert.equal(state?.owner_codex_session_id, 'codex-owner-a');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
21
35
|
async function withTempWorkingDir(run) {
|
|
22
36
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-auto-nudge-'));
|
|
23
37
|
try {
|
|
@@ -2048,6 +2062,656 @@ exit 0
|
|
|
2048
2062
|
assert.equal(autopilotState.turn_id, 'turn-later-autopilot-start');
|
|
2049
2063
|
});
|
|
2050
2064
|
});
|
|
2065
|
+
it('shares immutable classification across the terminal replay activation matrix', async () => {
|
|
2066
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2067
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2068
|
+
const sessionId = 'sess-notify-replay-matrix';
|
|
2069
|
+
const sessionStateDir = join(stateDir, 'sessions', sessionId);
|
|
2070
|
+
const terminalThreadId = 'thread-autopilot-complete';
|
|
2071
|
+
const terminalTurnId = 'turn-autopilot-complete';
|
|
2072
|
+
const terminalPayload = {
|
|
2073
|
+
type: 'agent-turn-complete',
|
|
2074
|
+
'thread-id': terminalThreadId,
|
|
2075
|
+
'turn-id': terminalTurnId,
|
|
2076
|
+
'last-assistant-message': 'Autopilot complete.',
|
|
2077
|
+
};
|
|
2078
|
+
await mkdir(sessionStateDir, { recursive: true });
|
|
2079
|
+
await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
|
|
2080
|
+
mode: 'autopilot',
|
|
2081
|
+
active: false,
|
|
2082
|
+
current_phase: 'complete',
|
|
2083
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2084
|
+
session_id: sessionId,
|
|
2085
|
+
thread_id: terminalThreadId,
|
|
2086
|
+
turn_id: terminalTurnId,
|
|
2087
|
+
});
|
|
2088
|
+
const terminalAutopilotStatePath = join(sessionStateDir, 'autopilot-state.json');
|
|
2089
|
+
const terminalSessionSkillStatePath = join(sessionStateDir, 'skill-active-state.json');
|
|
2090
|
+
const terminalRootSkillStatePath = join(stateDir, 'skill-active-state.json');
|
|
2091
|
+
for (const text of ['$autopilot replay task café\r\n', 'autopilot mode — replay café']) {
|
|
2092
|
+
const bytesBefore = Buffer.from(text, 'utf8');
|
|
2093
|
+
const terminalStateBefore = await readFile(terminalAutopilotStatePath);
|
|
2094
|
+
let classifierCalls = 0;
|
|
2095
|
+
let classifierText = '';
|
|
2096
|
+
let writerCalls = 0;
|
|
2097
|
+
const result = await recordNotifySkillActivation({
|
|
2098
|
+
stateDir,
|
|
2099
|
+
sourceCwd: cwd,
|
|
2100
|
+
text,
|
|
2101
|
+
sessionId,
|
|
2102
|
+
threadId: terminalThreadId,
|
|
2103
|
+
turnId: terminalTurnId,
|
|
2104
|
+
payload: terminalPayload,
|
|
2105
|
+
}, {
|
|
2106
|
+
classifyKeywordInput: (input) => {
|
|
2107
|
+
classifierCalls += 1;
|
|
2108
|
+
classifierText = input;
|
|
2109
|
+
return classifyKeywordInput(input);
|
|
2110
|
+
},
|
|
2111
|
+
recordSkillActivation: async () => {
|
|
2112
|
+
writerCalls += 1;
|
|
2113
|
+
return null;
|
|
2114
|
+
},
|
|
2115
|
+
});
|
|
2116
|
+
assert.equal(classifierCalls, 1, 'notify should classify each latest input once');
|
|
2117
|
+
assert.equal(writerCalls, 0, 'same-turn terminal replay must not reach the writer');
|
|
2118
|
+
assert.equal(result, null);
|
|
2119
|
+
assert.deepEqual(Buffer.from(classifierText, 'utf8'), bytesBefore, 'classifier must receive the original input bytes');
|
|
2120
|
+
assert.deepEqual(await readFile(terminalAutopilotStatePath), terminalStateBefore, 'same-turn replay must preserve terminal detail bytes');
|
|
2121
|
+
assert.equal(existsSync(terminalSessionSkillStatePath), false, 'same-turn replay must not create session canonical state');
|
|
2122
|
+
assert.equal(existsSync(terminalRootSkillStatePath), false, 'same-turn replay must not create root canonical state');
|
|
2123
|
+
}
|
|
2124
|
+
const markedSessionId = 'sess-notify-terminal-marked-answer';
|
|
2125
|
+
const markedThreadId = 'thread-notify-terminal-marked-answer';
|
|
2126
|
+
const markedTurnId = 'turn-notify-terminal-marked-answer';
|
|
2127
|
+
const markedSessionDir = join(stateDir, 'sessions', markedSessionId);
|
|
2128
|
+
const markedSkillPath = join(markedSessionDir, 'skill-active-state.json');
|
|
2129
|
+
const markedDetailPath = join(markedSessionDir, 'autopilot-state.json');
|
|
2130
|
+
await mkdir(markedSessionDir, { recursive: true });
|
|
2131
|
+
await writeJson(markedSkillPath, {
|
|
2132
|
+
version: 1,
|
|
2133
|
+
active: true,
|
|
2134
|
+
skill: 'autopilot',
|
|
2135
|
+
keyword: '$autopilot',
|
|
2136
|
+
phase: 'completing',
|
|
2137
|
+
activated_at: '2026-05-31T20:24:39.005Z',
|
|
2138
|
+
updated_at: '2026-05-31T20:24:39.005Z',
|
|
2139
|
+
session_id: markedSessionId,
|
|
2140
|
+
active_skills: [{ skill: 'autopilot', phase: 'completing', active: true, session_id: markedSessionId }],
|
|
2141
|
+
});
|
|
2142
|
+
await writeJson(markedDetailPath, {
|
|
2143
|
+
mode: 'autopilot',
|
|
2144
|
+
active: false,
|
|
2145
|
+
current_phase: 'complete',
|
|
2146
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2147
|
+
session_id: markedSessionId,
|
|
2148
|
+
});
|
|
2149
|
+
const markedSkillBefore = await readFile(markedSkillPath);
|
|
2150
|
+
const markedDetailBefore = await readFile(markedDetailPath);
|
|
2151
|
+
let markedWriterCalls = 0;
|
|
2152
|
+
const markedResult = await recordNotifySkillActivation({
|
|
2153
|
+
stateDir,
|
|
2154
|
+
sourceCwd: cwd,
|
|
2155
|
+
text: '[omx question answered] yes',
|
|
2156
|
+
sessionId: markedSessionId,
|
|
2157
|
+
threadId: markedThreadId,
|
|
2158
|
+
turnId: markedTurnId,
|
|
2159
|
+
payload: {
|
|
2160
|
+
type: 'agent-turn-complete',
|
|
2161
|
+
'thread-id': markedThreadId,
|
|
2162
|
+
'turn-id': markedTurnId,
|
|
2163
|
+
'last-assistant-message': 'Autopilot complete.',
|
|
2164
|
+
},
|
|
2165
|
+
}, {
|
|
2166
|
+
recordSkillActivation: async (input) => {
|
|
2167
|
+
markedWriterCalls += 1;
|
|
2168
|
+
return recordSkillActivation(input);
|
|
2169
|
+
},
|
|
2170
|
+
});
|
|
2171
|
+
assert.equal(markedWriterCalls, 1);
|
|
2172
|
+
assert.equal(markedResult, null);
|
|
2173
|
+
assert.deepEqual(await readFile(markedSkillPath), markedSkillBefore);
|
|
2174
|
+
assert.deepEqual(await readFile(markedDetailPath), markedDetailBefore);
|
|
2175
|
+
for (const orderedCase of [
|
|
2176
|
+
{ text: '$ralplan $autopilot plan this change', skill: 'ralplan' },
|
|
2177
|
+
{ text: '$ralph $autopilot ship this change', skill: 'ralph' },
|
|
2178
|
+
]) {
|
|
2179
|
+
const orderedSessionId = `sess-notify-primary-${orderedCase.skill}`;
|
|
2180
|
+
const orderedThreadId = `thread-notify-primary-${orderedCase.skill}`;
|
|
2181
|
+
const orderedTurnId = `turn-notify-primary-${orderedCase.skill}`;
|
|
2182
|
+
const orderedSessionDir = join(stateDir, 'sessions', orderedSessionId);
|
|
2183
|
+
await mkdir(orderedSessionDir, { recursive: true });
|
|
2184
|
+
await writeJson(join(orderedSessionDir, 'autopilot-state.json'), {
|
|
2185
|
+
mode: 'autopilot',
|
|
2186
|
+
active: false,
|
|
2187
|
+
current_phase: 'complete',
|
|
2188
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2189
|
+
session_id: orderedSessionId,
|
|
2190
|
+
thread_id: orderedThreadId,
|
|
2191
|
+
turn_id: orderedTurnId,
|
|
2192
|
+
});
|
|
2193
|
+
const orderedAutopilotPath = join(orderedSessionDir, 'autopilot-state.json');
|
|
2194
|
+
const orderedAutopilotBefore = await readFile(orderedAutopilotPath);
|
|
2195
|
+
await writeJson(join(orderedSessionDir, 'skill-active-state.json'), {
|
|
2196
|
+
version: 1,
|
|
2197
|
+
active: true,
|
|
2198
|
+
skill: 'autopilot',
|
|
2199
|
+
keyword: '$autopilot',
|
|
2200
|
+
phase: 'completing',
|
|
2201
|
+
activated_at: '2026-05-31T20:24:39.005Z',
|
|
2202
|
+
updated_at: '2026-05-31T20:24:39.005Z',
|
|
2203
|
+
session_id: orderedSessionId,
|
|
2204
|
+
thread_id: orderedThreadId,
|
|
2205
|
+
turn_id: orderedTurnId,
|
|
2206
|
+
active_skills: [{
|
|
2207
|
+
skill: 'autopilot',
|
|
2208
|
+
phase: 'completing',
|
|
2209
|
+
active: true,
|
|
2210
|
+
session_id: orderedSessionId,
|
|
2211
|
+
thread_id: orderedThreadId,
|
|
2212
|
+
turn_id: orderedTurnId,
|
|
2213
|
+
}],
|
|
2214
|
+
});
|
|
2215
|
+
let orderedWriterCalls = 0;
|
|
2216
|
+
const orderedResult = await recordNotifySkillActivation({
|
|
2217
|
+
stateDir,
|
|
2218
|
+
sourceCwd: cwd,
|
|
2219
|
+
text: orderedCase.text,
|
|
2220
|
+
sessionId: orderedSessionId,
|
|
2221
|
+
threadId: orderedThreadId,
|
|
2222
|
+
turnId: orderedTurnId,
|
|
2223
|
+
payload: {
|
|
2224
|
+
type: 'agent-turn-complete',
|
|
2225
|
+
'thread-id': orderedThreadId,
|
|
2226
|
+
'turn-id': orderedTurnId,
|
|
2227
|
+
'last-assistant-message': 'Autopilot complete.',
|
|
2228
|
+
},
|
|
2229
|
+
}, {
|
|
2230
|
+
recordSkillActivation: async (input) => {
|
|
2231
|
+
orderedWriterCalls += 1;
|
|
2232
|
+
return recordSkillActivation(input);
|
|
2233
|
+
},
|
|
2234
|
+
});
|
|
2235
|
+
assert.equal(orderedWriterCalls, 1, `leading ${orderedCase.skill} must reach the writer`);
|
|
2236
|
+
assert.equal(orderedResult?.skill, orderedCase.skill, orderedCase.text);
|
|
2237
|
+
assert.equal(orderedResult?.active, true, orderedCase.text);
|
|
2238
|
+
assert.equal(existsSync(join(orderedSessionDir, 'skill-active-state.json')), true, orderedCase.text);
|
|
2239
|
+
assert.equal(orderedResult?.active_skills?.some((entry) => entry.skill === 'autopilot'), false, orderedCase.text);
|
|
2240
|
+
assert.deepEqual(await readFile(orderedAutopilotPath), orderedAutopilotBefore, orderedCase.text);
|
|
2241
|
+
}
|
|
2242
|
+
const filteredSessionId = 'sess-notify-disabled-team-terminal-autopilot';
|
|
2243
|
+
const filteredThreadId = 'thread-notify-disabled-team-terminal-autopilot';
|
|
2244
|
+
const filteredTurnId = 'turn-notify-disabled-team-terminal-autopilot';
|
|
2245
|
+
const filteredSessionDir = join(stateDir, 'sessions', filteredSessionId);
|
|
2246
|
+
const filteredAutopilotPath = join(filteredSessionDir, 'autopilot-state.json');
|
|
2247
|
+
await mkdir(filteredSessionDir, { recursive: true });
|
|
2248
|
+
await writeJson(filteredAutopilotPath, {
|
|
2249
|
+
mode: 'autopilot',
|
|
2250
|
+
active: false,
|
|
2251
|
+
current_phase: 'complete',
|
|
2252
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2253
|
+
session_id: filteredSessionId,
|
|
2254
|
+
thread_id: filteredThreadId,
|
|
2255
|
+
turn_id: filteredTurnId,
|
|
2256
|
+
});
|
|
2257
|
+
const filteredAutopilotBefore = await readFile(filteredAutopilotPath);
|
|
2258
|
+
const previousTeamMode = process.env.OMX_TEAM_MODE;
|
|
2259
|
+
process.env.OMX_TEAM_MODE = 'disabled';
|
|
2260
|
+
try {
|
|
2261
|
+
const filteredResult = await recordNotifySkillActivation({
|
|
2262
|
+
stateDir,
|
|
2263
|
+
sourceCwd: cwd,
|
|
2264
|
+
text: '$team $autopilot retry',
|
|
2265
|
+
sessionId: filteredSessionId,
|
|
2266
|
+
threadId: filteredThreadId,
|
|
2267
|
+
turnId: filteredTurnId,
|
|
2268
|
+
payload: {
|
|
2269
|
+
type: 'agent-turn-complete',
|
|
2270
|
+
'thread-id': filteredThreadId,
|
|
2271
|
+
'turn-id': filteredTurnId,
|
|
2272
|
+
'last-assistant-message': 'Autopilot complete.',
|
|
2273
|
+
},
|
|
2274
|
+
});
|
|
2275
|
+
assert.equal(filteredResult, null);
|
|
2276
|
+
assert.deepEqual(await readFile(filteredAutopilotPath), filteredAutopilotBefore);
|
|
2277
|
+
assert.equal(existsSync(join(filteredSessionDir, 'skill-active-state.json')), false);
|
|
2278
|
+
assert.equal(existsSync(join(stateDir, 'skill-active-state.json')), false);
|
|
2279
|
+
}
|
|
2280
|
+
finally {
|
|
2281
|
+
if (previousTeamMode === undefined)
|
|
2282
|
+
delete process.env.OMX_TEAM_MODE;
|
|
2283
|
+
else
|
|
2284
|
+
process.env.OMX_TEAM_MODE = previousTeamMode;
|
|
2285
|
+
}
|
|
2286
|
+
const restartText = '$autopilot new task — café';
|
|
2287
|
+
const restartBytes = Buffer.from(restartText, 'utf8');
|
|
2288
|
+
let restartClassification;
|
|
2289
|
+
let writerClassification;
|
|
2290
|
+
let writerResult;
|
|
2291
|
+
let writerCalls = 0;
|
|
2292
|
+
let writerText = '';
|
|
2293
|
+
const restartResult = await recordNotifySkillActivation({
|
|
2294
|
+
stateDir,
|
|
2295
|
+
sourceCwd: cwd,
|
|
2296
|
+
text: restartText,
|
|
2297
|
+
sessionId,
|
|
2298
|
+
threadId: terminalThreadId,
|
|
2299
|
+
turnId: 'turn-autopilot-restart',
|
|
2300
|
+
payload: {
|
|
2301
|
+
...terminalPayload,
|
|
2302
|
+
'turn-id': 'turn-autopilot-restart',
|
|
2303
|
+
'last-assistant-message': 'Autopilot complete text from a prior turn.',
|
|
2304
|
+
},
|
|
2305
|
+
}, {
|
|
2306
|
+
classifyKeywordInput: (input) => {
|
|
2307
|
+
restartClassification = classifyKeywordInput(input);
|
|
2308
|
+
return restartClassification;
|
|
2309
|
+
},
|
|
2310
|
+
recordSkillActivation: async (input) => {
|
|
2311
|
+
writerCalls += 1;
|
|
2312
|
+
writerText = input.text;
|
|
2313
|
+
writerClassification = input.classification;
|
|
2314
|
+
writerResult = await recordSkillActivation(input);
|
|
2315
|
+
return writerResult;
|
|
2316
|
+
},
|
|
2317
|
+
});
|
|
2318
|
+
assert.equal(writerCalls, 1, 'a different turn must reach the writer');
|
|
2319
|
+
assert.strictEqual(writerClassification, restartClassification, 'writer must receive the classifier object by identity');
|
|
2320
|
+
assert.strictEqual(restartResult, writerResult, 'notify must return the writer result unchanged');
|
|
2321
|
+
assert.deepEqual(Buffer.from(writerText, 'utf8'), restartBytes, 'writer must receive the original input bytes');
|
|
2322
|
+
const reactivatedAutopilot = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
|
|
2323
|
+
assert.equal(reactivatedAutopilot.active, true);
|
|
2324
|
+
assert.equal(reactivatedAutopilot.current_phase, 'deep-interview');
|
|
2325
|
+
assert.equal(reactivatedAutopilot.turn_id, 'turn-autopilot-restart');
|
|
2326
|
+
const sessionSkillStatePath = join(sessionStateDir, 'skill-active-state.json');
|
|
2327
|
+
const autopilotStatePath = join(sessionStateDir, 'autopilot-state.json');
|
|
2328
|
+
const rootSkillStatePath = join(stateDir, 'skill-active-state.json');
|
|
2329
|
+
for (const [index, text] of ['do not start $autopilot — café', '"$autopilot" — quoted only'].entries()) {
|
|
2330
|
+
const bytesBefore = Buffer.from(text, 'utf8');
|
|
2331
|
+
const skillStateBefore = await readFile(sessionSkillStatePath);
|
|
2332
|
+
const autopilotStateBefore = await readFile(autopilotStatePath);
|
|
2333
|
+
let rejectedClassification;
|
|
2334
|
+
let rejectedWriterClassification;
|
|
2335
|
+
let rejectedWriterResult;
|
|
2336
|
+
let rejectedWriterCalls = 0;
|
|
2337
|
+
let rejectedWriterText = '';
|
|
2338
|
+
const rejectedResult = await recordNotifySkillActivation({
|
|
2339
|
+
stateDir,
|
|
2340
|
+
sourceCwd: cwd,
|
|
2341
|
+
text,
|
|
2342
|
+
sessionId,
|
|
2343
|
+
threadId: terminalThreadId,
|
|
2344
|
+
turnId: `turn-rejected-${index}`,
|
|
2345
|
+
payload: {
|
|
2346
|
+
type: 'agent-turn-complete',
|
|
2347
|
+
'thread-id': terminalThreadId,
|
|
2348
|
+
'turn-id': `turn-rejected-${index}`,
|
|
2349
|
+
'last-assistant-message': 'Normal nonterminal reply.',
|
|
2350
|
+
},
|
|
2351
|
+
}, {
|
|
2352
|
+
classifyKeywordInput: (input) => {
|
|
2353
|
+
rejectedClassification = classifyKeywordInput(input);
|
|
2354
|
+
return rejectedClassification;
|
|
2355
|
+
},
|
|
2356
|
+
recordSkillActivation: async (input) => {
|
|
2357
|
+
rejectedWriterCalls += 1;
|
|
2358
|
+
rejectedWriterText = input.text;
|
|
2359
|
+
rejectedWriterClassification = input.classification;
|
|
2360
|
+
rejectedWriterResult = await recordSkillActivation(input);
|
|
2361
|
+
return rejectedWriterResult;
|
|
2362
|
+
},
|
|
2363
|
+
});
|
|
2364
|
+
assert.equal(rejectedWriterCalls, 1, 'rejected nonterminal text must still reach the real writer once');
|
|
2365
|
+
assert.strictEqual(rejectedResult, rejectedWriterResult, 'notify must return the real writer result unchanged');
|
|
2366
|
+
assert.equal(rejectedResult, null);
|
|
2367
|
+
assert.strictEqual(rejectedWriterClassification, rejectedClassification, 'rejected input must retain classification identity');
|
|
2368
|
+
assert.deepEqual(rejectedClassification?.matches, [], 'negated and quoted text must not activate a workflow');
|
|
2369
|
+
assert.deepEqual(Buffer.from(rejectedWriterText, 'utf8'), bytesBefore, 'writer must receive rejected input bytes unchanged');
|
|
2370
|
+
assert.deepEqual(await readFile(sessionSkillStatePath), skillStateBefore, 'rejected input must preserve canonical state bytes');
|
|
2371
|
+
assert.deepEqual(await readFile(autopilotStatePath), autopilotStateBefore, 'rejected input must preserve detail state bytes');
|
|
2372
|
+
assert.equal(existsSync(rootSkillStatePath), false, 'rejected session input must not create root canonical state');
|
|
2373
|
+
}
|
|
2374
|
+
});
|
|
2375
|
+
});
|
|
2376
|
+
it('G1a-N preserves ordered multi-skill classification and seeds only the ralplan primary when Team is enabled', async () => {
|
|
2377
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2378
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2379
|
+
const sessionId = 'sess-g1a-notify-ordered';
|
|
2380
|
+
const threadId = 'thread-g1a-notify-ordered';
|
|
2381
|
+
const turnId = 'turn-g1a-notify-ordered';
|
|
2382
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
2383
|
+
const text = '$ralplan, $autopilot; $team';
|
|
2384
|
+
let classification;
|
|
2385
|
+
let writerClassification;
|
|
2386
|
+
let writerCalls = 0;
|
|
2387
|
+
const previousTeamMode = process.env.OMX_TEAM_MODE;
|
|
2388
|
+
process.env.OMX_TEAM_MODE = 'enabled';
|
|
2389
|
+
try {
|
|
2390
|
+
const result = await recordNotifySkillActivation({
|
|
2391
|
+
stateDir,
|
|
2392
|
+
sourceCwd: cwd,
|
|
2393
|
+
text,
|
|
2394
|
+
sessionId,
|
|
2395
|
+
threadId,
|
|
2396
|
+
turnId,
|
|
2397
|
+
payload: { type: 'agent-turn-complete', 'thread-id': threadId, 'turn-id': turnId },
|
|
2398
|
+
}, {
|
|
2399
|
+
classifyKeywordInput: (input) => {
|
|
2400
|
+
classification = classifyKeywordInput(input);
|
|
2401
|
+
return classification;
|
|
2402
|
+
},
|
|
2403
|
+
recordSkillActivation: async (input) => {
|
|
2404
|
+
writerCalls += 1;
|
|
2405
|
+
writerClassification = input.classification;
|
|
2406
|
+
return recordSkillActivation(input);
|
|
2407
|
+
},
|
|
2408
|
+
});
|
|
2409
|
+
assert.equal(writerCalls, 1);
|
|
2410
|
+
assert.strictEqual(writerClassification, classification, 'notify must pass the ordered classifier output to the writer');
|
|
2411
|
+
assert.deepEqual(classification?.matches.map((match) => match.skill), ['ralplan', 'autopilot', 'team']);
|
|
2412
|
+
assert.equal(result?.skill, 'ralplan');
|
|
2413
|
+
assert.deepEqual(result?.deferred_skills, ['autopilot', 'team']);
|
|
2414
|
+
assert.deepEqual(result?.active_skills?.map((entry) => entry.skill), ['ralplan']);
|
|
2415
|
+
assert.equal(existsSync(join(sessionDir, 'ralplan-state.json')), true);
|
|
2416
|
+
assert.equal(existsSync(join(sessionDir, 'autopilot-state.json')), false);
|
|
2417
|
+
assert.equal(existsSync(join(stateDir, 'team-state.json')), false);
|
|
2418
|
+
}
|
|
2419
|
+
finally {
|
|
2420
|
+
if (previousTeamMode === undefined)
|
|
2421
|
+
delete process.env.OMX_TEAM_MODE;
|
|
2422
|
+
else
|
|
2423
|
+
process.env.OMX_TEAM_MODE = previousTeamMode;
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
});
|
|
2427
|
+
it('G1c-N deduplicates exact canonical and alias Autopilot invocations across classifier, writer, canonical state, and detail state', async () => {
|
|
2428
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2429
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2430
|
+
const sessionId = 'sess-g1c-notify-duplicate';
|
|
2431
|
+
const threadId = 'thread-g1c-notify-duplicate';
|
|
2432
|
+
const turnId = 'turn-g1c-notify-duplicate';
|
|
2433
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
2434
|
+
const text = '$autopilot $oh-my-codex:autopilot build it';
|
|
2435
|
+
let classification;
|
|
2436
|
+
let writerClassification;
|
|
2437
|
+
let writerCalls = 0;
|
|
2438
|
+
const result = await recordNotifySkillActivation({
|
|
2439
|
+
stateDir,
|
|
2440
|
+
sourceCwd: cwd,
|
|
2441
|
+
text,
|
|
2442
|
+
sessionId,
|
|
2443
|
+
threadId,
|
|
2444
|
+
turnId,
|
|
2445
|
+
payload: { type: 'agent-turn-complete', 'thread-id': threadId, 'turn-id': turnId },
|
|
2446
|
+
}, {
|
|
2447
|
+
classifyKeywordInput: (input) => {
|
|
2448
|
+
classification = classifyKeywordInput(input);
|
|
2449
|
+
return classification;
|
|
2450
|
+
},
|
|
2451
|
+
recordSkillActivation: async (input) => {
|
|
2452
|
+
writerCalls += 1;
|
|
2453
|
+
writerClassification = input.classification;
|
|
2454
|
+
return recordSkillActivation(input);
|
|
2455
|
+
},
|
|
2456
|
+
});
|
|
2457
|
+
assert.equal(writerCalls, 1);
|
|
2458
|
+
assert.strictEqual(writerClassification, classification, 'writer must receive the deduplicated classifier output');
|
|
2459
|
+
assert.deepEqual(classification?.matches.map((match) => match.skill), ['autopilot']);
|
|
2460
|
+
assert.equal(result?.skill, 'autopilot');
|
|
2461
|
+
assert.deepEqual(result?.deferred_skills ?? [], []);
|
|
2462
|
+
assert.deepEqual(result?.active_skills?.map((entry) => entry.skill), ['autopilot']);
|
|
2463
|
+
const canonical = JSON.parse(await readFile(join(sessionDir, 'skill-active-state.json'), 'utf8'));
|
|
2464
|
+
assert.deepEqual(canonical.active_skills?.map((entry) => entry.skill), ['autopilot']);
|
|
2465
|
+
assert.equal(existsSync(join(sessionDir, 'autopilot-state.json')), true);
|
|
2466
|
+
});
|
|
2467
|
+
});
|
|
2468
|
+
// Notify Stop is N/A: it has no user-prompt activation transport to replay.
|
|
2469
|
+
it('G1b-N filters disabled Team before suppressing an exact same-turn terminal Autopilot replay without changing state bytes', async () => {
|
|
2470
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2471
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2472
|
+
const sessionId = 'sess-g1b-notify-terminal';
|
|
2473
|
+
const threadId = 'thread-g1b-notify-terminal';
|
|
2474
|
+
const turnId = 'turn-g1b-notify-terminal';
|
|
2475
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
2476
|
+
const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
|
|
2477
|
+
const sessionAutopilotPath = join(sessionDir, 'autopilot-state.json');
|
|
2478
|
+
const rootSkillPath = join(stateDir, 'skill-active-state.json');
|
|
2479
|
+
const rootAutopilotPath = join(stateDir, 'autopilot-state.json');
|
|
2480
|
+
const seededPaths = [sessionSkillPath, sessionAutopilotPath, rootSkillPath, rootAutopilotPath];
|
|
2481
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2482
|
+
await writeJson(sessionSkillPath, {
|
|
2483
|
+
version: 1,
|
|
2484
|
+
active: true,
|
|
2485
|
+
skill: 'autopilot',
|
|
2486
|
+
keyword: '$autopilot',
|
|
2487
|
+
phase: 'completing',
|
|
2488
|
+
session_id: sessionId,
|
|
2489
|
+
thread_id: threadId,
|
|
2490
|
+
turn_id: turnId,
|
|
2491
|
+
active_skills: [{ skill: 'autopilot', phase: 'completing', active: true, session_id: sessionId, thread_id: threadId, turn_id: turnId }],
|
|
2492
|
+
});
|
|
2493
|
+
await writeJson(sessionAutopilotPath, {
|
|
2494
|
+
mode: 'autopilot',
|
|
2495
|
+
active: false,
|
|
2496
|
+
current_phase: 'complete',
|
|
2497
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2498
|
+
session_id: sessionId,
|
|
2499
|
+
thread_id: threadId,
|
|
2500
|
+
turn_id: turnId,
|
|
2501
|
+
});
|
|
2502
|
+
await writeJson(rootSkillPath, {
|
|
2503
|
+
version: 1,
|
|
2504
|
+
active: true,
|
|
2505
|
+
skill: 'autopilot',
|
|
2506
|
+
keyword: '$autopilot',
|
|
2507
|
+
phase: 'completing',
|
|
2508
|
+
scope: 'root-copy',
|
|
2509
|
+
session_id: sessionId,
|
|
2510
|
+
thread_id: threadId,
|
|
2511
|
+
turn_id: turnId,
|
|
2512
|
+
});
|
|
2513
|
+
await writeJson(rootAutopilotPath, {
|
|
2514
|
+
mode: 'autopilot',
|
|
2515
|
+
active: false,
|
|
2516
|
+
current_phase: 'complete',
|
|
2517
|
+
completed_at: '2026-05-31T20:24:39.005Z',
|
|
2518
|
+
scope: 'root-copy',
|
|
2519
|
+
session_id: sessionId,
|
|
2520
|
+
thread_id: threadId,
|
|
2521
|
+
turn_id: turnId,
|
|
2522
|
+
});
|
|
2523
|
+
const bytesBefore = new Map(await Promise.all(seededPaths.map(async (path) => [path, await readFile(path)])));
|
|
2524
|
+
const previousTeamMode = process.env.OMX_TEAM_MODE;
|
|
2525
|
+
process.env.OMX_TEAM_MODE = 'disabled';
|
|
2526
|
+
try {
|
|
2527
|
+
let classification;
|
|
2528
|
+
let writerCalls = 0;
|
|
2529
|
+
const result = await recordNotifySkillActivation({
|
|
2530
|
+
stateDir,
|
|
2531
|
+
sourceCwd: cwd,
|
|
2532
|
+
text: '$team $autopilot retry',
|
|
2533
|
+
sessionId,
|
|
2534
|
+
threadId,
|
|
2535
|
+
turnId,
|
|
2536
|
+
payload: {
|
|
2537
|
+
type: 'agent-turn-complete',
|
|
2538
|
+
'thread-id': threadId,
|
|
2539
|
+
'turn-id': turnId,
|
|
2540
|
+
'last-assistant-message': 'Autopilot complete.',
|
|
2541
|
+
},
|
|
2542
|
+
}, {
|
|
2543
|
+
classifyKeywordInput: (text) => {
|
|
2544
|
+
classification = classifyKeywordInput(text);
|
|
2545
|
+
return classification;
|
|
2546
|
+
},
|
|
2547
|
+
recordSkillActivation: async () => {
|
|
2548
|
+
writerCalls += 1;
|
|
2549
|
+
return null;
|
|
2550
|
+
},
|
|
2551
|
+
});
|
|
2552
|
+
assert.deepEqual(classification?.matches.map((match) => match.skill), ['team', 'autopilot'], 'the source classification must retain Team before runtime filtering');
|
|
2553
|
+
assert.equal(writerCalls, 0, 'disabled Team filtering must expose the same-turn terminal Autopilot replay for suppression');
|
|
2554
|
+
assert.equal(result, null);
|
|
2555
|
+
for (const path of seededPaths) {
|
|
2556
|
+
assert.deepEqual(await readFile(path), bytesBefore.get(path), `same-turn notify replay must preserve ${path} byte-for-byte`);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
finally {
|
|
2560
|
+
if (previousTeamMode === undefined)
|
|
2561
|
+
delete process.env.OMX_TEAM_MODE;
|
|
2562
|
+
else
|
|
2563
|
+
process.env.OMX_TEAM_MODE = previousTeamMode;
|
|
2564
|
+
}
|
|
2565
|
+
});
|
|
2566
|
+
});
|
|
2567
|
+
it('G2a sends the exact stale predecessor prompt through the shared classification and writer boundary without state', async () => {
|
|
2568
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2569
|
+
const stateDir = join(cwd, 'isolated-g2a-state-root');
|
|
2570
|
+
const sessionId = 'sess-g2a-stale-predecessor';
|
|
2571
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
2572
|
+
const rootSkillPath = join(stateDir, 'skill-active-state.json');
|
|
2573
|
+
const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
|
|
2574
|
+
const rootRalplanPath = join(stateDir, 'ralplan-state.json');
|
|
2575
|
+
const sessionRalplanPath = join(sessionDir, 'ralplan-state.json');
|
|
2576
|
+
const text = 'use $ralplan is the consensus-planning command';
|
|
2577
|
+
const textBytes = Buffer.from(text, 'utf8');
|
|
2578
|
+
let classification;
|
|
2579
|
+
let writerClassification;
|
|
2580
|
+
let writerText = '';
|
|
2581
|
+
let writerCalls = 0;
|
|
2582
|
+
const result = await recordNotifySkillActivation({
|
|
2583
|
+
stateDir,
|
|
2584
|
+
sourceCwd: cwd,
|
|
2585
|
+
text,
|
|
2586
|
+
sessionId,
|
|
2587
|
+
threadId: 'thread-g2a-stale-predecessor',
|
|
2588
|
+
turnId: 'turn-g2a-stale-predecessor',
|
|
2589
|
+
payload: { type: 'agent-turn-complete' },
|
|
2590
|
+
}, {
|
|
2591
|
+
classifyKeywordInput: (input) => {
|
|
2592
|
+
classification = classifyKeywordInput(input);
|
|
2593
|
+
return classification;
|
|
2594
|
+
},
|
|
2595
|
+
recordSkillActivation: async (input) => {
|
|
2596
|
+
writerCalls += 1;
|
|
2597
|
+
writerText = input.text;
|
|
2598
|
+
writerClassification = input.classification;
|
|
2599
|
+
return recordSkillActivation(input);
|
|
2600
|
+
},
|
|
2601
|
+
});
|
|
2602
|
+
assert.equal(writerCalls, 1, 'notify must invoke the shared writer boundary once');
|
|
2603
|
+
assert.strictEqual(writerClassification, classification, 'notify must pass the original classification object to the writer');
|
|
2604
|
+
assert.deepEqual(Buffer.from(writerText, 'utf8'), textBytes, 'notify must pass the stale predecessor bytes unchanged');
|
|
2605
|
+
assert.deepEqual(classification?.matches, [], 'the stale predecessor wording must not activate ralplan');
|
|
2606
|
+
assert.equal(result, null);
|
|
2607
|
+
assert.equal(existsSync(stateDir), false, 'the stale predecessor wording must not create isolated state');
|
|
2608
|
+
assert.equal(existsSync(rootSkillPath), false, 'the stale predecessor wording must not create root canonical state');
|
|
2609
|
+
assert.equal(existsSync(sessionSkillPath), false, 'the stale predecessor wording must not create session canonical state');
|
|
2610
|
+
assert.equal(existsSync(rootRalplanPath), false, 'the stale predecessor wording must not create root ralplan detail state');
|
|
2611
|
+
assert.equal(existsSync(sessionRalplanPath), false, 'the stale predecessor wording must not create session ralplan detail state');
|
|
2612
|
+
});
|
|
2613
|
+
});
|
|
2614
|
+
it('G2b-N preserves five distinct terminal state files for the exact negated notify prompt without a fabricated Stop signal', async () => {
|
|
2615
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2616
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2617
|
+
const sessionId = 'sess-g2b-negated-terminal';
|
|
2618
|
+
const threadId = 'thread-g2b-negated-terminal';
|
|
2619
|
+
const turnId = 'turn-g2b-negated-terminal';
|
|
2620
|
+
const sessionDir = join(stateDir, 'sessions', sessionId);
|
|
2621
|
+
const sessionJsonPath = join(stateDir, 'session.json');
|
|
2622
|
+
const rootSkillPath = join(stateDir, 'skill-active-state.json');
|
|
2623
|
+
const rootAutopilotPath = join(stateDir, 'autopilot-state.json');
|
|
2624
|
+
const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
|
|
2625
|
+
const sessionAutopilotPath = join(sessionDir, 'autopilot-state.json');
|
|
2626
|
+
const seededPaths = [sessionJsonPath, rootSkillPath, rootAutopilotPath, sessionSkillPath, sessionAutopilotPath];
|
|
2627
|
+
const terminalBytes = [
|
|
2628
|
+
Buffer.from(`{\n "session_id": "${sessionId}",\n "started_at": "2026-06-01T00:00:01.001Z",\n "turn_id": "turn-g2b-session-pointer"\n}\n`),
|
|
2629
|
+
Buffer.from(`{\n "version": 1,\n "active": true,\n "skill": "autopilot",\n "phase": "completing",\n "updated_at": "2026-06-01T00:00:02.002Z",\n "turn_id": "turn-g2b-root-skill"\n}\n`),
|
|
2630
|
+
Buffer.from(`{\n "mode": "autopilot",\n "active": false,\n "current_phase": "complete",\n "completed_at": "2026-06-01T00:00:03.003Z",\n "turn_id": "turn-g2b-root-detail"\n}\n`),
|
|
2631
|
+
Buffer.from(`{\n "version": 1,\n "active": true,\n "skill": "autopilot",\n "phase": "completing",\n "updated_at": "2026-06-01T00:00:04.004Z",\n "turn_id": "turn-g2b-session-skill"\n}\n`),
|
|
2632
|
+
Buffer.from(`{\n "mode": "autopilot",\n "active": false,\n "current_phase": "complete",\n "completed_at": "2026-06-01T00:00:05.005Z",\n "turn_id": "turn-g2b-session-detail"\n}\n`),
|
|
2633
|
+
];
|
|
2634
|
+
await mkdir(sessionDir, { recursive: true });
|
|
2635
|
+
await Promise.all(seededPaths.map((path, index) => writeFile(path, terminalBytes[index])));
|
|
2636
|
+
const text = 'do not start $autopilot — café';
|
|
2637
|
+
const textBytes = Buffer.from(text, 'utf8');
|
|
2638
|
+
let classification;
|
|
2639
|
+
let writerClassification;
|
|
2640
|
+
let writerText = '';
|
|
2641
|
+
let writerCalls = 0;
|
|
2642
|
+
const result = await recordNotifySkillActivation({
|
|
2643
|
+
stateDir,
|
|
2644
|
+
sourceCwd: cwd,
|
|
2645
|
+
text,
|
|
2646
|
+
sessionId,
|
|
2647
|
+
threadId,
|
|
2648
|
+
turnId,
|
|
2649
|
+
payload: {
|
|
2650
|
+
type: 'agent-turn-complete',
|
|
2651
|
+
'thread-id': threadId,
|
|
2652
|
+
'turn-id': turnId,
|
|
2653
|
+
},
|
|
2654
|
+
}, {
|
|
2655
|
+
classifyKeywordInput: (input) => {
|
|
2656
|
+
classification = classifyKeywordInput(input);
|
|
2657
|
+
return classification;
|
|
2658
|
+
},
|
|
2659
|
+
recordSkillActivation: async (input) => {
|
|
2660
|
+
writerCalls += 1;
|
|
2661
|
+
writerText = input.text;
|
|
2662
|
+
writerClassification = input.classification;
|
|
2663
|
+
return recordSkillActivation(input);
|
|
2664
|
+
},
|
|
2665
|
+
});
|
|
2666
|
+
assert.equal(writerCalls, 1, 'the negated notify input must reach the shared writer boundary once');
|
|
2667
|
+
assert.strictEqual(writerClassification, classification, 'notify must retain classification identity for negated input');
|
|
2668
|
+
assert.deepEqual(Buffer.from(writerText, 'utf8'), textBytes, 'notify must retain the exact negated input bytes');
|
|
2669
|
+
assert.deepEqual(classification?.matches, [], 'the exact negated input must not restart Autopilot');
|
|
2670
|
+
assert.equal(result, null);
|
|
2671
|
+
for (const [index, path] of seededPaths.entries()) {
|
|
2672
|
+
assert.deepEqual(await readFile(path), terminalBytes[index], `negated notify input must preserve ${path} byte-for-byte`);
|
|
2673
|
+
}
|
|
2674
|
+
});
|
|
2675
|
+
});
|
|
2676
|
+
it('logs injected skill activation writer failures without failing the notify hook boundary', async () => {
|
|
2677
|
+
await withTempWorkingDir(async (cwd) => {
|
|
2678
|
+
const stateDir = join(cwd, '.omx', 'state');
|
|
2679
|
+
const logsDir = join(cwd, '.omx', 'logs');
|
|
2680
|
+
const sessionId = 'sess-notify-writer-failure';
|
|
2681
|
+
const threadId = 'thread-notify-writer-failure';
|
|
2682
|
+
const turnId = 'turn-notify-writer-failure';
|
|
2683
|
+
let writerCalls = 0;
|
|
2684
|
+
await mkdir(logsDir, { recursive: true });
|
|
2685
|
+
const result = await recordNotifySkillActivationNonFatal({
|
|
2686
|
+
stateDir,
|
|
2687
|
+
sourceCwd: cwd,
|
|
2688
|
+
text: '$ralplan plan this change',
|
|
2689
|
+
sessionId,
|
|
2690
|
+
threadId,
|
|
2691
|
+
turnId,
|
|
2692
|
+
payload: { type: 'agent-turn-complete' },
|
|
2693
|
+
}, logsDir, {
|
|
2694
|
+
recordSkillActivation: async () => {
|
|
2695
|
+
writerCalls += 1;
|
|
2696
|
+
throw new Error(`injected writer failure ${'x'.repeat(1_000)}`);
|
|
2697
|
+
},
|
|
2698
|
+
});
|
|
2699
|
+
assert.equal(result, null);
|
|
2700
|
+
assert.equal(writerCalls, 1);
|
|
2701
|
+
const logPath = join(logsDir, `notify-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
|
|
2702
|
+
const events = (await readFile(logPath, 'utf8')).trim().split('\n')
|
|
2703
|
+
.map((line) => JSON.parse(line));
|
|
2704
|
+
const failure = events.find((event) => event.type === 'notify_skill_activation_failure');
|
|
2705
|
+
assert.ok(failure);
|
|
2706
|
+
assert.equal(failure.level, 'warn');
|
|
2707
|
+
assert.equal(failure.session_id, sessionId);
|
|
2708
|
+
assert.equal(failure.thread_id, threadId);
|
|
2709
|
+
assert.equal(failure.turn_id, turnId);
|
|
2710
|
+
assert.match(String(failure.error), /^injected writer failure /);
|
|
2711
|
+
assert.ok(String(failure.error).length <= 512);
|
|
2712
|
+
assert.equal(Number.isNaN(Date.parse(String(failure.timestamp))), false);
|
|
2713
|
+
});
|
|
2714
|
+
});
|
|
2051
2715
|
it('writes skill-active-state.json when keyword activation is detected', async () => {
|
|
2052
2716
|
await withTempWorkingDir(async (cwd) => {
|
|
2053
2717
|
const omxDir = join(cwd, '.omx');
|
|
@@ -2067,7 +2731,7 @@ exit 0
|
|
|
2067
2731
|
await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
|
|
2068
2732
|
await chmod(join(fakeBinDir, 'tmux'), 0o755);
|
|
2069
2733
|
const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
|
|
2070
|
-
'input-messages': ['
|
|
2734
|
+
'input-messages': ['$autopilot handle this task'],
|
|
2071
2735
|
'last-assistant-message': 'Here is the plan I will follow.',
|
|
2072
2736
|
});
|
|
2073
2737
|
assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
|
|
@@ -2439,12 +3103,14 @@ exit 0
|
|
|
2439
3103
|
phase: 'executing',
|
|
2440
3104
|
source: 'keyword-detector',
|
|
2441
3105
|
session_id: 'sess-managed',
|
|
3106
|
+
owner_codex_session_id: 'sess-managed',
|
|
2442
3107
|
});
|
|
2443
3108
|
await writeJson(join(sessionStateDir, 'autoresearch-state.json'), {
|
|
2444
3109
|
active: true,
|
|
2445
3110
|
mode: 'autoresearch',
|
|
2446
3111
|
current_phase: 'executing',
|
|
2447
3112
|
session_id: 'sess-managed',
|
|
3113
|
+
owner_codex_session_id: 'sess-managed',
|
|
2448
3114
|
validation_mode: 'mission-validator-script',
|
|
2449
3115
|
mission_validator_command: 'node scripts/validate.js',
|
|
2450
3116
|
completion_artifact_path: '.omx/specs/autoresearch-demo/completion.json',
|
|
@@ -2488,12 +3154,14 @@ exit 0
|
|
|
2488
3154
|
phase: 'reviewing',
|
|
2489
3155
|
source: 'keyword-detector',
|
|
2490
3156
|
session_id: 'sess-managed',
|
|
3157
|
+
owner_codex_session_id: 'sess-managed',
|
|
2491
3158
|
});
|
|
2492
3159
|
await writeJson(join(sessionStateDir, 'autoresearch-state.json'), {
|
|
2493
3160
|
active: true,
|
|
2494
3161
|
mode: 'autoresearch',
|
|
2495
3162
|
current_phase: 'reviewing',
|
|
2496
3163
|
session_id: 'sess-managed',
|
|
3164
|
+
owner_codex_session_id: 'sess-managed',
|
|
2497
3165
|
validation_mode: 'mission-validator-script',
|
|
2498
3166
|
mission_validator_command: 'node scripts/validate.js',
|
|
2499
3167
|
completion_artifact_path: '.omx/specs/autoresearch-demo/completion.json',
|