oh-my-codex 0.15.2 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/dist/agents/__tests__/native-config.test.js +33 -0
  4. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  5. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -1
  6. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  7. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +2 -0
  8. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +1 -0
  9. package/dist/cli/__tests__/doctor-context-window-warning.test.js +122 -0
  10. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -0
  11. package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -2
  12. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  13. package/dist/cli/__tests__/exec.test.js +1 -0
  14. package/dist/cli/__tests__/exec.test.js.map +1 -1
  15. package/dist/cli/__tests__/explore.test.js +40 -17
  16. package/dist/cli/__tests__/explore.test.js.map +1 -1
  17. package/dist/cli/__tests__/index.test.js +141 -8
  18. package/dist/cli/__tests__/index.test.js.map +1 -1
  19. package/dist/cli/__tests__/mcp-serve.test.js +27 -1
  20. package/dist/cli/__tests__/mcp-serve.test.js.map +1 -1
  21. package/dist/cli/__tests__/ralph.test.js +59 -1
  22. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  23. package/dist/cli/__tests__/setup-scope.test.js +2 -1
  24. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  25. package/dist/cli/__tests__/team.test.js +55 -10
  26. package/dist/cli/__tests__/team.test.js.map +1 -1
  27. package/dist/cli/doctor.d.ts.map +1 -1
  28. package/dist/cli/doctor.js +46 -3
  29. package/dist/cli/doctor.js.map +1 -1
  30. package/dist/cli/index.d.ts +16 -1
  31. package/dist/cli/index.d.ts.map +1 -1
  32. package/dist/cli/index.js +126 -15
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/mcp-serve.d.ts +1 -0
  35. package/dist/cli/mcp-serve.d.ts.map +1 -1
  36. package/dist/cli/mcp-serve.js +8 -0
  37. package/dist/cli/mcp-serve.js.map +1 -1
  38. package/dist/cli/ralph.d.ts +2 -0
  39. package/dist/cli/ralph.d.ts.map +1 -1
  40. package/dist/cli/ralph.js +17 -1
  41. package/dist/cli/ralph.js.map +1 -1
  42. package/dist/cli/team.d.ts +4 -0
  43. package/dist/cli/team.d.ts.map +1 -1
  44. package/dist/cli/team.js +47 -22
  45. package/dist/cli/team.js.map +1 -1
  46. package/dist/config/__tests__/generator-idempotent.test.js +27 -5
  47. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  48. package/dist/config/generator.d.ts +11 -2
  49. package/dist/config/generator.d.ts.map +1 -1
  50. package/dist/config/generator.js +114 -58
  51. package/dist/config/generator.js.map +1 -1
  52. package/dist/hooks/__tests__/agents-overlay.test.js +59 -0
  53. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  54. package/dist/hooks/__tests__/anti-slop-workflow.test.js +109 -18
  55. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  56. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  57. package/dist/hooks/agents-overlay.js +21 -0
  58. package/dist/hooks/agents-overlay.js.map +1 -1
  59. package/dist/hud/__tests__/index.test.js +30 -14
  60. package/dist/hud/__tests__/index.test.js.map +1 -1
  61. package/dist/openclaw/__tests__/dispatcher.test.js +1 -1
  62. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
  63. package/dist/pipeline/__tests__/stages.test.js +398 -14
  64. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  65. package/dist/pipeline/stages/team-exec.d.ts +8 -4
  66. package/dist/pipeline/stages/team-exec.d.ts.map +1 -1
  67. package/dist/pipeline/stages/team-exec.js +198 -13
  68. package/dist/pipeline/stages/team-exec.js.map +1 -1
  69. package/dist/planning/__tests__/artifacts.test.js +246 -1
  70. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  71. package/dist/planning/artifact-names.d.ts +13 -0
  72. package/dist/planning/artifact-names.d.ts.map +1 -0
  73. package/dist/planning/artifact-names.js +108 -0
  74. package/dist/planning/artifact-names.js.map +1 -0
  75. package/dist/planning/artifacts.d.ts +22 -1
  76. package/dist/planning/artifacts.d.ts.map +1 -1
  77. package/dist/planning/artifacts.js +165 -50
  78. package/dist/planning/artifacts.js.map +1 -1
  79. package/dist/ralph/__tests__/persistence.test.js +21 -1
  80. package/dist/ralph/__tests__/persistence.test.js.map +1 -1
  81. package/dist/ralph/persistence.d.ts.map +1 -1
  82. package/dist/ralph/persistence.js +6 -4
  83. package/dist/ralph/persistence.js.map +1 -1
  84. package/dist/scripts/__tests__/codex-native-hook.test.js +352 -2
  85. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  86. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  87. package/dist/scripts/codex-native-hook.js +85 -6
  88. package/dist/scripts/codex-native-hook.js.map +1 -1
  89. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  90. package/dist/scripts/codex-native-pre-post.js +123 -0
  91. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  92. package/dist/scripts/notify-hook/team-worker-posttooluse.js +1 -1
  93. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
  94. package/dist/scripts/notify-hook.js +1 -1
  95. package/dist/scripts/notify-hook.js.map +1 -1
  96. package/dist/scripts/sync-plugin-mirror.d.ts +1 -0
  97. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  98. package/dist/scripts/sync-plugin-mirror.js +8 -2
  99. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  100. package/dist/state/__tests__/skill-active.test.js +41 -0
  101. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  102. package/dist/team/__tests__/api-interop.test.js +220 -0
  103. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  104. package/dist/team/__tests__/model-contract.test.js +40 -9
  105. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  106. package/dist/team/__tests__/repo-aware-decomposition.test.js +41 -0
  107. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -1
  108. package/dist/team/__tests__/runtime-cli.test.js +24 -0
  109. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  110. package/dist/team/__tests__/runtime.test.js +446 -67
  111. package/dist/team/__tests__/runtime.test.js.map +1 -1
  112. package/dist/team/__tests__/state.test.js +13 -0
  113. package/dist/team/__tests__/state.test.js.map +1 -1
  114. package/dist/team/__tests__/team-identity.test.d.ts +2 -0
  115. package/dist/team/__tests__/team-identity.test.d.ts.map +1 -0
  116. package/dist/team/__tests__/team-identity.test.js +166 -0
  117. package/dist/team/__tests__/team-identity.test.js.map +1 -0
  118. package/dist/team/__tests__/tmux-session.test.js +55 -1
  119. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  120. package/dist/team/__tests__/worker-bootstrap.test.js +12 -0
  121. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  122. package/dist/team/api-interop.d.ts +1 -0
  123. package/dist/team/api-interop.d.ts.map +1 -1
  124. package/dist/team/api-interop.js +159 -129
  125. package/dist/team/api-interop.js.map +1 -1
  126. package/dist/team/delivery-log.d.ts +1 -1
  127. package/dist/team/delivery-log.d.ts.map +1 -1
  128. package/dist/team/delivery-log.js.map +1 -1
  129. package/dist/team/repo-aware-decomposition.d.ts +3 -0
  130. package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
  131. package/dist/team/repo-aware-decomposition.js +2 -0
  132. package/dist/team/repo-aware-decomposition.js.map +1 -1
  133. package/dist/team/runtime-cli.d.ts +32 -2
  134. package/dist/team/runtime-cli.d.ts.map +1 -1
  135. package/dist/team/runtime-cli.js +78 -26
  136. package/dist/team/runtime-cli.js.map +1 -1
  137. package/dist/team/runtime.d.ts +1 -1
  138. package/dist/team/runtime.d.ts.map +1 -1
  139. package/dist/team/runtime.js +338 -35
  140. package/dist/team/runtime.js.map +1 -1
  141. package/dist/team/state.d.ts +9 -0
  142. package/dist/team/state.d.ts.map +1 -1
  143. package/dist/team/state.js +21 -0
  144. package/dist/team/state.js.map +1 -1
  145. package/dist/team/team-identity.d.ts +26 -0
  146. package/dist/team/team-identity.d.ts.map +1 -0
  147. package/dist/team/team-identity.js +169 -0
  148. package/dist/team/team-identity.js.map +1 -0
  149. package/dist/team/tmux-session.d.ts +18 -0
  150. package/dist/team/tmux-session.d.ts.map +1 -1
  151. package/dist/team/tmux-session.js +61 -1
  152. package/dist/team/tmux-session.js.map +1 -1
  153. package/dist/team/worker-bootstrap.d.ts +2 -0
  154. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  155. package/dist/team/worker-bootstrap.js +10 -1
  156. package/dist/team/worker-bootstrap.js.map +1 -1
  157. package/package.json +1 -1
  158. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  159. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +30 -5
  160. package/skills/ai-slop-cleaner/SKILL.md +30 -5
  161. package/src/scripts/__tests__/codex-native-hook.test.ts +398 -2
  162. package/src/scripts/codex-native-hook.ts +115 -5
  163. package/src/scripts/codex-native-pre-post.ts +121 -0
  164. package/src/scripts/notify-hook/team-worker-posttooluse.ts +1 -1
  165. package/src/scripts/notify-hook.ts +1 -1
  166. package/src/scripts/sync-plugin-mirror.ts +11 -2
