@team-agent/installer 0.5.111 → 0.5.113
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.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +93 -779
- package/crates/team-agent/src/cli/diagnose.rs +2 -424
- package/crates/team-agent/src/cli/emit.rs +158 -373
- package/crates/team-agent/src/cli/leaders.rs +32 -32
- package/crates/team-agent/src/cli/mod.rs +8 -15
- package/crates/team-agent/src/cli/named_address.rs +17 -16
- package/crates/team-agent/src/cli/route.rs +4 -4
- package/crates/team-agent/src/cli/send/presentation.rs +19 -18
- package/crates/team-agent/src/cli/send/resolve.rs +11 -11
- package/crates/team-agent/src/cli/send.rs +4 -4
- package/crates/team-agent/src/cli/spec.rs +29 -32
- package/crates/team-agent/src/cli/status.rs +7 -7
- package/crates/team-agent/src/cli/tests/base.rs +6 -6
- package/crates/team-agent/src/cli/tests/divergence.rs +3 -2
- package/crates/team-agent/src/cli/tests/lane_c.rs +1 -1
- package/crates/team-agent/src/cli/tests/leader_watch.rs +2 -86
- package/crates/team-agent/src/cli/tests/main_preserved.rs +15 -140
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +1 -258
- package/crates/team-agent/src/cli/tests/mod.rs +0 -2
- package/crates/team-agent/src/cli/tests/named_address.rs +3 -3
- package/crates/team-agent/src/cli/tests/status_send.rs +7 -7
- package/crates/team-agent/src/cli/triage.rs +53 -2
- package/crates/team-agent/src/cli/types.rs +12 -116
- package/crates/team-agent/src/compiler/tests.rs +12 -0
- package/crates/team-agent/src/compiler.rs +0 -9
- package/crates/team-agent/src/coordinator/health.rs +3 -283
- package/crates/team-agent/src/coordinator/mod.rs +0 -5
- package/crates/team-agent/src/coordinator/tests/basics.rs +0 -9
- package/crates/team-agent/src/coordinator/tests/mod.rs +0 -1
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -17
- package/crates/team-agent/src/coordinator/types.rs +1 -21
- package/crates/team-agent/src/db/message_store.rs +0 -42
- package/crates/team-agent/src/db/migration.rs +49 -9
- package/crates/team-agent/src/db/schema.rs +27 -20
- package/crates/team-agent/src/leader/owner_bind.rs +0 -24
- package/crates/team-agent/src/leader/start.rs +5 -0
- package/crates/team-agent/src/leader/tests/byte_findings.rs +0 -20
- package/crates/team-agent/src/leader/tests/identity.rs +21 -32
- package/crates/team-agent/src/leader/tests/lease_claim.rs +0 -55
- package/crates/team-agent/src/lifecycle/launch/identity.rs +172 -13
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +325 -14
- package/crates/team-agent/src/lifecycle/launch.rs +2 -2
- package/crates/team-agent/src/lifecycle/profile_launch.rs +58 -46
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +97 -52
- package/crates/team-agent/src/lifecycle/restart.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -51
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +23 -23
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +29 -55
- package/crates/team-agent/src/messaging/mod.rs +0 -2
- package/crates/team-agent/src/messaging/results.rs +0 -58
- package/crates/team-agent/src/messaging/tests/runtime.rs +0 -46
- package/crates/team-agent/src/provider/adapter.rs +8 -59
- package/crates/team-agent/src/provider/adapters/claude.rs +6 -14
- package/crates/team-agent/src/provider/adapters/codex.rs +8 -18
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -22
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +8 -45
- package/crates/team-agent/src/provider/adapters/grok.rs +7 -31
- package/crates/team-agent/src/provider/adapters/pi.rs +7 -18
- package/crates/team-agent/src/provider/command_helpers.rs +45 -0
- package/crates/team-agent/src/provider/mod.rs +1 -0
- package/crates/team-agent/src/provider/model_catalog.rs +21 -28
- package/crates/team-agent/src/provider/tests/adapter.rs +70 -0
- package/crates/team-agent/src/provider/tests/command_helpers.rs +55 -0
- package/crates/team-agent/src/state/repository.rs +1 -5
- package/package.json +4 -4
- package/templates/team_state.md +1 -1
- package/crates/team-agent/src/cli/tests/peer_allow.rs +0 -164
- package/crates/team-agent/src/cli/tests/verb_validate.rs +0 -195
- package/crates/team-agent/src/coordinator/tests/watch.rs +0 -223
- package/crates/team-agent/src/messaging/peers.rs +0 -34
|
@@ -49,7 +49,6 @@ pub(crate) enum DispatchKind {
|
|
|
49
49
|
Leaders,
|
|
50
50
|
Doctor,
|
|
51
51
|
Approvals,
|
|
52
|
-
AllowPeerTalk,
|
|
53
52
|
Route,
|
|
54
53
|
Profile,
|
|
55
54
|
InstallSkill,
|
|
@@ -75,7 +74,6 @@ pub(crate) const ALL_DISPATCH_KINDS: &[DispatchKind] = &[
|
|
|
75
74
|
DispatchKind::Leaders,
|
|
76
75
|
DispatchKind::Doctor,
|
|
77
76
|
DispatchKind::Approvals,
|
|
78
|
-
DispatchKind::AllowPeerTalk,
|
|
79
77
|
DispatchKind::Route,
|
|
80
78
|
DispatchKind::Profile,
|
|
81
79
|
DispatchKind::InstallSkill,
|
|
@@ -108,36 +106,35 @@ pub(crate) struct CommandSpec {
|
|
|
108
106
|
// Only human operations belong here. Compatibility commands are private in emit.rs.
|
|
109
107
|
#[rustfmt::skip]
|
|
110
108
|
pub(crate) const COMMAND_SPECS: &[CommandSpec] = &[
|
|
111
|
-
CommandSpec { name: "quick-start", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::QuickStart), summary: "
|
|
112
|
-
CommandSpec { name: "send", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Send), summary: "
|
|
113
|
-
CommandSpec { name: "status", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Status), summary: "
|
|
114
|
-
CommandSpec { name: "models", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Models), summary: "
|
|
115
|
-
CommandSpec { name: "inbox", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Inbox), summary: "
|
|
116
|
-
CommandSpec { name: "restart", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Restart), summary: "
|
|
117
|
-
CommandSpec { name: "shutdown", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Shutdown), summary: "
|
|
118
|
-
CommandSpec { name: "add-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::AddAgent), summary: "
|
|
119
|
-
CommandSpec { name: "start-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StartAgent), summary: "
|
|
120
|
-
CommandSpec { name: "stop-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StopAgent), summary: "
|
|
121
|
-
CommandSpec { name: "reset-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ResetAgent), summary: "
|
|
122
|
-
CommandSpec { name: "clone-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::CloneAgent), summary: "
|
|
123
|
-
CommandSpec { name: "fork-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ForkAgent), summary: "
|
|
124
|
-
CommandSpec { name: "remove-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::RemoveAgent), summary: "
|
|
125
|
-
CommandSpec { name: "leaders", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Leaders), summary: "
|
|
126
|
-
CommandSpec { name: "doctor", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Doctor), summary: "
|
|
127
|
-
CommandSpec { name: "approvals", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Approvals), summary: "
|
|
128
|
-
CommandSpec { name: "
|
|
129
|
-
CommandSpec { name: "
|
|
130
|
-
CommandSpec { name: "
|
|
131
|
-
CommandSpec { name: "
|
|
132
|
-
CommandSpec { name: "
|
|
133
|
-
CommandSpec { name: "
|
|
134
|
-
CommandSpec { name: "
|
|
135
|
-
CommandSpec { name: "
|
|
136
|
-
CommandSpec { name: "
|
|
137
|
-
CommandSpec { name: "
|
|
138
|
-
CommandSpec { name: "
|
|
139
|
-
CommandSpec { name: "
|
|
140
|
-
CommandSpec { name: "cursor", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "cursor_agent" }, summary: "用 Cursor 的 agent 工具打开主控对话", usage: "team-agent cursor [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
109
|
+
CommandSpec { name: "quick-start", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::QuickStart), summary: "Create a team from role files; use restart for an initialized team", usage: "team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--team TEAM] [--name NAME] [--team-id TEAM] [--yes] [--backend tmux|conpty] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
110
|
+
CommandSpec { name: "send", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Send), summary: "Send a task to a specified agent", usage: "team-agent send <agent> MESSAGE... [--workspace WORKSPACE] [--team TEAM] [--mailbox] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: Some("a future compatibility release"), action: Some("Use team-agent send <agent> 'task message'; select scope with --workspace and --team"), governance: None },
|
|
111
|
+
CommandSpec { name: "status", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Status), summary: "Check agent status without reading conversation content", usage: "team-agent status [<agent>] [--workspace WORKSPACE] [--team TEAM] [--json] [--summary|--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
112
|
+
CommandSpec { name: "models", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Models), summary: "Discover model names supported by the native provider", usage: "team-agent models [--provider pi|cursor_agent|codex|claude|claude_code|grok] [QUERY|--search TEXT] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
113
|
+
CommandSpec { name: "inbox", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Inbox), summary: "Read agent replies", usage: "team-agent inbox <agent> [-n N|--limit N] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
114
|
+
CommandSpec { name: "restart", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Restart), summary: "Restart an existing team using saved sessions when available", usage: "team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
115
|
+
CommandSpec { name: "shutdown", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Shutdown), summary: "Shut down the selected team and report residual resources", usage: "team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
116
|
+
CommandSpec { name: "add-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::AddAgent), summary: "Add and start an agent", usage: "team-agent add-agent <agent> [--role-file FILE] [--provider TOOL] [--model MODEL] [--effort LEVEL] [--bypass true|false] [--prompt TEXT] [--profile NAME] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
117
|
+
CommandSpec { name: "start-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StartAgent), summary: "Start an existing team agent", usage: "team-agent start-agent <agent> [--provider TOOL] [--model MODEL] [--effort LEVEL] [--bypass true|false] [--prompt TEXT] [--profile NAME] [--workspace WORKSPACE] [--team TEAM] [--allow-fresh] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
118
|
+
CommandSpec { name: "stop-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StopAgent), summary: "Stop an agent while retaining configuration and session history", usage: "team-agent stop-agent <agent> [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
119
|
+
CommandSpec { name: "reset-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ResetAgent), summary: "Discard an agent's saved session association", usage: "team-agent reset-agent <agent> --discard-session [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
120
|
+
CommandSpec { name: "clone-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::CloneAgent), summary: "Clone agent configuration into a new agent", usage: "team-agent clone-agent <agent> --as NEW_AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
121
|
+
CommandSpec { name: "fork-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ForkAgent), summary: "Fork an agent session where supported by the provider", usage: "team-agent fork-agent <agent> --as NEW_AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
122
|
+
CommandSpec { name: "remove-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::RemoveAgent), summary: "Remove an agent after confirmation", usage: "team-agent remove-agent <agent> --confirm [--workspace WORKSPACE] [--team TEAM] [--from-spec] [--force] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
123
|
+
CommandSpec { name: "leaders", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Leaders), summary: "List local leaders and their team scopes", usage: "team-agent leaders [QUERY|--search TEXT] [--all|--stale] [--json] | --prune [--dry-run] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
124
|
+
CommandSpec { name: "doctor", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Doctor), summary: "Diagnose a team and suggest recovery; read-only by default", usage: "team-agent doctor [SPEC] [--workspace WORKSPACE] [--team TEAM] [--comms] [--gate orphans|comms] [--fix] [--fix-schema] [--cleanup-orphans] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
125
|
+
CommandSpec { name: "approvals", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Approvals), summary: "List pending agent approvals", usage: "team-agent approvals [<agent>] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
126
|
+
CommandSpec { name: "route", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Route), summary: "Configure additional provider launch arguments", usage: "team-agent route [status|enable|disable|show [TOOL]|set TOOL -- ARG...|add TOOL -- ARG...|clear TOOL] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
127
|
+
CommandSpec { name: "profile", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Profile), summary: "Manage authentication and proxy profiles", usage: "team-agent profile init|doctor|show NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--proxy-mode direct|inherit] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
128
|
+
CommandSpec { name: "install-skill", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::InstallSkill), summary: "Optionally install an existing public operation skill", usage: "team-agent install-skill (--source DIR|--uninstall) [--target codex|claude|copilot|all] [--dest DIR] [--dry-run] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
129
|
+
CommandSpec { name: "claim-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::ClaimLeader), summary: "Register the current terminal as leader only when diagnosis recommends it", usage: "team-agent claim-leader [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
130
|
+
CommandSpec { name: "takeover", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::Takeover), summary: "Take over an existing team only after diagnosis and confirmation", usage: "team-agent takeover [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
131
|
+
CommandSpec { name: "attach-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::AttachLeader), summary: "Attach a verified leader terminal only when diagnosis recommends it", usage: "team-agent attach-leader [--workspace WORKSPACE] [--team TEAM] --pane PANE --provider TOOL [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
|
|
132
|
+
CommandSpec { name: "pi", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "pi" }, summary: "Open a leader session with Pi", usage: "team-agent pi [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
133
|
+
CommandSpec { name: "codex", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "codex" }, summary: "Open a leader session with Codex", usage: "team-agent codex [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
134
|
+
CommandSpec { name: "claude", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "claude" }, summary: "Open a leader session with Claude Code", usage: "team-agent claude [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
135
|
+
CommandSpec { name: "copilot", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "copilot" }, summary: "Open a leader session with Copilot", usage: "team-agent copilot [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
136
|
+
CommandSpec { name: "grok", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "grok" }, summary: "Open a leader session with Grok", usage: "team-agent grok [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
137
|
+
CommandSpec { name: "cursor", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "cursor_agent" }, summary: "Open a leader session with Cursor agent", usage: "team-agent cursor [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
|
|
141
138
|
];
|
|
142
139
|
|
|
143
140
|
pub(crate) fn command_spec(name: &str) -> Option<&'static CommandSpec> {
|
|
@@ -209,7 +209,7 @@ fn csv_agent_status(
|
|
|
209
209
|
health: Option<&serde_json::Map<String, Value>>,
|
|
210
210
|
) -> &'static str {
|
|
211
211
|
if stale_agent_bucket(agent).is_some() {
|
|
212
|
-
return "
|
|
212
|
+
return "error";
|
|
213
213
|
}
|
|
214
214
|
let raw = agent
|
|
215
215
|
.get("status")
|
|
@@ -226,7 +226,7 @@ fn csv_agent_status(
|
|
|
226
226
|
|| matches!(hstatus.as_str(), "failed" | "error" | "spawn_failed")
|
|
227
227
|
|| matches!(raw.as_str(), "stopped" | "done")
|
|
228
228
|
{
|
|
229
|
-
return "
|
|
229
|
+
return "error";
|
|
230
230
|
}
|
|
231
231
|
let pane_present = agent
|
|
232
232
|
.get("pane_id")
|
|
@@ -239,21 +239,21 @@ fn csv_agent_status(
|
|
|
239
239
|
.filter(|pane| !pane.is_empty())
|
|
240
240
|
.is_some();
|
|
241
241
|
if matches!(raw.as_str(), "running" | "busy" | "working") && !pane_present {
|
|
242
|
-
return "
|
|
242
|
+
return "error";
|
|
243
243
|
}
|
|
244
244
|
// 0.5.35 R4: canonical UNKNOWN beats legacy WORKING in human CSV too.
|
|
245
245
|
if canonical_worker_state_is_unknown(agent) {
|
|
246
|
-
return "
|
|
246
|
+
return "unknown";
|
|
247
247
|
}
|
|
248
248
|
if raw == "idle" || hstatus == "idle" {
|
|
249
|
-
return "
|
|
249
|
+
return "idle";
|
|
250
250
|
}
|
|
251
251
|
if matches!(raw.as_str(), "running" | "busy" | "working")
|
|
252
252
|
|| matches!(hstatus.as_str(), "running" | "working" | "busy")
|
|
253
253
|
{
|
|
254
|
-
return "
|
|
254
|
+
return "working";
|
|
255
255
|
}
|
|
256
|
-
"
|
|
256
|
+
"error"
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
/// `_latest_result_line`(`commands.py:333-337`):agent_id/summary/created_at 渲染单行。
|
|
@@ -420,7 +420,7 @@ fn format_status_csv_preserves_agent_order_and_collapses_errors() {
|
|
|
420
420
|
});
|
|
421
421
|
assert_eq!(
|
|
422
422
|
format_status_csv(&data),
|
|
423
|
-
"zeta
|
|
423
|
+
"zeta,idle\nalpha,working\nerr_failed,error\nerr_missing_pane,error\nerr_unknown,error\nerr_stopped,error"
|
|
424
424
|
);
|
|
425
425
|
}
|
|
426
426
|
|
|
@@ -489,7 +489,7 @@ fn cli_error_payload_plain_runtime() {
|
|
|
489
489
|
assert_eq!(payload.error, "some other error");
|
|
490
490
|
assert_eq!(
|
|
491
491
|
payload.action,
|
|
492
|
-
"
|
|
492
|
+
"Run team-agent doctor --workspace . for the selected team, or inspect the error log shown here."
|
|
493
493
|
);
|
|
494
494
|
assert_eq!(payload.log, "/tmp/y.log");
|
|
495
495
|
assert_eq!(payload.reason, None);
|
|
@@ -511,7 +511,7 @@ fn cli_error_payload_tmux_conflict_quick_start_enrichment() {
|
|
|
511
511
|
// context reset is only through restart --allow-fresh with explicit consent.
|
|
512
512
|
assert_eq!(
|
|
513
513
|
payload.action,
|
|
514
|
-
"
|
|
514
|
+
"Terminal session `my-team` already exists and may belong to your existing team. Resume with team-agent restart; use --allow-fresh only after explicitly accepting loss of saved context. To create another team, change the name in TEAM.md before quick-start. Do not shut down an existing team to bypass this refusal."
|
|
515
515
|
);
|
|
516
516
|
let next = payload.next_actions.as_ref().unwrap();
|
|
517
517
|
assert_eq!(next.len(), 2);
|
|
@@ -529,11 +529,11 @@ fn cli_error_payload_tmux_conflict_non_quick_start_enrichment() {
|
|
|
529
529
|
assert_eq!(payload.session_name.as_deref(), Some("my-team"));
|
|
530
530
|
assert_eq!(
|
|
531
531
|
payload.action,
|
|
532
|
-
"
|
|
532
|
+
"Terminal session `my-team` already exists and may belong to a running team. Do not shut it down; choose another team name before starting."
|
|
533
533
|
);
|
|
534
534
|
let next = payload.next_actions.as_ref().unwrap();
|
|
535
535
|
assert_eq!(next.len(), 1);
|
|
536
|
-
assert!(next[0].contains("
|
|
536
|
+
assert!(next[0].contains("team") && next[0].contains("name"));
|
|
537
537
|
}
|
|
538
538
|
|
|
539
539
|
#[test]
|
|
@@ -749,7 +749,7 @@ fn cmd_leader_passthrough_help_is_pure_human_guidance() {
|
|
|
749
749
|
let result = cmd_leader_passthrough(provider, &[alias.into()], &cwd).unwrap();
|
|
750
750
|
assert_eq!(result.exit, ExitCode::Ok);
|
|
751
751
|
assert!(
|
|
752
|
-
matches!(&result.output, CmdOutput::Human(text) if text.contains(provider) && text.contains("
|
|
752
|
+
matches!(&result.output, CmdOutput::Human(text) if text.contains(provider) && text.contains("Usage") && text.contains("Examples") && text.contains("Next Action"))
|
|
753
753
|
);
|
|
754
754
|
}
|
|
755
755
|
}
|
|
@@ -457,7 +457,7 @@ fn red_send_target_none_is_not_broadcast() {
|
|
|
457
457
|
assert_eq!(send_target(None, Some("*")), MessageTarget::Broadcast);
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
//
|
|
460
|
+
// Doctor retains bounded triage navigation plus complete diagnostic details.
|
|
461
461
|
#[test]
|
|
462
462
|
fn cmd_doctor_comms_human_is_compact_triage_without_boundary_prefix() {
|
|
463
463
|
let mut args = DoctorArgs {
|
|
@@ -483,8 +483,9 @@ fn cmd_doctor_comms_human_is_compact_triage_without_boundary_prefix() {
|
|
|
483
483
|
};
|
|
484
484
|
assert_eq!(text, crate::cli::triage::render("doctor", &report));
|
|
485
485
|
assert!(text.starts_with("doctor:"));
|
|
486
|
-
assert_eq!(text.lines().count(),
|
|
486
|
+
assert_eq!(text.lines().count(), 2 + report["issues"].as_array().unwrap().len()
|
|
487
487
|
+ report["suggested_repairs"].as_array().unwrap().len());
|
|
488
|
+
assert!(text.lines().last().unwrap().starts_with("details: "));
|
|
488
489
|
}
|
|
489
490
|
|
|
490
491
|
// ---- #13 / #27 (P2): run() must NOT treat 'claude_code' as a passthrough trigger ----
|
|
@@ -257,7 +257,7 @@ fn inbox_excludes_leader_stage_result_notifications() {
|
|
|
257
257
|
// the deterministic check sub-shapes (run_id is a random uuid; not value-locked). ────────────────
|
|
258
258
|
#[test]
|
|
259
259
|
fn comms_selftest_golden_boundary_scope_and_check_shapes() {
|
|
260
|
-
let boundary = "
|
|
260
|
+
let boundary = "This checks terminal connection consistency only; it does not send a message or prove that a worker replied.";
|
|
261
261
|
let ws = tmp_workspace();
|
|
262
262
|
let v = diagnose_port::comms_selftest(&ws, None, None).expect("comms_selftest");
|
|
263
263
|
let obj = v.as_object().expect("comms dict");
|
|
@@ -100,11 +100,10 @@ fn cli_shutdown_kills_team_session_real_teardown() {
|
|
|
100
100
|
|
|
101
101
|
// =========================================================================
|
|
102
102
|
// WAVE-2 Lane B — CLI leader handler delegation byte-parity (leader_port::*).
|
|
103
|
-
// The
|
|
103
|
+
// The retained CLI verbs are thin pass-throughs (cli/commands.py:152-157):
|
|
104
104
|
// cmd_takeover -> runtime.takeover(ws, team, confirm)
|
|
105
105
|
// cmd_claim_leader -> runtime.claim_leader(ws, team, confirm) (Family A)
|
|
106
|
-
//
|
|
107
|
-
// leader_port::{takeover,claim_leader,leader_identity} are STUBS returning
|
|
106
|
+
// leader_port::{takeover,claim_leader} are STUBS returning
|
|
108
107
|
// the WRONG shape today -> these LOCK the golden dict so the porter wires
|
|
109
108
|
// them into leader::* / runtime.* and matches byte-for-byte.
|
|
110
109
|
// Golden re-probed @ team-agent-public (probe_claim.py / probe_rtclaim.py /
|
|
@@ -297,89 +296,6 @@ fn leader_port_claim_leader_no_pane_refuses_caller_pane_missing_family_a() {
|
|
|
297
296
|
);
|
|
298
297
|
}
|
|
299
298
|
|
|
300
|
-
// RED — leader_identity(): CLI directly emits leader.leader_identity's 9-key
|
|
301
|
-
// dict (runtime.leader_identity is imported from leader). golden probe_lid.py
|
|
302
|
-
// keys: ok, uuid_prefix, machine_fingerprint, workspace_abspath, os_user,
|
|
303
|
-
// team_id, current_pane_id, last_seen_at, source. Current stub returns
|
|
304
|
-
// {ok:true, team:...} (wrong shape) -> RED.
|
|
305
|
-
#[test]
|
|
306
|
-
fn leader_port_leader_identity_emits_nine_key_dict() {
|
|
307
|
-
let ws = leader_port_ws("identity");
|
|
308
|
-
std::fs::create_dir_all(crate::model::paths::runtime_dir(&ws)).unwrap();
|
|
309
|
-
let v = super::leader_port::leader_identity(&ws, None).unwrap();
|
|
310
|
-
assert_eq!(v["ok"], json!(true));
|
|
311
|
-
let obj = v.as_object().expect("identity → JSON object");
|
|
312
|
-
for key in [
|
|
313
|
-
"ok",
|
|
314
|
-
"uuid_prefix",
|
|
315
|
-
"machine_fingerprint",
|
|
316
|
-
"workspace_abspath",
|
|
317
|
-
"os_user",
|
|
318
|
-
"team_id",
|
|
319
|
-
"current_pane_id",
|
|
320
|
-
"last_seen_at",
|
|
321
|
-
"source",
|
|
322
|
-
] {
|
|
323
|
-
assert!(
|
|
324
|
-
obj.contains_key(key),
|
|
325
|
-
"golden identity dict must carry '{key}', got {obj:?}"
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
// no override/state uuid → source is the leader-plan "derived" string.
|
|
329
|
-
assert_eq!(v["source"], json!("derived"));
|
|
330
|
-
// uuid_prefix is exactly 12 hex chars (derive[:12]).
|
|
331
|
-
let prefix = v["uuid_prefix"].as_str().expect("uuid_prefix str");
|
|
332
|
-
assert_eq!(prefix.len(), 12, "uuid_prefix == derived[:12]");
|
|
333
|
-
assert!(prefix.chars().all(|c| c.is_ascii_hexdigit()));
|
|
334
|
-
// no team registered + no TMUX_PANE/receiver → these are JSON null.
|
|
335
|
-
if std::env::var_os("TMUX_PANE").is_none() {
|
|
336
|
-
assert_eq!(v["current_pane_id"], serde_json::Value::Null);
|
|
337
|
-
}
|
|
338
|
-
assert_eq!(v["last_seen_at"], serde_json::Value::Null);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// ── cmd_watch (cli/adapters.rs:58) [RED] — today a CmdResult::none() no-op ───────────────────────
|
|
342
|
-
// Golden cmd_watch (cli/commands.py:103-109) DELEGATES to run_watch(workspace.resolve(), team) and
|
|
343
|
-
// exits 0. Golden run_watch (watch/__init__.py:25-37) is a `while True` LIVE TAIL that streams
|
|
344
|
-
// render_event_line output (collect_watch_lines) for the watched team. The Rust cmd_watch returns
|
|
345
|
-
// CmdResult::none() — a no-op that never touches the watch subsystem. The watch LINE SHAPE is itself
|
|
346
|
-
// byte-locked by coordinator::render_event_line (coordinator/tests.rs GROUP H); the cli contract here
|
|
347
|
-
// is that cmd_watch must DELEGATE and surface those rendered lines. Seeded a result_received event ->
|
|
348
|
-
// golden render = "result_received: <agent> -> <summary>" (render_event_line: agent_id + summary[:80]).
|
|
349
|
-
//
|
|
350
|
-
// RED confirmed TODAY: cmd_watch=none() returns immediately (no watch line) -> the assertion fails
|
|
351
|
-
// (and does NOT hang). PORTER: wire cmd_watch -> coordinator::run_watch(resolved workspace, team,
|
|
352
|
-
// interval, sink). Since golden's tail is `while True`, the cli port needs a TERMINATING / bounded
|
|
353
|
-
// entry to be both byte-parity AND unit-testable (collect the current watch lines into the CmdResult,
|
|
354
|
-
// or stream to stdout with a bounded test seam) — a blocking unit test is unacceptable.
|
|
355
|
-
#[test]
|
|
356
|
-
fn cmd_watch_delegates_and_surfaces_rendered_watch_lines_not_noop() {
|
|
357
|
-
let ws = tmp_workspace();
|
|
358
|
-
let logs = crate::model::paths::logs_dir(&ws);
|
|
359
|
-
std::fs::create_dir_all(&logs).unwrap();
|
|
360
|
-
std::fs::write(
|
|
361
|
-
logs.join("events.jsonl"),
|
|
362
|
-
"{\"event\":\"result_received\",\"agent_id\":\"alpha\",\"summary\":\"did the thing\"}\n",
|
|
363
|
-
)
|
|
364
|
-
.unwrap();
|
|
365
|
-
let r = cmd_watch(&WatchArgs {
|
|
366
|
-
workspace: ws.clone(),
|
|
367
|
-
team: None,
|
|
368
|
-
})
|
|
369
|
-
.expect("cmd_watch returns a CmdResult");
|
|
370
|
-
let text = match &r.output {
|
|
371
|
-
CmdOutput::Human(s) => s.clone(),
|
|
372
|
-
CmdOutput::Json(v) => v.to_string(),
|
|
373
|
-
CmdOutput::None => String::new(),
|
|
374
|
-
};
|
|
375
|
-
assert!(
|
|
376
|
-
text.contains("result_received: alpha -> did the thing"),
|
|
377
|
-
"cmd_watch must DELEGATE to the watch subsystem (run_watch -> render_event_line) and surface the \
|
|
378
|
-
rendered watch line; today it is a CmdResult::none() no-op. got output={:?}",
|
|
379
|
-
r.output
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
299
|
// D7 [WARN] — WAVE-2 Lane B: empty caller binds refuse as caller_pane_missing.
|
|
384
300
|
#[test]
|
|
385
301
|
#[serial_test::serial(env)]
|
|
@@ -175,58 +175,7 @@ fn inbox_matches_sender_or_recipient_and_excludes_others() {
|
|
|
175
175
|
);
|
|
176
176
|
let _ = std::fs::remove_dir_all(&ws);
|
|
177
177
|
}
|
|
178
|
-
|
|
179
|
-
// NOT a stored `pane_id` field. A live worker present in state (with a `window`, on the team's `-L`
|
|
180
|
-
// socket) must NOT be fabricated as "agent pane not found". ──────────────────────────────────────
|
|
181
|
-
// Golden status/peek.py:35-44: agent = state["agents"][id]; window = agent.get("window", id);
|
|
182
|
-
// if not session_name or not _tmux_window_exists(session_name, window): raise "agent terminal is
|
|
183
|
-
// not available: <id>"; else `tmux capture-pane -t session:window`. It NEVER reads a stored pane_id.
|
|
184
|
-
// Probed live (/tmp/probe_peek.py): a present worker whose window is absent on the socket raises
|
|
185
|
-
// `agent terminal is not available: w1`; a missing agent raises `unknown agent id: <id>`. Rust
|
|
186
|
-
// cmd_peek (adapters.rs:231 + agent_pane_id:279) keys off agent_state pane_id/pane/tmux_pane_id and
|
|
187
|
-
// returns {ok:false,error:"agent pane not found"} when absent — so a NORMAL live worker (window in
|
|
188
|
-
// state, no pane_id field) is mis-reported as not found. That is the CP-1 pane-resolution divergence.
|
|
189
|
-
//
|
|
190
|
-
// Deterministic without real tmux: on a host with no live session, the golden-correct peek resolves
|
|
191
|
-
// session:window, finds the window absent on the socket, and yields "agent terminal is not available:
|
|
192
|
-
// w1" — NOT "agent pane not found". (The window-on-socket -> real raw-screen capture positive case is
|
|
193
|
-
// real-machine; see the #[ignore] dispatch_routes_peek_real_machine.)
|
|
194
|
-
#[test]
|
|
195
|
-
fn peek_resolves_live_worker_via_session_window_not_pane_id_field() {
|
|
196
|
-
let ws = tmp_workspace();
|
|
197
|
-
// a live worker: present in state with a `window`, session_name set, but NO stored pane_id field.
|
|
198
|
-
// session name is unique so a real tmux session on the dev host can't accidentally satisfy it.
|
|
199
|
-
crate::state::persist::save_runtime_state(
|
|
200
|
-
&ws,
|
|
201
|
-
&json!({
|
|
202
|
-
"session_name": "team-peek-red-probe-x9q",
|
|
203
|
-
"agents": {"w1": {"status": "running", "provider": "codex", "window": "w1"}}
|
|
204
|
-
}),
|
|
205
|
-
)
|
|
206
|
-
.unwrap();
|
|
207
|
-
let args = PeekArgs {
|
|
208
|
-
agent: "w1".to_string(),
|
|
209
|
-
workspace: ws.clone(),
|
|
210
|
-
tail: 20,
|
|
211
|
-
head: None,
|
|
212
|
-
search: None,
|
|
213
|
-
allow_raw_screen: true,
|
|
214
|
-
json: true,
|
|
215
|
-
};
|
|
216
|
-
let text = outcome_text(cmd_peek(&args));
|
|
217
|
-
assert!(
|
|
218
|
-
!text.contains("agent pane not found"),
|
|
219
|
-
"peek keys off a stored pane_id field and fabricates 'agent pane not found' for a live worker \
|
|
220
|
-
that has a `window` in state; golden resolves session:window and never reads pane_id. got: {text}"
|
|
221
|
-
);
|
|
222
|
-
assert!(
|
|
223
|
-
text.contains("agent terminal is not available: w1"),
|
|
224
|
-
"golden status/peek.py: a worker whose window is not on the socket yields \
|
|
225
|
-
'agent terminal is not available: w1' (window-existence via session:window), NOT a \
|
|
226
|
-
pane_id-keyed error. got: {text}"
|
|
227
|
-
);
|
|
228
|
-
let _ = std::fs::remove_dir_all(&ws);
|
|
229
|
-
}
|
|
178
|
+
|
|
230
179
|
#[test]
|
|
231
180
|
fn ux_doctor_secret_scan_is_present_and_non_triggering_for_normal_paths() {
|
|
232
181
|
let ws = tmp_workspace();
|
|
@@ -295,44 +244,16 @@ fn ux_doctor_secret_scan_findings_name_the_exact_trigger() {
|
|
|
295
244
|
let _ = std::fs::remove_dir_all(&ws);
|
|
296
245
|
}
|
|
297
246
|
#[test]
|
|
298
|
-
fn
|
|
299
|
-
let
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
"tasks": [{"id": "t1", "assignee": "w1", "status": "pending"}],
|
|
306
|
-
"leader_receiver": {"status": "attached"},
|
|
307
|
-
}),
|
|
308
|
-
)
|
|
309
|
-
.unwrap();
|
|
310
|
-
let value = json_output(
|
|
311
|
-
cmd_wait_ready(&WaitReadyArgs {
|
|
312
|
-
workspace: ws.clone(),
|
|
313
|
-
timeout: 0.0,
|
|
314
|
-
json: true,
|
|
315
|
-
team: None,
|
|
316
|
-
})
|
|
317
|
-
.expect("wait-ready"),
|
|
318
|
-
);
|
|
319
|
-
assert_eq!(
|
|
320
|
-
value["ok"],
|
|
321
|
-
json!(false),
|
|
322
|
-
"wait-ready must not fake success before workers are ready"
|
|
323
|
-
);
|
|
324
|
-
assert_eq!(value.pointer("/readiness/ready"), Some(&json!(false)));
|
|
325
|
-
assert!(
|
|
326
|
-
value["summary"]
|
|
327
|
-
.as_str()
|
|
328
|
-
.unwrap_or("")
|
|
329
|
-
.contains("not ready"),
|
|
330
|
-
"wait-ready false state should explain not-ready status, got {value:?}"
|
|
331
|
-
);
|
|
332
|
-
let _ = std::fs::remove_dir_all(&ws);
|
|
247
|
+
fn runtime_readiness_rejects_starting_workers() {
|
|
248
|
+
let value = crate::cli::diagnose::wait_readiness(&json!({
|
|
249
|
+
"agents": {"w1": {"status": "starting"}},
|
|
250
|
+
"leader_receiver": {"status": "attached"},
|
|
251
|
+
}));
|
|
252
|
+
assert_eq!(value["ready"], json!(false));
|
|
253
|
+
assert_eq!(value["all_spawned"], json!(false));
|
|
333
254
|
}
|
|
334
255
|
#[test]
|
|
335
|
-
fn
|
|
256
|
+
fn runtime_readiness_counts_mcp_config_and_task_prompt_delivery() {
|
|
336
257
|
let ws = tmp_workspace();
|
|
337
258
|
let mcp_config = ws
|
|
338
259
|
.join(".team")
|
|
@@ -342,10 +263,9 @@ fn wait_ready_fake_quick_start_counts_mcp_config_and_task_prompt_delivery() {
|
|
|
342
263
|
.join("mcp_config.json");
|
|
343
264
|
std::fs::create_dir_all(mcp_config.parent().unwrap()).unwrap();
|
|
344
265
|
std::fs::write(&mcp_config, r#"{"mcpServers":{"team-agent":{}}}"#).unwrap();
|
|
345
|
-
|
|
346
|
-
&ws,
|
|
347
|
-
&json!({
|
|
266
|
+
let state = json!({
|
|
348
267
|
"session_name": "team-fake-ready",
|
|
268
|
+
"messages": {"delivered": 1},
|
|
349
269
|
"agents": {
|
|
350
270
|
"fake_impl": {
|
|
351
271
|
"status": "running",
|
|
@@ -359,30 +279,9 @@ fn wait_ready_fake_quick_start_counts_mcp_config_and_task_prompt_delivery() {
|
|
|
359
279
|
"status": "pending",
|
|
360
280
|
}],
|
|
361
281
|
"leader_receiver": {"status": "attached"},
|
|
362
|
-
})
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
let store = crate::message_store::MessageStore::open(&ws).unwrap();
|
|
366
|
-
store
|
|
367
|
-
.create_message(
|
|
368
|
-
Some("task_impl"),
|
|
369
|
-
"leader",
|
|
370
|
-
"fake_impl",
|
|
371
|
-
"initial task prompt",
|
|
372
|
-
None,
|
|
373
|
-
true,
|
|
374
|
-
None,
|
|
375
|
-
)
|
|
376
|
-
.unwrap();
|
|
377
|
-
let value = json_output(
|
|
378
|
-
cmd_wait_ready(&WaitReadyArgs {
|
|
379
|
-
workspace: ws.clone(),
|
|
380
|
-
timeout: 0.0,
|
|
381
|
-
json: true,
|
|
382
|
-
team: None,
|
|
383
|
-
})
|
|
384
|
-
.expect("wait-ready"),
|
|
385
|
-
);
|
|
282
|
+
});
|
|
283
|
+
let readiness = crate::cli::diagnose::wait_readiness(&state);
|
|
284
|
+
let value = json!({"readiness": readiness});
|
|
386
285
|
assert_eq!(
|
|
387
286
|
value.pointer("/readiness/mcp_ready"),
|
|
388
287
|
Some(&json!(true)),
|
|
@@ -400,31 +299,7 @@ fn wait_ready_fake_quick_start_counts_mcp_config_and_task_prompt_delivery() {
|
|
|
400
299
|
);
|
|
401
300
|
let _ = std::fs::remove_dir_all(&ws);
|
|
402
301
|
}
|
|
403
|
-
|
|
404
|
-
json!({
|
|
405
|
-
"schema_version": "result_envelope_v1",
|
|
406
|
-
"task_id": "task_impl",
|
|
407
|
-
"agent_id": "fake_impl",
|
|
408
|
-
"status": "success",
|
|
409
|
-
"summary": "done",
|
|
410
|
-
"artifacts": [],
|
|
411
|
-
"changes": [],
|
|
412
|
-
"tests": [{"command": "cargo test", "status": "passed"}],
|
|
413
|
-
"risks": [],
|
|
414
|
-
"next_actions": []
|
|
415
|
-
})
|
|
416
|
-
}
|
|
417
|
-
fn seed_uncollected_result(ws: &std::path::Path, result_id: &str) {
|
|
418
|
-
let store = crate::message_store::MessageStore::open(ws).unwrap();
|
|
419
|
-
let conn = crate::db::schema::open_db(store.db_path()).unwrap();
|
|
420
|
-
conn.execute(
|
|
421
|
-
"insert into results(
|
|
422
|
-
result_id, owner_team_id, task_id, agent_id, envelope, status, created_at
|
|
423
|
-
) values (?1, null, 'task_impl', 'fake_impl', ?2, 'success', '2026-06-02T10:00:00+00:00')",
|
|
424
|
-
rusqlite::params![result_id, valid_result_envelope().to_string()],
|
|
425
|
-
)
|
|
426
|
-
.unwrap();
|
|
427
|
-
}
|
|
302
|
+
|
|
428
303
|
fn json_output(result: CmdResult) -> serde_json::Value {
|
|
429
304
|
match result.output {
|
|
430
305
|
CmdOutput::Json(v) => v,
|