@team-agent/installer 0.5.113 → 0.5.114

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 (46) hide show
  1. package/Cargo.lock +252 -84
  2. package/Cargo.toml +3 -1
  3. package/crates/team-agent/Cargo.toml +3 -0
  4. package/crates/team-agent/src/cli/adapters.rs +28 -15
  5. package/crates/team-agent/src/cli/diagnose.rs +36 -13
  6. package/crates/team-agent/src/cli/emit.rs +55 -20
  7. package/crates/team-agent/src/cli/leader.rs +16 -0
  8. package/crates/team-agent/src/cli/leader_prompt.rs +261 -0
  9. package/crates/team-agent/src/cli/mod.rs +152 -8
  10. package/crates/team-agent/src/cli/models.rs +68 -18
  11. package/crates/team-agent/src/cli/spec.rs +7 -1
  12. package/crates/team-agent/src/cli/status_port/brief.rs +268 -101
  13. package/crates/team-agent/src/cli/tests/base.rs +88 -0
  14. package/crates/team-agent/src/cli/tests/status_send.rs +2 -0
  15. package/crates/team-agent/src/compiler.rs +66 -18
  16. package/crates/team-agent/src/contract_runtime/backend.rs +646 -0
  17. package/crates/team-agent/src/contract_runtime/config.rs +309 -0
  18. package/crates/team-agent/src/contract_runtime/discovery.rs +237 -0
  19. package/crates/team-agent/src/contract_runtime/forward.rs +229 -0
  20. package/crates/team-agent/src/contract_runtime/framework.rs +261 -0
  21. package/crates/team-agent/src/contract_runtime/mcp.rs +396 -0
  22. package/crates/team-agent/src/contract_runtime/mod.rs +14 -0
  23. package/crates/team-agent/src/contract_runtime/prompt.rs +216 -0
  24. package/crates/team-agent/src/contract_runtime/pump.rs +207 -0
  25. package/crates/team-agent/src/contract_runtime/registry.rs +30 -0
  26. package/crates/team-agent/src/coordinator/tick.rs +26 -8
  27. package/crates/team-agent/src/leader/mod.rs +1 -0
  28. package/crates/team-agent/src/leader/prompt.rs +906 -0
  29. package/crates/team-agent/src/leader/start.rs +260 -16
  30. package/crates/team-agent/src/leader/tests/mod.rs +2 -0
  31. package/crates/team-agent/src/leader/tests/prompt_contract.rs +268 -0
  32. package/crates/team-agent/src/leader/types.rs +6 -0
  33. package/crates/team-agent/src/lib.rs +4 -0
  34. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +472 -388
  35. package/crates/team-agent/src/lifecycle/launch/spawn.rs +38 -9
  36. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +17 -0
  37. package/crates/team-agent/src/lifecycle/launch.rs +39 -28
  38. package/crates/team-agent/src/lifecycle/types.rs +4 -1
  39. package/crates/team-agent/src/lifecycle/worker_command_context.rs +37 -27
  40. package/crates/team-agent/src/main.rs +6 -0
  41. package/crates/team-agent/src/messaging/delivery.rs +50 -1
  42. package/crates/team-agent/src/messaging/send.rs +10 -0
  43. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +131 -0
  44. package/crates/team-agent/src/model/spec.rs +24 -12
  45. package/crates/team-agent/src/state/persist.rs +73 -0
  46. package/package.json +4 -4
@@ -16,8 +16,8 @@ use crate::model::enums::TaskStatus;
16
16
  use crate::model::errors::ModelError;
17
17
  use crate::model::ids::TaskId;
18
18
  use crate::model::task_graph::{find_dependency_cycle, TaskNode};
19
- use crate::model::yaml::Value as Yaml;
20
19
  use crate::model::yaml;
20
+ use crate::model::yaml::Value as Yaml;
21
21
  use crate::provider::wire::parse_canonical_provider;
22
22
 
23
23
  const LEGACY_DISPLAY_KEY: &str = concat!("display", "_backend");