@@ -10,6 +10,7 @@ import { readLatestTeamProgressEvidenceMs } from './progress-evidence.js';
10
10
  import { resolveCanonicalTeamStateRoot } from './state-root.js';
11
11
  import { buildLeaderMailboxTriggerDirective, buildMailboxTriggerDirective } from './worker-bootstrap.js';
12
12
  import { teamBroadcast as broadcastMessage, teamListMailbox as listMailboxMessages, teamMarkMessageDelivered as markMessageDelivered, teamMarkMessageNotified as markMessageNotified, teamListDispatchRequests, teamMarkDispatchRequestNotified, teamMarkDispatchRequestDelivered, teamCreateTask, teamReadTask, teamListTasks, teamUpdateTask, teamClaimTask, teamTransitionTaskStatus, teamReleaseTaskClaim, teamCleanup, teamReadConfig, teamReadManifest, teamReadWorkerStatus, teamReadWorkerHeartbeat, teamUpdateWorkerHeartbeat, teamWriteWorkerInbox, teamWriteWorkerIdentity, teamAppendEvent, teamGetSummary, teamWriteShutdownRequest, teamReadShutdownAck, teamReadMonitorSnapshot, teamReadPhase, teamReadLeaderAttention, teamWriteMonitorSnapshot, teamReadTaskApproval, teamWriteTaskApproval, } from './team-ops.js';
