oh-my-copilot 4.13.73 → 4.13.79

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 (60) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bridge/cli.cjs +198 -66
  4. package/bridge/runtime-cli.cjs +68 -4
  5. package/bridge/team.js +85 -5
  6. package/dist/__tests__/hud-cache-wrapper.test.js +3 -1
  7. package/dist/__tests__/hud-cache-wrapper.test.js.map +1 -1
  8. package/dist/__tests__/pre-tool-enforcer.test.js +45 -0
  9. package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -1
  10. package/dist/cli/__tests__/launch.test.js +118 -3
  11. package/dist/cli/__tests__/launch.test.js.map +1 -1
  12. package/dist/cli/__tests__/tmux-clipboard.test.d.ts +2 -0
  13. package/dist/cli/__tests__/tmux-clipboard.test.d.ts.map +1 -0
  14. package/dist/cli/__tests__/tmux-clipboard.test.js +66 -0
  15. package/dist/cli/__tests__/tmux-clipboard.test.js.map +1 -0
  16. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  17. package/dist/cli/autoresearch-guided.js +9 -0
  18. package/dist/cli/autoresearch-guided.js.map +1 -1
  19. package/dist/cli/commands/__tests__/team-role-shorthand.test.js +2 -2
  20. package/dist/cli/commands/__tests__/team-role-shorthand.test.js.map +1 -1
  21. package/dist/cli/commands/__tests__/team.test.js +83 -1
  22. package/dist/cli/commands/__tests__/team.test.js.map +1 -1
  23. package/dist/cli/commands/team.d.ts +12 -1
  24. package/dist/cli/commands/team.d.ts.map +1 -1
  25. package/dist/cli/commands/team.js +72 -38
  26. package/dist/cli/commands/team.js.map +1 -1
  27. package/dist/cli/launch.d.ts.map +1 -1
  28. package/dist/cli/launch.js +33 -1
  29. package/dist/cli/launch.js.map +1 -1
  30. package/dist/cli/tmux-clipboard.d.ts +9 -0
  31. package/dist/cli/tmux-clipboard.d.ts.map +1 -0
  32. package/dist/cli/tmux-clipboard.js +42 -0
  33. package/dist/cli/tmux-clipboard.js.map +1 -0
  34. package/dist/installer/__tests__/hud-cache-wrapper.test.js +33 -2
  35. package/dist/installer/__tests__/hud-cache-wrapper.test.js.map +1 -1
  36. package/dist/team/__tests__/api-interop.cwd-resolution.test.js +24 -0
  37. package/dist/team/__tests__/api-interop.cwd-resolution.test.js.map +1 -1
  38. package/dist/team/__tests__/runtime-v2.dispatch.test.js +27 -2
  39. package/dist/team/__tests__/runtime-v2.dispatch.test.js.map +1 -1
  40. package/dist/team/__tests__/tmux-session.create-team.test.js +4 -0
  41. package/dist/team/__tests__/tmux-session.create-team.test.js.map +1 -1
  42. package/dist/team/__tests__/tmux-session.test.js +34 -1
  43. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  44. package/dist/team/__tests__/worker-canonicalization.test.js +11 -0
  45. package/dist/team/__tests__/worker-canonicalization.test.js.map +1 -1
  46. package/dist/team/runtime-v2.d.ts.map +1 -1
  47. package/dist/team/runtime-v2.js +19 -1
  48. package/dist/team/runtime-v2.js.map +1 -1
  49. package/dist/team/team-ops.d.ts.map +1 -1
  50. package/dist/team/team-ops.js +19 -1
  51. package/dist/team/team-ops.js.map +1 -1
  52. package/dist/team/tmux-session.d.ts.map +1 -1
  53. package/dist/team/tmux-session.js +19 -1
  54. package/dist/team/tmux-session.js.map +1 -1
  55. package/dist/team/worker-canonicalization.js +1 -1
  56. package/dist/team/worker-canonicalization.js.map +1 -1
  57. package/docs/copilot-instructions.md +1 -1
  58. package/package.json +1 -1
  59. package/scripts/lib/hud-cache-wrapper.sh +33 -23
  60. package/scripts/pre-tool-enforcer.mjs +3 -0
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "oh-my-copilot",
12
12
  "description": "Copilot CLI native multi-agent orchestration with intelligent model routing, 18 agent variants, and 32 powerful skills. Zero learning curve. Maximum power.",
13
- "version": "4.13.73",
13
+ "version": "4.13.79",
14
14
  "author": {
15
15
  "name": "Robin Norberg",
16
16
  "email": "github@platypus.se"
@@ -27,5 +27,5 @@
27
27
  ]
28
28
  }
29
29
  ],
30
- "version": "4.13.73"
30
+ "version": "4.13.79"
31
31
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-copilot",
3
- "version": "4.13.73",
3
+ "version": "4.13.79",
4
4
  "description": "Multi-agent orchestration system for Copilot CLI",
