@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
@@ -0,0 +1,468 @@
1
+ //! step 14a · mcp_server::wire — stdio loop + JSON-RPC route + tool dispatch + contracts.
2
+
3
+ use std::io::{BufRead, Write};
4
+ use std::path::Path;
5
+
6
+ use serde_json::Value;
7
+
8
+ use crate::messaging::MessageTarget;
9
+
10
+ use super::helpers::{json_dumps_default, object_fields};
11
+ use super::normalize::normalize_result_status;
12
+ use super::tools::TeamOrchestratorTools;
13
+ use super::types::{
14
+ McpError, McpTool, RpcError, RpcId, RpcMethod, RpcResponse, Scope, SendOutcome, ServerRunReport,
15
+ ToolError, ToolErrorReason, ToolOk, ToolResult,
16
+ };
17
+
18
+ // ═══════════════════════════════════════════════════════════════════════════
19
+ // CONTRACTS — TOOLS wire list (contracts.py), derived from McpTool.
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+
22
+ /// `TOOLS` (`contracts.py:4`): the `tools/list` payload — name/description/inputSchema
23
+ /// per tool. **Byte-stable wire single-truth**, derived from [`McpTool`] so name and
24
+ /// schema cannot drift from the enum. Returned verbatim by `tools/list`.
25
+ pub fn tools_contract() -> Vec<Value> {
26
+ let tools = [
27
+ McpTool::AssignTask,
28
+ McpTool::SendMessage,
29
+ McpTool::ReportResult,
30
+ McpTool::UpdateState,
31
+ McpTool::GetTeamStatus,
32
+ McpTool::StopAgent,
33
+ McpTool::ResetAgent,
34
+ McpTool::AddAgent,
35
+ McpTool::ForkAgent,
36
+ McpTool::RequestHuman,
37
+ McpTool::StuckList,
38
+ McpTool::StuckCancel,
39
+ ];
40
+ tools
41
+ .into_iter()
42
+ .map(tool_contract)
43
+ .collect()
44
+ }
45
+
46
+ // ═══════════════════════════════════════════════════════════════════════════
47
+ // SERVER — stdio loop + JSON-RPC route. THE single external MCP entry surface
48
+ // (boundary tests lock handle_mcp / dispatch / TOOLS).
49
+ // ═══════════════════════════════════════════════════════════════════════════
50
+
51
+ /// `dispatch(tools, request)` (`server.py:16-43`): route a `{tool, arguments}` (or
52
+ /// `{method, params}`) request to the matching [`TeamOrchestratorTools`] handler.
53
+ /// Unknown tool → `Err(ToolError{reason: UnknownTool})`. Argument/runtime errors
54
+ /// from the handler propagate as the handler's own [`ToolResult`]; the
55
+ /// argument-vs-internal exception split happens in [`handle_mcp`].
56
+ pub fn dispatch(tools: &TeamOrchestratorTools, request: &Value) -> ToolResult {
57
+ let tool_value = request
58
+ .get("tool")
59
+ .filter(|v| !v.as_str().is_some_and(str::is_empty))
60
+ .or_else(|| request.get("name").filter(|v| !v.as_str().is_some_and(str::is_empty)))
61
+ .or_else(|| request.get("method"));
62
+ let name = tool_value.and_then(Value::as_str);
63
+ let args = request
64
+ .get("arguments")
65
+ .or_else(|| request.get("params"))
66
+ .unwrap_or(&Value::Null);
67
+ let Some(name) = name else {
68
+ return Err(ToolError::new(
69
+ ToolErrorReason::UnknownTool,
70
+ "unknown tool None",
71
+ "UnknownTool",
72
+ ));
73
+ };
74
+ let Some(tool) = McpTool::parse(name) else {
75
+ return Err(ToolError::new(
76
+ ToolErrorReason::UnknownTool,
77
+ format!("unknown tool {}", python_repr(name)),
78
+ "UnknownTool",
79
+ ));
80
+ };
81
+ dispatch_tool(tools, tool, args)
82
+ }
83
+
84
+ /// `handle_mcp(tools, request)` (`server.py:46-91`): the JSON-RPC router.
85
+ /// - `initialize` → serverInfo `team_orchestrator` v0.1.4 + echoed protocolVersion.
86
+ /// - `tools/list` → `{tools: TOOLS}`.
87
+ /// - `tools/call` → run [`dispatch`], wrap into [`ToolCallResult`] (`isError` =
88
+ /// dispatch returned `Err`); the arg-vs-runtime exception split (`server.py:
89
+ /// 69-72`) classifies a caught failure into `InvalidToolArguments` vs
90
+ /// `InternalRuntimeError`.
91
+ /// - `notifications/*` → `Ok(None)` (no frame; **must not** emit to stdout).
92
+ /// - unknown method → `-32601` error frame.
93
+ /// Returns `Ok(None)` only for the notifications path; every other branch yields a
94
+ /// frame.
95
+ ///
96
+ /// [`ToolCallResult`]: super::ToolCallResult
97
+ pub fn handle_mcp(tools: &TeamOrchestratorTools, request: &Value) -> Result<Option<RpcResponse>, McpError> {
98
+ let id = rpc_id_from_request(request);
99
+ let method = request.get("method").and_then(Value::as_str).unwrap_or("");
100
+ match RpcMethod::classify(method) {
101
+ RpcMethod::Initialize => {
102
+ let protocol = request
103
+ .get("params")
104
+ .and_then(|p| p.get("protocolVersion"))
105
+ .and_then(Value::as_str)
106
+ .unwrap_or("2024-11-05");
107
+ let mut result = serde_json::Map::new();
108
+ result.insert("protocolVersion".to_string(), Value::String(protocol.to_string()));
109
+ result.insert("capabilities".to_string(), serde_json::json!({"tools": {}}));
110
+ result.insert(
111
+ "serverInfo".to_string(),
112
+ serde_json::json!({"name": "team_orchestrator", "version": "0.1.4"}),
113
+ );
114
+ Ok(Some(RpcResponse {
115
+ jsonrpc: "2.0".to_string(),
116
+ id,
117
+ result: Some(Value::Object(result)),
118
+ error: None,
119
+ }))
120
+ }
121
+ RpcMethod::ToolsList => Ok(Some(RpcResponse {
122
+ jsonrpc: "2.0".to_string(),
123
+ id,
124
+ result: Some(serde_json::json!({ "tools": tools_contract() })),
125
+ error: None,
126
+ })),
127
+ RpcMethod::ToolsCall => {
128
+ let params = request.get("params").unwrap_or(&Value::Null);
129
+ let body = match dispatch(tools, params) {
130
+ Ok(ok) => {
131
+ let value = Value::Object(ok.fields);
132
+ tool_call_result_value(value.get("ok").and_then(Value::as_bool) == Some(false), &value)
133
+ }
134
+ Err(err) => tool_call_result_value(true, &err.to_envelope()),
135
+ };
136
+ Ok(Some(RpcResponse {
137
+ jsonrpc: "2.0".to_string(),
138
+ id,
139
+ result: Some(body),
140
+ error: None,
141
+ }))
142
+ }
143
+ RpcMethod::Notification(_) => Ok(None),
144
+ RpcMethod::Unknown(method) => Ok(Some(RpcResponse {
145
+ jsonrpc: "2.0".to_string(),
146
+ id,
147
+ result: None,
148
+ error: Some(RpcError {
149
+ code: -32601,
150
+ message: format!("unknown method '{method}'"),
151
+ }),
152
+ })),
153
+ }
154
+ }
155
+
156
+ /// `main(argv)` (`server.py:114-151`): the stdio process entry. Reads stdin line by
157
+ /// line; for `jsonrpc:"2.0"` lines routes via [`handle_mcp`] and writes the response
158
+ /// frame (skipping `None`); legacy `{tool,...}` lines go straight to [`dispatch`].
159
+ /// **All errors surface as JSON-RPC frames on stdout**; the loop never crashes the
160
+ /// process. Returns a [`ServerRunReport`] summarizing the session for tests/daemon.
161
+ pub fn main(workspace: &Path, argv: &[String]) -> Result<ServerRunReport, McpError> {
162
+ let _ = argv;
163
+ let stdin = std::io::stdin();
164
+ let stdout = std::io::stdout();
165
+ run_stdio_loop(workspace, stdin.lock(), stdout.lock())
166
+ }
167
+
168
+ fn run_stdio_loop<R: BufRead, W: Write>(
169
+ workspace: &Path,
170
+ reader: R,
171
+ mut writer: W,
172
+ ) -> Result<ServerRunReport, McpError> {
173
+ let tools = TeamOrchestratorTools::new(workspace);
174
+ let mut report = ServerRunReport::default();
175
+ for line in reader.lines() {
176
+ let line = line?;
177
+ report.requests_read = report.requests_read.saturating_add(1);
178
+ let frame = handle_stdin_line(&tools, &line, &mut report)?;
179
+ if let Some(value) = frame {
180
+ serde_json::to_writer(&mut writer, &value)?;
181
+ writer.write_all(b"\n")?;
182
+ writer.flush()?;
183
+ report.responses_written = report.responses_written.saturating_add(1);
184
+ }
185
+ }
186
+ report.clean_eof = true;
187
+ Ok(report)
188
+ }
189
+
190
+ fn handle_stdin_line(
191
+ tools: &TeamOrchestratorTools,
192
+ line: &str,
193
+ report: &mut ServerRunReport,
194
+ ) -> Result<Option<Value>, McpError> {
195
+ let request: Value = match serde_json::from_str(line) {
196
+ Ok(value) => value,
197
+ Err(err) => {
198
+ report.error_frames = report.error_frames.saturating_add(1);
199
+ return Ok(Some(error_response_value(
200
+ RpcId::Null,
201
+ -32700,
202
+ format!("parse error: {err}"),
203
+ )));
204
+ }
205
+ };
206
+ if request.get("jsonrpc").and_then(Value::as_str) == Some("2.0") {
207
+ match handle_mcp(tools, &request)? {
208
+ Some(response) => {
209
+ if response.error.is_some() {
210
+ report.error_frames = report.error_frames.saturating_add(1);
211
+ }
212
+ Ok(Some(serde_json::to_value(response)?))
213
+ }
214
+ None => {
215
+ report.notifications_skipped = report.notifications_skipped.saturating_add(1);
216
+ Ok(None)
217
+ }
218
+ }
219
+ } else {
220
+ let value = match dispatch(tools, &request) {
221
+ Ok(ok) => Value::Object(ok.fields),
222
+ Err(err) => {
223
+ report.error_frames = report.error_frames.saturating_add(1);
224
+ err.to_envelope()
225
+ }
226
+ };
227
+ Ok(Some(value))
228
+ }
229
+ }
230
+
231
+ fn rpc_id_from_request(request: &Value) -> RpcId {
232
+ match request.get("id") {
233
+ Some(Value::Number(n)) => n.as_i64().map_or_else(|| RpcId::Number(n.clone()), RpcId::Int),
234
+ Some(Value::String(s)) => RpcId::Str(s.clone()),
235
+ _ => RpcId::Null,
236
+ }
237
+ }
238
+
239
+ fn tool_call_result_value(is_error: bool, body: &Value) -> Value {
240
+ let text = json_dumps_default(body);
241
+ let mut content = serde_json::Map::new();
242
+ content.insert("type".to_string(), Value::String("text".to_string()));
243
+ content.insert("text".to_string(), Value::String(text));
244
+ serde_json::json!({
245
+ "content": [Value::Object(content)],
246
+ "isError": is_error
247
+ })
248
+ }
249
+
250
+ fn error_response_value(id: RpcId, code: i64, message: String) -> Value {
251
+ let response = RpcResponse {
252
+ jsonrpc: "2.0".to_string(),
253
+ id,
254
+ result: None,
255
+ error: Some(RpcError { code, message }),
256
+ };
257
+ match serde_json::to_value(response) {
258
+ Ok(value) => value,
259
+ Err(_) => serde_json::json!({
260
+ "jsonrpc": "2.0",
261
+ "id": null,
262
+ "error": {
263
+ "code": -32000,
264
+ "message": "internal runtime error"
265
+ }
266
+ }),
267
+ }
268
+ }
269
+
270
+ fn python_repr(value: &str) -> String {
271
+ if value.contains('\'') && !value.contains('"') {
272
+ format!("\"{}\"", value.replace('"', "\\\""))
273
+ } else {
274
+ format!("'{}'", value.replace('\'', "\\'"))
275
+ }
276
+ }
277
+
278
+ fn tool_contract(tool: McpTool) -> Value {
279
+ let (description, required) = match tool {
280
+ McpTool::SendMessage => (
281
+ "Send a message to a teammate, the leader, or '*' for all other team members. Provide only target and content; Team Agent fills sender, task id, ack policy, and delivery metadata.",
282
+ vec!["to", "content"],
283
+ ),
284
+ McpTool::AssignTask => ("Assign or update a task in the team graph and deliver it to its assignee.", vec!["task"]),
285
+ McpTool::ReportResult => ("Report task completion with a result envelope.", Vec::new()),
286
+ McpTool::UpdateState => ("Append a note to team state and rewrite team_state.md.", vec!["note"]),
287
+ McpTool::GetTeamStatus => ("Return machine-readable team status.", Vec::new()),
288
+ McpTool::StopAgent => ("Stop a running worker.", vec!["agent_id"]),
289
+ McpTool::ResetAgent => ("Reset one worker to a fresh session.", vec!["agent_id", "discard_session"]),
290
+ McpTool::AddAgent => ("Add a first-class worker from a role file.", vec!["new_agent_id", "role_file_path"]),
291
+ McpTool::ForkAgent => ("Fork a running worker.", vec!["source_agent_id", "as_agent_id"]),
292
+ McpTool::RequestHuman => ("Ask the leader or user for human input.", vec!["question"]),
293
+ McpTool::StuckList => ("List manually suppressed idle alerts.", Vec::new()),
294
+ McpTool::StuckCancel => ("Suppress repeated stuck or idle alerts.", vec!["agent_id"]),
295
+ };
296
+ serde_json::json!({
297
+ "name": tool.wire_name(),
298
+ "description": description,
299
+ "inputSchema": {
300
+ "type": "object",
301
+ "properties": tool_properties(tool),
302
+ "required": required,
303
+ "additionalProperties": false
304
+ }
305
+ })
306
+ }
307
+
308
+ fn tool_properties(tool: McpTool) -> serde_json::Map<String, Value> {
309
+ let mut properties = serde_json::Map::new();
310
+ match tool {
311
+ McpTool::AssignTask => {
312
+ insert_property(&mut properties, "task", object_property("Task object to add or update."));
313
+ insert_property(&mut properties, "message", string_property("Optional message to deliver with the task."));
314
+ }
315
+ McpTool::SendMessage => {
316
+ insert_property(&mut properties, "to", string_property("Target agent id, 'leader', or '*' for broadcast."));
317
+ insert_property(&mut properties, "content", string_property("Message body."));
318
+ insert_property(&mut properties, "task_id", string_property("Optional task id to associate with the message."));
319
+ insert_property(&mut properties, "sender", string_property("Optional sender override."));
320
+ insert_property(&mut properties, "requires_ack", boolean_property("Whether the recipient should acknowledge delivery."));
321
+ insert_property(&mut properties, "scope", string_property("Optional delivery scope: team or workspace."));
322
+ }
323
+ McpTool::ReportResult => {
324
+ insert_property(&mut properties, "envelope", object_property("Optional full result envelope."));
325
+ insert_property(&mut properties, "summary", string_property("Short result summary."));
326
+ insert_property(&mut properties, "status", string_property("Result status."));
327
+ insert_property(&mut properties, "changes", array_property("Changed files or artifacts."));
328
+ insert_property(&mut properties, "tests", array_property("Tests or checks performed."));
329
+ insert_property(&mut properties, "risks", array_property("Risks or blockers."));
330
+ insert_property(&mut properties, "artifacts", array_property("Artifact references."));
331
+ insert_property(&mut properties, "next_actions", array_property("Suggested next actions."));
332
+ insert_property(&mut properties, "task_id", string_property("Optional task id override."));
333
+ insert_property(&mut properties, "agent_id", string_property("Optional reporting agent id override."));
334
+ }
335
+ McpTool::UpdateState => {
336
+ insert_property(&mut properties, "note", string_property("Note to append to team state."));
337
+ }
338
+ McpTool::GetTeamStatus | McpTool::StuckList => {}
339
+ McpTool::StopAgent => {
340
+ insert_property(&mut properties, "agent_id", string_property("Agent id to stop."));
341
+ }
342
+ McpTool::ResetAgent => {
343
+ insert_property(&mut properties, "agent_id", string_property("Agent id to reset."));
344
+ insert_property(&mut properties, "discard_session", boolean_property("Whether to discard the existing provider session."));
345
+ }
346
+ McpTool::AddAgent => {
347
+ insert_property(&mut properties, "new_agent_id", string_property("New agent id."));
348
+ insert_property(&mut properties, "role_file_path", string_property("Workspace-relative role file path."));
349
+ }
350
+ McpTool::ForkAgent => {
351
+ insert_property(&mut properties, "source_agent_id", string_property("Agent id to fork from."));
352
+ insert_property(&mut properties, "as_agent_id", string_property("Agent id for the forked worker."));
353
+ insert_property(&mut properties, "label", string_property("Optional display label."));
354
+ }
355
+ McpTool::RequestHuman => {
356
+ insert_property(&mut properties, "question", string_property("Question to ask the human."));
357
+ insert_property(&mut properties, "task_id", string_property("Optional related task id."));
358
+ insert_property(&mut properties, "agent_id", string_property("Optional requesting agent id."));
359
+ }
360
+ McpTool::StuckCancel => {
361
+ insert_property(&mut properties, "agent_id", string_property("Agent id whose stuck alerts should be suppressed."));
362
+ insert_property(&mut properties, "alert_type", string_property("Alert type to suppress, or all."));
363
+ }
364
+ }
365
+ properties
366
+ }
367
+
368
+ fn insert_property(properties: &mut serde_json::Map<String, Value>, name: &str, schema: Value) {
369
+ properties.insert(name.to_string(), schema);
370
+ }
371
+
372
+ fn string_property(description: &str) -> Value {
373
+ serde_json::json!({"type": "string", "description": description})
374
+ }
375
+
376
+ fn boolean_property(description: &str) -> Value {
377
+ serde_json::json!({"type": "boolean", "description": description})
378
+ }
379
+
380
+ fn object_property(description: &str) -> Value {
381
+ serde_json::json!({"type": "object", "description": description, "additionalProperties": true})
382
+ }
383
+
384
+ fn array_property(description: &str) -> Value {
385
+ serde_json::json!({"type": "array", "description": description, "items": {"type": "object", "additionalProperties": true}})
386
+ }
387
+
388
+ pub(crate) fn dispatch_tool(tools: &TeamOrchestratorTools, tool: McpTool, args: &Value) -> ToolResult {
389
+ match tool {
390
+ McpTool::AssignTask => tools.assign_task(args.get("task").unwrap_or(args), args.get("message").and_then(Value::as_str)),
391
+ McpTool::SendMessage => {
392
+ let target = message_target_from_value(args.get("to"));
393
+ let content = args.get("content").and_then(Value::as_str).unwrap_or("");
394
+ let scope = match args.get("scope").and_then(Value::as_str) {
395
+ Some("workspace") => Some(Scope::Workspace),
396
+ Some("team") => Some(Scope::Team),
397
+ _ => None,
398
+ };
399
+ let outcome = tools.send_message(
400
+ &target,
401
+ content,
402
+ args.get("task_id").and_then(Value::as_str),
403
+ args.get("sender").and_then(Value::as_str),
404
+ args.get("requires_ack").and_then(Value::as_bool),
405
+ scope,
406
+ )?;
407
+ match outcome {
408
+ SendOutcome::WorkerAccepted { .. } => Ok(ToolOk {
409
+ fields: object_fields(outcome.to_value()),
410
+ }),
411
+ SendOutcome::Direct(ok) => Ok(ok),
412
+ }
413
+ }
414
+ McpTool::ReportResult => tools.report_result(
415
+ args.get("envelope"),
416
+ args.get("summary").and_then(Value::as_str),
417
+ normalize_result_status(args.get("status").and_then(Value::as_str)),
418
+ args.get("changes").and_then(Value::as_array).map(Vec::as_slice),
419
+ args.get("tests").and_then(Value::as_array).map(Vec::as_slice),
420
+ args.get("risks").and_then(Value::as_array).map(Vec::as_slice),
421
+ args.get("artifacts").and_then(Value::as_array).map(Vec::as_slice),
422
+ args.get("next_actions").and_then(Value::as_array).map(Vec::as_slice),
423
+ args.get("task_id").and_then(Value::as_str),
424
+ args.get("agent_id").and_then(Value::as_str),
425
+ ),
426
+ McpTool::UpdateState => tools.update_state(args.get("note").and_then(Value::as_str).unwrap_or("")),
427
+ McpTool::GetTeamStatus => tools.get_team_status(),
428
+ McpTool::StopAgent => tools.stop_agent(args.get("agent_id").and_then(Value::as_str).unwrap_or("")),
429
+ McpTool::ResetAgent => tools.reset_agent(
430
+ args.get("agent_id").and_then(Value::as_str).unwrap_or(""),
431
+ args.get("discard_session").and_then(Value::as_bool).unwrap_or(false),
432
+ ),
433
+ McpTool::AddAgent => tools.add_agent(
434
+ args.get("new_agent_id").and_then(Value::as_str).unwrap_or(""),
435
+ args.get("role_file_path").and_then(Value::as_str).unwrap_or(""),
436
+ ),
437
+ McpTool::ForkAgent => tools.fork_agent(
438
+ args.get("source_agent_id").and_then(Value::as_str).unwrap_or(""),
439
+ args.get("as_agent_id").and_then(Value::as_str).unwrap_or(""),
440
+ args.get("label").and_then(Value::as_str),
441
+ ),
442
+ McpTool::RequestHuman => tools.request_human(
443
+ args.get("question").and_then(Value::as_str).unwrap_or(""),
444
+ args.get("task_id").and_then(Value::as_str),
445
+ args.get("agent_id").and_then(Value::as_str),
446
+ ),
447
+ McpTool::StuckList => tools.stuck_list(),
448
+ McpTool::StuckCancel => tools.stuck_cancel(
449
+ args.get("agent_id").and_then(Value::as_str).unwrap_or(""),
450
+ args.get("alert_type").and_then(Value::as_str).unwrap_or("all"),
451
+ ),
452
+ }
453
+ }
454
+
455
+ fn message_target_from_value(value: Option<&Value>) -> MessageTarget {
456
+ match value {
457
+ Some(Value::String(s)) if s == "*" => MessageTarget::Broadcast,
458
+ Some(Value::String(s)) => MessageTarget::Single(s.clone()),
459
+ Some(Value::Array(items)) => MessageTarget::Fanout(
460
+ items
461
+ .iter()
462
+ .filter_map(Value::as_str)
463
+ .map(ToString::to_string)
464
+ .collect(),
465
+ ),
466
+ _ => MessageTarget::Single(String::new()),
467
+ }
468
+ }