13
+ import { listTeamLookupCandidates, resolveTeamNameForCurrentContext, TeamLookupAmbiguityError } from './team-identity.js';
13
14
  const TEAM_UPDATE_TASK_MUTABLE_FIELDS = new Set(['subject', 'description', 'blocked_by', 'requires_code_change']);
14
15
  const TEAM_UPDATE_TASK_REQUEST_FIELDS = new Set(['team_name', 'task_id', 'workingDirectory', ...TEAM_UPDATE_TASK_MUTABLE_FIELDS]);
15
16
  export const LEGACY_TEAM_MCP_TOOLS = [
@@ -433,9 +434,9 @@ export function buildLegacyTeamDeprecationHint(legacyName, originalArgs) {
433
434
  }
434
435
  return `Use CLI interop: omx team api ${operation} --input '${payload}' --json`;
435
436
  }
436
- function validateCommonFields(args) {
437
+ function validateCommonFields(args, options = {}) {
437
438
  const teamName = String(args.team_name || '').trim();
438
- if (teamName && !TEAM_NAME_SAFE_PATTERN.test(teamName)) {
439
+ if (!options.skipTeamName && teamName && !TEAM_NAME_SAFE_PATTERN.test(teamName)) {
439
440
  throw new Error(`Invalid team_name: "${teamName}". Must match /^[a-z0-9][a-z0-9-]{0,29}$/ (lowercase alphanumeric + hyphens, max 30 chars).`);
440
441
  }
441
442
  for (const workerField of ['worker', 'from_worker', 'to_worker']) {
@@ -449,17 +450,43 @@ function validateCommonFields(args) {
449
450
  throw new Error(`Invalid task_id: "${rawTaskId}". Must be a positive integer (digits only, max 20 digits).`);
450
451
  }
451
452
  }
453
+ function normalizeTeamDisplayLookupName(value) {
454
+ return value
455
+ .toLowerCase()
456
+ .replace(/[^a-z0-9]+/g, '-')
457
+ .replace(/-+/g, '-')
458
+ .replace(/^-|-$/g, '')
459
+ .slice(0, 30)
460
+ .replace(/-$/, '');
461
+ }
462
+ function assertUnsafeTeamNameMatchesKnownDisplay(rawTeamName, cwd) {
463
+ if (TEAM_NAME_SAFE_PATTERN.test(rawTeamName))
464
+ return;
465
+ const normalized = normalizeTeamDisplayLookupName(rawTeamName);
466
+ const matchesKnownDisplay = listTeamLookupCandidates(cwd).some((candidate) => {
467
+ return normalizeTeamDisplayLookupName(candidate.displayName) === normalized
468
+ || normalizeTeamDisplayLookupName(candidate.requestedName) === normalized;
469
+ });
470
+ if (!matchesKnownDisplay) {
471
+ throw new Error(`Invalid team_name: "${rawTeamName}". Must match /^[a-z0-9][a-z0-9-]{0,29}$/ or resolve to an existing display name.`);
472
+ }
473
+ }
452
474
  export async function executeTeamApiOperation(operation, args, fallbackCwd) {
453
475
  try {
454
- validateCommonFields(args);
455
- const teamNameForCwd = String(args.team_name || '').trim();
456
- const cwd = teamNameForCwd ? resolveTeamWorkingDirectory(teamNameForCwd, fallbackCwd) : fallbackCwd;
476
+ validateCommonFields(args, { skipTeamName: true });
477
+ const rawTeamNameForCwd = String(args.team_name || '').trim();
478
+ if (rawTeamNameForCwd)
479
+ assertUnsafeTeamNameMatchesKnownDisplay(rawTeamNameForCwd, fallbackCwd);
480
+ const resolvedTeamName = rawTeamNameForCwd ? resolveTeamNameForCurrentContext(rawTeamNameForCwd, fallbackCwd) : '';
481
+ const cwd = resolvedTeamName ? resolveTeamWorkingDirectory(resolvedTeamName, fallbackCwd) : fallbackCwd;
482
+ const opArgs = resolvedTeamName ? { ...args, team_name: resolvedTeamName } : args;
483
+ validateCommonFields(opArgs);
457
484
  switch (operation) {
458
485
  case 'send-message': {
459
- const teamName = String(args.team_name || '').trim();
460
- const fromWorker = String(args.from_worker || '').trim();
461
- const toWorker = String(args.to_worker || '').trim();
462
- const body = String(args.body || '').trim();
486
+ const teamName = String(opArgs.team_name || '').trim();
487
+ const fromWorker = String(opArgs.from_worker || '').trim();
488
+ const toWorker = String(opArgs.to_worker || '').trim();
489
+ const body = String(opArgs.body || '').trim();
463
490
  if (!fromWorker) {
464
491
  return { ok: false, operation, error: { code: 'invalid_input', message: 'from_worker is required. You must identify yourself.' } };
465
492
  }
@@ -525,9 +552,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
525
552
  return { ok: true, operation, data: { message, dispatch: outcome } };
526
553
  }
527
554
  case 'broadcast': {
528
- const teamName = String(args.team_name || '').trim();
529
- const fromWorker = String(args.from_worker || '').trim();
530
- const body = String(args.body || '').trim();
555
+ const teamName = String(opArgs.team_name || '').trim();
556
+ const fromWorker = String(opArgs.from_worker || '').trim();
557
+ const body = String(opArgs.body || '').trim();
531
558
  if (!teamName || !fromWorker || !body) {
532
559
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, from_worker, body are required' } };
533
560
  }
@@ -535,9 +562,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
535
562
  return { ok: true, operation, data: { count: messages.length, messages } };
536
563
  }
537
564
  case 'mailbox-list': {
538
- const teamName = String(args.team_name || '').trim();
539
- const worker = String(args.worker || '').trim();
540
- const includeDelivered = args.include_delivered !== false;
565
+ const teamName = String(opArgs.team_name || '').trim();
566
+ const worker = String(opArgs.worker || '').trim();
567
+ const includeDelivered = opArgs.include_delivered !== false;
541
568
  if (!teamName || !worker) {
542
569
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and worker are required' } };
543
570
  }
@@ -546,9 +573,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
546
573
  return { ok: true, operation, data: { worker, count: messages.length, messages } };
547
574
  }
548
575
  case 'mailbox-mark-delivered': {
549
- const teamName = String(args.team_name || '').trim();
550
- const worker = String(args.worker || '').trim();
551
- const messageId = String(args.message_id || '').trim();
576
+ const teamName = String(opArgs.team_name || '').trim();
577
+ const worker = String(opArgs.worker || '').trim();
578
+ const messageId = String(opArgs.message_id || '').trim();
552
579
  if (!teamName || !worker || !messageId) {
553
580
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, message_id are required' } };
554
581
  }
@@ -577,9 +604,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
577
604
  };
578
605
  }
579
606
  case 'mailbox-mark-notified': {
580
- const teamName = String(args.team_name || '').trim();
581
- const worker = String(args.worker || '').trim();
582
- const messageId = String(args.message_id || '').trim();
607
+ const teamName = String(opArgs.team_name || '').trim();
608
+ const worker = String(opArgs.worker || '').trim();
609
+ const messageId = String(opArgs.message_id || '').trim();
583
610
  if (!teamName || !worker || !messageId) {
584
611
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, message_id are required' } };
585
612
  }
@@ -587,23 +614,23 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
587
614
  return { ok: true, operation, data: { worker, message_id: messageId, notified } };
588
615
  }
589
616
  case 'create-task': {
590
- const teamName = String(args.team_name || '').trim();
591
- const subject = String(args.subject || '').trim();
592
- const description = String(args.description || '').trim();
617
+ const teamName = String(opArgs.team_name || '').trim();
618
+ const subject = String(opArgs.subject || '').trim();
619
+ const description = String(opArgs.description || '').trim();
593
620
  if (!teamName || !subject || !description) {
594
621
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, subject, description are required' } };
595
622
  }
596
- const owner = args.owner;
597
- const blockedBy = args.blocked_by;
598
- const requiresCodeChange = args.requires_code_change;
623
+ const owner = opArgs.owner;
624
+ const blockedBy = opArgs.blocked_by;
625
+ const requiresCodeChange = opArgs.requires_code_change;
599
626
  const task = await teamCreateTask(teamName, {
600
627
  subject, description, status: 'pending', owner: owner || undefined, blocked_by: blockedBy, requires_code_change: requiresCodeChange,
601
628
  }, cwd);
602
629
  return { ok: true, operation, data: { task } };
603
630
  }
604
631
  case 'read-task': {
605
- const teamName = String(args.team_name || '').trim();
606
- const taskId = String(args.task_id || '').trim();
632
+ const teamName = String(opArgs.team_name || '').trim();
633
+ const taskId = String(opArgs.task_id || '').trim();
607
634
  if (!teamName || !taskId) {
608
635
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and task_id are required' } };
609
636
  }
@@ -613,7 +640,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
613
640
  : { ok: false, operation, error: { code: 'task_not_found', message: 'task_not_found' } };
614
641
  }
615
642
  case 'list-tasks': {
616
- const teamName = String(args.team_name || '').trim();
643
+ const teamName = String(opArgs.team_name || '').trim();
617
644
  if (!teamName) {
618
645
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
619
646
  }
@@ -621,8 +648,8 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
621
648
  return { ok: true, operation, data: { count: tasks.length, tasks } };
622
649
  }
623
650
  case 'update-task': {
624
- const teamName = String(args.team_name || '').trim();
625
- const taskId = String(args.task_id || '').trim();
651
+ const teamName = String(opArgs.team_name || '').trim();
652
+ const taskId = String(opArgs.task_id || '').trim();
626
653
  if (!teamName || !taskId) {
627
654
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and task_id are required' } };
628
655
  }
@@ -637,26 +664,26 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
637
664
  }
638
665
  const updates = {};
639
666
  if ('subject' in args) {
640
- if (typeof args.subject !== 'string') {
667
+ if (typeof opArgs.subject !== 'string') {
641
668
  return { ok: false, operation, error: { code: 'invalid_input', message: 'subject must be a string when provided' } };
642
669
  }
643
- updates.subject = args.subject.trim();
670
+ updates.subject = opArgs.subject.trim();
644
671
  }
645
672
  if ('description' in args) {
646
- if (typeof args.description !== 'string') {
673
+ if (typeof opArgs.description !== 'string') {
647
674
  return { ok: false, operation, error: { code: 'invalid_input', message: 'description must be a string when provided' } };
648
675
  }
649
- updates.description = args.description.trim();
676
+ updates.description = opArgs.description.trim();
650
677
  }
651
678
  if ('requires_code_change' in args) {
652
- if (typeof args.requires_code_change !== 'boolean') {
679
+ if (typeof opArgs.requires_code_change !== 'boolean') {
653
680
  return { ok: false, operation, error: { code: 'invalid_input', message: 'requires_code_change must be a boolean when provided' } };
654
681
  }
655
- updates.requires_code_change = args.requires_code_change;
682
+ updates.requires_code_change = opArgs.requires_code_change;
656
683
  }
657
684
  if ('blocked_by' in args) {
658
685
  try {
659
- updates.blocked_by = parseValidatedTaskIdArray(args.blocked_by, 'blocked_by');
686
+ updates.blocked_by = parseValidatedTaskIdArray(opArgs.blocked_by, 'blocked_by');
660
687
  }
661
688
  catch (error) {
662
689
  return { ok: false, operation, error: { code: 'invalid_input', message: error.message } };
@@ -668,13 +695,13 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
668
695
  : { ok: false, operation, error: { code: 'task_not_found', message: 'task_not_found' } };
669
696
  }
670
697
  case 'claim-task': {
671
- const teamName = String(args.team_name || '').trim();
672
- const taskId = String(args.task_id || '').trim();
673
- const worker = String(args.worker || '').trim();
698
+ const teamName = String(opArgs.team_name || '').trim();
699
+ const taskId = String(opArgs.task_id || '').trim();
700
+ const worker = String(opArgs.worker || '').trim();
674
701
  if (!teamName || !taskId || !worker) {
675
702
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, task_id, worker are required' } };
676
703
  }
677
- const rawExpectedVersion = args.expected_version;
704
+ const rawExpectedVersion = opArgs.expected_version;
678
705
  if (rawExpectedVersion !== undefined && (!isFiniteInteger(rawExpectedVersion) || rawExpectedVersion < 1)) {
679
706
  return { ok: false, operation, error: { code: 'invalid_input', message: 'expected_version must be a positive integer when provided' } };
680
707
  }
@@ -682,13 +709,13 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
682
709
  return { ok: true, operation, data: result };
683
710
  }
684
711
  case 'transition-task-status': {
685
- const teamName = String(args.team_name || '').trim();
686
- const taskId = String(args.task_id || '').trim();
687
- const from = String(args.from || '').trim();
688
- const to = String(args.to || '').trim();
689
- const claimToken = String(args.claim_token || '').trim();
690
- const transitionResult = args.result;
691
- const transitionError = args.error;
712
+ const teamName = String(opArgs.team_name || '').trim();
713
+ const taskId = String(opArgs.task_id || '').trim();
714
+ const from = String(opArgs.from || '').trim();
715
+ const to = String(opArgs.to || '').trim();
716
+ const claimToken = String(opArgs.claim_token || '').trim();
717
+ const transitionResult = opArgs.result;
718
+ const transitionError = opArgs.error;
692
719
  if (!teamName || !taskId || !from || !to || !claimToken) {
693
720
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, task_id, from, to, claim_token are required' } };
694
721
  }
@@ -709,10 +736,10 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
709
736
  return { ok: true, operation, data: result };
710
737
  }
711
738
  case 'release-task-claim': {
712
- const teamName = String(args.team_name || '').trim();
713
- const taskId = String(args.task_id || '').trim();
714
- const claimToken = String(args.claim_token || '').trim();
715
- const worker = String(args.worker || '').trim();
739
+ const teamName = String(opArgs.team_name || '').trim();
740
+ const taskId = String(opArgs.task_id || '').trim();
741
+ const claimToken = String(opArgs.claim_token || '').trim();
742
+ const worker = String(opArgs.worker || '').trim();
716
743
  if (!teamName || !taskId || !claimToken || !worker) {
717
744
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, task_id, claim_token, worker are required' } };
718
745
  }
@@ -720,7 +747,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
720
747
  return { ok: true, operation, data: result };
721
748
  }
722
749
  case 'read-config': {
723
- const teamName = String(args.team_name || '').trim();
750
+ const teamName = String(opArgs.team_name || '').trim();
724
751
  if (!teamName)
725
752
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
726
753
  const config = await teamReadConfig(teamName, cwd);
@@ -729,7 +756,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
729
756
  : { ok: false, operation, error: { code: 'team_not_found', message: 'team_not_found' } };
730
757
  }
731
758
  case 'read-manifest': {
732
- const teamName = String(args.team_name || '').trim();
759
+ const teamName = String(opArgs.team_name || '').trim();
733
760
  if (!teamName)
734
761
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
735
762
  const manifest = await teamReadManifest(teamName, cwd);
@@ -738,27 +765,27 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
738
765
  : { ok: false, operation, error: { code: 'manifest_not_found', message: 'manifest_not_found' } };
739
766
  }
740
767
  case 'read-worker-status': {
741
- const teamName = String(args.team_name || '').trim();
742
- const worker = String(args.worker || '').trim();
768
+ const teamName = String(opArgs.team_name || '').trim();
769
+ const worker = String(opArgs.worker || '').trim();
743
770
  if (!teamName || !worker)
744
771
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and worker are required' } };
745
772
  const status = await teamReadWorkerStatus(teamName, worker, cwd);
746
773
  return { ok: true, operation, data: { worker, status } };
747
774
  }
748
775
  case 'read-worker-heartbeat': {
749
- const teamName = String(args.team_name || '').trim();
750
- const worker = String(args.worker || '').trim();
776
+ const teamName = String(opArgs.team_name || '').trim();
777
+ const worker = String(opArgs.worker || '').trim();
751
778
  if (!teamName || !worker)
752
779
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and worker are required' } };
753
780
  const heartbeat = await teamReadWorkerHeartbeat(teamName, worker, cwd);
754
781
  return { ok: true, operation, data: { worker, heartbeat } };
755
782
  }
756
783
  case 'update-worker-heartbeat': {
757
- const teamName = String(args.team_name || '').trim();
758
- const worker = String(args.worker || '').trim();
759
- const pid = args.pid;
760
- const turnCount = args.turn_count;
761
- const alive = args.alive;
784
+ const teamName = String(opArgs.team_name || '').trim();
785
+ const worker = String(opArgs.worker || '').trim();
786
+ const pid = opArgs.pid;
787
+ const turnCount = opArgs.turn_count;
788
+ const alive = opArgs.alive;
762
789
  if (!teamName || !worker || typeof pid !== 'number' || typeof turnCount !== 'number' || typeof alive !== 'boolean') {
763
790
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, pid, turn_count, alive are required' } };
764
791
  }
@@ -766,9 +793,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
766
793
  return { ok: true, operation, data: { worker } };
767
794
  }
768
795
  case 'write-worker-inbox': {
769
- const teamName = String(args.team_name || '').trim();
770
- const worker = String(args.worker || '').trim();
771
- const content = String(args.content || '').trim();
796
+ const teamName = String(opArgs.team_name || '').trim();
797
+ const worker = String(opArgs.worker || '').trim();
798
+ const content = String(opArgs.content || '').trim();
772
799
  if (!teamName || !worker || !content) {
773
800
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, content are required' } };
774
801
  }
@@ -776,10 +803,10 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
776
803
  return { ok: true, operation, data: { worker } };
777
804
  }
778
805
  case 'write-worker-identity': {
779
- const teamName = String(args.team_name || '').trim();
780
- const worker = String(args.worker || '').trim();
781
- const index = args.index;
782
- const role = String(args.role || '').trim();
806
+ const teamName = String(opArgs.team_name || '').trim();
807
+ const worker = String(opArgs.worker || '').trim();
808
+ const index = opArgs.index;
809
+ const role = String(opArgs.role || '').trim();
783
810
  if (!teamName || !worker || typeof index !== 'number' || !role) {
784
811
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, index, role are required' } };
785
812
  }
@@ -787,21 +814,21 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
787
814
  name: worker,
788
815
  index,
789
816
  role,
790
- assigned_tasks: args.assigned_tasks ?? [],
791
- pid: args.pid,
792
- pane_id: args.pane_id,
793
- working_dir: args.working_dir,
794
- worktree_path: args.worktree_path,
795
- worktree_branch: args.worktree_branch,
796
- worktree_detached: args.worktree_detached,
797
- team_state_root: args.team_state_root,
817
+ assigned_tasks: opArgs.assigned_tasks ?? [],
818
+ pid: opArgs.pid,
819
+ pane_id: opArgs.pane_id,
820
+ working_dir: opArgs.working_dir,
821
+ worktree_path: opArgs.worktree_path,
822
+ worktree_branch: opArgs.worktree_branch,
823
+ worktree_detached: opArgs.worktree_detached,
824
+ team_state_root: opArgs.team_state_root,
798
825
  }, cwd);
799
826
  return { ok: true, operation, data: { worker } };
800
827
  }
801
828
  case 'append-event': {
802
- const teamName = String(args.team_name || '').trim();
803
- const eventType = String(args.type || '').trim();
804
- const worker = String(args.worker || '').trim();
829
+ const teamName = String(opArgs.team_name || '').trim();
830
+ const eventType = String(opArgs.type || '').trim();
831
+ const worker = String(opArgs.worker || '').trim();
805
832
  if (!teamName || !eventType || !worker) {
806
833
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, type, worker are required' } };
807
834
  }
@@ -811,29 +838,29 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
811
838
  const event = await teamAppendEvent(teamName, {
812
839
  type: eventType,
813
840
  worker,
814
- task_id: args.task_id,
815
- message_id: args.message_id ?? null,
816
- reason: args.reason,
817
- state: args.state,
818
- prev_state: args.prev_state,
819
- to_worker: args.to_worker,
820
- worker_count: typeof args.worker_count === 'number' ? args.worker_count : undefined,
821
- source_type: args.source_type,
822
- metadata: parseOptionalMetadata(args.metadata),
841
+ task_id: opArgs.task_id,
842
+ message_id: opArgs.message_id ?? null,
843
+ reason: opArgs.reason,
844
+ state: opArgs.state,
845
+ prev_state: opArgs.prev_state,
846
+ to_worker: opArgs.to_worker,
847
+ worker_count: typeof opArgs.worker_count === 'number' ? opArgs.worker_count : undefined,
848
+ source_type: opArgs.source_type,
849
+ metadata: parseOptionalMetadata(opArgs.metadata),
823
850
  }, cwd);
824
851
  return { ok: true, operation, data: { event } };
825
852
  }
826
853
  case 'read-events': {
827
- const teamName = String(args.team_name || '').trim();
854
+ const teamName = String(opArgs.team_name || '').trim();
828
855
  if (!teamName) {
829
856
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
830
857
  }
831
- const wakeableOnly = parseOptionalBoolean(args.wakeable_only, 'wakeable_only');
832
- const eventType = parseOptionalEventType(args.type);
833
- const worker = typeof args.worker === 'string' ? args.worker.trim() : '';
834
- const taskId = typeof args.task_id === 'string' ? args.task_id.trim() : '';
858
+ const wakeableOnly = parseOptionalBoolean(opArgs.wakeable_only, 'wakeable_only');
859
+ const eventType = parseOptionalEventType(opArgs.type);
860
+ const worker = typeof opArgs.worker === 'string' ? opArgs.worker.trim() : '';
861
+ const taskId = typeof opArgs.task_id === 'string' ? opArgs.task_id.trim() : '';
835
862
  const events = await readTeamEvents(teamName, cwd, {
836
- afterEventId: typeof args.after_event_id === 'string' ? args.after_event_id.trim() || undefined : undefined,
863
+ afterEventId: typeof opArgs.after_event_id === 'string' ? opArgs.after_event_id.trim() || undefined : undefined,
837
864
  wakeableOnly: wakeableOnly ?? false,
838
865
  type: eventType ?? undefined,
839
866
  worker: worker || undefined,
@@ -844,24 +871,24 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
844
871
  operation,
845
872
  data: {
846
873
  count: events.length,
847
- cursor: events.at(-1)?.event_id ?? (typeof args.after_event_id === 'string' ? args.after_event_id.trim() : ''),
874
+ cursor: events.at(-1)?.event_id ?? (typeof opArgs.after_event_id === 'string' ? opArgs.after_event_id.trim() : ''),
848
875
  events,
849
876
  },
850
877
  };
851
878
  }
852
879
  case 'await-event': {
853
- const teamName = String(args.team_name || '').trim();
880
+ const teamName = String(opArgs.team_name || '').trim();
854
881
  if (!teamName) {
855
882
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
856
883
  }
857
- const timeoutMs = parseOptionalNonNegativeInteger(args.timeout_ms, 'timeout_ms') ?? 30_000;
858
- const pollMs = parseOptionalNonNegativeInteger(args.poll_ms, 'poll_ms');
859
- const wakeableOnly = parseOptionalBoolean(args.wakeable_only, 'wakeable_only');
860
- const eventType = parseOptionalEventType(args.type);
861
- const worker = typeof args.worker === 'string' ? args.worker.trim() : '';
862
- const taskId = typeof args.task_id === 'string' ? args.task_id.trim() : '';
884
+ const timeoutMs = parseOptionalNonNegativeInteger(opArgs.timeout_ms, 'timeout_ms') ?? 30_000;
885
+ const pollMs = parseOptionalNonNegativeInteger(opArgs.poll_ms, 'poll_ms');
886
+ const wakeableOnly = parseOptionalBoolean(opArgs.wakeable_only, 'wakeable_only');
887
+ const eventType = parseOptionalEventType(opArgs.type);
888
+ const worker = typeof opArgs.worker === 'string' ? opArgs.worker.trim() : '';
889
+ const taskId = typeof opArgs.task_id === 'string' ? opArgs.task_id.trim() : '';
863
890
  const result = await waitForTeamEvent(teamName, cwd, {
864
- afterEventId: typeof args.after_event_id === 'string' ? args.after_event_id.trim() || undefined : undefined,
891
+ afterEventId: typeof opArgs.after_event_id === 'string' ? opArgs.after_event_id.trim() || undefined : undefined,
865
892
  timeoutMs,
866
893
  pollMs: pollMs ?? undefined,
867
894
  wakeableOnly: wakeableOnly ?? false,
@@ -880,7 +907,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
880
907
  };
881
908
  }
882
909
  case 'read-idle-state': {
883
- const teamName = String(args.team_name || '').trim();
910
+ const teamName = String(opArgs.team_name || '').trim();
884
911
  if (!teamName) {
885
912
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
886
913
  }
@@ -900,7 +927,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
900
927
  };
901
928
  }
902
929
  case 'read-stall-state': {
903
- const teamName = String(args.team_name || '').trim();
930
+ const teamName = String(opArgs.team_name || '').trim();
904
931
  if (!teamName) {
905
932
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
906
933
  }
@@ -943,7 +970,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
943
970
  };
944
971
  }
945
972
  case 'get-summary': {
946
- const teamName = String(args.team_name || '').trim();
973
+ const teamName = String(opArgs.team_name || '').trim();
947
974
  if (!teamName)
948
975
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
949
976
  const summary = await teamGetSummary(teamName, cwd);
@@ -952,7 +979,7 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
952
979
  : { ok: false, operation, error: { code: 'team_not_found', message: 'team_not_found' } };
953
980
  }
954
981
  case 'cleanup': {
955
- const teamName = String(args.team_name || '').trim();
982
+ const teamName = String(opArgs.team_name || '').trim();
956
983
  if (!teamName)
957
984
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
958
985
  const force = args.force === true;
@@ -961,16 +988,16 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
961
988
  return { ok: true, operation, data: { team_name: teamName, cleanup_mode: 'shutdown' } };
962
989
  }
963
990
  case 'orphan-cleanup': {
964
- const teamName = String(args.team_name || '').trim();
991
+ const teamName = String(opArgs.team_name || '').trim();
965
992
  if (!teamName)
966
993
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
967
994
  await teamCleanup(teamName, cwd);
968
995
  return { ok: true, operation, data: { team_name: teamName, cleanup_mode: 'orphan_cleanup' } };
969
996
  }
970
997
  case 'write-shutdown-request': {
971
- const teamName = String(args.team_name || '').trim();
972
- const worker = String(args.worker || '').trim();
973
- const requestedBy = String(args.requested_by || '').trim();
998
+ const teamName = String(opArgs.team_name || '').trim();
999
+ const worker = String(opArgs.worker || '').trim();
1000
+ const requestedBy = String(opArgs.requested_by || '').trim();
974
1001
  if (!teamName || !worker || !requestedBy) {
975
1002
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, worker, requested_by are required' } };
976
1003
  }
@@ -978,24 +1005,24 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
978
1005
  return { ok: true, operation, data: { worker } };
979
1006
  }
980
1007
  case 'read-shutdown-ack': {
981
- const teamName = String(args.team_name || '').trim();
982
- const worker = String(args.worker || '').trim();
1008
+ const teamName = String(opArgs.team_name || '').trim();
1009
+ const worker = String(opArgs.worker || '').trim();
983
1010
  if (!teamName || !worker) {
984
1011
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and worker are required' } };
985
1012
  }
986
- const ack = await teamReadShutdownAck(teamName, worker, cwd, args.min_updated_at);
1013
+ const ack = await teamReadShutdownAck(teamName, worker, cwd, opArgs.min_updated_at);
987
1014
  return { ok: true, operation, data: { worker, ack } };
988
1015
  }
989
1016
  case 'read-monitor-snapshot': {
990
- const teamName = String(args.team_name || '').trim();
1017
+ const teamName = String(opArgs.team_name || '').trim();
991
1018
  if (!teamName)
992
1019
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name is required' } };
993
1020
  const snapshot = await teamReadMonitorSnapshot(teamName, cwd);
994
1021
  return { ok: true, operation, data: { snapshot } };
995
1022
  }
996
1023
  case 'write-monitor-snapshot': {
997
- const teamName = String(args.team_name || '').trim();
998
- const snapshot = args.snapshot;
1024
+ const teamName = String(opArgs.team_name || '').trim();
1025
+ const snapshot = opArgs.snapshot;
999
1026
  if (!teamName || !snapshot) {
1000
1027
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and snapshot are required' } };
1001
1028
  }
@@ -1003,8 +1030,8 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
1003
1030
  return { ok: true, operation, data: {} };
1004
1031
  }
1005
1032
  case 'read-task-approval': {
1006
- const teamName = String(args.team_name || '').trim();
1007
- const taskId = String(args.task_id || '').trim();
1033
+ const teamName = String(opArgs.team_name || '').trim();
1034
+ const taskId = String(opArgs.task_id || '').trim();
1008
1035
  if (!teamName || !taskId) {
1009
1036
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name and task_id are required' } };
1010
1037
  }
@@ -1012,18 +1039,18 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
1012
1039
  return { ok: true, operation, data: { approval } };
1013
1040
  }
1014
1041
  case 'write-task-approval': {
1015
- const teamName = String(args.team_name || '').trim();
1016
- const taskId = String(args.task_id || '').trim();
1017
- const status = String(args.status || '').trim();
1018
- const reviewer = String(args.reviewer || '').trim();
1019
- const decisionReason = String(args.decision_reason || '').trim();
1042
+ const teamName = String(opArgs.team_name || '').trim();
1043
+ const taskId = String(opArgs.task_id || '').trim();
1044
+ const status = String(opArgs.status || '').trim();
1045
+ const reviewer = String(opArgs.reviewer || '').trim();
1046
+ const decisionReason = String(opArgs.decision_reason || '').trim();
1020
1047
  if (!teamName || !taskId || !status || !reviewer || !decisionReason) {
1021
1048
  return { ok: false, operation, error: { code: 'invalid_input', message: 'team_name, task_id, status, reviewer, decision_reason are required' } };
1022
1049
  }
1023
1050
  if (!TEAM_TASK_APPROVAL_STATUSES.includes(status)) {
1024
1051
  return { ok: false, operation, error: { code: 'invalid_input', message: `status must be one of: ${TEAM_TASK_APPROVAL_STATUSES.join(', ')}` } };
1025
1052
  }
1026
- const rawRequired = args.required;
1053
+ const rawRequired = opArgs.required;
1027
1054
  if (rawRequired !== undefined && typeof rawRequired !== 'boolean') {
1028
1055
  return { ok: false, operation, error: { code: 'invalid_input', message: 'required must be a boolean when provided' } };
1029
1056
  }
@@ -1040,6 +1067,9 @@ export async function executeTeamApiOperation(operation, args, fallbackCwd) {
1040
1067
  }
1041
1068
  }
1042
1069
  catch (error) {
1070
+ if (error instanceof TeamLookupAmbiguityError) {
1071
+ return { ok: false, operation, error: { code: 'ambiguous_team_name', message: error.message, details: { candidates: error.candidates } } };
1072
+ }
1043
1073
  return {
1044
1074
  ok: false,
1045
1075
  operation,