@team-agent/installer 0.5.66 → 0.5.68

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 (164) hide show
  1. package/Cargo.lock +8 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/Cargo.toml +1 -0
  4. package/crates/team-agent/src/cli/adapters.rs +5 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +82 -0
  6. package/crates/team-agent/src/cli/emit.rs +3 -3
  7. package/crates/team-agent/src/cli/grok_slot.rs +299 -0
  8. package/crates/team-agent/src/cli/leader.rs +21 -7
  9. package/crates/team-agent/src/cli/leaders.rs +125 -1
  10. package/crates/team-agent/src/cli/mod.rs +20 -0
  11. package/crates/team-agent/src/cli/send/presentation.rs +7 -1
  12. package/crates/team-agent/src/cli/spec.rs +2 -0
  13. package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
  14. package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
  15. package/crates/team-agent/src/cli/tests/base.rs +26 -3
  16. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
  17. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
  18. package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
  19. package/crates/team-agent/src/communication_mode/mod.rs +6 -4
  20. package/crates/team-agent/src/compiler.rs +59 -0
  21. package/crates/team-agent/src/coordinator/backoff.rs +55 -0
  22. package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
  23. package/crates/team-agent/src/coordinator/health.rs +173 -0
  24. package/crates/team-agent/src/coordinator/mod.rs +31 -0
  25. package/crates/team-agent/src/coordinator/orphan.rs +31 -0
  26. package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
  27. package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
  28. package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
  29. package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
  30. package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
  31. package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
  32. package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
  33. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
  34. package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
  35. package/crates/team-agent/src/coordinator/tick.rs +133 -22
  36. package/crates/team-agent/src/coordinator/types.rs +49 -0
  37. package/crates/team-agent/src/db/message_store.rs +39 -5
  38. package/crates/team-agent/src/layout/worker_env.rs +20 -3
  39. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  40. package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
  41. package/crates/team-agent/src/leader/registry.rs +65 -0
  42. package/crates/team-agent/src/leader/start.rs +920 -63
  43. package/crates/team-agent/src/lifecycle/display.rs +56 -0
  44. package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
  45. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -12
  46. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +62 -0
  47. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +59 -0
  48. package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
  49. package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
  50. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
  51. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -456
  52. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
  53. package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
  54. package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
  55. package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
  56. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
  57. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
  58. package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
  59. package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
  60. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
  61. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
  62. package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
  63. package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
  64. package/crates/team-agent/src/lifecycle/launch/spawn.rs +62 -2
  65. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +139 -0
  66. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -0
  67. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
  68. package/crates/team-agent/src/lifecycle/launch.rs +99 -29
  69. package/crates/team-agent/src/lifecycle/lock.rs +42 -1
  70. package/crates/team-agent/src/lifecycle/mod.rs +11 -0
  71. package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
  72. package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
  73. package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
  74. package/crates/team-agent/src/lifecycle/restart/agent.rs +124 -0
  75. package/crates/team-agent/src/lifecycle/restart/common.rs +369 -11
  76. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
  77. package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
  78. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +106 -0
  79. package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
  80. package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
  81. package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
  82. package/crates/team-agent/src/lifecycle/restart.rs +29 -0
  83. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +2 -3
  84. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
  85. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +150 -157
  86. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +2 -2
  87. package/crates/team-agent/src/lifecycle/tests/core.rs +4 -0
  88. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
  89. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
  90. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
  91. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
  92. package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
  93. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
  94. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
  95. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
  96. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
  97. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +63 -38
  98. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -2
  99. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +16 -8
  100. package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
  101. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +20 -19
  102. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +97 -61
  103. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +2 -0
  104. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +40 -7
  105. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +59 -1
  106. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
  107. package/crates/team-agent/src/lifecycle/tests.rs +23 -13
  108. package/crates/team-agent/src/lifecycle/types.rs +61 -0
  109. package/crates/team-agent/src/lifecycle/worker_command_context.rs +85 -11
  110. package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
  111. package/crates/team-agent/src/mcp_server/tests.rs +196 -2
  112. package/crates/team-agent/src/messaging/delivery.rs +405 -40
  113. package/crates/team-agent/src/messaging/helpers.rs +2 -0
  114. package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
  115. package/crates/team-agent/src/messaging/results.rs +4 -0
  116. package/crates/team-agent/src/messaging/send.rs +34 -0
  117. package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
  118. package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
  119. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
  120. package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
  121. package/crates/team-agent/src/messaging/types.rs +4 -1
  122. package/crates/team-agent/src/model/enums.rs +14 -5
  123. package/crates/team-agent/src/model/permissions.rs +3 -0
  124. package/crates/team-agent/src/os_probe.rs +73 -2
  125. package/crates/team-agent/src/provider/adapter.rs +231 -4
  126. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
  127. package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
  128. package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
  129. package/crates/team-agent/src/provider/bypass_flags.rs +46 -2
  130. package/crates/team-agent/src/provider/classify.rs +4 -2
  131. package/crates/team-agent/src/provider/faults.rs +2 -1
  132. package/crates/team-agent/src/provider/mod.rs +11 -0
  133. package/crates/team-agent/src/provider/session/capture.rs +158 -20
  134. package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
  135. package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
  136. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
  137. package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
  138. package/crates/team-agent/src/provider/session/mod.rs +18 -0
  139. package/crates/team-agent/src/provider/session/resume.rs +57 -0
  140. package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
  141. package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
  142. package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
  143. package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
  144. package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
  145. package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
  146. package/crates/team-agent/src/provider/session_scan.rs +8 -0
  147. package/crates/team-agent/src/provider/submit_now.rs +94 -0
  148. package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
  149. package/crates/team-agent/src/provider/types.rs +4 -2
  150. package/crates/team-agent/src/provider/wire.rs +23 -1
  151. package/crates/team-agent/src/state/persist.rs +301 -8
  152. package/crates/team-agent/src/state/repository.rs +5 -0
  153. package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
  154. package/crates/team-agent/src/tmux_backend.rs +1064 -75
  155. package/crates/team-agent/src/transport/tests/wire.rs +28 -2
  156. package/crates/team-agent/src/transport.rs +248 -1
  157. package/npm/install.mjs +129 -73
  158. package/package.json +4 -4
  159. package/skills/team-agent/SKILL.md +33 -238
  160. package/skills/team-agent/command-coverage.json +31 -0
  161. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
  162. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -488
  163. package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
  164. package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
