@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.
- package/Cargo.lock +252 -84
- package/Cargo.toml +3 -1
- package/crates/team-agent/Cargo.toml +3 -0
- package/crates/team-agent/src/cli/adapters.rs +28 -15
- package/crates/team-agent/src/cli/diagnose.rs +36 -13
- package/crates/team-agent/src/cli/emit.rs +55 -20
- package/crates/team-agent/src/cli/leader.rs +16 -0
- package/crates/team-agent/src/cli/leader_prompt.rs +261 -0
- package/crates/team-agent/src/cli/mod.rs +152 -8
- package/crates/team-agent/src/cli/models.rs +68 -18
- package/crates/team-agent/src/cli/spec.rs +7 -1
- package/crates/team-agent/src/cli/status_port/brief.rs +268 -101
- package/crates/team-agent/src/cli/tests/base.rs +88 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +2 -0
- package/crates/team-agent/src/compiler.rs +66 -18
- package/crates/team-agent/src/contract_runtime/backend.rs +646 -0
- package/crates/team-agent/src/contract_runtime/config.rs +309 -0
- package/crates/team-agent/src/contract_runtime/discovery.rs +237 -0
- package/crates/team-agent/src/contract_runtime/forward.rs +229 -0
- package/crates/team-agent/src/contract_runtime/framework.rs +261 -0
- package/crates/team-agent/src/contract_runtime/mcp.rs +396 -0
- package/crates/team-agent/src/contract_runtime/mod.rs +14 -0
- package/crates/team-agent/src/contract_runtime/prompt.rs +216 -0
- package/crates/team-agent/src/contract_runtime/pump.rs +207 -0
- package/crates/team-agent/src/contract_runtime/registry.rs +30 -0
- package/crates/team-agent/src/coordinator/tick.rs +26 -8
- package/crates/team-agent/src/leader/mod.rs +1 -0
- package/crates/team-agent/src/leader/prompt.rs +906 -0
- package/crates/team-agent/src/leader/start.rs +260 -16
- package/crates/team-agent/src/leader/tests/mod.rs +2 -0
- package/crates/team-agent/src/leader/tests/prompt_contract.rs +268 -0
- package/crates/team-agent/src/leader/types.rs +6 -0
- package/crates/team-agent/src/lib.rs +4 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +472 -388
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +38 -9
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +17 -0
- package/crates/team-agent/src/lifecycle/launch.rs +39 -28
- package/crates/team-agent/src/lifecycle/types.rs +4 -1
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +37 -27
- package/crates/team-agent/src/main.rs +6 -0
- package/crates/team-agent/src/messaging/delivery.rs +50 -1
- package/crates/team-agent/src/messaging/send.rs +10 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +131 -0
- package/crates/team-agent/src/model/spec.rs +24 -12
- package/crates/team-agent/src/state/persist.rs +73 -0
- 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
|
-
|
|
738
|
-
|
|
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!(
|
|
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(
|
|
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!(
|
|
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.
|
|
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.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
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",
|