@team-agent/installer 0.5.86 → 0.5.91
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 +104 -164
- package/crates/team-agent/src/cli/emit.rs +68 -87
- package/crates/team-agent/src/cli/mod.rs +1 -1
- package/crates/team-agent/src/cli/spec.rs +1 -4
- package/crates/team-agent/src/cli/status_port/brief.rs +187 -7
- package/crates/team-agent/src/cli/status_port/inbox.rs +42 -17
- package/crates/team-agent/src/cli/tests/lane_c.rs +34 -26
- package/crates/team-agent/src/cli/tests/main_preserved.rs +4 -70
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +0 -68
- package/crates/team-agent/src/cli/types.rs +3 -16
- package/crates/team-agent/src/compiler.rs +4 -7
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +5 -6
- package/crates/team-agent/src/coordinator/tick.rs +1 -16
- package/crates/team-agent/src/coordinator/types.rs +1 -1
- package/crates/team-agent/src/db/message_store.rs +10 -5
- package/crates/team-agent/src/fake_worker.rs +4 -4
- package/crates/team-agent/src/lifecycle/launch/identity.rs +39 -21
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +0 -10
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +2 -9
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -26
- package/crates/team-agent/src/main.rs +7 -2
- package/crates/team-agent/src/mcp_server/mod.rs +1 -1
- package/crates/team-agent/src/messaging/mod.rs +2 -2
- package/crates/team-agent/src/messaging/results.rs +234 -386
- package/crates/team-agent/src/messaging/tests/runtime.rs +91 -135
- package/crates/team-agent/src/messaging/watchers.rs +1 -1
- package/crates/team-agent/src/model/enums.rs +17 -3
- package/crates/team-agent/src/model/spec.rs +8 -7
- package/crates/team-agent/src/provider/wire.rs +1 -1
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +3 -3
- package/skills/team-agent/command-coverage.json +2 -9
- package/skills/team-agent/references/team-agent-operator.md +661 -0
|
@@ -595,36 +595,16 @@ fn report_result_valid_envelope_returns_ok_with_result_id() {
|
|
|
595
595
|
}
|
|
596
596
|
|
|
597
597
|
#[test]
|
|
598
|
-
fn
|
|
599
|
-
|
|
600
|
-
//
|
|
601
|
-
// [OLD assertion] report_result inserted a parallel `scheduled_events(kind='send',
|
|
602
|
-
// target='leader', status='pending')` row + returned `notification_status="queued"`,
|
|
603
|
-
// and the worker-facing tool body claimed success while leader had not yet seen the
|
|
604
|
-
// result. That queued-only path was MUST-8 / I-3 violating — `notification_status=
|
|
605
|
-
// queued` was returned as success but the leader pane never actually got the text.
|
|
606
|
-
//
|
|
607
|
-
// [NEW assertion] report_result now synchronously funnels through the shared leader-
|
|
608
|
-
// delivery primitive (`send_to_leader_receiver`), creating a `messages` row that
|
|
609
|
-
// `deliver_pending_messages` picks up on the same tick (NO `scheduled_events` row).
|
|
610
|
-
// Without a bound leader pane (this fixture has no `leader_receiver.pane_id`), the
|
|
611
|
-
// primitive returns I-4 `rebind_required` (Blocked / ok=false) — the row is persisted
|
|
612
|
-
// as `failed` for audit and the tool body's `notification_status` is `rebind_required`,
|
|
613
|
-
// NOT a misleading `queued` success. The contract grep that bans `queue_report_result_
|
|
614
|
-
// notification` / `notification_status="queued[_only]"` literals in `results.rs` is the
|
|
615
|
-
// direct mechanical counterpart of this assertion.
|
|
616
|
-
let ws = tmp_ws("reportnotify");
|
|
598
|
+
fn report_result_auto_finalizes_and_queues_compact_leader_notification() {
|
|
599
|
+
let ws = tmp_ws("reportauto");
|
|
617
600
|
crate::state::persist::save_runtime_state(
|
|
618
601
|
&ws,
|
|
619
602
|
&serde_json::json!({
|
|
620
|
-
"session_name": null,
|
|
621
|
-
"leader": {"id": "leader"},
|
|
622
603
|
"agents": {"worker": {"status": "running"}},
|
|
623
604
|
"tasks": [{"id": "task_1", "status": "running", "assignee": "worker"}]
|
|
624
605
|
}),
|
|
625
606
|
)
|
|
626
607
|
.unwrap();
|
|
627
|
-
let store = store_for(&ws);
|
|
628
608
|
let envelope = json(serde_json::json!({
|
|
629
609
|
"schema_version": "result_envelope_v1",
|
|
630
610
|
"task_id": "task_1",
|
|
@@ -639,63 +619,97 @@ fn report_result_funnels_into_leader_delivery_primitive_not_queued_scheduled_eve
|
|
|
639
619
|
}));
|
|
640
620
|
|
|
641
621
|
let out = report_result(&ws, &envelope).unwrap();
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
.expect("report_result returns generated result_id");
|
|
646
|
-
assert!(
|
|
647
|
-
result_id.starts_with("res_"),
|
|
648
|
-
"MessageStore.add_result generates res_* ids; got {result_id}"
|
|
649
|
-
);
|
|
622
|
+
assert_eq!(out["finalization_status"], "auto_finalized");
|
|
623
|
+
assert_eq!(out["notification_status"], "queued");
|
|
624
|
+
assert_eq!(out["leader_notified"], false);
|
|
650
625
|
|
|
651
|
-
|
|
626
|
+
let store = store_for(&ws);
|
|
652
627
|
let conn = seed_conn(&store);
|
|
653
|
-
let
|
|
654
|
-
.query_row("select
|
|
655
|
-
|
|
656
|
-
|
|
628
|
+
let result_status: String = conn
|
|
629
|
+
.query_row("select status from results", [], |row| row.get(0))
|
|
630
|
+
.unwrap();
|
|
631
|
+
let message_count: i64 = conn
|
|
632
|
+
.query_row("select count(*) from messages", [], |row| row.get(0))
|
|
633
|
+
.unwrap();
|
|
634
|
+
assert_eq!(result_status, "collected");
|
|
635
|
+
assert_eq!(message_count, 1);
|
|
636
|
+
let (presentation, content): (String, String) = conn
|
|
637
|
+
.query_row(
|
|
638
|
+
"select presentation, content from messages",
|
|
639
|
+
[],
|
|
640
|
+
|row| Ok((row.get(0)?, row.get(1)?)),
|
|
641
|
+
)
|
|
657
642
|
.unwrap();
|
|
658
643
|
assert_eq!(
|
|
659
|
-
|
|
660
|
-
"
|
|
661
|
-
);
|
|
662
|
-
|
|
663
|
-
// Tool body: no `queued`/`queued_only` notification_status. Without a bound leader
|
|
664
|
-
// pane this fixture surfaces I-4 `rebind_required` (ok=false on the leader delivery,
|
|
665
|
-
// but the result row + audit trail are durable for rebind replay).
|
|
666
|
-
assert_eq!(
|
|
667
|
-
out.get("notification_status").and_then(|v| v.as_str()),
|
|
668
|
-
Some("rebind_required"),
|
|
669
|
-
"I-4: unbound leader pane → rebind_required, never queued/queued_only success"
|
|
644
|
+
serde_json::from_str::<serde_json::Value>(&presentation).unwrap()["class"],
|
|
645
|
+
"stage_result"
|
|
670
646
|
);
|
|
647
|
+
assert!(content.len() < 320, "leader notification must stay compact");
|
|
648
|
+
let state = crate::state::persist::load_runtime_state(&ws).unwrap();
|
|
649
|
+
assert_eq!(state["tasks"][0]["status"], "done");
|
|
671
650
|
assert_eq!(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
"I-4: leader_notified=false when no leader pane is bound"
|
|
651
|
+
state["tasks"][0]["accepted_result_id"].as_str().is_some(),
|
|
652
|
+
true
|
|
675
653
|
);
|
|
676
654
|
assert!(
|
|
677
|
-
|
|
678
|
-
.
|
|
679
|
-
|
|
655
|
+
std::fs::read_to_string(ws.join(".team/logs/events.jsonl"))
|
|
656
|
+
.unwrap()
|
|
657
|
+
.contains("\"collect.result\"")
|
|
680
658
|
);
|
|
659
|
+
}
|
|
681
660
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
let
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
);
|
|
661
|
+
#[test]
|
|
662
|
+
fn report_result_message_scope_finalizes_latest_assigned_task() {
|
|
663
|
+
let ws = tmp_ws("reportauto-message");
|
|
664
|
+
crate::state::persist::save_runtime_state(
|
|
665
|
+
&ws,
|
|
666
|
+
&serde_json::json!({
|
|
667
|
+
"active_team_key": "team-a",
|
|
668
|
+
"teams": {
|
|
669
|
+
"team-a": {
|
|
670
|
+
"agents": {"worker": {"status": "running"}},
|
|
671
|
+
"tasks": [{"id": "task_initial", "status": "pending", "assignee": "worker"}]
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}),
|
|
675
|
+
)
|
|
676
|
+
.unwrap();
|
|
677
|
+
let store = store_for(&ws);
|
|
678
|
+
let conn = seed_conn(&store);
|
|
679
|
+
conn.execute(
|
|
680
|
+
"insert into messages(message_id, owner_team_id, sender, recipient, status, content, created_at) values (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
|
681
|
+
rusqlite::params![
|
|
682
|
+
"msg_turn",
|
|
683
|
+
"team-a",
|
|
684
|
+
"leader",
|
|
685
|
+
"worker",
|
|
686
|
+
"delivered",
|
|
687
|
+
"complete the task",
|
|
688
|
+
"2026-09-19T00:00:00Z",
|
|
689
|
+
],
|
|
690
|
+
)
|
|
691
|
+
.unwrap();
|
|
692
|
+
let envelope = json(serde_json::json!({
|
|
693
|
+
"schema_version": "result_envelope_v1",
|
|
694
|
+
"task_id": "msg_turn",
|
|
695
|
+
"agent_id": "worker",
|
|
696
|
+
"status": "success",
|
|
697
|
+
"summary": "done",
|
|
698
|
+
"changes": [],
|
|
699
|
+
"tests": [],
|
|
700
|
+
"risks": [],
|
|
701
|
+
"artifacts": [],
|
|
702
|
+
"next_actions": []
|
|
703
|
+
}));
|
|
704
|
+
|
|
705
|
+
let out = report_result(&ws, &envelope).unwrap();
|
|
706
|
+
assert_eq!(out["finalization_status"], "auto_finalized");
|
|
707
|
+
assert_eq!(out["notification_status"], "queued");
|
|
708
|
+
let state = crate::state::persist::load_runtime_state(&ws).unwrap();
|
|
709
|
+
assert_eq!(state["teams"]["team-a"]["tasks"][0]["status"], "done");
|
|
710
|
+
assert!(state["teams"]["team-a"]["tasks"][0]["accepted_result_id"]
|
|
711
|
+
.as_str()
|
|
712
|
+
.is_some());
|
|
699
713
|
}
|
|
700
714
|
|
|
701
715
|
#[test]
|
|
@@ -2423,56 +2437,6 @@ fn retry_result_deliveries_retries_notify_failed_watcher() {
|
|
|
2423
2437
|
);
|
|
2424
2438
|
}
|
|
2425
2439
|
|
|
2426
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
2427
|
-
// GROUP W — collect_results_and_notify_watchers orchestration shape.
|
|
2428
|
-
// results.py:430-447.
|
|
2429
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
2430
|
-
|
|
2431
|
-
#[test]
|
|
2432
|
-
fn collect_results_and_notify_watchers_returns_concrete_ok_shape() {
|
|
2433
|
-
// SEEDED contract (results.py:430-447): with NO uncollected results, collect() is
|
|
2434
|
-
// skipped (the `if store.results(uncollected_only=True)` guard is false), so the
|
|
2435
|
-
// result stays {ok:true, collected_results:[]}; a seeded notify_failed watcher
|
|
2436
|
-
// whose result_id has no matching results row is resolved to None by
|
|
2437
|
-
// retry_result_deliveries → skipped → notified stays []. Probed golden (against
|
|
2438
|
-
// exactly this fixture): {"ok": true, "collected": 0, "notified": []}.
|
|
2439
|
-
// (The previous test asserted only out["ok"].is_some(), trivially passed by
|
|
2440
|
-
// {"ok": false}.)
|
|
2441
|
-
let ws = tmp_ws("collectnotify");
|
|
2442
|
-
let store = store_for(&ws);
|
|
2443
|
-
let log = EventLog::new(&ws);
|
|
2444
|
-
|
|
2445
|
-
seed_watcher(
|
|
2446
|
-
&store,
|
|
2447
|
-
"w-orphan",
|
|
2448
|
-
"team-a",
|
|
2449
|
-
"t1",
|
|
2450
|
-
"alice",
|
|
2451
|
-
"notify_failed",
|
|
2452
|
-
Some("res_missing"),
|
|
2453
|
-
None,
|
|
2454
|
-
);
|
|
2455
|
-
|
|
2456
|
-
let out = collect_results_and_notify_watchers(&ws, &log).unwrap();
|
|
2457
|
-
assert_eq!(
|
|
2458
|
-
out.get("ok").and_then(|v| v.as_bool()),
|
|
2459
|
-
Some(true),
|
|
2460
|
-
"ok==true"
|
|
2461
|
-
);
|
|
2462
|
-
assert_eq!(
|
|
2463
|
-
out.get("collected").and_then(|v| v.as_i64()),
|
|
2464
|
-
Some(0),
|
|
2465
|
-
"no uncollected results → collected==0"
|
|
2466
|
-
);
|
|
2467
|
-
assert_eq!(
|
|
2468
|
-
out.get("notified")
|
|
2469
|
-
.and_then(|v| v.as_array())
|
|
2470
|
-
.map(|a| a.len()),
|
|
2471
|
-
Some(0),
|
|
2472
|
-
"orphan watcher (missing result) is skipped → notified empty"
|
|
2473
|
-
);
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
2440
|
// ════════════════════════════════════════════════════════════════════════
|
|
2477
2441
|
// GROUP X — delivered_result_message content-level dedupe lookup +
|
|
2478
2442
|
// result_id_from_text dual (scheduler send dedupe path). result_delivery.py:394.
|
|
@@ -2892,27 +2856,19 @@ fn r8_attach_requeue_exhausted_to_notify_failed_golden_attach_event() {
|
|
|
2892
2856
|
);
|
|
2893
2857
|
}
|
|
2894
2858
|
|
|
2895
|
-
// E15/E23
|
|
2896
|
-
//
|
|
2859
|
+
// E15/E23 single-funnel guard: report_result presents a compact result through
|
|
2860
|
+
// the shared leader receiver and does not carry a private direct-inject retry.
|
|
2897
2861
|
#[test]
|
|
2898
|
-
fn
|
|
2862
|
+
fn e15_report_result_uses_shared_leader_receiver_without_private_retry() {
|
|
2899
2863
|
let src = include_str!("../results.rs");
|
|
2900
|
-
// E23:旧 private direct inject 已合并到 shared deliver_to_leader_fallback_pane primitive。
|
|
2901
|
-
let gate = "if !outcome.ok {";
|
|
2902
|
-
let fallback_call = "deliver_to_leader_fallback_pane(";
|
|
2903
|
-
let gate_pos = src.find(gate);
|
|
2904
|
-
assert!(
|
|
2905
|
-
gate_pos.is_some(),
|
|
2906
|
-
"E15/E23: pane fallback must be gated by `if !outcome.ok` (deliver-fail fallback)"
|
|
2907
|
-
);
|
|
2908
|
-
let fallback_after_gate = src[gate_pos.unwrap()..].find(fallback_call);
|
|
2909
2864
|
assert!(
|
|
2910
|
-
|
|
2911
|
-
"E15/E23: report_result
|
|
2865
|
+
src.contains("send_to_leader_receiver_with_presentation"),
|
|
2866
|
+
"E15/E23: report_result must use the shared leader receiver presentation funnel"
|
|
2912
2867
|
);
|
|
2913
2868
|
assert!(
|
|
2914
|
-
!src.contains("inject_leader_notification_direct")
|
|
2915
|
-
|
|
2869
|
+
!src.contains("inject_leader_notification_direct")
|
|
2870
|
+
&& !src.contains("deliver_to_leader_fallback_pane"),
|
|
2871
|
+
"E23: private direct and removed fallback inject paths must stay deleted"
|
|
2916
2872
|
);
|
|
2917
2873
|
}
|
|
2918
2874
|
|
|
@@ -27,7 +27,7 @@ use super::{MessagingError, WatcherNotice, RESULT_DELIVERY_MAX_ATTEMPTS};
|
|
|
27
27
|
|
|
28
28
|
/// `notify_result_watchers` (`result_delivery.py:38`):匹配 + 去重 + (有界) 投递 result 给 leader
|
|
29
29
|
/// watcher。**恰好一次** (Gap 32/38):同 result_id 多 watcher → 1 次注入,余 `superseded`。
|
|
30
|
-
/// 去重唯一原语 = [`MessageStore::claim_leader_notification_delivery`]
|
|
30
|
+
/// 去重唯一原语 = [`MessageStore::claim_leader_notification_delivery`]。由 watcher/rebind recovery 调用。
|
|
31
31
|
pub(crate) fn notify_result_watchers(
|
|
32
32
|
workspace: &Path,
|
|
33
33
|
result: &serde_json::Value,
|
|
@@ -86,9 +86,8 @@ impl ProviderEffort {
|
|
|
86
86
|
matches!(self, Self::Max)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
///
|
|
90
|
-
///
|
|
91
|
-
/// Copilot/Gemini/CursorAgent/Fake ignore the field (warning at runtime).
|
|
89
|
+
/// Native command support. Claude/Pi accept max; Codex/Grok accept
|
|
90
|
+
/// the other levels. Use resolve_for_provider for admission/ignore policy.
|
|
92
91
|
pub fn is_supported_by(self, provider: Provider) -> bool {
|
|
93
92
|
match provider {
|
|
94
93
|
Provider::Claude | Provider::ClaudeCode | Provider::Pi => true,
|
|
@@ -98,6 +97,21 @@ impl ProviderEffort {
|
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
99
|
}
|
|
100
|
+
|
|
101
|
+
/// One admission policy for compiler, direct specs and runtime commands.
|
|
102
|
+
/// Ok(None) preserves the legacy warning-and-ignore providers.
|
|
103
|
+
pub fn resolve_for_provider(self, provider: Provider) -> Result<Option<Self>, &'static str> {
|
|
104
|
+
if provider == Provider::CursorAgent {
|
|
105
|
+
return Err("cursor_agent does not support effort; the Cursor CLI has no --effort flag");
|
|
106
|
+
}
|
|
107
|
+
if self.is_supported_by(provider) {
|
|
108
|
+
Ok(Some(self))
|
|
109
|
+
} else if self.is_claude_only() {
|
|
110
|
+
Err("effort 'max' is only supported by claude/claude_code/pi")
|
|
111
|
+
} else {
|
|
112
|
+
Ok(None)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
/// auth 模式(`AUTH_MODES` `profiles/constants.py:6`)。
|
|
@@ -18,7 +18,7 @@ use crate::model::ids::TaskId;
|
|
|
18
18
|
use crate::model::task_graph::{find_dependency_cycle, TaskNode};
|
|
19
19
|
use crate::model::yaml::Value as Yaml;
|
|
20
20
|
use crate::model::yaml;
|
|
21
|
-
use crate::provider::wire::
|
|
21
|
+
use crate::provider::wire::parse_canonical_provider;
|
|
22
22
|
|
|
23
23
|
/// result_envelope_v1 顶层 required(= allowed)。
|
|
24
24
|
const RESULT_REQUIRED: &[&str] = &[
|
|
@@ -463,15 +463,16 @@ fn check_agent(agent: &Yaml, path: &str, errors: &mut Vec<String>) {
|
|
|
463
463
|
"{path}/effort: unknown effort '{raw}' (allowed: low|medium|high|xhigh|max)"
|
|
464
464
|
));
|
|
465
465
|
}
|
|
466
|
-
Some(effort)
|
|
466
|
+
Some(effort) => {
|
|
467
467
|
let provider = agent.get("provider").and_then(Yaml::as_str).unwrap_or("");
|
|
468
|
-
if
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
468
|
+
if let Some(provider_enum) = parse_canonical_provider(provider) {
|
|
469
|
+
if let Err(reason) = effort.resolve_for_provider(provider_enum) {
|
|
470
|
+
errors.push(format!(
|
|
471
|
+
"{path}/effort: {reason} (effort: {raw}; provider: {provider})"
|
|
472
|
+
));
|
|
473
|
+
}
|
|
472
474
|
}
|
|
473
475
|
}
|
|
474
|
-
Some(_) => {}
|
|
475
476
|
}
|
|
476
477
|
}
|
|
477
478
|
check_keys_y(
|
|
@@ -231,7 +231,7 @@ mod tests {
|
|
|
231
231
|
);
|
|
232
232
|
assert!(
|
|
233
233
|
model_spec_rs.contains("parse_canonical_provider")
|
|
234
|
-
&& model_spec_rs.contains("
|
|
234
|
+
&& model_spec_rs.contains("resolve_for_provider"),
|
|
235
235
|
"model spec must validate providers through typed helpers"
|
|
236
236
|
);
|
|
237
237
|
assert!(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.91",
|
|
4
4
|
"description": "npx installer for Team Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"team-agent-installer": "npm/install.mjs"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@team-agent/cli-darwin-arm64": "0.5.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
23
|
+
"@team-agent/cli-darwin-arm64": "0.5.91",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.5.91",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.5.91"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|
|
@@ -7,7 +7,7 @@ last_verified_against: "0.5.66"
|
|
|
7
7
|
|
|
8
8
|
# Team Agent
|
|
9
9
|
|
|
10
|
-
Sealed appliance for someone who just got the CLI. Operator handbook (permissions, models, routing, recovery): `
|
|
10
|
+
Sealed appliance for someone who just got the CLI. Operator handbook (permissions, models, routing, recovery): `references/team-agent-operator.md`.
|
|
11
11
|
|
|
12
12
|
If `team-agent --version` does not match `last_verified_against`, do not copy examples as current truth. Learn from the live CLI:
|
|
13
13
|
|
|
@@ -29,11 +29,11 @@ team-agent doctor --help
|
|
|
29
29
|
|
|
30
30
|
**On failure:** if the CLI prints a structured `action`, run that `action` first, then stop. Do not guess flags. `coordinator.session_missing` is a self-healing transient — re-check `status --json`; do not shutdown because of it.
|
|
31
31
|
|
|
32
|
-
The current user-facing agent is the leader (orchestrate only). Workers call `report_result` exactly once. Nested teams: `
|
|
32
|
+
The current user-facing agent is the leader (orchestrate only). Workers call `report_result` exactly once. Nested teams: `references/team-in-team.md`.
|
|
33
33
|
|
|
34
34
|
## Provider Capability Matrix
|
|
35
35
|
|
|
36
|
-
Claude / Codex / Copilot / Gemini / fake: `
|
|
36
|
+
Claude / Codex / Copilot / Gemini / fake: `references/team-agent-operator.md`. These two are in the runtime but were missing from that table:
|
|
37
37
|
`quick-start` / `restart` / `claim-leader` JSON is compact by default (`ok`, `status`/`reason`, next action, attach/send, and `readiness.all_workers_spawned`); pass `--detail` only for internal diagnostics.
|
|
38
38
|
|
|
39
39
|
| Provider | Resume | Turn-state detection | Per-worker model override | Native session fork |
|
|
@@ -96,13 +96,6 @@
|
|
|
96
96
|
"owner": "runtime-owner:provider-launcher",
|
|
97
97
|
"plan": "Use a per-call hermetic codex PATH shim and assert the exact dangerous flag argv log plus the bound CLI exit/output without invoking a real provider."
|
|
98
98
|
},
|
|
99
|
-
{
|
|
100
|
-
"command": "team-agent collect",
|
|
101
|
-
"bucket": "declared_gap",
|
|
102
|
-
"covered": false,
|
|
103
|
-
"owner": "runtime-owner:results",
|
|
104
|
-
"plan": "Execute the exact human collect argv after a worker result and bind assertions to presentation and consumption of that same result."
|
|
105
|
-
},
|
|
106
99
|
{
|
|
107
100
|
"command": "team-agent doctor",
|
|
108
101
|
"bucket": "declared_gap",
|
|
@@ -118,14 +111,14 @@
|
|
|
118
111
|
"plan": "Use an isolated provider/session fixture or authorized subscription gate and bind assertions to fork success or its exact rollback refusal."
|
|
119
112
|
},
|
|
120
113
|
{
|
|
121
|
-
"command": "team-agent inbox",
|
|
114
|
+
"command": "team-agent inbox <agent_id> -n 3",
|
|
122
115
|
"bucket": "declared_gap",
|
|
123
116
|
"covered": false,
|
|
124
117
|
"owner": "runtime-owner:messaging",
|
|
125
118
|
"plan": "Execute the exact default inbox argv and bind assertions to its selected recipient and message or empty-state output."
|
|
126
119
|
},
|
|
127
120
|
{
|
|
128
|
-
"command": "team-agent inbox coder",
|
|
121
|
+
"command": "team-agent inbox coder -n 3",
|
|
129
122
|
"bucket": "declared_gap",
|
|
130
123
|
"covered": false,
|
|
131
124
|
"owner": "runtime-owner:messaging",
|