@team-agent/installer 0.5.66 → 0.5.68

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 (164) hide show
  1. package/Cargo.lock +8 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/Cargo.toml +1 -0
  4. package/crates/team-agent/src/cli/adapters.rs +5 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +82 -0
  6. package/crates/team-agent/src/cli/emit.rs +3 -3
  7. package/crates/team-agent/src/cli/grok_slot.rs +299 -0
  8. package/crates/team-agent/src/cli/leader.rs +21 -7
  9. package/crates/team-agent/src/cli/leaders.rs +125 -1
  10. package/crates/team-agent/src/cli/mod.rs +20 -0
  11. package/crates/team-agent/src/cli/send/presentation.rs +7 -1
  12. package/crates/team-agent/src/cli/spec.rs +2 -0
  13. package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
  14. package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
  15. package/crates/team-agent/src/cli/tests/base.rs +26 -3
  16. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
  17. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
  18. package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
  19. package/crates/team-agent/src/communication_mode/mod.rs +6 -4
  20. package/crates/team-agent/src/compiler.rs +59 -0
  21. package/crates/team-agent/src/coordinator/backoff.rs +55 -0
  22. package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
  23. package/crates/team-agent/src/coordinator/health.rs +173 -0
  24. package/crates/team-agent/src/coordinator/mod.rs +31 -0
  25. package/crates/team-agent/src/coordinator/orphan.rs +31 -0
  26. package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
  27. package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
  28. package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
  29. package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
  30. package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
  31. package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
  32. package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
  33. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
  34. package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
  35. package/crates/team-agent/src/coordinator/tick.rs +133 -22
  36. package/crates/team-agent/src/coordinator/types.rs +49 -0
  37. package/crates/team-agent/src/db/message_store.rs +39 -5
  38. package/crates/team-agent/src/layout/worker_env.rs +20 -3
  39. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  40. package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
  41. package/crates/team-agent/src/leader/registry.rs +65 -0
  42. package/crates/team-agent/src/leader/start.rs +920 -63
  43. package/crates/team-agent/src/lifecycle/display.rs +56 -0
  44. package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
  45. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -12
  46. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +62 -0
  47. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +59 -0
  48. package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
  49. package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
  50. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
  51. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -456
  52. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
  53. package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
  54. package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
  55. package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
  56. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
  57. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
  58. package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
  59. package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
  60. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
  61. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
  62. package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
  63. package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
  64. package/crates/team-agent/src/lifecycle/launch/spawn.rs +62 -2
  65. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +139 -0
  66. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -0
  67. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
  68. package/crates/team-agent/src/lifecycle/launch.rs +99 -29
  69. package/crates/team-agent/src/lifecycle/lock.rs +42 -1
  70. package/crates/team-agent/src/lifecycle/mod.rs +11 -0
  71. package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
  72. package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
  73. package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
  74. package/crates/team-agent/src/lifecycle/restart/agent.rs +124 -0
  75. package/crates/team-agent/src/lifecycle/restart/common.rs +369 -11
  76. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
  77. package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
  78. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +106 -0
  79. package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
  80. package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
  81. package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
  82. package/crates/team-agent/src/lifecycle/restart.rs +29 -0
  83. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +2 -3
  84. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
  85. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +150 -157
  86. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +2 -2
  87. package/crates/team-agent/src/lifecycle/tests/core.rs +4 -0
  88. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
  89. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
  90. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
  91. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
  92. package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
  93. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
  94. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
  95. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
  96. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
  97. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +63 -38
  98. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -2
  99. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +16 -8
  100. package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
  101. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +20 -19
  102. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +97 -61
  103. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +2 -0
  104. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +40 -7
  105. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +59 -1
  106. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
  107. package/crates/team-agent/src/lifecycle/tests.rs +23 -13
  108. package/crates/team-agent/src/lifecycle/types.rs +61 -0
  109. package/crates/team-agent/src/lifecycle/worker_command_context.rs +85 -11
  110. package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
  111. package/crates/team-agent/src/mcp_server/tests.rs +196 -2
  112. package/crates/team-agent/src/messaging/delivery.rs +405 -40
  113. package/crates/team-agent/src/messaging/helpers.rs +2 -0
  114. package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
  115. package/crates/team-agent/src/messaging/results.rs +4 -0
  116. package/crates/team-agent/src/messaging/send.rs +34 -0
  117. package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
  118. package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
  119. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
  120. package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
  121. package/crates/team-agent/src/messaging/types.rs +4 -1
  122. package/crates/team-agent/src/model/enums.rs +14 -5
  123. package/crates/team-agent/src/model/permissions.rs +3 -0
  124. package/crates/team-agent/src/os_probe.rs +73 -2
  125. package/crates/team-agent/src/provider/adapter.rs +231 -4
  126. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
  127. package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
  128. package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
  129. package/crates/team-agent/src/provider/bypass_flags.rs +46 -2
  130. package/crates/team-agent/src/provider/classify.rs +4 -2
  131. package/crates/team-agent/src/provider/faults.rs +2 -1
  132. package/crates/team-agent/src/provider/mod.rs +11 -0
  133. package/crates/team-agent/src/provider/session/capture.rs +158 -20
  134. package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
  135. package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
  136. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
  137. package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
  138. package/crates/team-agent/src/provider/session/mod.rs +18 -0
  139. package/crates/team-agent/src/provider/session/resume.rs +57 -0
  140. package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
  141. package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
  142. package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
  143. package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
  144. package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
  145. package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
  146. package/crates/team-agent/src/provider/session_scan.rs +8 -0
  147. package/crates/team-agent/src/provider/submit_now.rs +94 -0
  148. package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
  149. package/crates/team-agent/src/provider/types.rs +4 -2
  150. package/crates/team-agent/src/provider/wire.rs +23 -1
  151. package/crates/team-agent/src/state/persist.rs +301 -8
  152. package/crates/team-agent/src/state/repository.rs +5 -0
  153. package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
  154. package/crates/team-agent/src/tmux_backend.rs +1064 -75
  155. package/crates/team-agent/src/transport/tests/wire.rs +28 -2
  156. package/crates/team-agent/src/transport.rs +248 -1
  157. package/npm/install.mjs +129 -73
  158. package/package.json +4 -4
  159. package/skills/team-agent/SKILL.md +33 -238
  160. package/skills/team-agent/command-coverage.json +31 -0
  161. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
  162. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -488
  163. package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
  164. package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
