oh-my-codex 0.7.4 → 0.7.6

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.
Files changed (140) hide show
  1. package/README.md +14 -0
  2. package/dist/cli/__tests__/index.test.js +25 -1
  3. package/dist/cli/__tests__/index.test.js.map +1 -1
  4. package/dist/cli/__tests__/ralph.test.d.ts +2 -0
  5. package/dist/cli/__tests__/ralph.test.d.ts.map +1 -0
  6. package/dist/cli/__tests__/ralph.test.js +64 -0
  7. package/dist/cli/__tests__/ralph.test.js.map +1 -0
  8. package/dist/cli/__tests__/team-decompose.test.d.ts +2 -0
  9. package/dist/cli/__tests__/team-decompose.test.d.ts.map +1 -0
  10. package/dist/cli/__tests__/team-decompose.test.js +67 -0
  11. package/dist/cli/__tests__/team-decompose.test.js.map +1 -0
  12. package/dist/cli/index.d.ts +6 -0
  13. package/dist/cli/index.d.ts.map +1 -1
  14. package/dist/cli/index.js +25 -3
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/ralph.d.ts +12 -0
  17. package/dist/cli/ralph.d.ts.map +1 -1
  18. package/dist/cli/ralph.js +58 -1
  19. package/dist/cli/ralph.js.map +1 -1
  20. package/dist/cli/team.d.ts +18 -0
  21. package/dist/cli/team.d.ts.map +1 -1
  22. package/dist/cli/team.js +108 -16
  23. package/dist/cli/team.js.map +1 -1
  24. package/dist/config/generator.d.ts.map +1 -1
  25. package/dist/config/generator.js +8 -0
  26. package/dist/config/generator.js.map +1 -1
  27. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +10 -7
  28. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  29. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +11 -7
  30. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  31. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +199 -0
  32. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  33. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +11 -0
  34. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +1 -0
  35. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +266 -0
  36. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -0
  37. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +4 -5
  38. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  39. package/dist/hooks/__tests__/tmux-hook-engine.test.js +36 -1
  40. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -1
  41. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts +2 -0
  42. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts.map +1 -0
  43. package/dist/mcp/__tests__/team-server-cleanup.test.js +219 -0
  44. package/dist/mcp/__tests__/team-server-cleanup.test.js.map +1 -0
  45. package/dist/mcp/bootstrap.d.ts +1 -1
  46. package/dist/mcp/bootstrap.d.ts.map +1 -1
  47. package/dist/mcp/bootstrap.js +1 -0
  48. package/dist/mcp/bootstrap.js.map +1 -1
  49. package/dist/mcp/state-server.d.ts.map +1 -1
  50. package/dist/mcp/state-server.js +11 -2
  51. package/dist/mcp/state-server.js.map +1 -1
  52. package/dist/mcp/team-server.d.ts +24 -0
  53. package/dist/mcp/team-server.d.ts.map +1 -0
  54. package/dist/mcp/team-server.js +419 -0
  55. package/dist/mcp/team-server.js.map +1 -0
  56. package/dist/notifications/__tests__/verbosity.test.js +35 -0
  57. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  58. package/dist/notifications/config.d.ts.map +1 -1
  59. package/dist/notifications/config.js +4 -2
  60. package/dist/notifications/config.js.map +1 -1
  61. package/dist/notifications/tmux.d.ts.map +1 -1
  62. package/dist/notifications/tmux.js +11 -2
  63. package/dist/notifications/tmux.js.map +1 -1
  64. package/dist/notifications/types.d.ts +4 -0
  65. package/dist/notifications/types.d.ts.map +1 -1
  66. package/dist/openclaw/__tests__/index.test.js +40 -0
  67. package/dist/openclaw/__tests__/index.test.js.map +1 -1
  68. package/dist/openclaw/index.d.ts.map +1 -1
  69. package/dist/openclaw/index.js +1 -0
  70. package/dist/openclaw/index.js.map +1 -1
  71. package/dist/openclaw/types.d.ts +2 -0
  72. package/dist/openclaw/types.d.ts.map +1 -1
  73. package/dist/team/__tests__/role-router.test.d.ts +2 -0
  74. package/dist/team/__tests__/role-router.test.d.ts.map +1 -0
  75. package/dist/team/__tests__/role-router.test.js +204 -0
  76. package/dist/team/__tests__/role-router.test.js.map +1 -0
  77. package/dist/team/__tests__/runtime-cli.test.d.ts +2 -0
  78. package/dist/team/__tests__/runtime-cli.test.d.ts.map +1 -0
  79. package/dist/team/__tests__/runtime-cli.test.js +72 -0
  80. package/dist/team/__tests__/runtime-cli.test.js.map +1 -0
  81. package/dist/team/__tests__/runtime.test.js +194 -5
  82. package/dist/team/__tests__/runtime.test.js.map +1 -1
  83. package/dist/team/__tests__/scaling.test.js +132 -2
  84. package/dist/team/__tests__/scaling.test.js.map +1 -1
  85. package/dist/team/__tests__/tmux-session.test.js +86 -7
  86. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  87. package/dist/team/__tests__/worker-bootstrap.test.js +38 -0
  88. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  89. package/dist/team/__tests__/worktree.test.js +27 -1
  90. package/dist/team/__tests__/worktree.test.js.map +1 -1
  91. package/dist/team/idle-nudge.d.ts +53 -0
  92. package/dist/team/idle-nudge.d.ts.map +1 -0
  93. package/dist/team/idle-nudge.js +140 -0
  94. package/dist/team/idle-nudge.js.map +1 -0
  95. package/dist/team/mcp-comm.d.ts +1 -1
  96. package/dist/team/mcp-comm.d.ts.map +1 -1
  97. package/dist/team/role-router.d.ts +32 -0
  98. package/dist/team/role-router.d.ts.map +1 -0
  99. package/dist/team/role-router.js +137 -0
  100. package/dist/team/role-router.js.map +1 -0
  101. package/dist/team/runtime-cli.d.ts +18 -0
  102. package/dist/team/runtime-cli.d.ts.map +1 -0
  103. package/dist/team/runtime-cli.js +238 -0
  104. package/dist/team/runtime-cli.js.map +1 -0
  105. package/dist/team/runtime.d.ts +4 -0
  106. package/dist/team/runtime.d.ts.map +1 -1
  107. package/dist/team/runtime.js +108 -42
  108. package/dist/team/runtime.js.map +1 -1
  109. package/dist/team/scaling.d.ts +1 -0
  110. package/dist/team/scaling.d.ts.map +1 -1
  111. package/dist/team/scaling.js +41 -20
  112. package/dist/team/scaling.js.map +1 -1
  113. package/dist/team/state.d.ts +2 -1
  114. package/dist/team/state.d.ts.map +1 -1
  115. package/dist/team/state.js.map +1 -1
  116. package/dist/team/tmux-session.d.ts +42 -2
  117. package/dist/team/tmux-session.d.ts.map +1 -1
  118. package/dist/team/tmux-session.js +219 -65
  119. package/dist/team/tmux-session.js.map +1 -1
  120. package/dist/team/worker-bootstrap.d.ts +2 -0
  121. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  122. package/dist/team/worker-bootstrap.js +29 -5
  123. package/dist/team/worker-bootstrap.js.map +1 -1
  124. package/dist/team/worktree.d.ts +5 -1
  125. package/dist/team/worktree.d.ts.map +1 -1
  126. package/dist/team/worktree.js +28 -16
  127. package/dist/team/worktree.js.map +1 -1
  128. package/package.json +1 -1
  129. package/scripts/notify-hook/log.js +5 -0
  130. package/scripts/notify-hook/team-dispatch.js +44 -8
  131. package/scripts/notify-hook/team-worker.js +26 -4
  132. package/scripts/notify-hook/tmux-injection.js +45 -4
  133. package/scripts/notify-hook/visual-verdict.js +109 -0
  134. package/scripts/notify-hook.js +26 -0
  135. package/scripts/tmux-hook-engine.js +24 -0
  136. package/skills/autopilot/SKILL.md +2 -2
  137. package/skills/doctor/SKILL.md +1 -1
  138. package/skills/help/SKILL.md +3 -3
  139. package/skills/skill/SKILL.md +32 -32
  140. package/skills/team/SKILL.md +43 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * CLI entry point for team runtime.
