@team-agent/installer 0.5.117 → 0.5.119

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 CHANGED
@@ -727,7 +727,7 @@ dependencies = [
727
727
 
728
728
  [[package]]
729
729
  name = "team-agent"
730
- version = "0.5.117"
730
+ version = "0.5.119"
731
731
  dependencies = [
732
732
  "anyhow",
733
733
  "chrono",
package/Cargo.toml CHANGED
@@ -11,7 +11,7 @@ exclude = ["crates/team-agent-contract"]
11
11
 
12
12
  [workspace.package]
13
13
  edition = "2021"
14
- version = "0.5.117"
14
+ version = "0.5.119"
15
15
  license = "AGPL-3.0"
16
16
  rust-version = "1.95"
17
17
 
@@ -424,6 +424,26 @@ pub mod lifecycle_port {
424
424
  });
425
425
  if let Some(object) = value.as_object_mut() {
426
426
  object.extend(facts);
427
+ // Only a plain Pi entry can be retried verbatim with this command.
428
+ // Never drop explicit attach/external intent or provider arguments,
429
+ // clear the caller's environment, or adopt the unverified pane.
430
+ if cfg!(unix)
431
+ && provider == Provider::Pi
432
+ && attach == &LeaderLauncherArgs::default()
433
+ {
434
+ let command = "env -u TMUX -u TMUX_PANE team-agent pi";
435
+ object.insert("recovery_command".to_string(), json!(command));
436
+ object.insert(
437
+ ACTION_FIELD.to_string(),
438
+ json!(format!(
439
+ "The inherited TMUX/TMUX_PANE could not be authorized for \
440
+ requested_workspace; this is not an empty-directory error. \
441
+ To explicitly retry from requested_workspace, run `{command}`. \
442
+ This removes the inherited variables only for the new process \
443
+ and does not detach or modify your current tmux pane. {action}"
444
+ )),
445
+ );
446
+ }
427
447
  }
428
448
  value
429
449
  }