@@ -1,3 +1,23 @@
1
+ //! ---
2
+ //! purpose: adaptive 布局的窗格规划,定出每个席位落在哪个布局窗口的第几格
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: adaptive_layout_plan
6
+ //! what: 按每窗口容量把席位切成 team-w 序列的窗格安排
7
+ //! - name: adaptive_placement_for_agent
8
+ //! what: 为新席位在现有布局里找位置,找不到真实布局窗口时返回 None
9
+ //! - name: adaptive_existing_placement_for_agent
10
+ //! what: 为已有席位复原它的布局位置
11
+ //! - name: is_adaptive_layout_window_pub
12
+ //! what: 判断窗口名是否是规范的 team-w 布局窗口
13
+ //! depends:
14
+ //! - crate::transport::Transport
15
+ //! boundary:
16
+ //! - 只算位置,不真开窗口也不 spawn
17
+ //! - 只有规范 team-w 名才算布局窗口,按席位命名的窗口一律不算
18
+ //! - 现场没有真实布局窗口时返回 None,不凭空造一个新布局窗口
19
+ //! maturity: wired
20
+ //! ---
1
21
  use std::collections::{BTreeMap, BTreeSet};
2
22
  use std::path::{Path, PathBuf};
3
23
  use std::process::Command;
@@ -23,6 +43,12 @@ pub(crate) struct LayoutPlacement {
23
43
  pub starts_window: bool,
24
44
  }
25
45
 
