@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,11 +1,49 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 摘掉一席,含双确认门、六态一致性判定、原子摘除与字节级回滚快照
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: remove_agent
|
|
6
|
+
//! what: 从 spec、state、team_state 与 role 文件原子摘除一席
|
|
7
|
+
//! - name: remove_agent_flag_requirements
|
|
8
|
+
//! what: 只做前置判定,告诉调用方这次需要哪些确认标志
|
|
9
|
+
//! - name: ForceRecreateSnapshot
|
|
10
|
+
//! what: 强制重建用的快照,可在失败后恢复席位并清掉本事务新起的 pane
|
|
11
|
+
//! - name: resolve_seat
|
|
12
|
+
//! what: 由期望、持久与物理三源定出席位的唯一身份与一致性态
|
|
13
|
+
//! - name: spec_without_agent
|
|
14
|
+
//! what: 生成摘掉该席位后的 spec,并清掉指向它的路由与启动项
|
|
15
|
+
//! depends:
|
|
16
|
+
//! - crate::lifecycle::lock
|
|
17
|
+
//! - crate::lifecycle::restart::agent
|
|
18
|
+
//! - crate::lifecycle::restart::team_state
|
|
19
|
+
//! - crate::state::projection
|
|
20
|
+
//! - crate::transport::Transport
|
|
21
|
+
//! boundary:
|
|
22
|
+
//! - 未给 from_spec 确认或运行中未给 force 时拒绝,不擅自摘除
|
|
23
|
+
//! - 物理身份必须收敛到唯一的 session 加 window 加 pane,全局同名窗口不算身份
|
|
24
|
+
//! - 只删托管目录下的角色副本,用户自带的 role 文件不删
|
|
25
|
+
//! maturity: wired
|
|
26
|
+
//! ---
|
|
1
27
|
use super::agent::{resolve_team_scoped_state_or_refuse, start_agent_at_paths};
|
|
2
28
|
use super::common::*;
|
|
3
29
|
use super::team_state::write_team_state;
|
|
4
30
|
use super::*;
|
|
5
31
|
use crate::lifecycle::lock::{acquire_agent_lifecycle_lock, LifecycleLockRequest};
|
|
6
32
|
|
|
33
|
+
/// ---
|
|
34
|
+
/// purpose: 摘掉一席的对外入口,取生命周期锁后走实体实现
|
|
35
|
+
/// params:
|
|
36
|
+
/// from_spec: 确认同时从 spec 里摘掉
|
|
37
|
+
/// force: 席位仍在运行时必须给出
|
|
38
|
+
/// returns: 摘除结果
|
|
39
|
+
/// errors: 选不到 team 返回 TeamSelect;确认标志不足或一致性态不允许时返回 RequirementUnmet;写盘失败返回 StatePersist
|
|
40
|
+
/// contract_id: lifecycle.remove_agent.entry
|
|
41
|
+
/// ---
|
|
7
42
|
/// `remove_agent(workspace, agent_id, from_spec, force, team)`(`lifecycle/agents.py:22`)。
|
|
8
|
-
/// 从 spec/state/team_state/agent_health
|
|
43
|
+
/// 从 spec/state/team_state/agent_health 原子摘除。
|
|
44
|
+
/// 托管目录 `.team/dynamic-role-files/` 下的物化副本随席位清掉;托管目录之外的
|
|
45
|
+
/// `--role-file` 仍是用户资产,不删。A-28 对托管文件「默认保留」的承诺已由
|
|
46
|
+
/// `ledger.seat-supply-prereq` 推翻。
|
|
9
47
|
/// `_RemoveRollback` 字节级快照回滚全部运行时变更。未传 from_spec 确认 / 运行中未传 force → 拒绝。
|
|
10
48
|
pub fn remove_agent(
|
|
11
49
|
workspace: &Path,
|
|
@@ -35,6 +73,12 @@ pub fn remove_agent(
|
|
|
35
73
|
)
|
|
36
74
|
}
|
|
37
75
|
|
|
76
|
+
/// ---
|
|
77
|
+
/// purpose: 带注入 transport 的摘席入口,自行取锁
|
|
78
|
+
/// returns: 摘除结果
|
|
79
|
+
/// errors: 同 remove_agent
|
|
80
|
+
/// contract_id: lifecycle.remove_agent.entry
|
|
81
|
+
/// ---
|
|
38
82
|
pub(crate) fn remove_agent_with_transport(
|
|
39
83
|
workspace: &Path,
|
|
40
84
|
agent_id: &AgentId,
|
|
@@ -63,6 +107,12 @@ pub(crate) fn remove_agent_with_transport(
|
|
|
63
107
|
)
|
|
64
108
|
}
|
|
65
109
|
|
|
110
|
+
/// ---
|
|
111
|
+
/// purpose: 调用方已持有生命周期锁时的摘席入口,本函数不再取锁
|
|
112
|
+
/// returns: 摘除结果
|
|
113
|
+
/// errors: 同 remove_agent
|
|
114
|
+
/// contract_id: lifecycle.remove_agent.entry
|
|
115
|
+
/// ---
|
|
66
116
|
pub(crate) fn remove_agent_with_transport_locked(
|
|
67
117
|
workspace: &Path,
|
|
68
118
|
agent_id: &AgentId,
|
|
@@ -93,6 +143,11 @@ pub(crate) struct ForceRecreateSnapshot {
|
|
|
93
143
|
}
|
|
94
144
|
|
|
95
145
|
impl ForceRecreateSnapshot {
|
|
146
|
+
/// ---
|
|
147
|
+
/// purpose: 为强制重建拍一份可回滚的快照
|
|
148
|
+
/// returns: 含逻辑回滚数据与摘除前物理 pane 身份的快照
|
|
149
|
+
/// errors: 选不到 team 或席位解析失败时返回 LifecycleError
|
|
150
|
+
/// ---
|
|
96
151
|
pub(crate) fn capture(
|
|
97
152
|
workspace: &Path,
|
|
98
153
|
agent_id: &AgentId,
|
|
@@ -126,6 +181,10 @@ impl ForceRecreateSnapshot {
|
|
|
126
181
|
})
|
|
127
182
|
}
|
|
128
183
|
|
|
184
|
+
/// ---
|
|
185
|
+
/// purpose: 按快照恢复席位的逻辑状态
|
|
186
|
+
/// returns: 恢复过程中的错误描述列表,空表示恢复干净
|
|
187
|
+
/// ---
|
|
129
188
|
pub(crate) fn restore(
|
|
130
189
|
&self,
|
|
131
190
|
team: Option<&str>,
|
|
@@ -135,6 +194,10 @@ impl ForceRecreateSnapshot {
|
|
|
135
194
|
.restore(&self.run_workspace, &self.spec_workspace, team, transport)
|
|
136
195
|
}
|
|
137
196
|
|
|
197
|
+
/// ---
|
|
198
|
+
/// purpose: 旧 pane 已被消费后的恢复,先杀掉本次事务新起的 pane 再恢复逻辑快照
|
|
199
|
+
/// returns: 错误描述列表;恢复干净时还会校验物理身份是否回到摘除前的 session 与窗口
|
|
200
|
+
/// ---
|
|
138
201
|
/// The old pane has already been consumed. Any exact pane now resolved for
|
|
139
202
|
/// this seat belongs to this force-recreate transaction and must be removed
|
|
140
203
|
/// before the logical snapshot is restored, otherwise rollback can leave a
|
|
@@ -193,6 +256,11 @@ impl ForceRecreateSnapshot {
|
|
|
193
256
|
errors
|
|
194
257
|
}
|
|
195
258
|
|
|
259
|
+
/// ---
|
|
260
|
+
/// purpose: 强制重建之后要求席位处于一致态
|
|
261
|
+
/// returns: 一致时返回空值
|
|
262
|
+
/// errors: 解析失败透传;解析出的一致性态不是 Coherent 时返回 StatePersist
|
|
263
|
+
/// ---
|
|
196
264
|
pub(crate) fn require_coherent(
|
|
197
265
|
&self,
|
|
198
266
|
agent_id: &AgentId,
|
|
@@ -217,6 +285,11 @@ impl ForceRecreateSnapshot {
|
|
|
217
285
|
}
|
|
218
286
|
}
|
|
219
287
|
|
|
288
|
+
/// ---
|
|
289
|
+
/// purpose: 只做前置判定,给出这次摘席需要哪些确认标志
|
|
290
|
+
/// returns: 标志要求;不做任何摘除动作
|
|
291
|
+
/// errors: 选不到 team 或席位解析失败时返回 LifecycleError
|
|
292
|
+
/// ---
|
|
220
293
|
pub fn remove_agent_flag_requirements(
|
|
221
294
|
workspace: &Path,
|
|
222
295
|
agent_id: &AgentId,
|
|
@@ -263,6 +336,13 @@ pub(super) struct ResolvedSeat {
|
|
|
263
336
|
pub(super) consistency: SeatConsistency,
|
|
264
337
|
}
|
|
265
338
|
|
|
339
|
+
/// ---
|
|
340
|
+
/// purpose: 由 spec、runtime state 与物理 pane 三源定出席位身份与一致性态
|
|
341
|
+
/// params:
|
|
342
|
+
/// transport: 已绑定该 team endpoint 的 transport
|
|
343
|
+
/// returns: 席位解析结果,含所在 session、窗口、物理 pane 与六态之一的一致性判定
|
|
344
|
+
/// errors: 团队作用域 state 取不到或 owner 门不过时返回 LifecycleError
|
|
345
|
+
/// ---
|
|
266
346
|
/// Resolve one seat from the selected team's desired, persisted and physical
|
|
267
347
|
/// sources. The transport is already bound to the selected team's endpoint;
|
|
268
348
|
/// physical identity is then narrowed to exactly one `(session, window, pane)`
|
|
@@ -552,6 +632,7 @@ fn remove_agent_inner(
|
|
|
552
632
|
// after the stop (stop_agent persisted it); otherwise the originally-resolved projection drives the
|
|
553
633
|
// removal. Either way we operate on the PROJECTION, never a raw load_runtime_state.
|
|
554
634
|
let working_state = state;
|
|
635
|
+
let recorded_role_file = recorded_dynamic_role_file(&working_state, agent_id);
|
|
555
636
|
let mut stopped = false;
|
|
556
637
|
let mut cleared_locations = Vec::new();
|
|
557
638
|
if force {
|
|
@@ -620,10 +701,16 @@ fn remove_agent_inner(
|
|
|
620
701
|
"team.spec.yaml",
|
|
621
702
|
None,
|
|
622
703
|
)?;
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
|
|
704
|
+
// Managed copies under `.team/dynamic-role-files/` are framework residue
|
|
705
|
+
// and must not block the next same-id clone. External --role-file paths
|
|
706
|
+
// stay user-owned. Classify by the path's directory (do not follow a
|
|
707
|
+
// last-component symlink); unlink with remove_file so only the link dies.
|
|
708
|
+
let role_file_removed = clear_managed_role_residue(
|
|
709
|
+
paths.run_workspace,
|
|
710
|
+
agent_id,
|
|
711
|
+
recorded_role_file.as_deref(),
|
|
712
|
+
&mut cleared_locations,
|
|
713
|
+
)?;
|
|
627
714
|
let agent_health_deleted = delete_agent_health(paths.run_workspace, team_key, agent_id)?;
|
|
628
715
|
cleared_locations.push(serde_json::json!("agent_health"));
|
|
629
716
|
write_remove_step_event(
|
|
@@ -663,6 +750,94 @@ struct RemoveSuccess {
|
|
|
663
750
|
cleared_locations: Vec<serde_json::Value>,
|
|
664
751
|
}
|
|
665
752
|
|
|
753
|
+
fn recorded_dynamic_role_file(
|
|
754
|
+
state: &serde_json::Value,
|
|
755
|
+
agent_id: &AgentId,
|
|
756
|
+
) -> Option<std::path::PathBuf> {
|
|
757
|
+
state
|
|
758
|
+
.get("agents")
|
|
759
|
+
.and_then(|v| v.get(agent_id.as_str()))
|
|
760
|
+
.and_then(|v| v.get("dynamic_role_file"))
|
|
761
|
+
.and_then(|v| v.as_str())
|
|
762
|
+
.map(str::trim)
|
|
763
|
+
.filter(|s| !s.is_empty())
|
|
764
|
+
.map(std::path::PathBuf::from)
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
fn resolve_role_path(workspace: &Path, role_file: &Path) -> std::path::PathBuf {
|
|
768
|
+
if role_file.is_absolute() {
|
|
769
|
+
role_file.to_path_buf()
|
|
770
|
+
} else {
|
|
771
|
+
workspace.join(role_file)
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
fn default_managed_role_file(workspace: &Path, agent_id: &AgentId) -> std::path::PathBuf {
|
|
776
|
+
workspace
|
|
777
|
+
.join(".team")
|
|
778
|
+
.join("dynamic-role-files")
|
|
779
|
+
.join(format!("{}.md", agent_id.as_str()))
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/// Same prefix rule as `role_source_ownership`, but canonicalize the parent
|
|
783
|
+
/// only. Following the last component would classify a managed symlink whose
|
|
784
|
+
/// target lives outside the managed dir as external, and leave residue.
|
|
785
|
+
fn role_path_is_managed(workspace: &Path, role_file: &Path) -> bool {
|
|
786
|
+
let managed_root = workspace.join(".team").join("dynamic-role-files");
|
|
787
|
+
let Ok(root) = std::fs::canonicalize(&managed_root) else {
|
|
788
|
+
return false;
|
|
789
|
+
};
|
|
790
|
+
let abs = resolve_role_path(workspace, role_file);
|
|
791
|
+
let Some(parent) = abs.parent() else {
|
|
792
|
+
return false;
|
|
793
|
+
};
|
|
794
|
+
match std::fs::canonicalize(parent) {
|
|
795
|
+
Ok(parent_canon) => parent_canon.starts_with(&root),
|
|
796
|
+
Err(_) => false,
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
fn unlink_role_path(path: &Path) -> Result<bool, LifecycleError> {
|
|
801
|
+
match std::fs::symlink_metadata(path) {
|
|
802
|
+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
|
|
803
|
+
Err(err) => Err(LifecycleError::StatePersist(format!(
|
|
804
|
+
"inspect managed role file {}: {err}",
|
|
805
|
+
path.display()
|
|
806
|
+
))),
|
|
807
|
+
Ok(_) => std::fs::remove_file(path).map(|_| true).map_err(|err| {
|
|
808
|
+
LifecycleError::StatePersist(format!(
|
|
809
|
+
"remove managed role file {}: {err}",
|
|
810
|
+
path.display()
|
|
811
|
+
))
|
|
812
|
+
}),
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
fn clear_managed_role_residue(
|
|
817
|
+
workspace: &Path,
|
|
818
|
+
agent_id: &AgentId,
|
|
819
|
+
recorded: Option<&Path>,
|
|
820
|
+
cleared_locations: &mut Vec<serde_json::Value>,
|
|
821
|
+
) -> Result<bool, LifecycleError> {
|
|
822
|
+
let target = match recorded {
|
|
823
|
+
Some(recorded) => {
|
|
824
|
+
let abs = resolve_role_path(workspace, recorded);
|
|
825
|
+
if !role_path_is_managed(workspace, &abs) {
|
|
826
|
+
return Ok(false);
|
|
827
|
+
}
|
|
828
|
+
abs
|
|
829
|
+
}
|
|
830
|
+
None => default_managed_role_file(workspace, agent_id),
|
|
831
|
+
};
|
|
832
|
+
if !unlink_role_path(&target)? {
|
|
833
|
+
return Ok(false);
|
|
834
|
+
}
|
|
835
|
+
let resource = target.to_string_lossy().into_owned();
|
|
836
|
+
write_remove_step_event(workspace, agent_id, "role_file", &resource, None)?;
|
|
837
|
+
cleared_locations.push(serde_json::json!(resource));
|
|
838
|
+
Ok(true)
|
|
839
|
+
}
|
|
840
|
+
|
|
666
841
|
fn write_remove_step_event(
|
|
667
842
|
workspace: &Path,
|
|
668
843
|
agent_id: &AgentId,
|
|
@@ -780,6 +955,13 @@ fn remove_agent_from_state(
|
|
|
780
955
|
}
|
|
781
956
|
}
|
|
782
957
|
|
|
958
|
+
/// ---
|
|
959
|
+
/// purpose: 在 state 里给该席位打上退役标记
|
|
960
|
+
/// params:
|
|
961
|
+
/// state: 就地写 agent_lifecycle 下该席位的状态、时间与原因
|
|
962
|
+
/// returns: 已是退役态时幂等返回
|
|
963
|
+
/// errors: state 根、agent_lifecycle 或该条目不是对象时返回 StatePersist
|
|
964
|
+
/// ---
|
|
783
965
|
pub(crate) fn mark_agent_retired_in_state(
|
|
784
966
|
state: &mut serde_json::Value,
|
|
785
967
|
agent_id: &AgentId,
|
|
@@ -814,6 +996,11 @@ pub(crate) fn mark_agent_retired_in_state(
|
|
|
814
996
|
Ok(())
|
|
815
997
|
}
|
|
816
998
|
|
|
999
|
+
/// ---
|
|
1000
|
+
/// purpose: 清掉该席位的退役标记
|
|
1001
|
+
/// params:
|
|
1002
|
+
/// state: 就地删除;只有当前确为退役态才删
|
|
1003
|
+
/// ---
|
|
817
1004
|
pub(crate) fn clear_agent_retirement_in_state(state: &mut serde_json::Value, agent_id: &AgentId) {
|
|
818
1005
|
let Some(lifecycle) = state
|
|
819
1006
|
.get_mut("agent_lifecycle")
|
|
@@ -831,6 +1018,10 @@ pub(crate) fn clear_agent_retirement_in_state(state: &mut serde_json::Value, age
|
|
|
831
1018
|
}
|
|
832
1019
|
}
|
|
833
1020
|
|
|
1021
|
+
/// ---
|
|
1022
|
+
/// purpose: 生成摘掉该席位后的 spec
|
|
1023
|
+
/// returns: 去掉该 agent、去掉它的启动项、并清掉指向它的路由引用后的 spec;spec 不是 map 时原样返回
|
|
1024
|
+
/// ---
|
|
834
1025
|
/// Build the persisted spec after removing one worker. Besides deleting the worker and startup entry,
|
|
835
1026
|
/// prune routing references that would otherwise point at the removed worker.
|
|
836
1027
|
pub(crate) fn spec_without_agent(spec: &YamlValue, agent_id: &AgentId) -> YamlValue {
|
|
@@ -1,7 +1,39 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: restart 与 start 的纯决策层,定启动模式、first_send_at 分类与整队 resume 计划
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: decide_start_mode
|
|
6
|
+
//! what: 由 session_id 与 resume 依据决定 Resumed/Fresh/FreshAfterMissingRollout/Noop
|
|
7
|
+
//! - name: classify_first_send_at
|
|
8
|
+
//! what: 严格分类 first_send_at,绝不靠真值性
|
|
9
|
+
//! - name: restart_agent_has_context_to_preserve
|
|
10
|
+
//! what: 判断该席位是否有会被静默 fresh 丢掉的上下文
|
|
11
|
+
//! - name: classify_restart_plan
|
|
12
|
+
//! what: 纯计算出整队的 resume 决策、损坏条目与不可 resume 名单
|
|
13
|
+
//! - name: python_type_name
|
|
14
|
+
//! what: 给出与 Python 一致的类型名,用于审计载荷
|
|
15
|
+
//! depends:
|
|
16
|
+
//! - crate::provider::wire
|
|
17
|
+
//! boundary:
|
|
18
|
+
//! - 纯计算,不 spawn、不 kill、不写盘
|
|
19
|
+
//! - 拒绝结论必须先于任何 teardown 产出,本层不执行任何破坏性动作
|
|
20
|
+
//! - 类型名用 Python 命名而非 serde 命名,保持与真相源一致
|
|
21
|
+
//! maturity: wired
|
|
22
|
+
//! ---
|
|
1
23
|
use super::common::*;
|
|
2
24
|
use super::*;
|
|
3
25
|
use crate::provider::wire::{parse_canonical_provider, requires_resume_backing};
|
|
4
26
|
|
|
27
|
+
/// ---
|
|
28
|
+
/// purpose: 定出该席位这次的启动模式
|
|
29
|
+
/// params:
|
|
30
|
+
/// provider: provider wire 名,不支持 resume 时视为无 resume 依据
|
|
31
|
+
/// session_id: 已记录的会话;为空直接 Fresh
|
|
32
|
+
/// _rollout_path: 未参与判定
|
|
33
|
+
/// rollout_exists: resume 依据是否存在
|
|
34
|
+
/// allow_fresh: 依据缺失时是否允许改跑全新会话
|
|
35
|
+
/// returns: 依据齐全为 Resumed;缺依据且允许时为 FreshAfterMissingRollout;缺依据且不允许时为 Noop
|
|
36
|
+
/// ---
|
|
5
37
|
/// bug-085 四象限 `start_mode` 决策(`start.py:179-188` + `_resume_rollout_missing` `start.py:66-69`),
|
|
6
38
|
/// **从 start_agent 的整条 lock+spawn 路径里分离出的纯函数**(gate gap:porter 需要单元级 RED
|
|
7
39
|
/// for `FreshAfterMissingRollout`,而 start_agent 全路径不可单测)。语义:
|
|
@@ -31,10 +63,20 @@ pub fn decide_start_mode(
|
|
|
31
63
|
}
|
|
32
64
|
}
|
|
33
65
|
|
|
66
|
+
/// ---
|
|
67
|
+
/// purpose: 判断该 provider 的 resume 是否必须有落盘依据
|
|
68
|
+
/// returns: 能解析成规范 provider 且它要求依据时为 true
|
|
69
|
+
/// ---
|
|
34
70
|
pub(crate) fn resumable_provider_requires_backing(provider: &str) -> bool {
|
|
35
71
|
parse_canonical_provider(provider).is_some_and(requires_resume_backing)
|
|
36
72
|
}
|
|
37
73
|
|
|
74
|
+
/// ---
|
|
75
|
+
/// purpose: 严格分类 first_send_at 取值
|
|
76
|
+
/// params:
|
|
77
|
+
/// raw: 原始 JSON 值
|
|
78
|
+
/// returns: 空值为 Absent,合法 ISO 时间串为 Valid,其余一切取值都是 Corrupt
|
|
79
|
+
/// ---
|
|
38
80
|
/// `first_send_at` 严格分类(`_classify_first_send_at`,`orchestration.py:399`)。
|
|
39
81
|
/// **绝不靠 truthiness**:`""`/`0`/`False`/`"null"`/非 ISO → `Corrupt`。
|
|
40
82
|
pub(crate) fn classify_first_send_at(raw: &serde_json::Value) -> FirstSendAtState {
|
|
@@ -54,6 +96,10 @@ pub(crate) fn classify_first_send_at(raw: &serde_json::Value) -> FirstSendAtStat
|
|
|
54
96
|
}
|
|
55
97
|
}
|
|
56
98
|
|
|
99
|
+
/// ---
|
|
100
|
+
/// purpose: 判断该席位是否有一旦静默 fresh 就会丢掉的上下文
|
|
101
|
+
/// returns: first_send_at 合法、有 last_result_at 或标了已投递首任务,任一成立即 true
|
|
102
|
+
/// ---
|
|
57
103
|
/// RESTART-RESUME-001 (0.4.8): true if the agent has any signal of prior
|
|
58
104
|
/// interaction whose context would be lost by silent fresh-start. Checks
|
|
59
105
|
/// `first_send_at` (leader→worker delivery), `last_result_at` (worker
|
|
@@ -90,6 +136,12 @@ pub(crate) fn restart_agent_has_context_to_preserve(agent: &serde_json::Value) -
|
|
|
90
136
|
.unwrap_or(false)
|
|
91
137
|
}
|
|
92
138
|
|
|
139
|
+
/// ---
|
|
140
|
+
/// purpose: 判断该席位从未被捕获过会话,因而可以安全地直接 fresh
|
|
141
|
+
/// params:
|
|
142
|
+
/// session_id: 外部已知的会话 id,与席位行里的一并检查
|
|
143
|
+
/// returns: 无会话且无待保留上下文时为 true
|
|
144
|
+
/// ---
|
|
93
145
|
/// RESTART-RESUME-001: an agent is "never-captured" when its session_id is
|
|
94
146
|
/// absent AND there is no context to preserve. Such an agent is safe to
|
|
95
147
|
/// auto-fresh without `--allow-fresh` and should NOT be required to capture
|
|
@@ -154,6 +206,10 @@ fn normalize_iso_separator(raw: &str) -> String {
|
|
|
154
206
|
out
|
|
155
207
|
}
|
|
156
208
|
|
|
209
|
+
/// ---
|
|
210
|
+
/// purpose: 给出与 Python 一致的类型名
|
|
211
|
+
/// returns: NoneType、str、bool、list、dict、int 或 float
|
|
212
|
+
/// ---
|
|
157
213
|
/// Python `type(value).__name__` 映射(`orchestration.py:446`):corrupt first_send_at
|
|
158
214
|
/// 条目的 `raw_first_send_at_type` golden。锁死跨语言一致:`null→"NoneType"`、`""/"x"→"str"`、
|
|
159
215
|
/// `0/123→"int"`、`false→"bool"`、`[]→"list"`、`{}→"dict"`、float→`"float"`。
|
|
@@ -176,6 +232,14 @@ pub(crate) fn python_type_name(value: &serde_json::Value) -> &'static str {
|
|
|
176
232
|
}
|
|
177
233
|
}
|
|
178
234
|
|
|
235
|
+
/// ---
|
|
236
|
+
/// purpose: 纯计算出整队的 restart 计划
|
|
237
|
+
/// params:
|
|
238
|
+
/// allow_fresh: 允许无会话席位改跑全新会话
|
|
239
|
+
/// returns: 每个非 paused 席位的 resume 决策、损坏的 first_send_at 条目与不可 resume 名单
|
|
240
|
+
/// errors: 计算过程中的错误以 LifecycleError 返回
|
|
241
|
+
/// contract_id: lifecycle.selection.classify_restart_plan
|
|
242
|
+
/// ---
|
|
179
243
|
/// Route B 全量验证(纯计算,**无破坏性副作用**;`_emit_resume_decisions` +
|
|
180
244
|
/// `_collect_corrupt_first_send_at`,`orchestration.py:430/467`)。读 fixture state 的
|
|
181
245
|
/// `agents.<id>`,对每非 paused worker:
|
|
@@ -193,6 +257,14 @@ pub(crate) fn classify_restart_plan(
|
|
|
193
257
|
classify_restart_plan_with_resume_validation(None, state, allow_fresh)
|
|
194
258
|
}
|
|
195
259
|
|
|
260
|
+
/// ---
|
|
261
|
+
/// purpose: 同上,并可带 workspace 以校验 resume 依据是否真的在盘上
|
|
262
|
+
/// params:
|
|
263
|
+
/// workspace: 给出时才做落盘依据校验
|
|
264
|
+
/// returns: 同 classify_restart_plan
|
|
265
|
+
/// errors: 计算过程中的错误以 LifecycleError 返回
|
|
266
|
+
/// contract_id: lifecycle.selection.classify_restart_plan
|
|
267
|
+
/// ---
|
|
196
268
|
pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
197
269
|
workspace: Option<&Path>,
|
|
198
270
|
state: &serde_json::Value,
|
|
@@ -1,5 +1,27 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 把 spec 与 runtime state 渲染成人读的 team_state.md
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: write_team_state
|
|
6
|
+
//! what: 按固定版式写出目标、成员、任务图、阻塞与下一步
|
|
7
|
+
//! depends:
|
|
8
|
+
//! - crate::model::yaml
|
|
9
|
+
//! - std::fs
|
|
10
|
+
//! boundary:
|
|
11
|
+
//! - 只渲染与落盘,不改 runtime state
|
|
12
|
+
//! - 版式与分节顺序是对外契约,不随手调整
|
|
13
|
+
//! maturity: wired
|
|
14
|
+
//! ---
|
|
1
15
|
use super::*;
|
|
2
16
|
|
|
17
|
+
/// ---
|
|
18
|
+
/// purpose: 渲染并写出 team_state.md
|
|
19
|
+
/// params:
|
|
20
|
+
/// spec: 提供团队名、目标、成员与兜底任务列表
|
|
21
|
+
/// state: 提供 session 名、leader 收件端、各席位状态与任务实况,任务以 state 为先
|
|
22
|
+
/// returns: 写出的文件路径,路径取 spec 的 context.state_file,缺省为 team_state.md
|
|
23
|
+
/// errors: 建目录或写文件失败时返回 StatePersist
|
|
24
|
+
/// ---
|
|
3
25
|
pub(crate) fn write_team_state(
|
|
4
26
|
workspace: &Path,
|
|
5
27
|
spec: &YamlValue,
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: restart 子模块的装配层,转出单席起停重置删、整队重建、plan halt 与 status
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: lifecycle_run_workspace
|
|
6
|
+
//! what: 把入参 workspace 归一成 canonical run workspace
|
|
7
|
+
//! - name: input_has_no_local_team_context
|
|
8
|
+
//! what: 入口早退门,判断给定目录附近有没有本地 team 上下文
|
|
9
|
+
//! depends:
|
|
10
|
+
//! - crate::model::paths
|
|
11
|
+
//! - crate::state::selector
|
|
12
|
+
//! - crate::state::persist
|
|
13
|
+
//! - crate::tmux_backend
|
|
14
|
+
//! boundary:
|
|
15
|
+
//! - 本文件只做装配与路径解析,真正的行为在 agent/rebuild/remove/selection 等子文件
|
|
16
|
+
//! - 不直接拼 provider 命令,也不直接操作 pane
|
|
17
|
+
//! maturity: wired
|
|
18
|
+
//! ---
|
|
1
19
|
//!
|
|
2
20
|
//! lifecycle::restart —— 单 worker 起/停/重置/删 + 整队 Route B 重建 + plan halt/status。
|
|
3
21
|
|
|
@@ -92,6 +110,11 @@ pub use selection::decide_start_mode;
|
|
|
92
110
|
pub(crate) use selection::classify_restart_plan_with_resume_validation;
|
|
93
111
|
pub(crate) use team_state::write_team_state;
|
|
94
112
|
|
|
113
|
+
/// ---
|
|
114
|
+
/// purpose: 把调用方给的 workspace 归一成 canonical run workspace
|
|
115
|
+
/// returns: 归一后的绝对路径
|
|
116
|
+
/// errors: 归一失败时返回 StatePersist
|
|
117
|
+
/// ---
|
|
95
118
|
pub(crate) fn lifecycle_run_workspace(
|
|
96
119
|
workspace: &Path,
|
|
97
120
|
) -> Result<std::path::PathBuf, LifecycleError> {
|
|
@@ -142,6 +165,12 @@ fn lifecycle_paths(workspace: &Path, team: Option<&str>) -> Result<LifecyclePath
|
|
|
142
165
|
})
|
|
143
166
|
}
|
|
144
167
|
|
|
168
|
+
/// ---
|
|
169
|
+
/// purpose: 判断给定目录既不含 team spec、也不含 .team、也不含 runtime state,且不在 .team 内外一层
|
|
170
|
+
/// params:
|
|
171
|
+
/// workspace: 已经过 canonical_run_workspace 归一的路径
|
|
172
|
+
/// returns: true 表示这里没有本地 team 上下文,调用方应早退
|
|
173
|
+
/// ---
|
|
145
174
|
pub(crate) fn input_has_no_local_team_context(workspace: &Path) -> bool {
|
|
146
175
|
!workspace.join("team.spec.yaml").exists()
|
|
147
176
|
&& !workspace.join(".team").exists()
|
|
@@ -393,7 +393,7 @@ fn write_min_team(ws: &Path, name: &str) -> PathBuf {
|
|
|
393
393
|
.unwrap();
|
|
394
394
|
std::fs::write(
|
|
395
395
|
team.join("agents/worker_a.md"),
|
|
396
|
-
"---\nname: worker_a\nrole: Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker.\n",
|
|
396
|
+
"---\nname: worker_a\nrole: Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker.\n",
|
|
397
397
|
)
|
|
398
398
|
.unwrap();
|
|
399
399
|
team
|
|
@@ -269,9 +269,8 @@ fn lanea_fork_agent_duplicate_target_is_already_exists_before_session_check() {
|
|
|
269
269
|
fork_agent(&ws, &aid("alpha"), &aid("bravo"), None, false, None)
|
|
270
270
|
);
|
|
271
271
|
assert!(
|
|
272
|
-
text.contains("
|
|
273
|
-
"
|
|
274
|
-
check (golden precedence, the first guard); the stub returns 'source session_id is missing'; got {text}"
|
|
272
|
+
text.contains("unverified") || text.contains("未验证") || text.contains("refuses --as"),
|
|
273
|
+
"codex fork is unverified in-window; duplicate --as is not reached. got {text}"
|
|
275
274
|
);
|
|
276
275
|
}
|
|
277
276
|
|
|
@@ -330,7 +329,7 @@ fn add_agent_joins_w2_into_running_roster_and_existing_session() {
|
|
|
330
329
|
let role_file = team_dir.join("w2-role.md");
|
|
331
330
|
std::fs::write(
|
|
332
331
|
&role_file,
|
|
333
|
-
"---\nname: w2\nrole: Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker two.\n",
|
|
332
|
+
"---\nname: w2\nrole: Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker two.\n",
|
|
334
333
|
)
|
|
335
334
|
.unwrap();
|
|
336
335
|
let transport = OfflineTransport::new().with_session_present(true);
|
|
@@ -528,7 +528,7 @@ fn write_team(workspace: &Path, fixture: &TeamFixture<'_>) -> PathBuf {
|
|
|
528
528
|
std::fs::write(
|
|
529
529
|
team.join("agents").join(format!("{}.md", agent.id)),
|
|
530
530
|
format!(
|
|
531
|
-
"---\nname: {}\nrole: {}\nprovider: {}\n{model}auth_mode: {}\n{profile}
|
|
531
|
+
"---\nname: {}\nrole: {}\nprovider: {}\n{model}auth_mode: {}\n{profile}dangerously_skip_permissions: false\ntools:\n{tools}---\n\n{}\n",
|
|
532
532
|
agent.id, agent.role, agent.provider, agent.auth_mode, agent.body
|
|
533
533
|
),
|
|
534
534
|
)
|
|
@@ -152,14 +152,14 @@ fn write_claude_profile_team(ws: &Path, team_key: &str, agent_id: &str) -> PathB
|
|
|
152
152
|
std::fs::write(
|
|
153
153
|
team.join("TEAM.md"),
|
|
154
154
|
format!(
|
|
155
|
-
"---\nname: {team_key}\nobjective: Claude compatible config contract.\nprovider: claude\nauth_mode: compatible_api\n---\n\nTeam.\n"
|
|
155
|
+
"---\nname: {team_key}\nobjective: Claude compatible config contract.\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
156
156
|
),
|
|
157
157
|
)
|
|
158
158
|
.unwrap();
|
|
159
159
|
std::fs::write(
|
|
160
160
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
161
161
|
format!(
|
|
162
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
162
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
163
163
|
),
|
|
164
164
|
)
|
|
165
165
|
.unwrap();
|
|
@@ -218,14 +218,14 @@ fn write_claude_profile_team(ws: &Path, team_key: &str, agent_id: &str) -> PathB
|
|
|
218
218
|
std::fs::write(
|
|
219
219
|
team.join("TEAM.md"),
|
|
220
220
|
format!(
|
|
221
|
-
"---\nname: {team_key}\nobjective: Claude compatible profile launch contract.\nprovider: claude\nauth_mode: compatible_api\n---\n\nTeam.\n"
|
|
221
|
+
"---\nname: {team_key}\nobjective: Claude compatible profile launch contract.\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
222
222
|
),
|
|
223
223
|
)
|
|
224
224
|
.unwrap();
|
|
225
225
|
std::fs::write(
|
|
226
226
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
227
227
|
format!(
|
|
228
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
228
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
229
229
|
),
|
|
230
230
|
)
|
|
231
231
|
.unwrap();
|
|
@@ -247,14 +247,14 @@ fn write_claude_subscription_profile_team(ws: &Path, team_key: &str, agent_id: &
|
|
|
247
247
|
std::fs::write(
|
|
248
248
|
team.join("TEAM.md"),
|
|
249
249
|
format!(
|
|
250
|
-
"---\nname: {team_key}\nobjective: Claude subscription profile launch contract.\nprovider: claude\nauth_mode: subscription\n---\n\nTeam.\n"
|
|
250
|
+
"---\nname: {team_key}\nobjective: Claude subscription profile launch contract.\nprovider: claude\nauth_mode: subscription\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
251
251
|
),
|
|
252
252
|
)
|
|
253
253
|
.unwrap();
|
|
254
254
|
std::fs::write(
|
|
255
255
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
256
256
|
format!(
|
|
257
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: subscription\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
257
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: subscription\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
258
258
|
),
|
|
259
259
|
)
|
|
260
260
|
.unwrap();
|