@team-agent/installer 0.2.11 → 0.3.1

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 (326) hide show
  1. package/Cargo.lock +744 -0
  2. package/Cargo.toml +34 -0
  3. package/crates/team-agent/Cargo.toml +33 -0
  4. package/crates/team-agent/src/cli/adapters.rs +1343 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +554 -0
  6. package/crates/team-agent/src/cli/emit.rs +1204 -0
  7. package/crates/team-agent/src/cli/helpers.rs +88 -0
  8. package/crates/team-agent/src/cli/leader.rs +216 -0
  9. package/crates/team-agent/src/cli/mod.rs +1207 -0
  10. package/crates/team-agent/src/cli/profile.rs +306 -0
  11. package/crates/team-agent/src/cli/send.rs +215 -0
  12. package/crates/team-agent/src/cli/status.rs +179 -0
  13. package/crates/team-agent/src/cli/status_port.rs +502 -0
  14. package/crates/team-agent/src/cli/tests/base.rs +616 -0
  15. package/crates/team-agent/src/cli/tests/compile.rs +96 -0
  16. package/crates/team-agent/src/cli/tests/divergence.rs +509 -0
  17. package/crates/team-agent/src/cli/tests/lane_c.rs +333 -0
  18. package/crates/team-agent/src/cli/tests/leader_watch.rs +395 -0
  19. package/crates/team-agent/src/cli/tests/main_preserved.rs +675 -0
  20. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +390 -0
  21. package/crates/team-agent/src/cli/tests/mod.rs +97 -0
  22. package/crates/team-agent/src/cli/tests/peer_allow.rs +137 -0
  23. package/crates/team-agent/src/cli/tests/repair_state_byte_lock.rs +302 -0
  24. package/crates/team-agent/src/cli/tests/run_delegation.rs +305 -0
  25. package/crates/team-agent/src/cli/tests/status_send.rs +385 -0
  26. package/crates/team-agent/src/cli/tests/verb_profile.rs +182 -0
  27. package/crates/team-agent/src/cli/tests/verb_settle.rs +236 -0
  28. package/crates/team-agent/src/cli/tests/verb_validate.rs +184 -0
  29. package/crates/team-agent/src/cli/types.rs +605 -0
  30. package/crates/team-agent/src/compiler/tests.rs +701 -0
  31. package/crates/team-agent/src/compiler.rs +489 -0
  32. package/crates/team-agent/src/coordinator/backoff.rs +153 -0
  33. package/crates/team-agent/src/coordinator/health.rs +557 -0
  34. package/crates/team-agent/src/coordinator/mod.rs +80 -0
  35. package/crates/team-agent/src/coordinator/orphan.rs +179 -0
  36. package/crates/team-agent/src/coordinator/tests/abnormal.rs +255 -0
  37. package/crates/team-agent/src/coordinator/tests/basics.rs +262 -0
  38. package/crates/team-agent/src/coordinator/tests/daemon.rs +323 -0
  39. package/crates/team-agent/src/coordinator/tests/health_sync.rs +263 -0
  40. package/crates/team-agent/src/coordinator/tests/main_preserved.rs +136 -0
  41. package/crates/team-agent/src/coordinator/tests/mod.rs +310 -0
  42. package/crates/team-agent/src/coordinator/tests/spine.rs +261 -0
  43. package/crates/team-agent/src/coordinator/tests/takeover.rs +227 -0
  44. package/crates/team-agent/src/coordinator/tests/tick_core.rs +256 -0
  45. package/crates/team-agent/src/coordinator/tests/watch.rs +167 -0
  46. package/crates/team-agent/src/coordinator/tick.rs +2032 -0
  47. package/crates/team-agent/src/coordinator/types.rs +584 -0
  48. package/crates/team-agent/src/db/migration.rs +716 -0
  49. package/crates/team-agent/src/db/mod.rs +23 -0
  50. package/crates/team-agent/src/db/schema.rs +378 -0
  51. package/crates/team-agent/src/event_log.rs +375 -0
  52. package/crates/team-agent/src/fake_worker.rs +253 -0
  53. package/crates/team-agent/src/leader/helpers.rs +190 -0
  54. package/crates/team-agent/src/leader/inject.rs +33 -0
  55. package/crates/team-agent/src/leader/lease.rs +1084 -0
  56. package/crates/team-agent/src/leader/mod.rs +99 -0
  57. package/crates/team-agent/src/leader/owner_bind.rs +292 -0
  58. package/crates/team-agent/src/leader/rediscover/tests.rs +526 -0
  59. package/crates/team-agent/src/leader/rediscover.rs +1101 -0
  60. package/crates/team-agent/src/leader/start.rs +273 -0
  61. package/crates/team-agent/src/leader/takeover.rs +235 -0
  62. package/crates/team-agent/src/leader/tests/basics.rs +183 -0
  63. package/crates/team-agent/src/leader/tests/byte_findings.rs +237 -0
  64. package/crates/team-agent/src/leader/tests/identity.rs +206 -0
  65. package/crates/team-agent/src/leader/tests/idle.rs +272 -0
  66. package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
  67. package/crates/team-agent/src/leader/tests/lease_claim.rs +410 -0
  68. package/crates/team-agent/src/leader/tests/mod.rs +125 -0
  69. package/crates/team-agent/src/leader/tests/rediscover.rs +351 -0
  70. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +204 -0
  71. package/crates/team-agent/src/leader/types.rs +489 -0
  72. package/crates/team-agent/src/lib.rs +85 -0
  73. package/crates/team-agent/src/lifecycle/display.rs +228 -0
  74. package/crates/team-agent/src/lifecycle/helpers.rs +112 -0
  75. package/crates/team-agent/src/lifecycle/launch/plan.rs +227 -0
  76. package/crates/team-agent/src/lifecycle/launch.rs +2109 -0
  77. package/crates/team-agent/src/lifecycle/mod.rs +62 -0
  78. package/crates/team-agent/src/lifecycle/restart/agent.rs +533 -0
  79. package/crates/team-agent/src/lifecycle/restart/common.rs +517 -0
  80. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +41 -0
  81. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +268 -0
  82. package/crates/team-agent/src/lifecycle/restart/remove.rs +780 -0
  83. package/crates/team-agent/src/lifecycle/restart/selection.rs +208 -0
  84. package/crates/team-agent/src/lifecycle/restart/team_state.rs +242 -0
  85. package/crates/team-agent/src/lifecycle/restart.rs +76 -0
  86. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +455 -0
  87. package/crates/team-agent/src/lifecycle/tests/core.rs +989 -0
  88. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +583 -0
  89. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +985 -0
  90. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +265 -0
  91. package/crates/team-agent/src/lifecycle/tests.rs +27 -0
  92. package/crates/team-agent/src/lifecycle/types.rs +710 -0
  93. package/crates/team-agent/src/main.rs +41 -0
  94. package/crates/team-agent/src/mcp_server/helpers.rs +228 -0
  95. package/crates/team-agent/src/mcp_server/mod.rs +183 -0
  96. package/crates/team-agent/src/mcp_server/normalize.rs +312 -0
  97. package/crates/team-agent/src/mcp_server/tests/golden.rs +283 -0
  98. package/crates/team-agent/src/mcp_server/tests/normalize.rs +244 -0
  99. package/crates/team-agent/src/mcp_server/tests/scoped.rs +189 -0
  100. package/crates/team-agent/src/mcp_server/tests/send.rs +222 -0
  101. package/crates/team-agent/src/mcp_server/tests/tools.rs +158 -0
  102. package/crates/team-agent/src/mcp_server/tests/wire.rs +187 -0
  103. package/crates/team-agent/src/mcp_server/tests.rs +38 -0
  104. package/crates/team-agent/src/mcp_server/tools.rs +603 -0
  105. package/crates/team-agent/src/mcp_server/types.rs +421 -0
  106. package/crates/team-agent/src/mcp_server/wire.rs +468 -0
  107. package/crates/team-agent/src/message_store.rs +767 -0
  108. package/crates/team-agent/src/messaging/activity.rs +433 -0
  109. package/crates/team-agent/src/messaging/delivery.rs +743 -0
  110. package/crates/team-agent/src/messaging/helpers.rs +209 -0
  111. package/crates/team-agent/src/messaging/leader_receiver.rs +329 -0
  112. package/crates/team-agent/src/messaging/mod.rs +147 -0
  113. package/crates/team-agent/src/messaging/peers.rs +32 -0
  114. package/crates/team-agent/src/messaging/results.rs +553 -0
  115. package/crates/team-agent/src/messaging/scheduler.rs +344 -0
  116. package/crates/team-agent/src/messaging/selftest.rs +100 -0
  117. package/crates/team-agent/src/messaging/send.rs +578 -0
  118. package/crates/team-agent/src/messaging/tests/basic.rs +357 -0
  119. package/crates/team-agent/src/messaging/tests/main_preserved.rs +122 -0
  120. package/crates/team-agent/src/messaging/tests/mod.rs +293 -0
  121. package/crates/team-agent/src/messaging/tests/runtime.rs +1422 -0
  122. package/crates/team-agent/src/messaging/tests/spine.rs +437 -0
  123. package/crates/team-agent/src/messaging/trust.rs +192 -0
  124. package/crates/team-agent/src/messaging/types.rs +355 -0
  125. package/crates/team-agent/src/messaging/watchers.rs +591 -0
  126. package/crates/team-agent/src/model/enums.rs +311 -0
  127. package/crates/team-agent/src/model/errors.rs +17 -0
  128. package/crates/team-agent/src/model/ids.rs +155 -0
  129. package/crates/team-agent/src/model/mod.rs +22 -0
  130. package/crates/team-agent/src/model/paths.rs +228 -0
  131. package/crates/team-agent/src/model/permissions.rs +567 -0
  132. package/crates/team-agent/src/model/routing.rs +340 -0
  133. package/crates/team-agent/src/model/spec.rs +680 -0
  134. package/crates/team-agent/src/model/task_graph.rs +380 -0
  135. package/crates/team-agent/src/model/testdata/fuzz.golden.yaml +43 -0
  136. package/crates/team-agent/src/model/testdata/fuzz.yaml +43 -0
  137. package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +207 -0
  138. package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +206 -0
  139. package/crates/team-agent/src/model/testdata/team.spec.yaml +206 -0
  140. package/crates/team-agent/src/model/yaml/tests.rs +288 -0
  141. package/crates/team-agent/src/model/yaml.rs +800 -0
  142. package/crates/team-agent/src/packaging/install.rs +305 -0
  143. package/crates/team-agent/src/packaging/migrate.rs +30 -0
  144. package/crates/team-agent/src/packaging/mod.rs +82 -0
  145. package/crates/team-agent/src/packaging/repair.rs +24 -0
  146. package/crates/team-agent/src/packaging/tests.rs +829 -0
  147. package/crates/team-agent/src/packaging/types.rs +369 -0
  148. package/crates/team-agent/src/provider/adapter.rs +801 -0
  149. package/crates/team-agent/src/provider/approvals/mod.rs +2 -0
  150. package/crates/team-agent/src/provider/approvals/parsing.rs +452 -0
  151. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +163 -0
  152. package/crates/team-agent/src/provider/classify.rs +456 -0
  153. package/crates/team-agent/src/provider/faults.rs +136 -0
  154. package/crates/team-agent/src/provider/helpers.rs +41 -0
  155. package/crates/team-agent/src/provider/mod.rs +53 -0
  156. package/crates/team-agent/src/provider/startup_prompt.rs +423 -0
  157. package/crates/team-agent/src/provider/tests/adapter.rs +239 -0
  158. package/crates/team-agent/src/provider/tests/classify.rs +240 -0
  159. package/crates/team-agent/src/provider/tests/faults.rs +120 -0
  160. package/crates/team-agent/src/provider/tests/idle.rs +208 -0
  161. package/crates/team-agent/src/provider/tests/wire.rs +213 -0
  162. package/crates/team-agent/src/provider/tests.rs +31 -0
  163. package/crates/team-agent/src/provider/types.rs +424 -0
  164. package/crates/team-agent/src/state/identity.rs +659 -0
  165. package/crates/team-agent/src/state/mod.rs +58 -0
  166. package/crates/team-agent/src/state/owner_gate.rs +423 -0
  167. package/crates/team-agent/src/state/persist.rs +712 -0
  168. package/crates/team-agent/src/state/projection.rs +657 -0
  169. package/crates/team-agent/src/state/selector.rs +105 -0
  170. package/crates/team-agent/src/state/testdata/state-rich.canonical.json +133 -0
  171. package/crates/team-agent/src/tmux_backend/tests.rs +765 -0
  172. package/crates/team-agent/src/tmux_backend.rs +810 -0
  173. package/crates/team-agent/src/transport/test_support.rs +252 -0
  174. package/crates/team-agent/src/transport/tests/behavior.rs +327 -0
  175. package/crates/team-agent/src/transport/tests/mod.rs +199 -0
  176. package/crates/team-agent/src/transport/tests/wire.rs +527 -0
  177. package/crates/team-agent/src/transport.rs +774 -0
  178. package/npm/install.mjs +118 -112
  179. package/package.json +15 -13
  180. package/crates/team-agent-core/Cargo.toml +0 -12
  181. package/crates/team-agent-core/src/lib.rs +0 -332
  182. package/crates/team-agent-core/src/main.rs +0 -152
  183. package/pyproject.toml +0 -18
  184. package/scripts/install.py +0 -88
  185. package/scripts/run_regression_tests.py +0 -83
  186. package/src/team_agent/__init__.py +0 -3
  187. package/src/team_agent/__main__.py +0 -5
  188. package/src/team_agent/_legacy_pane_discovery.py +0 -186
  189. package/src/team_agent/abnormal_track.py +0 -253
  190. package/src/team_agent/approvals/__init__.py +0 -65
  191. package/src/team_agent/approvals/constants.py +0 -6
  192. package/src/team_agent/approvals/parsing.py +0 -176
  193. package/src/team_agent/approvals/runtime_prompts.py +0 -171
  194. package/src/team_agent/approvals/status.py +0 -176
  195. package/src/team_agent/cli/__init__.py +0 -137
  196. package/src/team_agent/cli/commands.py +0 -481
  197. package/src/team_agent/cli/e2e.py +0 -202
  198. package/src/team_agent/cli/helpers.py +0 -226
  199. package/src/team_agent/cli/parser.py +0 -540
  200. package/src/team_agent/compiler.py +0 -334
  201. package/src/team_agent/coordinator/__init__.py +0 -53
  202. package/src/team_agent/coordinator/__main__.py +0 -119
  203. package/src/team_agent/coordinator/lifecycle.py +0 -411
  204. package/src/team_agent/coordinator/metadata.py +0 -61
  205. package/src/team_agent/coordinator/paths.py +0 -17
  206. package/src/team_agent/diagnose/__init__.py +0 -48
  207. package/src/team_agent/diagnose/checks.py +0 -101
  208. package/src/team_agent/diagnose/comms.py +0 -213
  209. package/src/team_agent/diagnose/health.py +0 -241
  210. package/src/team_agent/diagnose/orphan_cleanup.py +0 -364
  211. package/src/team_agent/diagnose/preflight.py +0 -194
  212. package/src/team_agent/diagnose/quick_start.py +0 -324
  213. package/src/team_agent/display/__init__.py +0 -92
  214. package/src/team_agent/display/adaptive.py +0 -511
  215. package/src/team_agent/display/backend.py +0 -46
  216. package/src/team_agent/display/close.py +0 -154
  217. package/src/team_agent/display/ghostty.py +0 -77
  218. package/src/team_agent/display/rebuild.py +0 -102
  219. package/src/team_agent/display/tiling.py +0 -156
  220. package/src/team_agent/display/worker_window.py +0 -114
  221. package/src/team_agent/display/workspace.py +0 -382
  222. package/src/team_agent/errors.py +0 -10
  223. package/src/team_agent/events.py +0 -84
  224. package/src/team_agent/fake_worker.py +0 -80
  225. package/src/team_agent/idle_predicate.py +0 -218
  226. package/src/team_agent/idle_takeover.py +0 -59
  227. package/src/team_agent/idle_takeover_wiring.py +0 -114
  228. package/src/team_agent/launch/__init__.py +0 -41
  229. package/src/team_agent/launch/bootstrap.py +0 -85
  230. package/src/team_agent/launch/config.py +0 -106
  231. package/src/team_agent/launch/core.py +0 -301
  232. package/src/team_agent/launch/requirements.py +0 -57
  233. package/src/team_agent/leader/__init__.py +0 -926
  234. package/src/team_agent/leader_binding.py +0 -183
  235. package/src/team_agent/lifecycle/__init__.py +0 -5
  236. package/src/team_agent/lifecycle/agents.py +0 -278
  237. package/src/team_agent/lifecycle/operations.py +0 -411
  238. package/src/team_agent/lifecycle/paste_buffer_hygiene.py +0 -39
  239. package/src/team_agent/lifecycle/start.py +0 -363
  240. package/src/team_agent/mcp_server/__init__.py +0 -42
  241. package/src/team_agent/mcp_server/__main__.py +0 -7
  242. package/src/team_agent/mcp_server/contracts.py +0 -148
  243. package/src/team_agent/mcp_server/normalize.py +0 -257
  244. package/src/team_agent/mcp_server/server.py +0 -150
  245. package/src/team_agent/mcp_server/tools.py +0 -352
  246. package/src/team_agent/message_store/__init__.py +0 -23
  247. package/src/team_agent/message_store/agent_health.py +0 -113
  248. package/src/team_agent/message_store/core.py +0 -497
  249. package/src/team_agent/message_store/leader_notification_log.py +0 -198
  250. package/src/team_agent/message_store/result_watchers.py +0 -251
  251. package/src/team_agent/message_store/schema.py +0 -308
  252. package/src/team_agent/message_store/schema_migration.py +0 -448
  253. package/src/team_agent/messaging/__init__.py +0 -1
  254. package/src/team_agent/messaging/activity_detector.py +0 -262
  255. package/src/team_agent/messaging/delivery.py +0 -504
  256. package/src/team_agent/messaging/deps.py +0 -247
  257. package/src/team_agent/messaging/idle_alerts.py +0 -423
  258. package/src/team_agent/messaging/internal_delivery.py +0 -46
  259. package/src/team_agent/messaging/leader.py +0 -497
  260. package/src/team_agent/messaging/leader_api_errors.py +0 -216
  261. package/src/team_agent/messaging/leader_panes.py +0 -673
  262. package/src/team_agent/messaging/owner_bypass.py +0 -29
  263. package/src/team_agent/messaging/result_delivery.py +0 -539
  264. package/src/team_agent/messaging/results.py +0 -447
  265. package/src/team_agent/messaging/scheduler.py +0 -450
  266. package/src/team_agent/messaging/send.py +0 -532
  267. package/src/team_agent/messaging/session_drift.py +0 -94
  268. package/src/team_agent/messaging/tmux_io.py +0 -506
  269. package/src/team_agent/messaging/tmux_prompt.py +0 -338
  270. package/src/team_agent/messaging/trust_auto_answer.py +0 -52
  271. package/src/team_agent/orchestrator/__init__.py +0 -376
  272. package/src/team_agent/orchestrator/plan.py +0 -122
  273. package/src/team_agent/orchestrator/state.py +0 -128
  274. package/src/team_agent/paths.py +0 -45
  275. package/src/team_agent/permissions.py +0 -123
  276. package/src/team_agent/profiles/__init__.py +0 -82
  277. package/src/team_agent/profiles/constants.py +0 -19
  278. package/src/team_agent/profiles/core.py +0 -407
  279. package/src/team_agent/profiles/helpers.py +0 -69
  280. package/src/team_agent/profiles/provider_env.py +0 -188
  281. package/src/team_agent/profiles/smoke.py +0 -201
  282. package/src/team_agent/provider_cli/__init__.py +0 -43
  283. package/src/team_agent/provider_cli/adapter.py +0 -172
  284. package/src/team_agent/provider_cli/base.py +0 -48
  285. package/src/team_agent/provider_cli/claude.py +0 -503
  286. package/src/team_agent/provider_cli/codex.py +0 -336
  287. package/src/team_agent/provider_cli/copilot.py +0 -8
  288. package/src/team_agent/provider_cli/fake.py +0 -39
  289. package/src/team_agent/provider_cli/gemini.py +0 -95
  290. package/src/team_agent/provider_cli/opencode.py +0 -8
  291. package/src/team_agent/provider_cli/prompt.py +0 -62
  292. package/src/team_agent/provider_cli/registry.py +0 -18
  293. package/src/team_agent/provider_cli/unsupported.py +0 -32
  294. package/src/team_agent/provider_state/README.md +0 -78
  295. package/src/team_agent/provider_state/__init__.py +0 -91
  296. package/src/team_agent/provider_state/claude.py +0 -86
  297. package/src/team_agent/provider_state/codex.py +0 -84
  298. package/src/team_agent/provider_state/common.py +0 -207
  299. package/src/team_agent/provider_state/registry.py +0 -118
  300. package/src/team_agent/providers.py +0 -163
  301. package/src/team_agent/quality_gates.py +0 -104
  302. package/src/team_agent/restart/__init__.py +0 -34
  303. package/src/team_agent/restart/orchestration.py +0 -554
  304. package/src/team_agent/restart/selection.py +0 -89
  305. package/src/team_agent/restart/snapshot.py +0 -70
  306. package/src/team_agent/routing.py +0 -84
  307. package/src/team_agent/runtime.py +0 -1243
  308. package/src/team_agent/rust_core.py +0 -327
  309. package/src/team_agent/sessions/__init__.py +0 -25
  310. package/src/team_agent/sessions/capture.py +0 -144
  311. package/src/team_agent/sessions/inventory.py +0 -44
  312. package/src/team_agent/sessions/resume.py +0 -135
  313. package/src/team_agent/simple_yaml.py +0 -236
  314. package/src/team_agent/spec.py +0 -370
  315. package/src/team_agent/state.py +0 -693
  316. package/src/team_agent/status/__init__.py +0 -63
  317. package/src/team_agent/status/approvals.py +0 -52
  318. package/src/team_agent/status/compact.py +0 -158
  319. package/src/team_agent/status/constants.py +0 -18
  320. package/src/team_agent/status/inbox.py +0 -58
  321. package/src/team_agent/status/peek.py +0 -117
  322. package/src/team_agent/status/queries.py +0 -199
  323. package/src/team_agent/task_graph.py +0 -80
  324. package/src/team_agent/terminal.py +0 -57
  325. package/src/team_agent/wake.py +0 -58
  326. package/src/team_agent/watch/__init__.py +0 -145