5
5
  "author": {
6
6
  "name": "Robin Norberg and oh-my-copilot contributors"
package/bridge/cli.cjs CHANGED
@@ -20540,7 +20540,7 @@ function canonicalizeTeamConfigWorkers(config2) {
20540
20540
  return {
20541
20541
  ...config2,
20542
20542
  workers,
20543
- worker_count: workers.length
20543
+ worker_count: workers.length > 0 ? workers.length : config2.worker_count ?? 0
20544
20544
  };
20545
20545
  }
20546
20546
  var init_worker_canonicalization = __esm({
@@ -34369,6 +34369,7 @@ function isTeamTask(value) {
34369
34369
  }
34370
34370
  async function withLock(lockDir, fn) {
34371
34371
  const STALE_MS = 3e4;
34372
+ await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(lockDir), { recursive: true });
34372
34373
  try {
34373
34374
  await (0, import_promises5.mkdir)(lockDir, { recursive: false });
34374
34375
  } catch (err) {
@@ -34580,7 +34581,22 @@ async function teamClaimTask(teamName, taskId, workerName2, expectedVersion, cwd
34580
34581
  teamName,
34581
34582
  cwd,
34582
34583
  readTask: teamReadTask,
34583
- readTeamConfig: teamReadConfig,
34584
+ readTeamConfig: (async (tn, c) => {
34585
+ const cfg = await teamReadConfig(tn, c);
34586
+ if (!cfg) return null;
34587
+ if (cfg.workers.length > 0) return cfg;
34588
+ const match = /^worker-(\d+)$/.exec(workerName2);
34589
+ const workerIndex = match ? Number.parseInt(match[1], 10) : 0;
34590
+ if (workerIndex >= 1 && workerIndex <= (cfg.worker_count ?? 0)) {
34591
+ return {
34592
+ ...cfg,
34593
+ workers: Array.from({ length: cfg.worker_count ?? 0 }, (_, index) => ({
34594
+ name: `worker-${index + 1}`
34595
+ }))
34596
+ };
34597
+ }
34598
+ return cfg;
34599
+ }),
34584
34600
  withTaskClaimLock,
34585
34601
  normalizeTask,
34586
34602
  isTerminalTaskStatus: isTerminalTeamTaskStatus,
@@ -35548,6 +35564,50 @@ var init_model_contract = __esm({
35548
35564
  }
35549
35565
  });
35550
35566
 
35567
+ // src/cli/tmux-clipboard.ts
35568
+ function hasUniversalClipboardTerminalFeature(features) {
35569
+ return features.split(/\r?\n|,/).map((feature) => feature.trim()).some((feature) => feature === UNIVERSAL_CLIPBOARD_FEATURE || feature.startsWith(`${UNIVERSAL_CLIPBOARD_FEATURE}:`));
35570
+ }
35571
+ function configureTmuxClipboardForSession(sessionName2, opts) {
35572
+ tmuxExec(["set-option", "-t", sessionName2, "set-clipboard", "on"], opts);
35573
+ let terminalFeatures = "";
35574
+ try {
35575
+ terminalFeatures = String(tmuxExec(["show-options", "-t", sessionName2, "-v", "terminal-features"], opts) ?? "");
35576
+ } catch {
35577
+ terminalFeatures = "";
35578
+ }
35579
+ if (!hasUniversalClipboardTerminalFeature(terminalFeatures)) {
35580
+ tmuxExec(["set-option", "-at", sessionName2, "terminal-features", `,${UNIVERSAL_CLIPBOARD_FEATURE}`], opts);
35581
+ }
35582
+ }
35583
+ function configureTmuxClipboardForCurrentSession(opts) {
35584
+ const sessionName2 = String(tmuxExec(["display-message", "-p", "#S"], opts) ?? "").trim();
35585
+ if (sessionName2) {
35586
+ configureTmuxClipboardForSession(sessionName2, opts);
35587
+ }
35588
+ }
35589
+ async function configureTmuxClipboardForSessionAsync(sessionName2, opts) {
35590
+ await tmuxExecAsync(["set-option", "-t", sessionName2, "set-clipboard", "on"], opts);
35591
+ let terminalFeatures = "";
35592
+ try {
35593
+ const result = await tmuxExecAsync(["show-options", "-t", sessionName2, "-v", "terminal-features"], opts);
35594
+ terminalFeatures = String(result.stdout ?? "");
35595
+ } catch {
35596
+ terminalFeatures = "";
35597
+ }
35598
+ if (!hasUniversalClipboardTerminalFeature(terminalFeatures)) {
35599
+ await tmuxExecAsync(["set-option", "-at", sessionName2, "terminal-features", `,${UNIVERSAL_CLIPBOARD_FEATURE}`], opts);
35600
+ }
35601
+ }
35602
+ var UNIVERSAL_CLIPBOARD_FEATURE;
35603
+ var init_tmux_clipboard = __esm({
35604
+ "src/cli/tmux-clipboard.ts"() {
35605
+ "use strict";
35606
+ init_tmux_utils();
35607
+ UNIVERSAL_CLIPBOARD_FEATURE = "*:clipboard";
35608
+ }
35609
+ });
35610
+
35551
35611
  // src/team/tmux-session.ts
35552
35612
  var tmux_session_exports = {};
35553
35613
  __export(tmux_session_exports, {
@@ -35809,6 +35869,10 @@ function createSession(teamName, workerName2, workingDirectory) {
35809
35869
  args.push("-c", workingDirectory);
35810
35870
  }
35811
35871
  tmuxExec(args, { stripTmux: true, stdio: "pipe", timeout: 5e3 });
35872
+ try {
35873
+ configureTmuxClipboardForSession(name, { stripTmux: true, stdio: "pipe", timeout: 5e3 });
35874
+ } catch {
35875
+ }
35812
35876
  return name;
35813
35877
  }
35814
35878
  function killSession(teamName, workerName2) {
@@ -35935,6 +35999,10 @@ async function createTeamSession(teamName, workerCount, cwd, options = {}) {
35935
35999
  }
35936
36000
  const teamTarget = sessionAndWindow;
35937
36001
  const resolvedSessionName = teamTarget.split(":")[0];
36002
+ try {
36003
+ await configureTmuxClipboardForSessionAsync(resolvedSessionName);
36004
+ } catch {
36005
+ }
35938
36006
  const workerPaneIds = [];
35939
36007
  if (workerCount <= 0) {
35940
36008
  try {
@@ -36017,10 +36085,11 @@ function paneHasTrustPrompt(captured) {
36017
36085
  function paneHasClaudeStartupBanner(captured) {
36018
36086
  const lines = captured.split("\n").map((line) => line.replace(/\r/g, "").trim()).filter((line) => line.length > 0).slice(-20);
36019
36087
  const lastPromptIndex = lines.findLastIndex((line) => /^\s*[›>❯]\s*/u.test(line));
36088
+ if (lastPromptIndex >= 0) return false;
36020
36089
  const lastStartupBannerIndex = lines.findLastIndex(
36021
36090
  (line) => /bypass\s+permissions\s+on/i.test(line) || /shift\+tab\s+to\s+cycle/i.test(line) || /^⏵⏵\s+/.test(line)
36022
36091
  );
36023
- return lastStartupBannerIndex >= 0 && lastStartupBannerIndex > lastPromptIndex;
36092
+ return lastStartupBannerIndex >= 0;
36024
36093
  }
36025
36094
  function paneIsBootstrapping(captured) {
36026
36095
  if (paneHasClaudeStartupBanner(captured)) return true;
@@ -36306,6 +36375,7 @@ var init_tmux_session = __esm({
36306
36375
  import_promises8 = __toESM(require("fs/promises"), 1);
36307
36376
  init_team_name();
36308
36377
  init_tmux_utils();
36378
+ init_tmux_clipboard();
36309
36379
  sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
36310
36380
  TMUX_SESSION_PREFIX = "omcp-team";
36311
36381
  SUPPORTED_POSIX_SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "fish", "ksh"]);
@@ -39345,13 +39415,27 @@ async function spawnV2Worker(opts) {
39345
39415
  };
39346
39416
  }
39347
39417
  if (opts.agentType === "claude") {
39348
- const settled = await waitForWorkerStartupEvidence(
39418
+ let settled = await waitForWorkerStartupEvidence(
39349
39419
  opts.teamName,
39350
39420
  opts.workerName,
39351
39421
  opts.taskId,
39352
39422
  opts.cwd,
39353
39423
  6
39354
39424
  );
39425
+ for (let attempt = 1; !settled && attempt <= 4; attempt++) {
39426
+ try {
39427
+ await tmuxExecAsync(["send-keys", "-t", paneId, "Enter"]);
39428
+ } catch {
39429
+ break;
39430
+ }
39431
+ settled = await waitForWorkerStartupEvidence(
39432
+ opts.teamName,
39433
+ opts.workerName,
39434
+ opts.taskId,
39435
+ opts.cwd,
39436
+ 12
39437
+ );
39438
+ }
39355
39439
  if (!settled) {
39356
39440
  return {
39357
39441
  paneId,
@@ -39505,6 +39589,7 @@ async function startTeamV2(config2) {
39505
39589
  status: "pending",
39506
39590
  owner: null,
39507
39591
  result: null,
39592
+ ...config2.tasks[i].role ? { role: config2.tasks[i].role } : {},
39508
39593
  ...config2.tasks[i].delegation ? { delegation: config2.tasks[i].delegation } : {},
39509
39594
  created_at: (/* @__PURE__ */ new Date()).toISOString()
39510
39595
  }, null, 2), "utf-8");
@@ -39540,7 +39625,8 @@ async function startTeamV2(config2) {
39540
39625
  const allocationTasks = unownedTaskIndices.map((idx) => ({
39541
39626
  id: String(idx),
39542
39627
  subject: config2.tasks[idx].subject,
39543
- description: config2.tasks[idx].description
39628
+ description: config2.tasks[idx].description,
39629
+ ...config2.tasks[idx].role ? { role: config2.tasks[idx].role } : {}
39544
39630
  }));
39545
39631
  const allocationWorkers = workerNames.map((name, i) => ({
39546
39632
  name,
@@ -51711,9 +51797,9 @@ function renderCwd(cwd, format = "relative", useHyperlinks = false) {
51711
51797
  displayPath = cwd;
51712
51798
  break;
51713
51799
  case "folder": {
51714
- const parent = (0, import_node_path13.basename)((0, import_node_path13.dirname)(cwd));
51715
- const folder = (0, import_node_path13.basename)(cwd);
51716
- displayPath = parent ? (0, import_node_path13.join)(parent, folder) : folder;
51800
+ const parent = (0, import_node_path14.basename)((0, import_node_path14.dirname)(cwd));
51801
+ const folder = (0, import_node_path14.basename)(cwd);
51802
+ displayPath = parent ? (0, import_node_path14.join)(parent, folder) : folder;
51717
51803
  break;
51718
51804
  }
51719
51805
  default:
@@ -51726,12 +51812,12 @@ function renderCwd(cwd, format = "relative", useHyperlinks = false) {
51726
51812
  }
51727
51813
  return rendered;
51728
51814
  }
51729
- var import_node_os4, import_node_path13;
51815
+ var import_node_os4, import_node_path14;
51730
51816
  var init_cwd = __esm({
51731
51817
  "src/hud/elements/cwd.ts"() {
51732
51818
  "use strict";
51733
51819
  import_node_os4 = require("node:os");
51734
- import_node_path13 = require("node:path");
51820
+ import_node_path14 = require("node:path");
51735
51821
  init_colors();
51736
51822
  }
51737
51823
  });
@@ -51755,7 +51841,7 @@ var init_hostname = __esm({
51755
51841
 
51756
51842
  // src/hud/elements/git.ts
51757
51843
  function getGitRepoName(cwd) {
51758
- const key = cwd ? (0, import_node_path14.resolve)(cwd) : process.cwd();
51844
+ const key = cwd ? (0, import_node_path15.resolve)(cwd) : process.cwd();
51759
51845
  const cached2 = repoCache.get(key);
51760
51846
  if (cached2 && Date.now() < cached2.expiresAt) {
51761
51847
  return cached2.value;
@@ -51782,7 +51868,7 @@ function getGitRepoName(cwd) {
51782
51868
  return result;
51783
51869
  }
51784
51870
  function getGitBranch(cwd) {
51785
- const key = cwd ? (0, import_node_path14.resolve)(cwd) : process.cwd();
51871
+ const key = cwd ? (0, import_node_path15.resolve)(cwd) : process.cwd();
51786
51872
  const cached2 = branchCache.get(key);
51787
51873
  if (cached2 && Date.now() < cached2.expiresAt) {
51788
51874
  return cached2.value;
@@ -51804,7 +51890,7 @@ function getGitBranch(cwd) {
51804
51890
  return result;
51805
51891
  }
51806
51892
  function getWorktreeInfo(cwd) {
51807
- const key = cwd ? (0, import_node_path14.resolve)(cwd) : process.cwd();
51893
+ const key = cwd ? (0, import_node_path15.resolve)(cwd) : process.cwd();
51808
51894
  const cached2 = worktreeCache.get(key);
51809
51895
  if (cached2 && Date.now() < cached2.expiresAt) {
51810
51896
  return cached2.value;
@@ -51820,18 +51906,18 @@ function getWorktreeInfo(cwd) {
51820
51906
  try {
51821
51907
  const gitDir = (0, import_node_child_process10.execSync)("git rev-parse --git-dir", execOpts).trim();
51822
51908
  const gitCommonDir = (0, import_node_child_process10.execSync)("git rev-parse --git-common-dir", execOpts).trim();
51823
- let resolvedGitDir = (0, import_node_path14.resolve)(key, gitDir);
51824
- let resolvedCommonDir = (0, import_node_path14.resolve)(key, gitCommonDir);
51909
+ let resolvedGitDir = (0, import_node_path15.resolve)(key, gitDir);
51910
+ let resolvedCommonDir = (0, import_node_path15.resolve)(key, gitCommonDir);
51825
51911
  try {
51826
- resolvedGitDir = (0, import_node_fs10.realpathSync)(resolvedGitDir);
51912
+ resolvedGitDir = (0, import_node_fs11.realpathSync)(resolvedGitDir);
51827
51913
  } catch {
51828
51914
  }
51829
51915
  try {
51830
- resolvedCommonDir = (0, import_node_fs10.realpathSync)(resolvedCommonDir);
51916
+ resolvedCommonDir = (0, import_node_fs11.realpathSync)(resolvedCommonDir);
51831
51917
  } catch {
51832
51918
  }
51833
51919
  if (resolvedGitDir !== resolvedCommonDir) {
51834
- result = { isWorktree: true, worktreeName: (0, import_node_path14.basename)(resolvedGitDir) };
51920
+ result = { isWorktree: true, worktreeName: (0, import_node_path15.basename)(resolvedGitDir) };
51835
51921
  }
51836
51922
  } catch {
51837
51923
  }
@@ -51853,7 +51939,7 @@ function renderGitBranch(cwd) {
51853
51939
  return `${dim("branch:")}${cyan(branch)}`;
51854
51940
  }
51855
51941
  function getGitStatusCounts(cwd) {
51856
- const key = cwd ? (0, import_node_path14.resolve)(cwd) : process.cwd();
51942
+ const key = cwd ? (0, import_node_path15.resolve)(cwd) : process.cwd();
51857
51943
  const cached2 = statusCache.get(key);
51858
51944
  if (cached2 && Date.now() < cached2.expiresAt) {
51859
51945
  return cached2.value;
@@ -51910,13 +51996,13 @@ function renderGitStatus(cwd, labels = DEFAULT_HUD_LABELS) {
51910
51996
  if (behind > 0) parts.push(`${red(labels.behind)}${behind}`);
51911
51997
  return parts.join(" ");
51912
51998
  }
51913
- var import_node_child_process10, import_node_fs10, import_node_path14, CACHE_TTL_MS3, repoCache, branchCache, worktreeCache, statusCache;
51999
+ var import_node_child_process10, import_node_fs11, import_node_path15, CACHE_TTL_MS3, repoCache, branchCache, worktreeCache, statusCache;
51914
52000
  var init_git = __esm({
51915
52001
  "src/hud/elements/git.ts"() {
51916
52002
  "use strict";
51917
52003
  import_node_child_process10 = require("node:child_process");
51918
- import_node_fs10 = require("node:fs");
51919
- import_node_path14 = require("node:path");
52004
+ import_node_fs11 = require("node:fs");
52005
+ import_node_path15 = require("node:path");
51920
52006
  init_colors();
51921
52007
  init_types4();
51922
52008
  CACHE_TTL_MS3 = 3e4;
@@ -89095,13 +89181,15 @@ function inferDelegationPlanForTeamTask(text) {
89095
89181
 
89096
89182
  // src/cli/commands/team.ts
89097
89183
  init_loader();
89184
+ var import_node_fs8 = require("node:fs");
89185
+ var import_node_path11 = require("node:path");
89098
89186
  var HELP_TOKENS = /* @__PURE__ */ new Set(["--help", "-h", "help"]);
89099
89187
  var MIN_WORKER_COUNT = 1;
89100
89188
  var MAX_WORKER_COUNT = 20;
89101
89189
  var VALID_TEAM_CLI_AGENT_TYPES = /* @__PURE__ */ new Set(["claude", "copilot", "codex", "gemini"]);
89102
89190
  var DEFAULT_TEAM_CLI_AGENT_TYPE = "claude";
89103
89191
  var TEAM_HELP = `
89104
- Usage: omcp team [N:agent-type[:role]] [--new-window] [--auto-merge] "<task description>"
89192
+ Usage: omcp team [N:agent-type[:role]] [--new-window] [--auto-merge] [--no-decompose] "<task description>"
89105
89193
  omcp team status <team-name>
89106
89194
  omcp team shutdown <team-name> [--force]
89107
89195
  omcp team api <operation> [--input <json>] [--json]
@@ -89118,6 +89206,7 @@ Examples:
89118
89206
  omcp team api send-message --input '{"team_name":"my-team","from_worker":"worker-1","to_worker":"leader-fixed","body":"ACK"}' --json
89119
89207
 
89120
89208
  Auto-merge (v2-only):
89209
+ --no-decompose Treat the launch text as pre-authored/fixed worker scope; do not split by commas/lists.
89121
89210
  --auto-merge Enable per-commit auto-merge to leader and auto-rebase fanout.
89122
89211
  Each worker runs in a dedicated git worktree on omc-team/{team}/{worker}.
89123
89212
  Bursts of rapid worker commits coalesce to a single merge of HEAD.
@@ -89195,7 +89284,8 @@ var TEAM_API_OPERATION_NOTES = {
89195
89284
  var NUMBERED_LINE_RE = /^\s*\d+[.)]\s+(.+)$/;
89196
89285
  var BULLETED_LINE_RE = /^\s*[-*•]\s+(.+)$/;
89197
89286
  var CONJUNCTION_SPLIT_RE = /\s+(?:and|,\s*and|,)\s+/i;
89198
- function resolveTeamFanoutLimit(requestedWorkerCount, _explicitAgentType, _explicitWorkerCount, plan) {
89287
+ function resolveTeamFanoutLimit(requestedWorkerCount, _explicitAgentType, explicitWorkerCount, plan, noDecompose = false) {
89288
+ if (explicitWorkerCount !== void 0 || noDecompose) return requestedWorkerCount;
89199
89289
  if (plan.strategy === "atomic") return requestedWorkerCount;
89200
89290
  const subtaskCount = plan.subtasks.length;
89201
89291
  if (subtaskCount > 0 && subtaskCount < requestedWorkerCount) {
@@ -89240,7 +89330,20 @@ function splitTaskString(task) {
89240
89330
  };
89241
89331
  }
89242
89332
  function slugifyTask(task) {
89243
- return task.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 30) || "team-task";
89333
+ const compact = task.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
89334
+ return compact.slice(0, 30).replace(/^-|-$/g, "") || "team-task";
89335
+ }
89336
+ function resolveAvailableTeamName(baseName, cwd) {
89337
+ const sanitizedBase = slugifyTask(baseName);
89338
+ const stateRoot2 = (0, import_node_path11.join)(cwd, ".omcp", "state", "team");
89339
+ const teamDir2 = (name) => (0, import_node_path11.join)(stateRoot2, name);
89340
+ if (!(0, import_node_fs8.existsSync)(teamDir2(sanitizedBase))) return sanitizedBase;
89341
+ for (let suffix = 2; suffix <= 99; suffix++) {
89342
+ const suffixText = `-${suffix}`;
89343
+ const candidate = `${sanitizedBase.slice(0, 30 - suffixText.length).replace(/-$/g, "")}${suffixText}`;
89344
+ if (!(0, import_node_fs8.existsSync)(teamDir2(candidate))) return candidate;
89345
+ }
89346
+ throw new Error(`Unable to allocate a fresh team name for ${sanitizedBase}; remove stale .omcp/state/team entries or choose a more specific launch task.`);
89244
89347
  }
89245
89348
  function getTeamWorkerIdentityFromEnv(env2 = process.env) {
89246
89349
  const omg = typeof env2.OMC_TEAM_WORKER === "string" ? env2.OMC_TEAM_WORKER.trim() : "";
@@ -89280,6 +89383,7 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89280
89383
  let json2 = false;
89281
89384
  let newWindow = false;
89282
89385
  let autoMerge = process.env.OMC_TEAMS_AUTO_MERGE === "1";
89386
+ let noDecompose = false;
89283
89387
  const normalizedDefaultAgentType = VALID_TEAM_CLI_AGENT_TYPES.has(defaultAgentType) ? defaultAgentType : DEFAULT_TEAM_CLI_AGENT_TYPE;
89284
89388
  const filteredArgs = [];
89285
89389
  for (const arg of args) {
@@ -89289,6 +89393,8 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89289
89393
  newWindow = true;
89290
89394
  } else if (arg === "--auto-merge") {
89291
89395
  autoMerge = true;
89396
+ } else if (arg === "--no-decompose" || arg === "--fixed-workers" || arg === "--preformed-plan") {
89397
+ noDecompose = true;
89292
89398
  } else {
89293
89399
  filteredArgs.push(arg);
89294
89400
  }
@@ -89296,6 +89402,7 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89296
89402
  const first = filteredArgs[0] || "";
89297
89403
  let role;
89298
89404
  let specMatched = false;
89405
+ let explicitWorkerSpec = false;
89299
89406
  if (first.includes(",")) {
89300
89407
  const segments = first.split(",");
89301
89408
  const parsedSegments = [];
@@ -89324,6 +89431,7 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89324
89431
  const uniqueRoles = [...new Set(roles)];
89325
89432
  if (uniqueRoles.length === 1 && uniqueRoles[0]) role = uniqueRoles[0];
89326
89433
  specMatched = true;
89434
+ explicitWorkerSpec = true;
89327
89435
  filteredArgs.shift();
89328
89436
  }
89329
89437
  }
@@ -89338,6 +89446,7 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89338
89446
  agentType: normalized.agentType,
89339
89447
  ...role ? { role } : {}
89340
89448
  }));
89449
+ explicitWorkerSpec = true;
89341
89450
  filteredArgs.shift();
89342
89451
  }
89343
89452
  }
@@ -89350,7 +89459,32 @@ function parseTeamArgs(tokens, defaultAgentType = "copilot") {
89350
89459
  throw new Error('Usage: omcp team [N:agent-type] "<task description>"');
89351
89460
  }
89352
89461
  const teamName = slugifyTask(task);
89353
- return { workerCount, agentTypes, workerSpecs, role, task, teamName, json: json2, newWindow, autoMerge };
89462
+ return { workerCount, agentTypes, workerSpecs, role, task, teamName, json: json2, newWindow, autoMerge, explicitWorkerSpec, noDecompose };
89463
+ }
89464
+ function buildTeamLaunchTasks(parsed, decomposition, effectiveWorkerCount) {
89465
+ const tasks = [];
89466
+ if (parsed.explicitWorkerSpec && !parsed.noDecompose && decomposition.strategy !== "atomic" && decomposition.subtasks.length > 1 && decomposition.subtasks.length !== effectiveWorkerCount) {
89467
+ throw new Error(
89468
+ `Pre-authored task scope count (${decomposition.subtasks.length}) must match explicit worker count (${effectiveWorkerCount}); use --no-decompose to give every worker the full launch text.`
89469
+ );
89470
+ }
89471
+ const canUseDecomposition = !parsed.noDecompose && decomposition.strategy !== "atomic" && decomposition.subtasks.length > 1 && (!parsed.explicitWorkerSpec || decomposition.subtasks.length === effectiveWorkerCount);
89472
+ for (let i = 0; i < effectiveWorkerCount; i++) {
89473
+ const workerSpec = parsed.workerSpecs[i];
89474
+ const roleLabel = workerSpec?.role ? ` (${workerSpec.role})` : "";
89475
+ const source = canUseDecomposition ? decomposition.subtasks[i] : void 0;
89476
+ const description = source?.description ?? parsed.task;
89477
+ const subject = source?.subject ?? (effectiveWorkerCount === 1 ? parsed.task.slice(0, 80) : `Worker ${i + 1}${roleLabel}: ${parsed.task}`.slice(0, 80));
89478
+ const delegation = inferDelegationPlanForTeamTask(description);
89479
+ tasks.push({
89480
+ subject,
89481
+ description,
89482
+ owner: `worker-${i + 1}`,
89483
+ ...workerSpec?.role ? { role: workerSpec.role } : {},
89484
+ ...delegation ? { delegation } : {}
89485
+ });
89486
+ }
89487
+ return tasks;
89354
89488
  }
89355
89489
  function sampleValueForField(field) {
89356
89490
  switch (field) {
@@ -89499,32 +89633,12 @@ async function handleTeamStart(parsed, cwd) {
89499
89633
  const effectiveWorkerCount = resolveTeamFanoutLimit(
89500
89634
  parsed.workerCount,
89501
89635
  parsed.agentTypes[0],
89502
- parsed.workerCount,
89503
- decomposition
89636
+ parsed.explicitWorkerSpec ? parsed.workerCount : void 0,
89637
+ decomposition,
89638
+ parsed.noDecompose
89504
89639
  );
89505
- const tasks = [];
89506
- if (decomposition.strategy !== "atomic" && decomposition.subtasks.length > 1) {
89507
- const subtasks = decomposition.subtasks.slice(0, effectiveWorkerCount);
89508
- for (let i = 0; i < subtasks.length; i++) {
89509
- const delegation = inferDelegationPlanForTeamTask(subtasks[i].description);
89510
- tasks.push({
89511
- subject: subtasks[i].subject,
89512
- description: subtasks[i].description,
89513
- owner: `worker-${i + 1}`,
89514
- ...delegation ? { delegation } : {}
89515
- });
89516
- }
89517
- } else {
89518
- for (let i = 0; i < effectiveWorkerCount; i++) {
89519
- const delegation = inferDelegationPlanForTeamTask(parsed.task);
89520
- tasks.push({
89521
- subject: effectiveWorkerCount === 1 ? parsed.task.slice(0, 80) : `Worker ${i + 1}: ${parsed.task}`.slice(0, 80),
89522
- description: parsed.task,
89523
- owner: `worker-${i + 1}`,
89524
- ...delegation ? { delegation } : {}
89525
- });
89526
- }
89527
- }
89640
+ const tasks = buildTeamLaunchTasks(parsed, decomposition, effectiveWorkerCount);
89641
+ const launchTeamName = resolveAvailableTeamName(parsed.teamName, cwd);
89528
89642
  let rolePrompt;
89529
89643
  if (parsed.role) {
89530
89644
  const { loadAgentPrompt: loadAgentPrompt2 } = await Promise.resolve().then(() => (init_utils(), utils_exports));
@@ -89534,7 +89648,7 @@ async function handleTeamStart(parsed, cwd) {
89534
89648
  if (isRuntimeV2Enabled2()) {
89535
89649
  const { startTeamV2: startTeamV22, monitorTeamV2: monitorTeamV22 } = await Promise.resolve().then(() => (init_runtime_v2(), runtime_v2_exports));
89536
89650
  const runtime2 = await startTeamV22({
89537
- teamName: parsed.teamName,
89651
+ teamName: launchTeamName,
89538
89652
  workerCount: effectiveWorkerCount,
89539
89653
  agentTypes: parsed.agentTypes.slice(0, effectiveWorkerCount),
89540
89654
  tasks,
@@ -89568,7 +89682,7 @@ async function handleTeamStart(parsed, cwd) {
89568
89682
  }
89569
89683
  const { startTeam: startTeam2, monitorTeam: monitorTeam2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
89570
89684
  const runtime = await startTeam2({
89571
- teamName: parsed.teamName,
89685
+ teamName: launchTeamName,
89572
89686
  workerCount: effectiveWorkerCount,
89573
89687
  agentTypes: parsed.agentTypes.slice(0, effectiveWorkerCount),
89574
89688
  tasks,
@@ -89741,9 +89855,9 @@ async function teamCommand(args) {
89741
89855
  var import_promises18 = require("node:fs/promises");
89742
89856
 
89743
89857
  // src/goal-workflows/claude-goal-snapshot.ts
89744
- var import_node_fs8 = require("node:fs");
89858
+ var import_node_fs9 = require("node:fs");
89745
89859
  var import_promises16 = require("node:fs/promises");
89746
- var import_node_path11 = require("node:path");
89860
+ var import_node_path12 = require("node:path");
89747
89861
  var ClaudeGoalSnapshotError = class extends Error {
89748
89862
  };
89749
89863
  function safeObject(value) {
@@ -89796,8 +89910,8 @@ async function readClaudeGoalSnapshotInput(raw, cwd = process.cwd()) {
89796
89910
  try {
89797
89911
  return parseClaudeGoalSnapshot(JSON.parse(trimmed));
89798
89912
  } catch {
89799
- const path22 = (0, import_node_path11.resolve)(cwd, trimmed);
89800
- if (!(0, import_node_fs8.existsSync)(path22)) {
89913
+ const path22 = (0, import_node_path12.resolve)(cwd, trimmed);
89914
+ if (!(0, import_node_fs9.existsSync)(path22)) {
89801
89915
  throw new ClaudeGoalSnapshotError(`Claude goal snapshot is neither valid JSON nor a readable path: ${trimmed}`);
89802
89916
  }
89803
89917
  try {
@@ -89840,9 +89954,9 @@ function formatClaudeGoalReconciliation(reconciliation) {
89840
89954
  }
89841
89955
 
89842
89956
  // src/ultragoal/artifacts.ts
89843
- var import_node_fs9 = require("node:fs");
89957
+ var import_node_fs10 = require("node:fs");
89844
89958
  var import_promises17 = require("node:fs/promises");
89845
- var import_node_path12 = require("node:path");
89959
+ var import_node_path13 = require("node:path");
89846
89960
  var ULTRAGOAL_DIR = ".omcp/ultragoal";
89847
89961
  var ULTRAGOAL_BRIEF = "brief.md";
89848
89962
  var ULTRAGOAL_GOALS = "goals.json";
@@ -89853,19 +89967,19 @@ function iso(now = /* @__PURE__ */ new Date()) {
89853
89967
  return now.toISOString();
89854
89968
  }
89855
89969
  function ultragoalDir(cwd) {
89856
- return (0, import_node_path12.join)(cwd, ULTRAGOAL_DIR);
89970
+ return (0, import_node_path13.join)(cwd, ULTRAGOAL_DIR);
89857
89971
  }
89858
89972
  function ultragoalBriefPath(cwd) {
89859
- return (0, import_node_path12.join)(ultragoalDir(cwd), ULTRAGOAL_BRIEF);
89973
+ return (0, import_node_path13.join)(ultragoalDir(cwd), ULTRAGOAL_BRIEF);
89860
89974
  }
89861
89975
  function ultragoalGoalsPath(cwd) {
89862
- return (0, import_node_path12.join)(ultragoalDir(cwd), ULTRAGOAL_GOALS);
89976
+ return (0, import_node_path13.join)(ultragoalDir(cwd), ULTRAGOAL_GOALS);
89863
89977
  }
89864
89978
  function ultragoalLedgerPath(cwd) {
89865
- return (0, import_node_path12.join)(ultragoalDir(cwd), ULTRAGOAL_LEDGER);
89979
+ return (0, import_node_path13.join)(ultragoalDir(cwd), ULTRAGOAL_LEDGER);
89866
89980
  }
89867
89981
  function repoRelative(cwd, path22) {
89868
- return (0, import_node_path12.relative)(cwd, path22).split("\\").join("/");
89982
+ return (0, import_node_path13.relative)(cwd, path22).split("\\").join("/");
89869
89983
  }
89870
89984
  function cleanLine(line) {
89871
89985
  return line.replace(/^\s*(?:[-*+]\s+|\d+[.)]\s+)/, "").trim();
@@ -89991,7 +90105,7 @@ async function writePlan(cwd, plan) {
89991
90105
  `);
89992
90106
  }
89993
90107
  async function createUltragoalPlan(cwd, options) {
89994
- if (!options.force && (0, import_node_fs9.existsSync)(ultragoalGoalsPath(cwd))) {
90108
+ if (!options.force && (0, import_node_fs10.existsSync)(ultragoalGoalsPath(cwd))) {
89995
90109
  throw new UltragoalError(`Refusing to overwrite existing ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}; pass --force to recreate it.`);
89996
90110
  }
89997
90111
  const now = iso(options.now);
@@ -91188,6 +91302,7 @@ var import_path111 = require("path");
91188
91302
  init_paths3();
91189
91303
  init_config_dir();
91190
91304
  init_tmux_utils();
91305
+ init_tmux_clipboard();
91191
91306
  var MADMAX_FLAG = "--madmax";
91192
91307
  var YOLO_FLAG = "--yolo";
91193
91308
  var COPILOT_BYPASS_FLAG = "--dangerously-skip-permissions";
@@ -91364,6 +91479,10 @@ function runCopilot(cwd, args, sessionId) {
91364
91479
  }
91365
91480
  }
91366
91481
  function runCopilotInsideTmux(cwd, args) {
91482
+ try {
91483
+ configureTmuxClipboardForCurrentSession({ stdio: "ignore" });
91484
+ } catch {
91485
+ }
91367
91486
  try {
91368
91487
  tmuxExec(["set-option", "mouse", "on"], { stdio: "ignore" });
91369
91488
  } catch {
@@ -91424,7 +91543,20 @@ function runCopilotOutsideTmux(cwd, args, _sessionId) {
91424
91543
  "-t",
91425
91544
  sessionName2,
91426
91545
  "mouse",
91427
- "on"
91546
+ "on",
91547
+ // Enable OSC 52 clipboard forwarding so terminal-side copy-on-select keeps working.
91548
+ ";",
91549
+ "set-option",
91550
+ "-t",
91551
+ sessionName2,
91552
+ "set-clipboard",
91553
+ "on",
91554
+ ";",
91555
+ "set-option",
91556
+ "-at",
91557
+ sessionName2,
91558
+ "terminal-features",
91559
+ ",*:clipboard"
91428
91560
  ];
91429
91561
  tmuxArgs.push(";", "attach-session", "-t", sessionName2);
91430
91562
  try {