@@ -733,10 +733,13 @@ fn semantic_errors(spec: &Yaml, base_dir: &Path) -> Vec<String> {
733
733
 
734
734
  for (idx, agent) in agents.iter().enumerate() {
735
735
  let provider = agent.get("provider");
736
- if !provider
737
- .and_then(Yaml::as_str)
738
- .is_some_and(|p| parse_canonical_provider(p).is_some())
739
- {
736
+ if !provider.and_then(Yaml::as_str).is_some_and(|p| {
737
+ #[cfg(unix)]
738
+ if crate::contract_runtime::registry::descriptor(p).is_some() {
739
+ return true;
740
+ }
741
+ parse_canonical_provider(p).is_some()
742
+ }) {
740
743
  e.push(format!(
741
744
  "/agents/{idx}/provider: unknown provider {}",
742
745
  py_repr(provider)
@@ -1066,7 +1069,11 @@ mod tests {
1066
1069
  .iter()
1067
1070
  .filter(|m| m.starts_with("/agents/dangerously_skip_permissions: missing"))
1068
1071
  .collect();
1069
- assert_eq!(missing.len(), 1, "exactly one missing-field error, got: {errors:#?}");
1072
+ assert_eq!(
1073
+ missing.len(),
1074
+ 1,
1075
+ "exactly one missing-field error, got: {errors:#?}"
1076
+ );
1070
1077
  assert!(
1071
1078
  missing[0].contains("`codex_implementer`"),
1072
1079
  "must name the role id, got: {}",
@@ -1083,7 +1090,11 @@ mod tests {
1083
1090
  #[test]
1084
1091
  fn test_invalid_dangerously_type_rejected() {
1085
1092
  let text = include_str!("testdata/team.spec.yaml");
1086
- let bad = text.replacen(" dangerously_skip_permissions: false\n", " dangerously_skip_permissions: \"yes\"\n", 1);
1093
+ let bad = text.replacen(
1094
+ " dangerously_skip_permissions: false\n",
1095
+ " dangerously_skip_permissions: \"yes\"\n",
1096
+ 1,
1097
+ );
1087
1098
  assert_ne!(text, bad, "fixture must contain the field");
1088
1099
  let spec = yaml::loads(&bad).unwrap();
1089
1100
  let errors = all_spec_errors(&spec);
@@ -1091,7 +1102,11 @@ mod tests {
1091
1102
  .iter()
1092
1103
  .filter(|m| m.starts_with("/agents/dangerously_skip_permissions: must be a boolean"))
1093
1104
  .collect();
1094
- assert_eq!(type_errs.len(), 1, "exactly one type error, got: {errors:#?}");
1105
+ assert_eq!(
1106
+ type_errs.len(),
1107
+ 1,
1108
+ "exactly one type error, got: {errors:#?}"
1109
+ );
1095
1110
  assert!(
1096
1111
  type_errs[0].contains("`codex_implementer`"),
1097
1112
  "must name the role id, got: {}",
@@ -1139,10 +1154,7 @@ mod tests {
1139
1154
  // 缺失 role frontmatter 值时编译为安全默认 false;此处锁定公共编译入口的结果。
1140
1155
  #[test]
1141
1156
  fn test_all_7_triggers_use_compiled_default_bypass() {
1142
- let team = std::env::temp_dir().join(format!(
1143
- "ta-spec-7trigger-{}",
1144
- std::process::id()
1145
- ));
1157
+ let team = std::env::temp_dir().join(format!("ta-spec-7trigger-{}", std::process::id()));
1146
1158
  let _ = std::fs::remove_dir_all(&team);
1147
1159
  std::fs::create_dir_all(team.join("agents")).unwrap();
1148
1160
  std::fs::write(
@@ -1333,6 +1333,15 @@ fn lifecycle_placeholder(agent: &Value) -> bool {
1333
1333
  }
1334
1334
 
1335
1335
  fn lifecycle_peer_snapshot_is_stale(incoming: &Value, latest: &Value) -> bool {
1336
+ // A save that omitted a not-yet-spawned peer can carry roster_stub's
1337
+ // metadata-only row into a later save. It has neither status nor epoch;
1338
+ // it must not conflict with the peer that has since started.
1339
+ if incoming.get("status").is_none_or(Value::is_null)
1340
+ && live_topology_fields(incoming).is_empty()
1341
+ && latest.get("status").and_then(Value::as_str) == Some("running")
1342
+ {
1343
+ return true;
1344
+ }
1336
1345
  // A concurrent clone/restart can have promoted its peer to `running`
1337
1346
  // while its capture tuple is still pending. That row is still a
1338
1347
  // lifecycle snapshot, not a completed topology observation; preserving
@@ -2643,6 +2652,70 @@ mod tests {
2643
2652
  assert!(saved["agents"].get("f2").is_some());
2644
2653
  }
2645
2654
 
2655
+ #[test]
2656
+ fn lifecycle_authority_preserves_peer_that_started_after_roster_stub_snapshot() {
2657
+ let ws = temp_ws();
2658
+ write_state(
2659
+ &ws,
2660
+ &json!({
2661
+ "session_name": "team-a",
2662
+ "active_team_key": "team-a",
2663
+ "agents": {"f1": {"provider": "claude", "status": "starting"}}
2664
+ }),
2665
+ );
2666
+ // f2 loaded before f1's reservation. Persist carries the still-unspawned
2667
+ // f1 forward as an actual roster stub, not a fabricated test shape.
2668
+ let incoming = json!({
2669
+ "session_name": "team-a",
2670
+ "active_team_key": "team-a",
2671
+ "agents": {"f2": {"provider": "claude", "status": "starting"}}
2672
+ });
2673
+ save_runtime_state_with_lifecycle_topology_authority(&ws, &incoming, "team-a", &["f2"])
2674
+ .unwrap();
2675
+ let mut stale = read_state(&ws);
2676
+ assert!(stale["agents"]["f1"].get("status").is_none());
2677
+ assert!(live_topology_fields(&stale["agents"]["f1"]).is_empty());
2678
+
2679
+ // f1 starts after f2 takes its snapshot; capture is not complete yet.
2680
+ let mut started = stale.clone();
2681
+ started["agents"]["f1"] = json!({
2682
+ "provider": "claude",
2683
+ "status": "running",
2684
+ "pane_id": "%1",
2685
+ "pane_pid": 101,
2686
+ "window": "f1",
2687
+ "spawned_at": "2026-10-11T05:55:20Z",
2688
+ "spawn_epoch": 1,
2689
+ "_pending_session_id": "session-f1"
2690
+ });
2691
+ normalize_agent_session_state(&mut started);
2692
+ save_runtime_state_with_lifecycle_topology_authority(&ws, &started, "team-a", &["f1"])
2693
+ .unwrap();
2694
+ let latest = read_state(&ws);
2695
+ stale["agents"]["f2"] = json!({
2696
+ "provider": "claude",
2697
+ "status": "running",
2698
+ "pane_id": "%2",
2699
+ "pane_pid": 102,
2700
+ "window": "f2",
2701
+ "spawned_at": "2026-10-11T05:55:21Z",
2702
+ "spawn_epoch": 1,
2703
+ "_pending_session_id": "session-f2"
2704
+ });
2705
+
2706
+ // Ordinary writers still cannot overwrite the live peer from a stub.
2707
+ assert!(matches!(
2708
+ save_runtime_state(&ws, &stale),
2709
+ Err(StateError::SaveConflict(_))
2710
+ ));
2711
+ assert_eq!(read_state(&ws), latest);
2712
+ save_runtime_state_with_lifecycle_topology_authority(&ws, &stale, "team-a", &["f2"])
2713
+ .unwrap();
2714
+ let saved = read_state(&ws);
2715
+ assert_eq!(saved["agents"]["f1"], latest["agents"]["f1"]);
2716
+ assert_eq!(saved["agents"]["f2"], stale["agents"]["f2"]);
2717
+ }
2718
+
2646
2719
  #[test]
2647
2720
  fn lifecycle_authority_preserves_complete_latest_row_for_starting_peer() {
2648
2721
  let ws = temp_ws();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.113",
3
+ "version": "0.5.114",
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.113",
24
- "@team-agent/cli-darwin-x64": "0.5.113",
25
- "@team-agent/cli-linux-x64": "0.5.113"
23
+ "@team-agent/cli-darwin-arm64": "0.5.114",
24
+ "@team-agent/cli-darwin-x64": "0.5.114",
25
+ "@team-agent/cli-linux-x64": "0.5.114"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",