@team-agent/installer 0.5.60 → 0.5.62

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 (265) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +49 -3
  4. package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +184 -0
  6. package/crates/team-agent/src/cli/emit.rs +104 -21
  7. package/crates/team-agent/src/cli/helpers.rs +1 -0
  8. package/crates/team-agent/src/cli/leader.rs +14 -2
  9. package/crates/team-agent/src/cli/leaders.rs +2 -0
  10. package/crates/team-agent/src/cli/mod.rs +296 -8
  11. package/crates/team-agent/src/cli/named_address.rs +26 -2
  12. package/crates/team-agent/src/cli/profile.rs +2 -1
  13. package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
  14. package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
  15. package/crates/team-agent/src/cli/send/persist.rs +1 -0
  16. package/crates/team-agent/src/cli/send/presentation.rs +3 -0
  17. package/crates/team-agent/src/cli/send/resolve.rs +206 -1
  18. package/crates/team-agent/src/cli/send.rs +2 -1
  19. package/crates/team-agent/src/cli/spec.rs +5 -1
  20. package/crates/team-agent/src/cli/status.rs +2 -1
  21. package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
  22. package/crates/team-agent/src/cli/status_port/format.rs +1 -0
  23. package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
  24. package/crates/team-agent/src/cli/status_port/store.rs +7 -3
  25. package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
  26. package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
  27. package/crates/team-agent/src/cli/types.rs +36 -2
  28. package/crates/team-agent/src/communication_mode/mod.rs +54 -0
  29. package/crates/team-agent/src/compiler/tests.rs +5 -5
  30. package/crates/team-agent/src/compiler.rs +54 -1
  31. package/crates/team-agent/src/conpty/backend.rs +1 -0
  32. package/crates/team-agent/src/conpty/mod.rs +1 -0
  33. package/crates/team-agent/src/coordinator/backoff.rs +5 -8
  34. package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
  35. package/crates/team-agent/src/coordinator/health.rs +1 -0
  36. package/crates/team-agent/src/coordinator/mod.rs +2 -2
  37. package/crates/team-agent/src/coordinator/orphan.rs +4 -116
  38. package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
  39. package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
  40. package/crates/team-agent/src/coordinator/steps/abnormal.rs +6 -5
  41. package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
  42. package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
  43. package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
  44. package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
  45. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
  46. package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
  47. package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
  48. package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +0 -9
  49. package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
  50. package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
  51. package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -42
  52. package/crates/team-agent/src/coordinator/tick.rs +24 -28
  53. package/crates/team-agent/src/coordinator/types.rs +3 -176
  54. package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
  55. package/crates/team-agent/src/db/message_store.rs +47 -2
  56. package/crates/team-agent/src/db/migration.rs +5 -4
  57. package/crates/team-agent/src/db/mod.rs +1 -0
  58. package/crates/team-agent/src/db/schema.rs +1 -0
  59. package/crates/team-agent/src/diagnose/comms.rs +2 -1
  60. package/crates/team-agent/src/diagnose/mod.rs +1 -0
  61. package/crates/team-agent/src/diagnose/orphans.rs +1 -0
  62. package/crates/team-agent/src/fake_worker.rs +21 -1
  63. package/crates/team-agent/src/layout/manager.rs +3 -7
  64. package/crates/team-agent/src/layout/mod.rs +2 -2
  65. package/crates/team-agent/src/layout/overlay.rs +6 -1
  66. package/crates/team-agent/src/layout/placement.rs +1 -0
  67. package/crates/team-agent/src/layout/recovery.rs +3 -0
  68. package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
  69. package/crates/team-agent/src/layout/sessions.rs +8 -1
  70. package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
  71. package/crates/team-agent/src/layout/worker_env.rs +3 -0
  72. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  73. package/crates/team-agent/src/leader/helpers.rs +1 -0
  74. package/crates/team-agent/src/leader/incident.rs +1 -0
  75. package/crates/team-agent/src/leader/lease.rs +27 -22
  76. package/crates/team-agent/src/leader/mod.rs +2 -3
  77. package/crates/team-agent/src/leader/owner_bind.rs +13 -3
  78. package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
  79. package/crates/team-agent/src/leader/rediscover.rs +4 -17
  80. package/crates/team-agent/src/leader/registry.rs +3 -15
  81. package/crates/team-agent/src/leader/start.rs +1072 -186
  82. package/crates/team-agent/src/leader/takeover.rs +10 -232
  83. package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
  84. package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
  85. package/crates/team-agent/src/leader/tests/identity.rs +71 -59
  86. package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
  87. package/crates/team-agent/src/leader/tests/idle.rs +0 -193
  88. package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
  89. package/crates/team-agent/src/leader/tests/mod.rs +4 -41
  90. package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
  91. package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
  92. package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
  93. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
  94. package/crates/team-agent/src/leader/types.rs +1 -28
  95. package/crates/team-agent/src/lib.rs +7 -0
  96. package/crates/team-agent/src/lifecycle/display.rs +7 -1
  97. package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
  98. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
  99. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
  100. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
  101. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
  102. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
  103. package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
  104. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
  105. package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
  106. package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -28
  107. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
  108. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
  109. package/crates/team-agent/src/lifecycle/launch.rs +11 -12
  110. package/crates/team-agent/src/lifecycle/mod.rs +2 -1
  111. package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -4
  112. package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
  113. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
  114. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
  115. package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
  116. package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
  117. package/crates/team-agent/src/lifecycle/restart.rs +13 -11
  118. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
  119. package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
  120. package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
  121. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
  122. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
  123. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
  124. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
  125. package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
  126. package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
  127. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
  128. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
  129. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
  130. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
  131. package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
  132. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
  133. package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
  134. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
  135. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
  136. package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
  137. package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
  138. package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
  139. package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
  140. package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
  141. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
  142. package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
  143. package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
  144. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
  145. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
  146. package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
  147. package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
  148. package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
  149. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
  150. package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
  151. package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
  152. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
  153. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
  154. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
  155. package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
  156. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
  157. package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
  158. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
  159. package/crates/team-agent/src/lifecycle/tests.rs +59 -0
  160. package/crates/team-agent/src/lifecycle/types.rs +0 -9
  161. package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
  162. package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
  163. package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
  164. package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
  165. package/crates/team-agent/src/mcp_server/mod.rs +1 -0
  166. package/crates/team-agent/src/mcp_server/normalize.rs +5 -3
  167. package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
  168. package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
  169. package/crates/team-agent/src/mcp_server/tools.rs +101 -66
  170. package/crates/team-agent/src/mcp_server/types.rs +6 -18
  171. package/crates/team-agent/src/mcp_server/wire.rs +32 -26
  172. package/crates/team-agent/src/messaging/activity.rs +1 -0
  173. package/crates/team-agent/src/messaging/address.rs +1 -0
  174. package/crates/team-agent/src/messaging/delivery.rs +109 -41
  175. package/crates/team-agent/src/messaging/helpers.rs +2 -1
  176. package/crates/team-agent/src/messaging/leader_channel.rs +34 -10
  177. package/crates/team-agent/src/messaging/leader_receiver.rs +42 -24
  178. package/crates/team-agent/src/messaging/mod.rs +10 -14
  179. package/crates/team-agent/src/messaging/peers.rs +2 -0
  180. package/crates/team-agent/src/messaging/persist.rs +3 -1
  181. package/crates/team-agent/src/messaging/presentation.rs +111 -1
  182. package/crates/team-agent/src/messaging/results.rs +166 -17
  183. package/crates/team-agent/src/messaging/scheduler.rs +1 -0
  184. package/crates/team-agent/src/messaging/selftest.rs +1 -1
  185. package/crates/team-agent/src/messaging/send.rs +135 -89
  186. package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
  187. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
  188. package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
  189. package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
  190. package/crates/team-agent/src/messaging/types.rs +7 -2
  191. package/crates/team-agent/src/messaging/watchers.rs +24 -13
  192. package/crates/team-agent/src/model/enums.rs +1 -0
  193. package/crates/team-agent/src/model/errors.rs +1 -0
  194. package/crates/team-agent/src/model/ids.rs +1 -0
  195. package/crates/team-agent/src/model/mod.rs +2 -0
  196. package/crates/team-agent/src/model/name_similarity.rs +1 -0
  197. package/crates/team-agent/src/model/pane_authority_refusal.rs +359 -0
  198. package/crates/team-agent/src/model/paths.rs +1 -0
  199. package/crates/team-agent/src/model/permissions.rs +3 -2
  200. package/crates/team-agent/src/model/routing.rs +1 -0
  201. package/crates/team-agent/src/model/spec.rs +17 -0
  202. package/crates/team-agent/src/model/task_graph.rs +1 -0
  203. package/crates/team-agent/src/model/yaml/tests.rs +1 -0
  204. package/crates/team-agent/src/model/yaml.rs +1 -0
  205. package/crates/team-agent/src/packaging/install.rs +9 -147
  206. package/crates/team-agent/src/packaging/migrate.rs +2 -0
  207. package/crates/team-agent/src/packaging/mod.rs +1 -0
  208. package/crates/team-agent/src/packaging/repair.rs +2 -0
  209. package/crates/team-agent/src/packaging/tests.rs +29 -218
  210. package/crates/team-agent/src/packaging/types.rs +8 -15
  211. package/crates/team-agent/src/platform/argv.rs +4 -0
  212. package/crates/team-agent/src/platform/errors.rs +10 -1
  213. package/crates/team-agent/src/platform/file_lock.rs +4 -157
  214. package/crates/team-agent/src/platform/mod.rs +0 -61
  215. package/crates/team-agent/src/platform/process.rs +1 -0
  216. package/crates/team-agent/src/provider/adapter.rs +1 -0
  217. package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
  218. package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
  219. package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
  220. package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
  221. package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
  222. package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
  223. package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
  224. package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
  225. package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
  226. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
  227. package/crates/team-agent/src/provider/classify.rs +1 -0
  228. package/crates/team-agent/src/provider/faults.rs +1 -26
  229. package/crates/team-agent/src/provider/helpers.rs +1 -0
  230. package/crates/team-agent/src/provider/mod.rs +1 -1
  231. package/crates/team-agent/src/provider/session/capture.rs +41 -22
  232. package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
  233. package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
  234. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
  235. package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
  236. package/crates/team-agent/src/provider/session/mod.rs +2 -4
  237. package/crates/team-agent/src/provider/session/resume.rs +2 -209
  238. package/crates/team-agent/src/provider/session_scan/claude.rs +93 -3
  239. package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
  240. package/crates/team-agent/src/provider/session_scan/common.rs +24 -7
  241. package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
  242. package/crates/team-agent/src/provider/session_scan.rs +6 -42
  243. package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
  244. package/crates/team-agent/src/provider/types.rs +1 -0
  245. package/crates/team-agent/src/provider/wire.rs +1 -0
  246. package/crates/team-agent/src/state/identity.rs +16 -5
  247. package/crates/team-agent/src/state/identity_keys.rs +1 -0
  248. package/crates/team-agent/src/state/mod.rs +2 -0
  249. package/crates/team-agent/src/state/owner_gate.rs +5 -0
  250. package/crates/team-agent/src/state/ownership.rs +10 -4
  251. package/crates/team-agent/src/state/paths.rs +12 -0
  252. package/crates/team-agent/src/state/persist.rs +9 -3
  253. package/crates/team-agent/src/state/projection.rs +15 -2
  254. package/crates/team-agent/src/state/repository/intent.rs +1 -0
  255. package/crates/team-agent/src/state/repository/tests.rs +1 -0
  256. package/crates/team-agent/src/state/repository.rs +7 -0
  257. package/crates/team-agent/src/state/selector.rs +1 -0
  258. package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
  259. package/crates/team-agent/src/tmux_backend.rs +63 -0
  260. package/crates/team-agent/src/topology.rs +3 -0
  261. package/crates/team-agent/src/transport.rs +15 -0
  262. package/package.json +4 -4
  263. package/skills/team-agent/command-coverage.json +379 -0
  264. package/crates/team-agent/src/leader/inject.rs +0 -33
  265. package/crates/team-agent/src/provider/command.rs +0 -80