@@ -379,9 +379,10 @@ impl MessageStore {
379
379
  status: &str,
380
380
  error: Option<&str>,
381
381
  ) -> Result<(), MessageStoreError> {
382
- let conn = crate::db::schema::open_db(&self.path)?;
382
+ let mut conn = crate::db::schema::open_db(&self.path)?;
383
+ let tx = conn.transaction()?;
383
384
  let now = now_ts();
384
- let changed = conn.execute(
385
+ let changed = tx.execute(
385
386
  "update messages
386
387
  set status = case
387
388
  when status = 'acknowledged'
@@ -407,7 +408,7 @@ impl MessageStore {
407
408
  params![message_id, status, now, error],
408
409
  )?;
409
410
  if changed == 0 {
410
- let prior: Option<String> = conn
411
+ let prior: Option<String> = tx
411
412
  .query_row(
412
413
  "select status from messages where message_id = ?1",
413
414
  params![message_id],
@@ -449,6 +450,12 @@ impl MessageStore {
449
450
  )?;
450
451
  return Ok(());
451
452
  }
453
+ if status == "submitted_unverified" {
454
+ // Uncertainty and its independent safety net are one durable transition.
455
+ // Registration never depends on provider, parser, binding or paste proof.
456
+ crate::messaging::enter_rescue::schedule_in_tx(&tx, message_id, chrono::Utc::now())?;
457
+ }
458
+ tx.commit()?;
452
459
  Ok(())
453
460
  }
454
461
 
@@ -48,9 +48,6 @@ enum ManagedClientAttachMode {
48
48
  SwitchClient,
49
49
  }
50
50
 
51
- const DIFFERENT_TMUX_SERVER_PREFIX: &str =
52
- "managed launcher refuses a different ambient tmux server";
53
-
54
51
  impl PreparedLeaderStart {
55
52
  pub(crate) fn plan(&self) -> &LeaderStartPlan {
56
53
  &self.plan
@@ -141,8 +138,6 @@ pub(crate) fn prepare_leader_start_with_nested_attach(
141
138
  let (ambient_authority, managed_client_attach_mode, managed_exec_provider) =
142
139
  if explicit_external_path || state_external_path {
143
140
  (ambient_pane_authority_preflight(workspace)?, None, false)
144
- } else if workspace_state_is_managed_provider_reentry(workspace) {
145
- (ambient_pane_authority_preflight(workspace)?, None, true)
146
141
  } else {
147
142
  managed_launcher_ambient_route(
148
143
  provider,
@@ -159,7 +154,7 @@ pub(crate) fn prepare_leader_start_with_nested_attach(
159
154
  confirm_attach,
160
155
  attach_session,
161
156
  external_leader,
162
- std::env::var_os("TMUX").is_some(),
157
+ ambient_authority.is_some(),
163
158
  managed_client_attach_mode,
164
159
  managed_exec_provider,
165
160
  allow_nested_attach,
@@ -613,64 +608,49 @@ fn managed_launcher_ambient_route(
613
608
  ),
614
609
  PrepareLeaderStartError,
615
610
  > {
616
- let Some(tmux) = std::env::var_os("TMUX") else {
617
- return Ok((
618
- None,
619
- Some(ManagedClientAttachMode::AttachSession),
620
- false,
621
- ));
611
+ let isolated = || (None, Some(ManagedClientAttachMode::AttachSession), false);
612
+ let authority = match ambient_pane_authority_preflight(workspace) {
613
+ Ok(Some(authority)) => authority,
614
+ Ok(None) => return Ok(isolated()),
615
+ Err(PrepareLeaderStartError::PaneAuthorityRefused(_)) if !allow_nested_attach => {
616
+ // An inherited tuple cannot authorize adoption, but an ordinary
617
+ // managed launch can still create its own workspace pane. Keep
618
+ // explicit external/attach and nested-attach intent fail-closed.
619
+ return Ok(isolated());
620
+ }
621
+ Err(error) => return Err(error),
622
622
  };
623
- let tmux = tmux.into_string().map_err(|_| {
624
- PrepareLeaderStartError::PaneAuthorityRefused(ambient_tmux_endpoint_refusal(
625
- workspace,
626
- pane_refusal::AmbientTmuxEndpointUnavailableCause::TmuxValueNotUnicode,
627
- ))
628
- })?;
629
- let observed_endpoint = validated_ambient_tmux_endpoint(workspace, &tmux)
630
- .map_err(PrepareLeaderStartError::PaneAuthorityRefused)?;
631
- if provider == Provider::Pi && provider_args.is_empty() && !allow_nested_attach {
632
- // Pi's zero-argument managed entry already owns this verified pane as its
633
- // user-facing terminal. Replacing the current process is safe on either
634
- // the workspace server or another server; switching/attaching would move
635
- // the user away from the positively verified workspace pane.
636
- let authority = verified_ambient_pane_authority(workspace, &tmux)
637
- .map_err(PrepareLeaderStartError::PaneAuthorityRefused)?;
623
+ if workspace_state_is_managed_provider_reentry(workspace)
624
+ || (provider == Provider::Pi && provider_args.is_empty() && !allow_nested_attach)
625
+ {
626
+ // Only verified current-pane authority permits replacing the caller.
638
627
  return Ok((Some(authority), None, true));
639
628
  }
640
- let target_socket_name = TmuxBackend::for_workspace(workspace)
641
- .tmux_endpoint()
642
- .ok_or_else(|| LeaderError::Start("workspace tmux endpoint missing".to_string()))?;
643
629
  let target_endpoint = crate::tmux_backend::socket_path_for_workspace(workspace);
644
630
  let same_server = target_endpoint.as_ref().is_some_and(|target| {
645
- let observed = Path::new(&observed_endpoint)
631
+ let observed = Path::new(&authority.endpoint)
646
632
  .canonicalize()
647
- .unwrap_or_else(|_| PathBuf::from(&observed_endpoint));
633
+ .unwrap_or_else(|_| PathBuf::from(&authority.endpoint));
648
634
  let target = target.canonicalize().unwrap_or_else(|_| target.clone());
649
635
  observed == target
650
636
  });
651
637
  if same_server {
652
- let authority = verified_ambient_pane_authority(workspace, &tmux)
653
- .map_err(PrepareLeaderStartError::PaneAuthorityRefused)?;
654
638
  return Ok((
655
639
  Some(authority),
656
640
  Some(ManagedClientAttachMode::SwitchClient),
657
641
  false,
658
642
  ));
659
643
  }
660
- if !allow_nested_attach {
661
- return Err(LeaderError::Validation(format!(
662
- "{DIFFERENT_TMUX_SERVER_PREFIX}: observed_endpoint={observed_endpoint}; \
663
- requested_workspace_socket={target_socket_name}"
664
- ))
665
- .into());
644
+ if allow_nested_attach {
645
+ return Ok((
646
+ Some(authority),
647
+ Some(ManagedClientAttachMode::AttachSession),
648
+ false,
649
+ ));
666
650
  }
667
- let authority = verified_ambient_pane_authority(workspace, &tmux)
668
- .map_err(PrepareLeaderStartError::PaneAuthorityRefused)?;
669
- Ok((
670
- Some(authority),
671
- Some(ManagedClientAttachMode::AttachSession),
672
- false,
673
- ))
651
+ // Do not switch/adopt the unrelated server. The existing managed attach
652
+ // child clears TMUX/TMUX_PANE without changing the caller's environment.
653
+ Ok(isolated())
674
654
  }
675
655
 
676
656
  fn validated_ambient_tmux_endpoint(
@@ -4,7 +4,7 @@ use std::time::Duration;
4
4
 
5
5
  use crate::lifecycle::launch::pi_mcp::pi_seat_paths;
6
6
  use crate::messaging::delivery::{
7
- paste_to_submit_floor_for_recipient, recipient_allows_explicit_queue_flush, recipient_is_busy,
7
+ paste_to_submit_floor_for_recipient, recipient_allows_explicit_queue_flush,
8
8
  recipient_requires_single_enter,
9
9
  };
10
10
  use crate::model::enums::{Provider, ProviderEffort};
@@ -186,17 +186,12 @@ fn pi_delivery_submits_one_enter_and_never_flushes_or_retries() {
186
186
  paste_to_submit_floor_for_recipient(&idle, "worker-a"),
187
187
  Duration::ZERO
188
188
  );
189
- assert!(!recipient_is_busy(&idle, "worker-a"));
190
-
191
189
  let busy = serde_json::json!({
192
190
  "agents": {
193
191
  "worker-a": {"provider": "pi", "status": "busy"}
194
192
  }
195
193
  });
196
- assert!(
197
- recipient_is_busy(&busy, "worker-a"),
198
- "known busy must take the existing send.deferred_busy path before paste"
199
- );
194
+ // Working native CLIs queue the same single-Enter input; no idle admission.
200
195
  assert!(recipient_requires_single_enter(&busy, "worker-a"));
201
196
  assert!(!recipient_allows_explicit_queue_flush(&busy, "worker-a"));
202
197
  }