46
+ /// ---
47
+ /// purpose: 把一批席位按每窗口容量切成布局安排
48
+ /// params:
49
+ /// max_per_window: 每个布局窗口最多几格,小于 1 时按 1 处理
50
+ /// returns: 与入参同序的安排,窗口名形如 team-w 加序号,每窗口第一格标记 starts_window
51
+ /// ---
26
52
  pub(crate) fn adaptive_layout_plan(
27
53
  agent_ids: &[AgentId],
28
54
  max_per_window: usize,
@@ -47,6 +73,10 @@ pub(crate) fn adaptive_layout_plan(
47
73
 
48
74
  pub(crate) const ADAPTIVE_LAYOUT_MAX_PER_WINDOW: usize = 3;
49
75
 
76
+ /// ---
77
+ /// purpose: 判断该 state 是否在用 adaptive 布局
78
+ /// returns: 顶层或 runtime 段的 display_backend 为 adaptive,或任一席位带非空 layout_window 时为 true
79
+ /// ---
50
80
  pub(crate) fn state_uses_adaptive_layout(state: &serde_json::Value) -> bool {
51
81
  state
52
82
  .get("display_backend")
@@ -70,6 +100,12 @@ pub(crate) fn state_uses_adaptive_layout(state: &serde_json::Value) -> bool {
70
100
  })
71
101
  }
72
102
 
103
+ /// ---
104
+ /// purpose: 为新席位在现有 adaptive 布局里找一个位置
105
+ /// params:
106
+ /// transport: 用于取活 pane 与活窗口,交叉核对 state 里的窗口声明
107
+ /// returns: 最后一个布局窗口未满则占它的下一格;已满则开下一个 team-w 窗口;现场没有任何真实布局窗口时返回 None
108
+ /// ---
73
109
  pub(crate) fn adaptive_placement_for_agent(
74
110
  state: &serde_json::Value,
75
111
  transport: &dyn Transport,
@@ -191,6 +227,10 @@ pub(crate) fn adaptive_placement_for_agent(
191
227
  })
192
228
  }
193
229
 
230
+ /// ---
231
+ /// purpose: 复原已有席位的 adaptive 布局位置
232
+ /// returns: 声明的窗口不是规范布局名时为 None;窗口已不在活窗口里则退回以 agent id 新开窗口;否则按该窗口现有 pane 数定格位
233
+ /// ---
194
234
  pub(crate) fn adaptive_existing_placement_for_agent(
195
235
  state: &serde_json::Value,
196
236
  transport: &dyn Transport,
@@ -269,6 +309,12 @@ pub(crate) fn adaptive_existing_placement_for_agent(
269
309
  })
270
310
  }
271
311
 