package/npm/install.mjs CHANGED
@@ -1,4 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * purpose: place the Team Agent runtime and login wrappers via the npx installer
4
+ * contract: wrappers land only in the declared bin dir (~/.local/bin or --prefix/bin); installer-managed wrappers recorded in the manifest or recognized by marker are rewritten onto this install's runtime; a non-writable declared dir fails closed with ACTION
5
+ * boundary: never selects a PATH entry as the install target; never creates wrappers in third-party package dirs; does not treat host login PATH order as a landing picker
6
+ */
2
7
  import { spawnSync } from "node:child_process";
3
8
  import fs from "node:fs";
4
9
  import { createRequire } from "node:module";
@@ -119,7 +124,7 @@ Usage:
119
124
  npx @team-agent/installer@latest uninstall
120
125
 
121
126
  Options:
122
- --prefix <dir> fallback wrapper prefix when no writable PATH dir exists, default ~/.local
127
+ --prefix <dir> declared wrapper prefix (wrappers go in <dir>/bin), default ~/.local
123
128
  --runtime-dir <dir> stable runtime root, default ~/.team-agent/runtime
124
129
  --purge-runtime uninstall also removes the runtime root
125
130
  `);
@@ -128,6 +133,7 @@ Options:
128
133
  function install(argv) {
129
134
  const opts = parseOptions(argv);
130
135
  const runtimeRoot = path.resolve(expandHome(opts.runtimeDir || path.join(os.homedir(), ".team-agent", "runtime")));
136
+ const prevManifest = readInstallManifest(runtimeRoot);
131
137
  const installTarget = resolveInstallBinDir({ env: process.env, home: os.homedir(), prefix: opts.prefix });
132
138
  const binDir = installTarget.binDir;
133
139
  const version = packageJson.version || "dev";
@@ -161,6 +167,7 @@ function install(argv) {
161
167
  home: os.homedir(),
162
168
  binDir,
163
169
  runtimeBinary,
170
+ recordedBinDirs: recordedManagedBinDirs(prevManifest),
164
171
  log: (line) => console.log(line),
165
172
  });
166
173
  installSkills(runtimeBinary);
@@ -172,6 +179,11 @@ function install(argv) {
172
179
  installedAt: new Date().toISOString(),
173
180
  installTargetKind: installTarget.kind,
174
181
  pathShadowRepairs: shadowRepairs.map((repair) => repair.file),
182
+ managedBinDirs: uniqueDirs([
183
+ binDir,
184
+ ...recordedManagedBinDirs(prevManifest),
185
+ ...shadowRepairs.map((repair) => repair.binDir),
186
+ ]),
175
187
  });
176
188
 
177
189
  const teamAgent = path.join(binDir, "team-agent");
@@ -299,33 +311,71 @@ function parseOptions(argv) {
299
311
  return opts;
300
312
  }
301
313
 
314
+ export function declaredInstallBinDir(options = {}) {
315
+ const home = options.home || os.homedir();
316
+ const prefix = options.prefix
317
+ ? path.resolve(expandHomeFor(options.prefix, home))
318
+ : path.join(home, ".local");
319
+ return path.join(prefix, "bin");
320
+ }
321
+
302
322
  export function resolveInstallBinDir(options = {}) {
303
323
  const env = options.env || process.env;
304
324
  const home = options.home || os.homedir();
305
- const entries = uniquePathEntries(env.PATH || "", home);
306
- for (const entry of entries) {
307
- if (isVersionManagedPath(entry) || !canWriteDir(entry) || hasForeignWrapper(entry)) {
308
- continue;
309
- }
310
- return { binDir: entry, kind: "path", readyNow: true, rc: null };
325
+ const binDir = path.resolve(declaredInstallBinDir(options));
326
+ try {
327
+ fs.mkdirSync(binDir, { recursive: true });
328
+ } catch (error) {
329
+ throw declaredBinDirUnwritableError(binDir, "create", error);
311
330
  }
312
-
313
- for (const entry of entries) {
314
- if (isVersionManagedPath(entry) || !isReasonableUserBinDir(entry, home) || !canWriteDir(entry) || hasForeignWrapper(entry)) {
315
- continue;
316
- }
317
- return { binDir: entry, kind: "path_user", readyNow: true, rc: null };
331
+ if (!canWriteDir(binDir)) {
332
+ throw declaredBinDirUnwritableError(binDir, "write");
318
333
  }
319
334
 
320
- const fallbackPrefix = options.prefix
321
- ? path.resolve(expandHomeFor(options.prefix, home))
322
- : path.join(home, ".local");
323
- const binDir = path.join(fallbackPrefix, "bin");
324
- fs.mkdirSync(binDir, { recursive: true });
335
+ const onPath = uniquePathEntries(env.PATH || "", home).includes(binDir);
336
+ if (onPath) {
337
+ return { binDir, kind: "declared", readyNow: true, rc: null };
338
+ }
325
339
  const rc = ensureBinDirOnShellRc(binDir, { env, home });
326
340
  return { binDir, kind: "shell_rc", readyNow: false, rc };
327
341
  }
328
342
 
343
+ function declaredBinDirUnwritableError(binDir, op, cause) {
344
+ const detail = cause instanceof Error ? cause.message : cause ? String(cause) : "permission denied";
345
+ return new Error(
346
+ [
347
+ `ERROR: cannot ${op} Team Agent wrapper directory ${binDir}`,
348
+ `ACTION: make it writable (\`mkdir -p ${binDir} && chmod u+w ${binDir}\`), or rerun with --prefix <writable-dir>`,
349
+ `LOG: declared wrapper dir is the only landing; installer does not fall back to a PATH entry (${detail})`,
350
+ ].join("\n"),
351
+ );
352
+ }
353
+
354
+ export function recordedManagedBinDirs(manifest) {
355
+ const dirs = [];
356
+ if (!manifest || typeof manifest !== "object") {
357
+ return dirs;
358
+ }
359
+ if (typeof manifest.binDir === "string" && manifest.binDir) {
360
+ dirs.push(manifest.binDir);
361
+ }
362
+ if (Array.isArray(manifest.managedBinDirs)) {
363
+ for (const dir of manifest.managedBinDirs) {
364
+ if (typeof dir === "string" && dir) {
365
+ dirs.push(dir);
366
+ }
367
+ }
368
+ }
369
+ if (Array.isArray(manifest.pathShadowRepairs)) {
370
+ for (const file of manifest.pathShadowRepairs) {
371
+ if (typeof file === "string" && file) {
372
+ dirs.push(path.dirname(file));
373
+ }
374
+ }
375
+ }
376
+ return uniqueDirs(dirs);
377
+ }
378
+
329
379
  export function repairPathShadowingTeamAgentCommands(options = {}) {
330
380
  const env = options.env || process.env;
331
381
  const home = options.home || os.homedir();
@@ -337,42 +387,50 @@ export function repairPathShadowingTeamAgentCommands(options = {}) {
337
387
  }
338
388
  const installedWrapper = path.join(binDir, "team-agent");
339
389
  const repairs = [];
340
- const candidates = pathShadowRepairCandidates(env.PATH || "", home, binDir);
341
- log?.(`path-shadow: scanning ${candidates.length} candidate bin dirs before ${binDir}`);
390
+ const recordedBinDirs = options.recordedBinDirs || recordedManagedBinDirs(options.manifest);
391
+ const candidates = pathShadowRepairCandidates(env.PATH || "", home, binDir, recordedBinDirs);
392
+ log?.(`path-shadow: scanning ${candidates.length} candidate bin dirs for managed wrappers`);
342
393
  for (const candidateDir of candidates) {
343
394
  const entry = candidateDir.dir;
344
- const candidate = path.join(entry, "team-agent");
345
395
  if (isVersionManagedPath(entry)) {
346
- log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=version-managed-path`);
396
+ log?.(`path-shadow: skip ${path.join(entry, "team-agent")} source=${candidateDir.source} reason=version-managed-path`);
347
397
  continue;
348
398
  }
349
- if (!fs.existsSync(candidate)) {
350
- if (candidateDir.source === "home-local-bin") {
351
- log?.(`path-shadow: checked ${candidate} source=${candidateDir.source} reason=not-found`);
399
+ for (const name of WRAPPER_NAMES) {
400
+ const candidate = path.join(entry, name);
401
+ if (!fs.existsSync(candidate)) {
402
+ if (name === "team-agent" && candidateDir.source === "home-local-bin") {
403
+ log?.(`path-shadow: checked ${candidate} source=${candidateDir.source} reason=not-found`);
404
+ }
405
+ continue;
352
406
  }
353
- continue;
354
- }
355
- log?.(`path-shadow: found ${candidate} source=${candidateDir.source}`);
356
- if (!isExecutableFile(candidate)) {
357
- log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=not-executable-file`);
358
- continue;
359
- }
360
- if (sameFile(candidate, installedWrapper)) {
361
- log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=installed-wrapper`);
362
- continue;
363
- }
364
- if (sameFile(candidate, runtimeBinary)) {
365
- log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=runtime-binary`);
366
- continue;
367
- }
368
- try {
369
- writeExecWrapper(candidate, runtimeBinary, [], { allowForeign: true });
370
- } catch (error) {
371
- const detail = error instanceof Error ? error.message : String(error);
372
- throw new Error(`failed to update PATH-shadowing team-agent at ${candidate}: ${detail}`);
407
+ log?.(`path-shadow: found ${candidate} source=${candidateDir.source}`);
408
+ if (!isExecutableFile(candidate)) {
409
+ log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=not-executable-file`);
410
+ continue;
411
+ }
412
+ if (sameFile(candidate, installedWrapper) && name === "team-agent") {
413
+ log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=installed-wrapper`);
414
+ continue;
415
+ }
416
+ if (sameFile(candidate, runtimeBinary)) {
417
+ log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=runtime-binary`);
418
+ continue;
419
+ }
420
+ if (!isInstallerManagedWrapper(candidate)) {
421
+ log?.(`path-shadow: skip ${candidate} source=${candidateDir.source} reason=not-installer-managed`);
422
+ continue;
423
+ }
424
+ const extraArgs = name === "team_orchestrator" ? ["mcp-server"] : name === "team-agent-coordinator" ? ["coordinator"] : [];
425
+ try {
426
+ writeExecWrapper(candidate, runtimeBinary, extraArgs, { allowForeign: true });
427
+ } catch (error) {
428
+ const detail = error instanceof Error ? error.message : String(error);
429
+ throw new Error(`failed to update PATH-shadowing team-agent at ${candidate}: ${detail}`);
430
+ }
431
+ log?.(`path-shadow: updated ${candidate} source=${candidateDir.source} to runtime shim`);
432
+ repairs.push({ file: candidate, binDir: entry, source: candidateDir.source });
373
433
  }
374
- log?.(`path-shadow: updated ${candidate} source=${candidateDir.source} to runtime shim`);
375
- repairs.push({ file: candidate, binDir: entry, source: candidateDir.source });
376
434
  }
377
435
  if (repairs.length === 0) {
378
436
  log?.("path-shadow: no stale team-agent command repaired");
@@ -434,16 +492,7 @@ export function parseTeamAgentVersion(output) {
434
492
  return bare ? bare[1] : null;
435
493
  }
436
494
 
437
- function shadowingPathEntries(searchPath, home, binDir) {
438
- const entries = uniquePathEntries(searchPath, home);
439
- const installedIndex = entries.findIndex((entry) => path.resolve(entry) === path.resolve(binDir));
440
- if (installedIndex === -1) {
441
- return entries;
442
- }
443
- return entries.slice(0, installedIndex);
444
- }
445
-
446
- function pathShadowRepairCandidates(searchPath, home, binDir) {
495
+ function pathShadowRepairCandidates(searchPath, home, binDir, recordedBinDirs = []) {
447
496
  const candidates = [];
448
497
  const seen = new Set();
449
498
  const add = (dir, source) => {
@@ -454,17 +503,36 @@ function pathShadowRepairCandidates(searchPath, home, binDir) {
454
503
  seen.add(resolved);
455
504
  candidates.push({ dir: resolved, source });
456
505
  };
457
- for (const entry of shadowingPathEntries(searchPath, home, binDir)) {
458
- add(entry, "path-before-install");
506
+ for (const entry of uniquePathEntries(searchPath, home)) {
507
+ add(entry, "path");
459
508
  }
460
509
 
461
510
  const homeLocalBin = path.join(home, ".local", "bin");
462
- if (!sameFile(homeLocalBin, binDir)) {
463
- add(homeLocalBin, "home-local-bin");
511
+ add(homeLocalBin, "home-local-bin");
512
+ add(binDir, "declared-bin");
513
+ for (const dir of recordedBinDirs) {
514
+ add(dir, "manifest-recorded");
464
515
  }
465
516
  return candidates;
466
517
  }
467
518
 
519
+ function uniqueDirs(dirs) {
520
+ const seen = new Set();
521
+ const out = [];
522
+ for (const dir of dirs) {
523
+ if (typeof dir !== "string" || !dir) {
524
+ continue;
525
+ }
526
+ const resolved = path.resolve(dir);
527
+ if (seen.has(resolved)) {
528
+ continue;
529
+ }
530
+ seen.add(resolved);
531
+ out.push(resolved);
532
+ }
533
+ return out;
534
+ }
535
+
468
536
  function isExecutableFile(file) {
469
537
  try {
470
538
  fs.accessSync(file, fs.constants.X_OK);
@@ -513,11 +581,6 @@ function isVersionManagedPath(dir) {
513
581
  ].some((marker) => value.includes(marker));
514
582
  }
515
583
 
516
- function isReasonableUserBinDir(dir, home) {
517
- const relative = path.relative(home, dir);
518
- return Boolean(relative && !relative.startsWith("..") && !path.isAbsolute(relative));
519
- }
520
-
521
584
  function canWriteDir(dir) {
522
585
  try {
523
586
  const probe = path.join(dir, `.team-agent-write-test-${process.pid}-${Date.now()}`);
@@ -529,13 +592,6 @@ function canWriteDir(dir) {
529
592
  }
530
593
  }
531
594
 
532
- function hasForeignWrapper(binDir) {
533
- return WRAPPER_NAMES.some((name) => {
534
- const file = path.join(binDir, name);
535
- return fs.existsSync(file) && !isInstallerManagedWrapper(file);
536
- });
537
- }
538
-
539
595
  function isInstallerManagedWrapper(file) {
540
596
  try {
541
597
  const text = fs.readFileSync(file, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.66",
3
+ "version": "0.5.68",
4
4
  "description": "npx installer for Team Agent",
5
5
  "keywords": [
6
6
  "codex",
@@ -20,9 +20,9 @@
20
20
  "team-agent-installer": "npm/install.mjs"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@team-agent/cli-darwin-arm64": "0.5.66",
24
- "@team-agent/cli-darwin-x64": "0.5.66",
25
- "@team-agent/cli-linux-x64": "0.5.66"
23
+ "@team-agent/cli-darwin-arm64": "0.5.68",
24
+ "@team-agent/cli-darwin-x64": "0.5.68",
25
+ "@team-agent/cli-linux-x64": "0.5.68"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",
@@ -1,272 +1,67 @@
1
1
  ---
2
2
  name: team-agent
3
3
  description: Use only when the user explicitly asks to start, operate, inspect, shutdown, or restart a Team Agent team. Treat the team-agent CLI as a sealed appliance.
4
+ requires_team_agent: ">=0.5.0"
5
+ last_verified_against: "0.5.66"
4
6
  ---
5
7
 
6
8
  # Team Agent
7
9
 
8
- Use this skill only for Team Agent operation. The leader is the current user-facing agent; do not create a `leader` worker. Worker role docs live in `<workspace>/agents/`; `TEAM.md` lives at `<workspace>/TEAM.md`.
10
+ Sealed appliance for someone who just got the CLI. Operator handbook (permissions, models, routing, recovery): `docs/reference/team-agent-operator.md`.
9
11
 
10
- ## Leader Requirement
11
-
12
- Real Team Agent teams require the current leader to run inside a tmux-managed pane. Prefer the short launchers:
12
+ If `team-agent --version` does not match `last_verified_against`, do not copy examples as current truth. Learn from the live CLI:
13
13
 
14
14
  ```bash
15
- team-agent codex
16
- team-agent claude
15
+ team-agent --version
16
+ team-agent --help
17
+ team-agent doctor --help
17
18
  ```
18
19
 
19
- Pass provider flags after the provider name, for example `team-agent codex --dangerously-bypass-approvals-and-sandbox`. Existing tmux layouts are valid too, including Finder/Ghostty launchers, as long as `team-agent quick-start` is invoked from the leader's current tmux pane. Do not start a real team from a naked terminal that Team Agent cannot address through tmux.
20
-
21
- ## Leader Role
22
-
23
- Invoking this skill turns the current agent into the team leader. The leader **orchestrates**: read reports, set direction, decompose work, dispatch tasks to teammates, review results, and decide. The leader does **not** execute hands-on work — no `cargo test`, no product-code edits, no `git push`, no build/verify cycles. Those belong to teammates. If the leader catches themselves running tests, editing source files, or pushing commits, they have stepped out of role; stop and re-dispatch.
24
-
25
- When the user has been communicating in Chinese throughout the conversation, all leader↔teammate messaging (`send`, `report_result`, MCP messages, task descriptions) must also be in Chinese. The leader dispatches in Chinese, the worker reports back in Chinese. Switch back to the user's language only at the user-facing boundary.
26
-
27
- ## Minimal Copy-Paste Team
28
-
29
- ```bash
30
- mkdir -p .team/current/agents
31
- team-agent profile init codex-default --auth-mode subscription --workspace .
32
- cat > .team/current/TEAM.md <<'EOF'
33
- ---
34
- name: demo-team
35
- objective: One worker handles bounded tasks and reports through Team Agent MCP.
36
- dangerous_auto_approve: false
37
- fast: false
38
- provider_models:
39
- codex: gpt-5.5
40
- claude: claude-sonnet-4-6
41
- claude_code: claude-sonnet-4-6
42
- ---
43
-
44
- Team config only. This is not a worker role.
45
- EOF
46
- cat > .team/current/agents/coder.md <<'EOF'
47
- ---
48
- name: coder
49
- role: Implementation Worker
50
- provider: codex
51
- auth_mode: subscription
52
- profile: codex-default
53
- tools:
54
- - fs_read
55
- - fs_list
56
- - fs_write
57
- - execute_bash
58
- - mcp_team
59
- - provider_builtin
60
- ---
61
-
62
- Handle one bounded task at a time. Send progress to leader only when needed. Final completion must call report_result exactly once; MCP fills task ids and result envelope fields.
63
- EOF
64
- team-agent quick-start .team/current
65
- ```
66
-
67
- YAML lists must be block style. Use `tools:\n - fs_read`; do not use `tools: [fs_read, mcp_team]`.
68
-
69
- Display choices (set `display_backend:` in `TEAM.md` to opt in):
70
-
71
- - `none` (default): headless / no GUI window manager. The team runs entirely in the per-workspace tmux server; this is what the demo above uses.
72
- - `adaptive`: framework picks an available GUI layout for the local platform.
73
- - `ghostty_workspace`: one Ghostty window. Workers are shown in tmux tabs/windows, up to 3 side-by-side panes per tab. Four workers become `3 + 1`; eight become `3 + 3 + 2`.
74
- - `ghostty_window`: one Ghostty window per worker.
20
+ **Launch** from a tmux-addressable pane: `team-agent claude` or `team-agent codex`, then `team-agent quick-start .team/current`. Do not start a real team from a naked terminal. Existing tmux/Ghostty layouts are valid if `quick-start` runs from the leader pane.
75
21
 
76
- **Omitting `display_backend` defaults to `none`** (changed in 0.3.4). Set `display_backend: adaptive` (or one of the explicit ghostty variants) in `TEAM.md` only when the user wants GUI windows.
22
+ **Operate**
77
23
 
78
- ## Private Tmux Socket
24
+ - Dispatch: `team-agent send TO MESSAGE` (positional TO; `--watch-result` is deprecated). After success, do not poll with `sleep` / `status` / `inbox` / `collect`.
25
+ TO has two co-equal logical forms: an **in-team short name** (`team-agent send reviewer "..."`) and a fully qualified `<workspace>::<team>/<agent>`. Use the qualified form across workspaces.
26
+ - Inspect: `team-agent status` / `status --json`. `ok: true` plus `ready: false` is not a crash.
27
+ - Lifecycle: `restart .` resumes a stopped team; `add-agent NAME --role-file FILE` adds or `--force` recreates one worker; `shutdown --workspace .` stops. Do not shutdown the whole team to add a worker.
28
+ - Roles: every `agents/*.md` must declare boolean `dangerously_skip_permissions`. Never rewrite a user-supplied model id. Never read `.env` files.
79
29
 
80
- Worker windows live on a private per-workspace tmux server, not the user's default socket. `tmux list-sessions` (no `-L`/`-S`) will not show them; that is expected, not a failure.
30
+ **On failure:** if the CLI prints a structured `action`, run that `action` first, then stop. Do not guess flags. `coordinator.session_missing` is a self-healing transient re-check `status --json`; do not shutdown because of it.
81
31
 
82
- To attach manually, read `attach_commands` (or the `tmux` action printed near `ready:`) from `team-agent quick-start` / `team-agent restart` / `team-agent status --json` output. It is the canonical `tmux -L <socket-name> attach -t <session>` (or `-S <socket-path>`) line for the current team.
83
-
84
- Use `team-agent attach-leader` / `team-agent claim-leader` to bind the leader pane to a team. Do not invent socket paths by hand.
32
+ The current user-facing agent is the leader (orchestrate only). Workers call `report_result` exactly once. Nested teams: `skills/team-agent/references/team-in-team.md`.
85
33
 
86
34
  ## Provider Capability Matrix
87
35
 
36
+ Claude / Codex / Copilot / Gemini / fake: `docs/reference/team-agent-operator.md`. These two are in the runtime but were missing from that table:
37
+
88
38
  | Provider | Resume | Turn-state detection | Per-worker model override | Native session fork |
89
39
  |---|---|---|---|---|
90
- | `claude` / `claude_code` | yes (`--resume <id>`, transcript-verified) | yes (JSONL stream) | yes (role `model` overrides `provider_models`) | yes (snapshot copy + only `--resume <snapshot-id>`) |
91
- | `codex` | yes (`codex resume <id>`, session-store-verified) | yes (turn JSONL) | yes (role `model`) | yes (`codex fork`) |
92
- | `copilot` | yes (`copilot --resume <id|name>`, sqlite `sessions` row) | not yet (phase 1: `provider.classify.unsupported` event) | yes (role `model`) | yes (isolated `COPILOT_HOME` store fork) |
93
- | `gemini_cli` | no | no | yes | no |
94
- | `fake` (testing only) | no | no | n/a | no |
40
+ | `grok` | yes (`--resume <id>`, archive-gated) | no | yes (role `model` required) | yes (`--fork-session` + new `--session-id`) |
41
+ | `cursor_agent` | yes (argv `--resume <chatId>`, archive-gated) | no | required on role; same-family catalog id can take effect; unknown id silent-fallback; pane chrome ≠ proven live | **no `CapabilityUnsupported`** |
95
42
 
96
- Notes:
97
- - Per-worker model override means a role-doc `model:` value wins over `TEAM.md` `provider_models.<provider>`; subscription defaults still fill blanks.
98
- - Copilot fork copies the source session into an isolated `COPILOT_HOME` and rekeys its SQLite session references atomically. Missing or incomplete backing fails closed; it never falls back to a fresh spawn.
99
- - Copilot phase-1 idle/turn detection is intentionally Unknown; tick emits a single explicit `provider.classify.unsupported` event per state change (P4 dedup), never a silent default.
43
+ Grok / `cursor_agent` have no JSONL turn-state reader (classify → Unknown).
100
44
 
101
45
  ## Provider Prep
102
46
 
103
- ### Subscription auth (Codex / Claude account login)
104
-
105
- Before workers can use a subscription provider, create a named subscription profile in the workspace and reference it from role docs:
106
-
107
- ```bash
108
- team-agent profile init codex-default --auth-mode subscription --workspace .
109
- team-agent profile init claude-default --auth-mode subscription --workspace .
110
- ```
111
-
112
- Then in `agents/<role>.md` frontmatter, set `auth_mode: subscription` and `profile: codex-default` (or `claude-default`). The demo above uses `profile: codex-default`; that name only works after `profile init` has created it in the same workspace.
113
-
114
- Common errors:
115
-
116
- - `profile already exists`: a profile by that name is already in `.team/current/profiles/`. Either reuse it (skip `init`) or pick a new name.
117
- - `profile not found` during quick-start: the role doc references a profile that was never `profile init`-ed in this workspace. Run `team-agent profile init <name> --auth-mode subscription --workspace .` and retry.
118
-
119
- ### Codex provider notes
120
-
121
- Codex: run `codex login` first. Optional `~/.codex/config.toml` profile:
122
-
123
- ```toml
124
- [profiles.team-agent]
125
- model = "gpt-5.5"
126
- approval_policy = "on-request"
127
- sandbox_mode = "workspace-write"
128
- ```
129
-
130
- Use exact provider model ids, not display names. For Codex workers, the model must match a `slug` from `codex debug models`; for example use `gpt-5.3-codex-spark`, not `GPT-5.3-Codex-Spark`.
131
- Role docs may omit `model` for subscription workers. Team Agent fills subscription defaults from `TEAM.md` `provider_models`, then built-in provider defaults (`codex: gpt-5.5`, `claude/claude_code: claude-sonnet-4-6`). Use role-level `model` only for intentional per-worker overrides.
132
-
133
- Claude: run `claude auth status`; if missing, run `claude auth login`. Team Agent stores Claude worker sessions by passing `--session-id` and resumes with `--resume`.
134
- Use `provider: claude` or `provider: claude_code` for Claude workers.
135
-
136
- If the current leader process was started with `claude --dangerously-skip-permissions` or `codex --dangerously-bypass-approvals-and-sandbox`, Team Agent inherits that permission mode for worker launch, restart, and single-agent repair.
137
- Role `profile` values are secret-safe references. Do not put API keys in role docs or `TEAM.md`.
138
- Never read raw provider profile files into model context. Do not use `Read`, `cat`, `sed`, `grep`, editors, or screenshots on `.team/current/profiles/*.env` or `.team/runtime/provider-env/*.env`. Those files may contain live API keys. Use only `team-agent profile show <name> --workspace . --json` or `team-agent profile doctor <name> --workspace . --json` for redacted diagnostics; if a value is missing, ask the human user to edit the local profile file.
139
- When the user asks for a third-party or compatible API, do not ask them to paste keys into the chat. Generate a local blank profile instead, for example:
140
-
141
- ```bash
142
- team-agent profile init deepseek --auth-mode compatible_api --workspace .
143
- ```
144
-
145
- Tell the user to fill `.team/current/profiles/deepseek.env` locally:
146
-
147
- ```env
148
- AUTH_MODE=compatible_api
149
- PROFILE_NAME=deepseek
150
- BASE_URL=
151
- API_KEY=
152
- MODEL=
153
- ```
154
-
155
- Then reference only `auth_mode: compatible_api` and `profile: deepseek` in role docs. Do not invent or duplicate a role `model` when the profile already has `MODEL=`; if both places define a model they must match exactly. Team Agent loads the profile automatically during quick-start, launch, restart, and start-agent. Compatible API workers inherit the current shell proxy/CA environment by default. Claude compatible API workers use Team Agent managed `CLAUDE_CONFIG_DIR` so user-level Claude subscription settings cannot re-inject Anthropic proxy variables into third-party API sessions. If quick-start reports an ambient proxy blocker, do not silently unset proxy for the whole team; tell the user to choose one path: fix that proxy for `BASE_URL`, put `HTTPS_PROXY=`/`HTTP_PROXY=` in the profile, or put `PROXY_MODE=direct` in the profile to bypass proxy only for that worker. Subscription workers keep their native provider settings and environment. Startup runs a redacted smoke check for compatible API profiles before worker windows are created, so a bad URL/key/model or proxy/base URL connectivity failure is reported to the leader command instead of producing idle workers.
156
- For diagnosis, run `team-agent profile show deepseek --workspace . --json`; never open the `.env` file to check whether `API_KEY` or `MODEL` is filled.
157
-
158
- ## Commands
159
-
160
- - `team-agent codex ...` starts or attaches a tmux-managed Codex leader in the current directory; arguments after `codex` pass through to Codex.
161
- - `team-agent claude ...` starts or attaches a tmux-managed Claude leader in the current directory; arguments after `claude` pass through to Claude.
162
- - `team-agent quick-start .team/current` starts workers from `TEAM.md` and `agents/*.md`. When it prints `ready:` and `ready_signal`, startup is complete; do not run sleep/status/wait loops afterward unless diagnosing a failure.
163
- - For real workers, `quick-start` requires a current tmux leader pane. If it says the leader must run inside tmux, restart the leader with `team-agent codex`/`team-agent claude` or use an existing tmux-managed layout, then run quick-start again.
164
- - Quick-start generated files stay inside the selected team directory, for example `.team/current/` or `.team/alpha/`; do not create or expect root `team.spec.yaml` or `team_state.md`.
165
- - Use `team-agent quick-start ./roles --team-id alpha` to create a second generated team under `.team/alpha/`, or pass an existing team directory directly such as `team-agent quick-start .team/alpha`.
166
- - `quick-start` is only for first-time team creation from role docs. If that team already has runtime state, use `team-agent restart . --team <session_name_or_team_name>` to resume it. If restart cannot recover context, explain the loss and wait for explicit user consent before using `team-agent restart . --allow-fresh`; never reset context through quick-start.
167
- - If the user explicitly asks a worker to create or operate a nested child team, first read `references/team-in-team.md`. Child teams must use an independent child workspace, never the parent `.team/current`.
168
- - `team-agent send --watch-result coder "Do the bounded task"` sends a direct worker message, returns after delivery, and lets the coordinator collect/report completion asynchronously.
169
- - Positional `TO` has two co-equal forms: an in-team short name, for example `team-agent send reviewer "Review this change"`, and a fully-qualified logical name, `<workspace>::<team>/<agent>`. Use the fully-qualified form across workspaces or when the local team scope is ambiguous.
170
- - Advanced orchestration callers may add `--presentation-sink leader|casefile|silent --message-class CLASS [--case-id CASE]`. All sinks remain durable and pullable; `casefile`/`silent` suppress only live leader injection. Missing presentation metadata preserves the normal leader-visible behavior.
171
- - After `send --watch-result` succeeds, do not run `sleep`, `status`, `inbox`, or `collect` polling loops unless the user explicitly asks for diagnosis; the coordinator will notify the leader when the result arrives.
172
- - `team-agent send --task task_initial "Start"` routes by task.
173
- - `team-agent status` shows team, worker health, result-store counts, `session_id`, `captured_via`, and attribution confidence. `team-agent status --json` is compact and context-safe by default; use `team-agent status --detail --json` only for raw runtime-state diagnostics.
174
- - `team-agent status coder` shows one worker.
175
- - `team-agent approvals [coder]` shows structured pending approval prompts without copying worker terminal pages.
176
- - `team-agent inbox coder` shows message history only. Final results are not in inbox.
177
- - `team-agent shutdown --workspace . --keep-logs` stops the tmux session after a final session capture attempt.
178
- - `team-agent restart .` restarts a stopped team from stored worker sessions. If one workspace has multiple restartable teams, use `team-agent restart . --team <session_name_or_team_name>`.
179
- - `team-agent start-agent coder --workspace .` repairs one missing worker window without interrupting other workers.
180
- - `team-agent doctor` checks local dependencies and provider auth hints.
181
-
182
- ## Restart Semantics
47
+ ### Cursor provider notes
183
48
 
184
- `restart` takes one workspace argument. It preserves each worker's original provider. If a verified provider session exists, the worker resumes (`codex resume <id>` or `claude --resume <id>`). Claude sessions are considered resumable only after the provider has written a project transcript for that session; a freshly opened blank Claude window is not recorded as recovered context. If the stored id is stale, the runtime first tries to repair it from verified transcript history. If a stored session cannot be verified or repaired, restart fails closed instead of silently losing context; use `team-agent restart . --allow-fresh` only when the user explicitly accepts a fresh worker context. If multiple stopped teams in the same workspace have restart context, plain `team-agent restart .` fails and lists candidates; rerun with `--team <session_name_or_team_name>`. If no prior session id exists, that worker starts fresh and the event log records `restart.fresh_spawn`. Claude resume must run from the original cwd and the same provider transcript root; Team Agent stores `spawn_cwd` and compatible-API `claude_projects_root` for that.
49
+ Frontmatter: `provider: cursor_agent` (not `cursor`; launcher verb is `team-agent cursor`), `auth_mode: subscription`, `name:` required (omit `missing front matter field name`). Also required: `role:`, `tools:`, `dangerously_skip_permissions:` (bool). Subscription needs no `profile`.
185
50
 
186
- Startup trust prompts are handled by the runtime/coordinator with bounded probes; do not wait on raw worker screens or manually press Enter for routine startup trust prompts.
51
+ `model:` is required (omit compile-fails; blocks a silent builtin `sonnet-4-thinking`). The flag stays on argv. Same-family catalog ids can change pane chrome. An id not in that provider's catalog silent-falls back (landing not stable; no events/stderr/pane warning). Pick names from the catalog; after spawn, `capture-pane` once for chrome. Do not treat the role field or pane chrome as proof of the live model.
187
52
 
188
- Use `team-agent start-agent <agent_id> --workspace .` only as a narrow repair when one worker window is missing after launch/restart/display failure. It preserves the worker provider, resumes from `session_id` when available, starts fresh when there is no prior session id, and does not restart the rest of the team. If an existing session id cannot resume, it fails closed unless the user explicitly passes `--allow-fresh`.
53
+ One `cursor_agent` per workspace. A second seat (including `add-agent --force` of a different id) fail-closes:
189
54
 
190
- ## Adding A New Worker At Runtime
191
-
192
- To add a new worker to a running team, write the role doc and run **one command** — do not shutdown/restart, do not regenerate the compiled spec, and do not quick-start an existing team:
193
-
194
- ```bash
195
- cat > .team/current/agents/reviewer.md <<'EOF'
196
- ---
197
- name: reviewer
198
- role: Code Reviewer
199
- provider: codex
200
- auth_mode: subscription
201
- profile: codex-default
202
- tools:
203
- - fs_read
204
- - fs_list
205
- - mcp_team
206
- ---
207
-
208
- Review changed files and report findings to leader.
209
- EOF
210
- team-agent add-agent reviewer --role-file .team/current/agents/reviewer.md --workspace .
211
55
  ```
212
-
213
- `add-agent` registers the new worker into the running team's state, launches its window on the existing tmux socket, and leaves every other worker untouched. **Do not shutdown/restart for adding a worker** — it loses every other worker's resumable session. If `add-agent` fails, surface the structured error to the user; do not fall back to shutdown.
214
-
215
- Semantic distinction:
216
-
217
- - `team-agent add-agent <agent> --role-file <file>` — add a **new** worker not yet in team state.
218
- - `team-agent clone-agent <source> --as <new>` — reread the source worker's latest role file and start a fresh provider seat. It never copies conversation context. Success is initially honest `capture_state: pending_first_turn` with `session_id`, `new_session_id`, and `backing_path` all null; after the first turn, canonical capture changes the state to `captured` and fills the backing tuple.
219
- - `team-agent fork-agent <source> --as <new>` — reread the same latest role file and create a distinct, verified provider session that forks the source context. If the provider backing cannot be verified, the command fails and rolls back instead of silently cloning fresh.
220
- - `team-agent start-agent <agent>` — (re)launch a worker that **already exists** in team state but whose window is missing.
221
- - `team-agent reset-agent <agent> --discard-session` — keep the same seat and deliberately start it with fresh context.
222
- - `team-agent restart .` — resume a fully **stopped** team from stored worker sessions.
223
- - `team-agent quick-start <dir>` — first-time team creation from role docs; for existing teams use `restart`, and use `restart --allow-fresh` only after explicit user consent to discard context.
224
-
225
- Clone/fork names are always explicit: run concurrent calls with a different `--as` value for each new seat. Fork success includes a verified new `session_id` and independent backing; a tmux window alone is not fork success. Clone success uses the honest `pending_first_turn` state above until first-turn capture, never a fabricated verified tuple. Updating the source role file affects the next clone/fork without requiring a full-team rebuild. Automatic knowledge write-back from a clone/fork into the source role file is not provided.
226
-
227
- Removing a worker at runtime is the symmetric `team-agent remove-agent <agent> --workspace . --confirm`.
228
-
229
- ## Worker Protocol
230
-
231
- Workers normally do not run nested Team Agent teams. When the user or leader explicitly asks for a child team, follow `references/team-in-team.md`; otherwise workers only provide the target and content for progress, and a short completion summary at the end:
232
-
233
- ```text
234
- team_orchestrator.send_message(to="leader", content="short progress or blocker")
235
- # to another teammate:
236
- team_orchestrator.send_message(to="<agent_id>", content="short coordination note")
237
- # to every other team member:
238
- team_orchestrator.send_message(to="*", content="short broadcast")
239
- team_orchestrator.report_result(summary="short completion", status="success", tests=[{"command":"command","status":"passed"}])
56
+ error: cursor_agent seat already occupies this workspace
57
+ reason: <workspace>/.cursor/mcp.json is directory-scoped; a second seat overwrites TEAM_AGENT_ID (last-writer)
58
+ action: do not add another CursorAgent in this workspace until per-seat MCP identity is isolated
240
59
  ```
241
60
 
242
- For typed orchestration traffic, both `send_message` and `report_result` accept `presentation={"sink":"leader|casefile|silent","class":"message|progress|stage_result|stage_pass|bounce|blocking|final_review|timeout","case_id":"optional-case"}`. If the object is present, `sink` and `class` are required and unknown values fail closed. `casefile` and `silent` are durable-only, not deletion. The fixed critical classes `stage_pass`, `bounce`, `blocking`, `final_review`, and `timeout` always appear on the leader screen even when another sink is requested. Routing uses the typed class, never words in the content or summary.
243
-
244
- Do not pass `sender`, `task_id`, `requires_ack`, `schema_version`, or `agent_id` unless doing a low-level compatibility diagnostic. The MCP runtime fills those fields and keeps delivery metadata in runtime state and event logs. If provider env loses the worker id, MCP infers it from active task/message state and falls back to an explicit `unknown` sender instead of treating the worker as leader.
245
-
246
- Message targets are team-scoped. Use `leader`, another teammate agent id, or `*` for all other team members. The runtime excludes the sender from `*` broadcasts and never scans unrelated terminal windows for recipients.
247
-
248
- `report_result` stores final completion and immediately attempts a leader notification through the verified/fallback delivery path. `team-agent collect` remains the authoritative state-update path. Do not wait for final results through `team-agent inbox`, message ack counts, or repeated plain status polling. `acknowledged_count` only means prior task messages were acknowledged by the worker; it is not a missing-result signal.
249
- For normal leader dispatch, prefer `team-agent send --watch-result ...`; when it returns a registered watcher notice, the framework will notify the leader at completion.
250
-
251
- For long processes, workers must write logs, keep a pid, provide a health check, and stop after a bounded number of retries. QA/reviewer roles must stay within their authorized files and stop on service unavailable, approval prompts, or repeated startup failure.
252
-
253
- ## Failure Rules
254
-
255
- For any non-zero `team-agent` exit, report the command, exit code, last about 20 stderr lines, and affected task or agent when known. Then stop and wait for the user.
256
-
257
- Do not retry with changed flags. Do not inspect source code or private runtime state. Do not operate tmux directly except when the user asks for a manual diagnostic. Do not answer provider approval prompts for the user.
258
-
259
- If `quick-start` reports `tmux session already exists`, treat it as a team-name collision. The existing session may be an active team; do not terminate it and do not suggest `shutdown` as the normal fix. Change `name:` in `TEAM.md` so the next launch uses a different tmux session name, then run `team-agent quick-start .team/current` again.
260
-
261
- Known Team Agent control-plane MCP prompts such as `team_orchestrator.report_result` and `team_orchestrator.send_message` are handled by the coordinator. It uses session-scoped approval, verifies the prompt cleared, retries boundedly, and logs the result. Do not ask the user to approve those routine internal prompts.
262
-
263
- When `status` still shows `AWAITING_APPROVAL`, run `team-agent approvals <agent_id>`, show the structured prompt summary and choices, ask the user to decide, and wait.
264
-
265
- Do not inspect raw worker terminal output during normal operation. Use `team-agent status`, `team-agent approvals`, `team-agent inbox`, `team-agent collect`, and event logs instead. Raw-screen diagnostics are outside this skill's normal workflow, require explicit user authorization, and are guarded by the CLI; use them only as a one-shot bounded diagnostic, never as a routine workflow step.
61
+ Several cursor seats one workspace directory each. Same seat, fresh context `reset-agent --discard-session`.
266
62
 
267
- For "worker reported but leader cannot see completion":
63
+ `clone-agent` copies the source role (provider unchanged). Runtime add: `clone-agent` → `stop-agent` → `remove-agent --confirm` (deletes `.team/dynamic-role-files/`) → write the role file → `add-agent --role-file` → dispatch.
268
64
 
269
- 1. Run `team-agent collect` once; this is the final-result intake path.
270
- 2. If no result is collected, inspect `team-agent status --json` field `results`. `uncollected > 0` means the result is already accepted by MCP and waiting in the result store.
271
- 3. Check `.team/logs/events.jsonl` for `mcp.report_result` and `collect.result` before sending another prompt to the worker.
272
- 4. Do not loop on `team-agent inbox` or ack/status counts; that burns context and cannot consume final results.
65
+ - Restart emits `--resume <chatId>` when `store.db`/`meta.json` exist; the gate does not read chat text. Persist anything that must survive restart.
66
+ - Delivery sends one Enter; a second Enter interrupts the turn.
67
+ - After spawn, the pane footer should show `Cursor Agent v<version>`. Do not use `strings` to probe the binary.