@@ -0,0 +1,332 @@
1
+ //! BUG-7 (RS 0.3.1 dogfood): `quick-start` must NEVER report bare `ready`
2
+ //! while worker MCP tool-set load is unverified or any agent is observably
3
+ //! degraded. Real-machine evidence (see ../测试rust/BUG-0.3.0-codex-mcp-schema.md
4
+ //! 次要问题#2): `quick-start` printed `quick-start ready: ...` while the codex
5
+ //! worker had already silently rejected the team_orchestrator tool schema and
6
+ //! returned to IDLE — the user had no observable to distinguish "actually
7
+ //! ready" from "spawned but worker dead".
8
+ //!
9
+ //! Coverage:
10
+ //! T1 — worker spawned with a live window but the framework cannot confirm
11
+ //! the worker's MCP tool set finished loading. The report's
12
+ //! `worker_readiness` must signal `pending_tool_load` (NOT bare Ready),
13
+ //! and the CLI summary must NOT be the historical bare
14
+ //! `quick-start ready: <session>` string.
15
+ //! T2 — at least one worker silently failed to spawn (BUG-2 observable: tmux
16
+ //! window missing after launch). The report's `worker_readiness` must
17
+ //! be `Degraded { unhealthy_agents: [<id>] }`, the summary must call
18
+ //! out `degraded`, and `ok` in the JSON envelope must be false.
19
+
20
+ #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
21
+
22
+ use std::collections::BTreeMap;
23
+ use std::path::{Path, PathBuf};
24
+ use std::sync::{Arc, Mutex};
25
+
26
+ use team_agent::lifecycle::{quick_start_with_transport, QuickStartReadiness, QuickStartReport};
27
+ use team_agent::transport::{
28
+ AttachOutcome, BackendKind, CaptureRange, CapturedText, InjectPayload, InjectReport,
29
+ InjectStage, InjectVerification, Key, PaneField, PaneId, PaneInfo, PaneLiveness, SessionName,
30
+ SetEnvOutcome, SpawnResult, SubmitVerification, Target, Transport, TransportError,
31
+ TurnVerification, WindowName,
32
+ };
33
+
34
+ #[path = "../../../tests/support/hermetic.rs"]
35
+ mod hermetic;
36
+ use hermetic::HermeticTestEnv;
37
+
38
+ const TEAM_MD: &str =
39
+ "---\nname: bug7\nobjective: BUG-7 worker readiness honesty contract.\nprovider: codex\n---\n\nTeam.\n";
40
+
41
+ const CODEX_ROLE: &str = "---\nname: codexer\nrole: Codex Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nCodex worker.\n";
42
+
43
+ const CLAUDE_ROLE: &str = "---\nname: clauder\nrole: Claude Worker\nprovider: claude\nmodel: claude-sonnet-4-6\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nClaude worker.\n";
44
+
45
+ #[test]
46
+ #[ignore = "real-machine: quick-start worker readiness gate"]
47
+ fn t1_quick_start_must_not_emit_bare_ready_when_worker_tool_load_is_unverified() {
48
+ let hermetic = HermeticTestEnv::enter("quick-start-readiness-t1");
49
+ hermetic.scrub_tmux();
50
+ hermetic.assert_no_real_tmux();
51
+ let team = bug7_team_dir(&hermetic, "t1-pending");
52
+ // Both agents spawn successfully (recording transport reports both windows live)
53
+ // but the framework has no way to verify the worker MCP tool set actually
54
+ // loaded — codex/claude can still reject schemas asynchronously. The report
55
+ // therefore must be PendingToolLoad, not bare Ready.
56
+ let transport = RecordingTransport::new()
57
+ .with_windows(vec![WindowName::new("codexer"), WindowName::new("clauder")]);
58
+ let report = quick_start_with_transport(&team, None, true, None, &transport)
59
+ .expect("quick_start_with_transport should succeed for healthy spawn");
60
+ let QuickStartReport::Ready {
61
+ worker_readiness,
62
+ session_name,
63
+ ..
64
+ } = &report
65
+ else {
66
+ panic!("quick-start must return Ready for healthy spawn; got {report:?}");
67
+ };
68
+ assert_eq!(
69
+ worker_readiness,
70
+ &QuickStartReadiness::PendingToolLoad,
71
+ "T1: post-spawn report MUST be PendingToolLoad (framework cannot itself \
72
+ confirm worker MCP tool set load); bare Ready would lie. got {report:?}"
73
+ );
74
+ // Drive the CLI rendering path that the user sees — it must not contain the
75
+ // historical bare `quick-start ready: <session>` phrasing.
76
+ let rendered = render_quick_start_summary(&report);
77
+ assert!(
78
+ !rendered.starts_with("quick-start ready:"),
79
+ "T1: CLI summary must NOT begin with the bare `quick-start ready:` phrase \
80
+ while worker tool-load is unverified; got {rendered:?}"
81
+ );
82
+ assert!(
83
+ rendered.contains(session_name.as_str()),
84
+ "T1: CLI summary should still identify the session; got {rendered:?}"
85
+ );
86
+ assert!(
87
+ rendered.to_lowercase().contains("pending")
88
+ || rendered.to_lowercase().contains("unverified"),
89
+ "T1: CLI summary must label the readiness as pending / unverified; got {rendered:?}"
90
+ );
91
+ }
92
+
93
+ #[test]
94
+ #[ignore = "real-machine: quick-start worker readiness gate"]
95
+ fn t2_quick_start_must_report_degraded_when_a_worker_spawn_yields_no_live_window() {
96
+ let hermetic = HermeticTestEnv::enter("quick-start-readiness-t2");
97
+ hermetic.scrub_tmux();
98
+ hermetic.assert_no_real_tmux();
99
+ let team = bug7_team_dir(&hermetic, "t2-degraded");
100
+ // Recording transport simulates the Mac mini final capture: only the codex
101
+ // window exists after launch; the claude window never materialized (no
102
+ // `claude` binary on PATH, etc.). BUG-2 fix already marks `clauder` as
103
+ // spawn_failed in runtime state; BUG-7 must surface that as a Degraded
104
+ // verdict so quick-start cannot pretend the team is ready.
105
+ let transport = RecordingTransport::new().with_windows(vec![WindowName::new("codexer")]);
106
+ let report = quick_start_with_transport(&team, None, true, None, &transport)
107
+ .expect("quick_start_with_transport should reach the spawn/state path even when an agent fails to spawn");
108
+ let QuickStartReport::Ready {
109
+ worker_readiness, ..
110
+ } = &report
111
+ else {
112
+ panic!("quick-start must still return Ready (with Degraded verdict) so the user sees session details; got {report:?}");
113
+ };
114
+ let QuickStartReadiness::Degraded { unhealthy_agents } = worker_readiness else {
115
+ panic!(
116
+ "T2: silent-spawn-failure must produce Degraded verdict, NOT PendingToolLoad / bare Ready; got {worker_readiness:?}"
117
+ );
118
+ };
119
+ assert!(
120
+ unhealthy_agents.iter().any(|id| id == "clauder"),
121
+ "T2: Degraded verdict must list the agent whose window never materialized \
122
+ (clauder); got unhealthy_agents={unhealthy_agents:?}"
123
+ );
124
+ let rendered = render_quick_start_summary(&report);
125
+ assert!(
126
+ rendered.to_lowercase().contains("degraded"),
127
+ "T2: CLI summary must call out `degraded` so the user does not interpret \
128
+ the report as ready; got {rendered:?}"
129
+ );
130
+ assert!(
131
+ rendered.contains("clauder"),
132
+ "T2: CLI summary should mention the unhealthy agent id (clauder); got {rendered:?}"
133
+ );
134
+ }
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Fixture: minimal team layout + recording transport for the BUG-7 contracts.
138
+ // The transport returns whichever WindowName values are seeded via
139
+ // `with_windows(...)` from `list_windows`, simulating the post-spawn observable.
140
+ // ---------------------------------------------------------------------------
141
+
142
+ fn bug7_team_dir(hermetic: &HermeticTestEnv, tag: &str) -> PathBuf {
143
+ let base = hermetic.workspace(tag);
144
+ let team = base.join("teamdir");
145
+ std::fs::create_dir_all(team.join("agents")).expect("mkdir teamdir/agents");
146
+ std::fs::write(team.join("TEAM.md"), TEAM_MD).expect("write TEAM.md");
147
+ std::fs::write(team.join("agents").join("codexer.md"), CODEX_ROLE).expect("write codexer.md");
148
+ std::fs::write(team.join("agents").join("clauder.md"), CLAUDE_ROLE).expect("write clauder.md");
149
+ team
150
+ }
151
+
152
+ fn render_quick_start_summary(report: &QuickStartReport) -> String {
153
+ // Mirror `cli/mod.rs::quick_start_value`'s summary projection so the contract
154
+ // tests can verify the user-visible string without re-running the full CLI
155
+ // path. Keep this in lock-step with the CLI emit branch.
156
+ match report {
157
+ QuickStartReport::Ready {
158
+ session_name,
159
+ worker_readiness,
160
+ ..
161
+ } => match worker_readiness {
162
+ QuickStartReadiness::Degraded { unhealthy_agents } => format!(
163
+ "quick-start degraded: {}; unhealthy: {}",
164
+ session_name.as_str(),
165
+ unhealthy_agents.join(",")
166
+ ),
167
+ QuickStartReadiness::PendingToolLoad => format!(
168
+ "quick-start launched (worker tool load unverified): {}",
169
+ session_name.as_str()
170
+ ),
171
+ },
172
+ _ => "non-ready".to_string(),
173
+ }
174
+ }
175
+
176
+ #[derive(Clone, Default)]
177
+ struct RecordingTransport {
178
+ state: Arc<Mutex<RecordingState>>,
179
+ }
180
+
181
+ #[derive(Default)]
182
+ struct RecordingState {
183
+ windows: Vec<WindowName>,
184
+ sessions: Vec<SessionName>,
185
+ pane_seq: u64,
186
+ }
187
+
188
+ impl RecordingTransport {
189
+ fn new() -> Self {
190
+ Self::default()
191
+ }
192
+
193
+ fn with_windows(self, windows: Vec<WindowName>) -> Self {
194
+ {
195
+ let mut guard = self.state.lock().expect("lock");
196
+ guard.windows = windows;
197
+ }
198
+ self
199
+ }
200
+
201
+ fn next_pane_id(&self) -> PaneId {
202
+ let mut guard = self.state.lock().expect("lock");
203
+ guard.pane_seq += 1;
204
+ PaneId::new(format!("%{}", guard.pane_seq))
205
+ }
206
+ }
207
+
208
+ impl Transport for RecordingTransport {
209
+ fn kind(&self) -> BackendKind {
210
+ BackendKind::Tmux
211
+ }
212
+
213
+ fn spawn_first(
214
+ &self,
215
+ session: &SessionName,
216
+ window: &WindowName,
217
+ _argv: &[String],
218
+ _cwd: &Path,
219
+ _env: &BTreeMap<String, String>,
220
+ ) -> Result<SpawnResult, TransportError> {
221
+ {
222
+ let mut guard = self.state.lock().expect("lock");
223
+ if !guard
224
+ .sessions
225
+ .iter()
226
+ .any(|s| s.as_str() == session.as_str())
227
+ {
228
+ guard.sessions.push(session.clone());
229
+ }
230
+ }
231
+ Ok(SpawnResult {
232
+ pane_id: self.next_pane_id(),
233
+ session: session.clone(),
234
+ window: window.clone(),
235
+ child_pid: None,
236
+ })
237
+ }
238
+
239
+ fn spawn_into(
240
+ &self,
241
+ session: &SessionName,
242
+ window: &WindowName,
243
+ _argv: &[String],
244
+ _cwd: &Path,
245
+ _env: &BTreeMap<String, String>,
246
+ ) -> Result<SpawnResult, TransportError> {
247
+ Ok(SpawnResult {
248
+ pane_id: self.next_pane_id(),
249
+ session: session.clone(),
250
+ window: window.clone(),
251
+ child_pid: None,
252
+ })
253
+ }
254
+
255
+ fn inject(
256
+ &self,
257
+ _target: &Target,
258
+ _payload: &InjectPayload,
259
+ _submit: Key,
260
+ _bracketed: bool,
261
+ ) -> Result<InjectReport, TransportError> {
262
+ Ok(InjectReport {
263
+ stage_reached: InjectStage::Submit,
264
+ inject_verification: InjectVerification::CaptureContainsToken,
265
+ submit_verification: SubmitVerification::EnterSentWithoutPlaceholderCheck,
266
+ turn_verification: TurnVerification::NotYetObserved,
267
+ attempts: 1,
268
+ submit_diagnostics: None,
269
+ })
270
+ }
271
+
272
+ fn send_keys(&self, _target: &Target, _keys: &[Key]) -> Result<(), TransportError> {
273
+ Ok(())
274
+ }
275
+
276
+ fn capture(
277
+ &self,
278
+ _target: &Target,
279
+ range: CaptureRange,
280
+ ) -> Result<CapturedText, TransportError> {
281
+ Ok(CapturedText {
282
+ text: String::new(),
283
+ range,
284
+ })
285
+ }
286
+
287
+ fn query(&self, _target: &Target, _field: PaneField) -> Result<Option<String>, TransportError> {
288
+ Ok(None)
289
+ }
290
+
291
+ fn liveness(&self, _pane: &PaneId) -> Result<PaneLiveness, TransportError> {
292
+ Ok(PaneLiveness::Live)
293
+ }
294
+
295
+ fn list_targets(&self) -> Result<Vec<PaneInfo>, TransportError> {
296
+ Ok(Vec::new())
297
+ }
298
+
299
+ fn has_session(&self, session: &SessionName) -> Result<bool, TransportError> {
300
+ let guard = self.state.lock().expect("lock");
301
+ Ok(guard
302
+ .sessions
303
+ .iter()
304
+ .any(|s| s.as_str() == session.as_str()))
305
+ }
306
+
307
+ fn list_windows(&self, _session: &SessionName) -> Result<Vec<WindowName>, TransportError> {
308
+ let guard = self.state.lock().expect("lock");
309
+ Ok(guard.windows.clone())
310
+ }
311
+
312
+ fn set_session_env(
313
+ &self,
314
+ _session: &SessionName,
315
+ _key: &str,
316
+ _value: &str,
317
+ ) -> Result<SetEnvOutcome, TransportError> {
318
+ Ok(SetEnvOutcome::Applied)
319
+ }
320
+
321
+ fn kill_session(&self, _session: &SessionName) -> Result<(), TransportError> {
322
+ Ok(())
323
+ }
324
+
325
+ fn kill_window(&self, _target: &Target) -> Result<(), TransportError> {
326
+ Ok(())
327
+ }
328
+
329
+ fn attach_session(&self, _session: &SessionName) -> Result<AttachOutcome, TransportError> {
330
+ Ok(AttachOutcome::Attached)
331
+ }
332
+ }