3
+ * Reads JSON config from stdin, runs startTeam/monitorTeam/shutdownTeam,
4
+ * writes structured JSON result to stdout.
5
+ *
6
+ * Spawned by omx_run_team_start in state-server.ts.
7
+ */
8
+ import { readdirSync, readFileSync } from 'fs';
9
+ import { writeFile, rename } from 'fs/promises';
10
+ import { join } from 'path';
11
+ import { startTeam, monitorTeam, shutdownTeam } from './runtime.js';
12
+ import { teamReadConfig as readTeamConfig } from './team-ops.js';
13
+ async function writePanesFile(jobId, paneIds, leaderPaneId) {
14
+ const omxJobsDir = process.env.OMX_JOBS_DIR;
15
+ if (!jobId || !omxJobsDir)
16
+ return;
17
+ const panesPath = join(omxJobsDir, `${jobId}-panes.json`);
18
+ await writeFile(panesPath + '.tmp', JSON.stringify({ paneIds: [...paneIds], leaderPaneId }));
19
+ await rename(panesPath + '.tmp', panesPath);
20
+ }
21
+ export async function loadLivePaneState(teamName, cwd) {
22
+ const config = await readTeamConfig(teamName, cwd);
23
+ if (!config)
24
+ return null;
25
+ return {
26
+ paneIds: config.workers
27
+ .map((worker) => worker.pane_id)
28
+ .filter((paneId) => typeof paneId === 'string' && paneId.trim().length > 0),
29
+ leaderPaneId: config.leader_pane_id ?? '',
30
+ };
31
+ }
32
+ export async function shutdownWithForceFallback(teamName, cwd) {
33
+ try {
34
+ await shutdownTeam(teamName, cwd);
35
+ }
36
+ catch (error) {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ if (!message.includes('shutdown_gate_blocked') && !message.includes('shutdown_rejected')) {
39
+ throw error;
40
+ }
41
+ await shutdownTeam(teamName, cwd, { force: true });
42
+ }
43
+ }
44
+ export function detectDeadWorkerFailure(deadWorkerCount, liveWorkerPaneCount, hasOutstandingWork, phase) {
45
+ const allWorkersDead = liveWorkerPaneCount > 0 && deadWorkerCount >= liveWorkerPaneCount;
46
+ return {
47
+ deadWorkerFailure: allWorkersDead && hasOutstandingWork,
48
+ fixingWithNoWorkers: phase === 'team-fix' && allWorkersDead,
49
+ };
50
+ }
51
+ function collectTaskResults(stateRoot, teamName) {
52
+ const tasksDir = join(stateRoot, 'team', teamName, 'tasks');
53
+ try {
54
+ const files = readdirSync(tasksDir).filter(f => f.endsWith('.json'));
55
+ return files.map(f => {
56
+ try {
57
+ const raw = readFileSync(join(tasksDir, f), 'utf-8');
58
+ const task = JSON.parse(raw);
59
+ return {
60
+ taskId: task.id ?? f.replace('.json', ''),
61
+ status: task.status ?? 'unknown',
62
+ summary: (task.result ?? task.summary) ?? '',
63
+ };
64
+ }
65
+ catch {
66
+ return { taskId: f.replace('.json', ''), status: 'unknown', summary: '' };
67
+ }
68
+ });
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ }
74
+ async function main() {
75
+ const startTime = Date.now();
76
+ // Read stdin
77
+ const chunks = [];
78
+ for await (const chunk of process.stdin) {
79
+ chunks.push(chunk);
80
+ }
81
+ const rawInput = Buffer.concat(chunks).toString('utf-8').trim();
82
+ let input;
83
+ try {
84
+ input = JSON.parse(rawInput);
85
+ }
86
+ catch (err) {
87
+ process.stderr.write(`[runtime-cli] Failed to parse stdin JSON: ${err}\n`);
88
+ process.exit(1);
89
+ }
90
+ // Validate required fields
91
+ const missing = [];
92
+ if (!input.teamName)
93
+ missing.push('teamName');
94
+ if (!input.agentTypes || !Array.isArray(input.agentTypes) || input.agentTypes.length === 0)
95
+ missing.push('agentTypes');
96
+ if (!input.tasks || !Array.isArray(input.tasks) || input.tasks.length === 0)
97
+ missing.push('tasks');
98
+ if (!input.cwd)
99
+ missing.push('cwd');
100
+ if (missing.length > 0) {
101
+ process.stderr.write(`[runtime-cli] Missing required fields: ${missing.join(', ')}\n`);
102
+ process.exit(1);
103
+ }
104
+ const { teamName, agentTypes, tasks, cwd, pollIntervalMs = 5000, } = input;
105
+ const workerCount = input.workerCount ?? agentTypes.length;
106
+ const stateRoot = join(cwd, '.omx', 'state');
107
+ let runtime = null;
108
+ let finalStatus = 'failed';
109
+ let pollActive = true;
110
+ function exitCodeFor(status) {
111
+ return status === 'completed' ? 0 : 1;
112
+ }
113
+ async function doShutdown(status) {
114
+ pollActive = false;
115
+ finalStatus = status;
116
+ // 1. Collect task results
117
+ const taskResults = collectTaskResults(stateRoot, teamName);
118
+ // 2. Shutdown team
119
+ if (runtime) {
120
+ try {
121
+ if (status === 'failed') {
122
+ // Failure/cancellation path must force cleanup to bypass shutdown gate.
123
+ await shutdownTeam(runtime.teamName, runtime.cwd, { force: true });
124
+ }
125
+ else {
126
+ await shutdownWithForceFallback(runtime.teamName, runtime.cwd);
127
+ }
128
+ }
129
+ catch (err) {
130
+ process.stderr.write(`[runtime-cli] shutdownTeam error: ${err}\n`);
131
+ }
132
+ }
133
+ const duration = (Date.now() - startTime) / 1000;
134
+ const output = {
135
+ status: finalStatus,
136
+ teamName,
137
+ taskResults,
138
+ duration,
139
+ workerCount,
140
+ };
141
+ // 3. Write result to stdout
142
+ process.stdout.write(JSON.stringify(output) + '\n');
143
+ // 4. Exit
144
+ process.exit(exitCodeFor(status));
145
+ }
146
+ // Register signal handlers before poll loop
147
+ process.on('SIGINT', () => {
148
+ process.stderr.write('[runtime-cli] Received SIGINT, shutting down...\n');
149
+ doShutdown('failed').catch(() => process.exit(1));
150
+ });
151
+ process.on('SIGTERM', () => {
152
+ process.stderr.write('[runtime-cli] Received SIGTERM, shutting down...\n');
153
+ doShutdown('failed').catch(() => process.exit(1));
154
+ });
155
+ // Start the team — OMX's startTeam takes individual parameters
156
+ const agentType = agentTypes[0] ?? 'codex';
157
+ try {
158
+ runtime = await startTeam(teamName, tasks.map(t => t.subject).join('; '), agentType, workerCount, tasks, cwd);
159
+ }
160
+ catch (err) {
161
+ process.stderr.write(`[runtime-cli] startTeam failed: ${err}\n`);
162
+ process.exit(1);
163
+ }
164
+ // Persist pane IDs so MCP server can clean up explicitly via omx_run_team_cleanup.
165
+ const jobId = process.env.OMX_JOB_ID;
166
+ try {
167
+ const livePanes = await loadLivePaneState(teamName, cwd);
168
+ if (livePanes) {
169
+ await writePanesFile(jobId, livePanes.paneIds, livePanes.leaderPaneId);
170
+ }
171
+ else {
172
+ const fallbackPaneIds = runtime.config.workers
173
+ .map((worker) => worker.pane_id)
174
+ .filter((paneId) => typeof paneId === 'string' && paneId.trim().length > 0);
175
+ await writePanesFile(jobId, fallbackPaneIds, runtime.config.leader_pane_id ?? '');
176
+ }
177
+ }
178
+ catch (err) {
179
+ process.stderr.write(`[runtime-cli] Failed to persist pane IDs: ${err}\n`);
180
+ }
181
+ // Poll loop
182
+ while (pollActive) {
183
+ await new Promise(r => setTimeout(r, pollIntervalMs));
184
+ if (!pollActive)
185
+ break;
186
+ let snap;
187
+ try {
188
+ snap = await monitorTeam(teamName, cwd);
189
+ }
190
+ catch (err) {
191
+ process.stderr.write(`[runtime-cli] monitorTeam error: ${err}\n`);
192
+ continue;
193
+ }
194
+ if (!snap) {
195
+ process.stderr.write(`[runtime-cli] monitorTeam returned null\n`);
196
+ continue;
197
+ }
198
+ // Refresh pane IDs (workers may have scaled)
199
+ let livePaneState = null;
200
+ try {
201
+ livePaneState = await loadLivePaneState(teamName, cwd);
202
+ if (livePaneState) {
203
+ await writePanesFile(jobId, livePaneState.paneIds, livePaneState.leaderPaneId);
204
+ }
205
+ }
206
+ catch (err) {
207
+ process.stderr.write(`[runtime-cli] Failed to persist pane IDs: ${err}\n`);
208
+ }
209
+ const perfMs = snap.performance?.total_ms ?? 0;
210
+ process.stderr.write(`[runtime-cli] phase=${snap.phase} pending=${snap.tasks.pending} inProgress=${snap.tasks.in_progress} completed=${snap.tasks.completed} failed=${snap.tasks.failed} dead=${snap.deadWorkers.length} monitorMs=${perfMs.toFixed(0)}\n`);
211
+ // Check completion
212
+ if (snap.phase === 'complete') {
213
+ await doShutdown('completed');
214
+ return;
215
+ }
216
+ if (snap.phase === 'failed' || snap.phase === 'cancelled') {
217
+ await doShutdown('failed');
218
+ return;
219
+ }
220
+ // Check failure heuristics
221
+ const hasOutstandingWork = (snap.tasks.pending + snap.tasks.in_progress) > 0;
222
+ const liveWorkerPaneCount = livePaneState?.paneIds.length ?? 0;
223
+ const { deadWorkerFailure, fixingWithNoWorkers } = detectDeadWorkerFailure(snap.deadWorkers.length, liveWorkerPaneCount, hasOutstandingWork, snap.phase);
224
+ if (deadWorkerFailure || fixingWithNoWorkers) {
225
+ process.stderr.write(`[runtime-cli] Failure detected: deadWorkerFailure=${deadWorkerFailure} fixingWithNoWorkers=${fixingWithNoWorkers}\n`);
226
+ await doShutdown('failed');
227
+ return;
228
+ }
229
+ }
230
+ }
231
+ const shouldAutoStart = process.env.OMX_RUNTIME_CLI_DISABLE_AUTO_START !== '1';
232
+ if (shouldAutoStart) {
233
+ main().catch(err => {
234
+ process.stderr.write(`[runtime-cli] Fatal error: ${err}\n`);
235
+ process.exit(1);
236
+ });
237
+ }
238
+ //# sourceMappingURL=runtime-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-cli.js","sourceRoot":"","sources":["../../src/team/runtime-cli.ts"],"names":[],"mappings":"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"}
@@ -45,9 +45,13 @@ export interface TeamRuntime {
45
45
  }
46
46
  interface ShutdownOptions {
47
47
  force?: boolean;
48
+ /** When true, applies ralph-specific cleanup policy: no force-kill on failure, detailed audit logging. */
49
+ ralph?: boolean;
48
50
  }
49
51
  export interface TeamStartOptions {
50
52
  worktreeMode?: WorktreeMode;
53
+ /** When true, applies ralph-specific cleanup policy during startup rollback (skip branch deletion). */
54
+ ralph?: boolean;
51
55
  }
52
56
  export { TEAM_LOW_COMPLEXITY_DEFAULT_MODEL };
53
57
  export declare function resolveCanonicalTeamStateRoot(leaderCwd: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/team/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/team/runtime.ts"],"names":[],"mappings":"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"}
@@ -3,10 +3,12 @@ import { existsSync } from 'fs';
3
3
  import { readdir, readFile } from 'fs/promises';
4
4
  import { performance } from 'perf_hooks';
5
5
  import { spawn } from 'child_process';
6
- import { sanitizeTeamName, isTmuxAvailable, createTeamSession, buildWorkerProcessLaunchSpec, resolveTeamWorkerCli, resolveTeamWorkerCliPlan, resolveTeamWorkerLaunchMode, waitForWorkerReady, dismissTrustPromptIfPresent, sleepFractionalSeconds, sendToWorker, sendToWorkerStdin, notifyLeaderStatus, isWorkerAlive, getWorkerPanePid, killWorker, killWorkerByPaneId, unregisterResizeHook, destroyTeamSession, listTeamSessions, } from './tmux-session.js';
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, teamNormalizePolicy as normalizeTeamPolicy, teamClaimTask as claimTask, teamReleaseTaskClaim as releaseTaskClaim, teamAppendEvent as appendTeamEvent, teamReadTaskApproval as readTaskApproval, teamListMailbox as listMailboxMessages, 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';
6
+ import { sanitizeTeamName, isTmuxAvailable, createTeamSession, buildWorkerProcessLaunchSpec, resolveTeamWorkerCli, resolveTeamWorkerCliPlan, resolveTeamWorkerLaunchMode, waitForWorkerReady, dismissTrustPromptIfPresent, sleepFractionalSeconds, sendToWorker, sendToLeaderPane, sendToWorkerStdin, isWorkerAlive, getWorkerPanePid, killWorkerByPaneIdAsync, teardownWorkerPanes, unregisterResizeHook, destroyTeamSession, listTeamSessions, } from './tmux-session.js';
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, teamNormalizePolicy as normalizeTeamPolicy, teamClaimTask as claimTask, teamReleaseTaskClaim as releaseTaskClaim, 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
9
  import { generateWorkerOverlay, writeTeamWorkerInstructionsFile, removeTeamWorkerInstructionsFile, generateInitialInbox, generateTaskAssignmentInbox, generateShutdownInbox, generateTriggerMessage, generateMailboxTriggerMessage, } from './worker-bootstrap.js';
10
+ import { loadRolePrompt } from './role-router.js';
11
+ import { codexPromptsDir } from '../utils/paths.js';
10
12
  import { isLowComplexityAgentType, resolveTeamWorkerLaunchArgs, TEAM_LOW_COMPLEXITY_DEFAULT_MODEL, resolveTeamLowComplexityDefaultModel, parseTeamWorkerLaunchArgs, splitWorkerLaunchArgs, } from './model-contract.js';
11
13
  import { inferPhaseTargetFromTaskCounts, reconcilePhaseStateForMonitor } from './phase-controller.js';
12
14
  import { getTeamTmuxSessions } from '../notifications/tmux.js';
@@ -401,11 +403,24 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
401
403
  const workerWorkspace = workerWorkspaceByName.get(workerName) ?? { cwd: leaderCwd };
402
404
  // Get tasks assigned to this worker
403
405
  const workerTasks = allTasks.filter(t => t.owner === workerName);
406
+ // Resolve per-worker role from assigned task roles
407
+ const taskRoles = workerTasks.map(t => t.role).filter(Boolean);
408
+ const uniqueTaskRoles = new Set(taskRoles);
409
+ const workerRole = taskRoles.length > 0 && uniqueTaskRoles.size === 1
410
+ ? taskRoles[0]
411
+ : agentType;
412
+ if (uniqueTaskRoles.size > 1) {
413
+ console.log(`[omx:team] ${workerName}: mixed task roles [${[...uniqueTaskRoles].join(', ')}], falling back to ${agentType}`);
414
+ }
415
+ // Load role-specific prompt content if role differs from default
416
+ const rolePromptContent = workerRole !== agentType
417
+ ? await loadRolePrompt(workerRole, codexPromptsDir())
418
+ : null;
404
419
  // Write worker identity
405
420
  const identity = {
406
421
  name: workerName,
407
422
  index: i,
408
- role: agentType,
423
+ role: workerRole,
409
424
  worker_cli: workerCliPlan[i - 1],
410
425
  assigned_tasks: workerTasks.map(t => t.id),
411
426
  working_dir: workerWorkspace.cwd,
@@ -448,6 +463,8 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
448
463
  const inbox = generateInitialInbox(workerName, sanitized, agentType, workerTasks, {
449
464
  teamStateRoot,
450
465
  leaderCwd,
466
+ workerRole,
467
+ rolePromptContent: rolePromptContent ?? undefined,
451
468
  });
452
469
  const trigger = generateTriggerMessage(workerName, sanitized);
453
470
  const maxStartupDispatchRetries = 3;
@@ -524,13 +541,13 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
524
541
  if (sessionName.includes(':')) {
525
542
  for (const paneId of createdWorkerPaneIds) {
526
543
  try {
527
- killWorkerByPaneId(paneId, createdLeaderPaneId);
544
+ await killWorkerByPaneIdAsync(paneId, createdLeaderPaneId);
528
545
  }
529
546
  catch { /* ignore */ }
530
547
  }
531
548
  if (config?.hud_pane_id) {
532
549
  try {
533
- killWorkerByPaneId(config.hud_pane_id, createdLeaderPaneId);
550
+ await killWorkerByPaneIdAsync(config.hud_pane_id, createdLeaderPaneId);
534
551
  }
535
552
  catch { /* ignore */ }
536
553
  }
@@ -573,7 +590,9 @@ export async function startTeam(teamName, task, agentType, workerCount, tasks, c
573
590
  }
574
591
  if (provisionedWorktrees.length > 0) {
575
592
  try {
576
- await rollbackProvisionedWorktrees(provisionedWorktrees);
593
+ await rollbackProvisionedWorktrees(provisionedWorktrees, {
594
+ skipBranchDeletion: options.ralph === true,
595
+ });
577
596
  }
578
597
  catch (cleanupError) {
579
598
  rollbackErrors.push(`rollbackProvisionedWorktrees: ${String(cleanupError)}`);
@@ -691,6 +710,20 @@ export async function monitorTeam(teamName, cwd) {
691
710
  const mailboxDeliveryStartMs = performance.now();
692
711
  const mailboxNotifiedByMessageId = await deliverPendingMailboxMessages(sanitized, config, workers, previousSnapshot?.mailboxNotifiedByMessageId ?? {}, dispatchPolicy, cwd);
693
712
  const mailboxDeliveryMs = performance.now() - mailboxDeliveryStartMs;
713
+ // Prune ephemeral status messages from leader mailbox (TTL: 60s)
714
+ try {
715
+ const leaderMailbox = await listMailboxMessages(sanitized, 'leader-fixed', cwd);
716
+ const now = Date.now();
717
+ for (const msg of leaderMailbox) {
718
+ if (msg.from_worker === 'system' && msg.created_at) {
719
+ const age = now - new Date(msg.created_at).getTime();
720
+ if (age > 60_000) {
721
+ await markMessageDelivered(sanitized, 'leader-fixed', msg.message_id, cwd);
722
+ }
723
+ }
724
+ }
725
+ }
726
+ catch { /* best-effort */ }
694
727
  const updatedAt = new Date().toISOString();
695
728
  const totalMs = performance.now() - monitorStartMs;
696
729
  await writeMonitorSnapshot(sanitized, {
@@ -788,7 +821,7 @@ export async function assignTask(teamName, workerName, taskId, cwd) {
788
821
  waitForWorkerReady(config.tmux_session, workerInfo.index, 15_000, workerInfo.pane_id);
789
822
  }
790
823
  else {
791
- sleepFractionalSeconds(assignRetryDelayS);
824
+ await new Promise(r => setTimeout(r, assignRetryDelayS * 1000));
792
825
  }
793
826
  }
794
827
  }
@@ -827,6 +860,7 @@ export async function reassignTask(teamName, taskId, _fromWorker, toWorker, cwd)
827
860
  */
828
861
  export async function shutdownTeam(teamName, cwd, options = {}) {
829
862
  const force = options.force === true;
863
+ const ralph = options.ralph === true;
830
864
  const sanitized = sanitizeTeamName(teamName);
831
865
  const config = await readTeamConfig(sanitized, cwd);
832
866
  if (!config) {
@@ -854,10 +888,22 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
854
888
  await appendTeamEvent(sanitized, {
855
889
  type: 'shutdown_gate',
856
890
  worker: 'leader-fixed',
857
- reason: `allowed=${gate.allowed} total=${gate.total} pending=${gate.pending} blocked=${gate.blocked} in_progress=${gate.in_progress} completed=${gate.completed} failed=${gate.failed}`,
891
+ reason: `allowed=${gate.allowed} total=${gate.total} pending=${gate.pending} blocked=${gate.blocked} in_progress=${gate.in_progress} completed=${gate.completed} failed=${gate.failed}${ralph ? ' policy=ralph' : ''}`,
858
892
  }, cwd).catch(() => { });
859
893
  if (!gate.allowed) {
860
- throw new Error(`shutdown_gate_blocked:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`);
894
+ const hasActiveWork = gate.pending > 0 || gate.blocked > 0 || gate.in_progress > 0;
895
+ if (ralph && !hasActiveWork) {
896
+ // Ralph policy: bypass on failure-only scenarios (no pending/blocked/in_progress tasks).
897
+ // This allows the ralph loop to retry rather than leaving stale team state.
898
+ await appendTeamEvent(sanitized, {
899
+ type: 'ralph_cleanup_policy',
900
+ worker: 'leader-fixed',
901
+ reason: `gate_bypassed:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`,
902
+ }, cwd).catch(() => { });
903
+ }
904
+ else {
905
+ throw new Error(`shutdown_gate_blocked:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`);
906
+ }
861
907
  }
862
908
  }
863
909
  if (force) {
@@ -954,19 +1000,13 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
954
1000
  if (resizeHookWarning) {
955
1001
  console.warn(`[team shutdown] ${sanitized}: ${resizeHookWarning}; continuing teardown`);
956
1002
  }
957
- for (const w of config.workers) {
958
- try {
959
- // Guard: never kill the leader's own pane or the HUD pane.
960
- if (leaderPaneId && w.pane_id === leaderPaneId)
961
- continue;
962
- if (hudPaneId && w.pane_id === hudPaneId)
963
- continue;
964
- if (isWorkerAlive(sessionName, w.index, w.pane_id)) {
965
- killWorker(sessionName, w.index, w.pane_id, leaderPaneId ?? undefined);
966
- }
967
- }
968
- catch { /* ignore */ }
969
- }
1003
+ const workerPaneIds = config.workers
1004
+ .map((w) => w.pane_id)
1005
+ .filter((paneId) => typeof paneId === 'string' && paneId.trim().length > 0);
1006
+ await teardownWorkerPanes(workerPaneIds, {
1007
+ leaderPaneId,
1008
+ hudPaneId,
1009
+ });
970
1010
  // 4. Destroy tmux session
971
1011
  if (!sessionName.includes(':')) {
972
1012
  try {
@@ -993,7 +1033,19 @@ export async function shutdownTeam(teamName, cwd, options = {}) {
993
1033
  }
994
1034
  catch { /* ignore */ }
995
1035
  restoreTeamModelInstructionsFile(sanitized);
996
- // 6. Cleanup state
1036
+ // 6. Ralph stricter completion logging
1037
+ if (ralph) {
1038
+ const finalTasks = await listTasks(sanitized, cwd).catch(() => []);
1039
+ const completed = finalTasks.filter((t) => t.status === 'completed').length;
1040
+ const failed = finalTasks.filter((t) => t.status === 'failed').length;
1041
+ const pending = finalTasks.filter((t) => t.status === 'pending').length;
1042
+ await appendTeamEvent(sanitized, {
1043
+ type: 'ralph_cleanup_summary',
1044
+ worker: 'leader-fixed',
1045
+ reason: `total=${finalTasks.length} completed=${completed} failed=${failed} pending=${pending} force=${force}`,
1046
+ }, cwd).catch(() => { });
1047
+ }
1048
+ // 7. Cleanup state
997
1049
  await cleanupTeamState(sanitized, cwd);
998
1050
  }
999
1051
  /**
@@ -1144,7 +1196,7 @@ async function emitMonitorDerivedEvents(teamName, tasks, workers, previous, cwd)
1144
1196
  }
1145
1197
  }
1146
1198
  }
1147
- function notifyWorkerOutcome(config, workerIndex, message, workerPaneId) {
1199
+ async function notifyWorkerOutcome(config, workerIndex, message, workerPaneId) {
1148
1200
  const worker = config.workers.find((candidate) => candidate.index === workerIndex);
1149
1201
  if (!worker)
1150
1202
  return { ok: false, transport: 'none', reason: 'worker_not_found' };
@@ -1168,7 +1220,7 @@ function notifyWorkerOutcome(config, workerIndex, message, workerPaneId) {
1168
1220
  return { ok: false, transport: 'tmux_send_keys', reason: 'tmux_unavailable' };
1169
1221
  }
1170
1222
  try {
1171
- sendToWorker(config.tmux_session, workerIndex, message, workerPaneId, worker.worker_cli);
1223
+ await sendToWorker(config.tmux_session, workerIndex, message, workerPaneId, worker.worker_cli);
1172
1224
  return { ok: true, transport: 'tmux_send_keys', reason: 'tmux_send_keys_sent' };
1173
1225
  }
1174
1226
  catch (error) {
@@ -1240,7 +1292,7 @@ async function dispatchCriticalInboxInstruction(params) {
1240
1292
  return { ok: true, transport: 'hook', reason: `hook_receipt_${receipt.status}`, request_id: queued.request_id };
1241
1293
  }
1242
1294
  if (receipt?.status === 'failed') {
1243
- const fallback = notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
1295
+ const fallback = await notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
1244
1296
  if (fallback.ok) {
1245
1297
  await transitionDispatchRequest(teamName, queued.request_id, 'failed', 'failed', { last_reason: `fallback_confirmed_after_failed_receipt:${fallback.reason}` }, cwd).catch(() => { });
1246
1298
  return {
@@ -1258,7 +1310,7 @@ async function dispatchCriticalInboxInstruction(params) {
1258
1310
  request_id: queued.request_id,
1259
1311
  };
1260
1312
  }
1261
- const fallback = notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
1313
+ const fallback = await notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId);
1262
1314
  if (fallback.ok) {
1263
1315
  const marked = await markDispatchRequestNotified(teamName, queued.request_id, { last_reason: `fallback_confirmed:${fallback.reason}` }, cwd);
1264
1316
  if (!marked) {
@@ -1293,9 +1345,9 @@ async function finalizeHookPreferredMailboxDispatch(params) {
1293
1345
  return { ok: true, transport: 'hook', reason: `hook_receipt_${receipt.status}`, request_id: requestId, message_id: messageId };
1294
1346
  }
1295
1347
  const fallback = fallbackNotify
1296
- ? fallbackNotify()
1348
+ ? await fallbackNotify()
1297
1349
  : (typeof workerIndex === 'number'
1298
- ? notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId)
1350
+ ? await notifyWorkerOutcome(config, workerIndex, triggerMessage, paneId)
1299
1351
  : { ok: false, transport: 'none', reason: 'missing_worker_index' });
1300
1352
  if (receipt?.status === 'failed') {
1301
1353
  if (fallback.ok) {
@@ -1344,10 +1396,24 @@ async function finalizeHookPreferredMailboxDispatch(params) {
1344
1396
  message_id: messageId,
1345
1397
  };
1346
1398
  }
1347
- function notifyLeader(config, message) {
1399
+ async function notifyLeaderAsync(config, message, cwd) {
1400
+ // Primary: inject directly into the leader pane via tmux send-keys.
1401
+ // This is the fallback path when hook-based dispatch timed out, so the
1402
+ // leader needs a direct tmux notification to wake up. Fixes #437.
1403
+ if (config.leader_pane_id && isTmuxAvailable()) {
1404
+ try {
1405
+ await sendToLeaderPane(config.leader_pane_id, message);
1406
+ return true;
1407
+ }
1408
+ catch {
1409
+ // Fall through to mailbox
1410
+ }
1411
+ }
1412
+ // Fallback: write to leader mailbox (leader picks up on next hook cycle)
1348
1413
  if (!config.tmux_session)
1349
1414
  return false;
1350
- return notifyLeaderStatus(config.tmux_session, message);
1415
+ const { notifyLeaderMailboxAsync } = await import('./tmux-session.js');
1416
+ return notifyLeaderMailboxAsync(config.name, 'system', message, cwd);
1351
1417
  }
1352
1418
  async function deliverPendingMailboxMessages(teamName, config, workers, previousNotifications, dispatchPolicy, cwd) {
1353
1419
  const nextNotifications = {};
@@ -1410,7 +1476,7 @@ async function deliverPendingMailboxMessages(teamName, config, workers, previous
1410
1476
  });
1411
1477
  }
1412
1478
  else {
1413
- const direct = notifyWorkerOutcome(config, workerInfo.index, triggerMessage, workerInfo.pane_id);
1479
+ const direct = await notifyWorkerOutcome(config, workerInfo.index, triggerMessage, workerInfo.pane_id);
1414
1480
  outcome = { ...direct, request_id: queued.request.request_id, message_id: msg.message_id };
1415
1481
  if (outcome.ok) {
1416
1482
  await markMessageNotified(teamName, worker.name, msg.message_id, cwd).catch(() => false);
@@ -1451,9 +1517,9 @@ export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cw
1451
1517
  cwd,
1452
1518
  transportPreference: leaderTransportPreference,
1453
1519
  fallbackAllowed: leaderTransportPreference === 'hook_preferred_with_fallback',
1454
- notify: (_target, message) => (leaderTransportPreference === 'hook_preferred_with_fallback'
1520
+ notify: async (_target, message) => (leaderTransportPreference === 'hook_preferred_with_fallback'
1455
1521
  ? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
1456
- : { ok: notifyLeader(config, message), transport: 'tmux_send_keys', reason: 'leader_notified' }),
1522
+ : { ok: await notifyLeaderAsync(config, message, cwd), transport: 'mailbox', reason: 'leader_mailbox_notified' }),
1457
1523
  });
1458
1524
  let finalOutcome = outcome;
1459
1525
  const canLeaderFallbackDirectly = Boolean(config.leader_pane_id) && isTmuxAvailable();
@@ -1471,10 +1537,10 @@ export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cw
1471
1537
  config,
1472
1538
  dispatchPolicy,
1473
1539
  cwd,
1474
- fallbackNotify: () => ({
1475
- ok: notifyLeader(config, leaderTriggerMessage),
1476
- transport: 'tmux_send_keys',
1477
- reason: 'leader_notified',
1540
+ fallbackNotify: async () => ({
1541
+ ok: await notifyLeaderAsync(config, leaderTriggerMessage, cwd),
1542
+ transport: 'mailbox',
1543
+ reason: 'leader_mailbox_notified',
1478
1544
  }),
1479
1545
  });
1480
1546
  }
@@ -1500,9 +1566,9 @@ export async function sendWorkerMessage(teamName, fromWorker, toWorker, body, cw
1500
1566
  cwd,
1501
1567
  transportPreference,
1502
1568
  fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
1503
- notify: (_target, message) => (transportPreference === 'hook_preferred_with_fallback'
1569
+ notify: async (_target, message) => (transportPreference === 'hook_preferred_with_fallback'
1504
1570
  ? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
1505
- : notifyWorkerOutcome(config, recipient.index, message, recipient.pane_id)),
1571
+ : await notifyWorkerOutcome(config, recipient.index, message, recipient.pane_id)),
1506
1572
  });
1507
1573
  let finalOutcome = outcome;
1508
1574
  if (transportPreference === 'hook_preferred_with_fallback') {
@@ -1544,10 +1610,10 @@ export async function broadcastWorkerMessage(teamName, fromWorker, body, cwd) {
1544
1610
  triggerFor: (workerName) => generateMailboxTriggerMessage(workerName, sanitized, 1),
1545
1611
  transportPreference,
1546
1612
  fallbackAllowed: transportPreference === 'hook_preferred_with_fallback',
1547
- notify: (target, message) => transportPreference === 'hook_preferred_with_fallback'
1613
+ notify: async (target, message) => transportPreference === 'hook_preferred_with_fallback'
1548
1614
  ? { ok: true, transport: 'hook', reason: 'queued_for_hook_dispatch' }
1549
1615
  : (typeof target.workerIndex === 'number'
1550
- ? notifyWorkerOutcome(config, target.workerIndex, message, target.paneId)
1616
+ ? await notifyWorkerOutcome(config, target.workerIndex, message, target.paneId)
1551
1617
  : { ok: false, transport: 'none', reason: 'missing_worker_index' }),
1552
1618
  });
1553
1619
  const finalizedOutcomes = [];