@team-agent/installer 0.5.14 → 0.5.15

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
@@ -575,7 +575,7 @@ dependencies = [
575
575
 
576
576
  [[package]]
577
577
  name = "team-agent"
578
- version = "0.5.14"
578
+ version = "0.5.15"
579
579
  dependencies = [
580
580
  "anyhow",
581
581
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.14"
12
+ version = "0.5.15"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -255,6 +255,7 @@ pub(crate) fn start_agent_at_paths(
255
255
  Some(&safety),
256
256
  layout_placement.as_ref(),
257
257
  None,
258
+ None,
258
259
  Some(resolved_team_key.as_str()),
259
260
  )?;
260
261
  verify_spawned_pane_matches_target(
@@ -26,6 +26,7 @@ pub(super) fn spawn_agent_window(
26
26
  safety: Option<&DangerousApproval>,
27
27
  layout_placement: Option<&crate::lifecycle::launch::LayoutPlacement>,
28
28
  spawn_cwd_override: Option<&Path>,
29
+ tmux_endpoint_source: Option<&str>,
29
30
  // Issue 2 (Round 3b gate review §6): explicit owner_team_id override.
30
31
  // When `Some`, callers (restart/rebuild.rs, restart/agent.rs) thread the
31
32
  // resolved `selected.team_key` through here so the worker's MCP env /
@@ -205,6 +206,7 @@ pub(super) fn spawn_agent_window(
205
206
  let tmux_start_mode_pre_spawn =
206
207
  predict_tmux_start_mode(layout_placement, into_existing_session);
207
208
  let spawn_epoch = state_spawn_epoch_for_agent(workspace, agent_id);
209
+ let tmux_endpoint = transport.tmux_endpoint();
208
210
  let event_log = crate::event_log::EventLog::new(workspace);
209
211
  let _ = event_log.write(
210
212
  "provider.worker.spawn_argv",
@@ -220,6 +222,8 @@ pub(super) fn spawn_agent_window(
220
222
  "tmux_start_mode": tmux_start_mode_pre_spawn,
221
223
  "spawn_epoch": spawn_epoch,
222
224
  "source": "restart",
225
+ "tmux_endpoint": tmux_endpoint,
226
+ "tmux_endpoint_source": tmux_endpoint_source.unwrap_or("transport"),
223
227
  }),
224
228
  );
225
229
  }
@@ -564,6 +568,27 @@ pub(crate) fn lifecycle_worker_transport_for_selected_state(
564
568
  .map_err(|e| LifecycleError::TeamSelect(e.to_string()))
565
569
  }
566
570
 
571
+ pub(super) fn lifecycle_worker_tmux_backend_selection_for_state(
572
+ run_workspace: &Path,
573
+ state: &serde_json::Value,
574
+ ) -> Result<crate::tmux_backend::RuntimeTmuxBackendSelection, LifecycleError> {
575
+ if let Some(kind) = state.pointer("/transport/kind").and_then(|v| v.as_str()) {
576
+ if kind.eq_ignore_ascii_case("conpty") {
577
+ return Err(LifecycleError::TeamSelect(format!(
578
+ "backend_kind_mismatch: state.transport.kind={kind:?} but the legacy \
579
+ tmux-typed lifecycle resolver was invoked; caller must migrate to \
580
+ `lifecycle_worker_transport_for_selected_state` (Phase 1d Batch 2/3)"
581
+ )));
582
+ }
583
+ }
584
+ Ok(
585
+ crate::tmux_backend::tmux_backend_for_runtime_state_or_workspace(
586
+ run_workspace,
587
+ Some(state),
588
+ ),
589
+ )
590
+ }
591
+
567
592
  pub(super) fn lifecycle_worker_tmux_backend_for_state(
568
593
  run_workspace: &Path,
569
594
  state: &serde_json::Value,
@@ -23,16 +23,51 @@ pub fn restart_with_session_convergence_deadline(
23
23
  team: Option<&str>,
24
24
  session_converge_deadline_ms: Option<u64>,
25
25
  ) -> Result<RestartReport, LifecycleError> {
26
- let paths = lifecycle_paths(workspace, team)?;
27
- let transport = lifecycle_worker_tmux_backend_for_selected_state(&paths.run_workspace, team)?;
28
- restart_with_transport_with_session_convergence_deadline(
29
- workspace,
26
+ let context = resolve_restart_context(workspace, team)?;
27
+ restart_with_selected_team_and_transport(
28
+ context.selected,
30
29
  allow_fresh,
31
- team,
32
- &transport,
30
+ &context.transport,
33
31
  session_converge_deadline_ms,
34
32
  None,
33
+ Some(context.tmux_endpoint_source),
34
+ )
35
+ }
36
+
37
+ struct ResolvedRestartContext {
38
+ selected: crate::state::selector::SelectedTeam,
39
+ transport: crate::tmux_backend::TmuxBackend,
40
+ tmux_endpoint_source: &'static str,
41
+ }
42
+
43
+ fn resolve_restart_context(
44
+ workspace: &Path,
45
+ team: Option<&str>,
46
+ ) -> Result<ResolvedRestartContext, LifecycleError> {
47
+ let resolved_ws = crate::model::paths::canonical_run_workspace(workspace)
48
+ .map_err(|e| LifecycleError::StatePersist(e.to_string()))?;
49
+ if crate::lifecycle::restart::input_has_no_local_team_context(&resolved_ws) {
50
+ return Err(LifecycleError::TeamSelect(format!(
51
+ "active team spec not found: input_workspace={} expected_runtime_dir={}",
52
+ workspace.display(),
53
+ crate::model::paths::runtime_dir(&resolved_ws).display()
54
+ )));
55
+ }
56
+ let selected = crate::state::selector::resolve_active_team(
57
+ workspace,
58
+ team,
59
+ crate::state::selector::SelectorMode::RequireSpec,
35
60
  )
61
+ .map_err(|e| LifecycleError::TeamSelect(e.to_string()))?;
62
+ let transport_selection = lifecycle_worker_tmux_backend_selection_for_state(
63
+ &selected.run_workspace,
64
+ &selected.state,
65
+ )?;
66
+ Ok(ResolvedRestartContext {
67
+ selected,
68
+ transport: transport_selection.backend,
69
+ tmux_endpoint_source: transport_selection.tmux_endpoint_source.as_str(),
70
+ })
36
71
  }
37
72
 
38
73
  /// `restart` with an injected transport (tests: recording mock; prod: real TmuxBackend). The Route-B
@@ -129,6 +164,24 @@ pub fn restart_with_transport_with_session_convergence_deadline(
129
164
  expected.display()
130
165
  )));
131
166
  }
167
+ restart_with_selected_team_and_transport(
168
+ selected,
169
+ allow_fresh,
170
+ transport,
171
+ session_converge_deadline_ms,
172
+ readiness_deadline_ms,
173
+ None,
174
+ )
175
+ }
176
+
177
+ fn restart_with_selected_team_and_transport(
178
+ selected: crate::state::selector::SelectedTeam,
179
+ allow_fresh: bool,
180
+ transport: &dyn crate::transport::Transport,
181
+ session_converge_deadline_ms: Option<u64>,
182
+ readiness_deadline_ms: Option<u64>,
183
+ tmux_endpoint_source: Option<&str>,
184
+ ) -> Result<RestartReport, LifecycleError> {
132
185
  let lifecycle_lock = acquire_agent_lifecycle_lock(LifecycleLockRequest {
133
186
  workspace: &selected.run_workspace,
134
187
  operation: "restart",
@@ -381,6 +434,13 @@ pub fn restart_with_transport_with_session_convergence_deadline(
381
434
  &raw_agent,
382
435
  );
383
436
  if has_endpoint_convergence_marker(&state) && is_fake_model_harness_agent(&agent) {
437
+ write_fake_harness_spawn_argv_event(
438
+ &selected.run_workspace,
439
+ decision,
440
+ &agent,
441
+ transport,
442
+ tmux_endpoint_source,
443
+ );
384
444
  mark_fake_harness_agent_respawned(
385
445
  &mut state,
386
446
  &decision.agent_id,
@@ -438,6 +498,7 @@ pub fn restart_with_transport_with_session_convergence_deadline(
438
498
  Some(&safety),
439
499
  layout_placement.as_ref(),
440
500
  None,
501
+ tmux_endpoint_source,
441
502
  // Issue 2 (Round 3b gate review §6): thread the resolved
442
503
  // selected.team_key so the worker MCP env carries the right
443
504
  // owner_team_id even when top-level active_team_key is stale.
@@ -783,7 +844,14 @@ pub fn restart_with_transport_with_session_convergence_deadline(
783
844
  restart_readiness_poll_interval(),
784
845
  )?;
785
846
  let attach_commands =
786
- crate::tmux_backend::attach_command_for_session(&selected.run_workspace, &session_name)
847
+ crate::tmux_backend::attach_command_for_transport_session(transport, &session_name)
848
+ .or_else(|| {
849
+ crate::tmux_backend::attach_command_for_runtime_state_session_or_workspace(
850
+ &selected.run_workspace,
851
+ Some(&state),
852
+ &session_name,
853
+ )
854
+ })
787
855
  .into_iter()
788
856
  .collect::<Vec<_>>();
789
857
  let mut next_actions = Vec::new();
@@ -1719,6 +1787,29 @@ fn mark_fake_harness_agent_respawned(
1719
1787
  agent.insert("owner_team_id".to_string(), serde_json::json!(team_key));
1720
1788
  }
1721
1789
 
1790
+ fn write_fake_harness_spawn_argv_event(
1791
+ workspace: &Path,
1792
+ decision: &RestartedAgent,
1793
+ agent: &serde_json::Value,
1794
+ transport: &dyn crate::transport::Transport,
1795
+ tmux_endpoint_source: Option<&str>,
1796
+ ) {
1797
+ let _ = crate::event_log::EventLog::new(workspace).write(
1798
+ "provider.worker.spawn_argv",
1799
+ serde_json::json!({
1800
+ "agent_id": decision.agent_id.as_str(),
1801
+ "provider": agent_provider(agent),
1802
+ "argv": [],
1803
+ "session_id_in_argv": null,
1804
+ "expected_session_id": decision.session_id.as_ref().map(|s| s.as_str()),
1805
+ "tmux_start_mode": "fake_harness",
1806
+ "source": "restart",
1807
+ "tmux_endpoint": transport.tmux_endpoint(),
1808
+ "tmux_endpoint_source": tmux_endpoint_source.unwrap_or("transport"),
1809
+ }),
1810
+ );
1811
+ }
1812
+
1722
1813
  fn restart_failed_agent(
1723
1814
  decision: &RestartedAgent,
1724
1815
  phase: impl Into<String>,
@@ -524,7 +524,7 @@ fn normalize_string(text: String, ctx: &mut NormalizeCtx, key: Option<&str>) ->
524
524
  if key_is_timestamp(key) {
525
525
  return json!("<TS>");
526
526
  }
527
- if key.contains("endpoint") {
527
+ if key.contains("endpoint") && value_looks_like_endpoint_path(&text) {
528
528
  return json!("<SOCKET>");
529
529
  }
530
530
  if key_is_id(key, &text) {
@@ -557,6 +557,13 @@ fn normalize_path_string(text: &str, ctx: &NormalizeCtx) -> String {
557
557
  normalize_socket_token(&out)
558
558
  }
559
559
 
560
+ fn value_looks_like_endpoint_path(text: &str) -> bool {
561
+ text.starts_with('/')
562
+ || text.starts_with("ta-")
563
+ || text.contains("/tmux-")
564
+ || text.contains("tmux-")
565
+ }
566
+
560
567
  fn normalize_team_agent_binary_path(text: &str) -> String {
561
568
  let mut out = text.to_string();
562
569
  // 0.5.0 hermetic 教训「环境路径类 token 化」的直接延伸
@@ -566,6 +566,14 @@ pub(crate) fn attach_command_for_session(
566
566
  ))
567
567
  }
568
568
 
569
+ pub(crate) fn attach_command_for_transport_session(
570
+ transport: &dyn crate::transport::Transport,
571
+ session_name: &SessionName,
572
+ ) -> Option<String> {
573
+ let endpoint = transport.tmux_endpoint()?;
574
+ Some(attach_command_for_endpoint_session(&endpoint, session_name))
575
+ }
576
+
569
577
  /// Bug #7 (prerelease 0.4.0 gate review §6): when the runtime state carries a
570
578
  /// persisted `tmux_endpoint` / `tmux_socket` (e.g. `/private/tmp/tmux-501/default`),
571
579
  /// the attach command MUST point at THAT endpoint, not the workspace-hash
@@ -591,6 +599,26 @@ pub(crate) fn attach_command_for_runtime_state_or_workspace(
591
599
  attach_command_for_workspace(workspace, session_name, window_name)
592
600
  }
593
601
 
602
+ pub(crate) fn attach_command_for_runtime_state_session_or_workspace(
603
+ workspace: &Path,
604
+ state: Option<&serde_json::Value>,
605
+ session_name: &SessionName,
606
+ ) -> Option<String> {
607
+ if let Some((endpoint, _source)) = runtime_tmux_endpoint_from_state(state) {
608
+ return Some(attach_command_for_endpoint_session(endpoint, session_name));
609
+ }
610
+ attach_command_for_session(workspace, session_name)
611
+ }
612
+
613
+ fn attach_command_for_endpoint_session(endpoint: &str, session_name: &SessionName) -> String {
614
+ let flag = if Path::new(endpoint).is_absolute() {
615
+ "-S"
616
+ } else {
617
+ "-L"
618
+ };
619
+ format!("tmux {flag} {endpoint} attach -t {}", session_name.as_str())
620
+ }
621
+
594
622
  pub(crate) fn attach_commands_for_windows<'a>(
595
623
  workspace: &Path,
596
624
  session_name: &SessionName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.14",
3
+ "version": "0.5.15",
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.14",
24
- "@team-agent/cli-darwin-x64": "0.5.14",
25
- "@team-agent/cli-linux-x64": "0.5.14"
23
+ "@team-agent/cli-darwin-arm64": "0.5.15",
24
+ "@team-agent/cli-darwin-x64": "0.5.15",
25
+ "@team-agent/cli-linux-x64": "0.5.15"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",