Files
oh-my-claudecode/bridge/team.js
Codex Review 287565314b chore(release): bump version to v4.11.6
- Ralph security hardening: PRD gating non-bypassable, approval spoofing closed
- Permission handler: narrowed trust boundary, read-only gh commands allowed
- HUD: MiniMax coding plan provider, extra usage spend data, per-provider cache split
- tmux/openclaw: dead-pane suppression, stale replay suppression, keyword false-positive reduction
- Context dedup: no duplicate rule/skill injection from coexisting plugin+standalone
- Installer: user skills with OMC-style frontmatter preserved during updates
- Test isolation fix: hud-marketplace-resolution afterAll + setup-contracts-regression beforeAll
  restore hooks/hooks.json to prevent parallel worker race in full test suite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 14:03:35 +00:00

7708 lines
286 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/team/contracts.ts
function isTerminalTeamTaskStatus(status) {
return TEAM_TERMINAL_TASK_STATUSES.has(status);
}
function canTransitionTeamTaskStatus(from, to) {
return TEAM_TASK_STATUS_TRANSITIONS[from]?.includes(to) ?? false;
}
var TEAM_NAME_SAFE_PATTERN, WORKER_NAME_SAFE_PATTERN, TASK_ID_SAFE_PATTERN, TEAM_TASK_STATUSES, TEAM_TERMINAL_TASK_STATUSES, TEAM_TASK_STATUS_TRANSITIONS, TEAM_EVENT_TYPES, TEAM_TASK_APPROVAL_STATUSES;
var init_contracts = __esm({
"src/team/contracts.ts"() {
"use strict";
TEAM_NAME_SAFE_PATTERN = /^[a-z0-9][a-z0-9-]{0,29}$/;
WORKER_NAME_SAFE_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
TASK_ID_SAFE_PATTERN = /^\d{1,20}$/;
TEAM_TASK_STATUSES = ["pending", "blocked", "in_progress", "completed", "failed"];
TEAM_TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["completed", "failed"]);
TEAM_TASK_STATUS_TRANSITIONS = {
pending: [],
blocked: [],
in_progress: ["completed", "failed"],
completed: [],
failed: []
};
TEAM_EVENT_TYPES = [
"task_completed",
"task_failed",
"worker_idle",
"worker_stopped",
"message_received",
"shutdown_ack",
"shutdown_gate",
"shutdown_gate_forced",
"approval_decision",
"team_leader_nudge"
];
TEAM_TASK_APPROVAL_STATUSES = ["pending", "approved", "rejected"];
}
});
// src/team/state-paths.ts
import { isAbsolute, join } from "path";
function normalizeTaskFileStem(taskId) {
const trimmed = String(taskId).trim().replace(/\.json$/i, "");
if (/^task-\d+$/.test(trimmed)) return trimmed;
if (/^\d+$/.test(trimmed)) return `task-${trimmed}`;
return trimmed;
}
function absPath(cwd, relativePath) {
return isAbsolute(relativePath) ? relativePath : join(cwd, relativePath);
}
function teamStateRoot(cwd, teamName) {
return join(cwd, TeamPaths.root(teamName));
}
var TeamPaths;
var init_state_paths = __esm({
"src/team/state-paths.ts"() {
"use strict";
TeamPaths = {
root: (teamName) => `.omc/state/team/${teamName}`,
config: (teamName) => `.omc/state/team/${teamName}/config.json`,
shutdown: (teamName) => `.omc/state/team/${teamName}/shutdown.json`,
tasks: (teamName) => `.omc/state/team/${teamName}/tasks`,
taskFile: (teamName, taskId) => `.omc/state/team/${teamName}/tasks/${normalizeTaskFileStem(taskId)}.json`,
workers: (teamName) => `.omc/state/team/${teamName}/workers`,
workerDir: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}`,
heartbeat: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/heartbeat.json`,
inbox: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/inbox.md`,
outbox: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/outbox.jsonl`,
ready: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/.ready`,
overlay: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/AGENTS.md`,
shutdownAck: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/shutdown-ack.json`,
mailbox: (teamName, workerName) => `.omc/state/team/${teamName}/mailbox/${workerName}.json`,
mailboxLockDir: (teamName, workerName) => `.omc/state/team/${teamName}/mailbox/.lock-${workerName}`,
dispatchRequests: (teamName) => `.omc/state/team/${teamName}/dispatch/requests.json`,
dispatchLockDir: (teamName) => `.omc/state/team/${teamName}/dispatch/.lock`,
workerStatus: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/status.json`,
workerIdleNotify: (teamName) => `.omc/state/team/${teamName}/worker-idle-notify.json`,
workerPrevNotifyState: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/prev-notify-state.json`,
events: (teamName) => `.omc/state/team/${teamName}/events.jsonl`,
approval: (teamName, taskId) => `.omc/state/team/${teamName}/approvals/${taskId}.json`,
manifest: (teamName) => `.omc/state/team/${teamName}/manifest.json`,
monitorSnapshot: (teamName) => `.omc/state/team/${teamName}/monitor-snapshot.json`,
summarySnapshot: (teamName) => `.omc/state/team/${teamName}/summary-snapshot.json`,
phaseState: (teamName) => `.omc/state/team/${teamName}/phase-state.json`,
scalingLock: (teamName) => `.omc/state/team/${teamName}/.scaling-lock`,
workerIdentity: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/identity.json`,
workerAgentsMd: (teamName) => `.omc/state/team/${teamName}/worker-agents.md`,
shutdownRequest: (teamName, workerName) => `.omc/state/team/${teamName}/workers/${workerName}/shutdown-request.json`
};
}
});
// src/team/governance.ts
var governance_exports = {};
__export(governance_exports, {
DEFAULT_TEAM_GOVERNANCE: () => DEFAULT_TEAM_GOVERNANCE,
DEFAULT_TEAM_TRANSPORT_POLICY: () => DEFAULT_TEAM_TRANSPORT_POLICY,
getConfigGovernance: () => getConfigGovernance,
isLinkedRalphProfile: () => isLinkedRalphProfile,
normalizeTeamGovernance: () => normalizeTeamGovernance,
normalizeTeamManifest: () => normalizeTeamManifest,
normalizeTeamTransportPolicy: () => normalizeTeamTransportPolicy,
resolveLifecycleProfile: () => resolveLifecycleProfile
});
function normalizeTeamTransportPolicy(policy) {
return {
display_mode: policy?.display_mode ?? DEFAULT_TEAM_TRANSPORT_POLICY.display_mode,
worker_launch_mode: policy?.worker_launch_mode ?? DEFAULT_TEAM_TRANSPORT_POLICY.worker_launch_mode,
dispatch_mode: policy?.dispatch_mode ?? DEFAULT_TEAM_TRANSPORT_POLICY.dispatch_mode,
dispatch_ack_timeout_ms: typeof policy?.dispatch_ack_timeout_ms === "number" ? policy.dispatch_ack_timeout_ms : DEFAULT_TEAM_TRANSPORT_POLICY.dispatch_ack_timeout_ms
};
}
function normalizeTeamGovernance(governance, legacyPolicy) {
return {
delegation_only: governance?.delegation_only ?? legacyPolicy?.delegation_only ?? DEFAULT_TEAM_GOVERNANCE.delegation_only,
plan_approval_required: governance?.plan_approval_required ?? legacyPolicy?.plan_approval_required ?? DEFAULT_TEAM_GOVERNANCE.plan_approval_required,
nested_teams_allowed: governance?.nested_teams_allowed ?? legacyPolicy?.nested_teams_allowed ?? DEFAULT_TEAM_GOVERNANCE.nested_teams_allowed,
one_team_per_leader_session: governance?.one_team_per_leader_session ?? legacyPolicy?.one_team_per_leader_session ?? DEFAULT_TEAM_GOVERNANCE.one_team_per_leader_session,
cleanup_requires_all_workers_inactive: governance?.cleanup_requires_all_workers_inactive ?? legacyPolicy?.cleanup_requires_all_workers_inactive ?? DEFAULT_TEAM_GOVERNANCE.cleanup_requires_all_workers_inactive
};
}
function normalizeTeamManifest(manifest) {
return {
...manifest,
policy: normalizeTeamTransportPolicy(manifest.policy),
governance: normalizeTeamGovernance(manifest.governance, manifest.policy)
};
}
function getConfigGovernance(config) {
return normalizeTeamGovernance(config?.governance, config?.policy);
}
function resolveLifecycleProfile(config, manifest) {
if (manifest?.lifecycle_profile) return manifest.lifecycle_profile;
if (config?.lifecycle_profile) return config.lifecycle_profile;
return "default";
}
function isLinkedRalphProfile(config, manifest) {
return resolveLifecycleProfile(config, manifest) === "linked_ralph";
}
var DEFAULT_TEAM_TRANSPORT_POLICY, DEFAULT_TEAM_GOVERNANCE;
var init_governance = __esm({
"src/team/governance.ts"() {
"use strict";
DEFAULT_TEAM_TRANSPORT_POLICY = {
display_mode: "split_pane",
worker_launch_mode: "interactive",
dispatch_mode: "hook_preferred_with_fallback",
dispatch_ack_timeout_ms: 15e3
};
DEFAULT_TEAM_GOVERNANCE = {
delegation_only: false,
plan_approval_required: false,
nested_teams_allowed: false,
one_team_per_leader_session: true,
cleanup_requires_all_workers_inactive: true
};
}
});
// src/team/state/tasks.ts
import { randomUUID } from "crypto";
import { join as join2 } from "path";
import { existsSync } from "fs";
import { readFile, readdir } from "fs/promises";
async function computeTaskReadiness(teamName, taskId, cwd, deps) {
const task = await deps.readTask(teamName, taskId, cwd);
if (!task) return { ready: false, reason: "blocked_dependency", dependencies: [] };
const depIds = task.depends_on ?? task.blocked_by ?? [];
if (depIds.length === 0) return { ready: true };
const depTasks = await Promise.all(depIds.map((depId) => deps.readTask(teamName, depId, cwd)));
const incomplete = depIds.filter((_, idx) => depTasks[idx]?.status !== "completed");
if (incomplete.length > 0) return { ready: false, reason: "blocked_dependency", dependencies: incomplete };
return { ready: true };
}
async function claimTask(taskId, workerName, expectedVersion, deps) {
const cfg = await deps.readTeamConfig(deps.teamName, deps.cwd);
if (!cfg || !cfg.workers.some((w) => w.name === workerName)) return { ok: false, error: "worker_not_found" };
const existing = await deps.readTask(deps.teamName, taskId, deps.cwd);
if (!existing) return { ok: false, error: "task_not_found" };
const readiness = await computeTaskReadiness(deps.teamName, taskId, deps.cwd, deps);
if (readiness.ready === false) {
return { ok: false, error: "blocked_dependency", dependencies: readiness.dependencies };
}
const lock = await deps.withTaskClaimLock(deps.teamName, taskId, deps.cwd, async () => {
const current = await deps.readTask(deps.teamName, taskId, deps.cwd);
if (!current) return { ok: false, error: "task_not_found" };
const v = deps.normalizeTask(current);
if (expectedVersion !== null && v.version !== expectedVersion) return { ok: false, error: "claim_conflict" };
const readinessAfterLock = await computeTaskReadiness(deps.teamName, taskId, deps.cwd, deps);
if (readinessAfterLock.ready === false) {
return { ok: false, error: "blocked_dependency", dependencies: readinessAfterLock.dependencies };
}
if (deps.isTerminalTaskStatus(v.status)) return { ok: false, error: "already_terminal" };
if (v.status === "in_progress") return { ok: false, error: "claim_conflict" };
if (v.status === "pending" || v.status === "blocked") {
if (v.claim) return { ok: false, error: "claim_conflict" };
if (v.owner && v.owner !== workerName) return { ok: false, error: "claim_conflict" };
}
const claimToken = randomUUID();
const updated = {
...v,
status: "in_progress",
owner: workerName,
claim: { owner: workerName, token: claimToken, leased_until: new Date(Date.now() + 15 * 60 * 1e3).toISOString() },
version: v.version + 1
};
await deps.writeAtomic(deps.taskFilePath(deps.teamName, taskId, deps.cwd), JSON.stringify(updated, null, 2));
return { ok: true, task: updated, claimToken };
});
if (!lock.ok) return { ok: false, error: "claim_conflict" };
return lock.value;
}
async function transitionTaskStatus(taskId, from, to, claimToken, deps) {
if (!deps.canTransitionTaskStatus(from, to)) return { ok: false, error: "invalid_transition" };
const lock = await deps.withTaskClaimLock(deps.teamName, taskId, deps.cwd, async () => {
const current = await deps.readTask(deps.teamName, taskId, deps.cwd);
if (!current) return { ok: false, error: "task_not_found" };
const v = deps.normalizeTask(current);
if (deps.isTerminalTaskStatus(v.status)) return { ok: false, error: "already_terminal" };
if (!deps.canTransitionTaskStatus(v.status, to)) return { ok: false, error: "invalid_transition" };
if (v.status !== from) return { ok: false, error: "invalid_transition" };
if (!v.owner || !v.claim || v.claim.owner !== v.owner || v.claim.token !== claimToken) {
return { ok: false, error: "claim_conflict" };
}
if (new Date(v.claim.leased_until) <= /* @__PURE__ */ new Date()) return { ok: false, error: "lease_expired" };
const updated = {
...v,
status: to,
completed_at: to === "completed" ? (/* @__PURE__ */ new Date()).toISOString() : v.completed_at,
claim: void 0,
version: v.version + 1
};
await deps.writeAtomic(deps.taskFilePath(deps.teamName, taskId, deps.cwd), JSON.stringify(updated, null, 2));
if (to === "completed") {
await deps.appendTeamEvent(
deps.teamName,
{ type: "task_completed", worker: updated.owner || "unknown", task_id: updated.id, message_id: null, reason: void 0 },
deps.cwd
);
} else if (to === "failed") {
await deps.appendTeamEvent(
deps.teamName,
{ type: "task_failed", worker: updated.owner || "unknown", task_id: updated.id, message_id: null, reason: updated.error || "task_failed" },
deps.cwd
);
}
return { ok: true, task: updated };
});
if (!lock.ok) return { ok: false, error: "claim_conflict" };
if (to === "completed") {
const existing = await deps.readMonitorSnapshot(deps.teamName, deps.cwd);
const updated = existing ? { ...existing, completedEventTaskIds: { ...existing.completedEventTaskIds ?? {}, [taskId]: true } } : {
taskStatusById: {},
workerAliveByName: {},
workerStateByName: {},
workerTurnCountByName: {},
workerTaskIdByName: {},
mailboxNotifiedByMessageId: {},
completedEventTaskIds: { [taskId]: true }
};
await deps.writeMonitorSnapshot(deps.teamName, updated, deps.cwd);
}
return lock.value;
}
async function releaseTaskClaim(taskId, claimToken, _workerName, deps) {
const lock = await deps.withTaskClaimLock(deps.teamName, taskId, deps.cwd, async () => {
const current = await deps.readTask(deps.teamName, taskId, deps.cwd);
if (!current) return { ok: false, error: "task_not_found" };
const v = deps.normalizeTask(current);
if (v.status === "pending" && !v.claim && !v.owner) return { ok: true, task: v };
if (v.status === "completed" || v.status === "failed") return { ok: false, error: "already_terminal" };
if (!v.owner || !v.claim || v.claim.owner !== v.owner || v.claim.token !== claimToken) {
return { ok: false, error: "claim_conflict" };
}
if (new Date(v.claim.leased_until) <= /* @__PURE__ */ new Date()) return { ok: false, error: "lease_expired" };
const updated = {
...v,
status: "pending",
owner: void 0,
claim: void 0,
version: v.version + 1
};
await deps.writeAtomic(deps.taskFilePath(deps.teamName, taskId, deps.cwd), JSON.stringify(updated, null, 2));
return { ok: true, task: updated };
});
if (!lock.ok) return { ok: false, error: "claim_conflict" };
return lock.value;
}
async function listTasks(teamName, cwd, deps) {
const tasksRoot = join2(deps.teamDir(teamName, cwd), "tasks");
if (!existsSync(tasksRoot)) return [];
const entries = await readdir(tasksRoot, { withFileTypes: true });
const matched = entries.flatMap((entry) => {
if (!entry.isFile()) return [];
const match = /^(?:task-)?(\d+)\.json$/.exec(entry.name);
if (!match) return [];
return [{ id: match[1], fileName: entry.name }];
});
const loaded = await Promise.all(
matched.map(async ({ id, fileName }) => {
try {
const raw = await readFile(join2(tasksRoot, fileName), "utf8");
const parsed = JSON.parse(raw);
if (!deps.isTeamTask(parsed)) return null;
const normalized = deps.normalizeTask(parsed);
if (normalized.id !== id) return null;
return normalized;
} catch {
return null;
}
})
);
const tasks = [];
for (const task of loaded) {
if (task) tasks.push(task);
}
tasks.sort((a, b) => Number(a.id) - Number(b.id));
return tasks;
}
var init_tasks = __esm({
"src/team/state/tasks.ts"() {
"use strict";
}
});
// src/team/worker-canonicalization.ts
function hasText(value) {
return typeof value === "string" && value.trim().length > 0;
}
function hasAssignedTasks(worker) {
return Array.isArray(worker.assigned_tasks) && worker.assigned_tasks.length > 0;
}
function workerPriority(worker) {
if (hasText(worker.pane_id)) return 4;
if (typeof worker.pid === "number" && Number.isFinite(worker.pid)) return 3;
if (hasAssignedTasks(worker)) return 2;
if (typeof worker.index === "number" && worker.index > 0) return 1;
return 0;
}
function mergeAssignedTasks(primary, secondary) {
const merged = [];
for (const taskId of [...primary ?? [], ...secondary ?? []]) {
if (typeof taskId !== "string" || taskId.trim() === "" || merged.includes(taskId)) continue;
merged.push(taskId);
}
return merged;
}
function backfillText(primary, secondary) {
return hasText(primary) ? primary : secondary;
}
function backfillBoolean(primary, secondary) {
return typeof primary === "boolean" ? primary : secondary;
}
function backfillNumber(primary, secondary, predicate) {
const isUsable = (value) => typeof value === "number" && Number.isFinite(value) && (predicate ? predicate(value) : true);
return isUsable(primary) ? primary : isUsable(secondary) ? secondary : void 0;
}
function chooseWinningWorker(existing, incoming) {
const existingPriority = workerPriority(existing);
const incomingPriority = workerPriority(incoming);
if (incomingPriority > existingPriority) return { winner: incoming, loser: existing };
if (incomingPriority < existingPriority) return { winner: existing, loser: incoming };
if ((incoming.index ?? 0) >= (existing.index ?? 0)) return { winner: incoming, loser: existing };
return { winner: existing, loser: incoming };
}
function canonicalizeWorkers(workers) {
const byName = /* @__PURE__ */ new Map();
const duplicateNames = /* @__PURE__ */ new Set();
for (const worker of workers) {
const name = typeof worker.name === "string" ? worker.name.trim() : "";
if (!name) continue;
const normalized = {
...worker,
name,
assigned_tasks: Array.isArray(worker.assigned_tasks) ? worker.assigned_tasks : []
};
const existing = byName.get(name);
if (!existing) {
byName.set(name, normalized);
continue;
}
duplicateNames.add(name);
const { winner, loser } = chooseWinningWorker(existing, normalized);
byName.set(name, {
...winner,
name,
assigned_tasks: mergeAssignedTasks(winner.assigned_tasks, loser.assigned_tasks),
pane_id: backfillText(winner.pane_id, loser.pane_id),
pid: backfillNumber(winner.pid, loser.pid),
index: backfillNumber(winner.index, loser.index, (value) => value > 0) ?? 0,
role: backfillText(winner.role, loser.role) ?? winner.role,
worker_cli: backfillText(winner.worker_cli, loser.worker_cli),
working_dir: backfillText(winner.working_dir, loser.working_dir),
worktree_path: backfillText(winner.worktree_path, loser.worktree_path),
worktree_branch: backfillText(winner.worktree_branch, loser.worktree_branch),
worktree_detached: backfillBoolean(winner.worktree_detached, loser.worktree_detached),
team_state_root: backfillText(winner.team_state_root, loser.team_state_root)
});
}
return {
workers: Array.from(byName.values()),
duplicateNames: Array.from(duplicateNames.values())
};
}
function canonicalizeTeamConfigWorkers(config) {
const { workers, duplicateNames } = canonicalizeWorkers(config.workers ?? []);
if (duplicateNames.length > 0) {
console.warn(
`[team] canonicalized duplicate worker entries: ${duplicateNames.join(", ")}`
);
}
return {
...config,
workers,
worker_count: workers.length
};
}
var init_worker_canonicalization = __esm({
"src/team/worker-canonicalization.ts"() {
"use strict";
}
});
// src/team/team-ops.ts
var team_ops_exports = {};
__export(team_ops_exports, {
teamAppendEvent: () => teamAppendEvent,
teamBroadcast: () => teamBroadcast,
teamClaimTask: () => teamClaimTask,
teamCleanup: () => teamCleanup,
teamCreateTask: () => teamCreateTask,
teamGetSummary: () => teamGetSummary,
teamListMailbox: () => teamListMailbox,
teamListTasks: () => teamListTasks,
teamMarkMessageDelivered: () => teamMarkMessageDelivered,
teamMarkMessageNotified: () => teamMarkMessageNotified,
teamReadConfig: () => teamReadConfig,
teamReadManifest: () => teamReadManifest,
teamReadMonitorSnapshot: () => teamReadMonitorSnapshot,
teamReadShutdownAck: () => teamReadShutdownAck,
teamReadTask: () => teamReadTask,
teamReadTaskApproval: () => teamReadTaskApproval,
teamReadWorkerHeartbeat: () => teamReadWorkerHeartbeat,
teamReadWorkerStatus: () => teamReadWorkerStatus,
teamReleaseTaskClaim: () => teamReleaseTaskClaim,
teamSendMessage: () => teamSendMessage,
teamTransitionTaskStatus: () => teamTransitionTaskStatus,
teamUpdateTask: () => teamUpdateTask,
teamUpdateWorkerHeartbeat: () => teamUpdateWorkerHeartbeat,
teamWriteMonitorSnapshot: () => teamWriteMonitorSnapshot,
teamWriteShutdownRequest: () => teamWriteShutdownRequest,
teamWriteTaskApproval: () => teamWriteTaskApproval,
teamWriteWorkerIdentity: () => teamWriteWorkerIdentity,
teamWriteWorkerInbox: () => teamWriteWorkerInbox,
writeAtomic: () => writeAtomic
});
import { randomUUID as randomUUID2 } from "node:crypto";
import { existsSync as existsSync2 } from "node:fs";
import { appendFile, mkdir, readFile as readFile2, rm, writeFile } from "node:fs/promises";
import { dirname, join as join3 } from "node:path";
function teamDir(teamName, cwd) {
return absPath(cwd, TeamPaths.root(teamName));
}
function normalizeTaskId(taskId) {
const raw = String(taskId).trim();
return raw.startsWith("task-") ? raw.slice("task-".length) : raw;
}
function canonicalTaskFilePath(teamName, taskId, cwd) {
const normalizedTaskId = normalizeTaskId(taskId);
return join3(absPath(cwd, TeamPaths.tasks(teamName)), `task-${normalizedTaskId}.json`);
}
function legacyTaskFilePath(teamName, taskId, cwd) {
const normalizedTaskId = normalizeTaskId(taskId);
return join3(absPath(cwd, TeamPaths.tasks(teamName)), `${normalizedTaskId}.json`);
}
function taskFileCandidates(teamName, taskId, cwd) {
const canonical = canonicalTaskFilePath(teamName, taskId, cwd);
const legacy = legacyTaskFilePath(teamName, taskId, cwd);
return canonical === legacy ? [canonical] : [canonical, legacy];
}
async function writeAtomic(path4, data) {
const tmp = `${path4}.${process.pid}.tmp`;
await mkdir(dirname(path4), { recursive: true });
await writeFile(tmp, data, "utf8");
const { rename: rename3 } = await import("node:fs/promises");
await rename3(tmp, path4);
}
async function readJsonSafe(path4) {
try {
if (!existsSync2(path4)) return null;
const raw = await readFile2(path4, "utf8");
return JSON.parse(raw);
} catch {
return null;
}
}
function normalizeTask(task) {
return { ...task, version: task.version ?? 1 };
}
function isTeamTask(value) {
if (!value || typeof value !== "object") return false;
const v = value;
return typeof v.id === "string" && typeof v.subject === "string" && typeof v.status === "string";
}
async function withLock(lockDir, fn) {
const STALE_MS = 3e4;
try {
await mkdir(lockDir, { recursive: false });
} catch (err) {
if (err.code === "EEXIST") {
try {
const { stat: stat2 } = await import("node:fs/promises");
const s = await stat2(lockDir);
if (Date.now() - s.mtimeMs > STALE_MS) {
await rm(lockDir, { recursive: true, force: true });
try {
await mkdir(lockDir, { recursive: false });
} catch {
return { ok: false };
}
} else {
return { ok: false };
}
} catch {
return { ok: false };
}
} else {
throw err;
}
}
try {
const result = await fn();
return { ok: true, value: result };
} finally {
await rm(lockDir, { recursive: true, force: true }).catch(() => {
});
}
}
async function withTaskClaimLock(teamName, taskId, cwd, fn) {
const lockDir = join3(teamDir(teamName, cwd), "tasks", `.lock-${taskId}`);
return withLock(lockDir, fn);
}
async function withMailboxLock(teamName, workerName, cwd, fn) {
const lockDir = absPath(cwd, TeamPaths.mailboxLockDir(teamName, workerName));
const timeoutMs = 5e3;
const deadline = Date.now() + timeoutMs;
let delayMs = 20;
while (Date.now() < deadline) {
const result = await withLock(lockDir, fn);
if (result.ok) return result.value;
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
delayMs = Math.min(delayMs * 2, 200);
}
throw new Error(`Failed to acquire mailbox lock for ${workerName} after ${timeoutMs}ms`);
}
function configFromManifest(manifest) {
return {
name: manifest.name,
task: manifest.task,
agent_type: "claude",
policy: manifest.policy,
governance: manifest.governance,
worker_launch_mode: manifest.policy.worker_launch_mode,
worker_count: manifest.worker_count,
max_workers: 20,
workers: manifest.workers,
created_at: manifest.created_at,
tmux_session: manifest.tmux_session,
next_task_id: manifest.next_task_id,
leader_cwd: manifest.leader_cwd,
team_state_root: manifest.team_state_root,
workspace_mode: manifest.workspace_mode,
leader_pane_id: manifest.leader_pane_id,
hud_pane_id: manifest.hud_pane_id,
resize_hook_name: manifest.resize_hook_name,
resize_hook_target: manifest.resize_hook_target,
next_worker_index: manifest.next_worker_index
};
}
function mergeTeamConfigSources(config, manifest) {
if (!config && !manifest) return null;
if (!manifest) return config ? canonicalizeTeamConfigWorkers(config) : null;
if (!config) return canonicalizeTeamConfigWorkers(configFromManifest(manifest));
return canonicalizeTeamConfigWorkers({
...configFromManifest(manifest),
...config,
workers: [...config.workers ?? [], ...manifest.workers ?? []],
worker_count: Math.max(config.worker_count ?? 0, manifest.worker_count ?? 0),
next_task_id: Math.max(config.next_task_id ?? 1, manifest.next_task_id ?? 1),
max_workers: Math.max(config.max_workers ?? 0, 20)
});
}
async function teamReadConfig(teamName, cwd) {
const [manifest, config] = await Promise.all([
teamReadManifest(teamName, cwd),
readJsonSafe(absPath(cwd, TeamPaths.config(teamName)))
]);
return mergeTeamConfigSources(config, manifest);
}
async function teamReadManifest(teamName, cwd) {
const manifestPath = absPath(cwd, TeamPaths.manifest(teamName));
const manifest = await readJsonSafe(manifestPath);
return manifest ? normalizeTeamManifest(manifest) : null;
}
async function teamCleanup(teamName, cwd) {
await rm(teamDir(teamName, cwd), { recursive: true, force: true });
}
async function teamWriteWorkerIdentity(teamName, workerName, identity, cwd) {
const p = absPath(cwd, TeamPaths.workerIdentity(teamName, workerName));
await writeAtomic(p, JSON.stringify(identity, null, 2));
}
async function teamReadWorkerHeartbeat(teamName, workerName, cwd) {
const p = absPath(cwd, TeamPaths.heartbeat(teamName, workerName));
return readJsonSafe(p);
}
async function teamUpdateWorkerHeartbeat(teamName, workerName, heartbeat, cwd) {
const p = absPath(cwd, TeamPaths.heartbeat(teamName, workerName));
await writeAtomic(p, JSON.stringify(heartbeat, null, 2));
}
async function teamReadWorkerStatus(teamName, workerName, cwd) {
const unknownStatus = { state: "unknown", updated_at: "1970-01-01T00:00:00.000Z" };
const p = absPath(cwd, TeamPaths.workerStatus(teamName, workerName));
const status = await readJsonSafe(p);
return status ?? unknownStatus;
}
async function teamWriteWorkerInbox(teamName, workerName, prompt, cwd) {
const p = absPath(cwd, TeamPaths.inbox(teamName, workerName));
await writeAtomic(p, prompt);
}
async function teamCreateTask(teamName, task, cwd) {
const lockDir = join3(teamDir(teamName, cwd), ".lock-create-task");
const timeoutMs = 5e3;
const deadline = Date.now() + timeoutMs;
let delayMs = 20;
while (Date.now() < deadline) {
const result = await withLock(lockDir, async () => {
const cfg = await teamReadConfig(teamName, cwd);
if (!cfg) throw new Error(`Team ${teamName} not found`);
const nextId = String(cfg.next_task_id ?? 1);
const created = {
...task,
id: nextId,
status: task.status ?? "pending",
depends_on: task.depends_on ?? task.blocked_by ?? [],
version: 1,
created_at: (/* @__PURE__ */ new Date()).toISOString()
};
const taskPath2 = absPath(cwd, TeamPaths.tasks(teamName));
await mkdir(taskPath2, { recursive: true });
await writeAtomic(join3(taskPath2, `task-${nextId}.json`), JSON.stringify(created, null, 2));
cfg.next_task_id = Number(nextId) + 1;
await writeAtomic(absPath(cwd, TeamPaths.config(teamName)), JSON.stringify(cfg, null, 2));
return created;
});
if (result.ok) return result.value;
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
delayMs = Math.min(delayMs * 2, 200);
}
throw new Error(`Failed to acquire task creation lock for team ${teamName} after ${timeoutMs}ms`);
}
async function teamReadTask(teamName, taskId, cwd) {
for (const candidate of taskFileCandidates(teamName, taskId, cwd)) {
const task = await readJsonSafe(candidate);
if (!task || !isTeamTask(task)) continue;
return normalizeTask(task);
}
return null;
}
async function teamListTasks(teamName, cwd) {
return listTasks(teamName, cwd, {
teamDir: (tn, c) => teamDir(tn, c),
isTeamTask,
normalizeTask
});
}
async function teamUpdateTask(teamName, taskId, updates, cwd) {
const timeoutMs = 5e3;
const deadline = Date.now() + timeoutMs;
let delayMs = 20;
while (Date.now() < deadline) {
const result = await withTaskClaimLock(teamName, taskId, cwd, async () => {
const existing = await teamReadTask(teamName, taskId, cwd);
if (!existing) return null;
const merged = {
...normalizeTask(existing),
...updates,
id: existing.id,
created_at: existing.created_at,
version: Math.max(1, existing.version ?? 1) + 1
};
const p = canonicalTaskFilePath(teamName, taskId, cwd);
await writeAtomic(p, JSON.stringify(merged, null, 2));
return merged;
});
if (result.ok) return result.value;
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
delayMs = Math.min(delayMs * 2, 200);
}
throw new Error(`Failed to acquire task update lock for task ${taskId} in team ${teamName} after ${timeoutMs}ms`);
}
async function teamClaimTask(teamName, taskId, workerName, expectedVersion, cwd) {
const manifest = await teamReadManifest(teamName, cwd);
const governance = normalizeTeamGovernance(manifest?.governance, manifest?.policy);
if (governance.plan_approval_required) {
const task = await teamReadTask(teamName, taskId, cwd);
if (task?.requires_code_change) {
const approval = await teamReadTaskApproval(teamName, taskId, cwd);
if (!approval || approval.status !== "approved") {
return { ok: false, error: "blocked_dependency", dependencies: ["approval-required"] };
}
}
}
return claimTask(taskId, workerName, expectedVersion, {
teamName,
cwd,
readTask: teamReadTask,
readTeamConfig: teamReadConfig,
withTaskClaimLock,
normalizeTask,
isTerminalTaskStatus: isTerminalTeamTaskStatus,
taskFilePath: (tn, tid, c) => canonicalTaskFilePath(tn, tid, c),
writeAtomic
});
}
async function teamTransitionTaskStatus(teamName, taskId, from, to, claimToken, cwd) {
return transitionTaskStatus(taskId, from, to, claimToken, {
teamName,
cwd,
readTask: teamReadTask,
readTeamConfig: teamReadConfig,
withTaskClaimLock,
normalizeTask,
isTerminalTaskStatus: isTerminalTeamTaskStatus,
canTransitionTaskStatus: canTransitionTeamTaskStatus,
taskFilePath: (tn, tid, c) => canonicalTaskFilePath(tn, tid, c),
writeAtomic,
appendTeamEvent: teamAppendEvent,
readMonitorSnapshot: teamReadMonitorSnapshot,
writeMonitorSnapshot: teamWriteMonitorSnapshot
});
}
async function teamReleaseTaskClaim(teamName, taskId, claimToken, workerName, cwd) {
return releaseTaskClaim(taskId, claimToken, workerName, {
teamName,
cwd,
readTask: teamReadTask,
readTeamConfig: teamReadConfig,
withTaskClaimLock,
normalizeTask,
isTerminalTaskStatus: isTerminalTeamTaskStatus,
taskFilePath: (tn, tid, c) => canonicalTaskFilePath(tn, tid, c),
writeAtomic
});
}
function normalizeLegacyMailboxMessage(raw) {
if (raw.type === "notified") return null;
const messageId = typeof raw.message_id === "string" && raw.message_id.trim() !== "" ? raw.message_id : typeof raw.id === "string" && raw.id.trim() !== "" ? raw.id : "";
const fromWorker = typeof raw.from_worker === "string" && raw.from_worker.trim() !== "" ? raw.from_worker : typeof raw.from === "string" ? raw.from : "";
const toWorker = typeof raw.to_worker === "string" && raw.to_worker.trim() !== "" ? raw.to_worker : typeof raw.to === "string" ? raw.to : "";
const body = typeof raw.body === "string" ? raw.body : "";
const createdAt = typeof raw.created_at === "string" && raw.created_at.trim() !== "" ? raw.created_at : typeof raw.createdAt === "string" ? raw.createdAt : "";
if (!messageId || !fromWorker || !toWorker || !body || !createdAt) return null;
return {
message_id: messageId,
from_worker: fromWorker,
to_worker: toWorker,
body,
created_at: createdAt,
...typeof raw.notified_at === "string" ? { notified_at: raw.notified_at } : {},
...typeof raw.notifiedAt === "string" ? { notified_at: raw.notifiedAt } : {},
...typeof raw.delivered_at === "string" ? { delivered_at: raw.delivered_at } : {},
...typeof raw.deliveredAt === "string" ? { delivered_at: raw.deliveredAt } : {}
};
}
async function readLegacyMailboxJsonl(teamName, workerName, cwd) {
const legacyPath = absPath(cwd, TeamPaths.mailbox(teamName, workerName).replace(/\.json$/i, ".jsonl"));
if (!existsSync2(legacyPath)) return { worker: workerName, messages: [] };
try {
const raw = await readFile2(legacyPath, "utf8");
const lines = raw.split("\n").map((line) => line.trim()).filter(Boolean);
const byMessageId = /* @__PURE__ */ new Map();
for (const line of lines) {
let parsed;
try {
parsed = JSON.parse(line);
} catch {
continue;
}
if (!parsed || typeof parsed !== "object") continue;
const normalized = normalizeLegacyMailboxMessage(parsed);
if (!normalized) continue;
byMessageId.set(normalized.message_id, normalized);
}
return { worker: workerName, messages: [...byMessageId.values()] };
} catch {
return { worker: workerName, messages: [] };
}
}
async function readMailbox(teamName, workerName, cwd) {
const p = absPath(cwd, TeamPaths.mailbox(teamName, workerName));
const mailbox = await readJsonSafe(p);
if (mailbox && Array.isArray(mailbox.messages)) {
return { worker: workerName, messages: mailbox.messages };
}
return readLegacyMailboxJsonl(teamName, workerName, cwd);
}
async function writeMailbox(teamName, workerName, mailbox, cwd) {
const p = absPath(cwd, TeamPaths.mailbox(teamName, workerName));
await writeAtomic(p, JSON.stringify(mailbox, null, 2));
}
async function teamSendMessage(teamName, fromWorker, toWorker, body, cwd) {
return withMailboxLock(teamName, toWorker, cwd, async () => {
const mailbox = await readMailbox(teamName, toWorker, cwd);
const message = {
message_id: randomUUID2(),
from_worker: fromWorker,
to_worker: toWorker,
body,
created_at: (/* @__PURE__ */ new Date()).toISOString()
};
mailbox.messages.push(message);
await writeMailbox(teamName, toWorker, mailbox, cwd);
await teamAppendEvent(teamName, {
type: "message_received",
worker: toWorker,
message_id: message.message_id
}, cwd);
return message;
});
}
async function teamBroadcast(teamName, fromWorker, body, cwd) {
const cfg = await teamReadConfig(teamName, cwd);
if (!cfg) throw new Error(`Team ${teamName} not found`);
const messages = [];
for (const worker of cfg.workers) {
if (worker.name === fromWorker) continue;
const msg = await teamSendMessage(teamName, fromWorker, worker.name, body, cwd);
messages.push(msg);
}
return messages;
}
async function teamListMailbox(teamName, workerName, cwd) {
const mailbox = await readMailbox(teamName, workerName, cwd);
return mailbox.messages;
}
async function teamMarkMessageDelivered(teamName, workerName, messageId, cwd) {
return withMailboxLock(teamName, workerName, cwd, async () => {
const mailbox = await readMailbox(teamName, workerName, cwd);
const msg = mailbox.messages.find((m) => m.message_id === messageId);
if (!msg) return false;
msg.delivered_at = (/* @__PURE__ */ new Date()).toISOString();
await writeMailbox(teamName, workerName, mailbox, cwd);
return true;
});
}
async function teamMarkMessageNotified(teamName, workerName, messageId, cwd) {
return withMailboxLock(teamName, workerName, cwd, async () => {
const mailbox = await readMailbox(teamName, workerName, cwd);
const msg = mailbox.messages.find((m) => m.message_id === messageId);
if (!msg) return false;
msg.notified_at = (/* @__PURE__ */ new Date()).toISOString();
await writeMailbox(teamName, workerName, mailbox, cwd);
return true;
});
}
async function teamAppendEvent(teamName, event, cwd) {
const full = {
event_id: randomUUID2(),
team: teamName,
created_at: (/* @__PURE__ */ new Date()).toISOString(),
...event
};
const p = absPath(cwd, TeamPaths.events(teamName));
await mkdir(dirname(p), { recursive: true });
await appendFile(p, `${JSON.stringify(full)}
`, "utf8");
return full;
}
async function teamReadTaskApproval(teamName, taskId, cwd) {
const p = absPath(cwd, TeamPaths.approval(teamName, taskId));
return readJsonSafe(p);
}
async function teamWriteTaskApproval(teamName, approval, cwd) {
const p = absPath(cwd, TeamPaths.approval(teamName, approval.task_id));
await writeAtomic(p, JSON.stringify(approval, null, 2));
await teamAppendEvent(teamName, {
type: "approval_decision",
worker: approval.reviewer,
task_id: approval.task_id,
reason: `${approval.status}: ${approval.decision_reason}`
}, cwd);
}
async function teamGetSummary(teamName, cwd) {
const startMs = Date.now();
const cfg = await teamReadConfig(teamName, cwd);
if (!cfg) return null;
const tasksStartMs = Date.now();
const tasks = await teamListTasks(teamName, cwd);
const tasksLoadedMs = Date.now() - tasksStartMs;
const counts = {
total: tasks.length,
pending: 0,
blocked: 0,
in_progress: 0,
completed: 0,
failed: 0
};
for (const t of tasks) {
if (t.status in counts) counts[t.status]++;
}
const workersStartMs = Date.now();
const workerEntries = [];
const nonReporting = [];
for (const w of cfg.workers) {
const hb = await teamReadWorkerHeartbeat(teamName, w.name, cwd);
if (!hb) {
nonReporting.push(w.name);
workerEntries.push({ name: w.name, alive: false, lastTurnAt: null, turnsWithoutProgress: 0 });
} else {
workerEntries.push({
name: w.name,
alive: hb.alive,
lastTurnAt: hb.last_turn_at,
turnsWithoutProgress: 0
});
}
}
const workersPollMs = Date.now() - workersStartMs;
const performance2 = {
total_ms: Date.now() - startMs,
tasks_loaded_ms: tasksLoadedMs,
workers_polled_ms: workersPollMs,
task_count: tasks.length,
worker_count: cfg.workers.length
};
return {
teamName,
workerCount: cfg.workers.length,
tasks: counts,
workers: workerEntries,
nonReportingWorkers: nonReporting,
performance: performance2
};
}
async function teamWriteShutdownRequest(teamName, workerName, requestedBy, cwd) {
const p = absPath(cwd, TeamPaths.shutdownRequest(teamName, workerName));
await writeAtomic(p, JSON.stringify({ requested_at: (/* @__PURE__ */ new Date()).toISOString(), requested_by: requestedBy }, null, 2));
}
async function teamReadShutdownAck(teamName, workerName, cwd, minUpdatedAt) {
const ackPath = absPath(cwd, TeamPaths.shutdownAck(teamName, workerName));
const parsed = await readJsonSafe(ackPath);
if (!parsed || parsed.status !== "accept" && parsed.status !== "reject") return null;
if (typeof minUpdatedAt === "string" && minUpdatedAt.trim() !== "") {
const minTs = Date.parse(minUpdatedAt);
const ackTs = Date.parse(parsed.updated_at ?? "");
if (!Number.isFinite(minTs) || !Number.isFinite(ackTs) || ackTs < minTs) return null;
}
return parsed;
}
async function teamReadMonitorSnapshot(teamName, cwd) {
const p = absPath(cwd, TeamPaths.monitorSnapshot(teamName));
return readJsonSafe(p);
}
async function teamWriteMonitorSnapshot(teamName, snapshot, cwd) {
const p = absPath(cwd, TeamPaths.monitorSnapshot(teamName));
await writeAtomic(p, JSON.stringify(snapshot, null, 2));
}
var init_team_ops = __esm({
"src/team/team-ops.ts"() {
"use strict";
init_state_paths();
init_governance();
init_governance();
init_contracts();
init_tasks();
init_worker_canonicalization();
}
});
// src/team/fs-utils.ts
import { writeFileSync, existsSync as existsSync3, mkdirSync, renameSync, openSync, writeSync, closeSync, realpathSync, constants } from "fs";
import { dirname as dirname2, resolve, relative, basename, join as join4 } from "path";
function atomicWriteJson(filePath, data, mode = 384) {
const dir = dirname2(filePath);
if (!existsSync3(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
writeFileSync(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode });
renameSync(tmpPath, filePath);
}
function ensureDirWithMode(dirPath, mode = 448) {
if (!existsSync3(dirPath)) mkdirSync(dirPath, { recursive: true, mode });
}
function safeRealpath(p) {
try {
return realpathSync(p);
} catch {
const segments = [];
let current = resolve(p);
while (!existsSync3(current)) {
segments.unshift(basename(current));
const parent = dirname2(current);
if (parent === current) break;
current = parent;
}
try {
return join4(realpathSync(current), ...segments);
} catch {
return resolve(p);
}
}
}
function validateResolvedPath(resolvedPath, expectedBase) {
const absResolved = safeRealpath(resolvedPath);
const absBase = safeRealpath(expectedBase);
const rel = relative(absBase, absResolved);
if (rel.startsWith("..") || resolve(absBase, rel) !== absResolved) {
throw new Error(`Path traversal detected: "${resolvedPath}" escapes base "${expectedBase}"`);
}
}
var init_fs_utils = __esm({
"src/team/fs-utils.ts"() {
"use strict";
}
});
// src/team/dispatch-queue.ts
import { randomUUID as randomUUID3 } from "crypto";
import { existsSync as existsSync4 } from "fs";
import { mkdir as mkdir2, readFile as readFile3, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
import { dirname as dirname3, join as join5 } from "path";
function validateWorkerName(name) {
if (!WORKER_NAME_SAFE_PATTERN.test(name)) {
throw new Error(`Invalid worker name: "${name}"`);
}
}
function isDispatchKind(value) {
return value === "inbox" || value === "mailbox" || value === "nudge";
}
function isDispatchStatus(value) {
return value === "pending" || value === "notified" || value === "delivered" || value === "failed";
}
function resolveDispatchLockTimeoutMs(env = process.env) {
const raw = env[OMC_DISPATCH_LOCK_TIMEOUT_ENV];
if (raw === void 0 || raw === "") return DEFAULT_DISPATCH_LOCK_TIMEOUT_MS;
const parsed = Number(raw);
if (!Number.isFinite(parsed)) return DEFAULT_DISPATCH_LOCK_TIMEOUT_MS;
return Math.max(MIN_DISPATCH_LOCK_TIMEOUT_MS, Math.min(MAX_DISPATCH_LOCK_TIMEOUT_MS, Math.floor(parsed)));
}
async function withDispatchLock(teamName, cwd, fn) {
const root = absPath(cwd, TeamPaths.root(teamName));
if (!existsSync4(root)) throw new Error(`Team ${teamName} not found`);
const lockDir = absPath(cwd, TeamPaths.dispatchLockDir(teamName));
const ownerPath = join5(lockDir, "owner");
const ownerToken = `${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
const timeoutMs = resolveDispatchLockTimeoutMs(process.env);
const deadline = Date.now() + timeoutMs;
let pollMs = DISPATCH_LOCK_INITIAL_POLL_MS;
await mkdir2(dirname3(lockDir), { recursive: true });
while (true) {
try {
await mkdir2(lockDir, { recursive: false });
try {
await writeFile2(ownerPath, ownerToken, "utf8");
} catch (error) {
await rm2(lockDir, { recursive: true, force: true });
throw error;
}
break;
} catch (error) {
const err = error;
if (err.code !== "EEXIST") throw error;
try {
const info = await stat(lockDir);
if (Date.now() - info.mtimeMs > LOCK_STALE_MS) {
await rm2(lockDir, { recursive: true, force: true });
continue;
}
} catch {
}
if (Date.now() > deadline) {
throw new Error(
`Timed out acquiring dispatch lock for ${teamName} after ${timeoutMs}ms. Set ${OMC_DISPATCH_LOCK_TIMEOUT_ENV} to increase (current: ${timeoutMs}ms, max: ${MAX_DISPATCH_LOCK_TIMEOUT_MS}ms).`
);
}
const jitter = 0.5 + Math.random() * 0.5;
await new Promise((resolve4) => setTimeout(resolve4, Math.floor(pollMs * jitter)));
pollMs = Math.min(pollMs * 2, DISPATCH_LOCK_MAX_POLL_MS);
}
}
try {
return await fn();
} finally {
try {
const currentOwner = await readFile3(ownerPath, "utf8");
if (currentOwner.trim() === ownerToken) {
await rm2(lockDir, { recursive: true, force: true });
}
} catch {
}
}
}
async function readDispatchRequestsFromFile(teamName, cwd) {
const path4 = absPath(cwd, TeamPaths.dispatchRequests(teamName));
try {
if (!existsSync4(path4)) return [];
const raw = await readFile3(path4, "utf8");
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed)) return [];
return parsed.map((entry) => normalizeDispatchRequest(teamName, entry)).filter((req) => req !== null);
} catch {
return [];
}
}
async function writeDispatchRequestsToFile(teamName, requests, cwd) {
const path4 = absPath(cwd, TeamPaths.dispatchRequests(teamName));
const dir = dirname3(path4);
ensureDirWithMode(dir);
atomicWriteJson(path4, requests);
}
function normalizeDispatchRequest(teamName, raw, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
if (!isDispatchKind(raw.kind)) return null;
if (typeof raw.to_worker !== "string" || raw.to_worker.trim() === "") return null;
if (typeof raw.trigger_message !== "string" || raw.trigger_message.trim() === "") return null;
const status = isDispatchStatus(raw.status) ? raw.status : "pending";
return {
request_id: typeof raw.request_id === "string" && raw.request_id.trim() !== "" ? raw.request_id : randomUUID3(),
kind: raw.kind,
team_name: teamName,
to_worker: raw.to_worker,
worker_index: typeof raw.worker_index === "number" ? raw.worker_index : void 0,
pane_id: typeof raw.pane_id === "string" && raw.pane_id !== "" ? raw.pane_id : void 0,
trigger_message: raw.trigger_message,
message_id: typeof raw.message_id === "string" && raw.message_id !== "" ? raw.message_id : void 0,
inbox_correlation_key: typeof raw.inbox_correlation_key === "string" && raw.inbox_correlation_key !== "" ? raw.inbox_correlation_key : void 0,
transport_preference: raw.transport_preference === "transport_direct" || raw.transport_preference === "prompt_stdin" ? raw.transport_preference : "hook_preferred_with_fallback",
fallback_allowed: raw.fallback_allowed !== false,
status,
attempt_count: Number.isFinite(raw.attempt_count) ? Math.max(0, Math.floor(raw.attempt_count)) : 0,
created_at: typeof raw.created_at === "string" && raw.created_at !== "" ? raw.created_at : nowIso,
updated_at: typeof raw.updated_at === "string" && raw.updated_at !== "" ? raw.updated_at : nowIso,
notified_at: typeof raw.notified_at === "string" && raw.notified_at !== "" ? raw.notified_at : void 0,
delivered_at: typeof raw.delivered_at === "string" && raw.delivered_at !== "" ? raw.delivered_at : void 0,
failed_at: typeof raw.failed_at === "string" && raw.failed_at !== "" ? raw.failed_at : void 0,
last_reason: typeof raw.last_reason === "string" && raw.last_reason !== "" ? raw.last_reason : void 0
};
}
function equivalentPendingDispatch(existing, input) {
if (existing.status !== "pending") return false;
if (existing.kind !== input.kind) return false;
if (existing.to_worker !== input.to_worker) return false;
if (input.kind === "mailbox") {
return Boolean(input.message_id) && existing.message_id === input.message_id;
}
if (input.kind === "inbox" && input.inbox_correlation_key) {
return existing.inbox_correlation_key === input.inbox_correlation_key;
}
return existing.trigger_message === input.trigger_message;
}
function canTransitionDispatchStatus(from, to) {
if (from === to) return true;
if (from === "pending" && (to === "notified" || to === "failed")) return true;
if (from === "notified" && (to === "delivered" || to === "failed")) return true;
return false;
}
async function enqueueDispatchRequest(teamName, requestInput, cwd) {
if (!isDispatchKind(requestInput.kind)) throw new Error(`Invalid dispatch request kind: ${String(requestInput.kind)}`);
if (requestInput.kind === "mailbox" && (!requestInput.message_id || requestInput.message_id.trim() === "")) {
throw new Error("mailbox dispatch requests require message_id");
}
validateWorkerName(requestInput.to_worker);
return await withDispatchLock(teamName, cwd, async () => {
const requests = await readDispatchRequestsFromFile(teamName, cwd);
const existing = requests.find((req) => equivalentPendingDispatch(req, requestInput));
if (existing) return { request: existing, deduped: true };
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
const request = normalizeDispatchRequest(
teamName,
{
request_id: randomUUID3(),
...requestInput,
status: "pending",
attempt_count: 0,
created_at: nowIso,
updated_at: nowIso
},
nowIso
);
if (!request) throw new Error("failed_to_normalize_dispatch_request");
requests.push(request);
await writeDispatchRequestsToFile(teamName, requests, cwd);
return { request, deduped: false };
});
}
async function listDispatchRequests(teamName, cwd, opts = {}) {
const requests = await readDispatchRequestsFromFile(teamName, cwd);
let filtered = requests;
if (opts.status) filtered = filtered.filter((req) => req.status === opts.status);
if (opts.kind) filtered = filtered.filter((req) => req.kind === opts.kind);
if (opts.to_worker) filtered = filtered.filter((req) => req.to_worker === opts.to_worker);
if (typeof opts.limit === "number" && opts.limit > 0) filtered = filtered.slice(0, opts.limit);
return filtered;
}
async function readDispatchRequest(teamName, requestId, cwd) {
const requests = await readDispatchRequestsFromFile(teamName, cwd);
return requests.find((req) => req.request_id === requestId) ?? null;
}
async function transitionDispatchRequest(teamName, requestId, from, to, patch = {}, cwd) {
return await withDispatchLock(teamName, cwd, async () => {
const requests = await readDispatchRequestsFromFile(teamName, cwd);
const index = requests.findIndex((req) => req.request_id === requestId);
if (index < 0) return null;
const existing = requests[index];
if (existing.status !== from && existing.status !== to) return null;
if (!canTransitionDispatchStatus(existing.status, to)) return null;
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
const nextAttemptCount = Math.max(
existing.attempt_count,
Number.isFinite(patch.attempt_count) ? Math.floor(patch.attempt_count) : existing.status === to ? existing.attempt_count : existing.attempt_count + 1
);
const next = {
...existing,
...patch,
status: to,
attempt_count: Math.max(0, nextAttemptCount),
updated_at: nowIso
};
if (to === "notified") next.notified_at = patch.notified_at ?? nowIso;
if (to === "delivered") next.delivered_at = patch.delivered_at ?? nowIso;
if (to === "failed") next.failed_at = patch.failed_at ?? nowIso;
requests[index] = next;
await writeDispatchRequestsToFile(teamName, requests, cwd);
return next;
});
}
async function markDispatchRequestNotified(teamName, requestId, patch = {}, cwd) {
const current = await readDispatchRequest(teamName, requestId, cwd);
if (!current) return null;
if (current.status === "notified" || current.status === "delivered") return current;
return await transitionDispatchRequest(teamName, requestId, current.status, "notified", patch, cwd);
}
async function markDispatchRequestDelivered(teamName, requestId, patch = {}, cwd) {
const current = await readDispatchRequest(teamName, requestId, cwd);
if (!current) return null;
if (current.status === "delivered") return current;
return await transitionDispatchRequest(teamName, requestId, current.status, "delivered", patch, cwd);
}
var OMC_DISPATCH_LOCK_TIMEOUT_ENV, DEFAULT_DISPATCH_LOCK_TIMEOUT_MS, MIN_DISPATCH_LOCK_TIMEOUT_MS, MAX_DISPATCH_LOCK_TIMEOUT_MS, DISPATCH_LOCK_INITIAL_POLL_MS, DISPATCH_LOCK_MAX_POLL_MS, LOCK_STALE_MS;
var init_dispatch_queue = __esm({
"src/team/dispatch-queue.ts"() {
"use strict";
init_state_paths();
init_fs_utils();
init_contracts();
OMC_DISPATCH_LOCK_TIMEOUT_ENV = "OMC_TEAM_DISPATCH_LOCK_TIMEOUT_MS";
DEFAULT_DISPATCH_LOCK_TIMEOUT_MS = 15e3;
MIN_DISPATCH_LOCK_TIMEOUT_MS = 1e3;
MAX_DISPATCH_LOCK_TIMEOUT_MS = 12e4;
DISPATCH_LOCK_INITIAL_POLL_MS = 25;
DISPATCH_LOCK_MAX_POLL_MS = 500;
LOCK_STALE_MS = 5 * 60 * 1e3;
}
});
// src/lib/swallowed-error.ts
function formatSwallowedError(error) {
if (error instanceof Error) return error.message;
if (typeof error === "string") return error;
try {
return JSON.stringify(error);
} catch {
return String(error);
}
}
function logSwallowedError(context, error) {
try {
console.warn(`[omc] ${context}: ${formatSwallowedError(error)}`);
} catch {
}
}
function createSwallowedErrorLogger(context) {
return (error) => {
logSwallowedError(context, error);
};
}
var init_swallowed_error = __esm({
"src/lib/swallowed-error.ts"() {
"use strict";
}
});
// src/team/mcp-comm.ts
function isConfirmedNotification(outcome) {
if (!outcome.ok) return false;
if (outcome.transport !== "hook") return true;
return outcome.reason !== "queued_for_hook_dispatch";
}
function isLeaderPaneMissingMailboxPersistedOutcome(request, outcome) {
return request.to_worker === "leader-fixed" && outcome.ok && outcome.reason === "leader_pane_missing_mailbox_persisted";
}
function fallbackTransportForPreference(preference) {
if (preference === "prompt_stdin") return "prompt_stdin";
if (preference === "transport_direct") return "tmux_send_keys";
return "hook";
}
function notifyExceptionReason(error) {
const message = error instanceof Error ? error.message : String(error);
return `notify_exception:${message}`;
}
async function markImmediateDispatchFailure(params) {
const { teamName, request, reason, messageId, cwd } = params;
if (request.transport_preference === "hook_preferred_with_fallback") return;
const logTransitionFailure = createSwallowedErrorLogger(
"team.mcp-comm.markImmediateDispatchFailure transitionDispatchRequest failed"
);
const current = await readDispatchRequest(teamName, request.request_id, cwd);
if (!current) return;
if (current.status === "failed" || current.status === "notified" || current.status === "delivered") return;
await transitionDispatchRequest(
teamName,
request.request_id,
current.status,
"failed",
{
message_id: messageId ?? current.message_id,
last_reason: reason
},
cwd
).catch(logTransitionFailure);
}
async function markLeaderPaneMissingDeferred(params) {
const { teamName, request, cwd, messageId } = params;
const logTransitionFailure = createSwallowedErrorLogger(
"team.mcp-comm.markLeaderPaneMissingDeferred transitionDispatchRequest failed"
);
const current = await readDispatchRequest(teamName, request.request_id, cwd);
if (!current) return;
if (current.status !== "pending") return;
await transitionDispatchRequest(
teamName,
request.request_id,
current.status,
current.status,
{
message_id: messageId ?? current.message_id,
last_reason: "leader_pane_missing_deferred"
},
cwd
).catch(logTransitionFailure);
}
async function queueInboxInstruction(params) {
const queued = await enqueueDispatchRequest(
params.teamName,
{
kind: "inbox",
to_worker: params.workerName,
worker_index: params.workerIndex,
pane_id: params.paneId,
trigger_message: params.triggerMessage,
transport_preference: params.transportPreference,
fallback_allowed: params.fallbackAllowed,
inbox_correlation_key: params.inboxCorrelationKey
},
params.cwd
);
if (queued.deduped) {
return {
ok: false,
transport: "none",
reason: "duplicate_pending_dispatch_request",
request_id: queued.request.request_id
};
}
try {
await params.deps.writeWorkerInbox(params.teamName, params.workerName, params.inbox, params.cwd);
} catch (error) {
await markImmediateDispatchFailure({
teamName: params.teamName,
request: queued.request,
reason: "inbox_write_failed",
cwd: params.cwd
});
throw error;
}
const notifyOutcome = await Promise.resolve(params.notify(
{ workerName: params.workerName, workerIndex: params.workerIndex, paneId: params.paneId },
params.triggerMessage,
{ request: queued.request }
)).catch((error) => ({
ok: false,
transport: fallbackTransportForPreference(params.transportPreference),
reason: notifyExceptionReason(error)
}));
const outcome = { ...notifyOutcome, request_id: queued.request.request_id };
if (isConfirmedNotification(outcome)) {
await markDispatchRequestNotified(
params.teamName,
queued.request.request_id,
{ last_reason: outcome.reason },
params.cwd
);
} else {
await markImmediateDispatchFailure({
teamName: params.teamName,
request: queued.request,
reason: outcome.reason,
cwd: params.cwd
});
}
return outcome;
}
async function queueDirectMailboxMessage(params) {
const message = await params.deps.sendDirectMessage(params.teamName, params.fromWorker, params.toWorker, params.body, params.cwd);
const queued = await enqueueDispatchRequest(
params.teamName,
{
kind: "mailbox",
to_worker: params.toWorker,
worker_index: params.toWorkerIndex,
pane_id: params.toPaneId,
trigger_message: params.triggerMessage,
message_id: message.message_id,
transport_preference: params.transportPreference,
fallback_allowed: params.fallbackAllowed
},
params.cwd
);
if (queued.deduped) {
return {
ok: false,
transport: "none",
reason: "duplicate_pending_dispatch_request",
request_id: queued.request.request_id,
message_id: message.message_id
};
}
const notifyOutcome = await Promise.resolve(params.notify(
{ workerName: params.toWorker, workerIndex: params.toWorkerIndex, paneId: params.toPaneId },
params.triggerMessage,
{ request: queued.request, message_id: message.message_id }
)).catch((error) => ({
ok: false,
transport: fallbackTransportForPreference(params.transportPreference),
reason: notifyExceptionReason(error)
}));
const outcome = {
...notifyOutcome,
request_id: queued.request.request_id,
message_id: message.message_id,
to_worker: params.toWorker
};
if (isLeaderPaneMissingMailboxPersistedOutcome(queued.request, outcome)) {
await markLeaderPaneMissingDeferred({
teamName: params.teamName,
request: queued.request,
cwd: params.cwd,
messageId: message.message_id
});
return outcome;
}
if (isConfirmedNotification(outcome)) {
await params.deps.markMessageNotified(params.teamName, params.toWorker, message.message_id, params.cwd);
await markDispatchRequestNotified(
params.teamName,
queued.request.request_id,
{ message_id: message.message_id, last_reason: outcome.reason },
params.cwd
);
} else {
await markImmediateDispatchFailure({
teamName: params.teamName,
request: queued.request,
reason: outcome.reason,
messageId: message.message_id,
cwd: params.cwd
});
}
return outcome;
}
async function queueBroadcastMailboxMessage(params) {
const messages = await params.deps.broadcastMessage(params.teamName, params.fromWorker, params.body, params.cwd);
const recipientByName = new Map(params.recipients.map((r) => [r.workerName, r]));
const outcomes = [];
for (const message of messages) {
const recipient = recipientByName.get(message.to_worker);
if (!recipient) continue;
const queued = await enqueueDispatchRequest(
params.teamName,
{
kind: "mailbox",
to_worker: recipient.workerName,
worker_index: recipient.workerIndex,
pane_id: recipient.paneId,
trigger_message: params.triggerFor(recipient.workerName),
message_id: message.message_id,
transport_preference: params.transportPreference,
fallback_allowed: params.fallbackAllowed
},
params.cwd
);
if (queued.deduped) {
outcomes.push({
ok: false,
transport: "none",
reason: "duplicate_pending_dispatch_request",
request_id: queued.request.request_id,
message_id: message.message_id,
to_worker: recipient.workerName
});
continue;
}
const notifyOutcome = await Promise.resolve(params.notify(
{ workerName: recipient.workerName, workerIndex: recipient.workerIndex, paneId: recipient.paneId },
params.triggerFor(recipient.workerName),
{ request: queued.request, message_id: message.message_id }
)).catch((error) => ({
ok: false,
transport: fallbackTransportForPreference(params.transportPreference),
reason: notifyExceptionReason(error)
}));
const outcome = {
...notifyOutcome,
request_id: queued.request.request_id,
message_id: message.message_id,
to_worker: recipient.workerName
};
outcomes.push(outcome);
if (isConfirmedNotification(outcome)) {
await params.deps.markMessageNotified(params.teamName, recipient.workerName, message.message_id, params.cwd);
await markDispatchRequestNotified(
params.teamName,
queued.request.request_id,
{ message_id: message.message_id, last_reason: outcome.reason },
params.cwd
);
} else {
await markImmediateDispatchFailure({
teamName: params.teamName,
request: queued.request,
reason: outcome.reason,
messageId: message.message_id,
cwd: params.cwd
});
}
}
return outcomes;
}
var init_mcp_comm = __esm({
"src/team/mcp-comm.ts"() {
"use strict";
init_dispatch_queue();
init_swallowed_error();
}
});
// src/team/team-name.ts
function validateTeamName(teamName) {
if (!TEAM_NAME_PATTERN.test(teamName)) {
throw new Error(
`Invalid team name: "${teamName}". Team name must match /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/.`
);
}
return teamName;
}
var TEAM_NAME_PATTERN;
var init_team_name = __esm({
"src/team/team-name.ts"() {
"use strict";
TEAM_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/;
}
});
// src/cli/tmux-utils.ts
import {
exec,
execFile,
execFileSync,
execSync,
spawnSync
} from "child_process";
import { basename as basename2, isAbsolute as isAbsolute2, win32 as win32Path } from "path";
import { promisify } from "util";
function tmuxEnv() {
const { TMUX: _, ...env } = process.env;
return env;
}
function resolveEnv(opts) {
return opts?.stripTmux ? tmuxEnv() : process.env;
}
function quoteForCmd(arg) {
if (arg.length === 0) return '""';
if (!/[\s"%^&|<>()]/.test(arg)) return arg;
return `"${arg.replace(/(["%])/g, "$1$1")}"`;
}
function resolveTmuxInvocation(args) {
const resolvedBinary = resolveTmuxBinaryPath();
if (process.platform === "win32" && /\.(cmd|bat)$/i.test(resolvedBinary)) {
const comspec = process.env.COMSPEC || "cmd.exe";
const commandLine = [quoteForCmd(resolvedBinary), ...args.map(quoteForCmd)].join(" ");
return {
command: comspec,
args: ["/d", "/s", "/c", commandLine]
};
}
return {
command: resolvedBinary,
args
};
}
function tmuxExec(args, opts) {
const { stripTmux: _, ...execOpts } = opts ?? {};
const invocation = resolveTmuxInvocation(args);
return execFileSync(invocation.command, invocation.args, { encoding: "utf-8", ...execOpts, env: resolveEnv(opts) });
}
async function tmuxExecAsync(args, opts) {
const { stripTmux: _, timeout, ...rest } = opts ?? {};
const invocation = resolveTmuxInvocation(args);
return promisify(execFile)(invocation.command, invocation.args, {
encoding: "utf-8",
env: resolveEnv(opts),
...timeout !== void 0 ? { timeout } : {},
...rest
});
}
function tmuxShell(command, opts) {
const { stripTmux: _, ...execOpts } = opts ?? {};
return execSync(`tmux ${command}`, { encoding: "utf-8", ...execOpts, env: resolveEnv(opts) });
}
async function tmuxShellAsync(command, opts) {
const { stripTmux: _, timeout, ...rest } = opts ?? {};
return promisify(exec)(`tmux ${command}`, {
encoding: "utf-8",
env: resolveEnv(opts),
...timeout !== void 0 ? { timeout } : {},
...rest
});
}
async function tmuxCmdAsync(args, opts) {
if (args.some((a) => a.includes("#{"))) {
const escaped = args.map((a) => "'" + a.replace(/'/g, "'\\''") + "'").join(" ");
return tmuxShellAsync(escaped, opts);
}
return tmuxExecAsync(args, opts);
}
function resolveTmuxBinaryPath() {
if (process.platform !== "win32") {
return "tmux";
}
try {
const result = spawnSync("where", ["tmux"], {
timeout: 5e3,
encoding: "utf8"
});
if (result.status !== 0) return "tmux";
const candidates = result.stdout?.split(/\r?\n/).map((line) => line.trim()).filter(Boolean) ?? [];
const first = candidates[0];
if (first && (isAbsolute2(first) || win32Path.isAbsolute(first))) {
return first;
}
} catch {
}
return "tmux";
}
var init_tmux_utils = __esm({
"src/cli/tmux-utils.ts"() {
"use strict";
}
});
// src/team/tmux-session.ts
var tmux_session_exports = {};
__export(tmux_session_exports, {
applyMainVerticalLayout: () => applyMainVerticalLayout,
buildWorkerLaunchSpec: () => buildWorkerLaunchSpec,
buildWorkerStartCommand: () => buildWorkerStartCommand,
createSession: () => createSession,
createTeamSession: () => createTeamSession,
detectTeamMultiplexerContext: () => detectTeamMultiplexerContext,
getDefaultShell: () => getDefaultShell,
injectToLeaderPane: () => injectToLeaderPane,
isSessionAlive: () => isSessionAlive,
isUnixLikeOnWindows: () => isUnixLikeOnWindows,
isWorkerAlive: () => isWorkerAlive,
killSession: () => killSession,
killTeamSession: () => killTeamSession,
killWorkerPanes: () => killWorkerPanes,
listActiveSessions: () => listActiveSessions,
paneHasActiveTask: () => paneHasActiveTask,
paneLooksReady: () => paneLooksReady,
resolveShellFromCandidates: () => resolveShellFromCandidates,
resolveSplitPaneWorkerPaneIds: () => resolveSplitPaneWorkerPaneIds,
resolveSupportedShellAffinity: () => resolveSupportedShellAffinity,
sanitizeName: () => sanitizeName,
sendToWorker: () => sendToWorker,
sessionName: () => sessionName,
shouldAttemptAdaptiveRetry: () => shouldAttemptAdaptiveRetry,
spawnBridgeInSession: () => spawnBridgeInSession,
spawnWorkerInPane: () => spawnWorkerInPane,
validateTmux: () => validateTmux,
waitForPaneReady: () => waitForPaneReady
});
import { existsSync as existsSync5 } from "fs";
import { join as join6, basename as basename3, isAbsolute as isAbsolute3, win32 } from "path";
import fs from "fs/promises";
function detectTeamMultiplexerContext(env = process.env) {
if (env.TMUX) return "tmux";
if (env.CMUX_SURFACE_ID) return "cmux";
return "none";
}
function isUnixLikeOnWindows() {
return process.platform === "win32" && !!(process.env.MSYSTEM || process.env.MINGW_PREFIX);
}
async function applyMainVerticalLayout(teamTarget) {
try {
await tmuxExecAsync(["select-layout", "-t", teamTarget, "main-vertical"]);
} catch {
}
try {
const widthResult = await tmuxCmdAsync([
"display-message",
"-p",
"-t",
teamTarget,
"#{window_width}"
]);
const width = parseInt(widthResult.stdout.trim(), 10);
if (Number.isFinite(width) && width >= 40) {
const half = String(Math.floor(width / 2));
await tmuxExecAsync(["set-window-option", "-t", teamTarget, "main-pane-width", half]);
await tmuxExecAsync(["select-layout", "-t", teamTarget, "main-vertical"]);
}
} catch {
}
}
function getDefaultShell() {
if (process.platform === "win32" && !isUnixLikeOnWindows()) {
return process.env.COMSPEC || "cmd.exe";
}
const shell = process.env.SHELL || "/bin/bash";
const name = basename3(shell.replace(/\\/g, "/")).replace(/\.(exe|cmd|bat)$/i, "");
if (!SUPPORTED_POSIX_SHELLS.has(name)) {
return "/bin/sh";
}
return shell;
}
function pathEntries(envPath) {
return (envPath ?? "").split(process.platform === "win32" ? ";" : ":").map((entry) => entry.trim()).filter(Boolean);
}
function pathCandidateNames(candidatePath) {
const base = basename3(candidatePath.replace(/\\/g, "/"));
const bare = base.replace(/\.(exe|cmd|bat)$/i, "");
if (process.platform === "win32") {
return Array.from(/* @__PURE__ */ new Set([`${bare}.exe`, `${bare}.cmd`, `${bare}.bat`, bare]));
}
return Array.from(/* @__PURE__ */ new Set([base, bare]));
}
function resolveShellFromPath(candidatePath) {
for (const dir of pathEntries(process.env.PATH)) {
for (const name of pathCandidateNames(candidatePath)) {
const full = join6(dir, name);
if (existsSync5(full)) return full;
}
}
return null;
}
function resolveShellFromCandidates(paths, rcFile) {
for (const p of paths) {
if (existsSync5(p)) return { shell: p, rcFile };
const resolvedFromPath = resolveShellFromPath(p);
if (resolvedFromPath) return { shell: resolvedFromPath, rcFile };
}
return null;
}
function resolveSupportedShellAffinity(shellPath) {
if (!shellPath) return null;
const name = basename3(shellPath.replace(/\\/g, "/")).replace(/\.(exe|cmd|bat)$/i, "");
if (name !== "zsh" && name !== "bash") return null;
if (!existsSync5(shellPath)) return null;
const home = process.env.HOME ?? "";
const rcFile = home ? `${home}/.${name}rc` : null;
return { shell: shellPath, rcFile };
}
function buildWorkerLaunchSpec(shellPath) {
if (isUnixLikeOnWindows()) {
return { shell: "/bin/sh", rcFile: null };
}
const preferred = resolveSupportedShellAffinity(shellPath);
if (preferred) return preferred;
const home = process.env.HOME ?? "";
const zshRc = home ? `${home}/.zshrc` : null;
const zsh = resolveShellFromCandidates(ZSH_CANDIDATES, zshRc ?? "");
if (zsh) return { shell: zsh.shell, rcFile: zshRc };
const bashRc = home ? `${home}/.bashrc` : null;
const bash = resolveShellFromCandidates(BASH_CANDIDATES, bashRc ?? "");
if (bash) return { shell: bash.shell, rcFile: bashRc };
return { shell: "/bin/sh", rcFile: null };
}
function escapeForCmdSet(value) {
return value.replace(/"/g, '""');
}
function shellNameFromPath(shellPath) {
const shellName = basename3(shellPath.replace(/\\/g, "/"));
return shellName.replace(/\.(exe|cmd|bat)$/i, "");
}
function shellEscape(value) {
return `'${value.replace(/'/g, `'"'"'`)}'`;
}
function assertSafeEnvKey(key) {
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
throw new Error(`Invalid environment key: "${key}"`);
}
}
function isAbsoluteLaunchBinaryPath(value) {
return isAbsolute3(value) || win32.isAbsolute(value);
}
function assertSafeLaunchBinary(launchBinary) {
if (launchBinary.trim().length === 0) {
throw new Error("Invalid launchBinary: value cannot be empty");
}
if (launchBinary !== launchBinary.trim()) {
throw new Error("Invalid launchBinary: value cannot have leading/trailing whitespace");
}
if (DANGEROUS_LAUNCH_BINARY_CHARS.test(launchBinary)) {
throw new Error("Invalid launchBinary: contains dangerous shell metacharacters");
}
if (/\s/.test(launchBinary) && !isAbsoluteLaunchBinaryPath(launchBinary)) {
throw new Error("Invalid launchBinary: paths with spaces must be absolute");
}
}
function getLaunchWords(config) {
if (config.launchBinary) {
assertSafeLaunchBinary(config.launchBinary);
return [config.launchBinary, ...config.launchArgs ?? []];
}
if (config.launchCmd) {
throw new Error(
"launchCmd is deprecated and has been removed for security reasons. Use launchBinary + launchArgs instead."
);
}
throw new Error("Missing worker launch command. Provide launchBinary or launchCmd.");
}
function buildWorkerStartCommand(config) {
const shell = getDefaultShell();
const launchSpec = buildWorkerLaunchSpec(process.env.SHELL);
const launchWords = getLaunchWords(config);
const shouldSourceRc = process.env.OMC_TEAM_NO_RC !== "1";
if (process.platform === "win32" && !isUnixLikeOnWindows()) {
const envPrefix = Object.entries(config.envVars).map(([k, v]) => {
assertSafeEnvKey(k);
return `set "${k}=${escapeForCmdSet(v)}"`;
}).join(" && ");
const launch = config.launchBinary ? launchWords.map((part) => `"${escapeForCmdSet(part)}"`).join(" ") : launchWords[0];
const cmdBody = envPrefix ? `${envPrefix} && ${launch}` : launch;
return `${shell} /d /s /c "${cmdBody}"`;
}
if (config.launchBinary) {
const envAssignments = Object.entries(config.envVars).map(([key, value]) => {
assertSafeEnvKey(key);
return `${key}=${shellEscape(value)}`;
});
const shellName2 = shellNameFromPath(shell) || "bash";
const isFish2 = shellName2 === "fish";
const execArgsCommand = isFish2 ? "exec $argv" : 'exec "$@"';
let rcFile2 = (launchSpec.shell === shell ? launchSpec.rcFile : null) ?? "";
if (!rcFile2 && process.env.HOME) {
rcFile2 = isFish2 ? `${process.env.HOME}/.config/fish/config.fish` : `${process.env.HOME}/.${shellName2}rc`;
}
let script;
if (isFish2) {
script = shouldSourceRc && rcFile2 ? `test -f ${shellEscape(rcFile2)}; and source ${shellEscape(rcFile2)}; ${execArgsCommand}` : execArgsCommand;
} else {
script = shouldSourceRc && rcFile2 ? `[ -f ${shellEscape(rcFile2)} ] && . ${shellEscape(rcFile2)}; ${execArgsCommand}` : execArgsCommand;
}
const shellFlags = isFish2 ? ["-l", "-c"] : ["-lc"];
return [
shellEscape("env"),
...envAssignments,
...[shell, ...shellFlags, script, "--", ...launchWords].map(shellEscape)
].join(" ");
}
const envString = Object.entries(config.envVars).map(([k, v]) => {
assertSafeEnvKey(k);
return `${k}=${shellEscape(v)}`;
}).join(" ");
const shellName = shellNameFromPath(shell) || "bash";
const isFish = shellName === "fish";
let rcFile = (launchSpec.shell === shell ? launchSpec.rcFile : null) ?? "";
if (!rcFile && process.env.HOME) {
rcFile = isFish ? `${process.env.HOME}/.config/fish/config.fish` : `${process.env.HOME}/.${shellName}rc`;
}
let sourceCmd = "";
if (shouldSourceRc && rcFile) {
sourceCmd = isFish ? `test -f "${rcFile}"; and source "${rcFile}"; ` : `[ -f "${rcFile}" ] && source "${rcFile}"; `;
}
return `env ${envString} ${shell} -c "${sourceCmd}exec ${launchWords[0]}"`;
}
function validateTmux(hasTmuxContext = false) {
if (hasTmuxContext) {
return;
}
try {
tmuxShell("-V", { stripTmux: true, timeout: 5e3, stdio: "pipe" });
} catch {
throw new Error(
"tmux is not available. Install it:\n macOS: brew install tmux\n Ubuntu/Debian: sudo apt-get install tmux\n Fedora: sudo dnf install tmux\n Arch: sudo pacman -S tmux\n Windows: winget install psmux"
);
}
}
function sanitizeName(name) {
const sanitized = name.replace(/[^a-zA-Z0-9-]/g, "");
if (sanitized.length === 0) {
throw new Error(`Invalid name: "${name}" contains no valid characters (alphanumeric or hyphen)`);
}
if (sanitized.length < 2) {
throw new Error(`Invalid name: "${name}" too short after sanitization (minimum 2 characters)`);
}
return sanitized.slice(0, 50);
}
function sessionName(teamName, workerName) {
return `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-${sanitizeName(workerName)}`;
}
function createSession(teamName, workerName, workingDirectory) {
const name = sessionName(teamName, workerName);
try {
tmuxExec(["kill-session", "-t", name], { stripTmux: true, stdio: "pipe", timeout: 5e3 });
} catch {
}
const args = ["new-session", "-d", "-s", name, "-x", "200", "-y", "50"];
if (workingDirectory) {
args.push("-c", workingDirectory);
}
tmuxExec(args, { stripTmux: true, stdio: "pipe", timeout: 5e3 });
return name;
}
function killSession(teamName, workerName) {
const name = sessionName(teamName, workerName);
try {
tmuxExec(["kill-session", "-t", name], { stripTmux: true, stdio: "pipe", timeout: 5e3 });
} catch {
}
}
function isSessionAlive(teamName, workerName) {
const name = sessionName(teamName, workerName);
try {
tmuxExec(["has-session", "-t", name], { stripTmux: true, stdio: "pipe", timeout: 5e3 });
return true;
} catch {
return false;
}
}
function listActiveSessions(teamName) {
const prefix = `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-`;
try {
const output2 = tmuxShell("list-sessions -F '#{session_name}'", {
timeout: 5e3,
stdio: ["pipe", "pipe", "pipe"]
});
return output2.trim().split("\n").filter((s) => s.startsWith(prefix)).map((s) => s.slice(prefix.length));
} catch {
return [];
}
}
function spawnBridgeInSession(tmuxSession, bridgeScriptPath, configFilePath) {
const cmd = `node "${bridgeScriptPath}" --config "${configFilePath}"`;
tmuxExec(["send-keys", "-t", tmuxSession, cmd, "Enter"], { stripTmux: true, stdio: "pipe", timeout: 5e3 });
}
async function createTeamSession(teamName, workerCount, cwd, options = {}) {
const multiplexerContext = detectTeamMultiplexerContext();
const inTmux = multiplexerContext === "tmux";
const useDedicatedWindow = Boolean(options.newWindow && inTmux);
if (!inTmux) {
validateTmux();
}
const envPaneIdRaw = (process.env.TMUX_PANE ?? "").trim();
const envPaneId = /^%\d+$/.test(envPaneIdRaw) ? envPaneIdRaw : "";
let sessionAndWindow = "";
let leaderPaneId = envPaneId;
let sessionMode = inTmux ? "split-pane" : "detached-session";
if (!inTmux) {
const detachedSessionName = `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-${Date.now().toString(36)}`;
const detachedResult = await tmuxExecAsync([
"new-session",
"-d",
"-P",
"-F",
"#S:0 #{pane_id}",
"-s",
detachedSessionName,
"-c",
cwd
], { stripTmux: true });
const detachedLine = detachedResult.stdout.trim();
const detachedMatch = detachedLine.match(/^(\S+)\s+(%\d+)$/);
if (!detachedMatch) {
throw new Error(`Failed to create detached tmux session: "${detachedLine}"`);
}
sessionAndWindow = detachedMatch[1];
leaderPaneId = detachedMatch[2];
}
if (inTmux && envPaneId) {
try {
const targetedContextResult = await tmuxExecAsync([
"display-message",
"-p",
"-t",
envPaneId,
"#S:#I"
]);
sessionAndWindow = targetedContextResult.stdout.trim();
} catch {
sessionAndWindow = "";
leaderPaneId = "";
}
}
if (!sessionAndWindow || !leaderPaneId) {
const contextResult = await tmuxCmdAsync([
"display-message",
"-p",
"#S:#I #{pane_id}"
]);
const contextLine = contextResult.stdout.trim();
const contextMatch = contextLine.match(/^(\S+)\s+(%\d+)$/);
if (!contextMatch) {
throw new Error(`Failed to resolve tmux context: "${contextLine}"`);
}
sessionAndWindow = contextMatch[1];
leaderPaneId = contextMatch[2];
}
if (useDedicatedWindow) {
const targetSession = sessionAndWindow.split(":")[0] ?? sessionAndWindow;
const windowName = `omc-${sanitizeName(teamName)}`.slice(0, 32);
const newWindowResult = await tmuxExecAsync([
"new-window",
"-d",
"-P",
"-F",
"#S:#I #{pane_id}",
"-t",
targetSession,
"-n",
windowName,
"-c",
cwd
]);
const newWindowLine = newWindowResult.stdout.trim();
const newWindowMatch = newWindowLine.match(/^(\S+)\s+(%\d+)$/);
if (!newWindowMatch) {
throw new Error(`Failed to create team tmux window: "${newWindowLine}"`);
}
sessionAndWindow = newWindowMatch[1];
leaderPaneId = newWindowMatch[2];
sessionMode = "dedicated-window";
}
const teamTarget = sessionAndWindow;
const resolvedSessionName = teamTarget.split(":")[0];
const workerPaneIds = [];
if (workerCount <= 0) {
try {
await tmuxExecAsync(["set-option", "-t", resolvedSessionName, "mouse", "on"]);
} catch {
}
if (sessionMode !== "dedicated-window") {
try {
await tmuxExecAsync(["select-pane", "-t", leaderPaneId]);
} catch {
}
}
await new Promise((r) => setTimeout(r, 300));
return { sessionName: teamTarget, leaderPaneId, workerPaneIds, sessionMode };
}
for (let i = 0; i < workerCount; i++) {
const splitTarget = i === 0 ? leaderPaneId : workerPaneIds[i - 1];
const splitType = i === 0 ? "-h" : "-v";
const splitResult = await tmuxCmdAsync([
"split-window",
splitType,
"-t",
splitTarget,
"-d",
"-P",
"-F",
"#{pane_id}",
"-c",
cwd
]);
const paneId = splitResult.stdout.split("\n")[0]?.trim();
if (paneId) {
workerPaneIds.push(paneId);
}
}
await applyMainVerticalLayout(teamTarget);
try {
await tmuxExecAsync(["set-option", "-t", resolvedSessionName, "mouse", "on"]);
} catch {
}
if (sessionMode !== "dedicated-window") {
try {
await tmuxExecAsync(["select-pane", "-t", leaderPaneId]);
} catch {
}
}
await new Promise((r) => setTimeout(r, 300));
return { sessionName: teamTarget, leaderPaneId, workerPaneIds, sessionMode };
}
async function spawnWorkerInPane(sessionName2, paneId, config) {
validateTeamName(config.teamName);
const startCmd = buildWorkerStartCommand(config);
await tmuxExecAsync([
"send-keys",
"-t",
paneId,
"-l",
startCmd
]);
await tmuxExecAsync(["send-keys", "-t", paneId, "Enter"]);
}
function normalizeTmuxCapture(value) {
return value.replace(/\r/g, "").replace(/\s+/g, " ").trim();
}
async function capturePaneAsync(paneId) {
try {
const result = await tmuxExecAsync(["capture-pane", "-t", paneId, "-p", "-S", "-80"]);
return result.stdout;
} catch {
return "";
}
}
function paneHasTrustPrompt(captured) {
const lines = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
const tail = lines.slice(-12);
const hasQuestion = tail.some((l) => /Do you trust the contents of this directory\?/i.test(l));
const hasChoices = tail.some((l) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(l));
return hasQuestion && hasChoices;
}
function paneIsBootstrapping(captured) {
const lines = captured.split("\n").map((line) => line.replace(/\r/g, "").trim()).filter((line) => line.length > 0);
return lines.some(
(line) => /\b(loading|initializing|starting up)\b/i.test(line) || /\bmodel:\s*loading\b/i.test(line) || /\bconnecting\s+to\b/i.test(line)
);
}
function paneHasActiveTask(captured) {
const lines = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
const tail = lines.slice(-40);
if (tail.some((l) => /\b\d+\s+background terminal running\b/i.test(l))) return true;
if (tail.some((l) => /esc to interrupt/i.test(l))) return true;
if (tail.some((l) => /\bbackground terminal running\b/i.test(l))) return true;
if (tail.some((l) => /^[·]\s+[A-Za-z][A-Za-z0-9''-]*(?:\s+[A-Za-z][A-Za-z0-9''-]*){0,3}(?:|\.{3})$/u.test(l))) return true;
return false;
}
function paneLooksReady(captured) {
const content = captured.trimEnd();
if (content === "") return false;
const lines = content.split("\n").map((line) => line.replace(/\r/g, "").trimEnd()).filter((line) => line.trim() !== "");
if (lines.length === 0) return false;
if (paneIsBootstrapping(content)) return false;
const lastLine = lines[lines.length - 1];
if (/^\s*[>]\s*/u.test(lastLine)) return true;
const hasCodexPromptLine = lines.some((line) => /^\s*\s*/u.test(line));
const hasClaudePromptLine = lines.some((line) => /^\s*\s*/u.test(line));
return hasCodexPromptLine || hasClaudePromptLine;
}
async function waitForPaneReady(paneId, opts = {}) {
const envTimeout = Number.parseInt(process.env.OMC_SHELL_READY_TIMEOUT_MS ?? "", 10);
const timeoutMs = Number.isFinite(opts.timeoutMs) && (opts.timeoutMs ?? 0) > 0 ? Number(opts.timeoutMs) : Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 3e4;
const pollIntervalMs = Number.isFinite(opts.pollIntervalMs) && (opts.pollIntervalMs ?? 0) > 0 ? Number(opts.pollIntervalMs) : 250;
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const captured = await capturePaneAsync(paneId);
if (paneLooksReady(captured) && !paneHasActiveTask(captured)) {
return true;
}
await sleep(pollIntervalMs);
}
console.warn(
`[tmux-session] waitForPaneReady: pane ${paneId} timed out after ${timeoutMs}ms (set OMC_SHELL_READY_TIMEOUT_MS to tune)`
);
return false;
}
function paneTailContainsLiteralLine(captured, text) {
return normalizeTmuxCapture(captured).includes(normalizeTmuxCapture(text));
}
async function paneInCopyMode(paneId) {
try {
const result = await tmuxCmdAsync(["display-message", "-t", paneId, "-p", "#{pane_in_mode}"]);
return result.stdout.trim() === "1";
} catch {
return false;
}
}
function shouldAttemptAdaptiveRetry(args) {
if (process.env.OMC_TEAM_AUTO_INTERRUPT_RETRY === "0") return false;
if (args.retriesAttempted >= 1) return false;
if (args.paneInCopyMode) return false;
if (!args.paneBusy) return false;
if (typeof args.latestCapture !== "string") return false;
if (!paneTailContainsLiteralLine(args.latestCapture, args.message)) return false;
if (paneHasActiveTask(args.latestCapture)) return false;
if (!paneLooksReady(args.latestCapture)) return false;
return true;
}
async function sendToWorker(_sessionName, paneId, message) {
if (message.length > 200) {
console.warn(`[tmux-session] sendToWorker: message rejected (${message.length} chars exceeds 200 char limit)`);
return false;
}
try {
const sendKey = async (key) => {
await tmuxExecAsync(["send-keys", "-t", paneId, key]);
};
if (await paneInCopyMode(paneId)) {
return false;
}
const initialCapture = await capturePaneAsync(paneId);
const paneBusy = paneHasActiveTask(initialCapture);
if (paneHasTrustPrompt(initialCapture)) {
await sendKey("C-m");
await sleep(120);
await sendKey("C-m");
await sleep(200);
}
await tmuxExecAsync(["send-keys", "-t", paneId, "-l", "--", message]);
await sleep(150);
const submitRounds = 6;
for (let round = 0; round < submitRounds; round++) {
await sleep(100);
if (round === 0 && paneBusy) {
await sendKey("Tab");
await sleep(80);
await sendKey("C-m");
} else {
await sendKey("C-m");
await sleep(200);
await sendKey("C-m");
}
await sleep(140);
const checkCapture = await capturePaneAsync(paneId);
if (!paneTailContainsLiteralLine(checkCapture, message)) return true;
await sleep(140);
}
if (await paneInCopyMode(paneId)) {
return false;
}
const finalCapture = await capturePaneAsync(paneId);
const paneModeBeforeAdaptiveRetry = await paneInCopyMode(paneId);
if (shouldAttemptAdaptiveRetry({
paneBusy,
latestCapture: finalCapture,
message,
paneInCopyMode: paneModeBeforeAdaptiveRetry,
retriesAttempted: 0
})) {
if (await paneInCopyMode(paneId)) {
return false;
}
await sendKey("C-u");
await sleep(80);
if (await paneInCopyMode(paneId)) {
return false;
}
await tmuxExecAsync(["send-keys", "-t", paneId, "-l", "--", message]);
await sleep(120);
for (let round = 0; round < 4; round++) {
await sendKey("C-m");
await sleep(180);
await sendKey("C-m");
await sleep(140);
const retryCapture = await capturePaneAsync(paneId);
if (!paneTailContainsLiteralLine(retryCapture, message)) return true;
}
}
if (await paneInCopyMode(paneId)) {
return false;
}
await sendKey("C-m");
await sleep(120);
await sendKey("C-m");
await sleep(140);
const finalCheckCapture = await capturePaneAsync(paneId);
if (!finalCheckCapture || finalCheckCapture.trim() === "") {
return false;
}
return !paneTailContainsLiteralLine(finalCheckCapture, message);
} catch {
return false;
}
}
async function injectToLeaderPane(sessionName2, leaderPaneId, message) {
const prefixed = `[OMC_TMUX_INJECT] ${message}`.slice(0, 200);
try {
if (await paneInCopyMode(leaderPaneId)) {
return false;
}
const captured = await capturePaneAsync(leaderPaneId);
if (paneHasActiveTask(captured)) {
await tmuxExecAsync(["send-keys", "-t", leaderPaneId, "C-c"]);
await new Promise((r) => setTimeout(r, 250));
}
} catch {
}
return sendToWorker(sessionName2, leaderPaneId, prefixed);
}
async function isWorkerAlive(paneId) {
try {
const result = await tmuxCmdAsync([
"display-message",
"-t",
paneId,
"-p",
"#{pane_dead}"
]);
return result.stdout.trim() === "0";
} catch {
return false;
}
}
async function killWorkerPanes(opts) {
const { paneIds, leaderPaneId, teamName, cwd, graceMs = 1e4 } = opts;
if (!paneIds.length) return;
const shutdownPath = join6(cwd, ".omc", "state", "team", teamName, "shutdown.json");
try {
await fs.writeFile(shutdownPath, JSON.stringify({ requestedAt: Date.now() }));
const aliveChecks = await Promise.all(paneIds.map((id) => isWorkerAlive(id)));
if (aliveChecks.some((alive) => alive)) {
await sleep(graceMs);
}
} catch {
}
for (const paneId of paneIds) {
if (paneId === leaderPaneId) continue;
try {
await tmuxExecAsync(["kill-pane", "-t", paneId]);
} catch {
}
}
}
function isPaneId(value) {
return typeof value === "string" && /^%\d+$/.test(value.trim());
}
function dedupeWorkerPaneIds(paneIds, leaderPaneId) {
const unique = /* @__PURE__ */ new Set();
for (const paneId of paneIds) {
if (!isPaneId(paneId)) continue;
const normalized = paneId.trim();
if (normalized === leaderPaneId) continue;
unique.add(normalized);
}
return [...unique];
}
async function resolveSplitPaneWorkerPaneIds(sessionName2, recordedPaneIds, leaderPaneId) {
const resolved = dedupeWorkerPaneIds(recordedPaneIds ?? [], leaderPaneId);
if (!sessionName2.includes(":")) return resolved;
try {
const paneResult = await tmuxCmdAsync(["list-panes", "-t", sessionName2, "-F", "#{pane_id}"]);
return dedupeWorkerPaneIds(
[...resolved, ...paneResult.stdout.split("\n").map((paneId) => paneId.trim())],
leaderPaneId
);
} catch {
return resolved;
}
}
async function killTeamSession(sessionName2, workerPaneIds, leaderPaneId, options = {}) {
const sessionMode = options.sessionMode ?? (sessionName2.includes(":") ? "split-pane" : "detached-session");
if (sessionMode === "split-pane") {
if (!workerPaneIds?.length) return;
for (const id of workerPaneIds) {
if (id === leaderPaneId) continue;
try {
await tmuxExecAsync(["kill-pane", "-t", id]);
} catch {
}
}
return;
}
if (sessionMode === "dedicated-window") {
try {
await tmuxExecAsync(["kill-window", "-t", sessionName2]);
} catch {
}
return;
}
const sessionTarget = sessionName2.split(":")[0] ?? sessionName2;
if (process.env.OMC_TEAM_ALLOW_KILL_CURRENT_SESSION !== "1" && process.env.TMUX) {
try {
const current = await tmuxCmdAsync(["display-message", "-p", "#S"]);
const currentSessionName = current.stdout.trim();
if (currentSessionName && currentSessionName === sessionTarget) {
return;
}
} catch {
}
}
try {
await tmuxExecAsync(["kill-session", "-t", sessionTarget]);
} catch {
}
}
var sleep, TMUX_SESSION_PREFIX, SUPPORTED_POSIX_SHELLS, ZSH_CANDIDATES, BASH_CANDIDATES, DANGEROUS_LAUNCH_BINARY_CHARS;
var init_tmux_session = __esm({
"src/team/tmux-session.ts"() {
"use strict";
init_team_name();
init_tmux_utils();
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
TMUX_SESSION_PREFIX = "omc-team";
SUPPORTED_POSIX_SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "fish", "ksh"]);
ZSH_CANDIDATES = ["/bin/zsh", "/usr/bin/zsh", "/usr/local/bin/zsh", "/opt/homebrew/bin/zsh"];
BASH_CANDIDATES = ["/bin/bash", "/usr/bin/bash"];
DANGEROUS_LAUNCH_BINARY_CHARS = /[;&|`$()<>\n\r\t\0]/;
}
});
// src/agents/utils.ts
import { readFileSync } from "fs";
import { join as join7, dirname as dirname4, basename as basename4, resolve as resolve2, relative as relative2, isAbsolute as isAbsolute4 } from "path";
import { fileURLToPath } from "url";
function getPackageDir() {
if (typeof __dirname !== "undefined" && __dirname) {
const currentDirName = basename4(__dirname);
const parentDirName = basename4(dirname4(__dirname));
if (currentDirName === "bridge") {
return join7(__dirname, "..");
}
if (currentDirName === "agents" && (parentDirName === "src" || parentDirName === "dist")) {
return join7(__dirname, "..", "..");
}
}
try {
const __filename = fileURLToPath(import.meta.url);
const __dirname2 = dirname4(__filename);
const currentDirName = basename4(__dirname2);
if (currentDirName === "bridge") {
return join7(__dirname2, "..");
}
return join7(__dirname2, "..", "..");
} catch {
}
return process.cwd();
}
function stripFrontmatter(content) {
const match = content.match(/^---[\s\S]*?---\s*([\s\S]*)$/);
return match ? match[1].trim() : content.trim();
}
function loadAgentPrompt(agentName) {
if (!/^[a-z0-9-]+$/i.test(agentName)) {
throw new Error(`Invalid agent name: contains disallowed characters`);
}
try {
if (typeof __AGENT_PROMPTS__ !== "undefined" && __AGENT_PROMPTS__ !== null) {
const prompt = __AGENT_PROMPTS__[agentName];
if (prompt) return prompt;
}
} catch {
}
try {
const agentsDir = join7(getPackageDir(), "agents");
const agentPath = join7(agentsDir, `${agentName}.md`);
const resolvedPath = resolve2(agentPath);
const resolvedAgentsDir = resolve2(agentsDir);
const rel = relative2(resolvedAgentsDir, resolvedPath);
if (rel.startsWith("..") || isAbsolute4(rel)) {
throw new Error(`Invalid agent name: path traversal detected`);
}
const content = readFileSync(agentPath, "utf-8");
return stripFrontmatter(content);
} catch (error) {
const message = error instanceof Error && error.message.includes("Invalid agent name") ? error.message : "Agent prompt file not found";
console.warn(`[loadAgentPrompt] ${message}`);
return `Agent: ${agentName}
Prompt unavailable.`;
}
}
var init_utils = __esm({
"src/agents/utils.ts"() {
"use strict";
}
});
// src/utils/skininthegamebros-user.ts
var init_skininthegamebros_user = __esm({
"src/utils/skininthegamebros-user.ts"() {
"use strict";
}
});
// src/agents/skininthegamebros-guidance.ts
var init_skininthegamebros_guidance = __esm({
"src/agents/skininthegamebros-guidance.ts"() {
"use strict";
init_skininthegamebros_user();
}
});
// src/agents/prompt-helpers.ts
import { readdirSync } from "fs";
import { join as join8, dirname as dirname5, basename as basename5 } from "path";
import { fileURLToPath as fileURLToPath2 } from "url";
function getPackageDir2() {
if (typeof __dirname !== "undefined" && __dirname) {
const currentDirName = basename5(__dirname);
const parentDirName = basename5(dirname5(__dirname));
if (currentDirName === "bridge") {
return join8(__dirname, "..");
}
if (currentDirName === "agents" && (parentDirName === "src" || parentDirName === "dist")) {
return join8(__dirname, "..", "..");
}
}
try {
const __filename = fileURLToPath2(import.meta.url);
const __dirname2 = dirname5(__filename);
const currentDirName = basename5(__dirname2);
if (currentDirName === "bridge") {
return join8(__dirname2, "..");
}
return join8(__dirname2, "..", "..");
} catch {
}
return process.cwd();
}
function getValidAgentRoles() {
if (_cachedRoles) return _cachedRoles;
try {
if (typeof __AGENT_ROLES__ !== "undefined" && Array.isArray(__AGENT_ROLES__) && __AGENT_ROLES__.length > 0) {
_cachedRoles = __AGENT_ROLES__;
return _cachedRoles;
}
} catch {
}
try {
const agentsDir = join8(getPackageDir2(), "agents");
const files = readdirSync(agentsDir);
_cachedRoles = files.filter((f) => f.endsWith(".md")).map((f) => basename5(f, ".md")).sort();
} catch (err) {
console.error("[prompt-injection] CRITICAL: Could not scan agents/ directory for role discovery:", err);
_cachedRoles = [];
}
return _cachedRoles;
}
function sanitizePromptContent(content, maxLength = 4e3) {
if (!content) return "";
let sanitized = content.length > maxLength ? content.slice(0, maxLength) : content;
if (sanitized.length > 0) {
const lastCode = sanitized.charCodeAt(sanitized.length - 1);
if (lastCode >= 55296 && lastCode <= 56319) {
sanitized = sanitized.slice(0, -1);
}
}
sanitized = sanitized.replace(/<(\/?)(TASK_SUBJECT)[^>]*>/gi, "[$1$2]");
sanitized = sanitized.replace(/<(\/?)(TASK_DESCRIPTION)[^>]*>/gi, "[$1$2]");
sanitized = sanitized.replace(/<(\/?)(INBOX_MESSAGE)[^>]*>/gi, "[$1$2]");
sanitized = sanitized.replace(/<(\/?)(INSTRUCTIONS)[^>]*>/gi, "[$1$2]");
sanitized = sanitized.replace(/<(\/?)(SYSTEM)[^>]*>/gi, "[$1$2]");
return sanitized;
}
var _cachedRoles, VALID_AGENT_ROLES;
var init_prompt_helpers = __esm({
"src/agents/prompt-helpers.ts"() {
"use strict";
init_utils();
init_skininthegamebros_guidance();
_cachedRoles = null;
VALID_AGENT_ROLES = getValidAgentRoles();
}
});
// src/utils/omc-cli-rendering.ts
import { spawnSync as spawnSync2 } from "child_process";
function commandExists(command, env) {
const lookupCommand = process.platform === "win32" ? "where" : "which";
const result = spawnSync2(lookupCommand, [command], {
stdio: "ignore",
env
});
return result.status === 0;
}
function resolveOmcCliPrefix(options = {}) {
const env = options.env ?? process.env;
const omcAvailable = options.omcAvailable ?? commandExists(OMC_CLI_BINARY, env);
if (omcAvailable) {
return OMC_CLI_BINARY;
}
const pluginRoot = typeof env.CLAUDE_PLUGIN_ROOT === "string" ? env.CLAUDE_PLUGIN_ROOT.trim() : "";
if (pluginRoot) {
return OMC_PLUGIN_BRIDGE_PREFIX;
}
return OMC_CLI_BINARY;
}
function formatOmcCliInvocation(commandSuffix, options = {}) {
const suffix = commandSuffix.trim().replace(/^omc\s+/, "");
return `${resolveOmcCliPrefix(options)} ${suffix}`.trim();
}
var OMC_CLI_BINARY, OMC_PLUGIN_BRIDGE_PREFIX;
var init_omc_cli_rendering = __esm({
"src/utils/omc-cli-rendering.ts"() {
"use strict";
OMC_CLI_BINARY = "omc";
OMC_PLUGIN_BRIDGE_PREFIX = 'node "$CLAUDE_PLUGIN_ROOT"/bridge/cli.cjs';
}
});
// src/utils/config-dir.ts
import { join as join9, normalize, parse, sep } from "path";
import { homedir } from "os";
var init_config_dir = __esm({
"src/utils/config-dir.ts"() {
"use strict";
}
});
// src/utils/paths.ts
import { join as join10 } from "path";
import { existsSync as existsSync6, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync, unlinkSync, rmSync, symlinkSync } from "fs";
import { homedir as homedir2 } from "os";
function getConfigDir() {
if (process.platform === "win32") {
return process.env.APPDATA || join10(homedir2(), "AppData", "Roaming");
}
return process.env.XDG_CONFIG_HOME || join10(homedir2(), ".config");
}
function getStateDir() {
if (process.platform === "win32") {
return process.env.LOCALAPPDATA || join10(homedir2(), "AppData", "Local");
}
return process.env.XDG_STATE_HOME || join10(homedir2(), ".local", "state");
}
function prefersXdgOmcDirs() {
return process.platform !== "win32" && process.platform !== "darwin";
}
function getUserHomeDir() {
if (process.platform === "win32") {
return process.env.USERPROFILE || process.env.HOME || homedir2();
}
return process.env.HOME || homedir2();
}
function getLegacyOmcDir() {
return join10(getUserHomeDir(), ".omc");
}
function getGlobalOmcStateRoot() {
const explicitRoot = process.env.OMC_HOME?.trim();
if (explicitRoot) {
return join10(explicitRoot, "state");
}
if (prefersXdgOmcDirs()) {
return join10(getStateDir(), "omc");
}
return join10(getLegacyOmcDir(), "state");
}
function getGlobalOmcStatePath(...segments) {
return join10(getGlobalOmcStateRoot(), ...segments);
}
var STALE_THRESHOLD_MS;
var init_paths = __esm({
"src/utils/paths.ts"() {
"use strict";
init_config_dir();
STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
}
});
// src/utils/jsonc.ts
function parseJsonc(content) {
const cleaned = stripJsoncComments(content);
return JSON.parse(cleaned);
}
function stripJsoncComments(content) {
let result = "";
let i = 0;
while (i < content.length) {
if (content[i] === "/" && content[i + 1] === "/") {
while (i < content.length && content[i] !== "\n") {
i++;
}
continue;
}
if (content[i] === "/" && content[i + 1] === "*") {
i += 2;
while (i < content.length && !(content[i] === "*" && content[i + 1] === "/")) {
i++;
}
i += 2;
continue;
}
if (content[i] === '"') {
result += content[i];
i++;
while (i < content.length && content[i] !== '"') {
if (content[i] === "\\") {
result += content[i];
i++;
if (i < content.length) {
result += content[i];
i++;
}
continue;
}
result += content[i];
i++;
}
if (i < content.length) {
result += content[i];
i++;
}
continue;
}
result += content[i];
i++;
}
return result;
}
var init_jsonc = __esm({
"src/utils/jsonc.ts"() {
"use strict";
}
});
// src/utils/ssrf-guard.ts
var init_ssrf_guard = __esm({
"src/utils/ssrf-guard.ts"() {
"use strict";
}
});
// src/config/models.ts
function resolveTierModelFromEnv(tier) {
for (const key of TIER_ENV_KEYS[tier]) {
const value = process.env[key]?.trim();
if (value) {
return value;
}
}
return void 0;
}
function getDefaultModelHigh() {
return resolveTierModelFromEnv("HIGH") || BUILTIN_TIER_MODEL_DEFAULTS.HIGH;
}
function getDefaultModelMedium() {
return resolveTierModelFromEnv("MEDIUM") || BUILTIN_TIER_MODEL_DEFAULTS.MEDIUM;
}
function getDefaultModelLow() {
return resolveTierModelFromEnv("LOW") || BUILTIN_TIER_MODEL_DEFAULTS.LOW;
}
function getDefaultTierModels() {
return {
LOW: getDefaultModelLow(),
MEDIUM: getDefaultModelMedium(),
HIGH: getDefaultModelHigh()
};
}
function resolveClaudeFamily(modelId) {
const lower = modelId.toLowerCase();
if (!lower.includes("claude")) return null;
if (lower.includes("sonnet")) return "SONNET";
if (lower.includes("opus")) return "OPUS";
if (lower.includes("haiku")) return "HAIKU";
return null;
}
function isBedrock() {
if (process.env.CLAUDE_CODE_USE_BEDROCK === "1") {
return true;
}
const modelId = process.env.CLAUDE_MODEL || process.env.ANTHROPIC_MODEL || "";
if (modelId && /^((us|eu|ap|global)\.anthropic\.|anthropic\.claude)/i.test(modelId)) {
return true;
}
if (modelId && /^arn:aws(-[^:]+)?:bedrock:/i.test(modelId) && /:(inference-profile|application-inference-profile)\//i.test(modelId) && modelId.toLowerCase().includes("claude")) {
return true;
}
return false;
}
function isProviderSpecificModelId(modelId) {
if (/^((us|eu|ap|global)\.anthropic\.|anthropic\.claude)/i.test(modelId)) {
return true;
}
if (/^arn:aws(-[^:]+)?:bedrock:/i.test(modelId)) {
return true;
}
if (modelId.toLowerCase().startsWith("vertex_ai/")) {
return true;
}
return false;
}
function isVertexAI() {
if (process.env.CLAUDE_CODE_USE_VERTEX === "1") {
return true;
}
const modelId = process.env.CLAUDE_MODEL || process.env.ANTHROPIC_MODEL || "";
if (modelId && modelId.toLowerCase().startsWith("vertex_ai/")) {
return true;
}
return false;
}
var TIER_ENV_KEYS, CLAUDE_FAMILY_DEFAULTS, BUILTIN_TIER_MODEL_DEFAULTS, CLAUDE_FAMILY_HIGH_VARIANTS, BUILTIN_EXTERNAL_MODEL_DEFAULTS;
var init_models = __esm({
"src/config/models.ts"() {
"use strict";
init_ssrf_guard();
TIER_ENV_KEYS = {
LOW: [
"OMC_MODEL_LOW",
"CLAUDE_CODE_BEDROCK_HAIKU_MODEL",
"ANTHROPIC_DEFAULT_HAIKU_MODEL"
],
MEDIUM: [
"OMC_MODEL_MEDIUM",
"CLAUDE_CODE_BEDROCK_SONNET_MODEL",
"ANTHROPIC_DEFAULT_SONNET_MODEL"
],
HIGH: [
"OMC_MODEL_HIGH",
"CLAUDE_CODE_BEDROCK_OPUS_MODEL",
"ANTHROPIC_DEFAULT_OPUS_MODEL"
]
};
CLAUDE_FAMILY_DEFAULTS = {
HAIKU: "claude-haiku-4-5",
SONNET: "claude-sonnet-4-6",
OPUS: "claude-opus-4-6"
};
BUILTIN_TIER_MODEL_DEFAULTS = {
LOW: CLAUDE_FAMILY_DEFAULTS.HAIKU,
MEDIUM: CLAUDE_FAMILY_DEFAULTS.SONNET,
HIGH: CLAUDE_FAMILY_DEFAULTS.OPUS
};
CLAUDE_FAMILY_HIGH_VARIANTS = {
HAIKU: `${CLAUDE_FAMILY_DEFAULTS.HAIKU}-high`,
SONNET: `${CLAUDE_FAMILY_DEFAULTS.SONNET}-high`,
OPUS: `${CLAUDE_FAMILY_DEFAULTS.OPUS}-high`
};
BUILTIN_EXTERNAL_MODEL_DEFAULTS = {
codexModel: "gpt-5.3-codex",
geminiModel: "gemini-3.1-pro-preview"
};
}
});
// src/config/loader.ts
import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
import { join as join11, dirname as dirname6 } from "path";
function buildDefaultConfig() {
const defaultTierModels = getDefaultTierModels();
return {
agents: {
omc: { model: defaultTierModels.HIGH },
explore: { model: defaultTierModels.LOW },
analyst: { model: defaultTierModels.HIGH },
planner: { model: defaultTierModels.HIGH },
architect: { model: defaultTierModels.HIGH },
debugger: { model: defaultTierModels.MEDIUM },
executor: { model: defaultTierModels.MEDIUM },
verifier: { model: defaultTierModels.MEDIUM },
securityReviewer: { model: defaultTierModels.MEDIUM },
codeReviewer: { model: defaultTierModels.HIGH },
testEngineer: { model: defaultTierModels.MEDIUM },
designer: { model: defaultTierModels.MEDIUM },
writer: { model: defaultTierModels.LOW },
qaTester: { model: defaultTierModels.MEDIUM },
scientist: { model: defaultTierModels.MEDIUM },
tracer: { model: defaultTierModels.MEDIUM },
gitMaster: { model: defaultTierModels.MEDIUM },
codeSimplifier: { model: defaultTierModels.HIGH },
critic: { model: defaultTierModels.HIGH },
documentSpecialist: { model: defaultTierModels.MEDIUM }
},
features: {
parallelExecution: true,
lspTools: true,
// Real LSP integration with language servers
astTools: true,
// Real AST tools using ast-grep
continuationEnforcement: true,
autoContextInjection: true
},
mcpServers: {
exa: { enabled: true },
context7: { enabled: true }
},
permissions: {
allowBash: true,
allowEdit: true,
allowWrite: true,
maxBackgroundTasks: 5
},
magicKeywords: {
ultrawork: ["ultrawork", "ulw", "uw"],
search: ["search", "find", "locate"],
analyze: ["analyze", "investigate", "examine"],
ultrathink: ["ultrathink", "think", "reason", "ponder"]
},
// Intelligent model routing configuration
routing: {
enabled: true,
defaultTier: "MEDIUM",
forceInherit: false,
escalationEnabled: true,
maxEscalations: 2,
tierModels: { ...defaultTierModels },
agentOverrides: {
architect: {
tier: "HIGH",
reason: "Advisory agent requires deep reasoning"
},
planner: {
tier: "HIGH",
reason: "Strategic planning requires deep reasoning"
},
critic: {
tier: "HIGH",
reason: "Critical review requires deep reasoning"
},
analyst: {
tier: "HIGH",
reason: "Pre-planning analysis requires deep reasoning"
},
explore: { tier: "LOW", reason: "Exploration is search-focused" },
writer: { tier: "LOW", reason: "Documentation is straightforward" }
},
escalationKeywords: [
"critical",
"production",
"urgent",
"security",
"breaking",
"architecture",
"refactor",
"redesign",
"root cause"
],
simplificationKeywords: [
"find",
"list",
"show",
"where",
"search",
"locate",
"grep"
]
},
// External models configuration (Codex, Gemini)
// Static defaults only — env var overrides applied in loadEnvConfig()
externalModels: {
defaults: {
codexModel: BUILTIN_EXTERNAL_MODEL_DEFAULTS.codexModel,
geminiModel: BUILTIN_EXTERNAL_MODEL_DEFAULTS.geminiModel
},
fallbackPolicy: {
onModelFailure: "provider_chain",
allowCrossProvider: false,
crossProviderOrder: ["codex", "gemini"]
}
},
// Delegation routing configuration (opt-in feature for external model routing)
delegationRouting: {
enabled: false,
defaultProvider: "claude",
roles: {}
},
planOutput: {
directory: ".omc/plans",
filenameTemplate: "{{name}}.md"
},
teleport: {
symlinkNodeModules: true
},
startupCodebaseMap: {
enabled: true,
maxFiles: 200,
maxDepth: 4
},
taskSizeDetection: {
enabled: true,
smallWordLimit: 50,
largeWordLimit: 200,
suppressHeavyModesForSmallTasks: true
},
promptPrerequisites: {
enabled: true,
sectionNames: {
memory: ["M\xC9MOIRE", "MEMOIRE", "MEMORY"],
skills: ["SKILLS"],
verifyFirst: ["VERIFY-FIRST", "VERIFY FIRST", "VERIFY_FIRST"],
context: ["CONTEXT"]
},
blockingTools: ["Edit", "MultiEdit", "Write", "Agent", "Task"],
executionKeywords: ["ralph", "ultrawork", "autopilot"]
}
};
}
var DEFAULT_CONFIG;
var init_loader = __esm({
"src/config/loader.ts"() {
"use strict";
init_paths();
init_jsonc();
init_models();
DEFAULT_CONFIG = buildDefaultConfig();
}
});
// src/agents/architect.ts
var ARCHITECT_PROMPT_METADATA, architectAgent;
var init_architect = __esm({
"src/agents/architect.ts"() {
"use strict";
init_utils();
ARCHITECT_PROMPT_METADATA = {
category: "advisor",
cost: "EXPENSIVE",
promptAlias: "architect",
triggers: [
{ domain: "Architecture decisions", trigger: "Multi-system tradeoffs, unfamiliar patterns" },
{ domain: "Self-review", trigger: "After completing significant implementation" },
{ domain: "Hard debugging", trigger: "After 2+ failed fix attempts" }
],
useWhen: [
"Complex architecture design",
"After completing significant work",
"2+ failed fix attempts",
"Unfamiliar code patterns",
"Security/performance concerns",
"Multi-system tradeoffs"
],
avoidWhen: [
"Simple file operations (use direct tools)",
"First attempt at any fix (try yourself first)",
"Questions answerable from code you've read",
"Trivial decisions (variable names, formatting)",
"Things you can infer from existing code patterns"
]
};
architectAgent = {
name: "architect",
description: "Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design.",
prompt: loadAgentPrompt("architect"),
model: "opus",
defaultModel: "opus",
metadata: ARCHITECT_PROMPT_METADATA
};
}
});
// src/agents/designer.ts
var FRONTEND_ENGINEER_PROMPT_METADATA, designerAgent;
var init_designer = __esm({
"src/agents/designer.ts"() {
"use strict";
init_utils();
FRONTEND_ENGINEER_PROMPT_METADATA = {
category: "specialist",
cost: "CHEAP",
promptAlias: "designer",
triggers: [
{
domain: "UI/UX",
trigger: "Visual changes, styling, components, accessibility"
},
{
domain: "Design",
trigger: "Layout, animations, responsive design"
}
],
useWhen: [
"Visual styling or layout changes",
"Component design or refactoring",
"Animation implementation",
"Accessibility improvements",
"Responsive design work"
],
avoidWhen: [
"Pure logic changes in frontend files",
"Backend/API work",
"Non-visual refactoring"
]
};
designerAgent = {
name: "designer",
description: `Designer-turned-developer who crafts stunning UI/UX even without design mockups. Use for VISUAL changes only (styling, layout, animation). Pure logic changes in frontend files should be handled directly.`,
prompt: loadAgentPrompt("designer"),
model: "sonnet",
defaultModel: "sonnet",
metadata: FRONTEND_ENGINEER_PROMPT_METADATA
};
}
});
// src/agents/writer.ts
var DOCUMENT_WRITER_PROMPT_METADATA, writerAgent;
var init_writer = __esm({
"src/agents/writer.ts"() {
"use strict";
init_utils();
DOCUMENT_WRITER_PROMPT_METADATA = {
category: "specialist",
cost: "FREE",
promptAlias: "writer",
triggers: [
{
domain: "Documentation",
trigger: "README, API docs, guides, comments"
}
],
useWhen: [
"Creating or updating README files",
"Writing API documentation",
"Creating user guides or tutorials",
"Adding code comments or JSDoc",
"Architecture documentation"
],
avoidWhen: [
"Code implementation tasks",
"Bug fixes",
"Non-documentation tasks"
]
};
writerAgent = {
name: "writer",
description: `Technical writer who crafts clear, comprehensive documentation. Specializes in README files, API docs, architecture docs, and user guides.`,
prompt: loadAgentPrompt("writer"),
model: "haiku",
defaultModel: "haiku",
metadata: DOCUMENT_WRITER_PROMPT_METADATA
};
}
});
// src/agents/critic.ts
var CRITIC_PROMPT_METADATA, criticAgent;
var init_critic = __esm({
"src/agents/critic.ts"() {
"use strict";
init_utils();
CRITIC_PROMPT_METADATA = {
category: "reviewer",
cost: "EXPENSIVE",
promptAlias: "critic",
triggers: [
{
domain: "Plan Review",
trigger: "Evaluating work plans before execution"
}
],
useWhen: [
"After planner creates a work plan",
"Before executing a complex plan",
"When plan quality validation is needed",
"To catch gaps before implementation"
],
avoidWhen: [
"Simple, straightforward tasks",
"When no plan exists to review",
"During implementation phase"
]
};
criticAgent = {
name: "critic",
description: `Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards. Use after planner creates a work plan to validate it before execution.`,
prompt: loadAgentPrompt("critic"),
model: "opus",
defaultModel: "opus",
metadata: CRITIC_PROMPT_METADATA
};
}
});
// src/agents/analyst.ts
var ANALYST_PROMPT_METADATA, analystAgent;
var init_analyst = __esm({
"src/agents/analyst.ts"() {
"use strict";
init_utils();
ANALYST_PROMPT_METADATA = {
category: "planner",
cost: "EXPENSIVE",
promptAlias: "analyst",
triggers: [
{
domain: "Pre-Planning",
trigger: "Hidden requirements, edge cases, risk analysis"
}
],
useWhen: [
"Before creating a work plan",
"When requirements seem incomplete",
"To identify hidden assumptions",
"Risk analysis before implementation",
"Scope validation"
],
avoidWhen: [
"Simple, well-defined tasks",
"During implementation phase",
"When plan already reviewed"
]
};
analystAgent = {
name: "analyst",
description: `Pre-planning consultant that analyzes requests before implementation to identify hidden requirements, edge cases, and potential risks. Use before creating a work plan.`,
prompt: loadAgentPrompt("analyst"),
model: "opus",
defaultModel: "opus",
metadata: ANALYST_PROMPT_METADATA
};
}
});
// src/agents/executor.ts
var EXECUTOR_PROMPT_METADATA, executorAgent;
var init_executor = __esm({
"src/agents/executor.ts"() {
"use strict";
init_utils();
EXECUTOR_PROMPT_METADATA = {
category: "specialist",
cost: "CHEAP",
promptAlias: "Junior",
triggers: [
{ domain: "Direct implementation", trigger: "Single-file changes, focused tasks" },
{ domain: "Bug fixes", trigger: "Clear, scoped fixes" },
{ domain: "Small features", trigger: "Well-defined, isolated work" }
],
useWhen: [
"Direct, focused implementation tasks",
"Single-file or few-file changes",
"When delegation overhead isn't worth it",
"Clear, well-scoped work items"
],
avoidWhen: [
"Multi-file refactoring (use orchestrator)",
"Tasks requiring research (use explore/document-specialist first)",
"Complex decisions (consult architect)"
]
};
executorAgent = {
name: "executor",
description: "Focused task executor. Execute tasks directly. NEVER delegate or spawn other agents. Same discipline as OMC, no delegation.",
prompt: loadAgentPrompt("executor"),
model: "sonnet",
defaultModel: "sonnet",
metadata: EXECUTOR_PROMPT_METADATA
};
}
});
// src/agents/planner.ts
var PLANNER_PROMPT_METADATA, plannerAgent;
var init_planner = __esm({
"src/agents/planner.ts"() {
"use strict";
init_utils();
PLANNER_PROMPT_METADATA = {
category: "planner",
cost: "EXPENSIVE",
promptAlias: "planner",
triggers: [
{
domain: "Strategic Planning",
trigger: "Comprehensive work plans, interview-style consultation"
}
],
useWhen: [
"Complex features requiring planning",
"When requirements need clarification through interview",
"Creating comprehensive work plans",
"Before large implementation efforts"
],
avoidWhen: [
"Simple, straightforward tasks",
"When implementation should just start",
"When a plan already exists"
]
};
plannerAgent = {
name: "planner",
description: `Strategic planning consultant. Interviews users to understand requirements, then creates comprehensive work plans. NEVER implements - only plans.`,
prompt: loadAgentPrompt("planner"),
model: "opus",
defaultModel: "opus",
metadata: PLANNER_PROMPT_METADATA
};
}
});
// src/agents/qa-tester.ts
var QA_TESTER_PROMPT_METADATA, qaTesterAgent;
var init_qa_tester = __esm({
"src/agents/qa-tester.ts"() {
"use strict";
init_utils();
QA_TESTER_PROMPT_METADATA = {
category: "specialist",
cost: "CHEAP",
promptAlias: "QATester",
triggers: [
{ domain: "CLI testing", trigger: "Testing command-line applications" },
{ domain: "Service testing", trigger: "Starting and testing background services" },
{ domain: "Integration testing", trigger: "End-to-end CLI workflow verification" },
{ domain: "Interactive testing", trigger: "Testing applications requiring user input" }
],
useWhen: [
"Testing CLI applications that need interactive input",
"Starting background services and verifying their behavior",
"Running end-to-end tests on command-line tools",
"Testing applications that produce streaming output",
"Verifying service startup and shutdown behavior"
],
avoidWhen: [
"Unit testing (use standard test runners)",
"API testing without CLI interface (use curl/httpie directly)",
"Static code analysis (use architect or explore)"
]
};
qaTesterAgent = {
name: "qa-tester",
description: "Interactive CLI testing specialist using tmux. Tests CLI applications, background services, and interactive tools. Manages test sessions, sends commands, verifies output, and ensures cleanup.",
prompt: loadAgentPrompt("qa-tester"),
model: "sonnet",
defaultModel: "sonnet",
metadata: QA_TESTER_PROMPT_METADATA
};
}
});
// src/agents/scientist.ts
var SCIENTIST_PROMPT_METADATA, scientistAgent;
var init_scientist = __esm({
"src/agents/scientist.ts"() {
"use strict";
init_utils();
SCIENTIST_PROMPT_METADATA = {
category: "specialist",
cost: "CHEAP",
promptAlias: "scientist",
triggers: [
{ domain: "Data analysis", trigger: "Analyzing datasets and computing statistics" },
{ domain: "Research execution", trigger: "Running data experiments and generating findings" },
{ domain: "Python data work", trigger: "Using pandas, numpy, scipy for data tasks" },
{ domain: "EDA", trigger: "Exploratory data analysis on files" },
{ domain: "Hypothesis testing", trigger: "Statistical tests with confidence intervals and effect sizes" },
{ domain: "Research stages", trigger: "Multi-stage analysis with structured markers" }
],
useWhen: [
"Analyzing CSV, JSON, Parquet, or other data files",
"Computing descriptive statistics or aggregations",
"Performing exploratory data analysis (EDA)",
"Generating data-driven findings and insights",
"Simple ML tasks like clustering or regression",
"Data transformations and feature engineering",
"Generating data analysis reports with visualizations",
"Hypothesis testing with statistical evidence markers",
"Research stages with [STAGE:*] markers for orchestration"
],
avoidWhen: [
"Researching external documentation or APIs (use document-specialist)",
"Implementing production code features (use executor)",
"Architecture or system design questions (use architect)",
"No data files to analyze - just theoretical questions",
"Web scraping or external data fetching (use document-specialist)"
]
};
scientistAgent = {
name: "scientist",
description: "Data analysis and research execution specialist. Executes Python code for EDA, statistical analysis, and generating data-driven findings. Works with CSV, JSON, Parquet files using pandas, numpy, scipy.",
prompt: loadAgentPrompt("scientist"),
model: "sonnet",
defaultModel: "sonnet",
metadata: SCIENTIST_PROMPT_METADATA
};
}
});
// src/agents/explore.ts
var EXPLORE_PROMPT_METADATA, exploreAgent;
var init_explore = __esm({
"src/agents/explore.ts"() {
"use strict";
init_utils();
EXPLORE_PROMPT_METADATA = {
category: "exploration",
cost: "CHEAP",
promptAlias: "Explore",
triggers: [
{ domain: "Internal codebase search", trigger: "Finding implementations, patterns, files" },
{ domain: "Project structure", trigger: "Understanding code organization" },
{ domain: "Code discovery", trigger: "Locating specific code by pattern" }
],
useWhen: [
"Finding files by pattern or name",
"Searching for implementations in current project",
"Understanding project structure",
"Locating code by content or pattern",
"Quick codebase exploration"
],
avoidWhen: [
"External documentation, literature, or academic paper lookup (use document-specialist)",
"Database/reference/manual lookups outside the current project (use document-specialist)",
"GitHub/npm package research (use document-specialist)",
"Complex architectural analysis (use architect)",
"When you already know the file location"
]
};
exploreAgent = {
name: "explore",
description: "Fast codebase exploration and pattern search. Use for finding files, understanding structure, locating implementations. Searches INTERNAL codebase only; external docs, literature, papers, and reference databases belong to document-specialist.",
prompt: loadAgentPrompt("explore"),
model: "haiku",
defaultModel: "haiku",
metadata: EXPLORE_PROMPT_METADATA
};
}
});
// src/agents/tracer.ts
var TRACER_PROMPT_METADATA, tracerAgent;
var init_tracer = __esm({
"src/agents/tracer.ts"() {
"use strict";
init_utils();
TRACER_PROMPT_METADATA = {
category: "advisor",
cost: "EXPENSIVE",
promptAlias: "tracer",
triggers: [
{ domain: "Causal tracing", trigger: "Why did this happen? Which explanation best fits the evidence?" },
{ domain: "Forensic analysis", trigger: "Observed output, artifact, or behavior needs ranked explanations" },
{ domain: "Evidence-driven uncertainty reduction", trigger: "Need competing hypotheses and the next best probe" }
],
useWhen: [
"Tracing ambiguous runtime behavior, regressions, or orchestration outcomes",
"Ranking competing explanations for an observed result",
"Separating observation, evidence, and inference",
"Explaining performance, architecture, scientific, or configuration outcomes",
"Identifying the next probe that would collapse uncertainty fastest"
],
avoidWhen: [
"The task is pure implementation or fixing (use executor/debugger)",
"The task is a generic summary without causal analysis",
"A single-file code search is enough (use explore)",
"You already have decisive evidence and only need execution"
]
};
tracerAgent = {
name: "tracer",
description: "Evidence-driven causal tracing specialist. Explains observed outcomes using competing hypotheses, evidence for and against, uncertainty tracking, and next-probe recommendations.",
prompt: loadAgentPrompt("tracer"),
model: "sonnet",
defaultModel: "sonnet",
metadata: TRACER_PROMPT_METADATA
};
}
});
// src/agents/document-specialist.ts
var DOCUMENT_SPECIALIST_PROMPT_METADATA, documentSpecialistAgent;
var init_document_specialist = __esm({
"src/agents/document-specialist.ts"() {
"use strict";
init_utils();
DOCUMENT_SPECIALIST_PROMPT_METADATA = {
category: "exploration",
cost: "CHEAP",
promptAlias: "document-specialist",
triggers: [
{
domain: "Project documentation",
trigger: "README, docs/, migration guides, local references"
},
{
domain: "External documentation",
trigger: "API references, official docs"
},
{
domain: "API/framework correctness",
trigger: "Context Hub / chub first when available; curated backend fallback otherwise"
},
{
domain: "OSS implementations",
trigger: "GitHub examples, package source"
},
{
domain: "Best practices",
trigger: "Community patterns, recommendations"
},
{
domain: "Literature and reference research",
trigger: "Academic papers, manuals, reference databases"
}
],
useWhen: [
"Checking README/docs/local reference files before broader research",
"Looking up official documentation",
"Using Context Hub / chub (or another curated docs backend) for external API/framework correctness when available",
"Finding GitHub examples",
"Researching npm/pip packages",
"Stack Overflow solutions",
"External API references",
"Searching external literature or academic papers",
"Looking up manuals, databases, or reference material outside the current project"
],
avoidWhen: [
"Internal codebase implementation search (use explore)",
"Current project source files when the task is code discovery rather than documentation lookup (use explore)",
"When you already have the information"
]
};
documentSpecialistAgent = {
name: "document-specialist",
description: "Document Specialist for documentation research and reference finding. Use for local repo docs, official docs, Context Hub / chub or other curated docs backends for API/framework correctness, GitHub examples, OSS implementations, external literature, academic papers, and reference/database lookups. Avoid internal implementation search; use explore for code discovery.",
prompt: loadAgentPrompt("document-specialist"),
model: "sonnet",
defaultModel: "sonnet",
metadata: DOCUMENT_SPECIALIST_PROMPT_METADATA
};
}
});
// src/agents/definitions.ts
var debuggerAgent, verifierAgent, testEngineerAgent, securityReviewerAgent, codeReviewerAgent, gitMasterAgent, codeSimplifierAgent;
var init_definitions = __esm({
"src/agents/definitions.ts"() {
"use strict";
init_utils();
init_loader();
init_skininthegamebros_guidance();
init_architect();
init_designer();
init_writer();
init_critic();
init_analyst();
init_executor();
init_planner();
init_qa_tester();
init_scientist();
init_explore();
init_tracer();
init_document_specialist();
init_architect();
init_designer();
init_writer();
init_critic();
init_analyst();
init_executor();
init_planner();
init_qa_tester();
init_scientist();
init_explore();
init_tracer();
init_document_specialist();
debuggerAgent = {
name: "debugger",
description: "Root-cause analysis, regression isolation, failure diagnosis (Sonnet).",
prompt: loadAgentPrompt("debugger"),
model: "sonnet",
defaultModel: "sonnet"
};
verifierAgent = {
name: "verifier",
description: "Completion evidence, claim validation, test adequacy (Sonnet).",
prompt: loadAgentPrompt("verifier"),
model: "sonnet",
defaultModel: "sonnet"
};
testEngineerAgent = {
name: "test-engineer",
description: "Test strategy, coverage, flaky test hardening (Sonnet).",
prompt: loadAgentPrompt("test-engineer"),
model: "sonnet",
defaultModel: "sonnet"
};
securityReviewerAgent = {
name: "security-reviewer",
description: "Security vulnerability detection specialist (Sonnet). Use for security audits and OWASP detection.",
prompt: loadAgentPrompt("security-reviewer"),
model: "sonnet",
defaultModel: "sonnet"
};
codeReviewerAgent = {
name: "code-reviewer",
description: "Expert code review specialist (Opus). Use for comprehensive code quality review.",
prompt: loadAgentPrompt("code-reviewer"),
model: "opus",
defaultModel: "opus"
};
gitMasterAgent = {
name: "git-master",
description: "Git expert for atomic commits, rebasing, and history management with style detection",
prompt: loadAgentPrompt("git-master"),
model: "sonnet",
defaultModel: "sonnet"
};
codeSimplifierAgent = {
name: "code-simplifier",
description: "Simplifies and refines code for clarity, consistency, and maintainability (Opus).",
prompt: loadAgentPrompt("code-simplifier"),
model: "opus",
defaultModel: "opus"
};
}
});
// src/features/delegation-routing/types.ts
var init_types = __esm({
"src/features/delegation-routing/types.ts"() {
"use strict";
}
});
// src/features/delegation-enforcer.ts
function normalizeToCcAlias(model) {
const family = resolveClaudeFamily(model);
return family ? FAMILY_TO_ALIAS[family] ?? model : model;
}
var FAMILY_TO_ALIAS;
var init_delegation_enforcer = __esm({
"src/features/delegation-enforcer.ts"() {
"use strict";
init_definitions();
init_types();
init_loader();
init_models();
FAMILY_TO_ALIAS = {
SONNET: "sonnet",
OPUS: "opus",
HAIKU: "haiku"
};
}
});
// src/lib/security-config.ts
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
import { join as join12 } from "path";
function loadSecurityFromConfigFiles() {
const paths = [
join12(process.cwd(), ".claude", "omc.jsonc"),
join12(getConfigDir(), "claude-omc", "config.jsonc")
];
for (const configPath of paths) {
if (!existsSync8(configPath)) continue;
try {
const content = readFileSync4(configPath, "utf-8");
const parsed = parseJsonc(content);
if (parsed?.security && typeof parsed.security === "object") {
return parsed.security;
}
} catch {
}
}
return {};
}
function getSecurityConfig() {
if (cachedConfig) return cachedConfig;
const isStrict = process.env.OMC_SECURITY === "strict";
const base = isStrict ? { ...STRICT_OVERRIDES } : { ...DEFAULTS };
const fileOverrides = loadSecurityFromConfigFiles();
if (isStrict) {
cachedConfig = {
restrictToolPaths: base.restrictToolPaths || (fileOverrides.restrictToolPaths ?? false),
pythonSandbox: base.pythonSandbox || (fileOverrides.pythonSandbox ?? false),
disableProjectSkills: base.disableProjectSkills || (fileOverrides.disableProjectSkills ?? false),
disableAutoUpdate: base.disableAutoUpdate || (fileOverrides.disableAutoUpdate ?? false),
disableRemoteMcp: base.disableRemoteMcp || (fileOverrides.disableRemoteMcp ?? false),
disableExternalLLM: base.disableExternalLLM || (fileOverrides.disableExternalLLM ?? false),
hardMaxIterations: Math.min(base.hardMaxIterations, typeof fileOverrides.hardMaxIterations === "number" && fileOverrides.hardMaxIterations > 0 ? fileOverrides.hardMaxIterations : base.hardMaxIterations)
};
} else {
cachedConfig = {
restrictToolPaths: fileOverrides.restrictToolPaths ?? base.restrictToolPaths,
pythonSandbox: fileOverrides.pythonSandbox ?? base.pythonSandbox,
disableProjectSkills: fileOverrides.disableProjectSkills ?? base.disableProjectSkills,
disableAutoUpdate: fileOverrides.disableAutoUpdate ?? base.disableAutoUpdate,
disableRemoteMcp: fileOverrides.disableRemoteMcp ?? base.disableRemoteMcp,
disableExternalLLM: fileOverrides.disableExternalLLM ?? base.disableExternalLLM,
hardMaxIterations: fileOverrides.hardMaxIterations ?? base.hardMaxIterations
};
}
return cachedConfig;
}
function isExternalLLMDisabled() {
return getSecurityConfig().disableExternalLLM;
}
var DEFAULTS, STRICT_OVERRIDES, cachedConfig;
var init_security_config = __esm({
"src/lib/security-config.ts"() {
"use strict";
init_jsonc();
init_paths();
DEFAULTS = {
restrictToolPaths: false,
pythonSandbox: false,
disableProjectSkills: false,
disableAutoUpdate: false,
hardMaxIterations: 500,
disableRemoteMcp: false,
disableExternalLLM: false
};
STRICT_OVERRIDES = {
restrictToolPaths: true,
pythonSandbox: true,
disableProjectSkills: true,
disableAutoUpdate: true,
hardMaxIterations: 200,
disableRemoteMcp: true,
disableExternalLLM: true
};
cachedConfig = null;
}
});
// src/team/model-contract.ts
import { spawnSync as spawnSync3 } from "child_process";
import { isAbsolute as isAbsolute5, normalize as normalize2, win32 as win32Path2 } from "path";
function getTrustedPrefixes() {
const trusted = [
"/usr/local/bin",
"/usr/bin",
"/opt/homebrew/"
];
const home = process.env.HOME;
if (home) {
trusted.push(`${home}/.local/bin`);
trusted.push(`${home}/.nvm/`);
trusted.push(`${home}/.cargo/bin`);
}
const custom = (process.env.OMC_TRUSTED_CLI_DIRS ?? "").split(":").map((part) => part.trim()).filter(Boolean).filter((part) => isAbsolute5(part));
trusted.push(...custom);
return trusted;
}
function isTrustedPrefix(resolvedPath) {
const normalized = normalize2(resolvedPath);
return getTrustedPrefixes().some((prefix) => normalized.startsWith(normalize2(prefix)));
}
function assertBinaryName(binary) {
if (!/^[A-Za-z0-9._-]+$/.test(binary)) {
throw new Error(`Invalid CLI binary name: ${binary}`);
}
}
function resolveCliBinaryPath(binary) {
assertBinaryName(binary);
const cached = resolvedPathCache.get(binary);
if (cached) return cached;
const finder = process.platform === "win32" ? "where" : "which";
const result = spawnSync3(finder, [binary], {
timeout: 5e3,
env: process.env
});
if (result.status !== 0) {
throw new Error(`CLI binary '${binary}' not found in PATH`);
}
const stdout = result.stdout?.toString().trim() ?? "";
const firstLine = stdout.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
if (!firstLine) {
throw new Error(`CLI binary '${binary}' not found in PATH`);
}
const resolvedPath = normalize2(firstLine);
if (!isAbsolute5(resolvedPath)) {
throw new Error(`Resolved CLI binary '${binary}' to relative path`);
}
if (UNTRUSTED_PATH_PATTERNS.some((pattern) => pattern.test(resolvedPath))) {
throw new Error(`Resolved CLI binary '${binary}' to untrusted location: ${resolvedPath}`);
}
if (!isTrustedPrefix(resolvedPath)) {
console.warn(`[omc:cli-security] CLI binary '${binary}' resolved to non-standard path: ${resolvedPath}`);
}
resolvedPathCache.set(binary, resolvedPath);
return resolvedPath;
}
function getContract(agentType) {
const contract = CONTRACTS[agentType];
if (!contract) {
throw new Error(`Unknown agent type: ${agentType}. Supported: ${Object.keys(CONTRACTS).join(", ")}`);
}
if (agentType !== "claude" && isExternalLLMDisabled()) {
throw new Error(
`External LLM provider "${agentType}" is blocked by security policy (disableExternalLLM). Only Claude workers are allowed in the current security configuration.`
);
}
return contract;
}
function validateBinaryRef(binary) {
if (isAbsolute5(binary)) return;
if (/^[A-Za-z0-9._-]+$/.test(binary)) return;
throw new Error(`Unsafe CLI binary reference: ${binary}`);
}
function resolveBinaryPath(binary) {
validateBinaryRef(binary);
if (isAbsolute5(binary)) return binary;
try {
const resolver = process.platform === "win32" ? "where" : "which";
const result = spawnSync3(resolver, [binary], { timeout: 5e3, encoding: "utf8" });
if (result.status !== 0) return binary;
const lines = result.stdout?.split(/\r?\n/).map((line) => line.trim()).filter(Boolean) ?? [];
const firstPath = lines[0];
const isResolvedAbsolute = !!firstPath && (isAbsolute5(firstPath) || win32Path2.isAbsolute(firstPath));
return isResolvedAbsolute ? firstPath : binary;
} catch {
return binary;
}
}
function resolveValidatedBinaryPath(agentType) {
const contract = getContract(agentType);
return resolveCliBinaryPath(contract.binary);
}
function buildLaunchArgs(agentType, config) {
return getContract(agentType).buildLaunchArgs(config.model, config.extraFlags);
}
function buildWorkerArgv(agentType, config) {
validateTeamName(config.teamName);
const contract = getContract(agentType);
const binary = config.resolvedBinaryPath ? (() => {
validateBinaryRef(config.resolvedBinaryPath);
return config.resolvedBinaryPath;
})() : resolveBinaryPath(contract.binary);
const args = buildLaunchArgs(agentType, config);
return [binary, ...args];
}
function getWorkerEnv(teamName, workerName, agentType, env = process.env) {
validateTeamName(teamName);
const workerEnv = {
OMC_TEAM_WORKER: `${teamName}/${workerName}`,
OMC_TEAM_NAME: teamName,
OMC_WORKER_AGENT_TYPE: agentType
};
for (const key of WORKER_MODEL_ENV_ALLOWLIST) {
const value = env[key];
if (typeof value === "string" && value.length > 0) {
workerEnv[key] = value;
}
}
return workerEnv;
}
function isPromptModeAgent(agentType) {
const contract = getContract(agentType);
return !!contract.supportsPromptMode;
}
function resolveClaudeWorkerModel(env = process.env) {
if (env.OMC_ROUTING_FORCE_INHERIT === "true") {
return void 0;
}
if (!isBedrock() && !isVertexAI()) {
return void 0;
}
const directModel = env.ANTHROPIC_MODEL || env.CLAUDE_MODEL || "";
if (directModel) {
return directModel;
}
const bedrockModel = env.CLAUDE_CODE_BEDROCK_SONNET_MODEL || env.ANTHROPIC_DEFAULT_SONNET_MODEL || "";
if (bedrockModel) {
return bedrockModel;
}
const omcModel = env.OMC_MODEL_MEDIUM || "";
if (omcModel) {
return omcModel;
}
return void 0;
}
function getPromptModeArgs(agentType, instruction) {
const contract = getContract(agentType);
if (!contract.supportsPromptMode) {
return [];
}
if (contract.promptModeFlag) {
return [contract.promptModeFlag, instruction];
}
return [instruction];
}
var resolvedPathCache, UNTRUSTED_PATH_PATTERNS, CONTRACTS, WORKER_MODEL_ENV_ALLOWLIST;
var init_model_contract = __esm({
"src/team/model-contract.ts"() {
"use strict";
init_team_name();
init_delegation_enforcer();
init_models();
init_security_config();
resolvedPathCache = /* @__PURE__ */ new Map();
UNTRUSTED_PATH_PATTERNS = [
/^\/tmp(\/|$)/,
/^\/var\/tmp(\/|$)/,
/^\/dev\/shm(\/|$)/
];
CONTRACTS = {
claude: {
agentType: "claude",
binary: "claude",
installInstructions: "Install Claude CLI: https://claude.ai/download",
buildLaunchArgs(model, extraFlags = []) {
const args = ["--dangerously-skip-permissions"];
if (model) {
const resolved = isProviderSpecificModelId(model) ? model : normalizeToCcAlias(model);
args.push("--model", resolved);
}
return [...args, ...extraFlags];
},
parseOutput(rawOutput) {
return rawOutput.trim();
}
},
codex: {
agentType: "codex",
binary: "codex",
installInstructions: "Install Codex CLI: npm install -g @openai/codex",
supportsPromptMode: true,
// Codex accepts prompt as a positional argument (no flag needed):
// codex [OPTIONS] [PROMPT]
buildLaunchArgs(model, extraFlags = []) {
const args = ["--dangerously-bypass-approvals-and-sandbox"];
if (model) args.push("--model", model);
return [...args, ...extraFlags];
},
parseOutput(rawOutput) {
const lines = rawOutput.trim().split("\n").filter(Boolean);
for (let i = lines.length - 1; i >= 0; i--) {
try {
const parsed = JSON.parse(lines[i]);
if (parsed.type === "message" && parsed.role === "assistant") {
return parsed.content ?? rawOutput;
}
if (parsed.type === "result" || parsed.output) {
return parsed.output ?? parsed.result ?? rawOutput;
}
} catch {
}
}
return rawOutput.trim();
}
},
gemini: {
agentType: "gemini",
binary: "gemini",
installInstructions: "Install Gemini CLI: npm install -g @google/gemini-cli",
supportsPromptMode: true,
promptModeFlag: "-i",
buildLaunchArgs(model, extraFlags = []) {
const args = ["--approval-mode", "yolo"];
if (model) args.push("--model", model);
return [...args, ...extraFlags];
},
parseOutput(rawOutput) {
return rawOutput.trim();
}
}
};
WORKER_MODEL_ENV_ALLOWLIST = [
"ANTHROPIC_MODEL",
"CLAUDE_MODEL",
"ANTHROPIC_BASE_URL",
"CLAUDE_CODE_USE_BEDROCK",
"CLAUDE_CODE_USE_VERTEX",
"CLAUDE_CODE_BEDROCK_OPUS_MODEL",
"CLAUDE_CODE_BEDROCK_SONNET_MODEL",
"CLAUDE_CODE_BEDROCK_HAIKU_MODEL",
"ANTHROPIC_DEFAULT_OPUS_MODEL",
"ANTHROPIC_DEFAULT_SONNET_MODEL",
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
"OMC_MODEL_HIGH",
"OMC_MODEL_MEDIUM",
"OMC_MODEL_LOW",
"OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL",
"OMC_CODEX_DEFAULT_MODEL",
"OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL",
"OMC_GEMINI_DEFAULT_MODEL"
];
}
});
// src/team/worker-bootstrap.ts
import { mkdir as mkdir3, writeFile as writeFile3, appendFile as appendFile2 } from "fs/promises";
import { join as join13, dirname as dirname7 } from "path";
function buildInstructionPath(...parts) {
return join13(...parts).replaceAll("\\", "/");
}
function generateTriggerMessage(teamName, workerName, teamStateRoot3 = ".omc/state") {
const inboxPath = buildInstructionPath(teamStateRoot3, "team", teamName, "workers", workerName, "inbox.md");
if (teamStateRoot3 !== ".omc/state") {
return `Read ${inboxPath}, work now, report progress.`;
}
return `Read ${inboxPath}, start work now, report concrete progress (not ACK-only), and keep executing your assigned or next feasible work.`;
}
function generatePromptModeStartupPrompt(teamName, workerName, teamStateRoot3 = ".omc/state") {
const inboxPath = buildInstructionPath(teamStateRoot3, "team", teamName, "workers", workerName, "inbox.md");
return `Open ${inboxPath}. Follow it and begin the assigned work.`;
}
function generateMailboxTriggerMessage(teamName, workerName, count = 1, teamStateRoot3 = ".omc/state") {
const normalizedCount = Number.isFinite(count) ? Math.max(1, Math.floor(count)) : 1;
const mailboxPath = buildInstructionPath(teamStateRoot3, "team", teamName, "mailbox", `${workerName}.json`);
if (teamStateRoot3 !== ".omc/state") {
return `${normalizedCount} new msg(s): check ${mailboxPath}, act and report progress.`;
}
return `You have ${normalizedCount} new message(s). Check ${mailboxPath}, act now, reply with concrete progress (not ACK-only), and keep executing your assigned or next feasible work.`;
}
function agentTypeGuidance(agentType) {
const teamApiCommand = formatOmcCliInvocation("team api");
const claimTaskCommand = formatOmcCliInvocation("team api claim-task");
const transitionTaskStatusCommand = formatOmcCliInvocation("team api transition-task-status");
switch (agentType) {
case "codex":
return [
"### Agent-Type Guidance (codex)",
`- Prefer short, explicit \`${teamApiCommand} ... --json\` commands and parse outputs before next step.`,
"- If a command fails, report the exact stderr to leader-fixed before retrying.",
`- You MUST run \`${claimTaskCommand}\` before starting work and \`${transitionTaskStatusCommand}\` when done.`
].join("\n");
case "gemini":
return [
"### Agent-Type Guidance (gemini)",
"- Execute task work in small, verifiable increments and report each milestone to leader-fixed.",
"- Keep commit-sized changes scoped to assigned files only; no broad refactors.",
`- CRITICAL: You MUST run \`${claimTaskCommand}\` before starting work and \`${transitionTaskStatusCommand}\` when done. Do not exit without transitioning the task status.`
].join("\n");
case "claude":
default:
return [
"### Agent-Type Guidance (claude)",
"- Keep reasoning focused on assigned task IDs and send concise progress acks to leader-fixed.",
"- Before any risky command, send a blocker/proposal message to leader-fixed and wait for updated inbox instructions."
].join("\n");
}
}
function generateWorkerOverlay(params) {
const { teamName, workerName, agentType, tasks, bootstrapInstructions } = params;
const sanitizedTasks = tasks.map((t) => ({
id: t.id,
subject: sanitizePromptContent(t.subject),
description: sanitizePromptContent(t.description)
}));
const sentinelPath = `.omc/state/team/${teamName}/workers/${workerName}/.ready`;
const heartbeatPath = `.omc/state/team/${teamName}/workers/${workerName}/heartbeat.json`;
const inboxPath = `.omc/state/team/${teamName}/workers/${workerName}/inbox.md`;
const statusPath = `.omc/state/team/${teamName}/workers/${workerName}/status.json`;
const claimTaskCommand = formatOmcCliInvocation(`team api claim-task --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"worker\\":\\"${workerName}\\"}" --json`);
const sendAckCommand = formatOmcCliInvocation(`team api send-message --input "{\\"team_name\\":\\"${teamName}\\",\\"from_worker\\":\\"${workerName}\\",\\"to_worker\\":\\"leader-fixed\\",\\"body\\":\\"ACK: ${workerName} initialized\\"}" --json`);
const completeTaskCommand = formatOmcCliInvocation(`team api transition-task-status --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"from\\":\\"in_progress\\",\\"to\\":\\"completed\\",\\"claim_token\\":\\"<claim_token>\\"}" --json`);
const failTaskCommand = formatOmcCliInvocation(`team api transition-task-status --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"from\\":\\"in_progress\\",\\"to\\":\\"failed\\",\\"claim_token\\":\\"<claim_token>\\"}" --json`);
const readTaskCommand = formatOmcCliInvocation(`team api read-task --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\"}" --json`);
const releaseClaimCommand = formatOmcCliInvocation(`team api release-task-claim --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"claim_token\\":\\"<claim_token>\\",\\"worker\\":\\"${workerName}\\"}" --json`);
const mailboxListCommand = formatOmcCliInvocation(`team api mailbox-list --input "{\\"team_name\\":\\"${teamName}\\",\\"worker\\":\\"${workerName}\\"}" --json`);
const mailboxDeliveredCommand = formatOmcCliInvocation(`team api mailbox-mark-delivered --input "{\\"team_name\\":\\"${teamName}\\",\\"worker\\":\\"${workerName}\\",\\"message_id\\":\\"<id>\\"}" --json`);
const teamApiCommand = formatOmcCliInvocation("team api");
const teamCommand2 = formatOmcCliInvocation("team");
const taskList = sanitizedTasks.length > 0 ? sanitizedTasks.map((t) => `- **Task ${t.id}**: ${t.subject}
Description: ${t.description}
Status: pending`).join("\n") : "- No tasks assigned yet. Check your inbox for assignments.";
return `# Team Worker Protocol
You are a **team worker**, not the team leader. Operate strictly within worker protocol.
## FIRST ACTION REQUIRED
Before doing anything else, write your ready sentinel file:
\`\`\`bash
mkdir -p $(dirname ${sentinelPath}) && touch ${sentinelPath}
\`\`\`
## MANDATORY WORKFLOW \u2014 Follow These Steps In Order
You MUST complete ALL of these steps. Do NOT skip any step. Do NOT exit without step 4.
1. **Claim** your task (run this command first):
\`${claimTaskCommand}\`
Save the \`claim_token\` from the response \u2014 you need it for step 4.
2. **Do the work** described in your task assignment below.
3. **Send ACK** to the leader:
\`${sendAckCommand}\`
4. **Transition** the task status (REQUIRED before exit):
- On success: \`${completeTaskCommand}\`
- On failure: \`${failTaskCommand}\`
5. **Keep going after replies**: ACK/progress messages are not a stop signal. Keep executing your assigned or next feasible work until the task is actually complete or failed, then transition and exit.
## Identity
- **Team**: ${teamName}
- **Worker**: ${workerName}
- **Agent Type**: ${agentType}
- **Environment**: OMC_TEAM_WORKER=${teamName}/${workerName}
## Your Tasks
${taskList}
## Task Lifecycle Reference (CLI API)
Use the CLI API for all task lifecycle operations. Do NOT directly edit task files.
- Inspect task state: \`${readTaskCommand}\`
- Task id format: State/CLI APIs use task_id: "<id>" (example: "1"), not "task-1"
- Claim task: \`${claimTaskCommand}\`
- Complete task: \`${completeTaskCommand}\`
- Fail task: \`${failTaskCommand}\`
- Release claim (rollback): \`${releaseClaimCommand}\`
## Communication Protocol
- **Inbox**: Read ${inboxPath} for new instructions
- **Status**: Write to ${statusPath}:
\`\`\`json
{"state": "idle", "updated_at": "<ISO timestamp>"}
\`\`\`
States: "idle" | "working" | "blocked" | "done" | "failed"
- **Heartbeat**: Update ${heartbeatPath} every few minutes:
\`\`\`json
{"pid":<pid>,"last_turn_at":"<ISO timestamp>","turn_count":<n>,"alive":true}
\`\`\`
## Message Protocol
Send messages via CLI API:
- To leader: \`${formatOmcCliInvocation(`team api send-message --input "{\\"team_name\\":\\"${teamName}\\",\\"from_worker\\":\\"${workerName}\\",\\"to_worker\\":\\"leader-fixed\\",\\"body\\":\\"<message>\\"}" --json`)}\`
- Check mailbox: \`${mailboxListCommand}\`
- Mark delivered: \`${mailboxDeliveredCommand}\`
## Startup Handshake (Required)
Before doing any task work, send exactly one startup ACK to the leader:
\`${sendAckCommand}\`
## Shutdown Protocol
When you see a shutdown request in your inbox:
1. Write your decision to: .omc/state/team/${teamName}/workers/${workerName}/shutdown-ack.json
2. Format:
- Accept: {"status":"accept","reason":"ok","updated_at":"<iso>"}
- Reject: {"status":"reject","reason":"still working","updated_at":"<iso>"}
3. Exit your session
## Rules
- You are NOT the leader. Never run leader orchestration workflows.
- Do NOT edit files outside the paths listed in your task description
- Do NOT write lifecycle fields (status, owner, result, error) directly in task files; use CLI API
- Do NOT spawn sub-agents. Complete work in this worker session only.
- Do NOT create tmux panes/sessions (\`tmux split-window\`, \`tmux new-session\`, etc.).
- Do NOT run team spawning/orchestration commands (for example: \`${teamCommand2} ...\`, \`omx team ...\`, \`$team\`, \`$ultrawork\`, \`$autopilot\`, \`$ralph\`).
- Worker-allowed control surface is only: \`${teamApiCommand} ... --json\` (and equivalent \`omx team api ... --json\` where configured).
- If blocked, write {"state": "blocked", "reason": "..."} to your status file
${agentTypeGuidance(agentType)}
## BEFORE YOU EXIT
You MUST call \`${formatOmcCliInvocation("team api transition-task-status")}\` to mark your task as "completed" or "failed" before exiting.
If you skip this step, the leader cannot track your work and the task will appear stuck.
${bootstrapInstructions ? `## Role Context
${bootstrapInstructions}
` : ""}`;
}
async function composeInitialInbox(teamName, workerName, content, cwd) {
const inboxPath = join13(cwd, `.omc/state/team/${teamName}/workers/${workerName}/inbox.md`);
await mkdir3(dirname7(inboxPath), { recursive: true });
await writeFile3(inboxPath, content, "utf-8");
}
async function ensureWorkerStateDir(teamName, workerName, cwd) {
const workerDir = join13(cwd, `.omc/state/team/${teamName}/workers/${workerName}`);
await mkdir3(workerDir, { recursive: true });
const mailboxDir = join13(cwd, `.omc/state/team/${teamName}/mailbox`);
await mkdir3(mailboxDir, { recursive: true });
const tasksDir = join13(cwd, `.omc/state/team/${teamName}/tasks`);
await mkdir3(tasksDir, { recursive: true });
}
async function writeWorkerOverlay(params) {
const { teamName, workerName, cwd } = params;
const overlay = generateWorkerOverlay(params);
const overlayPath = join13(cwd, `.omc/state/team/${teamName}/workers/${workerName}/AGENTS.md`);
await mkdir3(dirname7(overlayPath), { recursive: true });
await writeFile3(overlayPath, overlay, "utf-8");
return overlayPath;
}
var init_worker_bootstrap = __esm({
"src/team/worker-bootstrap.ts"() {
"use strict";
init_prompt_helpers();
init_omc_cli_rendering();
init_model_contract();
}
});
// src/lib/atomic-write.ts
import * as fs2 from "fs/promises";
import * as fsSync from "fs";
import * as path from "path";
import * as crypto from "crypto";
function ensureDirSync(dir) {
if (fsSync.existsSync(dir)) {
return;
}
try {
fsSync.mkdirSync(dir, { recursive: true });
} catch (err) {
if (err.code === "EEXIST") {
return;
}
throw err;
}
}
var init_atomic_write = __esm({
"src/lib/atomic-write.ts"() {
"use strict";
}
});
// src/platform/process-utils.ts
import { execFileSync as execFileSync2, execFile as execFile2 } from "child_process";
import { promisify as promisify2 } from "util";
import * as fsPromises from "fs/promises";
function isProcessAlive(pid) {
if (!Number.isInteger(pid) || pid <= 0) return false;
try {
process.kill(pid, 0);
return true;
} catch (e) {
if (e && typeof e === "object" && "code" in e && e.code === "EPERM") {
return true;
}
return false;
}
}
var execFileAsync;
var init_process_utils = __esm({
"src/platform/process-utils.ts"() {
"use strict";
execFileAsync = promisify2(execFile2);
}
});
// src/platform/index.ts
import * as path2 from "path";
import { readFileSync as readFileSync5 } from "fs";
var PLATFORM;
var init_platform = __esm({
"src/platform/index.ts"() {
"use strict";
init_process_utils();
PLATFORM = process.platform;
}
});
// src/lib/file-lock.ts
var file_lock_exports = {};
__export(file_lock_exports, {
acquireFileLock: () => acquireFileLock,
acquireFileLockSync: () => acquireFileLockSync,
lockPathFor: () => lockPathFor,
releaseFileLock: () => releaseFileLock,
releaseFileLockSync: () => releaseFileLockSync,
withFileLock: () => withFileLock,
withFileLockSync: () => withFileLockSync
});
import {
openSync as openSync3,
closeSync as closeSync3,
unlinkSync as unlinkSync3,
writeSync as writeSync3,
readFileSync as readFileSync6,
statSync as statSync2,
constants as fsConstants
} from "fs";
import * as path3 from "path";
function isLockStale(lockPath, staleLockMs) {
try {
const stat2 = statSync2(lockPath);
const ageMs = Date.now() - stat2.mtimeMs;
if (ageMs < staleLockMs) return false;
try {
const raw = readFileSync6(lockPath, "utf-8");
const payload = JSON.parse(raw);
if (payload.pid && isProcessAlive(payload.pid)) return false;
} catch {
}
return true;
} catch {
return false;
}
}
function lockPathFor(filePath) {
return filePath + ".lock";
}
function tryAcquireSync(lockPath, staleLockMs) {
ensureDirSync(path3.dirname(lockPath));
try {
const fd = openSync3(
lockPath,
fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY,
384
);
try {
const payload = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
writeSync3(fd, payload, null, "utf-8");
} catch (writeErr) {
try {
closeSync3(fd);
} catch {
}
try {
unlinkSync3(lockPath);
} catch {
}
throw writeErr;
}
return { fd, path: lockPath };
} catch (err) {
if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
if (isLockStale(lockPath, staleLockMs)) {
try {
unlinkSync3(lockPath);
} catch {
}
try {
const fd = openSync3(
lockPath,
fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY,
384
);
try {
const payload = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
writeSync3(fd, payload, null, "utf-8");
} catch (writeErr) {
try {
closeSync3(fd);
} catch {
}
try {
unlinkSync3(lockPath);
} catch {
}
throw writeErr;
}
return { fd, path: lockPath };
} catch {
return null;
}
}
return null;
}
throw err;
}
}
function acquireFileLockSync(lockPath, opts) {
const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
const timeoutMs = opts?.timeoutMs ?? 0;
const retryDelayMs = opts?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
const handle = tryAcquireSync(lockPath, staleLockMs);
if (handle || timeoutMs <= 0) return handle;
const deadline = Date.now() + timeoutMs;
const sharedBuf = new SharedArrayBuffer(4);
const sharedArr = new Int32Array(sharedBuf);
while (Date.now() < deadline) {
const waitMs = Math.min(retryDelayMs, deadline - Date.now());
try {
Atomics.wait(sharedArr, 0, 0, waitMs);
} catch {
const waitUntil = Date.now() + waitMs;
while (Date.now() < waitUntil) {
}
}
const retryHandle = tryAcquireSync(lockPath, staleLockMs);
if (retryHandle) return retryHandle;
}
return null;
}
function releaseFileLockSync(handle) {
try {
closeSync3(handle.fd);
} catch {
}
try {
unlinkSync3(handle.path);
} catch {
}
}
function withFileLockSync(lockPath, fn, opts) {
const handle = acquireFileLockSync(lockPath, opts);
if (!handle) {
throw new Error(`Failed to acquire file lock: ${lockPath}`);
}
try {
return fn();
} finally {
releaseFileLockSync(handle);
}
}
function sleep2(ms) {
return new Promise((resolve4) => setTimeout(resolve4, ms));
}
async function acquireFileLock(lockPath, opts) {
const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
const timeoutMs = opts?.timeoutMs ?? 0;
const retryDelayMs = opts?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
const handle = tryAcquireSync(lockPath, staleLockMs);
if (handle || timeoutMs <= 0) return handle;
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
await sleep2(Math.min(retryDelayMs, deadline - Date.now()));
const retryHandle = tryAcquireSync(lockPath, staleLockMs);
if (retryHandle) return retryHandle;
}
return null;
}
function releaseFileLock(handle) {
releaseFileLockSync(handle);
}
async function withFileLock(lockPath, fn, opts) {
const handle = await acquireFileLock(lockPath, opts);
if (!handle) {
throw new Error(`Failed to acquire file lock: ${lockPath}`);
}
try {
return await fn();
} finally {
releaseFileLock(handle);
}
}
var DEFAULT_STALE_LOCK_MS, DEFAULT_RETRY_DELAY_MS;
var init_file_lock = __esm({
"src/lib/file-lock.ts"() {
"use strict";
init_atomic_write();
init_platform();
DEFAULT_STALE_LOCK_MS = 3e4;
DEFAULT_RETRY_DELAY_MS = 50;
}
});
// src/team/git-worktree.ts
import { existsSync as existsSync10, readFileSync as readFileSync7, rmSync as rmSync2 } from "node:fs";
import { join as join15 } from "node:path";
import { execFileSync as execFileSync3 } from "node:child_process";
function getWorktreePath(repoRoot, teamName, workerName) {
return join15(repoRoot, ".omc", "worktrees", sanitizeName(teamName), sanitizeName(workerName));
}
function getBranchName(teamName, workerName) {
return `omc-team/${sanitizeName(teamName)}/${sanitizeName(workerName)}`;
}
function getMetadataPath(repoRoot, teamName) {
return join15(repoRoot, ".omc", "state", "team-bridge", sanitizeName(teamName), "worktrees.json");
}
function readMetadata(repoRoot, teamName) {
const metaPath = getMetadataPath(repoRoot, teamName);
if (!existsSync10(metaPath)) return [];
try {
return JSON.parse(readFileSync7(metaPath, "utf-8"));
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
process.stderr.write(`[omc] warning: worktrees.json parse error: ${msg}
`);
return [];
}
}
function writeMetadata(repoRoot, teamName, entries) {
const metaPath = getMetadataPath(repoRoot, teamName);
validateResolvedPath(metaPath, repoRoot);
const dir = join15(repoRoot, ".omc", "state", "team-bridge", sanitizeName(teamName));
ensureDirWithMode(dir);
atomicWriteJson(metaPath, entries);
}
function removeWorkerWorktree(teamName, workerName, repoRoot) {
const wtPath = getWorktreePath(repoRoot, teamName, workerName);
const branch = getBranchName(teamName, workerName);
try {
execFileSync3("git", ["worktree", "remove", "--force", wtPath], { cwd: repoRoot, stdio: "pipe" });
} catch {
}
try {
execFileSync3("git", ["worktree", "prune"], { cwd: repoRoot, stdio: "pipe" });
} catch {
}
try {
execFileSync3("git", ["branch", "-D", branch], { cwd: repoRoot, stdio: "pipe" });
} catch {
}
const metaLockPath = getMetadataPath(repoRoot, teamName) + ".lock";
withFileLockSync(metaLockPath, () => {
const existing = readMetadata(repoRoot, teamName);
const updated = existing.filter((e) => e.workerName !== workerName);
writeMetadata(repoRoot, teamName, updated);
});
}
function cleanupTeamWorktrees(teamName, repoRoot) {
const entries = readMetadata(repoRoot, teamName);
for (const entry of entries) {
try {
removeWorkerWorktree(teamName, entry.workerName, repoRoot);
} catch {
}
}
}
var init_git_worktree = __esm({
"src/team/git-worktree.ts"() {
"use strict";
init_fs_utils();
init_tmux_session();
init_file_lock();
}
});
// src/team/allocation-policy.ts
function allocateTasksToWorkers(tasks, workers) {
if (tasks.length === 0 || workers.length === 0) return [];
const uniformRolePool = isUniformRolePool(workers);
const results = [];
const loadMap = new Map(workers.map((w) => [w.name, w.currentLoad]));
if (uniformRolePool) {
for (const task of tasks) {
const target = pickLeastLoaded(workers, loadMap);
results.push({
taskId: task.id,
workerName: target.name,
reason: `uniform pool round-robin (role=${target.role}, load=${loadMap.get(target.name)})`
});
loadMap.set(target.name, (loadMap.get(target.name) ?? 0) + 1);
}
} else {
for (const task of tasks) {
const target = pickBestWorker(task, workers, loadMap);
results.push({
taskId: task.id,
workerName: target.name,
reason: `role match (task.role=${task.role ?? "any"}, worker.role=${target.role}, load=${loadMap.get(target.name)})`
});
loadMap.set(target.name, (loadMap.get(target.name) ?? 0) + 1);
}
}
return results;
}
function isUniformRolePool(workers) {
if (workers.length === 0) return true;
const firstRole = workers[0].role;
return workers.every((w) => w.role === firstRole);
}
function pickLeastLoaded(workers, loadMap) {
let best = workers[0];
let bestLoad = loadMap.get(best.name) ?? 0;
for (const w of workers) {
const load = loadMap.get(w.name) ?? 0;
if (load < bestLoad) {
best = w;
bestLoad = load;
}
}
return best;
}
function pickBestWorker(task, workers, loadMap) {
const scored = workers.map((w) => {
const load = loadMap.get(w.name) ?? 0;
const roleScore = task.role ? w.role === task.role ? 1 : 0 : 0.5;
const score = roleScore - load * 0.2;
return { worker: w, score };
});
scored.sort((a, b) => b.score - a.score);
return scored[0].worker;
}
var init_allocation_policy = __esm({
"src/team/allocation-policy.ts"() {
"use strict";
}
});
// src/team/monitor.ts
import { existsSync as existsSync13 } from "fs";
import { readFile as readFile7, mkdir as mkdir5 } from "fs/promises";
import { dirname as dirname10 } from "path";
async function readJsonSafe3(filePath) {
try {
if (!existsSync13(filePath)) return null;
const raw = await readFile7(filePath, "utf-8");
return JSON.parse(raw);
} catch {
return null;
}
}
async function writeAtomic2(filePath, data) {
const { writeFile: writeFile6 } = await import("fs/promises");
await mkdir5(dirname10(filePath), { recursive: true });
const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
await writeFile6(tmpPath, data, "utf-8");
const { rename: rename3 } = await import("fs/promises");
await rename3(tmpPath, filePath);
}
function configFromManifest2(manifest) {
return {
name: manifest.name,
task: manifest.task,
agent_type: "claude",
policy: manifest.policy,
governance: manifest.governance,
worker_launch_mode: manifest.policy.worker_launch_mode,
worker_count: manifest.worker_count,
max_workers: 20,
workers: manifest.workers,
created_at: manifest.created_at,
tmux_session: manifest.tmux_session,
next_task_id: manifest.next_task_id,
leader_cwd: manifest.leader_cwd,
team_state_root: manifest.team_state_root,
workspace_mode: manifest.workspace_mode,
leader_pane_id: manifest.leader_pane_id,
hud_pane_id: manifest.hud_pane_id,
resize_hook_name: manifest.resize_hook_name,
resize_hook_target: manifest.resize_hook_target,
next_worker_index: manifest.next_worker_index
};
}
async function readTeamConfig(teamName, cwd) {
const [config, manifest] = await Promise.all([
readJsonSafe3(absPath(cwd, TeamPaths.config(teamName))),
readTeamManifest(teamName, cwd)
]);
if (!config && !manifest) return null;
if (!manifest) return config ? canonicalizeTeamConfigWorkers(config) : null;
if (!config) return canonicalizeTeamConfigWorkers(configFromManifest2(manifest));
return canonicalizeTeamConfigWorkers({
...configFromManifest2(manifest),
...config,
workers: [...config.workers ?? [], ...manifest.workers ?? []],
worker_count: Math.max(config.worker_count ?? 0, manifest.worker_count ?? 0),
next_task_id: Math.max(config.next_task_id ?? 1, manifest.next_task_id ?? 1),
max_workers: Math.max(config.max_workers ?? 0, 20)
});
}
async function readTeamManifest(teamName, cwd) {
const manifest = await readJsonSafe3(absPath(cwd, TeamPaths.manifest(teamName)));
return manifest ? normalizeTeamManifest(manifest) : null;
}
async function readWorkerStatus(teamName, workerName, cwd) {
const data = await readJsonSafe3(absPath(cwd, TeamPaths.workerStatus(teamName, workerName)));
return data ?? { state: "unknown", updated_at: "" };
}
async function readWorkerHeartbeat(teamName, workerName, cwd) {
return readJsonSafe3(absPath(cwd, TeamPaths.heartbeat(teamName, workerName)));
}
async function readMonitorSnapshot(teamName, cwd) {
const p = absPath(cwd, TeamPaths.monitorSnapshot(teamName));
if (!existsSync13(p)) return null;
try {
const raw = await readFile7(p, "utf-8");
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== "object") return null;
const monitorTimings = (() => {
const candidate = parsed.monitorTimings;
if (!candidate || typeof candidate !== "object") return void 0;
if (typeof candidate.list_tasks_ms !== "number" || typeof candidate.worker_scan_ms !== "number" || typeof candidate.mailbox_delivery_ms !== "number" || typeof candidate.total_ms !== "number" || typeof candidate.updated_at !== "string") {
return void 0;
}
return candidate;
})();
return {
taskStatusById: parsed.taskStatusById ?? {},
workerAliveByName: parsed.workerAliveByName ?? {},
workerStateByName: parsed.workerStateByName ?? {},
workerTurnCountByName: parsed.workerTurnCountByName ?? {},
workerTaskIdByName: parsed.workerTaskIdByName ?? {},
mailboxNotifiedByMessageId: parsed.mailboxNotifiedByMessageId ?? {},
completedEventTaskIds: parsed.completedEventTaskIds ?? {},
monitorTimings
};
} catch {
return null;
}
}
async function writeMonitorSnapshot(teamName, snapshot, cwd) {
await writeAtomic2(absPath(cwd, TeamPaths.monitorSnapshot(teamName)), JSON.stringify(snapshot, null, 2));
}
async function writeShutdownRequest(teamName, workerName, fromWorker, cwd) {
const data = {
from: fromWorker,
requested_at: (/* @__PURE__ */ new Date()).toISOString()
};
await writeAtomic2(absPath(cwd, TeamPaths.shutdownRequest(teamName, workerName)), JSON.stringify(data, null, 2));
}
async function readShutdownAck(teamName, workerName, cwd, requestedAfter) {
const ack = await readJsonSafe3(
absPath(cwd, TeamPaths.shutdownAck(teamName, workerName))
);
if (!ack) return null;
if (requestedAfter && ack.updated_at) {
if (new Date(ack.updated_at).getTime() < new Date(requestedAfter).getTime()) {
return null;
}
}
return ack;
}
async function listTasksFromFiles(teamName, cwd) {
const tasksDir = absPath(cwd, TeamPaths.tasks(teamName));
if (!existsSync13(tasksDir)) return [];
const { readdir: readdir3 } = await import("fs/promises");
const entries = await readdir3(tasksDir);
const tasks = [];
for (const entry of entries) {
const match = /^(?:task-)?(\d+)\.json$/.exec(entry);
if (!match) continue;
const task = await readJsonSafe3(absPath(cwd, `${TeamPaths.tasks(teamName)}/${entry}`));
if (task) tasks.push(task);
}
return tasks.sort((a, b) => Number(a.id) - Number(b.id));
}
async function writeWorkerInbox(teamName, workerName, content, cwd) {
await writeAtomic2(absPath(cwd, TeamPaths.inbox(teamName, workerName)), content);
}
async function saveTeamConfig(config, cwd) {
await writeAtomic2(absPath(cwd, TeamPaths.config(config.name)), JSON.stringify(config, null, 2));
const manifestPath = absPath(cwd, TeamPaths.manifest(config.name));
const existingManifest = await readJsonSafe3(manifestPath);
if (existingManifest) {
const nextManifest = normalizeTeamManifest({
...existingManifest,
workers: config.workers,
worker_count: config.worker_count,
tmux_session: config.tmux_session,
next_task_id: config.next_task_id,
created_at: config.created_at,
leader_cwd: config.leader_cwd,
team_state_root: config.team_state_root,
workspace_mode: config.workspace_mode,
leader_pane_id: config.leader_pane_id,
hud_pane_id: config.hud_pane_id,
resize_hook_name: config.resize_hook_name,
resize_hook_target: config.resize_hook_target,
next_worker_index: config.next_worker_index,
policy: config.policy ?? existingManifest.policy,
governance: config.governance ?? existingManifest.governance
});
await writeAtomic2(manifestPath, JSON.stringify(nextManifest, null, 2));
}
}
async function cleanupTeamState(teamName, cwd) {
const root = absPath(cwd, TeamPaths.root(teamName));
const { rm: rm5 } = await import("fs/promises");
try {
await rm5(root, { recursive: true, force: true });
} catch {
}
}
var init_monitor = __esm({
"src/team/monitor.ts"() {
"use strict";
init_state_paths();
init_governance();
init_worker_canonicalization();
}
});
// src/team/events.ts
import { randomUUID as randomUUID5 } from "crypto";
import { dirname as dirname11 } from "path";
import { mkdir as mkdir6, readFile as readFile8, appendFile as appendFile3 } from "fs/promises";
import { existsSync as existsSync14 } from "fs";
async function appendTeamEvent(teamName, event, cwd) {
const full = {
event_id: randomUUID5(),
team: teamName,
created_at: (/* @__PURE__ */ new Date()).toISOString(),
...event
};
const p = absPath(cwd, TeamPaths.events(teamName));
await mkdir6(dirname11(p), { recursive: true });
await appendFile3(p, `${JSON.stringify(full)}
`, "utf8");
return full;
}
async function emitMonitorDerivedEvents(teamName, tasks, workers, previousSnapshot, cwd) {
if (!previousSnapshot) return;
const logDerivedEventFailure = createSwallowedErrorLogger(
"team.events.emitMonitorDerivedEvents appendTeamEvent failed"
);
const completedEventTaskIds = { ...previousSnapshot.completedEventTaskIds ?? {} };
for (const task of tasks) {
const prevStatus = previousSnapshot.taskStatusById?.[task.id];
if (!prevStatus || prevStatus === task.status) continue;
if (task.status === "completed" && !completedEventTaskIds[task.id]) {
await appendTeamEvent(teamName, {
type: "task_completed",
worker: "leader-fixed",
task_id: task.id,
reason: `status_transition:${prevStatus}->${task.status}`
}, cwd).catch(logDerivedEventFailure);
completedEventTaskIds[task.id] = true;
} else if (task.status === "failed") {
await appendTeamEvent(teamName, {
type: "task_failed",
worker: "leader-fixed",
task_id: task.id,
reason: `status_transition:${prevStatus}->${task.status}`
}, cwd).catch(logDerivedEventFailure);
}
}
for (const worker of workers) {
const prevAlive = previousSnapshot.workerAliveByName?.[worker.name];
const prevState = previousSnapshot.workerStateByName?.[worker.name];
if (prevAlive === true && !worker.alive) {
await appendTeamEvent(teamName, {
type: "worker_stopped",
worker: worker.name,
reason: "pane_exited"
}, cwd).catch(logDerivedEventFailure);
}
if (prevState === "working" && worker.status.state === "idle") {
await appendTeamEvent(teamName, {
type: "worker_idle",
worker: worker.name,
reason: `state_transition:${prevState}->${worker.status.state}`
}, cwd).catch(logDerivedEventFailure);
}
}
}
var init_events = __esm({
"src/team/events.ts"() {
"use strict";
init_state_paths();
init_swallowed_error();
}
});
// src/team/phase-controller.ts
function inferPhase(tasks) {
if (tasks.length === 0) return "initializing";
const inProgress = tasks.filter((t) => t.status === "in_progress");
const pending = tasks.filter((t) => t.status === "pending");
const permanentlyFailed = tasks.filter(
(t) => t.status === "completed" && t.metadata?.permanentlyFailed === true
);
const genuinelyCompleted = tasks.filter(
(t) => t.status === "completed" && !t.metadata?.permanentlyFailed
);
const explicitlyFailed = tasks.filter((t) => t.status === "failed");
const allFailed = [...permanentlyFailed, ...explicitlyFailed];
if (inProgress.length > 0) return "executing";
if (pending.length === tasks.length && genuinelyCompleted.length === 0 && allFailed.length === 0) {
return "planning";
}
if (pending.length > 0 && genuinelyCompleted.length > 0 && inProgress.length === 0 && allFailed.length === 0) {
return "executing";
}
if (allFailed.length > 0) {
const hasRetriesRemaining = allFailed.some((t) => {
const retryCount = t.metadata?.retryCount ?? 0;
const maxRetries = t.metadata?.maxRetries ?? 3;
return retryCount < maxRetries;
});
if (allFailed.length === tasks.length && !hasRetriesRemaining || pending.length === 0 && inProgress.length === 0 && genuinelyCompleted.length === 0 && !hasRetriesRemaining) {
return "failed";
}
if (hasRetriesRemaining) return "fixing";
}
if (genuinelyCompleted.length === tasks.length && allFailed.length === 0) {
return "completed";
}
return "executing";
}
var init_phase_controller = __esm({
"src/team/phase-controller.ts"() {
"use strict";
}
});
// src/team/runtime-v2.ts
var runtime_v2_exports = {};
__export(runtime_v2_exports, {
CircuitBreakerV2: () => CircuitBreakerV2,
findActiveTeamsV2: () => findActiveTeamsV2,
isRuntimeV2Enabled: () => isRuntimeV2Enabled,
monitorTeamV2: () => monitorTeamV2,
requeueDeadWorkerTasks: () => requeueDeadWorkerTasks,
resumeTeamV2: () => resumeTeamV2,
shutdownTeamV2: () => shutdownTeamV2,
startTeamV2: () => startTeamV2,
writeWatchdogFailedMarker: () => writeWatchdogFailedMarker
});
import { join as join18, resolve as resolve3 } from "path";
import { existsSync as existsSync15 } from "fs";
import { mkdir as mkdir7, readdir as readdir2, readFile as readFile9, writeFile as writeFile5 } from "fs/promises";
import { performance } from "perf_hooks";
function isRuntimeV2Enabled(env = process.env) {
const raw = env.OMC_RUNTIME_V2;
if (!raw) return true;
const normalized = raw.trim().toLowerCase();
return !["0", "false", "no", "off"].includes(normalized);
}
function sanitizeTeamName(name) {
const sanitized = name.toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 30);
if (!sanitized) throw new Error(`Invalid team name: "${name}" produces empty slug after sanitization`);
return sanitized;
}
async function isWorkerPaneAlive(paneId) {
if (!paneId) return false;
try {
const { isWorkerAlive: isWorkerAlive2 } = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
return await isWorkerAlive2(paneId);
} catch {
return false;
}
}
async function captureWorkerPane(paneId) {
if (!paneId) return "";
try {
const result = await tmuxExecAsync(["capture-pane", "-t", paneId, "-p", "-S", "-80"]);
return result.stdout ?? "";
} catch {
return "";
}
}
function isFreshTimestamp(value, maxAgeMs = MONITOR_SIGNAL_STALE_MS) {
if (!value) return false;
const parsed = Date.parse(value);
if (!Number.isFinite(parsed)) return false;
return Date.now() - parsed <= maxAgeMs;
}
function findOutstandingWorkerTask(worker, taskById, inProgressByOwner) {
if (typeof worker.assigned_tasks === "object") {
for (const taskId of worker.assigned_tasks) {
const task = taskById.get(taskId);
if (task && (task.status === "pending" || task.status === "in_progress")) {
return task;
}
}
}
const owned = inProgressByOwner.get(worker.name) ?? [];
return owned[0] ?? null;
}
function getTaskDependencyIds(task) {
return task.depends_on ?? task.blocked_by ?? [];
}
function getMissingDependencyIds(task, taskById) {
return getTaskDependencyIds(task).filter((dependencyId) => !taskById.has(dependencyId));
}
function buildV2TaskInstruction(teamName, workerName, task, taskId) {
const claimTaskCommand = formatOmcCliInvocation(
`team api claim-task --input '${JSON.stringify({ team_name: teamName, task_id: taskId, worker: workerName })}' --json`,
{}
);
const completeTaskCommand = formatOmcCliInvocation(
`team api transition-task-status --input '${JSON.stringify({ team_name: teamName, task_id: taskId, from: "in_progress", to: "completed", claim_token: "<claim_token>" })}' --json`
);
const failTaskCommand = formatOmcCliInvocation(
`team api transition-task-status --input '${JSON.stringify({ team_name: teamName, task_id: taskId, from: "in_progress", to: "failed", claim_token: "<claim_token>" })}' --json`
);
return [
`## REQUIRED: Task Lifecycle Commands`,
`You MUST run these commands. Do NOT skip any step.`,
``,
`1. Claim your task:`,
` ${claimTaskCommand}`,
` Save the claim_token from the response.`,
`2. Do the work described below.`,
`3. On completion (use claim_token from step 1):`,
` ${completeTaskCommand}`,
`4. On failure (use claim_token from step 1):`,
` ${failTaskCommand}`,
`5. ACK/progress replies are not a stop signal. Keep executing your assigned or next feasible work until the task is actually complete or failed, then transition and exit.`,
``,
`## Task Assignment`,
`Task ID: ${taskId}`,
`Worker: ${workerName}`,
`Subject: ${task.subject}`,
``,
task.description,
``,
`REMINDER: You MUST run transition-task-status before exiting. Do NOT write done.json or edit task files directly.`
].join("\n");
}
async function notifyStartupInbox(sessionName2, paneId, message) {
const notified = await notifyPaneWithRetry(sessionName2, paneId, message);
return notified ? { ok: true, transport: "tmux_send_keys", reason: "worker_pane_notified" } : { ok: false, transport: "tmux_send_keys", reason: "worker_notify_failed" };
}
async function notifyPaneWithRetry(sessionName2, paneId, message, maxAttempts = 6, retryDelayMs = 350) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
if (await sendToWorker(sessionName2, paneId, message)) {
return true;
}
if (attempt < maxAttempts) {
await new Promise((r) => setTimeout(r, retryDelayMs));
}
}
return false;
}
function hasWorkerStatusProgress(status, taskId) {
if (status.current_task_id === taskId) return true;
return ["working", "blocked", "done", "failed"].includes(status.state);
}
async function hasWorkerTaskClaimEvidence(teamName, workerName, cwd, taskId) {
try {
const raw = await readFile9(absPath(cwd, TeamPaths.taskFile(teamName, taskId)), "utf-8");
const task = JSON.parse(raw);
return task.owner === workerName && ["in_progress", "completed", "failed"].includes(task.status);
} catch {
return false;
}
}
async function hasWorkerStartupEvidence(teamName, workerName, taskId, cwd) {
const [hasClaimEvidence, status] = await Promise.all([
hasWorkerTaskClaimEvidence(teamName, workerName, cwd, taskId),
readWorkerStatus(teamName, workerName, cwd)
]);
return hasClaimEvidence || hasWorkerStatusProgress(status, taskId);
}
async function waitForWorkerStartupEvidence(teamName, workerName, taskId, cwd, attempts = 3, delayMs = 250) {
for (let attempt = 1; attempt <= attempts; attempt++) {
if (await hasWorkerStartupEvidence(teamName, workerName, taskId, cwd)) {
return true;
}
if (attempt < attempts) {
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
}
}
return false;
}
async function spawnV2Worker(opts) {
const splitTarget = opts.existingWorkerPaneIds.length === 0 ? opts.leaderPaneId : opts.existingWorkerPaneIds[opts.existingWorkerPaneIds.length - 1];
const splitType = opts.existingWorkerPaneIds.length === 0 ? "-h" : "-v";
const splitResult = await tmuxExecAsync([
"split-window",
splitType,
"-t",
splitTarget,
"-d",
"-P",
"-F",
"#{pane_id}",
"-c",
opts.cwd
]);
const paneId = splitResult.stdout.split("\n")[0]?.trim();
if (!paneId) {
return { paneId: null, startupAssigned: false, startupFailureReason: "pane_id_missing" };
}
const usePromptMode = isPromptModeAgent(opts.agentType);
const instruction = buildV2TaskInstruction(
opts.teamName,
opts.workerName,
opts.task,
opts.taskId
);
const inboxTriggerMessage = generateTriggerMessage(opts.teamName, opts.workerName);
const promptModeStartupPrompt = generatePromptModeStartupPrompt(opts.teamName, opts.workerName);
if (usePromptMode) {
await composeInitialInbox(opts.teamName, opts.workerName, instruction, opts.cwd);
}
const envVars = {
...getWorkerEnv(opts.teamName, opts.workerName, opts.agentType),
OMC_TEAM_STATE_ROOT: teamStateRoot(opts.cwd, opts.teamName),
OMC_TEAM_LEADER_CWD: opts.cwd
};
const resolvedBinaryPath = opts.resolvedBinaryPaths[opts.agentType] ?? resolveValidatedBinaryPath(opts.agentType);
const modelForAgent = (() => {
if (opts.agentType === "codex") {
return process.env.OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL || process.env.OMC_CODEX_DEFAULT_MODEL || void 0;
}
if (opts.agentType === "gemini") {
return process.env.OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL || process.env.OMC_GEMINI_DEFAULT_MODEL || void 0;
}
return resolveClaudeWorkerModel();
})();
const [launchBinary, ...launchArgs] = buildWorkerArgv(opts.agentType, {
teamName: opts.teamName,
workerName: opts.workerName,
cwd: opts.cwd,
resolvedBinaryPath,
model: modelForAgent
});
if (usePromptMode) {
launchArgs.push(...getPromptModeArgs(opts.agentType, promptModeStartupPrompt));
}
const paneConfig = {
teamName: opts.teamName,
workerName: opts.workerName,
envVars,
launchBinary,
launchArgs,
cwd: opts.cwd
};
await spawnWorkerInPane(opts.sessionName, paneId, paneConfig);
await applyMainVerticalLayout(opts.sessionName);
if (!usePromptMode) {
const paneReady = await waitForPaneReady(paneId);
if (!paneReady) {
return {
paneId,
startupAssigned: false,
startupFailureReason: "worker_pane_not_ready"
};
}
}
const dispatchOutcome = await queueInboxInstruction({
teamName: opts.teamName,
workerName: opts.workerName,
workerIndex: opts.workerIndex + 1,
paneId,
inbox: instruction,
triggerMessage: inboxTriggerMessage,
cwd: opts.cwd,
transportPreference: usePromptMode ? "prompt_stdin" : "transport_direct",
fallbackAllowed: false,
inboxCorrelationKey: `startup:${opts.workerName}:${opts.taskId}`,
notify: async (_target, triggerMessage) => {
if (usePromptMode) {
return { ok: true, transport: "prompt_stdin", reason: "prompt_mode_launch_args" };
}
if (opts.agentType === "gemini") {
const confirmed = await notifyPaneWithRetry(opts.sessionName, paneId, "1");
if (!confirmed) {
return { ok: false, transport: "tmux_send_keys", reason: "worker_notify_failed:trust-confirm" };
}
await new Promise((r) => setTimeout(r, 800));
}
return notifyStartupInbox(opts.sessionName, paneId, triggerMessage);
},
deps: {
writeWorkerInbox
}
});
if (!dispatchOutcome.ok) {
return {
paneId,
startupAssigned: false,
startupFailureReason: dispatchOutcome.reason
};
}
if (opts.agentType === "claude") {
const settled = await waitForWorkerStartupEvidence(
opts.teamName,
opts.workerName,
opts.taskId,
opts.cwd,
6
);
if (!settled) {
return {
paneId,
startupAssigned: false,
startupFailureReason: "claude_startup_evidence_missing"
};
}
}
if (usePromptMode) {
const settled = await waitForWorkerStartupEvidence(
opts.teamName,
opts.workerName,
opts.taskId,
opts.cwd
);
if (!settled) {
return {
paneId,
startupAssigned: false,
startupFailureReason: `${opts.agentType}_startup_evidence_missing`
};
}
}
return {
paneId,
startupAssigned: true
};
}
async function startTeamV2(config) {
const sanitized = sanitizeTeamName(config.teamName);
const leaderCwd = resolve3(config.cwd);
validateTeamName(sanitized);
const agentTypes = config.agentTypes;
const resolvedBinaryPaths = {};
for (const agentType of [...new Set(agentTypes)]) {
resolvedBinaryPaths[agentType] = resolveValidatedBinaryPath(agentType);
}
await mkdir7(absPath(leaderCwd, TeamPaths.tasks(sanitized)), { recursive: true });
await mkdir7(absPath(leaderCwd, TeamPaths.workers(sanitized)), { recursive: true });
await mkdir7(join18(leaderCwd, ".omc", "state", "team", sanitized, "mailbox"), { recursive: true });
for (let i = 0; i < config.tasks.length; i++) {
const taskId = String(i + 1);
const taskFilePath = absPath(leaderCwd, TeamPaths.taskFile(sanitized, taskId));
await mkdir7(join18(taskFilePath, ".."), { recursive: true });
await writeFile5(taskFilePath, JSON.stringify({
id: taskId,
subject: config.tasks[i].subject,
description: config.tasks[i].description,
status: "pending",
owner: null,
result: null,
created_at: (/* @__PURE__ */ new Date()).toISOString()
}, null, 2), "utf-8");
}
const workerNames = Array.from({ length: config.workerCount }, (_, index) => `worker-${index + 1}`);
const workerNameSet = new Set(workerNames);
const startupAllocations = [];
const unownedTaskIndices = [];
for (let i = 0; i < config.tasks.length; i++) {
const owner = config.tasks[i]?.owner;
if (typeof owner === "string" && workerNameSet.has(owner)) {
startupAllocations.push({ workerName: owner, taskIndex: i });
} else {
unownedTaskIndices.push(i);
}
}
if (unownedTaskIndices.length > 0) {
const allocationTasks = unownedTaskIndices.map((idx) => ({
id: String(idx),
subject: config.tasks[idx].subject,
description: config.tasks[idx].description
}));
const allocationWorkers = workerNames.map((name, i) => ({
name,
role: config.workerRoles?.[i] ?? (agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude"),
currentLoad: 0
}));
for (const r of allocateTasksToWorkers(allocationTasks, allocationWorkers)) {
startupAllocations.push({ workerName: r.workerName, taskIndex: Number(r.taskId) });
}
}
for (let i = 0; i < workerNames.length; i++) {
const wName = workerNames[i];
const agentType = agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude";
await ensureWorkerStateDir(sanitized, wName, leaderCwd);
await writeWorkerOverlay({
teamName: sanitized,
workerName: wName,
agentType,
tasks: config.tasks.map((t, idx) => ({
id: String(idx + 1),
subject: t.subject,
description: t.description
})),
cwd: leaderCwd,
...config.rolePrompt ? { bootstrapInstructions: config.rolePrompt } : {}
});
}
const session = await createTeamSession(sanitized, 0, leaderCwd, {
newWindow: Boolean(config.newWindow)
});
const sessionName2 = session.sessionName;
const leaderPaneId = session.leaderPaneId;
const ownsWindow = session.sessionMode !== "split-pane";
const workerPaneIds = [];
const workersInfo = workerNames.map((wName, i) => ({
name: wName,
index: i + 1,
role: config.workerRoles?.[i] ?? (agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude"),
assigned_tasks: [],
working_dir: leaderCwd
}));
const teamConfig = {
name: sanitized,
task: config.tasks.map((t) => t.subject).join("; "),
agent_type: agentTypes[0] || "claude",
worker_launch_mode: "interactive",
policy: DEFAULT_TEAM_TRANSPORT_POLICY,
governance: DEFAULT_TEAM_GOVERNANCE,
worker_count: config.workerCount,
max_workers: 20,
workers: workersInfo,
created_at: (/* @__PURE__ */ new Date()).toISOString(),
tmux_session: sessionName2,
tmux_window_owned: ownsWindow,
next_task_id: config.tasks.length + 1,
leader_cwd: leaderCwd,
team_state_root: teamStateRoot(leaderCwd, sanitized),
leader_pane_id: leaderPaneId,
hud_pane_id: null,
resize_hook_name: null,
resize_hook_target: null,
...ownsWindow ? { workspace_mode: "single" } : {}
};
await saveTeamConfig(teamConfig, leaderCwd);
const permissionsSnapshot = {
approval_mode: process.env.OMC_APPROVAL_MODE || "default",
sandbox_mode: process.env.OMC_SANDBOX_MODE || "default",
network_access: process.env.OMC_NETWORK_ACCESS === "1"
};
const teamManifest = {
schema_version: 2,
name: sanitized,
task: teamConfig.task,
leader: {
session_id: sessionName2,
worker_id: "leader-fixed",
role: "leader"
},
policy: DEFAULT_TEAM_TRANSPORT_POLICY,
governance: DEFAULT_TEAM_GOVERNANCE,
permissions_snapshot: permissionsSnapshot,
tmux_session: sessionName2,
worker_count: teamConfig.worker_count,
workers: workersInfo,
next_task_id: teamConfig.next_task_id,
created_at: teamConfig.created_at,
leader_cwd: leaderCwd,
team_state_root: teamConfig.team_state_root,
workspace_mode: teamConfig.workspace_mode,
leader_pane_id: leaderPaneId,
hud_pane_id: null,
resize_hook_name: null,
resize_hook_target: null,
next_worker_index: teamConfig.next_worker_index
};
await writeFile5(absPath(leaderCwd, TeamPaths.manifest(sanitized)), JSON.stringify(teamManifest, null, 2), "utf-8");
const initialStartupAllocations = [];
const seenStartupWorkers = /* @__PURE__ */ new Set();
for (const decision of startupAllocations) {
if (seenStartupWorkers.has(decision.workerName)) continue;
initialStartupAllocations.push(decision);
seenStartupWorkers.add(decision.workerName);
if (initialStartupAllocations.length >= config.workerCount) break;
}
for (const decision of initialStartupAllocations) {
const wName = decision.workerName;
const workerIndex = Number.parseInt(wName.replace("worker-", ""), 10) - 1;
const taskId = String(decision.taskIndex + 1);
const task = config.tasks[decision.taskIndex];
if (!task || workerIndex < 0) continue;
const workerLaunch = await spawnV2Worker({
sessionName: sessionName2,
leaderPaneId,
existingWorkerPaneIds: workerPaneIds,
teamName: sanitized,
workerName: wName,
workerIndex,
agentType: agentTypes[workerIndex % agentTypes.length] ?? agentTypes[0] ?? "claude",
task,
taskId,
cwd: leaderCwd,
resolvedBinaryPaths
});
if (workerLaunch.paneId) {
workerPaneIds.push(workerLaunch.paneId);
const workerInfo = workersInfo[workerIndex];
if (workerInfo) {
workerInfo.pane_id = workerLaunch.paneId;
workerInfo.assigned_tasks = workerLaunch.startupAssigned ? [taskId] : [];
}
}
if (workerLaunch.startupFailureReason) {
const logEventFailure2 = createSwallowedErrorLogger(
"team.runtime-v2.startTeamV2 appendTeamEvent failed"
);
appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
reason: `startup_manual_intervention_required:${wName}:${workerLaunch.startupFailureReason}`
}, leaderCwd).catch(logEventFailure2);
}
}
teamConfig.workers = workersInfo;
await saveTeamConfig(teamConfig, leaderCwd);
const logEventFailure = createSwallowedErrorLogger(
"team.runtime-v2.startTeamV2 appendTeamEvent failed"
);
appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
reason: `start_team_v2: workers=${config.workerCount} tasks=${config.tasks.length} panes=${workerPaneIds.length}`
}, leaderCwd).catch(logEventFailure);
return {
teamName: sanitized,
sanitizedName: sanitized,
sessionName: sessionName2,
config: teamConfig,
cwd: leaderCwd,
ownsWindow
};
}
async function writeWatchdogFailedMarker(teamName, cwd, reason) {
const { writeFile: writeFile6 } = await import("fs/promises");
const marker = {
failedAt: Date.now(),
reason,
writtenBy: "runtime-v2"
};
const root = absPath(cwd, TeamPaths.root(sanitizeTeamName(teamName)));
const markerPath = join18(root, "watchdog-failed.json");
await mkdir7(root, { recursive: true });
await writeFile6(markerPath, JSON.stringify(marker, null, 2), "utf-8");
}
async function requeueDeadWorkerTasks(teamName, deadWorkerNames, cwd) {
const logEventFailure = createSwallowedErrorLogger(
"team.runtime-v2.requeueDeadWorkerTasks appendTeamEvent failed"
);
const sanitized = sanitizeTeamName(teamName);
const tasks = await listTasksFromFiles(sanitized, cwd);
const requeued = [];
const deadSet = new Set(deadWorkerNames);
for (const task of tasks) {
if (task.status !== "in_progress") continue;
if (!task.owner || !deadSet.has(task.owner)) continue;
const sidecarPath = absPath(cwd, `${TeamPaths.tasks(sanitized)}/${task.id}.failure.json`);
const sidecar = {
taskId: task.id,
lastError: `worker_dead:${task.owner}`,
retryCount: 0,
lastFailedAt: (/* @__PURE__ */ new Date()).toISOString()
};
const { writeFile: writeFile6 } = await import("fs/promises");
await mkdir7(absPath(cwd, TeamPaths.tasks(sanitized)), { recursive: true });
await writeFile6(sidecarPath, JSON.stringify(sidecar, null, 2), "utf-8");
const taskPath2 = absPath(cwd, TeamPaths.taskFile(sanitized, task.id));
try {
const { readFileSync: readFileSync11, writeFileSync: writeFileSync3 } = await import("fs");
const { withFileLockSync: withFileLockSync2 } = await Promise.resolve().then(() => (init_file_lock(), file_lock_exports));
withFileLockSync2(taskPath2 + ".lock", () => {
const raw = readFileSync11(taskPath2, "utf-8");
const taskData = JSON.parse(raw);
if (taskData.status === "in_progress") {
taskData.status = "pending";
taskData.owner = void 0;
taskData.claim = void 0;
writeFileSync3(taskPath2, JSON.stringify(taskData, null, 2), "utf-8");
requeued.push(task.id);
}
});
} catch {
}
await appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
task_id: task.id,
reason: `requeue_dead_worker:${task.owner}`
}, cwd).catch(logEventFailure);
}
return requeued;
}
async function monitorTeamV2(teamName, cwd) {
const monitorStartMs = performance.now();
const sanitized = sanitizeTeamName(teamName);
const config = await readTeamConfig(sanitized, cwd);
if (!config) return null;
const previousSnapshot = await readMonitorSnapshot(sanitized, cwd);
const listTasksStartMs = performance.now();
const allTasks = await listTasksFromFiles(sanitized, cwd);
const listTasksMs = performance.now() - listTasksStartMs;
const taskById = new Map(allTasks.map((task) => [task.id, task]));
const inProgressByOwner = /* @__PURE__ */ new Map();
for (const task of allTasks) {
if (task.status !== "in_progress" || !task.owner) continue;
const existing = inProgressByOwner.get(task.owner) || [];
existing.push(task);
inProgressByOwner.set(task.owner, existing);
}
const workers = [];
const deadWorkers = [];
const nonReportingWorkers = [];
const recommendations = [];
const workerScanStartMs = performance.now();
const workerSignals = await Promise.all(
config.workers.map(async (worker) => {
const alive = await isWorkerPaneAlive(worker.pane_id);
const [status, heartbeat, paneCapture] = await Promise.all([
readWorkerStatus(sanitized, worker.name, cwd),
readWorkerHeartbeat(sanitized, worker.name, cwd),
alive ? captureWorkerPane(worker.pane_id) : Promise.resolve("")
]);
return { worker, alive, status, heartbeat, paneCapture };
})
);
const workerScanMs = performance.now() - workerScanStartMs;
for (const { worker: w, alive, status, heartbeat, paneCapture } of workerSignals) {
const currentTask = status.current_task_id ? taskById.get(status.current_task_id) ?? null : null;
const outstandingTask = currentTask ?? findOutstandingWorkerTask(w, taskById, inProgressByOwner);
const expectedTaskId = status.current_task_id ?? outstandingTask?.id ?? w.assigned_tasks[0] ?? "";
const previousTurns = previousSnapshot ? previousSnapshot.workerTurnCountByName[w.name] ?? 0 : null;
const previousTaskId = previousSnapshot?.workerTaskIdByName[w.name] ?? "";
const currentTaskId = status.current_task_id ?? "";
const turnsWithoutProgress = heartbeat && previousTurns !== null && status.state === "working" && currentTask && (currentTask.status === "pending" || currentTask.status === "in_progress") && currentTaskId !== "" && previousTaskId === currentTaskId ? Math.max(0, heartbeat.turn_count - previousTurns) : 0;
workers.push({
name: w.name,
alive,
status,
heartbeat,
assignedTasks: w.assigned_tasks,
turnsWithoutProgress
});
if (!alive) {
deadWorkers.push(w.name);
const deadWorkerTasks = inProgressByOwner.get(w.name) || [];
for (const t of deadWorkerTasks) {
recommendations.push(`Reassign task-${t.id} from dead ${w.name}`);
}
}
const paneSuggestsIdle = alive && paneLooksReady(paneCapture) && !paneHasActiveTask(paneCapture);
const statusFresh = isFreshTimestamp(status.updated_at);
const heartbeatFresh = isFreshTimestamp(heartbeat?.last_turn_at);
const hasWorkStartEvidence = expectedTaskId !== "" && hasWorkerStatusProgress(status, expectedTaskId);
const missingDependencyIds = outstandingTask ? getMissingDependencyIds(outstandingTask, taskById) : [];
let stallReason = null;
if (paneSuggestsIdle && missingDependencyIds.length > 0) {
stallReason = "missing_dependency";
} else if (paneSuggestsIdle && expectedTaskId !== "" && !hasWorkStartEvidence) {
stallReason = "no_work_start_evidence";
} else if (paneSuggestsIdle && expectedTaskId !== "" && (!statusFresh || !heartbeatFresh)) {
stallReason = "stale_or_missing_worker_reports";
} else if (paneSuggestsIdle && turnsWithoutProgress > 5) {
stallReason = "no_meaningful_turn_progress";
}
if (stallReason) {
nonReportingWorkers.push(w.name);
if (stallReason === "missing_dependency") {
recommendations.push(
`Investigate ${w.name}: task-${outstandingTask?.id ?? expectedTaskId} is blocked by missing task ids [${missingDependencyIds.join(", ")}]; pane is idle at prompt`
);
} else if (stallReason === "no_work_start_evidence") {
recommendations.push(`Investigate ${w.name}: assigned work but no work-start evidence; pane is idle at prompt`);
} else if (stallReason === "stale_or_missing_worker_reports") {
recommendations.push(`Investigate ${w.name}: pane is idle while status/heartbeat are stale or missing`);
} else {
recommendations.push(`Investigate ${w.name}: no meaningful turn progress and pane is idle at prompt`);
}
}
}
const taskCounts = {
total: allTasks.length,
pending: allTasks.filter((t) => t.status === "pending").length,
blocked: allTasks.filter((t) => t.status === "blocked").length,
in_progress: allTasks.filter((t) => t.status === "in_progress").length,
completed: allTasks.filter((t) => t.status === "completed").length,
failed: allTasks.filter((t) => t.status === "failed").length
};
const allTasksTerminal = taskCounts.pending === 0 && taskCounts.blocked === 0 && taskCounts.in_progress === 0;
for (const task of allTasks) {
const missingDependencyIds = getMissingDependencyIds(task, taskById);
if (missingDependencyIds.length === 0) {
continue;
}
recommendations.push(
`Investigate task-${task.id}: depends on missing task ids [${missingDependencyIds.join(", ")}]`
);
}
const phase = inferPhase(allTasks.map((t) => ({
status: t.status,
metadata: void 0
})));
await emitMonitorDerivedEvents(
sanitized,
allTasks,
workers.map((w) => ({ name: w.name, alive: w.alive, status: w.status })),
previousSnapshot,
cwd
);
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
const totalMs = performance.now() - monitorStartMs;
await writeMonitorSnapshot(sanitized, {
taskStatusById: Object.fromEntries(allTasks.map((t) => [t.id, t.status])),
workerAliveByName: Object.fromEntries(workers.map((w) => [w.name, w.alive])),
workerStateByName: Object.fromEntries(workers.map((w) => [w.name, w.status.state])),
workerTurnCountByName: Object.fromEntries(workers.map((w) => [w.name, w.heartbeat?.turn_count ?? 0])),
workerTaskIdByName: Object.fromEntries(workers.map((w) => [w.name, w.status.current_task_id ?? ""])),
mailboxNotifiedByMessageId: previousSnapshot?.mailboxNotifiedByMessageId ?? {},
completedEventTaskIds: previousSnapshot?.completedEventTaskIds ?? {},
monitorTimings: {
list_tasks_ms: Number(listTasksMs.toFixed(2)),
worker_scan_ms: Number(workerScanMs.toFixed(2)),
mailbox_delivery_ms: 0,
total_ms: Number(totalMs.toFixed(2)),
updated_at: updatedAt
}
}, cwd);
return {
teamName: sanitized,
phase,
workers,
tasks: {
...taskCounts,
items: allTasks
},
allTasksTerminal,
deadWorkers,
nonReportingWorkers,
recommendations,
performance: {
list_tasks_ms: Number(listTasksMs.toFixed(2)),
worker_scan_ms: Number(workerScanMs.toFixed(2)),
total_ms: Number(totalMs.toFixed(2)),
updated_at: updatedAt
}
};
}
async function shutdownTeamV2(teamName, cwd, options = {}) {
const logEventFailure = createSwallowedErrorLogger(
"team.runtime-v2.shutdownTeamV2 appendTeamEvent failed"
);
const force = options.force === true;
const ralph = options.ralph === true;
const timeoutMs = options.timeoutMs ?? 15e3;
const sanitized = sanitizeTeamName(teamName);
const config = await readTeamConfig(sanitized, cwd);
if (!config) {
await cleanupTeamState(sanitized, cwd);
return;
}
if (!force) {
const allTasks = await listTasksFromFiles(sanitized, cwd);
const governance = getConfigGovernance(config);
const gate = {
total: allTasks.length,
pending: allTasks.filter((t) => t.status === "pending").length,
blocked: allTasks.filter((t) => t.status === "blocked").length,
in_progress: allTasks.filter((t) => t.status === "in_progress").length,
completed: allTasks.filter((t) => t.status === "completed").length,
failed: allTasks.filter((t) => t.status === "failed").length,
allowed: false
};
gate.allowed = gate.pending === 0 && gate.blocked === 0 && gate.in_progress === 0 && gate.failed === 0;
await appendTeamEvent(sanitized, {
type: "shutdown_gate",
worker: "leader-fixed",
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" : ""}`
}, cwd).catch(logEventFailure);
if (!gate.allowed) {
const hasActiveWork = gate.pending > 0 || gate.blocked > 0 || gate.in_progress > 0;
if (!governance.cleanup_requires_all_workers_inactive) {
await appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
reason: `cleanup_override_bypassed:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`
}, cwd).catch(logEventFailure);
} else if (ralph && !hasActiveWork) {
await appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
reason: `gate_bypassed:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`
}, cwd).catch(logEventFailure);
} else {
throw new Error(
`shutdown_gate_blocked:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`
);
}
}
}
if (force) {
await appendTeamEvent(sanitized, {
type: "shutdown_gate_forced",
worker: "leader-fixed",
reason: "force_bypass"
}, cwd).catch(logEventFailure);
}
const shutdownRequestTimes = /* @__PURE__ */ new Map();
for (const w of config.workers) {
try {
const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
await writeShutdownRequest(sanitized, w.name, "leader-fixed", cwd);
shutdownRequestTimes.set(w.name, requestedAt);
const shutdownInbox = `# Shutdown Request
All tasks are complete. Please wrap up and respond with a shutdown acknowledgement.
Write your ack to: ${TeamPaths.shutdownAck(sanitized, w.name)}
Format: {"status":"accept","reason":"ok","updated_at":"<iso>"}
Then exit your session.
`;
await writeWorkerInbox(sanitized, w.name, shutdownInbox, cwd);
} catch (err) {
process.stderr.write(`[team/runtime-v2] shutdown request failed for ${w.name}: ${err}
`);
}
}
const deadline = Date.now() + timeoutMs;
const rejected = [];
const ackedWorkers = /* @__PURE__ */ new Set();
while (Date.now() < deadline) {
for (const w of config.workers) {
if (ackedWorkers.has(w.name)) continue;
const ack = await readShutdownAck(sanitized, w.name, cwd, shutdownRequestTimes.get(w.name));
if (ack) {
ackedWorkers.add(w.name);
await appendTeamEvent(sanitized, {
type: "shutdown_ack",
worker: w.name,
reason: ack.status === "reject" ? `reject:${ack.reason || "no_reason"}` : "accept"
}, cwd).catch(logEventFailure);
if (ack.status === "reject") {
rejected.push({ worker: w.name, reason: ack.reason || "no_reason" });
}
}
}
if (rejected.length > 0 && !force) {
const detail = rejected.map((r) => `${r.worker}:${r.reason}`).join(",");
throw new Error(`shutdown_rejected:${detail}`);
}
const allDone = config.workers.every((w) => ackedWorkers.has(w.name));
if (allDone) break;
await new Promise((r) => setTimeout(r, 2e3));
}
try {
const { killWorkerPanes: killWorkerPanes2, killTeamSession: killTeamSession2, resolveSplitPaneWorkerPaneIds: resolveSplitPaneWorkerPaneIds2 } = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
const recordedWorkerPaneIds = config.workers.map((w) => w.pane_id).filter((p) => typeof p === "string" && p.trim().length > 0);
const ownsWindow = config.tmux_window_owned === true;
const workerPaneIds = ownsWindow ? recordedWorkerPaneIds : await resolveSplitPaneWorkerPaneIds2(
config.tmux_session,
recordedWorkerPaneIds,
config.leader_pane_id ?? void 0
);
await killWorkerPanes2({
paneIds: workerPaneIds,
leaderPaneId: config.leader_pane_id ?? void 0,
teamName: sanitized,
cwd
});
if (config.tmux_session && (ownsWindow || !config.tmux_session.includes(":"))) {
const sessionMode = ownsWindow ? config.tmux_session.includes(":") ? "dedicated-window" : "detached-session" : "detached-session";
await killTeamSession2(
config.tmux_session,
workerPaneIds,
config.leader_pane_id ?? void 0,
{ sessionMode }
);
}
} catch (err) {
process.stderr.write(`[team/runtime-v2] tmux cleanup: ${err}
`);
}
if (ralph) {
const finalTasks = await listTasksFromFiles(sanitized, cwd).catch(() => []);
const completed = finalTasks.filter((t) => t.status === "completed").length;
const failed = finalTasks.filter((t) => t.status === "failed").length;
const pending = finalTasks.filter((t) => t.status === "pending").length;
await appendTeamEvent(sanitized, {
type: "team_leader_nudge",
worker: "leader-fixed",
reason: `ralph_cleanup_summary: total=${finalTasks.length} completed=${completed} failed=${failed} pending=${pending} force=${force}`
}, cwd).catch(logEventFailure);
}
try {
cleanupTeamWorktrees(sanitized, cwd);
} catch (err) {
process.stderr.write(`[team/runtime-v2] worktree cleanup: ${err}
`);
}
await cleanupTeamState(sanitized, cwd);
}
async function resumeTeamV2(teamName, cwd) {
const sanitized = sanitizeTeamName(teamName);
const config = await readTeamConfig(sanitized, cwd);
if (!config) return null;
try {
const sessionName2 = config.tmux_session || `omc-team-${sanitized}`;
await tmuxExecAsync(["has-session", "-t", sessionName2.split(":")[0]]);
return {
teamName: sanitized,
sanitizedName: sanitized,
sessionName: sessionName2,
ownsWindow: config.tmux_window_owned === true,
config,
cwd
};
} catch {
return null;
}
}
async function findActiveTeamsV2(cwd) {
const root = join18(cwd, ".omc", "state", "team");
if (!existsSync15(root)) return [];
const entries = await readdir2(root, { withFileTypes: true });
const active = [];
for (const e of entries) {
if (!e.isDirectory()) continue;
const teamName = e.name;
const config = await readTeamConfig(teamName, cwd);
if (config) {
active.push(teamName);
}
}
return active;
}
var MONITOR_SIGNAL_STALE_MS, CIRCUIT_BREAKER_THRESHOLD, CircuitBreakerV2;
var init_runtime_v2 = __esm({
"src/team/runtime-v2.ts"() {
"use strict";
init_tmux_utils();
init_state_paths();
init_allocation_policy();
init_monitor();
init_events();
init_governance();
init_phase_controller();
init_team_name();
init_model_contract();
init_tmux_session();
init_worker_bootstrap();
init_mcp_comm();
init_git_worktree();
init_omc_cli_rendering();
init_swallowed_error();
MONITOR_SIGNAL_STALE_MS = 3e4;
CIRCUIT_BREAKER_THRESHOLD = 3;
CircuitBreakerV2 = class {
constructor(teamName, cwd, threshold = CIRCUIT_BREAKER_THRESHOLD) {
this.teamName = teamName;
this.cwd = cwd;
this.threshold = threshold;
}
consecutiveFailures = 0;
tripped = false;
recordSuccess() {
this.consecutiveFailures = 0;
}
async recordFailure(reason) {
this.consecutiveFailures++;
if (this.consecutiveFailures >= this.threshold && !this.tripped) {
this.tripped = true;
await writeWatchdogFailedMarker(this.teamName, this.cwd, reason);
return true;
}
return false;
}
isTripped() {
return this.tripped;
}
};
}
});
// src/cli/team.ts
import { randomUUID as randomUUID6 } from "crypto";
import { spawn } from "child_process";
import { existsSync as existsSync17, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "fs";
import { readFile as readFile10, rm as rm4 } from "fs/promises";
import { dirname as dirname13, join as join20 } from "path";
import { fileURLToPath as fileURLToPath3 } from "url";
// src/team/api-interop.ts
init_contracts();
init_team_ops();
init_mcp_comm();
init_tmux_session();
init_dispatch_queue();
init_worker_bootstrap();
import { existsSync as existsSync16, readFileSync as readFileSync9 } from "node:fs";
import { dirname as dirname12, join as join19, resolve as resolvePath } from "node:path";
// src/team/runtime.ts
init_tmux_utils();
init_model_contract();
init_team_name();
init_tmux_session();
init_worker_bootstrap();
init_git_worktree();
import { mkdir as mkdir4, writeFile as writeFile4, readFile as readFile6, rm as rm3, rename as rename2 } from "fs/promises";
import { join as join17 } from "path";
import { existsSync as existsSync12 } from "fs";
// src/team/task-file-ops.ts
init_config_dir();
init_tmux_session();
init_fs_utils();
init_platform();
init_state_paths();
import { readFileSync as readFileSync8, readdirSync as readdirSync3, existsSync as existsSync11, openSync as openSync4, closeSync as closeSync4, unlinkSync as unlinkSync4, writeSync as writeSync4, statSync as statSync3, constants as fsConstants2 } from "fs";
import { join as join16 } from "path";
// src/team/runtime.ts
function stateRoot(cwd, teamName) {
validateTeamName(teamName);
return join17(cwd, `.omc/state/team/${teamName}`);
}
async function writeJson(filePath, data) {
await mkdir4(join17(filePath, ".."), { recursive: true });
await writeFile4(filePath, JSON.stringify(data, null, 2), "utf-8");
}
async function readJsonSafe2(filePath) {
const isDoneSignalPath = filePath.endsWith("done.json");
const maxAttempts = isDoneSignalPath ? 4 : 1;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const content = await readFile6(filePath, "utf-8");
try {
return JSON.parse(content);
} catch {
if (!isDoneSignalPath || attempt === maxAttempts) {
return null;
}
}
} catch (error) {
const isMissingDoneSignal = isDoneSignalPath && typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
if (isMissingDoneSignal) {
return null;
}
if (!isDoneSignalPath || attempt === maxAttempts) {
return null;
}
}
await new Promise((resolve4) => setTimeout(resolve4, 25));
}
return null;
}
function taskPath(root, taskId) {
return join17(root, "tasks", `${taskId}.json`);
}
async function readTask(root, taskId) {
return readJsonSafe2(taskPath(root, taskId));
}
async function monitorTeam(teamName, cwd, workerPaneIds) {
validateTeamName(teamName);
const monitorStartedAt = Date.now();
const root = stateRoot(cwd, teamName);
const taskScanStartedAt = Date.now();
const taskCounts = { pending: 0, inProgress: 0, completed: 0, failed: 0 };
try {
const { readdir: readdir3 } = await import("fs/promises");
const taskFiles = await readdir3(join17(root, "tasks"));
for (const f of taskFiles.filter((f2) => f2.endsWith(".json"))) {
const task = await readJsonSafe2(join17(root, "tasks", f));
if (task?.status === "pending") taskCounts.pending++;
else if (task?.status === "in_progress") taskCounts.inProgress++;
else if (task?.status === "completed") taskCounts.completed++;
else if (task?.status === "failed") taskCounts.failed++;
}
} catch {
}
const listTasksMs = Date.now() - taskScanStartedAt;
const workerScanStartedAt = Date.now();
const workers = [];
const deadWorkers = [];
for (let i = 0; i < workerPaneIds.length; i++) {
const wName = `worker-${i + 1}`;
const paneId = workerPaneIds[i];
const alive = await isWorkerAlive(paneId);
const heartbeatPath = join17(root, "workers", wName, "heartbeat.json");
const heartbeat = await readJsonSafe2(heartbeatPath);
let stalled = false;
if (heartbeat?.updatedAt) {
const age = Date.now() - new Date(heartbeat.updatedAt).getTime();
stalled = age > 6e4;
}
const status = {
workerName: wName,
alive,
paneId,
currentTaskId: heartbeat?.currentTaskId,
lastHeartbeat: heartbeat?.updatedAt,
stalled
};
workers.push(status);
if (!alive) deadWorkers.push(wName);
}
const workerScanMs = Date.now() - workerScanStartedAt;
let phase = "executing";
if (taskCounts.inProgress === 0 && taskCounts.pending > 0 && taskCounts.completed === 0) {
phase = "planning";
} else if (taskCounts.failed > 0 && taskCounts.pending === 0 && taskCounts.inProgress === 0) {
phase = "fixing";
} else if (taskCounts.completed > 0 && taskCounts.pending === 0 && taskCounts.inProgress === 0 && taskCounts.failed === 0) {
phase = "completed";
}
return {
teamName,
phase,
workers,
taskCounts,
deadWorkers,
monitorPerformance: {
listTasksMs,
workerScanMs,
totalMs: Date.now() - monitorStartedAt
}
};
}
async function shutdownTeam(teamName, sessionName2, cwd, timeoutMs = 3e4, workerPaneIds, leaderPaneId, ownsWindow) {
const root = stateRoot(cwd, teamName);
await writeJson(join17(root, "shutdown.json"), {
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
teamName
});
const configData = await readJsonSafe2(join17(root, "config.json"));
const CLI_AGENT_TYPES = /* @__PURE__ */ new Set(["claude", "codex", "gemini"]);
const agentTypes = configData?.agentTypes ?? [];
const isCliWorkerTeam = agentTypes.length > 0 && agentTypes.every((t) => CLI_AGENT_TYPES.has(t));
if (!isCliWorkerTeam) {
const deadline = Date.now() + timeoutMs;
const workerCount = configData?.workerCount ?? 0;
const expectedAcks = Array.from({ length: workerCount }, (_, i) => `worker-${i + 1}`);
while (Date.now() < deadline && expectedAcks.length > 0) {
for (const wName of [...expectedAcks]) {
const ackPath = join17(root, "workers", wName, "shutdown-ack.json");
if (existsSync12(ackPath)) {
expectedAcks.splice(expectedAcks.indexOf(wName), 1);
}
}
if (expectedAcks.length > 0) {
await new Promise((r) => setTimeout(r, 500));
}
}
}
const sessionMode = ownsWindow ?? Boolean(configData?.tmuxOwnsWindow) ? sessionName2.includes(":") ? "dedicated-window" : "detached-session" : "split-pane";
const effectiveWorkerPaneIds = sessionMode === "split-pane" ? await resolveSplitPaneWorkerPaneIds(sessionName2, workerPaneIds, leaderPaneId) : workerPaneIds;
await killTeamSession(sessionName2, effectiveWorkerPaneIds, leaderPaneId, { sessionMode });
try {
cleanupTeamWorktrees(teamName, cwd);
} catch {
}
try {
await rm3(root, { recursive: true, force: true });
} catch {
}
}
async function resumeTeam(teamName, cwd) {
const root = stateRoot(cwd, teamName);
const configData = await readJsonSafe2(join17(root, "config.json"));
if (!configData) return null;
const sName = configData.tmuxSession || `omc-team-${teamName}`;
try {
await tmuxExecAsync(["has-session", "-t", sName.split(":")[0]]);
} catch {
return null;
}
const paneTarget = sName.includes(":") ? sName : sName.split(":")[0];
const panesResult = await tmuxExecAsync([
"list-panes",
"-t",
paneTarget,
"-F",
"#{pane_id}"
]);
const allPanes = panesResult.stdout.trim().split("\n").filter(Boolean);
const workerPaneIds = allPanes.slice(1);
const workerNames = workerPaneIds.map((_, i) => `worker-${i + 1}`);
const paneByWorker = new Map(
workerNames.map((wName, i) => [wName, workerPaneIds[i] ?? ""])
);
const activeWorkers = /* @__PURE__ */ new Map();
for (let i = 0; i < configData.tasks.length; i++) {
const taskId = String(i + 1);
const task = await readTask(root, taskId);
if (task?.status === "in_progress" && task.owner) {
const paneId = paneByWorker.get(task.owner) ?? "";
activeWorkers.set(task.owner, {
paneId,
taskId,
spawnedAt: task.assignedAt ? new Date(task.assignedAt).getTime() : Date.now()
});
}
}
return {
teamName,
sessionName: sName,
leaderPaneId: configData.leaderPaneId ?? allPanes[0] ?? "",
config: configData,
workerNames,
workerPaneIds,
activeWorkers,
cwd,
ownsWindow: Boolean(configData.tmuxOwnsWindow)
};
}
// src/team/api-interop.ts
init_runtime_v2();
init_swallowed_error();
var TEAM_UPDATE_TASK_MUTABLE_FIELDS = /* @__PURE__ */ new Set(["subject", "description", "blocked_by", "requires_code_change"]);
var TEAM_UPDATE_TASK_REQUEST_FIELDS = /* @__PURE__ */ new Set(["team_name", "task_id", "workingDirectory", ...TEAM_UPDATE_TASK_MUTABLE_FIELDS]);
var TEAM_API_OPERATIONS = [
"send-message",
"broadcast",
"mailbox-list",
"mailbox-mark-delivered",
"mailbox-mark-notified",
"create-task",
"read-task",
"list-tasks",
"update-task",
"claim-task",
"transition-task-status",
"release-task-claim",
"read-config",
"read-manifest",
"read-worker-status",
"read-worker-heartbeat",
"update-worker-heartbeat",
"write-worker-inbox",
"write-worker-identity",
"append-event",
"get-summary",
"cleanup",
"write-shutdown-request",
"read-shutdown-ack",
"read-monitor-snapshot",
"write-monitor-snapshot",
"read-task-approval",
"write-task-approval",
"orphan-cleanup"
];
function isFiniteInteger(value) {
return typeof value === "number" && Number.isInteger(value) && Number.isFinite(value);
}
function parseValidatedTaskIdArray(value, fieldName) {
if (!Array.isArray(value)) {
throw new Error(`${fieldName} must be an array of task IDs (strings)`);
}
const taskIds = [];
for (const item of value) {
if (typeof item !== "string") {
throw new Error(`${fieldName} entries must be strings`);
}
const normalized = item.trim();
if (!TASK_ID_SAFE_PATTERN.test(normalized)) {
throw new Error(`${fieldName} contains invalid task ID: "${item}"`);
}
taskIds.push(normalized);
}
return taskIds;
}
function teamStateExists(teamName, candidateCwd) {
if (!TEAM_NAME_SAFE_PATTERN.test(teamName)) return false;
const teamRoot = join19(candidateCwd, ".omc", "state", "team", teamName);
return existsSync16(join19(teamRoot, "config.json")) || existsSync16(join19(teamRoot, "tasks")) || existsSync16(teamRoot);
}
function parseTeamWorkerEnv(raw) {
if (typeof raw !== "string" || raw.trim() === "") return null;
const match = /^([a-z0-9][a-z0-9-]{0,29})\/(worker-\d+)$/.exec(raw.trim());
if (!match) return null;
return { teamName: match[1], workerName: match[2] };
}
function parseTeamWorkerContextFromEnv(env = process.env) {
return parseTeamWorkerEnv(env.OMC_TEAM_WORKER) ?? parseTeamWorkerEnv(env.OMX_TEAM_WORKER);
}
function readTeamStateRootFromEnv(env = process.env) {
const candidate = typeof env.OMC_TEAM_STATE_ROOT === "string" && env.OMC_TEAM_STATE_ROOT.trim() !== "" ? env.OMC_TEAM_STATE_ROOT.trim() : typeof env.OMX_TEAM_STATE_ROOT === "string" && env.OMX_TEAM_STATE_ROOT.trim() !== "" ? env.OMX_TEAM_STATE_ROOT.trim() : "";
return candidate || null;
}
function isRuntimeV2Config(config) {
return !!config && typeof config === "object" && Array.isArray(config.workers);
}
function isLegacyRuntimeConfig(config) {
return !!config && typeof config === "object" && Array.isArray(config.agentTypes);
}
async function executeTeamCleanupViaRuntime(teamName, cwd) {
const config = await teamReadConfig(teamName, cwd);
if (!config) {
await teamCleanup(teamName, cwd);
return;
}
if (isRuntimeV2Config(config)) {
await shutdownTeamV2(teamName, cwd);
return;
}
if (isLegacyRuntimeConfig(config)) {
const legacyConfig = config;
const sessionName2 = typeof legacyConfig.tmuxSession === "string" && legacyConfig.tmuxSession.trim() !== "" ? legacyConfig.tmuxSession.trim() : `omc-team-${teamName}`;
const leaderPaneId = typeof legacyConfig.leaderPaneId === "string" && legacyConfig.leaderPaneId.trim() !== "" ? legacyConfig.leaderPaneId.trim() : void 0;
await shutdownTeam(teamName, sessionName2, cwd, 3e4, void 0, leaderPaneId, legacyConfig.tmuxOwnsWindow === true);
return;
}
await teamCleanup(teamName, cwd);
}
function readTeamStateRootFromFile(path4) {
if (!existsSync16(path4)) return null;
try {
const parsed = JSON.parse(readFileSync9(path4, "utf8"));
return typeof parsed.team_state_root === "string" && parsed.team_state_root.trim() !== "" ? parsed.team_state_root.trim() : null;
} catch {
return null;
}
}
function stateRootToWorkingDirectory(stateRoot2) {
const absolute = resolvePath(stateRoot2);
const normalized = absolute.replaceAll("\\", "/");
for (const marker of ["/.omc/state/team/", "/.omx/state/team/"]) {
const idx = normalized.lastIndexOf(marker);
if (idx >= 0) {
const workspaceRoot = absolute.slice(0, idx);
if (workspaceRoot && workspaceRoot !== "/") return workspaceRoot;
return dirname12(dirname12(dirname12(dirname12(absolute))));
}
}
for (const marker of ["/.omc/state", "/.omx/state"]) {
const idx = normalized.lastIndexOf(marker);
if (idx >= 0) {
const workspaceRoot = absolute.slice(0, idx);
if (workspaceRoot && workspaceRoot !== "/") return workspaceRoot;
return dirname12(dirname12(absolute));
}
}
return dirname12(dirname12(absolute));
}
function resolveTeamWorkingDirectoryFromMetadata(teamName, candidateCwd, workerContext) {
const teamRoot = join19(candidateCwd, ".omc", "state", "team", teamName);
if (!existsSync16(teamRoot)) return null;
if (workerContext?.teamName === teamName) {
const workerRoot = readTeamStateRootFromFile(join19(teamRoot, "workers", workerContext.workerName, "identity.json"));
if (workerRoot) return stateRootToWorkingDirectory(workerRoot);
}
const fromConfig = readTeamStateRootFromFile(join19(teamRoot, "config.json"));
if (fromConfig) return stateRootToWorkingDirectory(fromConfig);
for (const manifestName of ["manifest.json", "manifest.v2.json"]) {
const fromManifest = readTeamStateRootFromFile(join19(teamRoot, manifestName));
if (fromManifest) return stateRootToWorkingDirectory(fromManifest);
}
return null;
}
function resolveTeamWorkingDirectory(teamName, preferredCwd) {
const normalizedTeamName = String(teamName || "").trim();
if (!normalizedTeamName) return preferredCwd;
const envTeamStateRoot = readTeamStateRootFromEnv();
if (typeof envTeamStateRoot === "string" && envTeamStateRoot.trim() !== "") {
return stateRootToWorkingDirectory(envTeamStateRoot.trim());
}
const seeds = [];
for (const seed of [preferredCwd, process.cwd()]) {
if (typeof seed !== "string" || seed.trim() === "") continue;
if (!seeds.includes(seed)) seeds.push(seed);
}
const workerContext = parseTeamWorkerContextFromEnv();
for (const seed of seeds) {
let cursor = seed;
while (cursor) {
if (teamStateExists(normalizedTeamName, cursor)) {
return resolveTeamWorkingDirectoryFromMetadata(normalizedTeamName, cursor, workerContext) ?? cursor;
}
const parent = dirname12(cursor);
if (!parent || parent === cursor) break;
cursor = parent;
}
}
return preferredCwd;
}
function normalizeTeamName(toolOrOperationName) {
const normalized = toolOrOperationName.trim().toLowerCase();
const withoutPrefix = normalized.startsWith("team_") ? normalized.slice("team_".length) : normalized;
return withoutPrefix.replaceAll("_", "-");
}
function resolveTeamApiOperation(name) {
const normalized = normalizeTeamName(name);
return TEAM_API_OPERATIONS.includes(normalized) ? normalized : null;
}
var QUEUED_FOR_HOOK_DISPATCH_REASON = "queued_for_hook_dispatch";
var LEADER_PANE_MISSING_MAILBOX_PERSISTED_REASON = "leader_pane_missing_mailbox_persisted";
var WORKTREE_TRIGGER_STATE_ROOT = "$OMC_TEAM_STATE_ROOT";
function resolveInstructionStateRoot(worktreePath) {
return worktreePath ? WORKTREE_TRIGGER_STATE_ROOT : void 0;
}
function queuedForHookDispatch() {
return {
ok: true,
transport: "hook",
reason: QUEUED_FOR_HOOK_DISPATCH_REASON
};
}
async function notifyMailboxTarget(teamName, toWorker, triggerMessage, cwd) {
const config = await teamReadConfig(teamName, cwd);
if (!config) return queuedForHookDispatch();
const sessionName2 = typeof config.tmux_session === "string" ? config.tmux_session.trim() : "";
if (!sessionName2) return queuedForHookDispatch();
if (toWorker === "leader-fixed") {
const leaderPaneId = typeof config.leader_pane_id === "string" ? config.leader_pane_id.trim() : "";
if (!leaderPaneId) {
return {
ok: true,
transport: "mailbox",
reason: LEADER_PANE_MISSING_MAILBOX_PERSISTED_REASON
};
}
const injected = await injectToLeaderPane(sessionName2, leaderPaneId, triggerMessage);
return injected ? { ok: true, transport: "tmux_send_keys", reason: "leader_pane_notified" } : queuedForHookDispatch();
}
const workerPaneId = config.workers.find((worker) => worker.name === toWorker)?.pane_id?.trim();
if (!workerPaneId) return queuedForHookDispatch();
const notified = await sendToWorker(sessionName2, workerPaneId, triggerMessage);
return notified ? { ok: true, transport: "tmux_send_keys", reason: "worker_pane_notified" } : queuedForHookDispatch();
}
function findWorkerDispatchTarget(teamName, toWorker, cwd) {
return teamReadConfig(teamName, cwd).then((config) => {
const recipient = config?.workers.find((worker) => worker.name === toWorker);
return {
paneId: recipient?.pane_id,
workerIndex: recipient?.index,
instructionStateRoot: resolveInstructionStateRoot(recipient?.worktree_path)
};
});
}
async function findMailboxDispatchRequestId(teamName, workerName, messageId, cwd) {
const requests = await listDispatchRequests(
teamName,
cwd,
{ kind: "mailbox", to_worker: workerName }
);
const matching = requests.filter((request) => request.message_id === messageId).sort((left, right) => Date.parse(right.created_at) - Date.parse(left.created_at));
return matching[0]?.request_id ?? null;
}
async function syncMailboxDispatchNotified(teamName, workerName, messageId, cwd) {
const logDispatchSyncFailure = createSwallowedErrorLogger(
"team.api-interop syncMailboxDispatchNotified dispatch state sync failed"
);
const requestId = await findMailboxDispatchRequestId(teamName, workerName, messageId, cwd);
if (!requestId) return;
await markDispatchRequestNotified(
teamName,
requestId,
{ message_id: messageId, last_reason: "mailbox_mark_notified" },
cwd
).catch(logDispatchSyncFailure);
}
async function syncMailboxDispatchDelivered(teamName, workerName, messageId, cwd) {
const logDispatchSyncFailure = createSwallowedErrorLogger(
"team.api-interop syncMailboxDispatchDelivered dispatch state sync failed"
);
const requestId = await findMailboxDispatchRequestId(teamName, workerName, messageId, cwd);
if (!requestId) return;
await markDispatchRequestNotified(
teamName,
requestId,
{ message_id: messageId, last_reason: "mailbox_mark_delivered" },
cwd
).catch(logDispatchSyncFailure);
await markDispatchRequestDelivered(
teamName,
requestId,
{ message_id: messageId, last_reason: "mailbox_mark_delivered" },
cwd
).catch(logDispatchSyncFailure);
}
function validateCommonFields(args) {
const teamName = String(args.team_name || "").trim();
if (teamName && !TEAM_NAME_SAFE_PATTERN.test(teamName)) {
throw new Error(`Invalid team_name: "${teamName}". Must match /^[a-z0-9][a-z0-9-]{0,29}$/ (lowercase alphanumeric + hyphens, max 30 chars).`);
}
for (const workerField of ["worker", "from_worker", "to_worker"]) {
const workerVal = String(args[workerField] || "").trim();
if (workerVal && !WORKER_NAME_SAFE_PATTERN.test(workerVal)) {
throw new Error(`Invalid ${workerField}: "${workerVal}". Must match /^[a-z0-9][a-z0-9-]{0,63}$/ (lowercase alphanumeric + hyphens, max 64 chars).`);
}
}
const rawTaskId = String(args.task_id || "").trim();
if (rawTaskId && !TASK_ID_SAFE_PATTERN.test(rawTaskId)) {
throw new Error(`Invalid task_id: "${rawTaskId}". Must be a positive integer (digits only, max 20 digits).`);
}
}
async function executeTeamApiOperation(operation, args, fallbackCwd) {
try {
validateCommonFields(args);
const teamNameForCwd = String(args.team_name || "").trim();
const cwd = teamNameForCwd ? resolveTeamWorkingDirectory(teamNameForCwd, fallbackCwd) : fallbackCwd;
switch (operation) {
case "send-message": {
const teamName = String(args.team_name || "").trim();
const fromWorker = String(args.from_worker || "").trim();
const toWorker = String(args.to_worker || "").trim();
const body = String(args.body || "").trim();
if (!fromWorker) {
return { ok: false, operation, error: { code: "invalid_input", message: "from_worker is required. You must identify yourself." } };
}
if (!teamName || !toWorker || !body) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, from_worker, to_worker, body are required" } };
}
let message = null;
const target = await findWorkerDispatchTarget(teamName, toWorker, cwd);
await queueDirectMailboxMessage({
teamName,
fromWorker,
toWorker,
toWorkerIndex: target.workerIndex,
toPaneId: target.paneId,
body,
triggerMessage: generateMailboxTriggerMessage(teamName, toWorker, 1, target.instructionStateRoot),
cwd,
notify: ({ workerName }, triggerMessage) => notifyMailboxTarget(teamName, workerName, triggerMessage, cwd),
deps: {
sendDirectMessage: async (resolvedTeamName, resolvedFromWorker, resolvedToWorker, resolvedBody, resolvedCwd) => {
message = await teamSendMessage(resolvedTeamName, resolvedFromWorker, resolvedToWorker, resolvedBody, resolvedCwd);
return message;
},
broadcastMessage: teamBroadcast,
markMessageNotified: async (resolvedTeamName, workerName, messageId, resolvedCwd) => {
await teamMarkMessageNotified(resolvedTeamName, workerName, messageId, resolvedCwd);
}
}
});
return { ok: true, operation, data: { message } };
}
case "broadcast": {
const teamName = String(args.team_name || "").trim();
const fromWorker = String(args.from_worker || "").trim();
const body = String(args.body || "").trim();
if (!teamName || !fromWorker || !body) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, from_worker, body are required" } };
}
let messages = [];
const config = await teamReadConfig(teamName, cwd);
const recipients = (config?.workers ?? []).filter((worker) => worker.name !== fromWorker).map((worker) => ({
workerName: worker.name,
workerIndex: worker.index,
paneId: worker.pane_id,
instructionStateRoot: resolveInstructionStateRoot(worker.worktree_path)
}));
await queueBroadcastMailboxMessage({
teamName,
fromWorker,
recipients,
body,
cwd,
triggerFor: (workerName) => generateMailboxTriggerMessage(
teamName,
workerName,
1,
recipients.find((recipient) => recipient.workerName === workerName)?.instructionStateRoot
),
notify: ({ workerName }, triggerMessage) => notifyMailboxTarget(teamName, workerName, triggerMessage, cwd),
deps: {
sendDirectMessage: teamSendMessage,
broadcastMessage: async (resolvedTeamName, resolvedFromWorker, resolvedBody, resolvedCwd) => {
messages = await teamBroadcast(resolvedTeamName, resolvedFromWorker, resolvedBody, resolvedCwd);
return messages;
},
markMessageNotified: async (resolvedTeamName, workerName, messageId, resolvedCwd) => {
await teamMarkMessageNotified(resolvedTeamName, workerName, messageId, resolvedCwd);
}
}
});
return { ok: true, operation, data: { count: messages.length, messages } };
}
case "mailbox-list": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const includeDelivered = args.include_delivered !== false;
if (!teamName || !worker) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and worker are required" } };
}
const all = await teamListMailbox(teamName, worker, cwd);
const messages = includeDelivered ? all : all.filter((m) => !m.delivered_at);
return { ok: true, operation, data: { worker, count: messages.length, messages } };
}
case "mailbox-mark-delivered": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const messageId = String(args.message_id || "").trim();
if (!teamName || !worker || !messageId) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, message_id are required" } };
}
const updated = await teamMarkMessageDelivered(teamName, worker, messageId, cwd);
if (updated) {
await syncMailboxDispatchDelivered(teamName, worker, messageId, cwd);
}
return { ok: true, operation, data: { worker, message_id: messageId, updated } };
}
case "mailbox-mark-notified": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const messageId = String(args.message_id || "").trim();
if (!teamName || !worker || !messageId) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, message_id are required" } };
}
const notified = await teamMarkMessageNotified(teamName, worker, messageId, cwd);
if (notified) {
await syncMailboxDispatchNotified(teamName, worker, messageId, cwd);
}
return { ok: true, operation, data: { worker, message_id: messageId, notified } };
}
case "create-task": {
const teamName = String(args.team_name || "").trim();
const subject = String(args.subject || "").trim();
const description = String(args.description || "").trim();
if (!teamName || !subject || !description) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, subject, description are required" } };
}
const owner = args.owner;
const blockedBy = args.blocked_by;
const requiresCodeChange = args.requires_code_change;
const task = await teamCreateTask(teamName, {
subject,
description,
status: "pending",
owner: owner || void 0,
blocked_by: blockedBy,
requires_code_change: requiresCodeChange
}, cwd);
return { ok: true, operation, data: { task } };
}
case "read-task": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
if (!teamName || !taskId) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and task_id are required" } };
}
const task = await teamReadTask(teamName, taskId, cwd);
return task ? { ok: true, operation, data: { task } } : { ok: false, operation, error: { code: "task_not_found", message: "task_not_found" } };
}
case "list-tasks": {
const teamName = String(args.team_name || "").trim();
if (!teamName) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
}
const tasks = await teamListTasks(teamName, cwd);
return { ok: true, operation, data: { count: tasks.length, tasks } };
}
case "update-task": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
if (!teamName || !taskId) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and task_id are required" } };
}
const lifecycleFields = ["status", "owner", "result", "error"];
const presentLifecycleFields = lifecycleFields.filter((f) => f in args);
if (presentLifecycleFields.length > 0) {
return { ok: false, operation, error: { code: "invalid_input", message: `team_update_task cannot mutate lifecycle fields: ${presentLifecycleFields.join(", ")}` } };
}
const unexpectedFields = Object.keys(args).filter((field) => !TEAM_UPDATE_TASK_REQUEST_FIELDS.has(field));
if (unexpectedFields.length > 0) {
return { ok: false, operation, error: { code: "invalid_input", message: `team_update_task received unsupported fields: ${unexpectedFields.join(", ")}` } };
}
const updates = {};
if ("subject" in args) {
if (typeof args.subject !== "string") {
return { ok: false, operation, error: { code: "invalid_input", message: "subject must be a string when provided" } };
}
updates.subject = args.subject.trim();
}
if ("description" in args) {
if (typeof args.description !== "string") {
return { ok: false, operation, error: { code: "invalid_input", message: "description must be a string when provided" } };
}
updates.description = args.description.trim();
}
if ("requires_code_change" in args) {
if (typeof args.requires_code_change !== "boolean") {
return { ok: false, operation, error: { code: "invalid_input", message: "requires_code_change must be a boolean when provided" } };
}
updates.requires_code_change = args.requires_code_change;
}
if ("blocked_by" in args) {
try {
updates.blocked_by = parseValidatedTaskIdArray(args.blocked_by, "blocked_by");
} catch (error) {
return { ok: false, operation, error: { code: "invalid_input", message: error.message } };
}
}
const task = await teamUpdateTask(teamName, taskId, updates, cwd);
return task ? { ok: true, operation, data: { task } } : { ok: false, operation, error: { code: "task_not_found", message: "task_not_found" } };
}
case "claim-task": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !taskId || !worker) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, task_id, worker are required" } };
}
const rawExpectedVersion = args.expected_version;
if (rawExpectedVersion !== void 0 && (!isFiniteInteger(rawExpectedVersion) || rawExpectedVersion < 1)) {
return { ok: false, operation, error: { code: "invalid_input", message: "expected_version must be a positive integer when provided" } };
}
const result = await teamClaimTask(teamName, taskId, worker, rawExpectedVersion ?? null, cwd);
return { ok: true, operation, data: result };
}
case "transition-task-status": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
const from = String(args.from || "").trim();
const to = String(args.to || "").trim();
const claimToken = String(args.claim_token || "").trim();
if (!teamName || !taskId || !from || !to || !claimToken) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, task_id, from, to, claim_token are required" } };
}
const allowed = new Set(TEAM_TASK_STATUSES);
if (!allowed.has(from) || !allowed.has(to)) {
return { ok: false, operation, error: { code: "invalid_input", message: "from and to must be valid task statuses" } };
}
const result = await teamTransitionTaskStatus(teamName, taskId, from, to, claimToken, cwd);
return { ok: true, operation, data: result };
}
case "release-task-claim": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
const claimToken = String(args.claim_token || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !taskId || !claimToken || !worker) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, task_id, claim_token, worker are required" } };
}
const result = await teamReleaseTaskClaim(teamName, taskId, claimToken, worker, cwd);
return { ok: true, operation, data: result };
}
case "read-config": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
const config = await teamReadConfig(teamName, cwd);
return config ? { ok: true, operation, data: { config } } : { ok: false, operation, error: { code: "team_not_found", message: "team_not_found" } };
}
case "read-manifest": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
const manifest = await teamReadManifest(teamName, cwd);
return manifest ? { ok: true, operation, data: { manifest } } : { ok: false, operation, error: { code: "manifest_not_found", message: "manifest_not_found" } };
}
case "read-worker-status": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !worker) return { ok: false, operation, error: { code: "invalid_input", message: "team_name and worker are required" } };
const status = await teamReadWorkerStatus(teamName, worker, cwd);
return { ok: true, operation, data: { worker, status } };
}
case "read-worker-heartbeat": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !worker) return { ok: false, operation, error: { code: "invalid_input", message: "team_name and worker are required" } };
const heartbeat = await teamReadWorkerHeartbeat(teamName, worker, cwd);
return { ok: true, operation, data: { worker, heartbeat } };
}
case "update-worker-heartbeat": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const pid = args.pid;
const turnCount = args.turn_count;
const alive = args.alive;
if (!teamName || !worker || typeof pid !== "number" || typeof turnCount !== "number" || typeof alive !== "boolean") {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, pid, turn_count, alive are required" } };
}
await teamUpdateWorkerHeartbeat(teamName, worker, { pid, turn_count: turnCount, alive, last_turn_at: (/* @__PURE__ */ new Date()).toISOString() }, cwd);
return { ok: true, operation, data: { worker } };
}
case "write-worker-inbox": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const content = String(args.content || "").trim();
if (!teamName || !worker || !content) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, content are required" } };
}
await teamWriteWorkerInbox(teamName, worker, content, cwd);
return { ok: true, operation, data: { worker } };
}
case "write-worker-identity": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const index = args.index;
const role = String(args.role || "").trim();
if (!teamName || !worker || typeof index !== "number" || !role) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, index, role are required" } };
}
await teamWriteWorkerIdentity(teamName, worker, {
name: worker,
index,
role,
assigned_tasks: args.assigned_tasks ?? [],
pid: args.pid,
pane_id: args.pane_id,
working_dir: args.working_dir,
worktree_path: args.worktree_path,
worktree_branch: args.worktree_branch,
worktree_detached: args.worktree_detached,
team_state_root: args.team_state_root
}, cwd);
return { ok: true, operation, data: { worker } };
}
case "append-event": {
const teamName = String(args.team_name || "").trim();
const eventType = String(args.type || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !eventType || !worker) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, type, worker are required" } };
}
if (!TEAM_EVENT_TYPES.includes(eventType)) {
return { ok: false, operation, error: { code: "invalid_input", message: `type must be one of: ${TEAM_EVENT_TYPES.join(", ")}` } };
}
const event = await teamAppendEvent(teamName, {
type: eventType,
worker,
task_id: args.task_id,
message_id: args.message_id ?? null,
reason: args.reason
}, cwd);
return { ok: true, operation, data: { event } };
}
case "get-summary": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
const summary = await teamGetSummary(teamName, cwd);
return summary ? { ok: true, operation, data: { summary } } : { ok: false, operation, error: { code: "team_not_found", message: "team_not_found" } };
}
case "cleanup": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
await executeTeamCleanupViaRuntime(teamName, cwd);
return { ok: true, operation, data: { team_name: teamName } };
}
case "orphan-cleanup": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
await teamCleanup(teamName, cwd);
return { ok: true, operation, data: { team_name: teamName } };
}
case "write-shutdown-request": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
const requestedBy = String(args.requested_by || "").trim();
if (!teamName || !worker || !requestedBy) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, worker, requested_by are required" } };
}
await teamWriteShutdownRequest(teamName, worker, requestedBy, cwd);
return { ok: true, operation, data: { worker } };
}
case "read-shutdown-ack": {
const teamName = String(args.team_name || "").trim();
const worker = String(args.worker || "").trim();
if (!teamName || !worker) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and worker are required" } };
}
const ack = await teamReadShutdownAck(teamName, worker, cwd, args.min_updated_at);
return { ok: true, operation, data: { worker, ack } };
}
case "read-monitor-snapshot": {
const teamName = String(args.team_name || "").trim();
if (!teamName) return { ok: false, operation, error: { code: "invalid_input", message: "team_name is required" } };
const snapshot = await teamReadMonitorSnapshot(teamName, cwd);
return { ok: true, operation, data: { snapshot } };
}
case "write-monitor-snapshot": {
const teamName = String(args.team_name || "").trim();
const snapshot = args.snapshot;
if (!teamName || !snapshot) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and snapshot are required" } };
}
await teamWriteMonitorSnapshot(teamName, snapshot, cwd);
return { ok: true, operation, data: {} };
}
case "read-task-approval": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
if (!teamName || !taskId) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name and task_id are required" } };
}
const approval = await teamReadTaskApproval(teamName, taskId, cwd);
return { ok: true, operation, data: { approval } };
}
case "write-task-approval": {
const teamName = String(args.team_name || "").trim();
const taskId = String(args.task_id || "").trim();
const status = String(args.status || "").trim();
const reviewer = String(args.reviewer || "").trim();
const decisionReason = String(args.decision_reason || "").trim();
if (!teamName || !taskId || !status || !reviewer || !decisionReason) {
return { ok: false, operation, error: { code: "invalid_input", message: "team_name, task_id, status, reviewer, decision_reason are required" } };
}
if (!TEAM_TASK_APPROVAL_STATUSES.includes(status)) {
return { ok: false, operation, error: { code: "invalid_input", message: `status must be one of: ${TEAM_TASK_APPROVAL_STATUSES.join(", ")}` } };
}
const rawRequired = args.required;
if (rawRequired !== void 0 && typeof rawRequired !== "boolean") {
return { ok: false, operation, error: { code: "invalid_input", message: "required must be a boolean when provided" } };
}
await teamWriteTaskApproval(teamName, {
task_id: taskId,
required: rawRequired !== false,
status,
reviewer,
decision_reason: decisionReason,
decided_at: (/* @__PURE__ */ new Date()).toISOString()
}, cwd);
return { ok: true, operation, data: { task_id: taskId, status } };
}
}
} catch (error) {
return {
ok: false,
operation,
error: {
code: "operation_failed",
message: error instanceof Error ? error.message : String(error)
}
};
}
}
// src/cli/team.ts
init_git_worktree();
init_tmux_session();
init_team_name();
init_monitor();
init_platform();
init_paths();
var JOB_ID_PATTERN = /^omc-[a-z0-9]{1,16}$/;
var VALID_CLI_AGENT_TYPES = /* @__PURE__ */ new Set(["claude", "codex", "gemini"]);
var SUBCOMMANDS = /* @__PURE__ */ new Set(["start", "status", "wait", "cleanup", "resume", "shutdown", "api", "help", "--help", "-h"]);
var SUPPORTED_API_OPERATIONS = /* @__PURE__ */ new Set([
"send-message",
"broadcast",
"mailbox-list",
"mailbox-mark-delivered",
"mailbox-mark-notified",
"list-tasks",
"read-task",
"read-config",
"get-summary",
"orphan-cleanup"
]);
var TEAM_API_USAGE = `
Usage:
omc team api <operation> --input '<json>' [--json] [--cwd DIR]
Supported operations:
${Array.from(SUPPORTED_API_OPERATIONS).join(", ")}
`.trim();
function getTeamWorkerIdentityFromEnv(env = process.env) {
const omc = typeof env.OMC_TEAM_WORKER === "string" ? env.OMC_TEAM_WORKER.trim() : "";
if (omc) return omc;
const omx = typeof env.OMX_TEAM_WORKER === "string" ? env.OMX_TEAM_WORKER.trim() : "";
return omx || null;
}
async function assertTeamSpawnAllowed(cwd, env = process.env) {
const workerIdentity = getTeamWorkerIdentityFromEnv(env);
const { teamReadManifest: teamReadManifest2 } = await Promise.resolve().then(() => (init_team_ops(), team_ops_exports));
const { findActiveTeamsV2: findActiveTeamsV22 } = await Promise.resolve().then(() => (init_runtime_v2(), runtime_v2_exports));
const { DEFAULT_TEAM_GOVERNANCE: DEFAULT_TEAM_GOVERNANCE2, normalizeTeamGovernance: normalizeTeamGovernance2 } = await Promise.resolve().then(() => (init_governance(), governance_exports));
if (workerIdentity) {
const [parentTeamName] = workerIdentity.split("/");
const parentManifest = parentTeamName ? await teamReadManifest2(parentTeamName, cwd) : null;
const governance = normalizeTeamGovernance2(parentManifest?.governance, parentManifest?.policy);
if (!governance.nested_teams_allowed) {
throw new Error(
`Worker context (${workerIdentity}) cannot start nested teams because nested_teams_allowed is false.`
);
}
if (!governance.delegation_only) {
throw new Error(
`Worker context (${workerIdentity}) cannot start nested teams because delegation_only is false.`
);
}
return;
}
const activeTeams = await findActiveTeamsV22(cwd);
for (const activeTeam of activeTeams) {
const manifest = await teamReadManifest2(activeTeam, cwd);
const governance = normalizeTeamGovernance2(manifest?.governance, manifest?.policy);
if (governance.one_team_per_leader_session ?? DEFAULT_TEAM_GOVERNANCE2.one_team_per_leader_session) {
throw new Error(
`Leader session already owns active team "${activeTeam}" and one_team_per_leader_session is enabled.`
);
}
}
}
function resolveJobsDir(env = process.env) {
return env.OMC_JOBS_DIR || getGlobalOmcStatePath("team-jobs");
}
function resolveRuntimeCliPath(env = process.env) {
if (env.OMC_RUNTIME_CLI_PATH) {
return env.OMC_RUNTIME_CLI_PATH;
}
const moduleDir = dirname13(fileURLToPath3(import.meta.url));
return join20(moduleDir, "../../bridge/runtime-cli.cjs");
}
function ensureJobsDir(jobsDir) {
if (!existsSync17(jobsDir)) {
mkdirSync3(jobsDir, { recursive: true });
}
}
function jobPath(jobsDir, jobId) {
return join20(jobsDir, `${jobId}.json`);
}
function resultArtifactPath(jobsDir, jobId) {
return join20(jobsDir, `${jobId}-result.json`);
}
function panesArtifactPath(jobsDir, jobId) {
return join20(jobsDir, `${jobId}-panes.json`);
}
function teamStateRoot2(cwd, teamName) {
return join20(cwd, ".omc", "state", "team", teamName);
}
function validateJobId(jobId) {
if (!JOB_ID_PATTERN.test(jobId)) {
throw new Error(`Invalid job id: ${jobId}`);
}
}
function parseJsonSafe(content) {
try {
return JSON.parse(content);
} catch {
return null;
}
}
function readJobFromDisk(jobId, jobsDir) {
try {
const content = readFileSync10(jobPath(jobsDir, jobId), "utf-8");
return parseJsonSafe(content);
} catch {
return null;
}
}
function writeJobToDisk(jobId, job, jobsDir) {
ensureJobsDir(jobsDir);
writeFileSync2(jobPath(jobsDir, jobId), JSON.stringify(job), "utf-8");
}
function parseJobResult(raw) {
if (!raw) return void 0;
const parsed = parseJsonSafe(raw);
return parsed ?? raw;
}
function buildStatus(jobId, job) {
return {
jobId,
status: job.status,
elapsedSeconds: ((Date.now() - job.startedAt) / 1e3).toFixed(1),
result: parseJobResult(job.result),
stderr: job.stderr
};
}
function generateJobId(now = Date.now()) {
return `omc-${now.toString(36)}${randomUUID6().slice(0, 8)}`;
}
function convergeWithResultArtifact(jobId, job, jobsDir) {
try {
const artifactRaw = readFileSync10(resultArtifactPath(jobsDir, jobId), "utf-8");
const artifactParsed = parseJsonSafe(artifactRaw);
if (artifactParsed?.status === "completed" || artifactParsed?.status === "failed") {
return {
...job,
status: artifactParsed.status,
result: artifactRaw
};
}
} catch {
}
if (job.status === "running" && job.pid != null && !isProcessAlive(job.pid)) {
return {
...job,
status: "failed",
result: job.result ?? JSON.stringify({ error: "Process no longer alive" })
};
}
return job;
}
function output(value, asJson) {
if (asJson) {
console.log(JSON.stringify(value, null, 2));
return;
}
console.log(value);
}
function toInt(value, flag) {
const parsed = Number.parseInt(value, 10);
if (!Number.isFinite(parsed)) {
throw new Error(`Invalid ${flag} value: ${value}`);
}
return parsed;
}
function normalizeAgentType(value) {
const normalized = value.trim().toLowerCase();
if (!normalized) throw new Error("Agent type cannot be empty");
if (!VALID_CLI_AGENT_TYPES.has(normalized)) {
throw new Error(`Unsupported agent type: ${value}`);
}
return normalized;
}
function autoTeamName(task) {
const slug = task.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24) || "task";
return `omc-${slug}-${Date.now().toString(36).slice(-4)}`;
}
function parseJsonInput(inputRaw) {
if (!inputRaw || !inputRaw.trim()) return {};
const parsed = parseJsonSafe(inputRaw);
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new Error("Invalid --input JSON payload");
}
return parsed;
}
async function startTeamJob(input) {
await assertTeamSpawnAllowed(input.cwd);
validateTeamName(input.teamName);
if (!Array.isArray(input.agentTypes) || input.agentTypes.length === 0) {
throw new Error("agentTypes must be a non-empty array");
}
if (!Array.isArray(input.tasks) || input.tasks.length === 0) {
throw new Error("tasks must be a non-empty array");
}
const jobsDir = resolveJobsDir();
const runtimeCliPath = resolveRuntimeCliPath();
const jobId = generateJobId();
const job = {
status: "running",
startedAt: Date.now(),
teamName: input.teamName,
cwd: input.cwd
};
const child = spawn("node", [runtimeCliPath], {
env: {
...process.env,
OMC_JOB_ID: jobId,
OMC_JOBS_DIR: jobsDir
},
detached: true,
stdio: ["pipe", "ignore", "ignore"]
});
const payload = {
teamName: input.teamName,
workerCount: input.workerCount,
agentTypes: input.agentTypes,
tasks: input.tasks,
cwd: input.cwd,
newWindow: input.newWindow,
pollIntervalMs: input.pollIntervalMs,
sentinelGateTimeoutMs: input.sentinelGateTimeoutMs,
sentinelGatePollIntervalMs: input.sentinelGatePollIntervalMs
};
if (child.stdin && typeof child.stdin.on === "function") {
child.stdin.on("error", () => {
});
}
child.stdin?.write(JSON.stringify(payload));
child.stdin?.end();
child.unref();
if (child.pid != null) {
job.pid = child.pid;
}
writeJobToDisk(jobId, job, jobsDir);
return {
jobId,
status: "running",
pid: child.pid
};
}
async function getTeamJobStatus(jobId) {
validateJobId(jobId);
const jobsDir = resolveJobsDir();
const job = readJobFromDisk(jobId, jobsDir);
if (!job) {
throw new Error(`No job found: ${jobId}`);
}
const converged = convergeWithResultArtifact(jobId, job, jobsDir);
if (JSON.stringify(converged) !== JSON.stringify(job)) {
writeJobToDisk(jobId, converged, jobsDir);
}
return buildStatus(jobId, converged);
}
async function waitForTeamJob(jobId, options = {}) {
const timeoutMs = Math.min(options.timeoutMs ?? 3e5, 36e5);
const deadline = Date.now() + timeoutMs;
let delayMs = 500;
while (Date.now() < deadline) {
const status2 = await getTeamJobStatus(jobId);
if (status2.status !== "running") {
return status2;
}
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
delayMs = Math.min(Math.floor(delayMs * 1.5), 2e3);
}
const status = await getTeamJobStatus(jobId);
return {
...status,
timedOut: true,
error: `Timed out waiting for job ${jobId} after ${(timeoutMs / 1e3).toFixed(0)}s`
};
}
async function cleanupTeamJob(jobId, graceMs = 1e4) {
validateJobId(jobId);
const jobsDir = resolveJobsDir();
const job = readJobFromDisk(jobId, jobsDir);
if (!job) {
throw new Error(`No job found: ${jobId}`);
}
const paneArtifact = await readFile10(panesArtifactPath(jobsDir, jobId), "utf-8").then((content) => parseJsonSafe(content)).catch(() => null);
if (paneArtifact?.sessionName && (paneArtifact.ownsWindow === true || !paneArtifact.sessionName.includes(":"))) {
const sessionMode = paneArtifact.ownsWindow === true ? paneArtifact.sessionName.includes(":") ? "dedicated-window" : "detached-session" : "detached-session";
await killTeamSession(
paneArtifact.sessionName,
paneArtifact.paneIds,
paneArtifact.leaderPaneId,
{ sessionMode }
);
} else if (paneArtifact?.paneIds?.length) {
await killWorkerPanes({
paneIds: paneArtifact.paneIds,
leaderPaneId: paneArtifact.leaderPaneId,
teamName: job.teamName,
cwd: job.cwd,
graceMs
});
}
await rm4(teamStateRoot2(job.cwd, job.teamName), {
recursive: true,
force: true
}).catch(() => void 0);
try {
cleanupTeamWorktrees(job.teamName, job.cwd);
} catch {
}
writeJobToDisk(jobId, {
...job,
cleanedUpAt: (/* @__PURE__ */ new Date()).toISOString()
}, jobsDir);
return {
jobId,
message: paneArtifact?.ownsWindow ? "Cleaned up team tmux window" : paneArtifact?.paneIds?.length ? `Cleaned up ${paneArtifact.paneIds.length} worker pane(s)` : "No worker pane ids found for this job"
};
}
async function teamStatusByTeamName(teamName, cwd = process.cwd()) {
validateTeamName(teamName);
const runtimeV2 = await Promise.resolve().then(() => (init_runtime_v2(), runtime_v2_exports));
if (runtimeV2.isRuntimeV2Enabled()) {
const snapshot2 = await runtimeV2.monitorTeamV2(teamName, cwd);
if (!snapshot2) {
return {
teamName,
running: false,
error: "Team state not found"
};
}
const config = await readTeamConfig(teamName, cwd);
return {
teamName,
running: true,
sessionName: config?.tmux_session,
leaderPaneId: config?.leader_pane_id,
workerPaneIds: Array.from(new Set(
(config?.workers ?? []).map((worker) => worker.pane_id).filter((paneId) => typeof paneId === "string" && paneId.trim().length > 0)
)),
snapshot: snapshot2
};
}
const runtime = await resumeTeam(teamName, cwd);
if (!runtime) {
return {
teamName,
running: false,
error: "Team session is not currently resumable"
};
}
const snapshot = await monitorTeam(teamName, cwd, runtime.workerPaneIds);
return {
teamName,
running: true,
sessionName: runtime.sessionName,
leaderPaneId: runtime.leaderPaneId,
workerPaneIds: runtime.workerPaneIds,
snapshot
};
}
async function teamResumeByName(teamName, cwd = process.cwd()) {
validateTeamName(teamName);
const runtime = await resumeTeam(teamName, cwd);
if (!runtime) {
return {
teamName,
resumed: false,
error: "Team session is not currently resumable"
};
}
return {
teamName,
resumed: true,
sessionName: runtime.sessionName,
leaderPaneId: runtime.leaderPaneId,
workerPaneIds: runtime.workerPaneIds,
activeWorkers: runtime.activeWorkers.size
};
}
async function teamShutdownByName(teamName, options = {}) {
validateTeamName(teamName);
const cwd = options.cwd ?? process.cwd();
const runtimeV2 = await Promise.resolve().then(() => (init_runtime_v2(), runtime_v2_exports));
if (runtimeV2.isRuntimeV2Enabled()) {
const config = await readTeamConfig(teamName, cwd);
await runtimeV2.shutdownTeamV2(teamName, cwd, { force: Boolean(options.force) });
return {
teamName,
shutdown: true,
forced: Boolean(options.force),
sessionFound: Boolean(config)
};
}
const runtime = await resumeTeam(teamName, cwd);
if (!runtime) {
if (options.force) {
await rm4(teamStateRoot2(cwd, teamName), { recursive: true, force: true }).catch(() => void 0);
return {
teamName,
shutdown: true,
forced: true,
sessionFound: false
};
}
throw new Error(`Team ${teamName} is not running. Use --force to clear stale state.`);
}
await shutdownTeam(
runtime.teamName,
runtime.sessionName,
runtime.cwd,
options.force ? 0 : 3e4,
runtime.workerPaneIds,
runtime.leaderPaneId,
runtime.ownsWindow
);
return {
teamName,
shutdown: true,
forced: Boolean(options.force),
sessionFound: true
};
}
async function executeTeamApiOperation2(operation, input, cwd = process.cwd()) {
const canonicalOperation = resolveTeamApiOperation(operation);
if (!canonicalOperation || !SUPPORTED_API_OPERATIONS.has(canonicalOperation)) {
return {
ok: false,
operation,
error: {
code: "UNSUPPORTED_OPERATION",
message: `Unsupported omc team api operation: ${operation}`
}
};
}
const normalizedInput = {
...input,
...typeof input.teamName === "string" && input.teamName.trim() !== "" && typeof input.team_name !== "string" ? { team_name: input.teamName } : {},
...typeof input.taskId === "string" && input.taskId.trim() !== "" && typeof input.task_id !== "string" ? { task_id: input.taskId } : {},
...typeof input.workerName === "string" && input.workerName.trim() !== "" && typeof input.worker !== "string" ? { worker: input.workerName } : {},
...typeof input.fromWorker === "string" && input.fromWorker.trim() !== "" && typeof input.from_worker !== "string" ? { from_worker: input.fromWorker } : {},
...typeof input.toWorker === "string" && input.toWorker.trim() !== "" && typeof input.to_worker !== "string" ? { to_worker: input.toWorker } : {},
...typeof input.messageId === "string" && input.messageId.trim() !== "" && typeof input.message_id !== "string" ? { message_id: input.messageId } : {}
};
const result = await executeTeamApiOperation(canonicalOperation, normalizedInput, cwd);
return result;
}
async function teamStartCommand(input, options = {}) {
const result = await startTeamJob(input);
output(result, Boolean(options.json));
return result;
}
async function teamStatusCommand(jobId, options = {}) {
const result = await getTeamJobStatus(jobId);
output(result, Boolean(options.json));
return result;
}
async function teamWaitCommand(jobId, waitOptions = {}, options = {}) {
const result = await waitForTeamJob(jobId, waitOptions);
output(result, Boolean(options.json));
return result;
}
async function teamCleanupCommand(jobId, cleanupOptions = {}, options = {}) {
const result = await cleanupTeamJob(jobId, cleanupOptions.graceMs);
output(result, Boolean(options.json));
return result;
}
var TEAM_USAGE = `
Usage:
omc team start --agent <claude|codex|gemini>[,<agent>...] --task "<task>" [--count N] [--name TEAM] [--cwd DIR] [--new-window] [--json]
omc team status <job_id|team_name> [--json] [--cwd DIR]
omc team wait <job_id> [--timeout-ms MS] [--json]
omc team cleanup <job_id> [--grace-ms MS] [--json]
omc team resume <team_name> [--json] [--cwd DIR]
omc team shutdown <team_name> [--force] [--json] [--cwd DIR]
omc team api <operation> [--input '<json>'] [--json] [--cwd DIR]
omc team [ralph] <N:agent-type[:role]> "task" [--json] [--cwd DIR] [--new-window]
Examples:
omc team start --agent codex --count 2 --task "review auth flow" --new-window
omc team status omc-abc123
omc team status auth-review
omc team resume auth-review
omc team shutdown auth-review --force
omc team api list-tasks --input '{"teamName":"auth-review"}' --json
omc team 3:codex "refactor launch command"
`.trim();
function parseStartArgs(args) {
const agentValues = [];
const taskValues = [];
let teamName;
let cwd = process.cwd();
let count = 1;
let json = false;
let newWindow = false;
let subjectPrefix = "Task";
let pollIntervalMs;
let sentinelGateTimeoutMs;
let sentinelGatePollIntervalMs;
for (let i = 0; i < args.length; i += 1) {
const token = args[i];
const next = args[i + 1];
if (token === "--json") {
json = true;
continue;
}
if (token === "--new-window") {
newWindow = true;
continue;
}
if (token === "--agent") {
if (!next) throw new Error("Missing value after --agent");
agentValues.push(...next.split(",").map(normalizeAgentType));
i += 1;
continue;
}
if (token.startsWith("--agent=")) {
agentValues.push(...token.slice("--agent=".length).split(",").map(normalizeAgentType));
continue;
}
if (token === "--task") {
if (!next) throw new Error("Missing value after --task");
taskValues.push(next);
i += 1;
continue;
}
if (token.startsWith("--task=")) {
taskValues.push(token.slice("--task=".length));
continue;
}
if (token === "--count") {
if (!next) throw new Error("Missing value after --count");
count = toInt(next, "--count");
i += 1;
continue;
}
if (token.startsWith("--count=")) {
count = toInt(token.slice("--count=".length), "--count");
continue;
}
if (token === "--name") {
if (!next) throw new Error("Missing value after --name");
teamName = next;
i += 1;
continue;
}
if (token.startsWith("--name=")) {
teamName = token.slice("--name=".length);
continue;
}
if (token === "--cwd") {
if (!next) throw new Error("Missing value after --cwd");
cwd = next;
i += 1;
continue;
}
if (token.startsWith("--cwd=")) {
cwd = token.slice("--cwd=".length);
continue;
}
if (token === "--subject") {
if (!next) throw new Error("Missing value after --subject");
subjectPrefix = next;
i += 1;
continue;
}
if (token.startsWith("--subject=")) {
subjectPrefix = token.slice("--subject=".length);
continue;
}
if (token === "--poll-interval-ms") {
if (!next) throw new Error("Missing value after --poll-interval-ms");
pollIntervalMs = toInt(next, "--poll-interval-ms");
i += 1;
continue;
}
if (token.startsWith("--poll-interval-ms=")) {
pollIntervalMs = toInt(token.slice("--poll-interval-ms=".length), "--poll-interval-ms");
continue;
}
if (token === "--sentinel-gate-timeout-ms") {
if (!next) throw new Error("Missing value after --sentinel-gate-timeout-ms");
sentinelGateTimeoutMs = toInt(next, "--sentinel-gate-timeout-ms");
i += 1;
continue;
}
if (token.startsWith("--sentinel-gate-timeout-ms=")) {
sentinelGateTimeoutMs = toInt(token.slice("--sentinel-gate-timeout-ms=".length), "--sentinel-gate-timeout-ms");
continue;
}
if (token === "--sentinel-gate-poll-interval-ms") {
if (!next) throw new Error("Missing value after --sentinel-gate-poll-interval-ms");
sentinelGatePollIntervalMs = toInt(next, "--sentinel-gate-poll-interval-ms");
i += 1;
continue;
}
if (token.startsWith("--sentinel-gate-poll-interval-ms=")) {
sentinelGatePollIntervalMs = toInt(token.slice("--sentinel-gate-poll-interval-ms=".length), "--sentinel-gate-poll-interval-ms");
continue;
}
throw new Error(`Unknown argument for "omc team start": ${token}`);
}
if (count < 1) throw new Error("--count must be >= 1");
if (agentValues.length === 0) throw new Error("Missing required --agent");
if (taskValues.length === 0) throw new Error("Missing required --task");
const agentTypes = agentValues.length === 1 ? Array.from({ length: count }, () => agentValues[0]) : [...agentValues];
if (agentValues.length > 1 && count !== 1) {
throw new Error("Do not combine --count with multiple --agent values; either use one agent+count or explicit agent list.");
}
const taskDescriptions = taskValues.length === 1 ? Array.from({ length: agentTypes.length }, () => taskValues[0]) : [...taskValues];
if (taskDescriptions.length !== agentTypes.length) {
throw new Error(`Task count (${taskDescriptions.length}) must match worker count (${agentTypes.length}).`);
}
const resolvedTeamName = teamName && teamName.trim() ? teamName.trim() : autoTeamName(taskDescriptions[0]);
const tasks = taskDescriptions.map((description, index) => ({
subject: `${subjectPrefix} ${index + 1}`,
description
}));
return {
input: {
teamName: resolvedTeamName,
agentTypes,
tasks,
cwd,
...newWindow ? { newWindow: true } : {},
...pollIntervalMs != null ? { pollIntervalMs } : {},
...sentinelGateTimeoutMs != null ? { sentinelGateTimeoutMs } : {},
...sentinelGatePollIntervalMs != null ? { sentinelGatePollIntervalMs } : {}
},
json
};
}
function parseCommonJobArgs(args, command) {
let json = false;
let target;
let cwd;
let timeoutMs;
let graceMs;
for (let i = 0; i < args.length; i += 1) {
const token = args[i];
const next = args[i + 1];
if (!token.startsWith("-") && !target) {
target = token;
continue;
}
if (token === "--json") {
json = true;
continue;
}
if (token === "--cwd") {
if (!next) throw new Error("Missing value after --cwd");
cwd = next;
i += 1;
continue;
}
if (token.startsWith("--cwd=")) {
cwd = token.slice("--cwd=".length);
continue;
}
if (token === "--job-id") {
if (!next) throw new Error("Missing value after --job-id");
target = next;
i += 1;
continue;
}
if (token.startsWith("--job-id=")) {
target = token.slice("--job-id=".length);
continue;
}
if (command === "wait") {
if (token === "--timeout-ms") {
if (!next) throw new Error("Missing value after --timeout-ms");
timeoutMs = toInt(next, "--timeout-ms");
i += 1;
continue;
}
if (token.startsWith("--timeout-ms=")) {
timeoutMs = toInt(token.slice("--timeout-ms=".length), "--timeout-ms");
continue;
}
}
if (command === "cleanup") {
if (token === "--grace-ms") {
if (!next) throw new Error("Missing value after --grace-ms");
graceMs = toInt(next, "--grace-ms");
i += 1;
continue;
}
if (token.startsWith("--grace-ms=")) {
graceMs = toInt(token.slice("--grace-ms=".length), "--grace-ms");
continue;
}
}
throw new Error(`Unknown argument for "omc team ${command}": ${token}`);
}
if (!target) {
throw new Error(`Missing required target for "omc team ${command}".`);
}
return {
target,
json,
...cwd ? { cwd } : {},
...timeoutMs != null ? { timeoutMs } : {},
...graceMs != null ? { graceMs } : {}
};
}
function parseTeamTargetArgs(args, command) {
let teamName;
let json = false;
let cwd;
let force = false;
for (let i = 0; i < args.length; i += 1) {
const token = args[i];
const next = args[i + 1];
if (!token.startsWith("-") && !teamName) {
teamName = token;
continue;
}
if (token === "--json") {
json = true;
continue;
}
if (token === "--cwd") {
if (!next) throw new Error("Missing value after --cwd");
cwd = next;
i += 1;
continue;
}
if (token.startsWith("--cwd=")) {
cwd = token.slice("--cwd=".length);
continue;
}
if (command === "shutdown" && token === "--force") {
force = true;
continue;
}
throw new Error(`Unknown argument for "omc team ${command}": ${token}`);
}
if (!teamName) {
throw new Error(`Missing required <team_name> for "omc team ${command}".`);
}
return {
teamName,
json,
...cwd ? { cwd } : {},
...command === "shutdown" ? { force } : {}
};
}
function parseApiArgs(args) {
let operation;
let inputRaw;
let json = false;
let cwd;
for (let i = 0; i < args.length; i += 1) {
const token = args[i];
const next = args[i + 1];
if (!token.startsWith("-") && !operation) {
operation = token;
continue;
}
if (token === "--json") {
json = true;
continue;
}
if (token === "--input") {
if (!next) throw new Error("Missing value after --input");
inputRaw = next;
i += 1;
continue;
}
if (token.startsWith("--input=")) {
inputRaw = token.slice("--input=".length);
continue;
}
if (token === "--cwd") {
if (!next) throw new Error("Missing value after --cwd");
cwd = next;
i += 1;
continue;
}
if (token.startsWith("--cwd=")) {
cwd = token.slice("--cwd=".length);
continue;
}
throw new Error(`Unknown argument for "omc team api": ${token}`);
}
if (!operation) {
throw new Error(`Missing required <operation> for "omc team api"
${TEAM_API_USAGE}`);
}
return {
operation,
input: parseJsonInput(inputRaw),
json,
...cwd ? { cwd } : {}
};
}
function parseLegacyStartAlias(args) {
if (args.length < 2) return null;
let index = 0;
let ralph = false;
if (args[index]?.toLowerCase() === "ralph") {
ralph = true;
index += 1;
}
const spec = args[index];
if (!spec) return null;
const match = spec.match(/^(\d+):([a-zA-Z0-9_-]+)(?::([a-zA-Z0-9_-]+))?$/);
if (!match) return null;
const workerCount = toInt(match[1], "worker-count");
if (workerCount < 1) throw new Error("worker-count must be >= 1");
const agentType = normalizeAgentType(match[2]);
const role = match[3] || void 0;
index += 1;
let json = false;
let cwd = process.cwd();
let newWindow = false;
const taskParts = [];
for (let i = index; i < args.length; i += 1) {
const token = args[i];
const next = args[i + 1];
if (token === "--json") {
json = true;
continue;
}
if (token === "--new-window") {
newWindow = true;
continue;
}
if (token === "--cwd") {
if (!next) throw new Error("Missing value after --cwd");
cwd = next;
i += 1;
continue;
}
if (token.startsWith("--cwd=")) {
cwd = token.slice("--cwd=".length);
continue;
}
taskParts.push(token);
}
const task = taskParts.join(" ").trim();
if (!task) throw new Error("Legacy start alias requires a task string");
return {
workerCount,
agentType,
role,
task,
teamName: autoTeamName(task),
ralph,
json,
cwd,
...newWindow ? { newWindow: true } : {}
};
}
async function teamCommand(argv) {
const [commandRaw, ...rest] = argv;
const command = (commandRaw || "").toLowerCase();
if (!command || command === "help" || command === "--help" || command === "-h") {
console.log(TEAM_USAGE);
return;
}
if (command === "start") {
const parsed = parseStartArgs(rest);
await teamStartCommand(parsed.input, { json: parsed.json });
return;
}
if (command === "status") {
const parsed = parseCommonJobArgs(rest, "status");
if (JOB_ID_PATTERN.test(parsed.target)) {
await teamStatusCommand(parsed.target, { json: parsed.json });
return;
}
const byTeam = await teamStatusByTeamName(parsed.target, parsed.cwd ?? process.cwd());
output(byTeam, parsed.json);
return;
}
if (command === "wait") {
const parsed = parseCommonJobArgs(rest, "wait");
await teamWaitCommand(parsed.target, { ...parsed.timeoutMs != null ? { timeoutMs: parsed.timeoutMs } : {} }, { json: parsed.json });
return;
}
if (command === "cleanup") {
const parsed = parseCommonJobArgs(rest, "cleanup");
await teamCleanupCommand(parsed.target, { ...parsed.graceMs != null ? { graceMs: parsed.graceMs } : {} }, { json: parsed.json });
return;
}
if (command === "resume") {
const parsed = parseTeamTargetArgs(rest, "resume");
const result = await teamResumeByName(parsed.teamName, parsed.cwd ?? process.cwd());
output(result, parsed.json);
return;
}
if (command === "shutdown") {
const parsed = parseTeamTargetArgs(rest, "shutdown");
const result = await teamShutdownByName(parsed.teamName, {
cwd: parsed.cwd ?? process.cwd(),
force: Boolean(parsed.force)
});
output(result, parsed.json);
return;
}
if (command === "api") {
if (rest.length === 0 || rest[0] === "help" || rest[0] === "--help" || rest[0] === "-h") {
console.log(TEAM_API_USAGE);
return;
}
const parsed = parseApiArgs(rest);
const result = await executeTeamApiOperation2(parsed.operation, parsed.input, parsed.cwd ?? process.cwd());
if (!result.ok && !parsed.json) {
throw new Error(result.error?.message ?? "Team API operation failed");
}
output(result, parsed.json);
return;
}
if (!SUBCOMMANDS.has(command)) {
const legacy = parseLegacyStartAlias(argv);
if (legacy) {
const tasks = Array.from({ length: legacy.workerCount }, (_, idx) => ({
subject: legacy.ralph ? `Ralph Task ${idx + 1}` : `Task ${idx + 1}`,
description: legacy.task
}));
const result = await startTeamJob({
teamName: legacy.teamName,
workerCount: legacy.workerCount,
agentTypes: Array.from({ length: legacy.workerCount }, () => legacy.agentType),
tasks,
cwd: legacy.cwd,
...legacy.newWindow ? { newWindow: true } : {}
});
output(result, legacy.json);
return;
}
}
throw new Error(`Unknown team command: ${command}
${TEAM_USAGE}`);
}
async function main(argv) {
await teamCommand(argv);
}
export {
TEAM_USAGE,
cleanupTeamJob,
executeTeamApiOperation2 as executeTeamApiOperation,
generateJobId,
getTeamJobStatus,
main,
startTeamJob,
teamCleanupCommand,
teamCommand,
teamResumeByName,
teamShutdownByName,
teamStartCommand,
teamStatusByTeamName,
teamStatusCommand,
teamWaitCommand,
waitForTeamJob
};