@team-agent/installer 0.2.11 → 0.3.0

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 +1077 -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 +1141 -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 +436 -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 +1063 -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 +525 -0
  59. package/crates/team-agent/src/leader/rediscover.rs +1099 -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 +234 -0
  64. package/crates/team-agent/src/leader/tests/identity.rs +206 -0
  65. package/crates/team-agent/src/leader/tests/idle.rs +271 -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 +253 -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 +487 -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 +1833 -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 +933 -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 +685 -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 +159 -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 +388 -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 +542 -0
  110. package/crates/team-agent/src/messaging/helpers.rs +209 -0
  111. package/crates/team-agent/src/messaging/leader_receiver.rs +340 -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 +537 -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 +582 -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 +656 -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 +586 -0
  172. package/crates/team-agent/src/tmux_backend.rs +758 -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 +90 -106
  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,41 @@
1
+ //! `team-agent` 二进制入口。
2
+
3
+ fn main() -> anyhow::Result<()> {
4
+ let mut args = std::env::args().skip(1);
5
+ let command = args.next();
6
+ if matches!(command.as_deref(), Some("fake-worker")) {
7
+ let mut workspace = None;
8
+ let mut agent_id = None;
9
+ while let Some(arg) = args.next() {
10
+ match arg.as_str() {
11
+ "--workspace" => workspace = args.next().map(std::path::PathBuf::from),
12
+ "--agent-id" => agent_id = args.next(),
13
+ other => return Err(anyhow::anyhow!("unknown fake-worker argument: {other}")),
14
+ }
15
+ }
16
+ let workspace = workspace
17
+ .ok_or_else(|| anyhow::anyhow!("fake-worker requires --workspace <path>"))?;
18
+ let agent_id = agent_id
19
+ .ok_or_else(|| anyhow::anyhow!("fake-worker requires --agent-id <id>"))?;
20
+ let stdin = std::io::stdin();
21
+ let stdout = std::io::stdout();
22
+ team_agent::fake_worker::run(&workspace, &agent_id, stdin.lock(), stdout.lock())
23
+ .map_err(|e| anyhow::anyhow!(e.to_string()))?;
24
+ return Ok(());
25
+ }
26
+ if matches!(command.as_deref(), Some("mcp-server")) {
27
+ let mut workspace = None;
28
+ while let Some(arg) = args.next() {
29
+ match arg.as_str() {
30
+ "--workspace" => workspace = args.next().map(std::path::PathBuf::from),
31
+ other => return Err(anyhow::anyhow!("unknown mcp-server argument: {other}")),
32
+ }
33
+ }
34
+ let workspace = workspace.unwrap_or(std::env::current_dir()?);
35
+ team_agent::mcp_server::main(&workspace, &[])?;
36
+ return Ok(());
37
+ }
38
+ let argv = std::env::args().skip(1).collect::<Vec<_>>();
39
+ let cwd = std::env::current_dir()?;
40
+ std::process::exit(team_agent::cli::run(&argv, &cwd).code());
41
+ }
@@ -0,0 +1,228 @@
1
+ //! step 14a · mcp_server::helpers — pure regularization + shared free helpers.
2
+
3
+ use std::io::Write as _;
4
+ use std::path::Path;
5
+
6
+ use serde::Serialize;
7
+ use serde_json::Value;
8
+
9
+ use crate::messaging::{DeliveryOutcome, MessageTarget};
10
+ use crate::state::persist::load_runtime_state;
11
+
12
+ use super::types::{NormalizedReportEnvelope, ToolError, ToolErrorReason};
13
+
14
+ // ═══════════════════════════════════════════════════════════════════════════
15
+ // MODULE HELPERS (tools.py:16-69) — pure regularization, contract-callable.
16
+ // ═══════════════════════════════════════════════════════════════════════════
17
+
18
+ /// `_requires_ack_for_target` (`tools.py:16-19`): leader-only targets default to no
19
+ /// ack; any non-leader target → requires ack.
20
+ pub fn requires_ack_for_target(to: &MessageTarget) -> bool {
21
+ match to {
22
+ MessageTarget::Single(target) => !(target == "leader" || target == "Leader"),
23
+ MessageTarget::Broadcast => true,
24
+ MessageTarget::Fanout(targets) => targets
25
+ .iter()
26
+ .any(|target| !(target == "leader" || target == "Leader")),
27
+ }
28
+ }
29
+
30
+ /// `_is_worker_recipient` (`tools.py:22-27`): a single string target that is not
31
+ /// `""`/`"*"`/`"leader"`/`"Leader"` → worker recipient (async accepted path).
32
+ pub fn is_worker_recipient(to: &MessageTarget) -> bool {
33
+ match to {
34
+ MessageTarget::Single(target) => {
35
+ !(target.is_empty() || target == "*" || target == "leader" || target == "Leader")
36
+ }
37
+ MessageTarget::Broadcast | MessageTarget::Fanout(_) => false,
38
+ }
39
+ }
40
+
41
+ /// `_merge_tasks_by_id` (`tools.py:30-49`): dedupe a task list keyed by `id`,
42
+ /// `prefer` entries winning on duplicates (so an earlier `done` is not regressed).
43
+ pub fn merge_tasks_by_id(prefer: &[Value], fallback: &[Value]) -> Vec<Value> {
44
+ let mut seen = std::collections::BTreeSet::new();
45
+ let mut out = Vec::new();
46
+ for item in prefer.iter().chain(fallback.iter()) {
47
+ let Some(id) = item.get("id").and_then(Value::as_str) else {
48
+ continue;
49
+ };
50
+ if seen.insert(id.to_string()) && item.is_object() {
51
+ out.push(item.clone());
52
+ }
53
+ }
54
+ out
55
+ }
56
+
57
+ pub(crate) fn tool_error_reason_wire(reason: ToolErrorReason) -> &'static str {
58
+ match reason {
59
+ ToolErrorReason::UnknownTool => "unknown_tool",
60
+ ToolErrorReason::InvalidToolArguments => "invalid_tool_arguments",
61
+ ToolErrorReason::InternalRuntimeError => "internal_runtime_error",
62
+ ToolErrorReason::PeerNotInScope => "peer_not_in_scope",
63
+ }
64
+ }
65
+
66
+ pub(crate) fn normalize_token(value: Option<&str>) -> String {
67
+ value
68
+ .unwrap_or("")
69
+ .trim()
70
+ .to_ascii_lowercase()
71
+ .replace(['-', ' '], "_")
72
+ }
73
+
74
+ pub(crate) fn text_field(value: &Value, key: &str) -> Option<String> {
75
+ value.get(key).and_then(text_of_value)
76
+ }
77
+
78
+ pub(crate) fn text_of_value(value: &Value) -> Option<String> {
79
+ match value {
80
+ Value::Null => None,
81
+ Value::String(s) => non_empty_string(s).map(ToString::to_string),
82
+ Value::Number(n) => Some(n.to_string()),
83
+ Value::Bool(b) => Some(if *b { "True" } else { "False" }.to_string()),
84
+ Value::Array(_) | Value::Object(_) => None,
85
+ }
86
+ }
87
+
88
+ pub(crate) fn items_from_value(value: Option<&Value>) -> Vec<Value> {
89
+ match value {
90
+ Some(Value::Array(items)) => items.clone(),
91
+ Some(Value::Null) | None => Vec::new(),
92
+ Some(other) => vec![other.clone()],
93
+ }
94
+ }
95
+
96
+ pub(crate) fn non_empty_string(value: &str) -> Option<&str> {
97
+ let trimmed = value.trim();
98
+ if trimmed.is_empty() {
99
+ None
100
+ } else {
101
+ Some(trimmed)
102
+ }
103
+ }
104
+
105
+ pub(crate) fn enum_value<T: Serialize>(value: T) -> Value {
106
+ match serde_json::to_value(value) {
107
+ Ok(value) => value,
108
+ Err(_) => Value::Null,
109
+ }
110
+ }
111
+
112
+ pub(crate) fn json_dumps_default(value: &Value) -> String {
113
+ let mut bytes = Vec::new();
114
+ let mut ser = serde_json::Serializer::with_formatter(&mut bytes, PythonJsonFormatter);
115
+ if value.serialize(&mut ser).is_err() {
116
+ return "{}".to_string();
117
+ }
118
+ String::from_utf8(bytes).unwrap_or_else(|_| "{}".to_string())
119
+ }
120
+
121
+ struct PythonJsonFormatter;
122
+
123
+ impl serde_json::ser::Formatter for PythonJsonFormatter {
124
+ fn begin_array_value<W: ?Sized + std::io::Write>(
125
+ &mut self,
126
+ writer: &mut W,
127
+ first: bool,
128
+ ) -> std::io::Result<()> {
129
+ if first {
130
+ Ok(())
131
+ } else {
132
+ writer.write_all(b", ")
133
+ }
134
+ }
135
+
136
+ fn begin_object_key<W: ?Sized + std::io::Write>(
137
+ &mut self,
138
+ writer: &mut W,
139
+ first: bool,
140
+ ) -> std::io::Result<()> {
141
+ if first {
142
+ Ok(())
143
+ } else {
144
+ writer.write_all(b", ")
145
+ }
146
+ }
147
+
148
+ fn begin_object_value<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
149
+ writer.write_all(b": ")
150
+ }
151
+ }
152
+
153
+ pub(crate) fn normalized_envelope_value(env: &NormalizedReportEnvelope) -> Value {
154
+ match serde_json::to_value(env) {
155
+ Ok(value) => value,
156
+ Err(_) => serde_json::json!({
157
+ "schema_version": "result_envelope_v1",
158
+ "task_id": env.task_id.as_str(),
159
+ "agent_id": env.agent_id.as_str(),
160
+ "status": "success",
161
+ "summary": env.summary,
162
+ "changes": [], "tests": [], "risks": [], "artifacts": [], "next_actions": []
163
+ }),
164
+ }
165
+ }
166
+
167
+ pub(crate) fn ensure_object(value: &mut Value) {
168
+ if !value.is_object() {
169
+ *value = Value::Object(serde_json::Map::new());
170
+ }
171
+ }
172
+
173
+ pub(crate) fn insert_array(obj: &mut serde_json::Map<String, Value>, key: &str, value: Option<&[Value]>) {
174
+ if let Some(items) = value {
175
+ obj.insert(key.to_string(), Value::Array(items.to_vec()));
176
+ }
177
+ }
178
+
179
+ pub(crate) fn tool_runtime_error(err: impl std::fmt::Display) -> ToolError {
180
+ ToolError::new(
181
+ ToolErrorReason::InternalRuntimeError,
182
+ ToolError::public_exception_message(&err.to_string(), "RuntimeError"),
183
+ "RuntimeError",
184
+ )
185
+ }
186
+
187
+ pub(crate) fn object_fields(value: Value) -> serde_json::Map<String, Value> {
188
+ match value {
189
+ Value::Object(map) => map,
190
+ other => {
191
+ let mut map = serde_json::Map::new();
192
+ map.insert("ok".to_string(), Value::Bool(true));
193
+ map.insert("value".to_string(), other);
194
+ map
195
+ }
196
+ }
197
+ }
198
+
199
+ pub(crate) fn delivery_outcome_value(out: &DeliveryOutcome) -> Value {
200
+ serde_json::json!({
201
+ "ok": out.ok,
202
+ "status": enum_value(out.status),
203
+ "message_id": out.message_id,
204
+ })
205
+ }
206
+
207
+ pub(crate) fn latest_task_for_assignee(workspace: &Path, agent_id: &str) -> Option<String> {
208
+ let state = load_runtime_state(workspace).ok()?;
209
+ let tasks = state.get("tasks").and_then(Value::as_array)?;
210
+ for task in tasks.iter().rev() {
211
+ let assignee = task.get("assignee").and_then(Value::as_str)?;
212
+ if assignee != agent_id {
213
+ continue;
214
+ }
215
+ let status = task
216
+ .get("status")
217
+ .and_then(Value::as_str)
218
+ .unwrap_or("")
219
+ .to_ascii_lowercase();
220
+ if matches!(status.as_str(), "done" | "success" | "failed" | "blocked" | "cancelled") {
221
+ continue;
222
+ }
223
+ if let Some(id) = task.get("id").and_then(text_of_value) {
224
+ return Some(id);
225
+ }
226
+ }
227
+ None
228
+ }
@@ -0,0 +1,183 @@
1
+ //! step 14a · mcp_server — stdio MCP server (`team_orchestrator`) over JSON-RPC 2.0.
2
+ //!
3
+ //! Card: `docs/phase0/subsystems/14-mcp_cli.md` (MCP half).
4
+ //! Truth source (READ-ONLY) `team-agent-public` @ v0.2.11 / `439bef8`:
5
+ //! - `mcp_server/server.py` — stdio loop + JSON-RPC route (`dispatch`/`handle_mcp`/`main`)
6
+ //! - `mcp_server/tools.py` — `TeamOrchestratorTools`: the 12 typed tool handlers
7
+ //! - `mcp_server/contracts.py` — `TOOLS`: name/description/inputSchema (wire single-truth)
8
+ //! - `mcp_server/normalize.py` — result envelope / compact-result regularization
9
+ //! - `mcp_server/__init__.py` — package re-export surface locked by boundary tests
10
+ //!
11
+ //! SCOPE — this is the TYPE + BEHAVIORAL-ENTRY-FN layer so RED contracts can both
12
+ //! NAME the wire/envelope types AND CALL real handlers and assert against rich
13
+ //! return values. It is "the thinnest shell": it owns the wire protocol shape, the
14
+ //! tool-regularization rules, the error envelope, and identity/scope anchoring —
15
+ //! everything durable is delegated to step 5/6/7/11/13. Bodies are
16
+ //! `unimplemented!("step14 port: …")`.
17
+ //!
18
+ //! REUSE (do NOT redefine):
19
+ //! - [`MessageStore`] (step 7) — `request_human` creates the leader message row.
20
+ //! - [`EventLog`] (step 4) — `mcp.scope_resolved` / `mcp.send_message_refused` /
21
+ //! `mcp.identity_inference_failed` / `mcp.task_inference_failed` audit events.
22
+ //! - [`load_runtime_state`] / [`save_runtime_state`] (step 5 persist) — `assign_task`
23
+ //! / `update_state` read-modify-write; `get_visible_peers` reads team scope.
24
+ //! - [`messaging`] (step 11) — `send_message` / `report_result` / `collect` /
25
+ //! `stuck_list` / `stuck_cancel` delegated by the tool handlers.
26
+ //! - [`crate::model::enums`] (step 2) — [`ResultStatus`] / [`ChangeKind`] /
27
+ //! [`TestStatus`] / [`RiskSeverity`] are the normalized result-envelope value
28
+ //! enums; this layer ONLY does string-alias regularization onto them.
29
+ //! - [`AgentId`] / [`TaskId`] / [`TeamKey`] (step 2 ids) — identity/scope anchors.
30
+ //!
31
+ //! 铁律 (card §11, Rust 绝不重蹈 Python 坑):
32
+ //! - **scope 锚 env, 禁候选扫描** (C13-C17/bug-064/082): sender identity =
33
+ //! spawn-time `TEAM_AGENT_ID`; scope = `TEAM_AGENT_OWNER_TEAM_ID`. `to="*"`
34
+ //! defaults to the sender team; `scope="workspace"` is the only cross-team
35
+ //! opt-in. A peer not in scope → typed [`ToolError`] with
36
+ //! [`ToolErrorReason::PeerNotInScope`] — never leak other-team peer names.
37
+ //! - **错误信封冗余键** (server.py:98-106): `reason == error_code` and
38
+ //! `message == error` are byte-stable downstream contracts — preserved verbatim
39
+ //! in [`ToolError`]'s serialization, NOT "cleaned up".
40
+ //! - **notifications/* 不回包** (server.py:49-50): `notifications/*` → [`RpcMethod::
41
+ //! Notification`] → [`handle_mcp`] returns `None`; the loop `continue`s. Emitting
42
+ //! a frame here would corrupt the stdout JSON-RPC stream.
43
+ //! - **stdout 是传输通道** (server.py:135): every error is surfaced ON stdout as a
44
+ //! JSON-RPC frame; logs/warnings MUST go to stderr/file, never stdout.
45
+ //! - **worker-recipient 异步 accepted** (tools.py:176-183): a worker recipient with
46
+ //! a message_id → [`SendOutcome::WorkerAccepted`] carrying the byte-stable
47
+ //! `poll_via = "team-agent inbox <id>"`; leader/`*` → [`SendOutcome::Direct`].
48
+ //! - **兜底字符串字节级保留** (bug-085): `_infer_task_id` failure → `"manual"` (not
49
+ //! None); `_infer_agent_id` failure → `None` → caller routes to `"unknown"`.
50
+ //!
51
+ //! §10 deny: this subsystem is NOT a daemon/coordinator path, so the MCP shell does
52
+ //! not force top-level `#![deny(unwrap/expect/panic)]` (leader decides at
53
+ //! integration; card §109 carves out only `diagnose::comms::evaluate_idle_behavior`
54
+ //! and `diagnose::orphan::*`, which live in the CLI/diagnose lane, not here). All
55
+ //! fallible handlers return `Result<_, McpError>` regardless.
56
+
57
+ // ROUND-0 skeleton: fn bodies are all unimplemented!() so imports/fields/methods are
58
+ // not yet exercised; P2 porter removes this when implementing.
59
+ #![allow(dead_code, unused_imports, unused_variables, clippy::result_large_err, clippy::doc_overindented_list_items, clippy::doc_lazy_continuation, clippy::io_other_error)]
60
+ // §10:MCP stdio handlers 实现层禁 unwrap/expect/panic(unimplemented!() stub 不被拦);tests 子模块各自 allow。
61
+ #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
62
+
63
+ use std::collections::BTreeSet;
64
+ use std::io::Write as _;
65
+ use std::path::{Path, PathBuf};
66
+
67
+ use serde::{Deserialize, Serialize};
68
+ use serde_json::Value;
69
+ use thiserror::Error;
70
+
71
+ // ── REUSE: step 2 model (ids + normalized-envelope value enums) ─────────────
72
+ use crate::model::enums::{ChangeKind, ResultStatus, RiskSeverity, TestStatus};
73
+ use crate::model::ids::{AgentId, TaskId, TeamKey};
74
+
75
+ // ── REUSE: step 4 event_log / step 7 message_store ──────────────────────────
76
+ use crate::event_log::EventLog;
77
+ use crate::message_store::MessageStore;
78
+
79
+ // ── REUSE: step 5 state persist / projection ────────────────────────────────
80
+ use crate::state::persist::{load_runtime_state, save_runtime_state};
81
+
82
+ // ── REUSE: step 11 messaging delegate surface ───────────────────────────────
83
+ use crate::messaging::{self, DeliveryOutcome, MessageTarget, SendOptions};
84
+
85
+ pub mod helpers;
86
+ pub mod normalize;
87
+ pub mod tools;
88
+ pub mod types;
89
+ pub mod wire;
90
+
91
+ // ── re-export: 保持 `crate::mcp_server::X` 与 test `super::X` 解析不变 ─────────
92
+ pub use helpers::*;
93
+ pub use normalize::*;
94
+ pub use tools::*;
95
+ pub use types::*;
96
+ pub use wire::*;
97
+
98
+ // pub(crate) 子项 (normalize 的 list helpers、wire 的 dispatch_tool 等) 经此再导出,
99
+ // 使 `#[cfg(test)] mod tests` 的 `use super::*` 与跨子模块引用解析不变。
100
+ pub(crate) use helpers::{
101
+ delivery_outcome_value, ensure_object, enum_value, insert_array, latest_task_for_assignee,
102
+ non_empty_string, normalize_token, normalized_envelope_value, object_fields, text_field,
103
+ text_of_value, tool_error_reason_wire, tool_runtime_error,
104
+ };
105
+ pub(crate) use normalize::{
106
+ normalize_artifacts, normalize_changes, normalize_next_actions, normalize_risks, normalize_tests,
107
+ };
108
+ pub(crate) use wire::dispatch_tool;
109
+
110
+ // ═══════════════════════════════════════════════════════════════════════════
111
+ // CROSS-DEP PLACEHOLDERS — step 13 lifecycle / team_state surface not yet in tree.
112
+ // The 13/15 sibling lanes are in flight; do NOT guess their authoritative names.
113
+ // Leader reconciles these at integration.
114
+ // ═══════════════════════════════════════════════════════════════════════════
115
+
116
+ /// **PLACEHOLDER** — step 13 lifecycle `runtime.{stop,reset,add,fork}_agent`. The
117
+ /// lifecycle lane is not yet in the tree; these tool handlers delegate to it. Minimal
118
+ /// local stubs so the handler signatures compile and contracts can name the
119
+ /// delegation. Leader swaps for the authoritative step-13 surface at integration.
120
+ pub mod lifecycle_placeholder {
121
+ use super::*;
122
+
123
+ /// `runtime.stop_agent(workspace, agent_id)` (step 13).
124
+ pub fn stop_agent(workspace: &Path, agent_id: &str) -> Result<Value, McpError> {
125
+ let _ = workspace;
126
+ Ok(serde_json::json!({"ok": true, "status": "stopped", "agent_id": agent_id}))
127
+ }
128
+
129
+ /// `runtime.reset_agent(workspace, agent_id, discard_session)` (step 13).
130
+ pub fn reset_agent(workspace: &Path, agent_id: &str, discard_session: bool) -> Result<Value, McpError> {
131
+ let _ = workspace;
132
+ Ok(serde_json::json!({"ok": true, "status": "reset", "agent_id": agent_id, "discard_session": discard_session}))
133
+ }
134
+
135
+ /// `runtime.add_agent(workspace, new_agent_id, role_file_path)` (step 13).
136
+ pub fn add_agent(workspace: &Path, new_agent_id: &str, role_file_path: &str) -> Result<Value, McpError> {
137
+ let _ = workspace;
138
+ Ok(serde_json::json!({"ok": true, "status": "added", "agent_id": new_agent_id, "role_file_path": role_file_path}))
139
+ }
140
+
141
+ /// `runtime.fork_agent(workspace, source_agent_id, as_agent_id, label)` (step 13).
142
+ pub fn fork_agent(workspace: &Path, source_agent_id: &str, as_agent_id: &str, label: Option<&str>) -> Result<Value, McpError> {
143
+ let _ = workspace;
144
+ Ok(serde_json::json!({"ok": true, "status": "forked", "source_agent_id": source_agent_id, "agent_id": as_agent_id, "label": label}))
145
+ }
146
+
147
+ /// `runtime.status(workspace, as_json=true, compact=true)` (step 13 status
148
+ /// projection; `tools.py:328`).
149
+ pub fn runtime_status(workspace: &Path, compact: bool) -> Result<Value, McpError> {
150
+ let _ = (workspace, compact);
151
+ Ok(serde_json::json!({"ok": true, "status": "ok"}))
152
+ }
153
+
154
+ /// `state.write_team_state(workspace, spec, state)` (step 5/13 team_state.md
155
+ /// rewrite; `tools.py:324`). Step 5 persist exists, but this writer is not yet
156
+ /// exported; placeholder until the persist/lifecycle lane lands it.
157
+ pub fn write_team_state(workspace: &Path, spec: &Value, state: &Value) -> Result<PathBuf, McpError> {
158
+ let rel = spec
159
+ .get("context")
160
+ .and_then(|v| v.get("state_file"))
161
+ .and_then(Value::as_str)
162
+ .unwrap_or("team_state.md");
163
+ let path = workspace.join(rel);
164
+ if let Some(parent) = path.parent() {
165
+ std::fs::create_dir_all(parent)?;
166
+ }
167
+ let mut text = String::from("# Team State\n\n## Notes\n\n");
168
+ if let Some(notes) = state.get("notes").and_then(Value::as_array) {
169
+ for note in notes {
170
+ if let Some(note) = note.as_str() {
171
+ text.push_str("- ");
172
+ text.push_str(note);
173
+ text.push('\n');
174
+ }
175
+ }
176
+ }
177
+ std::fs::write(&path, text)?;
178
+ Ok(path)
179
+ }
180
+ }
181
+
182
+ #[cfg(test)]
183
+ mod tests;