312
+ /// ---
313
+ /// purpose: 从窗口名解析出布局序号
314
+ /// params:
315
+ /// window: 形如 team-w 加序号,可带后缀
316
+ /// returns: 从 0 起的序号;前缀不符或序号为 0 时为 None
317
+ /// ---
272
318
  pub(super) fn parse_team_layout_index(window: &str) -> Option<usize> {
273
319
  window
274
320
  .strip_prefix("team-w")
@@ -277,6 +323,11 @@ pub(super) fn parse_team_layout_index(window: &str) -> Option<usize> {
277
323
  .and_then(|idx| idx.checked_sub(1))
278
324
  }
279
325
 
326
+ /// ---
327
+ /// purpose: 判断窗口名是否是规范的 adaptive 布局窗口
328
+ /// returns: 能解析出布局序号即为 true
329
+ /// contract_id: lifecycle.layout.is_adaptive_layout_window
330
+ /// ---
280
331
  /// E45 (0.3.24 bug#4, demo-director second-layer drift): a window name is a
281
332
  /// REAL adaptive layout window only when it matches the canonical
282
333
  /// `team-w<N>[-suffix]` shape (i.e. `parse_team_layout_index` returns Some).
@@ -290,6 +341,11 @@ pub(super) fn is_adaptive_layout_window(window: &str) -> bool {
290
341
  parse_team_layout_index(window).is_some()
291
342
  }
292
343
 
344
+ /// ---
345
+ /// purpose: 把上面的判定以更宽可见性转出,供 spawn 侧做兜底守卫
346
+ /// returns: 同 is_adaptive_layout_window
347
+ /// contract_id: lifecycle.layout.is_adaptive_layout_window
348
+ /// ---
293
349
  /// Crate-public wrapper for the defensive guard at
294
350
  /// `restart/common.rs::spawn_agent_window`. Same semantics as the private
295
351
  /// helper above; promoted to `pub(crate)` so the spawn-time defence-in-depth
@@ -299,6 +355,10 @@ pub(crate) fn is_adaptive_layout_window_pub(window: &str) -> bool {
299
355
  is_adaptive_layout_window(window)
300
356
  }
301
357
 
358
+ /// ---
359
+ /// purpose: 在活窗口集合里找一个不冲突的布局窗口名
360
+ /// returns: 基名未被占用就用基名,否则依次尝试加数字后缀
361
+ /// ---
302
362
  pub(super) fn unique_layout_window_name(base: &str, live_windows: &BTreeSet<String>) -> WindowName {
303
363
  if !live_windows.contains(base) {
304
364
  return WindowName::new(base);
@@ -1,3 +1,28 @@
1
+ //! ---
2
+ //! purpose: leader pane 环境变量的校验,以及 quick-start 场景下 owner 与 provider 的归因
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: validate_active_leader_pane_env
6
+ //! what: TEAM_AGENT_LEADER_PANE_ID 指向死或不存在的 pane 时 fail-fast
7
+ //! - name: active_leader_pane_state_across_transports
8
+ //! what: 跨多个 tmux socket 汇总某 pane 的存活判定
9
+ //! - name: seed_unbound_launched_owner
10
+ //! what: 无 caller pane 时种入一份 unbound owner 与 receiver
11
+ //! - name: attributed_provider_for_pane_across_tmux_sockets
12
+ //! what: 跨所有 tmux socket 找到该 pane 并归因它的 provider
13
+ //! depends:
14
+ //! - crate::tmux_backend
15
+ //! - crate::transport::Transport
16
+ //! - crate::state::ownership
17
+ //! - crate::event_log::EventLog
18
+ //! - crate::leader
19
+ //! - crate::compiler
20
+ //! boundary:
21
+ //! - 只在显式判定为 dead 或 absent 时拦截,Unknown 一律放行
22
+ //! - 归因不出 provider 时留空,绝不默认成某个 provider
23
+ //! - 只校验与归因,不 spawn、不改 pane
24
+ //! maturity: wired
25
+ //! ---
1
26
  use std::collections::{BTreeMap, BTreeSet};
2
27
  use std::path::{Path, PathBuf};
3
28
  use std::process::Command;
@@ -15,6 +40,12 @@ use crate::lifecycle::lock::{acquire_agent_lifecycle_lock, LifecycleLockRequest}
15
40
 
16
41
  use super::*;
17
42
 
43
+ /// ---
44
+ /// purpose: 校验 TEAM_AGENT_LEADER_PANE_ID 指向的 pane 是否可用,不带 workspace 上下文
45
+ /// returns: 通过返回空值
46
+ /// errors: pane 明确为 dead 或 absent 时返回 RequirementUnmet,消息含 error/action/log 三行
47
+ /// contract_id: lifecycle.leader_context.validate_leader_pane_env
48
+ /// ---
18
49
  /// B-7 / 036b — TEAM_AGENT_LEADER_PANE_ID 主动路径 fail-fast helper。
19
50
  /// 入口形态(N38 三行式):
20
51
  /// error : `TEAM_AGENT_LEADER_PANE_ID points at a dead/absent pane: %<id>`
@@ -32,6 +63,12 @@ pub(crate) fn validate_active_leader_pane_env(
32
63
  validate_active_leader_pane_env_with_workspaces(transport, &[])
33
64
  }
34
65
 
66
+ /// ---
67
+ /// purpose: 同上,附带一个 workspace 用于写告警事件
68
+ /// returns: 通过返回空值
69
+ /// errors: 同 validate_active_leader_pane_env
70
+ /// contract_id: lifecycle.leader_context.validate_leader_pane_env
71
+ /// ---
35
72
  pub(crate) fn validate_active_leader_pane_env_with_workspace(
36
73
  transport: &dyn Transport,
37
74
  workspace: Option<&Path>,
@@ -40,6 +77,14 @@ pub(crate) fn validate_active_leader_pane_env_with_workspace(
40
77
  validate_active_leader_pane_env_with_workspaces(transport, &workspaces)
41
78
  }
42
79
 
80
+ /// ---
81
+ /// purpose: 校验 leader pane 环境变量的实体实现
82
+ /// params:
83
+ /// workspaces: 写格式告警事件的候选 workspace 列表,可为空
84
+ /// returns: 环境变量未设或为空、pane 格式不合法、判定为 live 或 unknown 时都通过
85
+ /// errors: pane 明确 dead 或 absent 时返回 RequirementUnmet
86
+ /// contract_id: lifecycle.leader_context.validate_leader_pane_env
87
+ /// ---
43
88
  pub(crate) fn validate_active_leader_pane_env_with_workspaces(
44
89
  transport: &dyn Transport,
45
90
  workspaces: &[&Path],
@@ -68,6 +113,12 @@ pub(crate) fn validate_active_leader_pane_env_with_workspaces(
68
113
  )))
69
114
  }
70
115
 
116
+ /// ---
117
+ /// purpose: pane id 格式不合法时写一条告警事件
118
+ /// params:
119
+ /// workspaces: 逐个去重后尝试写事件
120
+ /// returns: 所有 workspace 都没写成时退回 stderr 打印
121
+ /// ---
71
122
  pub(super) fn write_invalid_leader_pane_env_warning(workspaces: &[&Path], pane_id_raw: &str) {
72
123
  let message = "invalid pane id format, skipping validation";
73
124
  let mut wrote = false;
@@ -101,6 +152,12 @@ pub(super) fn write_invalid_leader_pane_env_warning(workspaces: &[&Path], pane_i
101
152
  }
102
153
  }
103
154
 
155
+ /// ---
156
+ /// purpose: TEAM.md 里写了 owner_team_id 时告知它被忽略
157
+ /// params:
158
+ /// runtime_team_key: 真正生效的 canonical 团队键
159
+ /// returns: TEAM.md 没写该字段时什么都不做;否则打印三行提示并写 spec.field_ignored 事件
160
+ /// ---
104
161
  pub(super) fn warn_ignored_owner_team_id(
105
162
  workspace: &Path,
106
163
  team_dir: &Path,
@@ -139,6 +196,10 @@ pub(crate) enum LeaderPaneEnvState {
139
196
  Unknown,
140
197
  }
141
198
 
199
+ /// ---
200
+ /// purpose: 定出校验用的 pane 状态
201
+ /// returns: 格式不合法返回 Unknown;transport 探真实 socket 时跨 socket 判定,否则只问该 transport
202
+ /// ---
142
203
  pub(super) fn leader_pane_env_state_for_validation(
143
204
  transport: &dyn Transport,
144
205
  pane: &crate::transport::PaneId,
@@ -152,11 +213,19 @@ pub(super) fn leader_pane_env_state_for_validation(
152
213
  active_leader_pane_state(transport, pane)
153
214
  }
154
215
 
216
+ /// ---
217
+ /// purpose: 判断字符串是否是 tmux pane id 形状
218
+ /// returns: 以百分号起头且其后全为数字时为 true
219
+ /// ---
155
220
  pub(super) fn is_tmux_pane_id_format(pane: &crate::transport::PaneId) -> bool {
156
221
  let pane = pane.as_str();
157
222
  pane.len() > 1 && pane.starts_with('%') && pane[1..].chars().all(|ch| ch.is_ascii_digit())
158
223
  }
159
224
 
225
+ /// ---
226
+ /// purpose: 枚举本机所有 tmux socket,跨 server 判定该 pane 的状态
227
+ /// returns: 汇总后的状态
228
+ /// ---
160
229
  pub(super) fn active_leader_pane_state_across_tmux_sockets(
161
230
  pane: &crate::transport::PaneId,
162
231
  ) -> LeaderPaneEnvState {
@@ -173,6 +242,10 @@ pub(super) fn active_leader_pane_state_across_tmux_sockets(
173
242
  )
174
243
  }
175
244
 
245
+ /// ---
246
+ /// purpose: 在多个 transport 上汇总某 pane 的状态
247
+ /// returns: 任一为 Live 即 Live;否则有 Dead 报 Dead,有 Absent 报 Absent,全 Unknown 报 Unknown
248
+ /// ---
176
249
  pub(crate) fn active_leader_pane_state_across_transports<'a>(
177
250
  transports: impl IntoIterator<Item = &'a dyn Transport>,
178
251
  pane: &crate::transport::PaneId,
@@ -196,6 +269,10 @@ pub(crate) fn active_leader_pane_state_across_transports<'a>(
196
269
  }
197
270
  }
198
271
 
272
+ /// ---
273
+ /// purpose: 在单个 transport 上判定 pane 状态
274
+ /// returns: has_pane 给出确定答案时直接用,否则退到 liveness;两者都判不出时为 Unknown
275
+ /// ---
199
276
  pub(super) fn active_leader_pane_state(
200
277
  transport: &dyn Transport,
201
278
  pane: &crate::transport::PaneId,
@@ -212,6 +289,13 @@ pub(super) fn active_leader_pane_state(
212
289
  }
213
290
  }
214
291
 
292
+ /// ---
293
+ /// purpose: 在没有 caller pane 的情况下种入一份 unbound owner 与 receiver
294
+ /// params:
295
+ /// launched: 待改写的 state
296
+ /// launched_key: 团队键
297
+ /// returns: 归因不出 provider 时直接返回不写,避免默认成某个 provider
298
+ /// ---
215
299
  pub(super) fn seed_unbound_launched_owner(launched: &mut serde_json::Value, launched_key: &str) {
216
300
  let Some(owner) = unbound_launched_owner(launched, launched_key) else {
217
301
  return;
@@ -241,6 +325,10 @@ pub(super) fn seed_unbound_launched_owner(launched: &mut serde_json::Value, laun
241
325
  crate::state::ownership::write_owner(launched, launched_key, record);
242
326
  }
243
327
 
328
+ /// ---
329
+ /// purpose: 构造 unbound owner 记录
330
+ /// returns: provider 归因成功且能派生出 leader session uuid 时给出 owner JSON,否则 None
331
+ /// ---
244
332
  pub(super) fn unbound_launched_owner(
245
333
  launched: &serde_json::Value,
246
334
  launched_key: &str,
@@ -276,6 +364,10 @@ pub(super) fn unbound_launched_owner(
276
364
  }))
277
365
  }
278
366
 
367
+ /// ---
368
+ /// purpose: 归因 unbound owner 的 provider
369
+ /// returns: 先用 state 里已写的 provider,其次按 owner 的 pane 跨 socket 归因;都失败为 None
370
+ /// ---
279
371
  pub(super) fn unbound_launched_provider(launched: &serde_json::Value) -> Option<String> {
280
372
  if let Some(provider) = launched
281
373
  .get("team_owner")
@@ -296,12 +388,20 @@ pub(super) fn unbound_launched_provider(launched: &serde_json::Value) -> Option<
296
388
  attributed_provider_for_pane_across_tmux_sockets(&target).and_then(provider_wire_string)
297
389
  }
298
390
 
391
+ /// ---
392
+ /// purpose: 把 provider 枚举转成它的 wire 字符串
393
+ /// returns: 序列化得到的字符串,转换失败为 None
394
+ /// ---
299
395
  pub(super) fn provider_wire_string(provider: Provider) -> Option<String> {
300
396
  serde_json::to_value(provider)
301
397
  .ok()
302
398
  .and_then(|value| value.as_str().map(str::to_string))
303
399
  }
304
400
 
401
+ /// ---
402
+ /// purpose: 跨本机所有 tmux socket 找到该 pane 并归因它的 provider
403
+ /// returns: 找到且能归因时给出 provider,否则 None
404
+ /// ---
305
405
  pub(super) fn attributed_provider_for_pane_across_tmux_sockets(pane: &PaneId) -> Option<Provider> {
306
406
  crate::tmux_backend::tmux_socket_endpoints()
307
407
  .into_iter()
@@ -315,6 +415,12 @@ pub(super) fn attributed_provider_for_pane_across_tmux_sockets(pane: &PaneId) ->
315
415
  .and_then(|info| crate::leader::attribute_pane_provider(&info))
316
416
  }
317
417
 
418
+ /// ---
419
+ /// purpose: 定出 caller 的 provider wire 名
420
+ /// params:
421
+ /// lookup_pane_provider: 由 pane 反查 provider 的函数,便于测试替换
422
+ /// returns: caller 自报的 provider 优先,其次按 caller pane 反查;都不成为 None
423
+ /// ---
318
424
  pub(super) fn caller_provider_for_seed_with_lookup(
319
425
  caller: &crate::state::owner_gate::CallerIdentity,
320
426
  lookup_pane_provider: impl Fn(&PaneId) -> Option<Provider>,
@@ -457,6 +563,12 @@ mod e22_unbound_owner_provider_tests {
457
563
  }
458
564
  }
459
565
 
566
+ /// ---
567
+ /// purpose: 判断该 pane 是否已经是别的团队的 owner pane
568
+ /// params:
569
+ /// launched_key: 本次团队键,比较时被排除
570
+ /// returns: 存在另一团队的 team_owner.pane_id 等于它则为 true
571
+ /// ---
460
572
  pub(super) fn owner_pane_belongs_to_other_team(
461
573
  existing: &serde_json::Value,
462
574
  launched_key: &str,