oh-my-codex 0.11.13 → 0.12.1
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 +34 -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 +37 -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 +276 -5
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +95 -1
- package/dist/cli/__tests__/launch-fallback.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 +10 -5
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/index.d.ts +21 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +298 -36
- 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__/keyword-detector.test.js +132 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +292 -4
- 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/keyword-detector.d.ts +2 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +76 -4
- package/dist/hooks/keyword-detector.js.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 +1050 -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 +792 -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 +322 -21
- 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 +543 -15
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +133 -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 +409 -191
- 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 +45 -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 +15 -102
- 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 +1346 -0
- package/src/scripts/codex-native-hook.ts +983 -0
- package/src/scripts/codex-native-pre-post.ts +161 -0
- package/src/scripts/notify-fallback-watcher.ts +378 -29
- 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
package/dist/team/runtime.js
CHANGED
|
@@ -3,10 +3,11 @@ import { existsSync, appendFileSync, mkdirSync } from 'fs';
|
|
|
3
3
|
import { mkdir, readdir, readFile, writeFile } from 'fs/promises';
|
|
4
4
|
import { performance } from 'perf_hooks';
|
|
5
5
|
import { spawn, spawnSync } from 'child_process';
|
|
6
|
-
import { sanitizeTeamName, isTmuxAvailable, createTeamSession, buildWorkerProcessLaunchSpec, resolveTeamWorkerCli, resolveTeamWorkerCliPlan, resolveTeamWorkerLaunchMode, waitForWorkerReady, dismissTrustPromptIfPresent, sleepFractionalSeconds, sendToWorker, sendToWorkerStdin, isWorkerAlive, getWorkerPanePid, killWorkerByPaneIdAsync, restoreStandaloneHudPane, teardownWorkerPanes, unregisterResizeHook, destroyTeamSession, listTeamSessions, } from './tmux-session.js';
|
|
6
|
+
import { sanitizeTeamName, isTmuxAvailable, hasCurrentTmuxClientContext, createTeamSession, buildWorkerProcessLaunchSpec, resolveTeamWorkerCli, resolveTeamWorkerCliPlan, resolveTeamWorkerLaunchMode, waitForWorkerReady, dismissTrustPromptIfPresent, sleepFractionalSeconds, sendToWorker, sendToWorkerStdin, isWorkerAlive, getWorkerPanePid, killWorkerByPaneIdAsync, restoreStandaloneHudPane, teardownWorkerPanes, unregisterResizeHook, destroyTeamSession, listPaneIds, listTeamSessions, } from './tmux-session.js';
|
|
7
7
|
import { teamInit as initTeamState, DEFAULT_MAX_WORKERS, teamReadConfig as readTeamConfig, teamWriteWorkerIdentity as writeWorkerIdentity, teamReadWorkerHeartbeat as readWorkerHeartbeat, teamReadWorkerStatus as readWorkerStatus, teamWriteWorkerInbox as writeWorkerInbox, teamCreateTask as createStateTask, teamReadTask as readTask, teamListTasks as listTasks, teamReadManifest as readTeamManifestV2, teamNormalizeGovernance as normalizeTeamGovernance, teamNormalizePolicy as normalizeTeamPolicy, teamClaimTask as claimTask, teamReleaseTaskClaim as releaseTaskClaim, teamReclaimExpiredTaskClaim as reclaimExpiredTaskClaim, teamAppendEvent as appendTeamEvent, teamReadTaskApproval as readTaskApproval, teamListMailbox as listMailboxMessages, teamMarkMessageDelivered as markMessageDelivered, teamMarkMessageNotified as markMessageNotified, teamEnqueueDispatchRequest as enqueueDispatchRequest, teamMarkDispatchRequestNotified as markDispatchRequestNotified, teamTransitionDispatchRequest as transitionDispatchRequest, teamReadDispatchRequest as readDispatchRequest, teamCleanup as cleanupTeamState, teamSaveConfig as saveTeamConfig, teamWriteShutdownRequest as writeShutdownRequest, teamReadShutdownAck as readShutdownAck, teamReadMonitorSnapshot as readMonitorSnapshot, teamWriteMonitorSnapshot as writeMonitorSnapshot, teamReadPhase as readTeamPhaseState, teamWritePhase as writeTeamPhaseState, } from './team-ops.js';
|
|
8
8
|
import { queueInboxInstruction, queueDirectMailboxMessage, queueBroadcastMailboxMessage, waitForDispatchReceipt, } from './mcp-comm.js';
|
|
9
|
-
import {
|
|
9
|
+
import { appendTeamDeliveryLogForCwd } from './delivery-log.js';
|
|
10
|
+
import { generateWorkerOverlay, writeTeamWorkerInstructionsFile, removeTeamWorkerInstructionsFile, writeWorkerWorktreeRootAgentsFile, removeWorkerWorktreeRootAgentsFile, generateInitialInbox, generateTaskAssignmentInbox, generateShutdownInbox, buildTriggerDirective, buildMailboxTriggerDirective, buildLeaderMailboxTriggerDirective, writeWorkerRoleInstructionsFile, } from './worker-bootstrap.js';
|
|
10
11
|
import { loadRolePrompt } from './role-router.js';
|
|
11
12
|
import { composeRoleInstructionsForRole } from '../agents/native-config.js';
|
|
12
13
|
import { codexPromptsDir } from '../utils/paths.js';
|
|
@@ -49,6 +50,58 @@ async function syncRootTeamModeStateOnTerminalPhase(teamName, phase, cwd) {
|
|
|
49
50
|
// Best-effort compatibility sync only.
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
export function applyCreatedInteractiveSessionToConfig(config, createdSession, workerPaneIds) {
|
|
54
|
+
config.tmux_session = createdSession.name;
|
|
55
|
+
config.leader_pane_id = createdSession.leaderPaneId;
|
|
56
|
+
config.hud_pane_id = createdSession.hudPaneId;
|
|
57
|
+
config.resize_hook_name = createdSession.resizeHookName;
|
|
58
|
+
config.resize_hook_target = createdSession.resizeHookTarget;
|
|
59
|
+
for (let i = 0; i < createdSession.workerPaneIds.length; i++) {
|
|
60
|
+
const paneId = createdSession.workerPaneIds[i];
|
|
61
|
+
workerPaneIds[i] = paneId;
|
|
62
|
+
if (config.workers[i]) {
|
|
63
|
+
config.workers[i].pane_id = paneId;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function collectShutdownPaneIds(params) {
|
|
68
|
+
const { config, livePaneIds = [], restoredStandaloneHudPaneId = null } = params;
|
|
69
|
+
const excludedPaneIds = new Set([
|
|
70
|
+
config.leader_pane_id,
|
|
71
|
+
config.hud_pane_id,
|
|
72
|
+
restoredStandaloneHudPaneId,
|
|
73
|
+
].filter((paneId) => typeof paneId === 'string' && paneId.trim().startsWith('%')));
|
|
74
|
+
const paneIds = new Set();
|
|
75
|
+
for (const paneId of [
|
|
76
|
+
...config.workers.map((worker) => worker.pane_id),
|
|
77
|
+
...livePaneIds,
|
|
78
|
+
]) {
|
|
79
|
+
if (typeof paneId !== 'string')
|
|
80
|
+
continue;
|
|
81
|
+
const normalized = paneId.trim();
|
|
82
|
+
if (!normalized.startsWith('%'))
|
|
83
|
+
continue;
|
|
84
|
+
if (excludedPaneIds.has(normalized))
|
|
85
|
+
continue;
|
|
86
|
+
paneIds.add(normalized);
|
|
87
|
+
}
|
|
88
|
+
return [...paneIds];
|
|
89
|
+
}
|
|
90
|
+
async function logRuntimeDispatchOutcome(params) {
|
|
91
|
+
const { cwd, teamName, workerName, requestId, messageId, intent, outcome, source = 'team.runtime' } = params;
|
|
92
|
+
await appendTeamDeliveryLogForCwd(cwd, {
|
|
93
|
+
event: 'dispatch_result',
|
|
94
|
+
source,
|
|
95
|
+
team: teamName,
|
|
96
|
+
request_id: requestId,
|
|
97
|
+
message_id: messageId,
|
|
98
|
+
to_worker: workerName,
|
|
99
|
+
intent,
|
|
100
|
+
transport: outcome.transport,
|
|
101
|
+
result: outcome.ok ? 'confirmed' : 'failed',
|
|
102
|
+
reason: outcome.reason,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
52
105
|
function collectProvisionedShutdownWorktrees(config) {
|
|
53
106
|
const seenWorktreePaths = new Set();
|
|
54
107
|
const worktrees = [];
|
|
@@ -147,6 +200,36 @@ async function appendIntegrationEvent(teamName, type, worker, metadata, cwd) {
|
|
|
147
200
|
async function sendIntegrationMessageToLeader(teamName, worker, body, cwd) {
|
|
148
201
|
await sendWorkerMessage(teamName, worker.name, 'leader-fixed', body, cwd).catch(() => { });
|
|
149
202
|
}
|
|
203
|
+
function leaderHeadAdvanced(before, after) {
|
|
204
|
+
return typeof after === 'string' && after.length > 0 && after !== before;
|
|
205
|
+
}
|
|
206
|
+
async function recordIntegrationFailure(teamName, worker, state, details, cwd) {
|
|
207
|
+
const leaderHeadAfter = details.leaderHeadAfter ?? details.leaderHeadBefore;
|
|
208
|
+
const sourceShort = details.sourceCommit.slice(0, 12);
|
|
209
|
+
const leaderShort = details.leaderHeadBefore.slice(0, 12);
|
|
210
|
+
state.last_leader_head = leaderHeadAfter;
|
|
211
|
+
state.status = 'integration_failed';
|
|
212
|
+
state.conflict_commit = details.sourceCommit;
|
|
213
|
+
state.conflict_files = undefined;
|
|
214
|
+
state.updated_at = new Date().toISOString();
|
|
215
|
+
await appendIntegrationEvent(teamName, 'worker_integration_failed', worker, {
|
|
216
|
+
worker_name: worker.name,
|
|
217
|
+
operation: details.operation,
|
|
218
|
+
source_commit: details.sourceCommit,
|
|
219
|
+
leader_head_before: details.leaderHeadBefore,
|
|
220
|
+
leader_head_after: leaderHeadAfter,
|
|
221
|
+
worktree_path: details.worktreePath,
|
|
222
|
+
summary: `${details.operation} for ${worker.name} reported success but leader HEAD did not advance`,
|
|
223
|
+
}, cwd);
|
|
224
|
+
appendIntegrationReport(teamName, {
|
|
225
|
+
workerName: worker.name,
|
|
226
|
+
operation: details.operation,
|
|
227
|
+
strategy: details.strategy,
|
|
228
|
+
files: [],
|
|
229
|
+
detail: `${details.operation} reported success for ${sourceShort}, but leader HEAD did not advance from ${leaderShort}; not marking worker as integrated.`,
|
|
230
|
+
}, cwd);
|
|
231
|
+
await sendIntegrationMessageToLeader(teamName, worker, `INTEGRATION FAILED: ${details.operation} for ${worker.name} reported success, but leader HEAD stayed at ${leaderShort}. Not emitting INTEGRATED; retry or inspect leader branch state before continuing.`, cwd);
|
|
232
|
+
}
|
|
150
233
|
function autoCommitDirtyWorktree(worker) {
|
|
151
234
|
const worktreePath = resolve(worker.worktree_path);
|
|
152
235
|
const repoRoot = resolve(worker.worktree_repo_root);
|
|
@@ -247,8 +330,17 @@ async function integrateWorkerCommitsIntoLeader(params) {
|
|
|
247
330
|
if (merge.ok) {
|
|
248
331
|
const newLeaderHead = resolveLeaderHead(repoRoot, cwd) ?? leaderHead;
|
|
249
332
|
const workerIntegrated = leaderContainsCommit(repoRoot, cwd, workerHead);
|
|
250
|
-
|
|
251
|
-
|
|
333
|
+
if (!leaderHeadAdvanced(leaderHead, newLeaderHead)) {
|
|
334
|
+
await recordIntegrationFailure(teamName, worker, state, {
|
|
335
|
+
operation: 'merge',
|
|
336
|
+
sourceCommit: workerHead,
|
|
337
|
+
leaderHeadBefore: leaderHead,
|
|
338
|
+
leaderHeadAfter: newLeaderHead,
|
|
339
|
+
worktreePath,
|
|
340
|
+
strategy: '-X theirs',
|
|
341
|
+
}, cwd);
|
|
342
|
+
}
|
|
343
|
+
else if (workerIntegrated) {
|
|
252
344
|
state.last_integrated_head = workerHead;
|
|
253
345
|
state.last_leader_head = newLeaderHead;
|
|
254
346
|
state.status = 'integrated';
|
|
@@ -383,6 +475,18 @@ async function integrateWorkerCommitsIntoLeader(params) {
|
|
|
383
475
|
break;
|
|
384
476
|
}
|
|
385
477
|
const newLeaderHead = resolveLeaderHead(repoRoot, cwd) ?? leaderHead;
|
|
478
|
+
if (!leaderHeadAdvanced(leaderHead, newLeaderHead)) {
|
|
479
|
+
await recordIntegrationFailure(teamName, worker, state, {
|
|
480
|
+
operation: 'cherry-pick',
|
|
481
|
+
sourceCommit: commit,
|
|
482
|
+
leaderHeadBefore: leaderHead,
|
|
483
|
+
leaderHeadAfter: newLeaderHead,
|
|
484
|
+
worktreePath,
|
|
485
|
+
strategy: '-X theirs',
|
|
486
|
+
}, cwd);
|
|
487
|
+
allPicked = false;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
386
490
|
state.last_integrated_head = commit;
|
|
387
491
|
state.last_leader_head = newLeaderHead;
|
|
388
492
|
state.status = 'integrated';
|
|
@@ -1172,7 +1276,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1172
1276
|
if (!isTmuxAvailable()) {
|
|
1173
1277
|
throw new Error('Team mode requires tmux. Install with: apt install tmux / brew install tmux');
|
|
1174
1278
|
}
|
|
1175
|
-
if (!
|
|
1279
|
+
if (!hasCurrentTmuxClientContext()) {
|
|
1176
1280
|
throw new Error('Team mode requires running inside tmux current leader pane');
|
|
1177
1281
|
}
|
|
1178
1282
|
}
|
|
@@ -1305,7 +1409,8 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1305
1409
|
rolePromptContent: rawRolePromptContent ?? undefined,
|
|
1306
1410
|
worktreeRootAgentsCanonical: Boolean(workerWorkspace.worktreePath),
|
|
1307
1411
|
});
|
|
1308
|
-
const
|
|
1412
|
+
const triggerDirective = buildTriggerDirective(workerName, sanitized, resolveInstructionStateRoot(workerWorkspace.worktreePath));
|
|
1413
|
+
const trigger = triggerDirective.text;
|
|
1309
1414
|
const initialPrompt = workerCliPlan[i - 1] === 'gemini' ? trigger : undefined;
|
|
1310
1415
|
if (initialPrompt) {
|
|
1311
1416
|
await writeWorkerInbox(sanitized, workerName, inbox, leaderCwd);
|
|
@@ -1319,6 +1424,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1319
1424
|
instructionsFilePath,
|
|
1320
1425
|
inbox,
|
|
1321
1426
|
trigger,
|
|
1427
|
+
triggerIntent: triggerDirective.intent,
|
|
1322
1428
|
initialPrompt,
|
|
1323
1429
|
workerLaunchArgs,
|
|
1324
1430
|
workerCli: workerCliPlan[i - 1],
|
|
@@ -1355,14 +1461,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1355
1461
|
sessionCreated = true;
|
|
1356
1462
|
createdWorkerPaneIds.push(...createdSession.workerPaneIds);
|
|
1357
1463
|
createdLeaderPaneId = createdSession.leaderPaneId;
|
|
1358
|
-
config
|
|
1359
|
-
config.leader_pane_id = createdSession.leaderPaneId;
|
|
1360
|
-
config.hud_pane_id = createdSession.hudPaneId;
|
|
1361
|
-
config.resize_hook_name = createdSession.resizeHookName;
|
|
1362
|
-
config.resize_hook_target = createdSession.resizeHookTarget;
|
|
1363
|
-
for (let i = 0; i < createdSession.workerPaneIds.length; i++) {
|
|
1364
|
-
workerPaneIds[i] = createdSession.workerPaneIds[i];
|
|
1365
|
-
}
|
|
1464
|
+
applyCreatedInteractiveSessionToConfig(config, createdSession, workerPaneIds);
|
|
1366
1465
|
}
|
|
1367
1466
|
else {
|
|
1368
1467
|
config.tmux_session = `prompt-${sanitized}`;
|
|
@@ -1388,13 +1487,14 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1388
1487
|
if (!bootstrapPlan) {
|
|
1389
1488
|
throw new Error(`missing bootstrap plan for worker-${i}`);
|
|
1390
1489
|
}
|
|
1391
|
-
const { workerName, paneId, workerTasks, workerRole, inbox, trigger, initialPrompt } = {
|
|
1490
|
+
const { workerName, paneId, workerTasks, workerRole, inbox, trigger, triggerIntent, initialPrompt } = {
|
|
1392
1491
|
workerName: bootstrapPlan.workerName,
|
|
1393
1492
|
paneId: workerPaneIds[i - 1],
|
|
1394
1493
|
workerTasks: bootstrapPlan.workerTasks,
|
|
1395
1494
|
workerRole: bootstrapPlan.workerRole,
|
|
1396
1495
|
inbox: bootstrapPlan.inbox,
|
|
1397
1496
|
trigger: bootstrapPlan.trigger,
|
|
1497
|
+
triggerIntent: bootstrapPlan.triggerIntent,
|
|
1398
1498
|
initialPrompt: bootstrapPlan.initialPrompt,
|
|
1399
1499
|
};
|
|
1400
1500
|
const workerWorkspace = bootstrapPlan.workerWorkspace;
|
|
@@ -1418,7 +1518,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1418
1518
|
};
|
|
1419
1519
|
// Get pane PID and store it (interactive mode) or process PID (prompt mode)
|
|
1420
1520
|
if (workerLaunchMode === 'interactive') {
|
|
1421
|
-
const panePid = getWorkerPanePid(sessionName, i);
|
|
1521
|
+
const panePid = getWorkerPanePid(sessionName, i, paneId);
|
|
1422
1522
|
if (panePid)
|
|
1423
1523
|
identity.pid = panePid;
|
|
1424
1524
|
}
|
|
@@ -1428,6 +1528,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1428
1528
|
if (paneId)
|
|
1429
1529
|
identity.pane_id = paneId;
|
|
1430
1530
|
if (config.workers[i - 1]) {
|
|
1531
|
+
config.workers[i - 1].pid = identity.pid;
|
|
1431
1532
|
config.workers[i - 1].pane_id = paneId;
|
|
1432
1533
|
config.workers[i - 1].role = workerRole;
|
|
1433
1534
|
config.workers[i - 1].worker_cli = workerCliPlan[i - 1];
|
|
@@ -1466,6 +1567,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1466
1567
|
workerCli: workerCliPlan[i - 1],
|
|
1467
1568
|
inbox,
|
|
1468
1569
|
triggerMessage: trigger,
|
|
1570
|
+
intent: triggerIntent,
|
|
1469
1571
|
cwd: leaderCwd,
|
|
1470
1572
|
dispatchPolicy,
|
|
1471
1573
|
inboxCorrelationKey: `startup:${workerName}`,
|
|
@@ -1874,6 +1976,7 @@ export async function assignTask(teamName, workerName, taskId, cwd) {
|
|
|
1874
1976
|
const maxAssignRetries = 2;
|
|
1875
1977
|
const assignRetryDelayS = 2;
|
|
1876
1978
|
let outcome = { ok: false, transport: 'none', reason: 'not_attempted' };
|
|
1979
|
+
const triggerDirective = buildTriggerDirective(workerName, sanitized, resolveInstructionStateRoot(workerInfo.worktree_path));
|
|
1877
1980
|
for (let attempt = 1; attempt <= maxAssignRetries; attempt++) {
|
|
1878
1981
|
outcome = await dispatchCriticalInboxInstruction({
|
|
1879
1982
|
teamName: sanitized,
|
|
@@ -1882,7 +1985,8 @@ export async function assignTask(teamName, workerName, taskId, cwd) {
|
|
|
1882
1985
|
workerIndex: workerInfo.index,
|
|
1883
1986
|
paneId: workerInfo.pane_id,
|
|
1884
1987
|
inbox,
|
|
1885
|
-
triggerMessage:
|
|
1988
|
+
triggerMessage: triggerDirective.text,
|
|
1989
|
+
intent: triggerDirective.intent,
|
|
1886
1990
|
cwd,
|
|
1887
1991
|
dispatchPolicy,
|
|
1888
1992
|
inboxCorrelationKey: `assign:${taskId}:${workerName}`,
|
|
@@ -1988,6 +2092,7 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
1988
2092
|
const requestedAt = new Date().toISOString();
|
|
1989
2093
|
await writeShutdownRequest(sanitized, w.name, 'leader-fixed', cwd);
|
|
1990
2094
|
shutdownRequestTimes.set(w.name, requestedAt);
|
|
2095
|
+
const triggerDirective = buildTriggerDirective(w.name, sanitized, resolveInstructionStateRoot(w.worktree_path));
|
|
1991
2096
|
await dispatchCriticalInboxInstruction({
|
|
1992
2097
|
teamName: sanitized,
|
|
1993
2098
|
config,
|
|
@@ -1995,7 +2100,8 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
1995
2100
|
workerIndex: w.index,
|
|
1996
2101
|
paneId: w.pane_id,
|
|
1997
2102
|
inbox: generateShutdownInbox(sanitized, w.name),
|
|
1998
|
-
triggerMessage:
|
|
2103
|
+
triggerMessage: triggerDirective.text,
|
|
2104
|
+
intent: triggerDirective.intent,
|
|
1999
2105
|
cwd,
|
|
2000
2106
|
dispatchPolicy,
|
|
2001
2107
|
inboxCorrelationKey: `shutdown:${w.name}`,
|
|
@@ -2049,8 +2155,10 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
2049
2155
|
const leaderPaneId = config.leader_pane_id;
|
|
2050
2156
|
const hudPaneId = config.hud_pane_id;
|
|
2051
2157
|
if (config.worker_launch_mode === 'interactive') {
|
|
2052
|
-
const
|
|
2053
|
-
|
|
2158
|
+
const livePaneIds = listPaneIds(sessionName);
|
|
2159
|
+
let shutdownPaneIds = collectShutdownPaneIds({ config, livePaneIds });
|
|
2160
|
+
const workerPanePids = shutdownPaneIds
|
|
2161
|
+
.map((paneId) => getWorkerPanePid(sessionName, 1, paneId))
|
|
2054
2162
|
.filter((pid) => typeof pid === 'number' && Number.isFinite(pid) && pid > 0);
|
|
2055
2163
|
for (const panePid of workerPanePids) {
|
|
2056
2164
|
await terminateTrackedProcessTree(panePid);
|
|
@@ -2073,22 +2181,25 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
2073
2181
|
if (resizeHookWarning) {
|
|
2074
2182
|
console.warn(`[team shutdown] ${sanitized}: ${resizeHookWarning}; continuing teardown`);
|
|
2075
2183
|
}
|
|
2076
|
-
|
|
2077
|
-
.map((w) => w.pane_id)
|
|
2078
|
-
.filter((paneId) => typeof paneId === 'string' && paneId.trim().length > 0);
|
|
2079
|
-
await teardownWorkerPanes(workerPaneIds, {
|
|
2080
|
-
leaderPaneId,
|
|
2081
|
-
hudPaneId,
|
|
2082
|
-
});
|
|
2184
|
+
let restoredHudPaneId = null;
|
|
2083
2185
|
if (hudPaneId) {
|
|
2084
2186
|
await killWorkerByPaneIdAsync(hudPaneId, leaderPaneId ?? undefined);
|
|
2085
2187
|
if (sessionName.includes(':')) {
|
|
2086
|
-
|
|
2188
|
+
restoredHudPaneId = restoreStandaloneHudPane(leaderPaneId, cwd);
|
|
2087
2189
|
if (!restoredHudPaneId) {
|
|
2088
2190
|
console.warn(`[team shutdown] ${sanitized}: failed to restore standalone HUD pane`);
|
|
2089
2191
|
}
|
|
2090
2192
|
}
|
|
2091
2193
|
}
|
|
2194
|
+
shutdownPaneIds = collectShutdownPaneIds({
|
|
2195
|
+
config,
|
|
2196
|
+
livePaneIds: listPaneIds(sessionName),
|
|
2197
|
+
restoredStandaloneHudPaneId: restoredHudPaneId,
|
|
2198
|
+
});
|
|
2199
|
+
await teardownWorkerPanes(shutdownPaneIds, {
|
|
2200
|
+
leaderPaneId,
|
|
2201
|
+
hudPaneId: restoredHudPaneId ?? hudPaneId,
|
|
2202
|
+
});
|
|
2092
2203
|
// 4. Destroy tmux session
|
|
2093
2204
|
if (!sessionName.includes(':')) {
|
|
2094
2205
|
try {
|
|
@@ -2416,7 +2527,7 @@ async function markDispatchRequestLeaderPaneMissingDeferred(params) {
|
|
|
2416
2527
|
}, cwd).catch(() => { });
|
|
2417
2528
|
}
|
|
2418
2529
|
async function dispatchCriticalInboxInstruction(params) {
|
|
2419
|
-
const { teamName, config, workerName, workerIndex, paneId, workerCli, inbox, triggerMessage, cwd, dispatchPolicy, inboxCorrelationKey, requireWorkerStartupEvidence, } = params;
|
|
2530
|
+
const { teamName, config, workerName, workerIndex, paneId, workerCli, inbox, triggerMessage, intent, cwd, dispatchPolicy, inboxCorrelationKey, requireWorkerStartupEvidence, } = params;
|
|
2420
2531
|
if (config.worker_launch_mode === 'prompt') {
|
|
2421
2532
|
return await queueInboxInstruction({
|
|
2422
2533
|
teamName,
|
|
@@ -2425,6 +2536,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2425
2536
|
paneId,
|
|
2426
2537
|
inbox,
|
|
2427
2538
|
triggerMessage,
|
|
2539
|
+
intent,
|
|
2428
2540
|
cwd,
|
|
2429
2541
|
transportPreference: 'prompt_stdin',
|
|
2430
2542
|
fallbackAllowed: false,
|
|
@@ -2440,6 +2552,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2440
2552
|
paneId,
|
|
2441
2553
|
inbox,
|
|
2442
2554
|
triggerMessage,
|
|
2555
|
+
intent,
|
|
2443
2556
|
cwd,
|
|
2444
2557
|
transportPreference: 'transport_direct',
|
|
2445
2558
|
fallbackAllowed: false,
|
|
@@ -2454,6 +2567,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2454
2567
|
paneId,
|
|
2455
2568
|
inbox,
|
|
2456
2569
|
triggerMessage,
|
|
2570
|
+
intent,
|
|
2457
2571
|
cwd,
|
|
2458
2572
|
transportPreference: 'hook_preferred_with_fallback',
|
|
2459
2573
|
fallbackAllowed: true,
|
|
@@ -2494,7 +2608,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2494
2608
|
if (receipt?.status === 'failed') {
|
|
2495
2609
|
const fallback = await notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
|
|
2496
2610
|
if (fallback.ok) {
|
|
2497
|
-
await
|
|
2611
|
+
await transitionDispatchRequest(teamName, queued.request_id, 'failed', 'failed', { last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2498
2612
|
return {
|
|
2499
2613
|
ok: true,
|
|
2500
2614
|
transport: fallback.transport,
|
|
@@ -2543,14 +2657,16 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2543
2657
|
};
|
|
2544
2658
|
}
|
|
2545
2659
|
async function finalizeHookPreferredMailboxDispatch(params) {
|
|
2546
|
-
const { teamName, requestId, workerName, workerIndex, paneId, messageId, triggerMessage, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2660
|
+
const { teamName, requestId, workerName, workerIndex, paneId, messageId, triggerMessage, intent, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2547
2661
|
const receipt = await waitForDispatchReceipt(teamName, requestId, cwd, {
|
|
2548
2662
|
timeoutMs: dispatchPolicy.dispatch_ack_timeout_ms,
|
|
2549
2663
|
pollMs: 50,
|
|
2550
2664
|
});
|
|
2551
2665
|
if (receipt && (receipt.status === 'notified' || receipt.status === 'delivered')) {
|
|
2552
2666
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2553
|
-
|
|
2667
|
+
const outcome = { ok: true, transport: 'hook', reason: `hook_receipt_${receipt.status}`, request_id: requestId, message_id: messageId };
|
|
2668
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2669
|
+
return outcome;
|
|
2554
2670
|
}
|
|
2555
2671
|
const fallback = fallbackNotify
|
|
2556
2672
|
? await fallbackNotify()
|
|
@@ -2560,23 +2676,27 @@ async function finalizeHookPreferredMailboxDispatch(params) {
|
|
|
2560
2676
|
if (receipt?.status === 'failed') {
|
|
2561
2677
|
if (fallback.ok) {
|
|
2562
2678
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2563
|
-
await
|
|
2564
|
-
|
|
2679
|
+
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2680
|
+
const outcome = {
|
|
2565
2681
|
ok: true,
|
|
2566
2682
|
transport: fallback.transport,
|
|
2567
2683
|
reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}`,
|
|
2568
2684
|
request_id: requestId,
|
|
2569
2685
|
message_id: messageId,
|
|
2570
2686
|
};
|
|
2687
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2688
|
+
return outcome;
|
|
2571
2689
|
}
|
|
2572
2690
|
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_attempted_but_unconfirmed:${fallback.reason}` }, cwd).catch(() => { });
|
|
2573
|
-
|
|
2691
|
+
const outcome = {
|
|
2574
2692
|
ok: false,
|
|
2575
2693
|
transport: fallback.transport,
|
|
2576
2694
|
reason: `fallback_attempted_but_unconfirmed:${fallback.reason}`,
|
|
2577
2695
|
request_id: requestId,
|
|
2578
2696
|
message_id: messageId,
|
|
2579
2697
|
};
|
|
2698
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2699
|
+
return outcome;
|
|
2580
2700
|
}
|
|
2581
2701
|
if (fallback.ok) {
|
|
2582
2702
|
if (isLeaderPaneMissingMailboxPersistedOutcome({ workerName, paneId, outcome: fallback })) {
|
|
@@ -2586,38 +2706,44 @@ async function finalizeHookPreferredMailboxDispatch(params) {
|
|
|
2586
2706
|
messageId,
|
|
2587
2707
|
cwd,
|
|
2588
2708
|
});
|
|
2589
|
-
|
|
2709
|
+
const outcome = {
|
|
2590
2710
|
ok: true,
|
|
2591
2711
|
transport: fallback.transport,
|
|
2592
2712
|
reason: 'leader_pane_missing_mailbox_persisted',
|
|
2593
2713
|
request_id: requestId,
|
|
2594
2714
|
message_id: messageId,
|
|
2595
2715
|
};
|
|
2716
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2717
|
+
return outcome;
|
|
2596
2718
|
}
|
|
2597
2719
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2598
2720
|
const marked = await markDispatchRequestNotified(teamName, requestId, { message_id: messageId, last_reason: `fallback_confirmed:${fallback.reason}` }, cwd);
|
|
2599
2721
|
if (!marked) {
|
|
2600
2722
|
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2601
2723
|
}
|
|
2602
|
-
|
|
2724
|
+
const outcome = {
|
|
2603
2725
|
ok: true,
|
|
2604
2726
|
transport: fallback.transport,
|
|
2605
2727
|
reason: `hook_timeout_fallback_confirmed:${fallback.reason}`,
|
|
2606
2728
|
request_id: requestId,
|
|
2607
2729
|
message_id: messageId,
|
|
2608
2730
|
};
|
|
2731
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2732
|
+
return outcome;
|
|
2609
2733
|
}
|
|
2610
2734
|
const current = await readDispatchRequest(teamName, requestId, cwd);
|
|
2611
2735
|
if (current) {
|
|
2612
2736
|
await transitionDispatchRequest(teamName, requestId, current.status, 'failed', { message_id: messageId, last_reason: `fallback_attempted_but_unconfirmed:${fallback.reason}` }, cwd).catch(() => { });
|
|
2613
2737
|
}
|
|
2614
|
-
|
|
2738
|
+
const outcome = {
|
|
2615
2739
|
ok: false,
|
|
2616
2740
|
transport: fallback.transport,
|
|
2617
2741
|
reason: `fallback_attempted_but_unconfirmed:${fallback.reason}`,
|
|
2618
2742
|
request_id: requestId,
|
|
2619
2743
|
message_id: messageId,
|
|
2620
2744
|
};
|
|
2745
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2746
|
+
return outcome;
|
|
2621
2747
|
}
|
|
2622
2748
|
async function notifyLeaderAsync(config, message, cwd) {
|
|
2623
2749
|
// Canonical leader delivery is durable mailbox persistence plus HUD-owned
|
|
@@ -2663,44 +2789,15 @@ async function deliverPendingMailboxMessages(teamName, config, workers, previous
|
|
|
2663
2789
|
if (!worker.alive)
|
|
2664
2790
|
continue;
|
|
2665
2791
|
for (const msg of unnotified) {
|
|
2666
|
-
const
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
pane_id: workerInfo.pane_id,
|
|
2676
|
-
trigger_message: triggerMessage,
|
|
2677
|
-
message_id: msg.message_id,
|
|
2678
|
-
transport_preference: transportPreference,
|
|
2679
|
-
fallback_allowed: fallbackAllowed,
|
|
2680
|
-
}, cwd);
|
|
2681
|
-
let outcome;
|
|
2682
|
-
if (transportPreference === 'hook_preferred_with_fallback') {
|
|
2683
|
-
outcome = await finalizeHookPreferredMailboxDispatch({
|
|
2684
|
-
teamName,
|
|
2685
|
-
requestId: queued.request.request_id,
|
|
2686
|
-
workerName: worker.name,
|
|
2687
|
-
workerIndex: workerInfo.index,
|
|
2688
|
-
paneId: workerInfo.pane_id,
|
|
2689
|
-
messageId: msg.message_id,
|
|
2690
|
-
triggerMessage,
|
|
2691
|
-
config,
|
|
2692
|
-
dispatchPolicy,
|
|
2693
|
-
cwd,
|
|
2694
|
-
});
|
|
2695
|
-
}
|
|
2696
|
-
else {
|
|
2697
|
-
const direct = await notifyWorkerOutcome(config, workerInfo.index, triggerMessage, workerInfo.pane_id);
|
|
2698
|
-
outcome = { ...direct, request_id: queued.request.request_id, message_id: msg.message_id };
|
|
2699
|
-
if (outcome.ok) {
|
|
2700
|
-
await markMessageNotified(teamName, worker.name, msg.message_id, cwd).catch(() => false);
|
|
2701
|
-
await markDispatchRequestNotified(teamName, queued.request.request_id, { message_id: msg.message_id, last_reason: outcome.reason }, cwd).catch(() => null);
|
|
2702
|
-
}
|
|
2703
|
-
}
|
|
2792
|
+
const outcome = await dispatchPendingMailboxMessage({
|
|
2793
|
+
teamName,
|
|
2794
|
+
workerName: worker.name,
|
|
2795
|
+
workerInfo,
|
|
2796
|
+
messageId: msg.message_id,
|
|
2797
|
+
config,
|
|
2798
|
+
dispatchPolicy,
|
|
2799
|
+
cwd,
|
|
2800
|
+
});
|
|
2704
2801
|
if (outcome.ok) {
|
|
2705
2802
|
nextNotifications[msg.message_id] = new Date().toISOString();
|
|
2706
2803
|
}
|
|
@@ -2713,87 +2810,175 @@ async function deliverPendingMailboxMessages(teamName, config, workers, previous
|
|
|
2713
2810
|
}
|
|
2714
2811
|
return pruned;
|
|
2715
2812
|
}
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2813
|
+
function resolveWorkerMailboxTransportPreference(config, dispatchPolicy) {
|
|
2814
|
+
return config.worker_launch_mode === 'prompt'
|
|
2815
|
+
? 'prompt_stdin'
|
|
2816
|
+
: (dispatchPolicy.dispatch_mode === 'transport_direct' ? 'transport_direct' : 'hook_preferred_with_fallback');
|
|
2817
|
+
}
|
|
2818
|
+
function resolveLeaderMailboxTransportPreference(dispatchPolicy) {
|
|
2819
|
+
return dispatchPolicy.dispatch_mode === 'transport_direct' ? 'transport_direct' : 'hook_preferred_with_fallback';
|
|
2820
|
+
}
|
|
2821
|
+
function isExistingMailboxNotificationOutcome(outcome) {
|
|
2822
|
+
return outcome.ok && outcome.reason === 'existing_message_already_notified';
|
|
2823
|
+
}
|
|
2824
|
+
async function dispatchPendingMailboxMessage(params) {
|
|
2825
|
+
const { teamName, workerName, workerInfo, messageId, config, dispatchPolicy, cwd } = params;
|
|
2826
|
+
const triggerDirective = buildMailboxTriggerDirective(workerName, teamName, 1, resolveInstructionStateRoot(workerInfo.worktree_path));
|
|
2827
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2828
|
+
const queued = await enqueueDispatchRequest(teamName, {
|
|
2829
|
+
kind: 'mailbox',
|
|
2830
|
+
to_worker: workerName,
|
|
2831
|
+
worker_index: workerInfo.index,
|
|
2832
|
+
pane_id: workerInfo.pane_id,
|
|
2833
|
+
trigger_message: triggerDirective.text,
|
|
2834
|
+
intent: triggerDirective.intent,
|
|
2835
|
+
message_id: messageId,
|
|
2836
|
+
transport_preference: transportPreference,
|
|
2837
|
+
fallback_allowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2838
|
+
}, cwd);
|
|
2839
|
+
if (transportPreference === 'hook_preferred_with_fallback') {
|
|
2840
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2841
|
+
queuedOutcome: {
|
|
2842
|
+
ok: true,
|
|
2843
|
+
transport: 'hook',
|
|
2844
|
+
reason: 'queued_for_hook_dispatch',
|
|
2845
|
+
request_id: queued.request.request_id,
|
|
2846
|
+
message_id: messageId,
|
|
2847
|
+
},
|
|
2848
|
+
transportPreference,
|
|
2849
|
+
teamName,
|
|
2850
|
+
workerName,
|
|
2851
|
+
workerIndex: workerInfo.index,
|
|
2852
|
+
paneId: workerInfo.pane_id,
|
|
2853
|
+
messageId,
|
|
2854
|
+
triggerMessage: triggerDirective.text,
|
|
2855
|
+
intent: triggerDirective.intent,
|
|
2856
|
+
config,
|
|
2857
|
+
dispatchPolicy,
|
|
2735
2858
|
cwd,
|
|
2736
|
-
transportPreference: leaderTransportPreference,
|
|
2737
|
-
fallbackAllowed: leaderTransportPreference === 'hook_preferred_with_fallback',
|
|
2738
|
-
notify: async (_target, message) => (leaderTransportPreference === 'hook_preferred_with_fallback'
|
|
2739
|
-
? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
|
|
2740
|
-
: await notifyLeaderAsync(config, message, cwd)),
|
|
2741
2859
|
});
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2860
|
+
}
|
|
2861
|
+
const direct = await notifyWorkerOutcome(config, workerInfo.index, triggerDirective.text, workerInfo.pane_id);
|
|
2862
|
+
const outcome = { ...direct, request_id: queued.request.request_id, message_id: messageId };
|
|
2863
|
+
if (outcome.ok) {
|
|
2864
|
+
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2865
|
+
await markDispatchRequestNotified(teamName, queued.request.request_id, { message_id: messageId, last_reason: outcome.reason }, cwd).catch(() => null);
|
|
2866
|
+
}
|
|
2867
|
+
await logRuntimeDispatchOutcome({
|
|
2868
|
+
cwd,
|
|
2869
|
+
teamName,
|
|
2870
|
+
workerName,
|
|
2871
|
+
requestId: queued.request.request_id,
|
|
2872
|
+
messageId,
|
|
2873
|
+
outcome,
|
|
2874
|
+
});
|
|
2875
|
+
return outcome;
|
|
2876
|
+
}
|
|
2877
|
+
async function finalizeQueuedMailboxDispatch(params) {
|
|
2878
|
+
const { queuedOutcome, transportPreference, teamName, workerName, workerIndex, paneId, messageId, triggerMessage, intent, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2879
|
+
if (transportPreference !== 'hook_preferred_with_fallback') {
|
|
2880
|
+
return queuedOutcome;
|
|
2881
|
+
}
|
|
2882
|
+
if (isExistingMailboxNotificationOutcome(queuedOutcome)) {
|
|
2883
|
+
return queuedOutcome;
|
|
2884
|
+
}
|
|
2885
|
+
if (!queuedOutcome.request_id || !messageId) {
|
|
2886
|
+
return { ...queuedOutcome, ok: false, reason: 'dispatch_request_missing_id' };
|
|
2887
|
+
}
|
|
2888
|
+
return await finalizeHookPreferredMailboxDispatch({
|
|
2889
|
+
teamName,
|
|
2890
|
+
requestId: queuedOutcome.request_id,
|
|
2891
|
+
workerName,
|
|
2892
|
+
workerIndex,
|
|
2893
|
+
paneId,
|
|
2894
|
+
messageId,
|
|
2895
|
+
triggerMessage,
|
|
2896
|
+
intent,
|
|
2897
|
+
config,
|
|
2898
|
+
dispatchPolicy,
|
|
2899
|
+
cwd,
|
|
2900
|
+
fallbackNotify,
|
|
2901
|
+
});
|
|
2902
|
+
}
|
|
2903
|
+
async function sendLeaderMailboxMessage(params) {
|
|
2904
|
+
const { teamName, fromWorker, body, config, dispatchPolicy, cwd } = params;
|
|
2905
|
+
const triggerDirective = buildLeaderMailboxTriggerDirective(teamName, fromWorker, config.team_state_root || undefined);
|
|
2906
|
+
const transportPreference = resolveLeaderMailboxTransportPreference(dispatchPolicy);
|
|
2907
|
+
const queuedOutcome = await queueDirectMailboxMessage({
|
|
2908
|
+
teamName,
|
|
2909
|
+
fromWorker,
|
|
2910
|
+
toWorker: 'leader-fixed',
|
|
2911
|
+
toPaneId: config.leader_pane_id ?? undefined,
|
|
2912
|
+
body,
|
|
2913
|
+
triggerMessage: triggerDirective.text,
|
|
2914
|
+
intent: triggerDirective.intent,
|
|
2915
|
+
cwd,
|
|
2916
|
+
transportPreference,
|
|
2917
|
+
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2918
|
+
notify: async (_target, message) => (transportPreference === 'hook_preferred_with_fallback'
|
|
2919
|
+
? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
|
|
2920
|
+
: await notifyLeaderAsync(config, message, cwd)),
|
|
2921
|
+
});
|
|
2922
|
+
if (!isExistingMailboxNotificationOutcome(queuedOutcome)
|
|
2923
|
+
&& transportPreference === 'hook_preferred_with_fallback'
|
|
2924
|
+
&& !config.leader_pane_id) {
|
|
2925
|
+
if (queuedOutcome.request_id) {
|
|
2926
|
+
await markDispatchRequestLeaderPaneMissingDeferred({
|
|
2927
|
+
teamName,
|
|
2928
|
+
requestId: queuedOutcome.request_id,
|
|
2929
|
+
messageId: queuedOutcome.message_id,
|
|
2774
2930
|
cwd,
|
|
2775
|
-
fallbackNotify: async () => await notifyLeaderAsync(config, leaderTriggerMessage, cwd),
|
|
2776
2931
|
});
|
|
2777
2932
|
}
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2933
|
+
const deferredOutcome = {
|
|
2934
|
+
...queuedOutcome,
|
|
2935
|
+
ok: true,
|
|
2936
|
+
transport: 'mailbox',
|
|
2937
|
+
reason: 'leader_pane_missing_mailbox_persisted',
|
|
2938
|
+
};
|
|
2939
|
+
await logRuntimeDispatchOutcome({
|
|
2940
|
+
cwd,
|
|
2941
|
+
teamName,
|
|
2942
|
+
workerName: 'leader-fixed',
|
|
2943
|
+
requestId: deferredOutcome.request_id,
|
|
2944
|
+
messageId: deferredOutcome.message_id,
|
|
2945
|
+
intent: triggerDirective.intent,
|
|
2946
|
+
outcome: deferredOutcome,
|
|
2947
|
+
});
|
|
2948
|
+
return deferredOutcome;
|
|
2781
2949
|
}
|
|
2782
|
-
const
|
|
2950
|
+
const canLeaderFallbackDirectly = Boolean(config.leader_pane_id) && isTmuxAvailable();
|
|
2951
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2952
|
+
queuedOutcome,
|
|
2953
|
+
transportPreference: canLeaderFallbackDirectly ? transportPreference : 'transport_direct',
|
|
2954
|
+
teamName,
|
|
2955
|
+
workerName: 'leader-fixed',
|
|
2956
|
+
paneId: config.leader_pane_id ?? undefined,
|
|
2957
|
+
messageId: queuedOutcome.message_id,
|
|
2958
|
+
triggerMessage: triggerDirective.text,
|
|
2959
|
+
intent: triggerDirective.intent,
|
|
2960
|
+
config,
|
|
2961
|
+
dispatchPolicy,
|
|
2962
|
+
cwd,
|
|
2963
|
+
fallbackNotify: async () => await notifyLeaderAsync(config, triggerDirective.text, cwd),
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
async function sendRecipientMailboxMessage(params) {
|
|
2967
|
+
const { teamName, fromWorker, toWorker, body, config, dispatchPolicy, cwd } = params;
|
|
2968
|
+
const recipient = config.workers.find((worker) => worker.name === toWorker);
|
|
2783
2969
|
if (!recipient)
|
|
2784
2970
|
throw new Error(`Worker ${toWorker} not found in team`);
|
|
2785
|
-
const
|
|
2786
|
-
const transportPreference = config
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
const outcome = await queueDirectMailboxMessage({
|
|
2790
|
-
teamName: sanitized,
|
|
2971
|
+
const triggerDirective = buildMailboxTriggerDirective(toWorker, teamName, 1, resolveInstructionStateRoot(recipient.worktree_path));
|
|
2972
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2973
|
+
const queuedOutcome = await queueDirectMailboxMessage({
|
|
2974
|
+
teamName,
|
|
2791
2975
|
fromWorker,
|
|
2792
2976
|
toWorker,
|
|
2793
2977
|
toWorkerIndex: recipient.index,
|
|
2794
2978
|
toPaneId: recipient.pane_id,
|
|
2795
2979
|
body,
|
|
2796
|
-
triggerMessage,
|
|
2980
|
+
triggerMessage: triggerDirective.text,
|
|
2981
|
+
intent: triggerDirective.intent,
|
|
2797
2982
|
cwd,
|
|
2798
2983
|
transportPreference,
|
|
2799
2984
|
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
@@ -2801,25 +2986,82 @@ export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cw
|
|
|
2801
2986
|
? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
|
|
2802
2987
|
: await notifyWorkerOutcome(config, recipient.index, message, recipient.pane_id)),
|
|
2803
2988
|
});
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2989
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2990
|
+
queuedOutcome,
|
|
2991
|
+
transportPreference,
|
|
2992
|
+
teamName,
|
|
2993
|
+
workerName: recipient.name,
|
|
2994
|
+
workerIndex: recipient.index,
|
|
2995
|
+
paneId: recipient.pane_id,
|
|
2996
|
+
messageId: queuedOutcome.message_id,
|
|
2997
|
+
triggerMessage: triggerDirective.text,
|
|
2998
|
+
intent: triggerDirective.intent,
|
|
2999
|
+
config,
|
|
3000
|
+
dispatchPolicy,
|
|
3001
|
+
cwd,
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
async function finalizeBroadcastMailboxOutcomes(params) {
|
|
3005
|
+
const { teamName, outcomes, transportPreference, config, dispatchPolicy, cwd } = params;
|
|
3006
|
+
if (transportPreference !== 'hook_preferred_with_fallback') {
|
|
3007
|
+
return outcomes;
|
|
3008
|
+
}
|
|
3009
|
+
const finalizedOutcomes = [];
|
|
3010
|
+
for (const outcome of outcomes) {
|
|
3011
|
+
const target = outcome.to_worker
|
|
3012
|
+
? (config.workers.find((worker) => worker.name === outcome.to_worker) ?? null)
|
|
3013
|
+
: null;
|
|
3014
|
+
if (!target) {
|
|
3015
|
+
finalizedOutcomes.push({ ...outcome, ok: false, reason: 'missing_worker_index' });
|
|
3016
|
+
continue;
|
|
2809
3017
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
3018
|
+
const triggerDirective = buildMailboxTriggerDirective(target.name, teamName, 1, resolveInstructionStateRoot(target.worktree_path));
|
|
3019
|
+
finalizedOutcomes.push(await finalizeQueuedMailboxDispatch({
|
|
3020
|
+
queuedOutcome: outcome,
|
|
3021
|
+
transportPreference,
|
|
3022
|
+
teamName,
|
|
3023
|
+
workerName: target.name,
|
|
3024
|
+
workerIndex: target.index,
|
|
3025
|
+
paneId: target.pane_id,
|
|
2816
3026
|
messageId: outcome.message_id,
|
|
2817
|
-
triggerMessage,
|
|
3027
|
+
triggerMessage: triggerDirective.text,
|
|
3028
|
+
intent: triggerDirective.intent,
|
|
3029
|
+
config,
|
|
3030
|
+
dispatchPolicy,
|
|
3031
|
+
cwd,
|
|
3032
|
+
}));
|
|
3033
|
+
}
|
|
3034
|
+
return finalizedOutcomes;
|
|
3035
|
+
}
|
|
3036
|
+
export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cwd) {
|
|
3037
|
+
const sanitized = sanitizeTeamName(teamName);
|
|
3038
|
+
const config = await readTeamConfig(sanitized, cwd);
|
|
3039
|
+
if (!config)
|
|
3040
|
+
throw new Error(`Team ${sanitized} not found`);
|
|
3041
|
+
const manifest = await readTeamManifestV2(sanitized, cwd);
|
|
3042
|
+
const dispatchPolicy = resolveDispatchPolicy(manifest?.policy, config.worker_launch_mode);
|
|
3043
|
+
if (toWorker === 'leader-fixed') {
|
|
3044
|
+
const finalOutcome = await sendLeaderMailboxMessage({
|
|
3045
|
+
teamName: sanitized,
|
|
3046
|
+
fromWorker,
|
|
3047
|
+
body,
|
|
2818
3048
|
config,
|
|
2819
3049
|
dispatchPolicy,
|
|
2820
3050
|
cwd,
|
|
2821
3051
|
});
|
|
3052
|
+
if (!finalOutcome.ok)
|
|
3053
|
+
throw new Error(`mailbox_notify_failed:${finalOutcome.reason}`);
|
|
3054
|
+
return finalOutcome;
|
|
2822
3055
|
}
|
|
3056
|
+
const finalOutcome = await sendRecipientMailboxMessage({
|
|
3057
|
+
teamName: sanitized,
|
|
3058
|
+
fromWorker,
|
|
3059
|
+
toWorker,
|
|
3060
|
+
body,
|
|
3061
|
+
config,
|
|
3062
|
+
dispatchPolicy,
|
|
3063
|
+
cwd,
|
|
3064
|
+
});
|
|
2823
3065
|
if (!finalOutcome.ok)
|
|
2824
3066
|
throw new Error(`mailbox_notify_failed:${finalOutcome.reason}`);
|
|
2825
3067
|
return finalOutcome;
|
|
@@ -2831,16 +3073,15 @@ export async function broadcastWorkerMessage(teamName, fromWorker, body, cwd) {
|
|
|
2831
3073
|
throw new Error(`Team ${sanitized} not found`);
|
|
2832
3074
|
const manifest = await readTeamManifestV2(sanitized, cwd);
|
|
2833
3075
|
const dispatchPolicy = resolveDispatchPolicy(manifest?.policy, config.worker_launch_mode);
|
|
2834
|
-
const transportPreference = config
|
|
2835
|
-
? 'prompt_stdin'
|
|
2836
|
-
: (dispatchPolicy.dispatch_mode === 'transport_direct' ? 'transport_direct' : 'hook_preferred_with_fallback');
|
|
3076
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2837
3077
|
const outcomes = await queueBroadcastMailboxMessage({
|
|
2838
3078
|
teamName: sanitized,
|
|
2839
3079
|
fromWorker,
|
|
2840
3080
|
recipients: config.workers.map((w) => ({ workerName: w.name, workerIndex: w.index, paneId: w.pane_id })),
|
|
2841
3081
|
body,
|
|
2842
3082
|
cwd,
|
|
2843
|
-
triggerFor: (workerName) =>
|
|
3083
|
+
triggerFor: (workerName) => buildMailboxTriggerDirective(workerName, sanitized, 1, resolveInstructionStateRoot(config.workers.find((worker) => worker.name === workerName)?.worktree_path)).text,
|
|
3084
|
+
intentFor: () => 'pending-mailbox-review',
|
|
2844
3085
|
transportPreference,
|
|
2845
3086
|
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2846
3087
|
notify: async (target, message) => transportPreference === 'hook_preferred_with_fallback'
|
|
@@ -2849,37 +3090,14 @@ export async function broadcastWorkerMessage(teamName, fromWorker, body, cwd) {
|
|
|
2849
3090
|
? await notifyWorkerOutcome(config, target.workerIndex, message, target.paneId)
|
|
2850
3091
|
: { ok: false, transport: 'none', reason: 'missing_worker_index' }),
|
|
2851
3092
|
});
|
|
2852
|
-
const
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
continue;
|
|
2861
|
-
}
|
|
2862
|
-
const target = outcome.to_worker
|
|
2863
|
-
? (config.workers.find((w) => w.name === outcome.to_worker) ?? null)
|
|
2864
|
-
: null;
|
|
2865
|
-
if (!target) {
|
|
2866
|
-
finalizedOutcomes.push({ ...outcome, ok: false, reason: 'missing_worker_index' });
|
|
2867
|
-
continue;
|
|
2868
|
-
}
|
|
2869
|
-
finalizedOutcomes.push(await finalizeHookPreferredMailboxDispatch({
|
|
2870
|
-
teamName: sanitized,
|
|
2871
|
-
requestId: outcome.request_id,
|
|
2872
|
-
workerName: target.name,
|
|
2873
|
-
workerIndex: target.index,
|
|
2874
|
-
paneId: target.pane_id,
|
|
2875
|
-
messageId: outcome.message_id,
|
|
2876
|
-
triggerMessage: generateMailboxTriggerMessage(target.name, sanitized, 1, resolveInstructionStateRoot(target.worktree_path)),
|
|
2877
|
-
config,
|
|
2878
|
-
dispatchPolicy,
|
|
2879
|
-
cwd,
|
|
2880
|
-
}));
|
|
2881
|
-
}
|
|
2882
|
-
const results = transportPreference === 'hook_preferred_with_fallback' ? finalizedOutcomes : outcomes;
|
|
3093
|
+
const results = await finalizeBroadcastMailboxOutcomes({
|
|
3094
|
+
teamName: sanitized,
|
|
3095
|
+
outcomes,
|
|
3096
|
+
transportPreference,
|
|
3097
|
+
config,
|
|
3098
|
+
dispatchPolicy,
|
|
3099
|
+
cwd,
|
|
3100
|
+
});
|
|
2883
3101
|
if (results.some((result) => !result.ok)) {
|
|
2884
3102
|
const firstFailure = results.find((result) => !result.ok);
|
|
2885
3103
|
throw new Error(`mailbox_notify_failed:${firstFailure?.reason ?? 'unknown'}`);
|