@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,183 +0,0 @@
1
- """Family A — positive-source owner binding (0.2.6).
2
-
3
- Constitution MUST-11 / MUST-NOT-12: the caller identity for owner binding
4
- is sourced from the caller-supplied positive facts only:
5
-
6
- 1. ``$TMUX_PANE`` (the tmux pane the user invoked the CLI from).
7
- 2. ``tmux display-message -p -t $TMUX_PANE '#{pane_current_command}'``
8
- (a single targeted lookup to confirm the caller pane is hosting a
9
- leader CLI).
10
-
11
- Reverse enumeration of panes / windows / clients is forbidden. Heuristic
12
- ranking ("active pane", "current client", "first leader-shaped pane") is
13
- forbidden. ``$TMUX_PANE`` missing → refuse and emit ``owner.bind_refused``.
14
- The pane's current command is diagnostic metadata only. Successful binds emit
15
- ``owner.bound_from_caller_pane`` and force-write every owner identity
16
- field; old fields are not merged or migrated.
17
- """
18
-
19
- from __future__ import annotations
20
-
21
- import hashlib
22
- import os
23
- import subprocess
24
- from datetime import datetime, timezone
25
- from pathlib import Path
26
- from typing import Any
27
-
28
- from team_agent.events import EventLog
29
-
30
-
31
- def run_cmd(args: list[str], timeout: int = 5) -> subprocess.CompletedProcess[str]:
32
- """Tmux command bridge — kept here so contract tests can patch
33
- ``team_agent.leader_binding.run_cmd`` to observe the exact tmux call
34
- pattern this module makes."""
35
- return subprocess.run(
36
- args, text=True, capture_output=True, timeout=timeout, check=False
37
- )
38
-
39
-
40
- _HINT_RUN_FROM_LEADER_PANE = (
41
- "run team-agent from inside your leader pane "
42
- "(the tmux pane you want to own this team)."
43
- )
44
-
45
-
46
- def bind_owner_from_caller_pane(
47
- workspace: Path,
48
- team_id: str,
49
- override_uuid: str | None = None,
50
- ) -> dict[str, Any]:
51
- """Derive the owner identity from the caller pane.
52
-
53
- Returns
54
- -------
55
- On success::
56
-
57
- {
58
- "ok": True,
59
- "owner": {
60
- "pane_id": ..., "leader_session_uuid": ...,
61
- "machine_fingerprint": ..., "provider": ...,
62
- "os_user": ..., "claimed_at": <iso8601>,
63
- },
64
- "caller_pane_id": ..., "caller_current_command": ...,
65
- "team_id": team_id,
66
- }
67
-
68
- On refusal::
69
-
70
- {
71
- "ok": False,
72
- "reason": "caller_pane_missing",
73
- "caller_pane_id": ..., "caller_current_command": ...,
74
- "hint": ...,
75
- }
76
- """
77
- event_log = EventLog(workspace)
78
- caller_pane = os.environ.get("TMUX_PANE") or ""
79
- if not caller_pane:
80
- hint = _HINT_RUN_FROM_LEADER_PANE
81
- event_log.write(
82
- "owner.bind_refused",
83
- reason="caller_pane_missing",
84
- caller_pane_id="",
85
- caller_current_command="",
86
- team_id=team_id,
87
- hint=hint,
88
- )
89
- return {
90
- "ok": False,
91
- "reason": "caller_pane_missing",
92
- "caller_pane_id": "",
93
- "caller_current_command": "",
94
- "hint": hint,
95
- }
96
- proc = run_cmd(
97
- [
98
- "tmux",
99
- "display-message",
100
- "-p",
101
- "-t",
102
- caller_pane,
103
- "#{pane_current_command}",
104
- ],
105
- timeout=5,
106
- )
107
- if getattr(proc, "returncode", 1) != 0:
108
- caller_command = ""
109
- else:
110
- caller_command = (getattr(proc, "stdout", "") or "").strip()
111
- machine_fingerprint = os.environ.get("TEAM_AGENT_MACHINE_FINGERPRINT") or ""
112
- os_user = os.environ.get("USER") or os.environ.get("USERNAME") or ""
113
- provider = (
114
- os.environ.get("TEAM_AGENT_LEADER_PROVIDER")
115
- or _provider_from_command(caller_command)
116
- )
117
- if override_uuid:
118
- leader_session_uuid = override_uuid
119
- else:
120
- env_override = (
121
- os.environ.get("TEAM_AGENT_LEADER_SESSION_UUID_OVERRIDE") or ""
122
- )
123
- if env_override:
124
- leader_session_uuid = env_override
125
- else:
126
- leader_session_uuid = derive_leader_session_uuid(
127
- machine_fingerprint, workspace, os_user, team_id
128
- )
129
- owner = {
130
- "pane_id": caller_pane,
131
- "leader_session_uuid": leader_session_uuid,
132
- "machine_fingerprint": machine_fingerprint,
133
- "provider": provider,
134
- "os_user": os_user,
135
- "claimed_at": datetime.now(timezone.utc).isoformat(),
136
- }
137
- return {
138
- "ok": True,
139
- "owner": owner,
140
- "caller_pane_id": caller_pane,
141
- "caller_current_command": caller_command,
142
- "team_id": team_id,
143
- }
144
-
145
-
146
- def derive_leader_session_uuid(
147
- machine_fingerprint: str, workspace: Path, os_user: str, team_id: str
148
- ) -> str:
149
- workspace_abspath = str(Path(workspace).resolve())
150
- payload = "\0".join((machine_fingerprint, workspace_abspath, os_user, team_id))
151
- return hashlib.sha256(payload.encode("utf-8")).hexdigest()[:32]
152
-
153
-
154
- def _provider_from_command(cmd: str) -> str:
155
- if cmd in {"claude", "claude.exe"}:
156
- return "claude"
157
- if cmd == "codex":
158
- return "codex"
159
- return ""
160
-
161
-
162
- def emit_owner_bound_event(
163
- workspace: Path,
164
- *,
165
- caller_pane_id: str,
166
- caller_current_command: str,
167
- derived_leader_session_uuid: str,
168
- team_id: str,
169
- old_leader_session_uuid: str | None,
170
- ) -> None:
171
- """Audit hook for successful owner bind. Use after a caller has
172
- accepted ``bind_owner_from_caller_pane`` and persisted the new owner.
173
-
174
- Only short uuid prefixes go to the event log so we do not leak the
175
- full session uuid into operator-readable transcripts."""
176
- EventLog(workspace).write(
177
- "owner.bound_from_caller_pane",
178
- caller_pane_id=caller_pane_id,
179
- caller_current_command=caller_current_command,
180
- derived_uuid_prefix=(derived_leader_session_uuid or "")[:12],
181
- team_id=team_id,
182
- old_uuid_prefix=(old_leader_session_uuid or "")[:12],
183
- )
@@ -1,5 +0,0 @@
1
- """Lifecycle/state/spec lane package.
2
-
3
- Future Team and Agent lifecycle orchestration moves here behind runtime.py
4
- facade wiring.
5
- """
@@ -1,278 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import copy
4
- from pathlib import Path
5
- from typing import Any
6
-
7
- from team_agent.errors import RuntimeError
8
- from team_agent.events import EventLog
9
- from team_agent.message_store import MessageStore
10
- from team_agent.spec import load_spec, validate_spec
11
- from team_agent.state import (
12
- check_team_owner,
13
- load_runtime_state,
14
- resolve_team_scoped_state,
15
- save_runtime_state,
16
- save_team_scoped_state,
17
- write_spec,
18
- write_team_state,
19
- )
20
-
21
-
22
- def remove_agent(
23
- workspace: Path,
24
- agent_id: str,
25
- *,
26
- from_spec: bool = False,
27
- confirm: bool = False,
28
- force: bool = False,
29
- team: str | None = None,
30
- ) -> dict[str, Any]:
31
- import team_agent.runtime as runtime
32
-
33
- workspace = workspace.resolve()
34
- state, refusal = resolve_team_scoped_state(workspace, team)
35
- if refusal:
36
- return refusal
37
- gate = check_team_owner(state)
38
- if gate:
39
- return gate
40
- spec_path = Path(state.get("spec_path", workspace / "team.spec.yaml"))
41
- spec = load_spec(spec_path)
42
- agent = _find_worker(spec, agent_id)
43
- if not agent:
44
- raise RuntimeError(f"unknown worker agent id: {agent_id}")
45
-
46
- event_log = EventLog(workspace)
47
- store = MessageStore(workspace)
48
- agent_state = state.get("agents", {}).get(agent_id) or {}
49
- dynamic_role_file = _dynamic_role_file(workspace, agent_id, agent_state)
50
- dynamic_agent = bool(agent_state.get("dynamic_role_file") or agent.get("forked_from"))
51
- running = _is_running(runtime, state, agent_id, agent_state)
52
-
53
- if not dynamic_agent and not (from_spec and confirm):
54
- return {"ok": False, "agent_id": agent_id, "status": "refused", "reason": "from_spec_confirm_required"}
55
- if running and not force:
56
- return {"ok": False, "agent_id": agent_id, "status": "refused", "reason": "force_required"}
57
-
58
- rollback = _RemoveRollback(workspace, spec_path, spec, state, dynamic_role_file, store, agent_id, False)
59
- stopped: dict[str, Any] | None = None
60
- cleared_locations: list[str] = []
61
- current_step = "init"
62
- current_resource: str | None = None
63
-
64
- def _step_done(name: str, resource: str | None = None, **extra: Any) -> None:
65
- cleared_locations.append(name)
66
- event_log.write(
67
- "lifecycle.remove_step_completed",
68
- agent_id=agent_id,
69
- step=name,
70
- resource=resource,
71
- **extra,
72
- )
73
-
74
- try:
75
- if running and force:
76
- current_step, current_resource = "stop_agent", agent_id
77
- stopped = runtime.stop_agent(workspace, agent_id, team=team)
78
- rollback.restore_running = True
79
- state, _refusal_after = resolve_team_scoped_state(workspace, team)
80
- _step_done("stop_agent", resource=agent_id, stopped=stopped)
81
-
82
- current_step, current_resource = "workspace_state", "state.json:agents"
83
- removed_state = copy.deepcopy(state)
84
- removed_state.get("agents", {}).pop(agent_id, None)
85
- save_team_scoped_state(workspace, removed_state)
86
- _step_done("workspace_state", resource=current_resource)
87
-
88
- current_step, current_resource = "spec_yaml", str(spec_path)
89
- removed_spec = copy.deepcopy(spec)
90
- removed_spec["agents"] = [item for item in removed_spec.get("agents", []) if item.get("id") != agent_id]
91
- startup_order = removed_spec.get("runtime", {}).get("startup_order")
92
- if isinstance(startup_order, list):
93
- removed_spec["runtime"]["startup_order"] = [item for item in startup_order if item != agent_id]
94
- validate_spec(removed_spec, base_dir=spec_path.parent)
95
- current_step, current_resource = "team_state_md", "team_state.md"
96
- team_state_path = write_team_state(workspace, removed_spec, removed_state)
97
- _step_done("team_state_md", resource=str(team_state_path))
98
- current_step, current_resource = "spec_yaml", str(spec_path)
99
- write_spec(spec_path, removed_spec)
100
- _step_done("spec_yaml", resource=str(spec_path))
101
-
102
- current_step, current_resource = "role_file", str(dynamic_role_file)
103
- role_file_removed = _remove_dynamic_role_file(dynamic_role_file, bool(agent_state.get("dynamic_role_file")))
104
- if role_file_removed:
105
- _step_done("role_file", resource=str(dynamic_role_file))
106
-
107
- current_step, current_resource = "agent_health", agent_id
108
- _delete_agent_health(store, agent_id)
109
- _step_done("agent_health", resource=agent_id)
110
- except Exception as exc:
111
- rollback_result = rollback.restore(runtime, event_log)
112
- event_log.write(
113
- "remove_agent.rollback",
114
- agent_id=agent_id,
115
- ok=rollback_result["ok"],
116
- error=str(exc),
117
- failed_step=current_step,
118
- resource=current_resource,
119
- cleared_before_failure=cleared_locations,
120
- rollback=rollback_result,
121
- )
122
- event_log.write(
123
- "lifecycle.remove_rolled_back",
124
- agent_id=agent_id,
125
- ok=rollback_result["ok"],
126
- failed_step=current_step,
127
- resource=current_resource,
128
- rollback_errors=rollback_result.get("errors", []),
129
- )
130
- raise RuntimeError(
131
- f"remove-agent failed for {agent_id} at step={current_step} "
132
- f"resource={current_resource}: {exc}; rollback_ok={rollback_result['ok']}"
133
- ) from exc
134
-
135
- runtime._save_team_runtime_snapshot(workspace, removed_state)
136
- warning = None
137
- try:
138
- # Storage commit is authoritative; final success event logging is best-effort.
139
- event_log.write(
140
- "remove_agent.complete",
141
- agent_id=agent_id,
142
- from_spec=from_spec,
143
- force=force,
144
- stopped=stopped,
145
- role_file_removed=role_file_removed,
146
- cleared_locations=cleared_locations,
147
- )
148
- except Exception as exc:
149
- warning = f"remove-agent completed but success event logging failed: {exc}"
150
- return {
151
- "ok": True,
152
- "agent_id": agent_id,
153
- "status": "removed",
154
- "from_spec": from_spec,
155
- "force": force,
156
- "stopped": stopped,
157
- "state_file": str(team_state_path),
158
- "role_file_removed": role_file_removed,
159
- "cleared_locations": cleared_locations,
160
- **({"warning": warning} if warning else {}),
161
- }
162
-
163
-
164
- class _RemoveRollback:
165
- def __init__(
166
- self,
167
- workspace: Path,
168
- spec_path: Path,
169
- spec: dict[str, Any],
170
- state: dict[str, Any],
171
- dynamic_role_file: Path,
172
- store: MessageStore,
173
- agent_id: str,
174
- restore_running: bool,
175
- ) -> None:
176
- self.workspace = workspace
177
- self.spec_path = spec_path
178
- self.spec_text = spec_path.read_text(encoding="utf-8")
179
- self.spec = copy.deepcopy(spec)
180
- self.state = copy.deepcopy(state)
181
- self.team_state_path = workspace / spec.get("context", {}).get("state_file", "team_state.md")
182
- self.team_state_text = self.team_state_path.read_text(encoding="utf-8") if self.team_state_path.exists() else None
183
- self.dynamic_role_file = dynamic_role_file
184
- self.dynamic_role_bytes = dynamic_role_file.read_bytes() if dynamic_role_file.exists() else None
185
- self.health = copy.deepcopy(store.agent_health().get(agent_id))
186
- self.agent_id = agent_id
187
- self.restore_running = restore_running
188
-
189
- def restore(self, runtime: Any, event_log: EventLog) -> dict[str, Any]:
190
- errors: list[str] = []
191
- try:
192
- self.spec_path.write_text(self.spec_text, encoding="utf-8")
193
- except Exception as exc:
194
- errors.append(f"spec:{exc}")
195
- try:
196
- save_team_scoped_state(self.workspace, self.state)
197
- except Exception as exc:
198
- errors.append(f"workspace_state:{exc}")
199
- try:
200
- if self.team_state_text is None:
201
- self.team_state_path.unlink(missing_ok=True)
202
- else:
203
- self.team_state_path.parent.mkdir(parents=True, exist_ok=True)
204
- self.team_state_path.write_text(self.team_state_text, encoding="utf-8")
205
- except Exception as exc:
206
- errors.append(f"team_state:{exc}")
207
- try:
208
- if self.dynamic_role_bytes is None:
209
- self.dynamic_role_file.unlink(missing_ok=True)
210
- else:
211
- self.dynamic_role_file.parent.mkdir(parents=True, exist_ok=True)
212
- self.dynamic_role_file.write_bytes(self.dynamic_role_bytes)
213
- except Exception as exc:
214
- errors.append(f"role_file:{exc}")
215
- try:
216
- _restore_agent_health(MessageStore(self.workspace), self.agent_id, self.health)
217
- except Exception as exc:
218
- errors.append(f"agent_health:{exc}")
219
- if self.restore_running and not errors:
220
- try:
221
- runtime.start_agent(self.workspace, self.agent_id, force=True, allow_fresh=True)
222
- except Exception as exc:
223
- errors.append(f"worker_restore:{exc}")
224
- result = {"ok": not errors, "errors": errors}
225
- if errors:
226
- event_log.write("remove_agent.rollback_failed", agent_id=self.agent_id, errors=errors)
227
- return result
228
-
229
-
230
- def _find_worker(spec: dict[str, Any], agent_id: str) -> dict[str, Any] | None:
231
- if spec.get("leader", {}).get("id") == agent_id:
232
- return None
233
- for agent in spec.get("agents", []):
234
- if agent.get("id") == agent_id:
235
- return agent
236
- return None
237
-
238
-
239
- def _dynamic_role_file(workspace: Path, agent_id: str, agent_state: dict[str, Any]) -> Path:
240
- raw = agent_state.get("dynamic_role_file")
241
- if raw:
242
- path = Path(str(raw))
243
- return path if path.is_absolute() else workspace / path
244
- return workspace / ".team" / "dynamic-role-files" / f"{agent_id}.md"
245
-
246
-
247
- def _is_running(runtime: Any, state: dict[str, Any], agent_id: str, agent_state: dict[str, Any]) -> bool:
248
- if str(agent_state.get("status") or "").lower() in {"running", "busy"}:
249
- return True
250
- session_name = state.get("session_name")
251
- window = agent_state.get("window") or agent_id
252
- return bool(session_name and runtime._tmux_window_exists(str(session_name), str(window)))
253
-
254
-
255
- def _remove_dynamic_role_file(path: Path, required: bool) -> bool:
256
- if path.exists():
257
- path.unlink()
258
- return True
259
- if required:
260
- raise RuntimeError(f"dynamic role file missing: {path}")
261
- return False
262
-
263
-
264
- def _delete_agent_health(store: MessageStore, agent_id: str) -> None:
265
- store.delete_agent_health(agent_id)
266
-
267
-
268
- def _restore_agent_health(store: MessageStore, agent_id: str, row: dict[str, Any] | None) -> None:
269
- if not row:
270
- _delete_agent_health(store, agent_id)
271
- return
272
- store.upsert_agent_health(
273
- agent_id,
274
- row.get("status") or "IDLE",
275
- last_output_at=row.get("last_output_at"),
276
- context_usage_pct=row.get("context_usage_pct"),
277
- current_task_id=row.get("current_task_id"),
278
- )