@team-agent/installer 0.5.65 → 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.
- package/Cargo.lock +8 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +6 -0
- package/crates/team-agent/src/cli/adapters.rs +6 -1
- package/crates/team-agent/src/cli/diagnose.rs +82 -0
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +21 -7
- package/crates/team-agent/src/cli/leaders.rs +125 -1
- package/crates/team-agent/src/cli/mod.rs +20 -0
- package/crates/team-agent/src/cli/send/presentation.rs +7 -1
- package/crates/team-agent/src/cli/spec.rs +2 -0
- package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
- package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
- package/crates/team-agent/src/cli/tests/base.rs +26 -3
- package/crates/team-agent/src/cli/tests/compile.rs +1 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
- package/crates/team-agent/src/cli/tests/mod.rs +2 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
- package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
- package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
- package/crates/team-agent/src/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler/tests.rs +23 -20
- package/crates/team-agent/src/compiler.rs +84 -5
- package/crates/team-agent/src/conpty/backend.rs +16 -0
- package/crates/team-agent/src/coordinator/backoff.rs +55 -0
- package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
- package/crates/team-agent/src/coordinator/health.rs +173 -0
- package/crates/team-agent/src/coordinator/mod.rs +31 -0
- package/crates/team-agent/src/coordinator/orphan.rs +31 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
- package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
- package/crates/team-agent/src/coordinator/tick.rs +133 -22
- package/crates/team-agent/src/coordinator/types.rs +49 -0
- package/crates/team-agent/src/db/message_store.rs +39 -5
- package/crates/team-agent/src/layout/worker_env.rs +20 -3
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
- package/crates/team-agent/src/leader/registry.rs +65 -0
- package/crates/team-agent/src/leader/start.rs +1080 -58
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/display.rs +56 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -14
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +69 -2
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +196 -2
- package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
- package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -457
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
- package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
- package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
- package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
- package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +101 -4
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +244 -48
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -2
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +209 -43
- package/crates/team-agent/src/lifecycle/lock.rs +42 -1
- package/crates/team-agent/src/lifecycle/mod.rs +11 -0
- package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +213 -3
- package/crates/team-agent/src/lifecycle/restart/common.rs +373 -18
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +165 -15
- package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
- package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
- package/crates/team-agent/src/lifecycle/restart.rs +29 -0
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -4
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +159 -174
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +15 -13
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -18
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
- package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +65 -40
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +20 -32
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +17 -9
- package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +24 -23
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +98 -62
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -1
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +41 -8
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +60 -2
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +23 -15
- package/crates/team-agent/src/lifecycle/types.rs +61 -2
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +200 -33
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
- package/crates/team-agent/src/mcp_server/tests.rs +196 -2
- package/crates/team-agent/src/messaging/delivery.rs +405 -40
- package/crates/team-agent/src/messaging/helpers.rs +2 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
- package/crates/team-agent/src/messaging/results.rs +4 -0
- package/crates/team-agent/src/messaging/send.rs +34 -0
- package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
- package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
- package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
- package/crates/team-agent/src/messaging/types.rs +4 -1
- package/crates/team-agent/src/model/enums.rs +14 -5
- package/crates/team-agent/src/model/permissions.rs +3 -0
- package/crates/team-agent/src/model/spec.rs +129 -6
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
- package/crates/team-agent/src/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +231 -4
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +124 -0
- package/crates/team-agent/src/provider/classify.rs +4 -2
- package/crates/team-agent/src/provider/faults.rs +2 -1
- package/crates/team-agent/src/provider/mod.rs +13 -0
- package/crates/team-agent/src/provider/session/capture.rs +158 -20
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
- package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
- package/crates/team-agent/src/provider/session/mod.rs +18 -0
- package/crates/team-agent/src/provider/session/resume.rs +57 -0
- package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
- package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
- package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
- package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
- package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
- package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
- package/crates/team-agent/src/provider/session_scan.rs +8 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +23 -1
- package/crates/team-agent/src/state/persist.rs +301 -8
- package/crates/team-agent/src/state/repository.rs +5 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
- package/crates/team-agent/src/tmux_backend.rs +1083 -75
- package/crates/team-agent/src/transport/test_support.rs +20 -0
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +265 -1
- package/npm/install.mjs +129 -73
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +33 -238
- package/skills/team-agent/command-coverage.json +31 -0
- package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -483
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
|
@@ -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,
|