oh-my-codex 0.11.13 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +5 -5
- package/Cargo.toml +1 -1
- package/README.md +27 -17
- package/crates/omx-runtime/src/main.rs +6 -2
- package/dist/agents/native-config.js +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +74 -2
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.js +22 -30
- package/dist/cli/__tests__/cleanup.test.js.map +1 -1
- package/dist/cli/__tests__/error-handling-warnings.test.js +3 -1
- package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +217 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +49 -9
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +9 -0
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +136 -11
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +10 -0
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -0
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +2 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch.d.ts.map +1 -1
- package/dist/cli/autoresearch.js +2 -1
- package/dist/cli/autoresearch.js.map +1 -1
- package/dist/cli/cleanup.d.ts.map +1 -1
- package/dist/cli/cleanup.js +4 -2
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +238 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/omx.js +2 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +41 -7
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +16 -557
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +34 -9
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +79 -2
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +2 -0
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +11 -0
- package/dist/config/codex-hooks.d.ts.map +1 -0
- package/dist/config/codex-hooks.js +50 -0
- package/dist/config/codex-hooks.js.map +1 -0
- package/dist/config/generator.d.ts +5 -3
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +24 -14
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +20 -0
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +236 -2
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +86 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +40 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +54 -0
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-modules.test.js +31 -0
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +51 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +136 -0
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +120 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +145 -20
- 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 +116 -0
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +86 -0
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js +1 -0
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/runtime.test.js +49 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -1
- package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
- package/dist/hooks/extensibility/runtime.js +10 -0
- package/dist/hooks/extensibility/runtime.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +1 -1
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +12 -8
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/session.d.ts +5 -1
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +10 -6
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +6 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +0 -3
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +27 -1
- package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +0 -5
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +1 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +0 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +20 -0
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js +6 -5
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/notifications/__tests__/idle-cooldown.test.js +24 -1
- package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js +20 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/tmux.test.js +41 -0
- package/dist/notifications/__tests__/tmux.test.js.map +1 -1
- package/dist/notifications/idle-cooldown.d.ts +13 -0
- package/dist/notifications/idle-cooldown.d.ts.map +1 -1
- package/dist/notifications/idle-cooldown.js +50 -16
- package/dist/notifications/idle-cooldown.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js +2 -0
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/tmux.d.ts.map +1 -1
- package/dist/notifications/tmux.js +4 -0
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.d.ts +2 -0
- package/dist/scripts/__tests__/codex-native-hook.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +720 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +22 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -0
- package/dist/scripts/codex-native-hook.js +594 -0
- package/dist/scripts/codex-native-hook.js.map +1 -0
- package/dist/scripts/codex-native-pre-post.d.ts +26 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -0
- package/dist/scripts/codex-native-pre-post.js +118 -0
- package/dist/scripts/codex-native-pre-post.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +262 -18
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +5 -6
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/log.d.ts +2 -2
- package/dist/scripts/notify-hook/log.d.ts.map +1 -1
- package/dist/scripts/notify-hook/log.js +10 -2
- package/dist/scripts/notify-hook/log.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +2 -0
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +18 -0
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -0
- package/dist/scripts/notify-hook/orchestration-intent.js +72 -0
- package/dist/scripts/notify-hook/orchestration-intent.js.map +1 -0
- package/dist/scripts/notify-hook/process-runner.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +7 -0
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +15 -6
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +125 -6
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +3 -2
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +165 -37
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +33 -44
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +68 -5
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/utils.d.ts +1 -1
- package/dist/scripts/notify-hook/utils.d.ts.map +1 -1
- package/dist/scripts/notify-hook/utils.js.map +1 -1
- package/dist/scripts/notify-hook.js +55 -32
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +344 -18
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts +2 -0
- package/dist/team/__tests__/delivery-e2e-smoke.test.d.ts.map +1 -0
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +671 -0
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -0
- package/dist/team/__tests__/mcp-comm.test.js +5 -0
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +422 -12
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +126 -8
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +4 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +160 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +19 -1
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +95 -23
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/contracts.d.ts +11 -1
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/contracts.js +29 -0
- package/dist/team/contracts.js.map +1 -1
- package/dist/team/delivery-log.d.ts +14 -0
- package/dist/team/delivery-log.d.ts.map +1 -0
- package/dist/team/delivery-log.js +35 -0
- package/dist/team/delivery-log.js.map +1 -0
- package/dist/team/idle-nudge.d.ts +2 -2
- package/dist/team/idle-nudge.js +2 -2
- package/dist/team/mcp-comm.d.ts +4 -0
- package/dist/team/mcp-comm.d.ts.map +1 -1
- package/dist/team/mcp-comm.js +84 -1
- package/dist/team/mcp-comm.js.map +1 -1
- package/dist/team/pane-status.d.ts +149 -0
- package/dist/team/pane-status.d.ts.map +1 -0
- package/dist/team/pane-status.js +558 -0
- package/dist/team/pane-status.js.map +1 -0
- package/dist/team/reminder-intents.d.ts +11 -0
- package/dist/team/reminder-intents.d.ts.map +1 -0
- package/dist/team/reminder-intents.js +40 -0
- package/dist/team/reminder-intents.js.map +1 -0
- package/dist/team/runtime-cli.d.ts +1 -1
- package/dist/team/runtime-cli.js +2 -2
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts +2 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +407 -190
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +6 -5
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch.d.ts +4 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +59 -18
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/mailbox.d.ts.map +1 -1
- package/dist/team/state/mailbox.js +39 -2
- package/dist/team/state/mailbox.js.map +1 -1
- package/dist/team/state/monitor.d.ts +2 -1
- package/dist/team/state/monitor.d.ts.map +1 -1
- package/dist/team/state/monitor.js +30 -1
- package/dist/team/state/monitor.js.map +1 -1
- package/dist/team/state/types.d.ts +5 -2
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state.d.ts +30 -3
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +170 -2
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-ops.d.ts +5 -1
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +4 -0
- package/dist/team/team-ops.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 +19 -3
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +4 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +33 -6
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +63 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/__tests__/platform-command.test.js +50 -4
- package/dist/utils/__tests__/platform-command.test.js.map +1 -1
- package/dist/utils/paths.d.ts +12 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +44 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.d.ts.map +1 -1
- package/dist/utils/platform-command.js +13 -5
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js +10 -1
- package/dist/utils/sleep.js.map +1 -1
- package/package.json +1 -1
- package/prompts/analyst.md +2 -2
- package/prompts/api-reviewer.md +2 -2
- package/prompts/architect.md +2 -2
- package/prompts/build-fixer.md +2 -2
- package/prompts/code-reviewer.md +2 -2
- package/prompts/code-simplifier.md +1 -1
- package/prompts/critic.md +2 -2
- package/prompts/debugger.md +3 -2
- package/prompts/dependency-expert.md +2 -2
- package/prompts/designer.md +2 -2
- package/prompts/executor.md +3 -2
- package/prompts/explore.md +2 -2
- package/prompts/git-master.md +2 -2
- package/prompts/information-architect.md +2 -2
- package/prompts/performance-reviewer.md +2 -2
- package/prompts/planner.md +3 -2
- package/prompts/product-analyst.md +2 -2
- package/prompts/product-manager.md +2 -2
- package/prompts/qa-tester.md +2 -2
- package/prompts/quality-reviewer.md +2 -2
- package/prompts/quality-strategist.md +2 -2
- package/prompts/researcher.md +2 -2
- package/prompts/security-reviewer.md +2 -2
- package/prompts/sisyphus-lite.md +2 -2
- package/prompts/style-reviewer.md +2 -2
- package/prompts/team-executor.md +2 -2
- package/prompts/test-engineer.md +2 -2
- package/prompts/ux-researcher.md +2 -2
- package/prompts/verifier.md +3 -2
- package/prompts/vision.md +2 -2
- package/prompts/writer.md +2 -2
- package/skills/team/SKILL.md +18 -33
- package/src/scripts/__tests__/codex-native-hook.test.ts +931 -0
- package/src/scripts/codex-native-hook.ts +721 -0
- package/src/scripts/codex-native-pre-post.ts +161 -0
- package/src/scripts/notify-fallback-watcher.ts +318 -26
- package/src/scripts/notify-hook/auto-nudge.ts +5 -10
- package/src/scripts/notify-hook/log.ts +18 -4
- package/src/scripts/notify-hook/managed-tmux.ts +1 -0
- package/src/scripts/notify-hook/orchestration-intent.ts +82 -0
- package/src/scripts/notify-hook/process-runner.ts +4 -4
- package/src/scripts/notify-hook/ralph-session-resume.ts +9 -0
- package/src/scripts/notify-hook/team-dispatch.ts +134 -6
- package/src/scripts/notify-hook/team-leader-nudge.ts +183 -37
- package/src/scripts/notify-hook/team-tmux-guard.ts +35 -43
- package/src/scripts/notify-hook/team-worker.ts +73 -4
- package/src/scripts/notify-hook/utils.ts +1 -1
- package/src/scripts/notify-hook.ts +64 -32
- package/templates/AGENTS.md +21 -11
- package/README.de.md +0 -263
- package/README.el.md +0 -223
- package/README.es.md +0 -263
- package/README.fr.md +0 -263
- package/README.it.md +0 -263
- package/README.ja.md +0 -264
- package/README.ko.md +0 -264
- package/README.pl.md +0 -216
- package/README.pt.md +0 -263
- package/README.ru.md +0 -263
- package/README.tr.md +0 -263
- package/README.vi.md +0 -223
- package/README.zh-TW.md +0 -293
- package/README.zh.md +0 -264
- package/dist/mcp/__tests__/team-server-cleanup.test.d.ts +0 -2
- package/dist/mcp/__tests__/team-server-cleanup.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/team-server-cleanup.test.js +0 -219
- package/dist/mcp/__tests__/team-server-cleanup.test.js.map +0 -1
- package/dist/mcp/__tests__/team-server-runtime-deps.test.d.ts +0 -2
- package/dist/mcp/__tests__/team-server-runtime-deps.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/team-server-runtime-deps.test.js +0 -13
- package/dist/mcp/__tests__/team-server-runtime-deps.test.js.map +0 -1
- package/dist/mcp/__tests__/team-server-wait.test.d.ts +0 -2
- package/dist/mcp/__tests__/team-server-wait.test.d.ts.map +0 -1
- package/dist/mcp/__tests__/team-server-wait.test.js +0 -155
- package/dist/mcp/__tests__/team-server-wait.test.js.map +0 -1
- package/dist/mcp/team-server.d.ts +0 -24
- package/dist/mcp/team-server.d.ts.map +0 -1
- package/dist/mcp/team-server.js +0 -482
- package/dist/mcp/team-server.js.map +0 -1
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
import { DEFAULT_MARKER } from './tmux-hook-engine.js';
|
|
26
26
|
import { isTerminalPhase } from './notify-hook/utils.js';
|
|
27
27
|
import { isSessionStale, readSessionState } from '../hooks/session.js';
|
|
28
|
+
import {
|
|
29
|
+
DEFAULT_SUBAGENT_ACTIVE_WINDOW_MS,
|
|
30
|
+
readSubagentSessionSummary,
|
|
31
|
+
} from '../subagents/tracker.js';
|
|
28
32
|
|
|
29
33
|
function argValue(name: string, fallback = ''): string {
|
|
30
34
|
const idx = process.argv.indexOf(name);
|
|
@@ -82,6 +86,10 @@ const authorityOnly = process.argv.includes('--authority-only');
|
|
|
82
86
|
// ack budget so leaderless team dispatch + stale-alert recovery do not feel
|
|
83
87
|
// laggy between native notify-hook turns.
|
|
84
88
|
const pollMs = Math.max(50, asNumber(argValue('--poll-ms', '250'), 250));
|
|
89
|
+
const idleMaxPollMs = Math.max(
|
|
90
|
+
pollMs,
|
|
91
|
+
asNumber(argValue('--idle-max-poll-ms', process.env.OMX_NOTIFY_FALLBACK_IDLE_MAX_POLL_MS || '1000'), 1000),
|
|
92
|
+
);
|
|
85
93
|
const parentPid = Math.trunc(asNumber(argValue('--parent-pid', String(process.ppid || 0)), process.ppid || 0));
|
|
86
94
|
const startedAt = Date.now();
|
|
87
95
|
const fileWindowMs = runOnce ? 15000 : 30000;
|
|
@@ -131,6 +139,8 @@ interface RalphContinueSteerState {
|
|
|
131
139
|
pane_id: string;
|
|
132
140
|
pane_current_command: string;
|
|
133
141
|
current_phase: string;
|
|
142
|
+
subagent_session_id: string;
|
|
143
|
+
active_subagent_thread_ids: string[];
|
|
134
144
|
shared_timestamp_path: string;
|
|
135
145
|
shared_last_sent_at: string;
|
|
136
146
|
singleton_lock_path: string;
|
|
@@ -174,6 +184,15 @@ interface ParentGuardState {
|
|
|
174
184
|
pane_count?: number;
|
|
175
185
|
}
|
|
176
186
|
|
|
187
|
+
interface AuthorityBackoffState {
|
|
188
|
+
active: boolean;
|
|
189
|
+
reason: string;
|
|
190
|
+
primary_pid: number | null;
|
|
191
|
+
primary_last_tick_at: string;
|
|
192
|
+
freshness_ms: number | null;
|
|
193
|
+
threshold_ms: number | null;
|
|
194
|
+
}
|
|
195
|
+
|
|
177
196
|
interface ActiveTeamResult {
|
|
178
197
|
active: boolean;
|
|
179
198
|
reason: string;
|
|
@@ -196,6 +215,22 @@ interface FallbackAutoNudgeState {
|
|
|
196
215
|
last_nudged_at: string;
|
|
197
216
|
}
|
|
198
217
|
|
|
218
|
+
interface AdaptivePollState {
|
|
219
|
+
enabled: boolean;
|
|
220
|
+
base_ms: number;
|
|
221
|
+
max_ms: number;
|
|
222
|
+
current_ms: number;
|
|
223
|
+
idle_streak: number;
|
|
224
|
+
last_tick_at: string | null;
|
|
225
|
+
last_activity_at: string | null;
|
|
226
|
+
last_activity_reason: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface CycleActivitySummary {
|
|
230
|
+
active: boolean;
|
|
231
|
+
reason: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
199
234
|
const fileState = new Map<string, WatcherFileMeta>();
|
|
200
235
|
const seenTurnKeys = new Set<string>();
|
|
201
236
|
let stopping = false;
|
|
@@ -231,6 +266,8 @@ let lastRalphContinueSteer: RalphContinueSteerState = {
|
|
|
231
266
|
pane_id: '',
|
|
232
267
|
pane_current_command: '',
|
|
233
268
|
current_phase: '',
|
|
269
|
+
subagent_session_id: '',
|
|
270
|
+
active_subagent_thread_ids: [],
|
|
234
271
|
shared_timestamp_path: ralphSteerTimestampPath,
|
|
235
272
|
shared_last_sent_at: '',
|
|
236
273
|
singleton_lock_path: ralphSteerLockPath,
|
|
@@ -240,6 +277,14 @@ let lastParentGuard: ParentGuardState = {
|
|
|
240
277
|
state_path: '',
|
|
241
278
|
current_phase: '',
|
|
242
279
|
};
|
|
280
|
+
let lastAuthorityBackoff: AuthorityBackoffState = {
|
|
281
|
+
active: false,
|
|
282
|
+
reason: '',
|
|
283
|
+
primary_pid: null,
|
|
284
|
+
primary_last_tick_at: '',
|
|
285
|
+
freshness_ms: null,
|
|
286
|
+
threshold_ms: null,
|
|
287
|
+
};
|
|
243
288
|
const AUTO_NUDGE_STALL_MS = Math.max(
|
|
244
289
|
pollMs,
|
|
245
290
|
asNumber(process.env.OMX_NOTIFY_FALLBACK_AUTO_NUDGE_STALL_MS || '5000', 5000),
|
|
@@ -256,6 +301,16 @@ let lastFallbackAutoNudge: FallbackAutoNudgeState = {
|
|
|
256
301
|
last_nudged_signature: '',
|
|
257
302
|
last_nudged_at: '',
|
|
258
303
|
};
|
|
304
|
+
let adaptivePollState: AdaptivePollState = {
|
|
305
|
+
enabled: true,
|
|
306
|
+
base_ms: pollMs,
|
|
307
|
+
max_ms: idleMaxPollMs,
|
|
308
|
+
current_ms: pollMs,
|
|
309
|
+
idle_streak: 0,
|
|
310
|
+
last_tick_at: null,
|
|
311
|
+
last_activity_at: null,
|
|
312
|
+
last_activity_reason: 'init',
|
|
313
|
+
};
|
|
259
314
|
function eventLog(event: Record<string, unknown>): Promise<void> {
|
|
260
315
|
return appendFile(logPath, `${JSON.stringify({ timestamp: new Date().toISOString(), ...event })}\n`).catch(() => {});
|
|
261
316
|
}
|
|
@@ -264,6 +319,41 @@ function shouldLogLeaderNudgeTick(reason: string): boolean {
|
|
|
264
319
|
return reason === 'leader_nudge_checked' || reason === 'leader_nudge_failed';
|
|
265
320
|
}
|
|
266
321
|
|
|
322
|
+
function nextIdlePollMs(currentMs: number): number {
|
|
323
|
+
return Math.min(idleMaxPollMs, Math.max(pollMs, currentMs * 2));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function updateAdaptivePollState(summary: CycleActivitySummary): number {
|
|
327
|
+
const nowIso = new Date().toISOString();
|
|
328
|
+
if (summary.active) {
|
|
329
|
+
adaptivePollState = {
|
|
330
|
+
...adaptivePollState,
|
|
331
|
+
enabled: true,
|
|
332
|
+
base_ms: pollMs,
|
|
333
|
+
max_ms: idleMaxPollMs,
|
|
334
|
+
current_ms: pollMs,
|
|
335
|
+
idle_streak: 0,
|
|
336
|
+
last_tick_at: nowIso,
|
|
337
|
+
last_activity_at: nowIso,
|
|
338
|
+
last_activity_reason: summary.reason,
|
|
339
|
+
};
|
|
340
|
+
return adaptivePollState.current_ms;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const nextMs = nextIdlePollMs(adaptivePollState.current_ms);
|
|
344
|
+
adaptivePollState = {
|
|
345
|
+
...adaptivePollState,
|
|
346
|
+
enabled: true,
|
|
347
|
+
base_ms: pollMs,
|
|
348
|
+
max_ms: idleMaxPollMs,
|
|
349
|
+
current_ms: nextMs,
|
|
350
|
+
idle_streak: adaptivePollState.idle_streak + 1,
|
|
351
|
+
last_tick_at: nowIso,
|
|
352
|
+
last_activity_reason: summary.reason,
|
|
353
|
+
};
|
|
354
|
+
return adaptivePollState.current_ms;
|
|
355
|
+
}
|
|
356
|
+
|
|
267
357
|
function shouldLogDispatchDrainTick(result: unknown): boolean {
|
|
268
358
|
if (!result || typeof result !== 'object') return false;
|
|
269
359
|
const record = result as Record<string, unknown>;
|
|
@@ -291,6 +381,10 @@ function normalizeRalphContinueSteerState(raw: Record<string, unknown> | null |
|
|
|
291
381
|
pane_id: safeString(raw.pane_id),
|
|
292
382
|
pane_current_command: safeString(raw.pane_current_command),
|
|
293
383
|
current_phase: safeString(raw.current_phase),
|
|
384
|
+
subagent_session_id: safeString(raw.subagent_session_id),
|
|
385
|
+
active_subagent_thread_ids: Array.isArray(raw.active_subagent_thread_ids)
|
|
386
|
+
? raw.active_subagent_thread_ids.map((value) => safeString(value).trim()).filter(Boolean)
|
|
387
|
+
: [],
|
|
294
388
|
shared_timestamp_path: safeString(raw.shared_timestamp_path) || ralphSteerTimestampPath,
|
|
295
389
|
shared_last_sent_at: safeString(raw.shared_last_sent_at),
|
|
296
390
|
singleton_lock_path: safeString(raw.singleton_lock_path) || ralphSteerLockPath,
|
|
@@ -328,6 +422,19 @@ async function loadPersistedWatcherState(): Promise<void> {
|
|
|
328
422
|
last_nudged_at: safeString(persistedAutoNudge.last_nudged_at),
|
|
329
423
|
};
|
|
330
424
|
}
|
|
425
|
+
const persistedAdaptivePoll = persisted?.adaptive_poll as Record<string, unknown> | null | undefined;
|
|
426
|
+
if (persistedAdaptivePoll && typeof persistedAdaptivePoll === 'object') {
|
|
427
|
+
adaptivePollState = {
|
|
428
|
+
enabled: persistedAdaptivePoll.enabled !== false,
|
|
429
|
+
base_ms: pollMs,
|
|
430
|
+
max_ms: idleMaxPollMs,
|
|
431
|
+
current_ms: Math.min(idleMaxPollMs, Math.max(pollMs, asNumber(persistedAdaptivePoll.current_ms as string | number | undefined, pollMs))),
|
|
432
|
+
idle_streak: Math.max(0, Math.trunc(asNumber(persistedAdaptivePoll.idle_streak as string | number | undefined, 0))),
|
|
433
|
+
last_tick_at: safeString(persistedAdaptivePoll.last_tick_at) || null,
|
|
434
|
+
last_activity_at: safeString(persistedAdaptivePoll.last_activity_at) || null,
|
|
435
|
+
last_activity_reason: safeString(persistedAdaptivePoll.last_activity_reason) || 'init',
|
|
436
|
+
};
|
|
437
|
+
}
|
|
331
438
|
}
|
|
332
439
|
|
|
333
440
|
interface ActiveModeResult {
|
|
@@ -534,7 +641,8 @@ async function withRalphSteerLock<T>(task: () => Promise<T>): Promise<T | null>
|
|
|
534
641
|
if (code !== 'EEXIST') throw error;
|
|
535
642
|
const existing = await readRalphSteerLock(ralphSteerLockPath);
|
|
536
643
|
const lockAgeMs = parseIsoMillis(existing?.acquired_at) ?? 0;
|
|
537
|
-
const stale =
|
|
644
|
+
const stale = existing !== null
|
|
645
|
+
&& (!isPidAlive(existing.pid) || (lockAgeMs > 0 && Date.now() - lockAgeMs > RALPH_STEER_LOCK_STALE_MS));
|
|
538
646
|
if (stale) {
|
|
539
647
|
await unlink(ralphSteerLockPath).catch(() => {});
|
|
540
648
|
continue;
|
|
@@ -560,29 +668,51 @@ interface RalphProgressGateResult {
|
|
|
560
668
|
allow: boolean;
|
|
561
669
|
reason: string;
|
|
562
670
|
progress_at: string;
|
|
563
|
-
|
|
671
|
+
subagent_session_id?: string;
|
|
672
|
+
active_subagent_thread_ids?: string[];
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async function readRalphProgressGate(
|
|
676
|
+
activeRalphState: Record<string, unknown> | null,
|
|
677
|
+
now: number,
|
|
678
|
+
): Promise<RalphProgressGateResult> {
|
|
679
|
+
const subagentSessionId = safeString(activeRalphState?.owner_codex_session_id).trim();
|
|
680
|
+
if (subagentSessionId) {
|
|
681
|
+
const summary = await readSubagentSessionSummary(cwd, subagentSessionId, {
|
|
682
|
+
now: new Date(now),
|
|
683
|
+
activeWindowMs: DEFAULT_SUBAGENT_ACTIVE_WINDOW_MS,
|
|
684
|
+
});
|
|
685
|
+
if ((summary?.activeSubagentThreadIds.length ?? 0) > 0) {
|
|
686
|
+
return {
|
|
687
|
+
allow: false,
|
|
688
|
+
reason: 'subagents_active',
|
|
689
|
+
progress_at: '',
|
|
690
|
+
subagent_session_id: subagentSessionId,
|
|
691
|
+
active_subagent_thread_ids: summary?.activeSubagentThreadIds ?? [],
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
}
|
|
564
695
|
|
|
565
|
-
async function readRalphProgressGate(now: number): Promise<RalphProgressGateResult> {
|
|
566
696
|
const hudState = await readJsonObject(join(stateDir, 'hud-state.json'));
|
|
567
697
|
if (!hudState || typeof hudState !== 'object') {
|
|
568
|
-
return { allow: false, reason: 'progress_missing', progress_at: '' };
|
|
698
|
+
return { allow: false, reason: 'progress_missing', progress_at: '', subagent_session_id: subagentSessionId };
|
|
569
699
|
}
|
|
570
700
|
|
|
571
701
|
const progressAt = safeString(hudState.last_progress_at).trim();
|
|
572
702
|
if (!progressAt) {
|
|
573
|
-
return { allow: false, reason: 'progress_missing', progress_at: '' };
|
|
703
|
+
return { allow: false, reason: 'progress_missing', progress_at: '', subagent_session_id: subagentSessionId };
|
|
574
704
|
}
|
|
575
705
|
|
|
576
706
|
const progressMs = parseIsoMillis(progressAt);
|
|
577
707
|
if (progressMs === null) {
|
|
578
|
-
return { allow: false, reason: 'progress_invalid', progress_at: progressAt };
|
|
708
|
+
return { allow: false, reason: 'progress_invalid', progress_at: progressAt, subagent_session_id: subagentSessionId };
|
|
579
709
|
}
|
|
580
710
|
|
|
581
711
|
if (now - progressMs < RALPH_CONTINUE_CADENCE_MS) {
|
|
582
|
-
return { allow: false, reason: 'progress_fresh', progress_at: progressAt };
|
|
712
|
+
return { allow: false, reason: 'progress_fresh', progress_at: progressAt, subagent_session_id: subagentSessionId };
|
|
583
713
|
}
|
|
584
714
|
|
|
585
|
-
return { allow: true, reason: 'progress_stale', progress_at: progressAt };
|
|
715
|
+
return { allow: true, reason: 'progress_stale', progress_at: progressAt, subagent_session_id: subagentSessionId };
|
|
586
716
|
}
|
|
587
717
|
|
|
588
718
|
function shouldSkipRalphContinue(now: number, candidateIso: string, startupIso: string): { skip: boolean; reason: string; anchorMs: number; anchorIso: string } {
|
|
@@ -625,6 +755,108 @@ async function readPidFileRecord(path: string): Promise<PidFileRecord | null> {
|
|
|
625
755
|
}
|
|
626
756
|
}
|
|
627
757
|
|
|
758
|
+
function createAuthorityBackoffState(
|
|
759
|
+
reason: string,
|
|
760
|
+
overrides: Partial<AuthorityBackoffState> = {},
|
|
761
|
+
): AuthorityBackoffState {
|
|
762
|
+
return {
|
|
763
|
+
active: false,
|
|
764
|
+
reason,
|
|
765
|
+
primary_pid: null,
|
|
766
|
+
primary_last_tick_at: '',
|
|
767
|
+
freshness_ms: null,
|
|
768
|
+
threshold_ms: null,
|
|
769
|
+
...overrides,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function latestWatcherTickIso(state: Record<string, unknown> | null): string {
|
|
774
|
+
if (!state || typeof state !== 'object') return '';
|
|
775
|
+
const candidates = [
|
|
776
|
+
safeString((state.dispatch_drain as Record<string, unknown> | undefined)?.last_tick_at),
|
|
777
|
+
safeString((state.leader_nudge as Record<string, unknown> | undefined)?.last_tick_at),
|
|
778
|
+
safeString((state.fallback_auto_nudge as Record<string, unknown> | undefined)?.last_tick_at),
|
|
779
|
+
safeString((state.ralph_continue_steer as Record<string, unknown> | undefined)?.last_state_check_at),
|
|
780
|
+
]
|
|
781
|
+
.map((value) => value.trim())
|
|
782
|
+
.filter(Boolean);
|
|
783
|
+
let latestIso = '';
|
|
784
|
+
let latestMs = -1;
|
|
785
|
+
for (const candidate of candidates) {
|
|
786
|
+
const parsed = parseIsoMillis(candidate);
|
|
787
|
+
if (parsed === null || parsed <= latestMs) continue;
|
|
788
|
+
latestMs = parsed;
|
|
789
|
+
latestIso = candidate;
|
|
790
|
+
}
|
|
791
|
+
return latestIso;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
async function resolveAuthorityPrimaryWatcherHealth(now = Date.now()): Promise<AuthorityBackoffState> {
|
|
795
|
+
if (!authorityOnly) return createAuthorityBackoffState('not_authority');
|
|
796
|
+
|
|
797
|
+
const existingRecord = await readPidFileRecord(pidFilePath).catch(() => null);
|
|
798
|
+
if (!existingRecord) return createAuthorityBackoffState('pid_missing');
|
|
799
|
+
if (existingRecord.cwd && resolve(existingRecord.cwd) !== cwd) return createAuthorityBackoffState('cwd_mismatch');
|
|
800
|
+
if (!isPidAlive(existingRecord.pid)) {
|
|
801
|
+
return createAuthorityBackoffState('pid_stale', {
|
|
802
|
+
primary_pid: existingRecord.pid,
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const persistedState = await readJsonObject(statePath);
|
|
807
|
+
if (!persistedState) {
|
|
808
|
+
return createAuthorityBackoffState('state_missing', {
|
|
809
|
+
primary_pid: existingRecord.pid,
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const persistedPid = Math.trunc(asNumber(persistedState.pid as string | number | undefined, 0));
|
|
814
|
+
if (persistedPid > 0 && persistedPid !== existingRecord.pid) {
|
|
815
|
+
return createAuthorityBackoffState('state_pid_mismatch', {
|
|
816
|
+
primary_pid: existingRecord.pid,
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const lastTickAt = latestWatcherTickIso(persistedState);
|
|
821
|
+
if (!lastTickAt) {
|
|
822
|
+
return createAuthorityBackoffState('tick_missing', {
|
|
823
|
+
primary_pid: existingRecord.pid,
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const lastTickMs = parseIsoMillis(lastTickAt);
|
|
828
|
+
const primaryPollMs = Math.max(50, asNumber(persistedState.poll_ms as string | number | undefined, 250));
|
|
829
|
+
const thresholdMs = Math.max(1_000, primaryPollMs * 4);
|
|
830
|
+
if (lastTickMs === null) {
|
|
831
|
+
return createAuthorityBackoffState('tick_invalid', {
|
|
832
|
+
primary_pid: existingRecord.pid,
|
|
833
|
+
primary_last_tick_at: lastTickAt,
|
|
834
|
+
threshold_ms: thresholdMs,
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const freshnessMs = now - lastTickMs;
|
|
839
|
+
if (freshnessMs > thresholdMs) {
|
|
840
|
+
return {
|
|
841
|
+
active: false,
|
|
842
|
+
reason: 'tick_stale',
|
|
843
|
+
primary_pid: existingRecord.pid,
|
|
844
|
+
primary_last_tick_at: lastTickAt,
|
|
845
|
+
freshness_ms: freshnessMs,
|
|
846
|
+
threshold_ms: thresholdMs,
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return {
|
|
851
|
+
active: true,
|
|
852
|
+
reason: 'primary_watcher_healthy',
|
|
853
|
+
primary_pid: existingRecord.pid,
|
|
854
|
+
primary_last_tick_at: lastTickAt,
|
|
855
|
+
freshness_ms: freshnessMs,
|
|
856
|
+
threshold_ms: thresholdMs,
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
628
860
|
async function writePidFileRecord(): Promise<void> {
|
|
629
861
|
const nextRecord: PidFileRecord = {
|
|
630
862
|
pid: process.pid,
|
|
@@ -653,6 +885,8 @@ async function runRalphContinueSteerTick(): Promise<void> {
|
|
|
653
885
|
state_path: activeRalph.path,
|
|
654
886
|
pane_id: activePaneId,
|
|
655
887
|
pane_current_command: '',
|
|
888
|
+
subagent_session_id: safeString(activeRalph.state?.owner_codex_session_id).trim(),
|
|
889
|
+
active_subagent_thread_ids: [],
|
|
656
890
|
shared_timestamp_path: ralphSteerTimestampPath,
|
|
657
891
|
singleton_lock_path: ralphSteerLockPath,
|
|
658
892
|
};
|
|
@@ -686,9 +920,11 @@ async function runRalphContinueSteerTick(): Promise<void> {
|
|
|
686
920
|
return { sent: false, skipped: true };
|
|
687
921
|
}
|
|
688
922
|
|
|
689
|
-
const progressGate = await readRalphProgressGate(Date.now());
|
|
923
|
+
const progressGate = await readRalphProgressGate(activeRalph.state, Date.now());
|
|
690
924
|
if (!progressGate.allow) {
|
|
691
925
|
lastRalphContinueSteer.last_reason = progressGate.reason;
|
|
926
|
+
lastRalphContinueSteer.subagent_session_id = progressGate.subagent_session_id ?? lastRalphContinueSteer.subagent_session_id;
|
|
927
|
+
lastRalphContinueSteer.active_subagent_thread_ids = progressGate.active_subagent_thread_ids ?? [];
|
|
692
928
|
return { sent: false, skipped: true };
|
|
693
929
|
}
|
|
694
930
|
|
|
@@ -811,6 +1047,8 @@ async function writeState(extra: Record<string, unknown> = {}): Promise<void> {
|
|
|
811
1047
|
notify_script: notifyScript,
|
|
812
1048
|
authority_only: authorityOnly,
|
|
813
1049
|
poll_ms: pollMs,
|
|
1050
|
+
effective_poll_ms: adaptivePollState.current_ms,
|
|
1051
|
+
idle_max_poll_ms: idleMaxPollMs,
|
|
814
1052
|
pid_file: runOnce ? null : pidFilePath,
|
|
815
1053
|
max_lifetime_ms: maxLifetimeMs,
|
|
816
1054
|
tracked_files: fileState.size,
|
|
@@ -837,11 +1075,27 @@ async function writeState(extra: Record<string, unknown> = {}): Promise<void> {
|
|
|
837
1075
|
enabled: true,
|
|
838
1076
|
stall_ms: AUTO_NUDGE_STALL_MS,
|
|
839
1077
|
},
|
|
1078
|
+
authority_backoff: lastAuthorityBackoff,
|
|
1079
|
+
adaptive_poll: {
|
|
1080
|
+
...adaptivePollState,
|
|
1081
|
+
enabled: true,
|
|
1082
|
+
base_ms: pollMs,
|
|
1083
|
+
max_ms: idleMaxPollMs,
|
|
1084
|
+
},
|
|
840
1085
|
...extra,
|
|
841
1086
|
};
|
|
842
1087
|
await writeFile(statePath, JSON.stringify(state, null, 2)).catch(() => {});
|
|
843
1088
|
}
|
|
844
1089
|
|
|
1090
|
+
async function writeAuthorityBackoffState(): Promise<void> {
|
|
1091
|
+
await mkdir(stateDir, { recursive: true }).catch(() => {});
|
|
1092
|
+
const existing = await readJsonObject(statePath);
|
|
1093
|
+
const state = existing && typeof existing === 'object'
|
|
1094
|
+
? { ...existing, authority_backoff: lastAuthorityBackoff }
|
|
1095
|
+
: { authority_backoff: lastAuthorityBackoff };
|
|
1096
|
+
await writeFile(statePath, JSON.stringify(state, null, 2)).catch(() => {});
|
|
1097
|
+
}
|
|
1098
|
+
|
|
845
1099
|
async function readJsonObject(path: string): Promise<Record<string, unknown> | null> {
|
|
846
1100
|
return readFile(path, 'utf-8')
|
|
847
1101
|
.then((content) => JSON.parse(content) as Record<string, unknown>)
|
|
@@ -1195,7 +1449,8 @@ function splitBufferedLines(partial: string, delta: string): { lines: string[];
|
|
|
1195
1449
|
};
|
|
1196
1450
|
}
|
|
1197
1451
|
|
|
1198
|
-
async function pollFiles(): Promise<
|
|
1452
|
+
async function pollFiles(): Promise<number> {
|
|
1453
|
+
let processedCount = 0;
|
|
1199
1454
|
for (const [path, meta] of fileState.entries()) {
|
|
1200
1455
|
const currentSize = (await stat(path).catch(() => ({ size: 0 }))).size || 0;
|
|
1201
1456
|
if (currentSize <= meta.offset) continue;
|
|
@@ -1209,11 +1464,13 @@ async function pollFiles(): Promise<void> {
|
|
|
1209
1464
|
for (const line of lines) {
|
|
1210
1465
|
if (!line.trim()) continue;
|
|
1211
1466
|
await processLine(meta, line, path);
|
|
1467
|
+
processedCount += 1;
|
|
1212
1468
|
}
|
|
1213
1469
|
}
|
|
1470
|
+
return processedCount;
|
|
1214
1471
|
}
|
|
1215
1472
|
|
|
1216
|
-
async function runLeaderNudgeTick(): Promise<
|
|
1473
|
+
async function runLeaderNudgeTick(): Promise<boolean> {
|
|
1217
1474
|
const startedIso = new Date().toISOString();
|
|
1218
1475
|
const leaderOnly = safeString(process.env.OMX_TEAM_WORKER || '').trim() === '';
|
|
1219
1476
|
const staleThresholdMs = resolveLeaderStalenessThresholdMs();
|
|
@@ -1228,7 +1485,7 @@ async function runLeaderNudgeTick(): Promise<void> {
|
|
|
1228
1485
|
last_tick_at: startedIso,
|
|
1229
1486
|
last_error: 'worker_context',
|
|
1230
1487
|
};
|
|
1231
|
-
return;
|
|
1488
|
+
return false;
|
|
1232
1489
|
}
|
|
1233
1490
|
|
|
1234
1491
|
try {
|
|
@@ -1239,6 +1496,7 @@ async function runLeaderNudgeTick(): Promise<void> {
|
|
|
1239
1496
|
logsDir,
|
|
1240
1497
|
preComputedLeaderStale,
|
|
1241
1498
|
allowFreshMailboxNudges: false,
|
|
1499
|
+
source: 'notify_fallback_watcher',
|
|
1242
1500
|
});
|
|
1243
1501
|
leaderNudgeRuns += 1;
|
|
1244
1502
|
lastLeaderNudge = {
|
|
@@ -1260,6 +1518,7 @@ async function runLeaderNudgeTick(): Promise<void> {
|
|
|
1260
1518
|
reason,
|
|
1261
1519
|
});
|
|
1262
1520
|
}
|
|
1521
|
+
return preComputedLeaderStale;
|
|
1263
1522
|
} catch (err) {
|
|
1264
1523
|
leaderNudgeRuns += 1;
|
|
1265
1524
|
lastLeaderNudge = {
|
|
@@ -1278,10 +1537,11 @@ async function runLeaderNudgeTick(): Promise<void> {
|
|
|
1278
1537
|
reason: 'leader_nudge_failed',
|
|
1279
1538
|
error: lastLeaderNudge.last_error,
|
|
1280
1539
|
});
|
|
1540
|
+
return true;
|
|
1281
1541
|
}
|
|
1282
1542
|
}
|
|
1283
1543
|
|
|
1284
|
-
async function runDispatchDrainTick(): Promise<
|
|
1544
|
+
async function runDispatchDrainTick(): Promise<boolean> {
|
|
1285
1545
|
const startedIso = new Date().toISOString();
|
|
1286
1546
|
try {
|
|
1287
1547
|
const result = await drainPendingTeamDispatch({ cwd, stateDir, logsDir, maxPerTick: dispatchTickMax } as any);
|
|
@@ -1301,6 +1561,7 @@ async function runDispatchDrainTick(): Promise<void> {
|
|
|
1301
1561
|
...(result && typeof result === 'object' ? result as Record<string, unknown> : {}),
|
|
1302
1562
|
});
|
|
1303
1563
|
}
|
|
1564
|
+
return shouldLogDispatchDrainTick(result);
|
|
1304
1565
|
} catch (err) {
|
|
1305
1566
|
dispatchDrainRuns += 1;
|
|
1306
1567
|
lastDispatchDrain = {
|
|
@@ -1317,6 +1578,7 @@ async function runDispatchDrainTick(): Promise<void> {
|
|
|
1317
1578
|
reason: 'dispatch_drain_failed',
|
|
1318
1579
|
error: lastDispatchDrain.last_error,
|
|
1319
1580
|
});
|
|
1581
|
+
return true;
|
|
1320
1582
|
}
|
|
1321
1583
|
}
|
|
1322
1584
|
|
|
@@ -1328,34 +1590,62 @@ async function shouldSuppressInteractiveFallbackTicks(): Promise<boolean> {
|
|
|
1328
1590
|
return deepInterviewStateActive || deepInterviewInputLockActive;
|
|
1329
1591
|
}
|
|
1330
1592
|
|
|
1331
|
-
async function pumpTeamControlPlaneTick(): Promise<
|
|
1332
|
-
await runDispatchDrainTick();
|
|
1333
|
-
if (await shouldSuppressInteractiveFallbackTicks())
|
|
1334
|
-
|
|
1593
|
+
async function pumpTeamControlPlaneTick(): Promise<CycleActivitySummary> {
|
|
1594
|
+
const dispatchActive = await runDispatchDrainTick();
|
|
1595
|
+
if (await shouldSuppressInteractiveFallbackTicks()) {
|
|
1596
|
+
return { active: dispatchActive, reason: dispatchActive ? 'dispatch_drain' : 'deep_interview_locked' };
|
|
1597
|
+
}
|
|
1598
|
+
const leaderActive = await runLeaderNudgeTick();
|
|
1335
1599
|
await runFallbackAutoNudgeTick();
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1600
|
+
const autoNudgeActive = lastFallbackAutoNudge.last_reason === 'sent';
|
|
1601
|
+
if (dispatchActive) return { active: true, reason: 'dispatch_drain' };
|
|
1602
|
+
if (leaderActive) return { active: true, reason: 'leader_nudge' };
|
|
1603
|
+
if (autoNudgeActive) return { active: true, reason: 'fallback_auto_nudge' };
|
|
1604
|
+
return { active: false, reason: lastFallbackAutoNudge.last_reason || 'control_plane_idle' };
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
async function runWatcherCycle(): Promise<number> {
|
|
1609
|
+
let processedRolloutCount = 0;
|
|
1610
|
+
if (authorityOnly) {
|
|
1611
|
+
const authorityBackoff = await resolveAuthorityPrimaryWatcherHealth();
|
|
1612
|
+
lastAuthorityBackoff = authorityBackoff;
|
|
1613
|
+
if (authorityBackoff.active) {
|
|
1614
|
+
await writeAuthorityBackoffState();
|
|
1615
|
+
return processedRolloutCount;
|
|
1616
|
+
}
|
|
1617
|
+
} else {
|
|
1618
|
+
lastAuthorityBackoff = createAuthorityBackoffState('');
|
|
1619
|
+
}
|
|
1340
1620
|
if (!authorityOnly) {
|
|
1341
1621
|
await ensureTrackedFiles();
|
|
1342
|
-
await pollFiles();
|
|
1622
|
+
processedRolloutCount = await pollFiles();
|
|
1343
1623
|
}
|
|
1344
|
-
await pumpTeamControlPlaneTick();
|
|
1624
|
+
const controlPlaneSummary = await pumpTeamControlPlaneTick();
|
|
1345
1625
|
if (!authorityOnly && !(await shouldSuppressInteractiveFallbackTicks())) {
|
|
1346
1626
|
await runRalphWatcherBehaviorTick();
|
|
1347
1627
|
}
|
|
1348
|
-
|
|
1628
|
+
const ralphActive = lastRalphContinueSteer.last_reason === 'sent';
|
|
1629
|
+
const summary: CycleActivitySummary = processedRolloutCount > 0
|
|
1630
|
+
? { active: true, reason: 'rollout_event' }
|
|
1631
|
+
: controlPlaneSummary.active
|
|
1632
|
+
? controlPlaneSummary
|
|
1633
|
+
: ralphActive
|
|
1634
|
+
? { active: true, reason: 'ralph_continue_steer' }
|
|
1635
|
+
: { active: false, reason: controlPlaneSummary.reason || lastRalphContinueSteer.last_reason || 'idle' };
|
|
1636
|
+
const nextDelayMs = updateAdaptivePollState(summary);
|
|
1637
|
+
await writeState({ last_cycle_activity: summary.reason });
|
|
1638
|
+
return nextDelayMs;
|
|
1349
1639
|
}
|
|
1350
1640
|
|
|
1351
1641
|
async function tick(): Promise<void> {
|
|
1352
1642
|
if (stopping) return;
|
|
1353
1643
|
if (await enforceLifecycleGuards()) return;
|
|
1354
|
-
await runWatcherCycle();
|
|
1644
|
+
const nextDelayMs = await runWatcherCycle();
|
|
1355
1645
|
if (await enforceLifecycleGuards()) return;
|
|
1356
1646
|
setTimeout(() => {
|
|
1357
1647
|
void tick();
|
|
1358
|
-
},
|
|
1648
|
+
}, nextDelayMs);
|
|
1359
1649
|
}
|
|
1360
1650
|
|
|
1361
1651
|
function shutdown(signal: string): void {
|
|
@@ -1379,6 +1669,8 @@ async function main(): Promise<void> {
|
|
|
1379
1669
|
notify_script: notifyScript,
|
|
1380
1670
|
authority_only: authorityOnly,
|
|
1381
1671
|
poll_ms: pollMs,
|
|
1672
|
+
effective_poll_ms: adaptivePollState.current_ms,
|
|
1673
|
+
idle_max_poll_ms: idleMaxPollMs,
|
|
1382
1674
|
once: runOnce,
|
|
1383
1675
|
parent_pid: parentPid,
|
|
1384
1676
|
pid_file: runOnce ? null : pidFilePath,
|
|
@@ -12,6 +12,7 @@ import { readJsonIfExists, getScopedStateDirsForCurrentSession, readdir } from '
|
|
|
12
12
|
import { runProcess } from './process-runner.js';
|
|
13
13
|
import { logTmuxHookEvent } from './log.js';
|
|
14
14
|
import { evaluatePaneInjectionReadiness, mapPaneInjectionReadinessReason, sendPaneInput } from './team-tmux-guard.js';
|
|
15
|
+
import { stripOrchestrationIntentTags } from './orchestration-intent.js';
|
|
15
16
|
import { buildCapturePaneArgv, DEFAULT_MARKER, tmuxHookExplicitlyDisablesInjection } from '../tmux-hook-engine.js';
|
|
16
17
|
import {
|
|
17
18
|
isManagedOmxSession,
|
|
@@ -72,18 +73,12 @@ function buildBlockedAutoApprovalMatcher(blockedInputs) {
|
|
|
72
73
|
export function isBlockedAutoApprovalInput(text, blockedInputs = DEEP_INTERVIEW_BLOCKED_APPROVAL_INPUTS) {
|
|
73
74
|
const normalized = normalizeBlockedAutoApprovalInput(text);
|
|
74
75
|
if (!normalized) return false;
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
const blockedPrefixes = normalizedBlockedInputs.filter((entry) => DEEP_INTERVIEW_BLOCKED_APPROVAL_PREFIXES.has(entry));
|
|
79
|
-
if (blockedPrefixes.some((prefix) => normalized.startsWith(`${prefix} `))) return true;
|
|
76
|
+
const { exactMatches, prefixedMatches, blockedTokenSet } = buildBlockedAutoApprovalMatcher(blockedInputs);
|
|
77
|
+
if (exactMatches.has(normalized)) return true;
|
|
78
|
+
if (prefixedMatches.some((prefix) => normalized.startsWith(`${prefix} `))) return true;
|
|
80
79
|
|
|
81
80
|
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
82
81
|
if (tokens.length === 0) return false;
|
|
83
|
-
|
|
84
|
-
const blockedTokenSet = new Set(
|
|
85
|
-
normalizedBlockedInputs.flatMap((entry) => entry.split(/\s+/).filter(Boolean)),
|
|
86
|
-
);
|
|
87
82
|
return tokens.every((token) => blockedTokenSet.has(token));
|
|
88
83
|
}
|
|
89
84
|
|
|
@@ -288,7 +283,7 @@ const SEMANTIC_STALL_PROMPT_PATTERNS = [
|
|
|
288
283
|
];
|
|
289
284
|
|
|
290
285
|
function normalizeStallDetectionText(text) {
|
|
291
|
-
return safeString(text)
|
|
286
|
+
return stripOrchestrationIntentTags(safeString(text))
|
|
292
287
|
.replace(/\r\n?/g, '\n')
|
|
293
288
|
.split('\n')
|
|
294
289
|
.filter((line) => !line.includes(DEFAULT_MARKER))
|
|
@@ -5,12 +5,26 @@
|
|
|
5
5
|
import { appendFile } from 'fs/promises';
|
|
6
6
|
import { join } from 'path';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
async function safeAppend(file: string, line: string): Promise<void> {
|
|
9
|
+
try {
|
|
10
|
+
await appendFile(file, line);
|
|
11
|
+
} catch {
|
|
12
|
+
// Fall through — log writes should never crash the caller
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function logTmuxHookEvent(
|
|
17
|
+
logsDir: string,
|
|
18
|
+
event: Record<string, unknown>,
|
|
19
|
+
): Promise<void> {
|
|
9
20
|
const file = join(logsDir, `tmux-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
|
|
10
|
-
await
|
|
21
|
+
await safeAppend(file, JSON.stringify(event) + '\n');
|
|
11
22
|
}
|
|
12
23
|
|
|
13
|
-
export async function logNotifyHookEvent(
|
|
24
|
+
export async function logNotifyHookEvent(
|
|
25
|
+
logsDir: string,
|
|
26
|
+
event: Record<string, unknown>,
|
|
27
|
+
): Promise<void> {
|
|
14
28
|
const file = join(logsDir, `notify-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
|
|
15
|
-
await
|
|
29
|
+
await safeAppend(file, JSON.stringify(event) + '\n');
|
|
16
30
|
}
|
|
@@ -72,6 +72,7 @@ function readCurrentTmuxSessionName(): string {
|
|
|
72
72
|
function readParentPid(pid: number): number | null {
|
|
73
73
|
if (!Number.isInteger(pid) || pid <= 1) return null;
|
|
74
74
|
try {
|
|
75
|
+
if (process.platform === 'win32') return null;
|
|
75
76
|
if (process.platform === 'linux') {
|
|
76
77
|
const stat = readFileSync(`/proc/${pid}/stat`, 'utf-8');
|
|
77
78
|
const commandEnd = stat.lastIndexOf(')');
|