@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
@@ -0,0 +1,207 @@
1
+ //! One coordinator-owned consumer of the K3 outbox. No CLI send side channel,
2
+ //! implicit business retry, queue flush, or replay of uncertain messages.
3
+ use super::{
4
+ backend::{self, Backend, BackendError},
5
+ forward, framework,
6
+ };
7
+ use serde_json::Value;
8
+ use std::path::Path;
9
+ use std::time::Duration;
10
+ use team_agent_contract::contract::{delivery::InputSurface, probe::*, types::*};
11
+ use team_agent_contract::host::{
12
+ clock::{Clock, RealClock},
13
+ process::verify_native_ancestry,
14
+ };
15
+ use team_agent_contract::kiro::{interaction, KIRO_DESCRIPTOR};
16
+ use team_agent_contract::orchestration::{physical::*, store::*, supervisor::*};
17
+ use team_agent_contract::runtime::probes::*;
18
+
19
+ fn protocol(
20
+ backend: &mut Backend,
21
+ seat: &SeatRecord,
22
+ clock: &RealClock,
23
+ ) -> Result<ProtocolSnapshot, BackendError> {
24
+ let target = seat.physical.as_ref().ok_or(BackendError::Metadata)?;
25
+ let active: Vec<_> = backend
26
+ .store
27
+ .connections(&seat.identity)?
28
+ .into_iter()
29
+ .filter(|record| {
30
+ !record.closed
31
+ && record.native_process == target.process
32
+ && verify_native_ancestry(&record.process, &record.native_process).is_ok()
33
+ })
34
+ .collect();
35
+ if active.len() != 1 {
36
+ return Ok(collect_protocol(
37
+ target,
38
+ &seat.identity.instance,
39
+ &seat.server_key,
40
+ &[],
41
+ clock.now(),
42
+ Duration::from_secs(2),
43
+ ));
44
+ }
45
+ let connection = &active[0];
46
+ let facts = backend
47
+ .store
48
+ .connection_facts(&seat.identity, &connection.connection)?;
49
+ let mut events = Vec::new();
50
+ // T3a is connection state, sampled against BOTH captured process births.
51
+ // Completed server writes are never promoted to client discovery.
52
+ for (fact, protocol) in [
53
+ (
54
+ "initialize_response_written",
55
+ ProtocolFact::InitializeResponseWritten {
56
+ server_instance: connection.connection.clone(),
57
+ },
58
+ ),
59
+ (
60
+ "tools_list_response_written",
61
+ ProtocolFact::ToolsListResponseWritten {
62
+ server_instance: connection.connection.clone(),
63
+ },
64
+ ),
65
+ ] {
66
+ if facts.iter().any(|value| value == fact) {
67
+ events.push(ProtocolEvent {
68
+ scope: target.scope(
69
+ events.len() as u64,
70
+ clock.now(),
71
+ Duration::from_secs(2),
72
+ "live-owned-stdio-state",
73
+ ),
74
+ fact: protocol,
75
+ });
76
+ }
77
+ }
78
+ Ok(collect_protocol(
79
+ target,
80
+ &connection.connection,
81
+ &seat.server_key,
82
+ &events,
83
+ clock.now(),
84
+ Duration::from_secs(2),
85
+ ))
86
+ }
87
+
88
+ fn deliver_one(backend: &mut Backend, seat: &SeatRecord) -> Result<(), BackendError> {
89
+ if matches!(seat.status, SeatStatus::Stopped | SeatStatus::Unknown)
90
+ || !backend.store.has_queued_for(&seat.identity)?
91
+ {
92
+ return Ok(());
93
+ }
94
+ let clock = RealClock::new();
95
+ let adapter = backend::adapter(&backend.binding, &seat.identity)?;
96
+ let hooks = adapter.hooks();
97
+ let operation = OperationId::new(format!(
98
+ "deliver-{}",
99
+ backend
100
+ .store
101
+ .propose_identity(&seat.identity.seat)?
102
+ .instance
103
+ .as_str()
104
+ ))?;
105
+ let mut physical = PhysicalRuntime::new(
106
+ Registration {
107
+ descriptor: &KIRO_DESCRIPTOR,
108
+ hooks: &hooks,
109
+ controls: interaction::CONTROLS,
110
+ },
111
+ backend::settings(&backend.binding),
112
+ operation.clone(),
113
+ &clock,
114
+ )?;
115
+ physical.evidence = backend::policy_evidence(&seat.native, backend.binding.candidate_sha256);
116
+ physical.protocol = Some(protocol(backend, seat, &clock)?);
117
+ let sample = physical.readiness(seat)?;
118
+ if !matches!(sample.pane.outcome, ProbeOutcome::Observed(ref pane) if pane.surface == InputSurface::ComposerReady)
119
+ || !matches!(sample.server.outcome, ProbeOutcome::Observed(ref server) if server.initialize_response_written && server.tools_list_response_written)
120
+ {
121
+ return Ok(());
122
+ }
123
+ backend
124
+ .store
125
+ .begin_observation(&seat.identity, &operation)?;
126
+ // A completed-but-uncertain inspector quarantines the seat, without an
127
+ // orphan lease that would prevent explicit scoped shutdown. No replay or
128
+ // blind Escape to clear an unrelated approval/composer is permitted.
129
+ let binding = match physical.client_binding(seat, &interaction::TOOL_PANEL) {
130
+ Ok(binding) => binding,
131
+ Err(error) => {
132
+ backend.store.fail_observation(&seat.identity, &operation)?;
133
+ return Err(error.into());
134
+ }
135
+ };
136
+ backend
137
+ .store
138
+ .finish_observation(&seat.identity, &operation)?;
139
+ if !matches!(binding.outcome, ProbeOutcome::Observed(_)) {
140
+ return Ok(());
141
+ }
142
+ let mut current_protocol = protocol(backend, seat, &clock)?;
143
+ current_protocol.binding = binding;
144
+ physical.protocol = Some(current_protocol);
145
+ let mut bootstrap = OutboxBootstrap::new(ContractStore::open(
146
+ &backend.binding.transport_root,
147
+ backend.binding.scope.clone(),
148
+ &backend.binding.endpoint,
149
+ )?);
150
+ physical.bootstrap = Some(&mut bootstrap);
151
+ let sample = physical.readiness(seat)?;
152
+ let authorization = DeliveryAuthorization {
153
+ allow_first_business_bootstrap: false,
154
+ require_server_handshake: true,
155
+ channel: Channel::Tmux,
156
+ policy_sha256: interaction::POLICY,
157
+ };
158
+ let _ = team_agent_contract::orchestration::supervisor::tick(
159
+ &mut backend.store,
160
+ &seat.identity,
161
+ &sample,
162
+ &authorization,
163
+ &mut physical,
164
+ )?;
165
+ Ok(())
166
+ }
167
+
168
+ pub fn tick(workspace: &Path, state: &mut Value) -> Result<(), BackendError> {
169
+ if !framework::has_contract(state) {
170
+ return Ok(());
171
+ }
172
+ let team = crate::state::projection::team_state_key(state);
173
+ let mut backend = Backend::open(workspace, &team)?;
174
+ let ids: Vec<_> = state
175
+ .get("agents")
176
+ .and_then(Value::as_object)
177
+ .into_iter()
178
+ .flat_map(|agents| agents.iter())
179
+ .filter(|(_, agent)| framework::is_contract(agent))
180
+ .map(|(id, _)| id.clone())
181
+ .collect();
182
+ let mut failure = None;
183
+ for id in ids {
184
+ let Some(seat) = backend.store.seat(&SeatId::new(&id)?)? else {
185
+ continue;
186
+ };
187
+ if let Err(error) = deliver_one(&mut backend, &seat) {
188
+ failure = Some(error);
189
+ }
190
+ if let Some(agent) = state
191
+ .get_mut("agents")
192
+ .and_then(|agents| agents.get_mut(&id))
193
+ {
194
+ match framework::project_seat(workspace, &team, &id) {
195
+ Ok(projected) => *agent = projected,
196
+ Err(error) => failure = Some(error),
197
+ }
198
+ }
199
+ }
200
+ // One blocked seat must not prevent already committed results from reaching
201
+ // the shared framework task-finalization/leader-presentation path.
202
+ forward::drain(&backend.binding.framework(), &mut backend.store, 32)?;
203
+ match failure {
204
+ Some(error) => Err(error),
205
+ None => Ok(()),
206
+ }
207
+ }
@@ -0,0 +1,30 @@
1
+ //! The sole new-runtime provider registration. This is not an admission claim:
2
+ //! the descriptor's Unverified gates still apply to each requested operation.
3
+ use team_agent_contract::contract::descriptor::ProviderDescriptor;
4
+ use team_agent_contract::kiro::KIRO_DESCRIPTOR;
5
+
6
+ const DESCRIPTORS: &[&ProviderDescriptor] = &[&KIRO_DESCRIPTOR];
7
+
8
+ pub(crate) fn descriptors() -> &'static [&'static ProviderDescriptor] {
9
+ DESCRIPTORS
10
+ }
11
+
12
+ pub fn descriptor(key: &str) -> Option<&'static ProviderDescriptor> {
13
+ DESCRIPTORS.iter().copied().find(|descriptor| {
14
+ descriptor.identity.id == key || descriptor.identity.aliases.contains(&key)
15
+ })
16
+ }
17
+
18
+ /// Recognize a misspelled/case-modified contract declaration so it can fail
19
+ /// explicitly instead of accidentally selecting a legacy default provider.
20
+ pub fn recognizes(key: &str) -> bool {
21
+ let key = key.trim();
22
+ DESCRIPTORS.iter().any(|descriptor| {
23
+ descriptor.identity.id.eq_ignore_ascii_case(key)
24
+ || descriptor
25
+ .identity
26
+ .aliases
27
+ .iter()
28
+ .any(|alias| alias.eq_ignore_ascii_case(key))
29
+ })
30
+ }
@@ -359,6 +359,19 @@ impl Coordinator {
359
359
  let event_log = EventLog::new(self.workspace.as_path());
360
360
  increment_coordinator_tick_iteration_count(&self.workspace);
361
361
 
362
+ #[cfg(unix)]
363
+ if let Err(error) =
364
+ crate::contract_runtime::pump::tick(self.workspace.as_path(), &mut state)
365
+ {
366
+ let _ = event_log.write(
367
+ "contract.tick.failed",
368
+ serde_json::json!({"error":error.to_string()}),
369
+ );
370
+ }
371
+ #[cfg(unix)]
372
+ let contract_only = crate::contract_runtime::framework::only_contract(&state);
373
+ #[cfg(not(unix))]
374
+ let contract_only = false;
362
375
  self.record_step(TickStepGroup::SessionGate, "tmux_session_gate");
363
376
  if let Some(session_name) = state
364
377
  .get("session_name")
@@ -367,7 +380,7 @@ impl Coordinator {
367
380
  .map(str::to_owned)
368
381
  {
369
382
  let session = crate::transport::SessionName::new(&session_name);
370
- if !self.transport.has_session(&session)? {
383
+ if !contract_only && !self.transport.has_session(&session)? {
371
384
  event_log.write(
372
385
  "coordinator.session_missing",
373
386
  serde_json::json!({"session": session_name}),
@@ -564,13 +577,14 @@ impl Coordinator {
564
577
  // Keep the sampled topology guard, but commit only this tick's
565
578
  // observations onto latest so task/note writers cannot be lost.
566
579
  let team_key = crate::state::projection::team_state_key(&state);
567
- crate::state::repository::StateRepository::new(self.workspace.as_path()).commit_observations(
568
- crate::state::repository::StateWriteIntent::CoordinatorTick {
569
- team_key: team_key.as_str(),
570
- },
571
- &before_observation,
572
- &state,
573
- )
580
+ crate::state::repository::StateRepository::new(self.workspace.as_path())
581
+ .commit_observations(
582
+ crate::state::repository::StateWriteIntent::CoordinatorTick {
583
+ team_key: team_key.as_str(),
584
+ },
585
+ &before_observation,
586
+ &state,
587
+ )
574
588
  }
575
589
  };
576
590
  if saved.is_err() {
@@ -1876,6 +1890,10 @@ fn tick_has_work_obligation(store: &crate::message_store::MessageStore) -> bool
1876
1890
  }
1877
1891
 
1878
1892
  fn agent_probe_base_eligible(agent: &Value) -> bool {
1893
+ #[cfg(unix)]
1894
+ if crate::contract_runtime::framework::is_contract(agent) {
1895
+ return false;
1896
+ }
1879
1897
  let status = agent.get("status").and_then(Value::as_str);
1880
1898
  !matches!(
1881
1899
  status,
@@ -81,6 +81,7 @@ pub mod incident;
81
81
  pub mod lease;
82
82
  pub mod owner_bind;
83
83
  pub mod provider_attribution;
84
+ pub mod prompt;
84
85
  pub mod rediscover;
85
86
  pub mod registry;
86
87
  pub mod start;