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
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;
|
|
@@ -1466,6 +1566,7 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
|
|
|
1466
1566
|
workerCli: workerCliPlan[i - 1],
|
|
1467
1567
|
inbox,
|
|
1468
1568
|
triggerMessage: trigger,
|
|
1569
|
+
intent: triggerIntent,
|
|
1469
1570
|
cwd: leaderCwd,
|
|
1470
1571
|
dispatchPolicy,
|
|
1471
1572
|
inboxCorrelationKey: `startup:${workerName}`,
|
|
@@ -1874,6 +1975,7 @@ export async function assignTask(teamName, workerName, taskId, cwd) {
|
|
|
1874
1975
|
const maxAssignRetries = 2;
|
|
1875
1976
|
const assignRetryDelayS = 2;
|
|
1876
1977
|
let outcome = { ok: false, transport: 'none', reason: 'not_attempted' };
|
|
1978
|
+
const triggerDirective = buildTriggerDirective(workerName, sanitized, resolveInstructionStateRoot(workerInfo.worktree_path));
|
|
1877
1979
|
for (let attempt = 1; attempt <= maxAssignRetries; attempt++) {
|
|
1878
1980
|
outcome = await dispatchCriticalInboxInstruction({
|
|
1879
1981
|
teamName: sanitized,
|
|
@@ -1882,7 +1984,8 @@ export async function assignTask(teamName, workerName, taskId, cwd) {
|
|
|
1882
1984
|
workerIndex: workerInfo.index,
|
|
1883
1985
|
paneId: workerInfo.pane_id,
|
|
1884
1986
|
inbox,
|
|
1885
|
-
triggerMessage:
|
|
1987
|
+
triggerMessage: triggerDirective.text,
|
|
1988
|
+
intent: triggerDirective.intent,
|
|
1886
1989
|
cwd,
|
|
1887
1990
|
dispatchPolicy,
|
|
1888
1991
|
inboxCorrelationKey: `assign:${taskId}:${workerName}`,
|
|
@@ -1988,6 +2091,7 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
1988
2091
|
const requestedAt = new Date().toISOString();
|
|
1989
2092
|
await writeShutdownRequest(sanitized, w.name, 'leader-fixed', cwd);
|
|
1990
2093
|
shutdownRequestTimes.set(w.name, requestedAt);
|
|
2094
|
+
const triggerDirective = buildTriggerDirective(w.name, sanitized, resolveInstructionStateRoot(w.worktree_path));
|
|
1991
2095
|
await dispatchCriticalInboxInstruction({
|
|
1992
2096
|
teamName: sanitized,
|
|
1993
2097
|
config,
|
|
@@ -1995,7 +2099,8 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
1995
2099
|
workerIndex: w.index,
|
|
1996
2100
|
paneId: w.pane_id,
|
|
1997
2101
|
inbox: generateShutdownInbox(sanitized, w.name),
|
|
1998
|
-
triggerMessage:
|
|
2102
|
+
triggerMessage: triggerDirective.text,
|
|
2103
|
+
intent: triggerDirective.intent,
|
|
1999
2104
|
cwd,
|
|
2000
2105
|
dispatchPolicy,
|
|
2001
2106
|
inboxCorrelationKey: `shutdown:${w.name}`,
|
|
@@ -2049,8 +2154,10 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
2049
2154
|
const leaderPaneId = config.leader_pane_id;
|
|
2050
2155
|
const hudPaneId = config.hud_pane_id;
|
|
2051
2156
|
if (config.worker_launch_mode === 'interactive') {
|
|
2052
|
-
const
|
|
2053
|
-
|
|
2157
|
+
const livePaneIds = listPaneIds(sessionName);
|
|
2158
|
+
let shutdownPaneIds = collectShutdownPaneIds({ config, livePaneIds });
|
|
2159
|
+
const workerPanePids = shutdownPaneIds
|
|
2160
|
+
.map((paneId) => getWorkerPanePid(sessionName, 1, paneId))
|
|
2054
2161
|
.filter((pid) => typeof pid === 'number' && Number.isFinite(pid) && pid > 0);
|
|
2055
2162
|
for (const panePid of workerPanePids) {
|
|
2056
2163
|
await terminateTrackedProcessTree(panePid);
|
|
@@ -2073,22 +2180,25 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
|
|
|
2073
2180
|
if (resizeHookWarning) {
|
|
2074
2181
|
console.warn(`[team shutdown] ${sanitized}: ${resizeHookWarning}; continuing teardown`);
|
|
2075
2182
|
}
|
|
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
|
-
});
|
|
2183
|
+
let restoredHudPaneId = null;
|
|
2083
2184
|
if (hudPaneId) {
|
|
2084
2185
|
await killWorkerByPaneIdAsync(hudPaneId, leaderPaneId ?? undefined);
|
|
2085
2186
|
if (sessionName.includes(':')) {
|
|
2086
|
-
|
|
2187
|
+
restoredHudPaneId = restoreStandaloneHudPane(leaderPaneId, cwd);
|
|
2087
2188
|
if (!restoredHudPaneId) {
|
|
2088
2189
|
console.warn(`[team shutdown] ${sanitized}: failed to restore standalone HUD pane`);
|
|
2089
2190
|
}
|
|
2090
2191
|
}
|
|
2091
2192
|
}
|
|
2193
|
+
shutdownPaneIds = collectShutdownPaneIds({
|
|
2194
|
+
config,
|
|
2195
|
+
livePaneIds: listPaneIds(sessionName),
|
|
2196
|
+
restoredStandaloneHudPaneId: restoredHudPaneId,
|
|
2197
|
+
});
|
|
2198
|
+
await teardownWorkerPanes(shutdownPaneIds, {
|
|
2199
|
+
leaderPaneId,
|
|
2200
|
+
hudPaneId: restoredHudPaneId ?? hudPaneId,
|
|
2201
|
+
});
|
|
2092
2202
|
// 4. Destroy tmux session
|
|
2093
2203
|
if (!sessionName.includes(':')) {
|
|
2094
2204
|
try {
|
|
@@ -2416,7 +2526,7 @@ async function markDispatchRequestLeaderPaneMissingDeferred(params) {
|
|
|
2416
2526
|
}, cwd).catch(() => { });
|
|
2417
2527
|
}
|
|
2418
2528
|
async function dispatchCriticalInboxInstruction(params) {
|
|
2419
|
-
const { teamName, config, workerName, workerIndex, paneId, workerCli, inbox, triggerMessage, cwd, dispatchPolicy, inboxCorrelationKey, requireWorkerStartupEvidence, } = params;
|
|
2529
|
+
const { teamName, config, workerName, workerIndex, paneId, workerCli, inbox, triggerMessage, intent, cwd, dispatchPolicy, inboxCorrelationKey, requireWorkerStartupEvidence, } = params;
|
|
2420
2530
|
if (config.worker_launch_mode === 'prompt') {
|
|
2421
2531
|
return await queueInboxInstruction({
|
|
2422
2532
|
teamName,
|
|
@@ -2425,6 +2535,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2425
2535
|
paneId,
|
|
2426
2536
|
inbox,
|
|
2427
2537
|
triggerMessage,
|
|
2538
|
+
intent,
|
|
2428
2539
|
cwd,
|
|
2429
2540
|
transportPreference: 'prompt_stdin',
|
|
2430
2541
|
fallbackAllowed: false,
|
|
@@ -2440,6 +2551,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2440
2551
|
paneId,
|
|
2441
2552
|
inbox,
|
|
2442
2553
|
triggerMessage,
|
|
2554
|
+
intent,
|
|
2443
2555
|
cwd,
|
|
2444
2556
|
transportPreference: 'transport_direct',
|
|
2445
2557
|
fallbackAllowed: false,
|
|
@@ -2454,6 +2566,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2454
2566
|
paneId,
|
|
2455
2567
|
inbox,
|
|
2456
2568
|
triggerMessage,
|
|
2569
|
+
intent,
|
|
2457
2570
|
cwd,
|
|
2458
2571
|
transportPreference: 'hook_preferred_with_fallback',
|
|
2459
2572
|
fallbackAllowed: true,
|
|
@@ -2494,7 +2607,7 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2494
2607
|
if (receipt?.status === 'failed') {
|
|
2495
2608
|
const fallback = await notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
|
|
2496
2609
|
if (fallback.ok) {
|
|
2497
|
-
await
|
|
2610
|
+
await transitionDispatchRequest(teamName, queued.request_id, 'failed', 'failed', { last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2498
2611
|
return {
|
|
2499
2612
|
ok: true,
|
|
2500
2613
|
transport: fallback.transport,
|
|
@@ -2543,14 +2656,16 @@ async function dispatchCriticalInboxInstruction(params) {
|
|
|
2543
2656
|
};
|
|
2544
2657
|
}
|
|
2545
2658
|
async function finalizeHookPreferredMailboxDispatch(params) {
|
|
2546
|
-
const { teamName, requestId, workerName, workerIndex, paneId, messageId, triggerMessage, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2659
|
+
const { teamName, requestId, workerName, workerIndex, paneId, messageId, triggerMessage, intent, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2547
2660
|
const receipt = await waitForDispatchReceipt(teamName, requestId, cwd, {
|
|
2548
2661
|
timeoutMs: dispatchPolicy.dispatch_ack_timeout_ms,
|
|
2549
2662
|
pollMs: 50,
|
|
2550
2663
|
});
|
|
2551
2664
|
if (receipt && (receipt.status === 'notified' || receipt.status === 'delivered')) {
|
|
2552
2665
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2553
|
-
|
|
2666
|
+
const outcome = { ok: true, transport: 'hook', reason: `hook_receipt_${receipt.status}`, request_id: requestId, message_id: messageId };
|
|
2667
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2668
|
+
return outcome;
|
|
2554
2669
|
}
|
|
2555
2670
|
const fallback = fallbackNotify
|
|
2556
2671
|
? await fallbackNotify()
|
|
@@ -2560,23 +2675,27 @@ async function finalizeHookPreferredMailboxDispatch(params) {
|
|
|
2560
2675
|
if (receipt?.status === 'failed') {
|
|
2561
2676
|
if (fallback.ok) {
|
|
2562
2677
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2563
|
-
await
|
|
2564
|
-
|
|
2678
|
+
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2679
|
+
const outcome = {
|
|
2565
2680
|
ok: true,
|
|
2566
2681
|
transport: fallback.transport,
|
|
2567
2682
|
reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}`,
|
|
2568
2683
|
request_id: requestId,
|
|
2569
2684
|
message_id: messageId,
|
|
2570
2685
|
};
|
|
2686
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2687
|
+
return outcome;
|
|
2571
2688
|
}
|
|
2572
2689
|
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_attempted_but_unconfirmed:${fallback.reason}` }, cwd).catch(() => { });
|
|
2573
|
-
|
|
2690
|
+
const outcome = {
|
|
2574
2691
|
ok: false,
|
|
2575
2692
|
transport: fallback.transport,
|
|
2576
2693
|
reason: `fallback_attempted_but_unconfirmed:${fallback.reason}`,
|
|
2577
2694
|
request_id: requestId,
|
|
2578
2695
|
message_id: messageId,
|
|
2579
2696
|
};
|
|
2697
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2698
|
+
return outcome;
|
|
2580
2699
|
}
|
|
2581
2700
|
if (fallback.ok) {
|
|
2582
2701
|
if (isLeaderPaneMissingMailboxPersistedOutcome({ workerName, paneId, outcome: fallback })) {
|
|
@@ -2586,38 +2705,44 @@ async function finalizeHookPreferredMailboxDispatch(params) {
|
|
|
2586
2705
|
messageId,
|
|
2587
2706
|
cwd,
|
|
2588
2707
|
});
|
|
2589
|
-
|
|
2708
|
+
const outcome = {
|
|
2590
2709
|
ok: true,
|
|
2591
2710
|
transport: fallback.transport,
|
|
2592
2711
|
reason: 'leader_pane_missing_mailbox_persisted',
|
|
2593
2712
|
request_id: requestId,
|
|
2594
2713
|
message_id: messageId,
|
|
2595
2714
|
};
|
|
2715
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2716
|
+
return outcome;
|
|
2596
2717
|
}
|
|
2597
2718
|
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2598
2719
|
const marked = await markDispatchRequestNotified(teamName, requestId, { message_id: messageId, last_reason: `fallback_confirmed:${fallback.reason}` }, cwd);
|
|
2599
2720
|
if (!marked) {
|
|
2600
2721
|
await transitionDispatchRequest(teamName, requestId, 'failed', 'failed', { message_id: messageId, last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
|
|
2601
2722
|
}
|
|
2602
|
-
|
|
2723
|
+
const outcome = {
|
|
2603
2724
|
ok: true,
|
|
2604
2725
|
transport: fallback.transport,
|
|
2605
2726
|
reason: `hook_timeout_fallback_confirmed:${fallback.reason}`,
|
|
2606
2727
|
request_id: requestId,
|
|
2607
2728
|
message_id: messageId,
|
|
2608
2729
|
};
|
|
2730
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2731
|
+
return outcome;
|
|
2609
2732
|
}
|
|
2610
2733
|
const current = await readDispatchRequest(teamName, requestId, cwd);
|
|
2611
2734
|
if (current) {
|
|
2612
2735
|
await transitionDispatchRequest(teamName, requestId, current.status, 'failed', { message_id: messageId, last_reason: `fallback_attempted_but_unconfirmed:${fallback.reason}` }, cwd).catch(() => { });
|
|
2613
2736
|
}
|
|
2614
|
-
|
|
2737
|
+
const outcome = {
|
|
2615
2738
|
ok: false,
|
|
2616
2739
|
transport: fallback.transport,
|
|
2617
2740
|
reason: `fallback_attempted_but_unconfirmed:${fallback.reason}`,
|
|
2618
2741
|
request_id: requestId,
|
|
2619
2742
|
message_id: messageId,
|
|
2620
2743
|
};
|
|
2744
|
+
await logRuntimeDispatchOutcome({ cwd, teamName, workerName, requestId, messageId, intent, outcome });
|
|
2745
|
+
return outcome;
|
|
2621
2746
|
}
|
|
2622
2747
|
async function notifyLeaderAsync(config, message, cwd) {
|
|
2623
2748
|
// Canonical leader delivery is durable mailbox persistence plus HUD-owned
|
|
@@ -2663,44 +2788,15 @@ async function deliverPendingMailboxMessages(teamName, config, workers, previous
|
|
|
2663
2788
|
if (!worker.alive)
|
|
2664
2789
|
continue;
|
|
2665
2790
|
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
|
-
}
|
|
2791
|
+
const outcome = await dispatchPendingMailboxMessage({
|
|
2792
|
+
teamName,
|
|
2793
|
+
workerName: worker.name,
|
|
2794
|
+
workerInfo,
|
|
2795
|
+
messageId: msg.message_id,
|
|
2796
|
+
config,
|
|
2797
|
+
dispatchPolicy,
|
|
2798
|
+
cwd,
|
|
2799
|
+
});
|
|
2704
2800
|
if (outcome.ok) {
|
|
2705
2801
|
nextNotifications[msg.message_id] = new Date().toISOString();
|
|
2706
2802
|
}
|
|
@@ -2713,87 +2809,175 @@ async function deliverPendingMailboxMessages(teamName, config, workers, previous
|
|
|
2713
2809
|
}
|
|
2714
2810
|
return pruned;
|
|
2715
2811
|
}
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2812
|
+
function resolveWorkerMailboxTransportPreference(config, dispatchPolicy) {
|
|
2813
|
+
return config.worker_launch_mode === 'prompt'
|
|
2814
|
+
? 'prompt_stdin'
|
|
2815
|
+
: (dispatchPolicy.dispatch_mode === 'transport_direct' ? 'transport_direct' : 'hook_preferred_with_fallback');
|
|
2816
|
+
}
|
|
2817
|
+
function resolveLeaderMailboxTransportPreference(dispatchPolicy) {
|
|
2818
|
+
return dispatchPolicy.dispatch_mode === 'transport_direct' ? 'transport_direct' : 'hook_preferred_with_fallback';
|
|
2819
|
+
}
|
|
2820
|
+
function isExistingMailboxNotificationOutcome(outcome) {
|
|
2821
|
+
return outcome.ok && outcome.reason === 'existing_message_already_notified';
|
|
2822
|
+
}
|
|
2823
|
+
async function dispatchPendingMailboxMessage(params) {
|
|
2824
|
+
const { teamName, workerName, workerInfo, messageId, config, dispatchPolicy, cwd } = params;
|
|
2825
|
+
const triggerDirective = buildMailboxTriggerDirective(workerName, teamName, 1, resolveInstructionStateRoot(workerInfo.worktree_path));
|
|
2826
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2827
|
+
const queued = await enqueueDispatchRequest(teamName, {
|
|
2828
|
+
kind: 'mailbox',
|
|
2829
|
+
to_worker: workerName,
|
|
2830
|
+
worker_index: workerInfo.index,
|
|
2831
|
+
pane_id: workerInfo.pane_id,
|
|
2832
|
+
trigger_message: triggerDirective.text,
|
|
2833
|
+
intent: triggerDirective.intent,
|
|
2834
|
+
message_id: messageId,
|
|
2835
|
+
transport_preference: transportPreference,
|
|
2836
|
+
fallback_allowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2837
|
+
}, cwd);
|
|
2838
|
+
if (transportPreference === 'hook_preferred_with_fallback') {
|
|
2839
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2840
|
+
queuedOutcome: {
|
|
2841
|
+
ok: true,
|
|
2842
|
+
transport: 'hook',
|
|
2843
|
+
reason: 'queued_for_hook_dispatch',
|
|
2844
|
+
request_id: queued.request.request_id,
|
|
2845
|
+
message_id: messageId,
|
|
2846
|
+
},
|
|
2847
|
+
transportPreference,
|
|
2848
|
+
teamName,
|
|
2849
|
+
workerName,
|
|
2850
|
+
workerIndex: workerInfo.index,
|
|
2851
|
+
paneId: workerInfo.pane_id,
|
|
2852
|
+
messageId,
|
|
2853
|
+
triggerMessage: triggerDirective.text,
|
|
2854
|
+
intent: triggerDirective.intent,
|
|
2855
|
+
config,
|
|
2856
|
+
dispatchPolicy,
|
|
2735
2857
|
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
2858
|
});
|
|
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
|
-
|
|
2859
|
+
}
|
|
2860
|
+
const direct = await notifyWorkerOutcome(config, workerInfo.index, triggerDirective.text, workerInfo.pane_id);
|
|
2861
|
+
const outcome = { ...direct, request_id: queued.request.request_id, message_id: messageId };
|
|
2862
|
+
if (outcome.ok) {
|
|
2863
|
+
await markMessageNotified(teamName, workerName, messageId, cwd).catch(() => false);
|
|
2864
|
+
await markDispatchRequestNotified(teamName, queued.request.request_id, { message_id: messageId, last_reason: outcome.reason }, cwd).catch(() => null);
|
|
2865
|
+
}
|
|
2866
|
+
await logRuntimeDispatchOutcome({
|
|
2867
|
+
cwd,
|
|
2868
|
+
teamName,
|
|
2869
|
+
workerName,
|
|
2870
|
+
requestId: queued.request.request_id,
|
|
2871
|
+
messageId,
|
|
2872
|
+
outcome,
|
|
2873
|
+
});
|
|
2874
|
+
return outcome;
|
|
2875
|
+
}
|
|
2876
|
+
async function finalizeQueuedMailboxDispatch(params) {
|
|
2877
|
+
const { queuedOutcome, transportPreference, teamName, workerName, workerIndex, paneId, messageId, triggerMessage, intent, config, dispatchPolicy, cwd, fallbackNotify, } = params;
|
|
2878
|
+
if (transportPreference !== 'hook_preferred_with_fallback') {
|
|
2879
|
+
return queuedOutcome;
|
|
2880
|
+
}
|
|
2881
|
+
if (isExistingMailboxNotificationOutcome(queuedOutcome)) {
|
|
2882
|
+
return queuedOutcome;
|
|
2883
|
+
}
|
|
2884
|
+
if (!queuedOutcome.request_id || !messageId) {
|
|
2885
|
+
return { ...queuedOutcome, ok: false, reason: 'dispatch_request_missing_id' };
|
|
2886
|
+
}
|
|
2887
|
+
return await finalizeHookPreferredMailboxDispatch({
|
|
2888
|
+
teamName,
|
|
2889
|
+
requestId: queuedOutcome.request_id,
|
|
2890
|
+
workerName,
|
|
2891
|
+
workerIndex,
|
|
2892
|
+
paneId,
|
|
2893
|
+
messageId,
|
|
2894
|
+
triggerMessage,
|
|
2895
|
+
intent,
|
|
2896
|
+
config,
|
|
2897
|
+
dispatchPolicy,
|
|
2898
|
+
cwd,
|
|
2899
|
+
fallbackNotify,
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
async function sendLeaderMailboxMessage(params) {
|
|
2903
|
+
const { teamName, fromWorker, body, config, dispatchPolicy, cwd } = params;
|
|
2904
|
+
const triggerDirective = buildLeaderMailboxTriggerDirective(teamName, fromWorker);
|
|
2905
|
+
const transportPreference = resolveLeaderMailboxTransportPreference(dispatchPolicy);
|
|
2906
|
+
const queuedOutcome = await queueDirectMailboxMessage({
|
|
2907
|
+
teamName,
|
|
2908
|
+
fromWorker,
|
|
2909
|
+
toWorker: 'leader-fixed',
|
|
2910
|
+
toPaneId: config.leader_pane_id ?? undefined,
|
|
2911
|
+
body,
|
|
2912
|
+
triggerMessage: triggerDirective.text,
|
|
2913
|
+
intent: triggerDirective.intent,
|
|
2914
|
+
cwd,
|
|
2915
|
+
transportPreference,
|
|
2916
|
+
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2917
|
+
notify: async (_target, message) => (transportPreference === 'hook_preferred_with_fallback'
|
|
2918
|
+
? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
|
|
2919
|
+
: await notifyLeaderAsync(config, message, cwd)),
|
|
2920
|
+
});
|
|
2921
|
+
if (!isExistingMailboxNotificationOutcome(queuedOutcome)
|
|
2922
|
+
&& transportPreference === 'hook_preferred_with_fallback'
|
|
2923
|
+
&& !config.leader_pane_id) {
|
|
2924
|
+
if (queuedOutcome.request_id) {
|
|
2925
|
+
await markDispatchRequestLeaderPaneMissingDeferred({
|
|
2926
|
+
teamName,
|
|
2927
|
+
requestId: queuedOutcome.request_id,
|
|
2928
|
+
messageId: queuedOutcome.message_id,
|
|
2774
2929
|
cwd,
|
|
2775
|
-
fallbackNotify: async () => await notifyLeaderAsync(config, leaderTriggerMessage, cwd),
|
|
2776
2930
|
});
|
|
2777
2931
|
}
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2932
|
+
const deferredOutcome = {
|
|
2933
|
+
...queuedOutcome,
|
|
2934
|
+
ok: true,
|
|
2935
|
+
transport: 'mailbox',
|
|
2936
|
+
reason: 'leader_pane_missing_mailbox_persisted',
|
|
2937
|
+
};
|
|
2938
|
+
await logRuntimeDispatchOutcome({
|
|
2939
|
+
cwd,
|
|
2940
|
+
teamName,
|
|
2941
|
+
workerName: 'leader-fixed',
|
|
2942
|
+
requestId: deferredOutcome.request_id,
|
|
2943
|
+
messageId: deferredOutcome.message_id,
|
|
2944
|
+
intent: triggerDirective.intent,
|
|
2945
|
+
outcome: deferredOutcome,
|
|
2946
|
+
});
|
|
2947
|
+
return deferredOutcome;
|
|
2781
2948
|
}
|
|
2782
|
-
const
|
|
2949
|
+
const canLeaderFallbackDirectly = Boolean(config.leader_pane_id) && isTmuxAvailable();
|
|
2950
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2951
|
+
queuedOutcome,
|
|
2952
|
+
transportPreference: canLeaderFallbackDirectly ? transportPreference : 'transport_direct',
|
|
2953
|
+
teamName,
|
|
2954
|
+
workerName: 'leader-fixed',
|
|
2955
|
+
paneId: config.leader_pane_id ?? undefined,
|
|
2956
|
+
messageId: queuedOutcome.message_id,
|
|
2957
|
+
triggerMessage: triggerDirective.text,
|
|
2958
|
+
intent: triggerDirective.intent,
|
|
2959
|
+
config,
|
|
2960
|
+
dispatchPolicy,
|
|
2961
|
+
cwd,
|
|
2962
|
+
fallbackNotify: async () => await notifyLeaderAsync(config, triggerDirective.text, cwd),
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
async function sendRecipientMailboxMessage(params) {
|
|
2966
|
+
const { teamName, fromWorker, toWorker, body, config, dispatchPolicy, cwd } = params;
|
|
2967
|
+
const recipient = config.workers.find((worker) => worker.name === toWorker);
|
|
2783
2968
|
if (!recipient)
|
|
2784
2969
|
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,
|
|
2970
|
+
const triggerDirective = buildMailboxTriggerDirective(toWorker, teamName, 1, resolveInstructionStateRoot(recipient.worktree_path));
|
|
2971
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2972
|
+
const queuedOutcome = await queueDirectMailboxMessage({
|
|
2973
|
+
teamName,
|
|
2791
2974
|
fromWorker,
|
|
2792
2975
|
toWorker,
|
|
2793
2976
|
toWorkerIndex: recipient.index,
|
|
2794
2977
|
toPaneId: recipient.pane_id,
|
|
2795
2978
|
body,
|
|
2796
|
-
triggerMessage,
|
|
2979
|
+
triggerMessage: triggerDirective.text,
|
|
2980
|
+
intent: triggerDirective.intent,
|
|
2797
2981
|
cwd,
|
|
2798
2982
|
transportPreference,
|
|
2799
2983
|
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
@@ -2801,25 +2985,82 @@ export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cw
|
|
|
2801
2985
|
? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
|
|
2802
2986
|
: await notifyWorkerOutcome(config, recipient.index, message, recipient.pane_id)),
|
|
2803
2987
|
});
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2988
|
+
return await finalizeQueuedMailboxDispatch({
|
|
2989
|
+
queuedOutcome,
|
|
2990
|
+
transportPreference,
|
|
2991
|
+
teamName,
|
|
2992
|
+
workerName: recipient.name,
|
|
2993
|
+
workerIndex: recipient.index,
|
|
2994
|
+
paneId: recipient.pane_id,
|
|
2995
|
+
messageId: queuedOutcome.message_id,
|
|
2996
|
+
triggerMessage: triggerDirective.text,
|
|
2997
|
+
intent: triggerDirective.intent,
|
|
2998
|
+
config,
|
|
2999
|
+
dispatchPolicy,
|
|
3000
|
+
cwd,
|
|
3001
|
+
});
|
|
3002
|
+
}
|
|
3003
|
+
async function finalizeBroadcastMailboxOutcomes(params) {
|
|
3004
|
+
const { teamName, outcomes, transportPreference, config, dispatchPolicy, cwd } = params;
|
|
3005
|
+
if (transportPreference !== 'hook_preferred_with_fallback') {
|
|
3006
|
+
return outcomes;
|
|
3007
|
+
}
|
|
3008
|
+
const finalizedOutcomes = [];
|
|
3009
|
+
for (const outcome of outcomes) {
|
|
3010
|
+
const target = outcome.to_worker
|
|
3011
|
+
? (config.workers.find((worker) => worker.name === outcome.to_worker) ?? null)
|
|
3012
|
+
: null;
|
|
3013
|
+
if (!target) {
|
|
3014
|
+
finalizedOutcomes.push({ ...outcome, ok: false, reason: 'missing_worker_index' });
|
|
3015
|
+
continue;
|
|
2809
3016
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
3017
|
+
const triggerDirective = buildMailboxTriggerDirective(target.name, teamName, 1, resolveInstructionStateRoot(target.worktree_path));
|
|
3018
|
+
finalizedOutcomes.push(await finalizeQueuedMailboxDispatch({
|
|
3019
|
+
queuedOutcome: outcome,
|
|
3020
|
+
transportPreference,
|
|
3021
|
+
teamName,
|
|
3022
|
+
workerName: target.name,
|
|
3023
|
+
workerIndex: target.index,
|
|
3024
|
+
paneId: target.pane_id,
|
|
2816
3025
|
messageId: outcome.message_id,
|
|
2817
|
-
triggerMessage,
|
|
3026
|
+
triggerMessage: triggerDirective.text,
|
|
3027
|
+
intent: triggerDirective.intent,
|
|
3028
|
+
config,
|
|
3029
|
+
dispatchPolicy,
|
|
3030
|
+
cwd,
|
|
3031
|
+
}));
|
|
3032
|
+
}
|
|
3033
|
+
return finalizedOutcomes;
|
|
3034
|
+
}
|
|
3035
|
+
export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cwd) {
|
|
3036
|
+
const sanitized = sanitizeTeamName(teamName);
|
|
3037
|
+
const config = await readTeamConfig(sanitized, cwd);
|
|
3038
|
+
if (!config)
|
|
3039
|
+
throw new Error(`Team ${sanitized} not found`);
|
|
3040
|
+
const manifest = await readTeamManifestV2(sanitized, cwd);
|
|
3041
|
+
const dispatchPolicy = resolveDispatchPolicy(manifest?.policy, config.worker_launch_mode);
|
|
3042
|
+
if (toWorker === 'leader-fixed') {
|
|
3043
|
+
const finalOutcome = await sendLeaderMailboxMessage({
|
|
3044
|
+
teamName: sanitized,
|
|
3045
|
+
fromWorker,
|
|
3046
|
+
body,
|
|
2818
3047
|
config,
|
|
2819
3048
|
dispatchPolicy,
|
|
2820
3049
|
cwd,
|
|
2821
3050
|
});
|
|
3051
|
+
if (!finalOutcome.ok)
|
|
3052
|
+
throw new Error(`mailbox_notify_failed:${finalOutcome.reason}`);
|
|
3053
|
+
return finalOutcome;
|
|
2822
3054
|
}
|
|
3055
|
+
const finalOutcome = await sendRecipientMailboxMessage({
|
|
3056
|
+
teamName: sanitized,
|
|
3057
|
+
fromWorker,
|
|
3058
|
+
toWorker,
|
|
3059
|
+
body,
|
|
3060
|
+
config,
|
|
3061
|
+
dispatchPolicy,
|
|
3062
|
+
cwd,
|
|
3063
|
+
});
|
|
2823
3064
|
if (!finalOutcome.ok)
|
|
2824
3065
|
throw new Error(`mailbox_notify_failed:${finalOutcome.reason}`);
|
|
2825
3066
|
return finalOutcome;
|
|
@@ -2831,16 +3072,15 @@ export async function broadcastWorkerMessage(teamName, fromWorker, body, cwd) {
|
|
|
2831
3072
|
throw new Error(`Team ${sanitized} not found`);
|
|
2832
3073
|
const manifest = await readTeamManifestV2(sanitized, cwd);
|
|
2833
3074
|
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');
|
|
3075
|
+
const transportPreference = resolveWorkerMailboxTransportPreference(config, dispatchPolicy);
|
|
2837
3076
|
const outcomes = await queueBroadcastMailboxMessage({
|
|
2838
3077
|
teamName: sanitized,
|
|
2839
3078
|
fromWorker,
|
|
2840
3079
|
recipients: config.workers.map((w) => ({ workerName: w.name, workerIndex: w.index, paneId: w.pane_id })),
|
|
2841
3080
|
body,
|
|
2842
3081
|
cwd,
|
|
2843
|
-
triggerFor: (workerName) =>
|
|
3082
|
+
triggerFor: (workerName) => buildMailboxTriggerDirective(workerName, sanitized, 1, resolveInstructionStateRoot(config.workers.find((worker) => worker.name === workerName)?.worktree_path)).text,
|
|
3083
|
+
intentFor: () => 'pending-mailbox-review',
|
|
2844
3084
|
transportPreference,
|
|
2845
3085
|
fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
|
|
2846
3086
|
notify: async (target, message) => transportPreference === 'hook_preferred_with_fallback'
|
|
@@ -2849,37 +3089,14 @@ export async function broadcastWorkerMessage(teamName, fromWorker, body, cwd) {
|
|
|
2849
3089
|
? await notifyWorkerOutcome(config, target.workerIndex, message, target.paneId)
|
|
2850
3090
|
: { ok: false, transport: 'none', reason: 'missing_worker_index' }),
|
|
2851
3091
|
});
|
|
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;
|
|
3092
|
+
const results = await finalizeBroadcastMailboxOutcomes({
|
|
3093
|
+
teamName: sanitized,
|
|
3094
|
+
outcomes,
|
|
3095
|
+
transportPreference,
|
|
3096
|
+
config,
|
|
3097
|
+
dispatchPolicy,
|
|
3098
|
+
cwd,
|
|
3099
|
+
});
|
|
2883
3100
|
if (results.some((result) => !result.ok)) {
|
|
2884
3101
|
const firstFailure = results.find((result) => !result.ok);
|
|
2885
3102
|
throw new Error(`mailbox_notify_failed:${firstFailure?.reason ?? 'unknown'}`);
|