@team-agent/installer 0.5.113 → 0.5.115
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 +57 -22
- 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 +157 -8
- package/crates/team-agent/src/cli/models.rs +119 -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 +959 -0
- package/crates/team-agent/src/contract_runtime/commands.rs +245 -0
- package/crates/team-agent/src/contract_runtime/config.rs +340 -0
- package/crates/team-agent/src/contract_runtime/config_tests.rs +56 -0
- package/crates/team-agent/src/contract_runtime/discovery.rs +383 -0
- package/crates/team-agent/src/contract_runtime/forward.rs +229 -0
- package/crates/team-agent/src/contract_runtime/framework.rs +294 -0
- package/crates/team-agent/src/contract_runtime/mcp.rs +396 -0
- package/crates/team-agent/src/contract_runtime/mod.rs +16 -0
- package/crates/team-agent/src/contract_runtime/prompt.rs +216 -0
- package/crates/team-agent/src/contract_runtime/pump.rs +269 -0
- package/crates/team-agent/src/contract_runtime/registry.rs +197 -0
- package/crates/team-agent/src/contract_runtime/workspace.rs +160 -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 +353 -21
- 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 +571 -389
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +38 -9
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +15 -0
- package/crates/team-agent/src/lifecycle/launch.rs +45 -28
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +23 -1
- package/crates/team-agent/src/lifecycle/restart/selection.rs +34 -0
- package/crates/team-agent/src/lifecycle/role_config.rs +17 -1
- 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
|
@@ -797,3 +797,91 @@ fn cmd_leader_passthrough_maps_grok_and_cursor_not_claude() {
|
|
|
797
797
|
assert_eq!(leader_passthrough_provider("cursor_agent"), None);
|
|
798
798
|
assert_eq!(leader_passthrough_provider("not-a-passthrough"), None);
|
|
799
799
|
}
|
|
800
|
+
|
|
801
|
+
#[cfg(unix)]
|
|
802
|
+
#[test]
|
|
803
|
+
#[serial_test::serial(env)]
|
|
804
|
+
fn kiro_doctor_inventory_is_read_only_and_does_not_claim_native_readiness() {
|
|
805
|
+
use std::os::unix::fs::PermissionsExt;
|
|
806
|
+
let env = crate::cli::hermetic_test_support::HermeticTestEnv::enter("kiro-inventory");
|
|
807
|
+
let bin = env.workspace("bin");
|
|
808
|
+
let _path = env.with_env("PATH", &bin.to_string_lossy());
|
|
809
|
+
let inventory = provider_doctor_checks();
|
|
810
|
+
assert_eq!(inventory["kiro"]["installed"], false);
|
|
811
|
+
assert_eq!(inventory["codex"]["command"], "codex");
|
|
812
|
+
let launcher = bin.join("kiro-cli");
|
|
813
|
+
std::fs::write(
|
|
814
|
+
&launcher,
|
|
815
|
+
"#!/bin/sh\nprintf called > \"$0.called\"\nexit 0\n",
|
|
816
|
+
)
|
|
817
|
+
.unwrap();
|
|
818
|
+
for (mode, installed) in [(0o600, false), (0o700, true)] {
|
|
819
|
+
std::fs::set_permissions(&launcher, std::fs::Permissions::from_mode(mode)).unwrap();
|
|
820
|
+
assert_eq!(
|
|
821
|
+
provider_doctor_checks()["kiro"],
|
|
822
|
+
json!({
|
|
823
|
+
"auth": "unknown",
|
|
824
|
+
"command": "kiro-cli",
|
|
825
|
+
"installed": installed,
|
|
826
|
+
"version": "unknown",
|
|
827
|
+
"probe_status": "not_run",
|
|
828
|
+
"provider_probe_status": "not_run",
|
|
829
|
+
})
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
assert!(!bin.join("kiro-cli.called").exists());
|
|
833
|
+
assert!(env.registry_entries().is_empty());
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
#[cfg(unix)]
|
|
837
|
+
#[test]
|
|
838
|
+
#[serial_test::serial(env)]
|
|
839
|
+
fn kiro_leader_entry_has_help_and_typed_refusal_without_native_or_fallback_effects() {
|
|
840
|
+
use std::os::unix::fs::PermissionsExt;
|
|
841
|
+
let env = crate::cli::hermetic_test_support::HermeticTestEnv::enter("kiro-leader-gate");
|
|
842
|
+
let cwd = env.workspace("empty");
|
|
843
|
+
let bin = env.workspace("bin");
|
|
844
|
+
for tool in ["kiro-cli", "kiro-cli-chat", "codex", "pi", "tmux"] {
|
|
845
|
+
let path = bin.join(tool);
|
|
846
|
+
std::fs::write(&path, "#!/bin/sh\nprintf called > \"$0.called\"\nexit 0\n").unwrap();
|
|
847
|
+
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700)).unwrap();
|
|
848
|
+
}
|
|
849
|
+
let _path = env.with_env("PATH", &bin.to_string_lossy());
|
|
850
|
+
assert!(!crate::cli::emit::is_leader_passthrough_command("kiro"));
|
|
851
|
+
assert_eq!(leader_passthrough_provider("kiro"), None);
|
|
852
|
+
let help = crate::cli::emit::command_help(Some("kiro"));
|
|
853
|
+
assert!(help.contains("team-agent kiro [--json]"));
|
|
854
|
+
assert!(help.contains("kiro_leader_not_admitted"));
|
|
855
|
+
assert!(crate::cli::emit::default_help().contains("Check Kiro leader launch admission"));
|
|
856
|
+
for alias in ["-h", "--help"] {
|
|
857
|
+
assert_eq!(
|
|
858
|
+
crate::cli::run(&["kiro".into(), alias.into()], &cwd),
|
|
859
|
+
ExitCode::Ok
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
let cases: &[&[&str]] = &[&[], &["--json"], &["--attach-existing", "--confirm"]];
|
|
863
|
+
for values in cases {
|
|
864
|
+
let args: Vec<String> = values.iter().map(|arg| (*arg).into()).collect();
|
|
865
|
+
let result = cmd_kiro_leader(&args);
|
|
866
|
+
assert_eq!(result.exit, ExitCode::Error);
|
|
867
|
+
assert_eq!(result.as_json, values.contains(&"--json"));
|
|
868
|
+
let CmdOutput::Json(value) = result.output else {
|
|
869
|
+
panic!("expected structured capability refusal");
|
|
870
|
+
};
|
|
871
|
+
assert_eq!(value["schema_version"], "leader_launch.v1");
|
|
872
|
+
assert_eq!(value["ok"], false);
|
|
873
|
+
assert_eq!(value["provider"], "kiro");
|
|
874
|
+
assert_eq!(value["capability"], "leader_launch");
|
|
875
|
+
assert_eq!(value["reason"], "kiro_leader_not_admitted");
|
|
876
|
+
let mut argv = vec!["kiro".into()];
|
|
877
|
+
argv.extend(args);
|
|
878
|
+
assert_eq!(crate::cli::run(&argv, &cwd), ExitCode::Error);
|
|
879
|
+
}
|
|
880
|
+
assert_eq!(std::fs::read_dir(&cwd).unwrap().count(), 0);
|
|
881
|
+
assert_eq!(
|
|
882
|
+
std::fs::read_dir(&bin).unwrap().count(),
|
|
883
|
+
5,
|
|
884
|
+
"no tool invoked"
|
|
885
|
+
);
|
|
886
|
+
assert!(env.registry_entries().is_empty());
|
|
887
|
+
}
|
|
@@ -436,6 +436,8 @@ fn leader_attach_command_for_plan_uses_plan_leader_window() {
|
|
|
436
436
|
)),
|
|
437
437
|
argv: Vec::new(),
|
|
438
438
|
provider_argv: Vec::new(),
|
|
439
|
+
leader_prompt: None,
|
|
440
|
+
session_capture: None,
|
|
439
441
|
leader_window: Some(crate::transport::WindowName::new("claude_code")),
|
|
440
442
|
is_external_leader: false,
|
|
441
443
|
leader_env: std::collections::BTreeMap::new(),
|
|
@@ -42,10 +42,16 @@ pub struct IgnoredTeamField {
|
|
|
42
42
|
pub fn read_front_matter(path: &Path) -> Result<(Value, String), ModelError> {
|
|
43
43
|
let text = fs::read_to_string(path)
|
|
44
44
|
.map_err(|e| ModelError::Runtime(format!("{}: {e}", path.display())))?;
|
|
45
|
+
Ok(split_front_matter(&text))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Parse the same captured bytes that a prompt receipt hashes; the existing
|
|
49
|
+
/// path-based compiler keeps its original normalization/plain-text fallback.
|
|
50
|
+
pub(crate) fn split_front_matter(text: &str) -> (Value, String) {
|
|
45
51
|
let text = text.replace("\r\n", "\n").replace('\r', "\n");
|
|
46
52
|
let empty_meta = || Value::Map(Vec::new());
|
|
47
53
|
let Some(rest) = text.strip_prefix("---\n") else {
|
|
48
|
-
return
|
|
54
|
+
return (empty_meta(), text);
|
|
49
55
|
};
|
|
50
56
|
|
|
51
57
|
let mut offset = 0;
|
|
@@ -58,7 +64,7 @@ pub fn read_front_matter(path: &Path) -> Result<(Value, String), ModelError> {
|
|
|
58
64
|
offset += line.len();
|
|
59
65
|
}
|
|
60
66
|
let Some(close) = close else {
|
|
61
|
-
return
|
|
67
|
+
return (empty_meta(), text);
|
|
62
68
|
};
|
|
63
69
|
let raw_meta = &rest[..close];
|
|
64
70
|
let meta = if raw_meta.trim().is_empty() {
|
|
@@ -66,11 +72,11 @@ pub fn read_front_matter(path: &Path) -> Result<(Value, String), ModelError> {
|
|
|
66
72
|
} else {
|
|
67
73
|
match yaml::loads(raw_meta) {
|
|
68
74
|
Ok(meta) if meta.is_map() => meta,
|
|
69
|
-
_ => return
|
|
75
|
+
_ => return (empty_meta(), text),
|
|
70
76
|
}
|
|
71
77
|
};
|
|
72
78
|
let after_marker = &rest[close + 3..];
|
|
73
|
-
|
|
79
|
+
(meta, after_marker.trim_start_matches('\n').to_string())
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
pub fn ignored_owner_team_id_from_team_md(
|
|
@@ -489,6 +495,17 @@ fn compile_role_agent_with_mode(
|
|
|
489
495
|
.filter(|provider| !provider.trim().is_empty())
|
|
490
496
|
.unwrap_or_else(|| "pi".to_string());
|
|
491
497
|
let is_pi = parse_canonical_provider(&provider) == Some(Provider::Pi);
|
|
498
|
+
#[cfg(unix)]
|
|
499
|
+
let contract = crate::contract_runtime::registry::descriptor(&provider);
|
|
500
|
+
#[cfg(unix)]
|
|
501
|
+
let contract_role = contract.is_some();
|
|
502
|
+
#[cfg(not(unix))]
|
|
503
|
+
let contract_role = false;
|
|
504
|
+
#[cfg(unix)]
|
|
505
|
+
let skip_team_effort =
|
|
506
|
+
contract.is_some_and(|descriptor| !descriptor.effort.inherit_team_default);
|
|
507
|
+
#[cfg(not(unix))]
|
|
508
|
+
let skip_team_effort = false;
|
|
492
509
|
validate_pi_role_fields(&meta, role_path, &provider)?;
|
|
493
510
|
let model = string_field(&meta, "model")
|
|
494
511
|
.filter(|value| !value.trim().is_empty())
|
|
@@ -567,7 +584,7 @@ fn compile_role_agent_with_mode(
|
|
|
567
584
|
Some(raw) if !raw.trim().is_empty() => ProviderEffort::parse(raw.trim()),
|
|
568
585
|
_ => None,
|
|
569
586
|
};
|
|
570
|
-
let resolved_effort = if is_pi {
|
|
587
|
+
let resolved_effort = if is_pi || skip_team_effort {
|
|
571
588
|
role_effort
|
|
572
589
|
} else {
|
|
573
590
|
role_effort.or(team_effort)
|
|
@@ -582,13 +599,30 @@ fn compile_role_agent_with_mode(
|
|
|
582
599
|
_ => None,
|
|
583
600
|
})
|
|
584
601
|
.unwrap_or("");
|
|
585
|
-
|
|
586
|
-
if let
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
602
|
+
#[cfg(unix)]
|
|
603
|
+
if let Some(descriptor) = contract {
|
|
604
|
+
use team_agent_contract::contract::descriptor::{Effort, EffortAdmission};
|
|
605
|
+
let native_effort = Effort::parse(effort.as_str())
|
|
606
|
+
.map_err(|error| ModelError::Validation(error.to_string()))?;
|
|
607
|
+
if let EffortAdmission::Reject(reason) =
|
|
608
|
+
descriptor.effort.admission[native_effort.index()]
|
|
609
|
+
{
|
|
610
|
+
return Err(ModelError::Validation(format!(
|
|
611
|
+
"{}: {}",
|
|
612
|
+
role_path.display(),
|
|
613
|
+
reason.message
|
|
614
|
+
)));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if !contract_role {
|
|
618
|
+
let provider_enum = parse_canonical_provider(provider_str).unwrap_or(Provider::Codex);
|
|
619
|
+
if let Err(reason) = effort.resolve_for_provider(provider_enum) {
|
|
620
|
+
return Err(ModelError::Validation(format!(
|
|
621
|
+
"{}: {reason} (effort: {}; provider: {provider_str})",
|
|
622
|
+
role_path.display(),
|
|
623
|
+
effort.as_str()
|
|
624
|
+
)));
|
|
625
|
+
}
|
|
592
626
|
}
|
|
593
627
|
agent_items.push(("effort", Value::Str(effort.as_str().to_string())));
|
|
594
628
|
}
|
|
@@ -712,12 +746,17 @@ mod pi_preflight_tests {
|
|
|
712
746
|
|
|
713
747
|
#[test]
|
|
714
748
|
fn omitted_qualified_and_non_pi_do_not_discover() {
|
|
715
|
-
for meta in [
|
|
749
|
+
for meta in [
|
|
750
|
+
role("pi", None),
|
|
751
|
+
role("pi", Some("openai/gpt-5")),
|
|
752
|
+
role("codex", Some("gpt-5")),
|
|
753
|
+
] {
|
|
716
754
|
let calls = Cell::new(0);
|
|
717
755
|
assert!(preflight_pi_role_model_with(&meta, |_| {
|
|
718
756
|
calls.set(calls.get() + 1);
|
|
719
757
|
Ok(vec![])
|
|
720
|
-
})
|
|
758
|
+
})
|
|
759
|
+
.is_ok());
|
|
721
760
|
assert_eq!(calls.get(), 0);
|
|
722
761
|
}
|
|
723
762
|
}
|
|
@@ -728,12 +767,21 @@ mod pi_preflight_tests {
|
|
|
728
767
|
let error = preflight_pi_role_model_with(&role("pi", Some("gpt-5.6-sol")), |requested| {
|
|
729
768
|
calls.set(calls.get() + 1);
|
|
730
769
|
assert_eq!(requested, "gpt-5.6-sol");
|
|
731
|
-
Ok(vec![
|
|
732
|
-
|
|
770
|
+
Ok(vec![
|
|
771
|
+
"openai-codex/gpt-5.6-sol".into(),
|
|
772
|
+
"azure/gpt-5.6-sol".into(),
|
|
773
|
+
])
|
|
774
|
+
})
|
|
775
|
+
.expect_err("unqualified model must fail closed");
|
|
733
776
|
assert_eq!(calls.get(), 1);
|
|
734
|
-
assert_eq!(
|
|
777
|
+
assert_eq!(
|
|
778
|
+
error.candidates,
|
|
779
|
+
vec!["openai-codex/gpt-5.6-sol", "azure/gpt-5.6-sol"]
|
|
780
|
+
);
|
|
735
781
|
assert!(!error.not_ready);
|
|
736
|
-
assert!(error
|
|
782
|
+
assert!(error
|
|
783
|
+
.action
|
|
784
|
+
.contains("team-agent models --provider pi --search gpt-5.6-sol"));
|
|
737
785
|
}
|
|
738
786
|
|
|
739
787
|
#[test]
|