@@ -1,481 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import json
5
- import shutil
6
- import sys
7
- from pathlib import Path
8
- from typing import Any
9
-
10
- from team_agent import compiler, profiles, runtime
11
- from team_agent.errors import TeamAgentError
12
- from team_agent.paths import repo_root, team_workspace
13
- from team_agent.spec import validate_result_envelope
14
-
15
- from team_agent.cli.helpers import _provider_args
16
-
17
-
18
- def cmd_quick_start(args: argparse.Namespace) -> dict[str, Any]:
19
- result = runtime.quick_start(Path(args.agents_dir), name=args.name, yes=args.yes, fresh=args.fresh, team_id=args.team_id)
20
- if args.json or not result.get("ok"):
21
- return result
22
- return result["summary"]
23
-
24
-
25
- def cmd_codex(args: argparse.Namespace) -> None:
26
- runtime.start_leader("codex", _provider_args(args.provider_args), Path.cwd().resolve())
27
-
28
-
29
- def cmd_claude(args: argparse.Namespace) -> None:
30
- runtime.start_leader("claude_code", _provider_args(args.provider_args), Path.cwd().resolve())
31
-
32
-
33
- def cmd_init(args: argparse.Namespace) -> dict[str, Any]:
34
- paths = runtime.init_workspace(Path(args.workspace).resolve(), force=args.force)
35
- return {"ok": True, "spec": str(paths["spec"]), "state": str(paths["state"])}
36
-
37
-
38
- def cmd_validate(args: argparse.Namespace) -> dict[str, Any]:
39
- return runtime.validate_file(Path(args.spec).resolve())
40
-
41
-
42
- def cmd_compile(args: argparse.Namespace) -> dict[str, Any]:
43
- result = compiler.compile_team(Path(args.team).resolve(), Path(args.out).resolve())
44
- return {"ok": True, "team_dir": result["team_dir"], "out": result["out"], "agents": [a["id"] for a in result["spec"]["agents"]]}
45
-
46
-
47
- def _profile_scope(args: argparse.Namespace) -> tuple[Path, Path | None]:
48
- team = getattr(args, "team", None)
49
- if team:
50
- team_dir = Path(team).resolve()
51
- return team_workspace(team_dir), team_dir / "profiles"
52
- return Path(args.workspace).resolve(), None
53
-
54
-
55
- def cmd_profile_init(args: argparse.Namespace) -> dict[str, Any]:
56
- workspace, profiles_dir = _profile_scope(args)
57
- return profiles.init_profile(workspace, args.name, args.auth_mode, profiles_dir=profiles_dir)
58
-
59
-
60
- def cmd_profile_doctor(args: argparse.Namespace) -> dict[str, Any]:
61
- workspace, profiles_dir = _profile_scope(args)
62
- return profiles.doctor_profile(workspace, args.name, profiles_dir=profiles_dir)
63
-
64
-
65
- def cmd_profile_show(args: argparse.Namespace) -> dict[str, Any]:
66
- workspace, profiles_dir = _profile_scope(args)
67
- return profiles.show_profile(workspace, args.name, profiles_dir=profiles_dir)
68
-
69
-
70
- def cmd_launch(args: argparse.Namespace) -> dict[str, Any]:
71
- return runtime.launch(Path(args.spec).resolve(), dry_run=args.dry_run, auto_approve=args.yes)
72
-
73
-
74
- def cmd_preflight(args: argparse.Namespace) -> dict[str, Any]:
75
- return runtime.preflight(Path(args.team).resolve())
76
-
77
-
78
- def cmd_start(args: argparse.Namespace) -> dict[str, Any]:
79
- return runtime.start(Path(args.team).resolve(), yes=args.yes)
80
-
81
-
82
- def cmd_wait_ready(args: argparse.Namespace) -> dict[str, Any]:
83
- return runtime.wait_ready(Path(args.workspace).resolve(), timeout=args.timeout)
84
-
85
-
86
- def cmd_settle(args: argparse.Namespace) -> dict[str, Any]:
87
- return runtime.settle(Path(args.workspace).resolve())
88
-
89
-
90
- def cmd_status(args: argparse.Namespace) -> dict[str, Any]:
91
- if getattr(args, "summary", False) is True:
92
- if getattr(args, "json", False) is True:
93
- raise TeamAgentError("--summary and --json are mutually exclusive")
94
- if getattr(args, "agent", None):
95
- raise TeamAgentError("status --summary does not accept an agent argument")
96
- data = runtime.status(Path(args.workspace).resolve(), as_json=True, compact=False)
97
- return _format_status_summary(data)
98
- if getattr(args, "json", False) is True:
99
- return runtime.status(Path(args.workspace).resolve(), as_json=True, compact=not (getattr(args, "detail", False) is True))
100
- return runtime.format_status(Path(args.workspace).resolve(), getattr(args, "agent", None))
101
-
102
-
103
- def cmd_watch(args: argparse.Namespace) -> None:
104
- from team_agent.watch import run_watch
105
- try:
106
- run_watch(Path(args.workspace).resolve(), team=getattr(args, "team", None))
107
- except KeyboardInterrupt:
108
- raise SystemExit(0)
109
- raise SystemExit(0)
110
-
111
-
112
- def cmd_approvals(args: argparse.Namespace) -> dict[str, Any]:
113
- if args.json:
114
- return runtime.approvals(Path(args.workspace).resolve(), agent_id=args.agent)
115
- return runtime.format_approvals(Path(args.workspace).resolve(), agent_id=args.agent)
116
-
117
-
118
- def cmd_peek(args: argparse.Namespace) -> dict[str, Any]:
119
- if not args.allow_raw_screen:
120
- raise TeamAgentError(
121
- "raw worker terminal inspection requires explicit user authorization and --allow-raw-screen; "
122
- "normal operation must use status, approvals, inbox, collect, or event logs"
123
- )
124
- result = runtime.peek(
125
- Path(args.workspace).resolve(),
126
- args.agent,
127
- head=args.head,
128
- tail=args.tail,
129
- search=args.search,
130
- context=args.context,
131
- )
132
- if args.json:
133
- return result
134
- return result["text"]
135
-
136
-
137
- def cmd_inbox(args: argparse.Namespace) -> dict[str, Any]:
138
- since = getattr(args, "since", None)
139
- if args.json:
140
- return runtime.inbox(Path(args.workspace).resolve(), args.agent, limit=args.limit, since=since)
141
- return runtime.format_inbox(Path(args.workspace).resolve(), args.agent, limit=args.limit, since=since)
142
-
143
-
144
- def cmd_sessions(args: argparse.Namespace) -> dict[str, Any]:
145
- return runtime.sessions(Path(args.workspace).resolve())
146
-
147
-
148
- def cmd_attach_leader(args: argparse.Namespace) -> dict[str, Any]:
149
- return runtime.attach_leader(Path(args.workspace).resolve(), pane=args.pane, provider=args.provider)
150
-
151
-
152
- def cmd_takeover(args: argparse.Namespace) -> dict[str, Any]:
153
- return runtime.takeover(Path(args.workspace).resolve(), team=args.team, confirm=args.confirm)
154
-
155
-
156
- def cmd_claim_leader(args: argparse.Namespace) -> dict[str, Any]:
157
- return runtime.claim_leader(Path(args.workspace).resolve(), team=args.team, confirm=args.confirm)
158
-
159
-
160
- def cmd_identity(args: argparse.Namespace) -> dict[str, Any]:
161
- return runtime.leader_identity(Path(args.workspace).resolve(), team=args.team)
162
-
163
-
164
- def cmd_send(args: argparse.Namespace) -> dict[str, Any]:
165
- target = _send_target(args)
166
- return runtime.send_message(
167
- Path(args.workspace).resolve(),
168
- target,
169
- " ".join(args.message),
170
- task_id=args.task,
171
- sender=args.sender,
172
- requires_ack=not args.no_ack,
173
- confirm_human=args.confirm_human,
174
- wait_visible=not args.no_wait,
175
- timeout=args.timeout,
176
- watch_result=args.watch_result,
177
- team=args.team,
178
- )
179
-
180
-
181
- def _send_target(args: argparse.Namespace) -> str | list[str] | None:
182
- if getattr(args, "targets", None):
183
- return [item.strip() for item in args.targets.split(",") if item.strip()]
184
- return args.target
185
-
186
-
187
- def cmd_collect(args: argparse.Namespace) -> dict[str, Any]:
188
- result_file = Path(args.result_file).resolve() if args.result_file else None
189
- return runtime.collect(Path(args.workspace).resolve(), result_file=result_file)
190
-
191
-
192
- def cmd_diagnose(args: argparse.Namespace) -> dict[str, Any]:
193
- return runtime.diagnose(Path(args.workspace).resolve())
194
-
195
-
196
- def cmd_repair_state(args: argparse.Namespace) -> dict[str, Any]:
197
- return runtime.repair_state(
198
- Path(args.workspace).resolve(),
199
- task_id=args.task,
200
- assignee=args.assignee,
201
- status_value=args.status,
202
- summary=args.summary,
203
- )
204
-
205
-
206
- def cmd_validate_result(args: argparse.Namespace) -> dict[str, Any]:
207
- if args.file:
208
- raw = Path(args.file).read_text(encoding="utf-8")
209
- elif args.result:
210
- raw = args.result
211
- else:
212
- raw = sys.stdin.read()
213
- envelope = json.loads(raw)
214
- validate_result_envelope(envelope)
215
- return {"ok": True, "task_id": envelope["task_id"], "agent_id": envelope["agent_id"], "status": envelope["status"]}
216
-
217
-
218
- def cmd_doctor(args: argparse.Namespace) -> dict[str, Any] | str:
219
- gate = getattr(args, "gate", None)
220
- if getattr(args, "fix", False) is True and not gate:
221
- raise TeamAgentError("--fix requires --gate")
222
- if getattr(args, "comms", False) is True or gate == "comms":
223
- from team_agent.diagnose.comms import COMMS_BOUNDARY_TEXT, run_comms_selftest
224
- result = run_comms_selftest(
225
- Path(args.workspace).resolve(),
226
- team=getattr(args, "team", None),
227
- gate=gate,
228
- )
229
- if args.json:
230
- return result
231
- return f"{COMMS_BOUNDARY_TEXT}\n{json.dumps(result, indent=2, ensure_ascii=False, sort_keys=True)}"
232
- if isinstance(gate, str) and gate:
233
- from team_agent.diagnose.orphan_cleanup import orphan_gate
234
- if gate != "orphans":
235
- raise TeamAgentError(f"unknown doctor gate: {gate}")
236
- return orphan_gate(fix=bool(getattr(args, "fix", False)), confirm=bool(getattr(args, "confirm", False)))
237
- from team_agent.message_store.schema import SCHEMA_VERSION
238
- from team_agent.message_store.schema_migration import fix_schema_layout, schema_diagnosis
239
- if getattr(args, "fix_schema", False) is True:
240
- return fix_schema_layout(Path(args.workspace).resolve(), schema_version=SCHEMA_VERSION)
241
- schema = schema_diagnosis(Path(args.workspace).resolve(), schema_version=SCHEMA_VERSION)
242
- if schema.get("layout_diffs"):
243
- return {
244
- "ok": True,
245
- "schema": schema,
246
- "coordinator": {
247
- "schema_ok": False,
248
- "schema_error": "team.db physical layout drift detected",
249
- },
250
- }
251
- if getattr(args, "cleanup_orphans", False):
252
- from team_agent.diagnose.orphan_cleanup import cleanup_orphan_coordinators, format_cleanup_orphans
253
- result = cleanup_orphan_coordinators(confirm=bool(getattr(args, "confirm", False)))
254
- if args.json:
255
- return result
256
- return format_cleanup_orphans(result)
257
- spec = Path(args.spec).resolve() if args.spec else None
258
- result = runtime.doctor(spec)
259
- result["schema"] = schema
260
- return result
261
-
262
-
263
- def _format_status_summary(data: dict[str, Any]) -> str:
264
- coordinator = data.get("coordinator") or {}
265
- receiver = data.get("leader_receiver") or {}
266
- agents = data.get("agents") or {}
267
- health = data.get("agent_health") or {}
268
- latest = (data.get("latest_results") or [{}])[0] if data.get("latest_results") else None
269
- counts = _agent_summary_counts(agents, health)
270
- agents_line = (
271
- f"agents: {len(agents)} — running={counts['running']} busy={counts['busy']} "
272
- f"idle={counts['idle']} stopped={counts['stopped']} failed={counts['failed']} "
273
- f"unknown={counts['unknown']}"
274
- )
275
- # C3 (cr verdict, 2026-05-27): append a (N interacted, M never) marker
276
- # only when at least one worker has a valid first_send_at stamp. When N
277
- # is zero, the agents line stays byte-identical to the pre-Route-B
278
- # output so the Gap 18a triage contract (strict five-line shape with
279
- # exact line[2] string) remains unchanged.
280
- interacted_count, never_count = _interaction_counts(agents)
281
- if interacted_count > 0:
282
- agents_line = f"{agents_line} ({interacted_count} interacted, {never_count} never)"
283
- return "\n".join([
284
- f"coordinator: {coordinator.get('status') or 'stopped'} schema_ok={bool(coordinator.get('schema_ok'))} tmux={bool(data.get('tmux_session_present'))}",
285
- f"receiver: {receiver.get('pane_id') or '-'} cmd={receiver.get('pane_current_command') or receiver.get('current_command') or '-'}",
286
- agents_line,
287
- f"queued: {len(data.get('queued_messages') or [])} mailbox messages awaiting delivery",
288
- _latest_result_line(latest),
289
- ])
290
-
291
-
292
- def _interaction_counts(agents: dict[str, Any]) -> tuple[int, int]:
293
- """Return (interacted, never_interacted) over the agents dict. An agent is
294
- interacted when its `interacted` field (added by status.queries.status) is
295
- a non-empty string other than the literal "never". This intentionally
296
- sources from the enriched per-status interacted field rather than re-
297
- parsing first_send_at so the summary stays a derived view."""
298
- interacted = 0
299
- never = 0
300
- for entry in agents.values():
301
- marker = (entry or {}).get("interacted") if isinstance(entry, dict) else None
302
- if isinstance(marker, str) and marker and marker != "never":
303
- interacted += 1
304
- else:
305
- never += 1
306
- return interacted, never
307
-
308
-
309
- def _agent_summary_counts(agents: dict[str, Any], health: dict[str, Any]) -> dict[str, int]:
310
- counts = dict.fromkeys(("running", "busy", "idle", "stopped", "failed", "unknown"), 0)
311
- for agent_id, agent in agents.items():
312
- raw = str((agent or {}).get("status") or "").lower()
313
- hstatus = str((health.get(agent_id) or {}).get("status") or "").lower()
314
- if raw in {"failed", "error"} or hstatus in {"failed", "error"}:
315
- counts["failed"] += 1
316
- elif raw in {"stopped", "done"} or hstatus == "done":
317
- counts["stopped"] += 1
318
- elif raw == "busy" or hstatus in {"running", "working"}:
319
- counts["busy"] += 1
320
- elif hstatus == "idle":
321
- counts["idle"] += 1
322
- elif raw in {"blocked", "awaiting_approval", "interrupted", "missing", "stuck", "uncertain"} or hstatus in {
323
- "blocked", "awaiting_approval", "interrupted", "missing", "stuck", "uncertain"
324
- }:
325
- counts["unknown"] += 1
326
- elif raw == "running":
327
- counts["running"] += 1
328
- else:
329
- counts["unknown"] += 1
330
- return counts
331
-
332
-
333
- def _latest_result_line(result: dict[str, Any] | None) -> str:
334
- if not result:
335
- return "latest result: none"
336
- summary = str(result.get("summary") or "").replace("\n", " ")[:80]
337
- return f"latest result: {result.get('agent_id') or '-'} -> {summary or '-'} @ {runtime._age_text(result.get('created_at'))}"
338
-
339
-
340
- def cmd_shutdown(args: argparse.Namespace) -> dict[str, Any]:
341
- return runtime.shutdown(Path(args.workspace).resolve(), keep_logs=args.keep_logs, team=args.team)
342
-
343
-
344
- def cmd_restart(args: argparse.Namespace) -> dict[str, Any]:
345
- return runtime.restart(Path(args.workspace).resolve(), allow_fresh=args.allow_fresh, team=args.team)
346
-
347
-
348
- def cmd_start_agent(args: argparse.Namespace) -> dict[str, Any]:
349
- return runtime.start_agent(
350
- Path(args.workspace).resolve(),
351
- args.agent,
352
- force=args.force,
353
- open_display=not args.no_display,
354
- allow_fresh=args.allow_fresh,
355
- team=args.team,
356
- )
357
-
358
-
359
- def cmd_stop_agent(args: argparse.Namespace) -> dict[str, Any]:
360
- return runtime.stop_agent(Path(args.workspace).resolve(), args.agent, team=args.team)
361
-
362
-
363
- def cmd_reset_agent(args: argparse.Namespace) -> dict[str, Any]:
364
- return runtime.reset_agent(
365
- Path(args.workspace).resolve(),
366
- args.agent,
367
- discard_session=args.discard_session,
368
- open_display=not args.no_display,
369
- team=args.team,
370
- )
371
-
372
-
373
- def cmd_add_agent(args: argparse.Namespace) -> dict[str, Any]:
374
- return runtime.add_agent(
375
- Path(args.workspace).resolve(),
376
- args.agent,
377
- role_file_path=args.role_file,
378
- open_display=not args.no_display,
379
- team=args.team,
380
- )
381
-
382
-
383
- def cmd_fork_agent(args: argparse.Namespace) -> dict[str, Any]:
384
- return runtime.fork_agent(
385
- Path(args.workspace).resolve(),
386
- args.source_agent,
387
- as_agent_id=args.as_agent,
388
- label=args.label,
389
- open_display=not args.no_display,
390
- team=args.team,
391
- )
392
-
393
-
394
- def cmd_remove_agent(args: argparse.Namespace) -> dict[str, Any]:
395
- return runtime.remove_agent(
396
- Path(args.workspace).resolve(),
397
- args.agent,
398
- from_spec=args.from_spec,
399
- confirm=args.confirm,
400
- force=args.force,
401
- team=args.team,
402
- )
403
-
404
-
405
- def cmd_stuck_list(args: argparse.Namespace) -> dict[str, Any]:
406
- return runtime.stuck_list(Path(args.workspace).resolve())
407
-
408
-
409
- def cmd_stuck_cancel(args: argparse.Namespace) -> dict[str, Any]:
410
- return runtime.stuck_cancel(
411
- Path(args.workspace).resolve(),
412
- args.agent,
413
- alert_type=args.alert_type,
414
- suppressed_by="leader",
415
- )
416
-
417
-
418
- def cmd_acknowledge_idle(args: argparse.Namespace) -> dict[str, Any]:
419
- return runtime.acknowledge_idle(Path(args.workspace).resolve(), team=args.team)
420
-
421
-
422
- def cmd_allow_peer_talk(args: argparse.Namespace) -> dict[str, Any]:
423
- return runtime.allow_peer_talk(Path(args.workspace).resolve(), args.agent_a, args.agent_b)
424
-
425
-
426
- def cmd_run_overnight(args: argparse.Namespace) -> dict[str, Any]:
427
- from team_agent import orchestrator
428
- workspace = Path(args.workspace).resolve()
429
- if args.status:
430
- return orchestrator.plan_status(workspace, plan_id=args.plan_id)
431
- if args.halt:
432
- if not args.plan_id:
433
- raise TeamAgentError("--halt requires --plan-id")
434
- return orchestrator.halt_plan(workspace, args.plan_id, reason=args.reason)
435
- if not args.plan:
436
- raise TeamAgentError("--plan PATH is required unless --status or --halt is used")
437
- return orchestrator.start_plan(workspace, Path(args.plan).resolve(), start=not args.no_start)
438
-
439
-
440
- def cmd_advanced(args: argparse.Namespace) -> str:
441
- return "\n".join(
442
- [
443
- "Low-level commands:",
444
- " init validate compile profile launch preflight start wait-ready settle",
445
- " sessions attach-leader collect diagnose repair-state validate-result",
446
- " install-skill e2e",
447
- ]
448
- )
449
-
450
-
451
- def cmd_install_skill(args: argparse.Namespace) -> dict[str, Any]:
452
- source = repo_root() / "skills" / "team-agent"
453
- if args.dest and args.target == "all":
454
- raise TeamAgentError("--dest cannot be combined with --target all")
455
- if args.dest:
456
- dest_dir = Path(args.dest).expanduser().resolve()
457
- return _install_skill_to(source, dest_dir, args.dry_run)
458
- if args.target == "all":
459
- results = [
460
- _install_skill_to(source, _skill_dest_dir("codex"), args.dry_run),
461
- _install_skill_to(source, _skill_dest_dir("claude"), args.dry_run),
462
- ]
463
- return {"ok": all(item["ok"] for item in results), "targets": results}
464
- return _install_skill_to(source, _skill_dest_dir(args.target), args.dry_run)
465
-
466
-
467
- def _skill_dest_dir(target: str) -> Path:
468
- if target == "claude":
469
- dest_dir = Path.home() / ".claude" / "skills" / "team-agent"
470
- else:
471
- dest_dir = Path.home() / ".codex" / "skills" / "team-agent"
472
- return dest_dir
473
-
474
-
475
- def _install_skill_to(source: Path, dest_dir: Path, dry_run: bool) -> dict[str, Any]:
476
- dest = dest_dir / "SKILL.md"
477
- if dry_run:
478
- return {"ok": True, "source": str(source / "SKILL.md"), "dest": str(dest), "dry_run": True}
479
- dest_dir.mkdir(parents=True, exist_ok=True)
480
- shutil.copytree(source, dest_dir, dirs_exist_ok=True)
481
- return {"ok": True, "source": str(source / "SKILL.md"), "dest": str(dest)}
@@ -1,202 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import tempfile
5
- from pathlib import Path
6
- from typing import Any
7
-
8
- from team_agent import runtime
9
- from team_agent.simple_yaml import dumps
10
-
11
-
12
- def cmd_e2e(args: argparse.Namespace) -> dict[str, Any]:
13
- providers = [item.strip() for item in args.providers.split(",") if item.strip()]
14
- workspace = Path(args.workspace).resolve() if args.workspace else Path(tempfile.mkdtemp(prefix="team-agent-e2e-"))
15
- workspace.mkdir(parents=True, exist_ok=True)
16
- results: dict[str, Any] = {"workspace": str(workspace), "providers": {}, "ok": True}
17
- if "fake" in providers:
18
- spec_path = workspace / "team.spec.yaml"
19
- spec_path.write_text(dumps(_fake_spec(workspace)), encoding="utf-8")
20
- results["providers"]["fake"] = _run_fake_e2e(spec_path, workspace)
21
- results["ok"] = results["ok"] and results["providers"]["fake"]["ok"]
22
- for provider in [p for p in providers if p != "fake"]:
23
- from team_agent.providers import get_adapter
24
-
25
- adapter = get_adapter(provider)
26
- installed = adapter.is_installed()
27
- if not installed:
28
- provider_result = {
29
- "ok": False,
30
- "skipped": True,
31
- "reason": f"{adapter.command_name} not installed",
32
- "version": None,
33
- }
34
- elif not args.real:
35
- provider_result = {
36
- "ok": False,
37
- "skipped": True,
38
- "reason": "real provider launch disabled; rerun with --real on an authenticated machine",
39
- "version": adapter.version(),
40
- }
41
- else:
42
- provider_result = _run_real_launch_smoke(provider, workspace)
43
- results["providers"][provider] = provider_result
44
- results["ok"] = results["ok"] and provider_result["ok"]
45
- return results
46
-
47
-
48
- def _run_fake_e2e(spec_path: Path, workspace: Path) -> dict[str, Any]:
49
- launched = runtime.launch(spec_path, auto_approve=True)
50
- sent = runtime.send_message(workspace, None, "implement fake task", task_id="task_impl", requires_ack=True)
51
- import time
52
-
53
- time.sleep(1.0)
54
- collected = runtime.collect(workspace)
55
- stopped = runtime.shutdown(workspace)
56
- return {"ok": bool(launched["ok"] and sent["ok"] and collected["collected"] and stopped["ok"]), "launch": launched, "send": sent, "collect": collected, "shutdown": stopped}
57
-
58
-
59
- def _run_real_launch_smoke(provider: str, workspace: Path) -> dict[str, Any]:
60
- spec_path = workspace / f"team.{provider}.spec.yaml"
61
- spec = _fake_spec(workspace)
62
- spec["team"]["name"] = f"real-{provider}-smoke"
63
- spec["leader"]["provider"] = provider
64
- spec["agents"][0]["provider"] = provider
65
- spec["agents"][0]["id"] = f"{provider}_smoke"
66
- spec["agents"][0]["tools"] = ["fs_read", "fs_list", "git_diff", "mcp_team", "provider_builtin"]
67
- spec["agents"][0]["role"] = "reviewer"
68
- spec["agents"][0]["system_prompt"]["inline"] = (
69
- "Real provider smoke. Do not edit files or run shell. "
70
- "Do not call team-agent launch and do not create a nested Team Agent team. "
71
- "When asked, call team_orchestrator.report_result exactly once with result_envelope_v1."
72
- )
73
- spec["routing"]["rules"][0]["assign_to"] = spec["agents"][0]["id"]
74
- spec["runtime"]["session_name"] = f"team-agent-real-{provider}"
75
- spec["runtime"]["startup_order"] = [spec["agents"][0]["id"]]
76
- spec["tasks"][0]["id"] = f"task_real_{provider}_callback"
77
- spec["tasks"][0]["title"] = f"Real {provider} callback smoke"
78
- spec["tasks"][0]["assignee"] = spec["agents"][0]["id"]
79
- spec["tasks"][0]["requires_tools"] = ["fs_read", "git_diff"]
80
- spec["tasks"][0]["type"] = "review"
81
- spec_path.write_text(dumps(spec), encoding="utf-8")
82
- launched = runtime.launch(spec_path, auto_approve=True)
83
- import time
84
-
85
- time.sleep(10.0 if provider == "codex" else 3.0)
86
- collected = None
87
- sent = None
88
- if provider == "codex":
89
- task_id = spec["tasks"][0]["id"]
90
- agent_id = spec["agents"][0]["id"]
91
- message = (
92
- "Do not call team-agent launch and do not create a nested Team Agent team. "
93
- "Do not edit files or run shell. "
94
- "Call team_orchestrator.report_result with envelope "
95
- f'{{"schema_version":"result_envelope_v1","task_id":"{task_id}",'
96
- f'"agent_id":"{agent_id}","status":"success","summary":"ok",'
97
- '"changes":[],"tests":[{"command":"real-codex-callback-smoke","status":"passed"}],'
98
- '"risks":[],"artifacts":[],"next_actions":[]}. Do not edit files or run shell.'
99
- )
100
- sent = runtime.send_message(workspace, agent_id, message, task_id=task_id, requires_ack=True)
101
- for _ in range(24):
102
- time.sleep(5.0)
103
- result = runtime.collect(workspace)
104
- if result["collected"]:
105
- collected = result
106
- break
107
- status = runtime.status(workspace, as_json=True)
108
- stopped = runtime.shutdown(workspace)
109
- agent_id = spec["agents"][0]["id"]
110
- agent_status = status["agents"].get(agent_id, {})
111
- callback_ok = provider != "codex" or bool(collected and collected["collected"])
112
- return {
113
- "ok": bool(launched["ok"] and stopped["ok"] and agent_status.get("tmux_window_present") and callback_ok),
114
- "launch": launched,
115
- "send": sent,
116
- "collect": collected,
117
- "status": status,
118
- "shutdown": stopped,
119
- }
120
-
121
-
122
- def _fake_spec(workspace: Path) -> dict[str, Any]:
123
- return {
124
- "version": 1,
125
- "team": {
126
- "name": "fake-e2e",
127
- "mode": "supervisor_worker",
128
- "objective": "Exercise fake provider orchestration.",
129
- "workspace": str(workspace),
130
- },
131
- "leader": {
132
- "id": "leader",
133
- "role": "leader",
134
- "provider": "fake",
135
- "model": None,
136
- "tools": ["fs_read", "fs_list", "mcp_team"],
137
- "context_policy": {
138
- "keep_user_thread": True,
139
- "receive_worker_outputs": "structured_only",
140
- "max_worker_result_tokens": 2000,
141
- },
142
- },
143
- "agents": [
144
- {
145
- "id": "fake_impl",
146
- "role": "implementation_engineer",
147
- "provider": "fake",
148
- "model": None,
149
- "working_directory": str(workspace),
150
- "system_prompt": {"inline": "Handle fake implementation tasks.", "file": None},
151
- "tools": ["fs_read", "fs_write", "fs_list", "execute_bash", "git_diff", "mcp_team", "provider_builtin"],
152
- "permission_mode": "restricted",
153
- "preferred_for": ["implementation"],
154
- "avoid_for": [],
155
- "output_contract": {"format": "result_envelope_v1", "required_fields": ["task_id", "status", "summary", "artifacts"]},
156
- }
157
- ],
158
- "routing": {
159
- "default_assignee": "leader",
160
- "rules": [{"id": "implementation-to-fake", "match": {"type": ["implementation"]}, "assign_to": "fake_impl", "priority": 10}],
161
- },
162
- "communication": {
163
- "protocol": "mcp_inbox",
164
- "topology": "leader_centered",
165
- "worker_to_worker": True,
166
- "ack_timeout_sec": 2,
167
- "result_format": "result_envelope_v1",
168
- "message_store": {"sqlite": ".team/runtime/team.db", "mirror_files": ".team/messages"},
169
- },
170
- "runtime": {
171
- "backend": "tmux",
172
- "display_backend": "none",
173
- "session_name": "team-agent-fake-e2e",
174
- "auto_launch": True,
175
- "require_user_approval_before_launch": False,
176
- "max_active_agents": 1,
177
- "startup_order": ["fake_impl"],
178
- },
179
- "context": {
180
- "state_file": "team_state.md",
181
- "artifact_dir": ".team/artifacts",
182
- "log_dir": ".team/logs",
183
- "summarization": {
184
- "worker_full_logs": "retain_outside_leader_context",
185
- "state_update": "after_each_result",
186
- },
187
- },
188
- "tasks": [
189
- {
190
- "id": "task_impl",
191
- "title": "Fake implementation",
192
- "type": "implementation",
193
- "assignee": None,
194
- "deps": [],
195
- "acceptance": ["fake result collected"],
196
- "status": "pending",
197
- "requires_tools": ["fs_write", "execute_bash"],
198
- "files": ["src/example.py"],
199
- "risk": "low",
200
- }
201
- ],
202
- }