@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,32 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 冷启后把席位实况投影进 runtime state,并做团队级合并、投影与 owner 清洗
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: persist_spawn_agent_state
|
|
6
|
+
//! what: 按 spawn 结果与 tmux 实况写出各席位状态,分 running/paused/spawn_failed
|
|
7
|
+
//! - name: save_launched_team_state_for_key
|
|
8
|
+
//! what: 把本次团队状态并入既有 state,投影后经 repository 落盘
|
|
9
|
+
//! - name: merge_workspace_team_state_with_key
|
|
10
|
+
//! what: 以显式团队键把本次状态并进 teams 表,不丢既有团队
|
|
11
|
+
//! - name: drop_worker_pane_seeded_owner
|
|
12
|
+
//! what: 识别出被 worker pane 误种的 owner 并改种 unbound owner
|
|
13
|
+
//! depends:
|
|
14
|
+
//! - crate::state::repository
|
|
15
|
+
//! - crate::state::projection
|
|
16
|
+
//! - crate::state::persist
|
|
17
|
+
//! - crate::state::ownership
|
|
18
|
+
//! - crate::tmux_backend
|
|
19
|
+
//! - crate::lifecycle::launch::agent_state
|
|
20
|
+
//! - crate::lifecycle::launch::identity
|
|
21
|
+
//! - crate::lifecycle::launch::leader_context
|
|
22
|
+
//! - crate::lifecycle::launch::spec_state
|
|
23
|
+
//! - crate::lifecycle::launch::worker_env
|
|
24
|
+
//! boundary:
|
|
25
|
+
//! - 只写 state,不 spawn、不 kill、不开显示
|
|
26
|
+
//! - 落盘一律经 StateRepository 带写意图,不直接改文件
|
|
27
|
+
//! - owner 归属判不准时倒向 unbound,不认领他队的 pane
|
|
28
|
+
//! maturity: wired
|
|
29
|
+
//! ---
|
|
1
30
|
//!
|
|
2
31
|
use std::collections::{BTreeMap, BTreeSet};
|
|
3
32
|
use std::path::{Path, PathBuf};
|
|
@@ -21,6 +50,14 @@ use super::leader_context::{
|
|
|
21
50
|
use super::spec_state::{has_positive_caller_leader_env, spec_agent_values};
|
|
22
51
|
use super::worker_env::{agent_is_paused, spawn_timestamp_for_agent};
|
|
23
52
|
|
|
53
|
+
/// ---
|
|
54
|
+
/// purpose: 把本次 spawn 的结果写成 runtime state 里的各席位状态
|
|
55
|
+
/// params:
|
|
56
|
+
/// started: 本次 spawn 成功返回的席位
|
|
57
|
+
/// transport: 用于查活窗口与 pane pid
|
|
58
|
+
/// returns: 成功返回空值。spec 里 paused 的席位记 paused,spawn 后窗口不在的记 spawn_failed,其余记 running
|
|
59
|
+
/// errors: 读或写 runtime state 失败时返回 StatePersist
|
|
60
|
+
/// ---
|
|
24
61
|
pub(super) fn persist_spawn_agent_state(
|
|
25
62
|
workspace: &Path,
|
|
26
63
|
spec_path: &Path,
|
|
@@ -28,7 +65,6 @@ pub(super) fn persist_spawn_agent_state(
|
|
|
28
65
|
session_name: &SessionName,
|
|
29
66
|
transport: &dyn Transport,
|
|
30
67
|
started: &[StartedAgent],
|
|
31
|
-
safety: &DangerousApproval,
|
|
32
68
|
) -> Result<(), LifecycleError> {
|
|
33
69
|
let state_path = crate::state::persist::runtime_state_path(workspace);
|
|
34
70
|
let mut state = match crate::state::repository::StateRepository::new(workspace)
|
|
@@ -134,7 +170,6 @@ pub(super) fn persist_spawn_agent_state(
|
|
|
134
170
|
&team_id,
|
|
135
171
|
Some(agent_id_to_pane_id(started, id)),
|
|
136
172
|
pane_pid,
|
|
137
|
-
safety,
|
|
138
173
|
started_agent,
|
|
139
174
|
Some(&profile_dir),
|
|
140
175
|
)?,
|
|
@@ -150,6 +185,10 @@ pub(super) fn persist_spawn_agent_state(
|
|
|
150
185
|
save_launched_team_state_for_key(workspace, &state, Some(&team_id), None)
|
|
151
186
|
}
|
|
152
187
|
|
|
188
|
+
/// ---
|
|
189
|
+
/// purpose: 给出各已起席位对应 pane 的进程号
|
|
190
|
+
/// returns: agent_id 到 pane pid 的映射,查不到的席位不出现
|
|
191
|
+
/// ---
|
|
153
192
|
pub(super) fn pane_pids_by_started_agent(
|
|
154
193
|
transport: &dyn Transport,
|
|
155
194
|
started: &[StartedAgent],
|
|
@@ -167,6 +206,10 @@ pub(super) fn pane_pids_by_started_agent(
|
|
|
167
206
|
.collect()
|
|
168
207
|
}
|
|
169
208
|
|
|
209
|
+
/// ---
|
|
210
|
+
/// purpose: 由 agent id 找出它这次 spawn 的目标 pane
|
|
211
|
+
/// returns: 命中的 pane 串,找不到时为空串
|
|
212
|
+
/// ---
|
|
170
213
|
pub(super) fn agent_id_to_pane_id<'a>(started: &'a [StartedAgent], agent_id: &str) -> &'a str {
|
|
171
214
|
started
|
|
172
215
|
.iter()
|
|
@@ -175,6 +218,12 @@ pub(super) fn agent_id_to_pane_id<'a>(started: &'a [StartedAgent], agent_id: &st
|
|
|
175
218
|
.unwrap_or("")
|
|
176
219
|
}
|
|
177
220
|
|
|
221
|
+
/// ---
|
|
222
|
+
/// purpose: 不带显式团队键地保存本次团队状态
|
|
223
|
+
/// returns: 成功返回空值
|
|
224
|
+
/// errors: 落盘失败时返回 StatePersist
|
|
225
|
+
/// contract_id: lifecycle.state_projection.save_launched_team_state
|
|
226
|
+
/// ---
|
|
178
227
|
pub(super) fn save_launched_team_state(
|
|
179
228
|
workspace: &Path,
|
|
180
229
|
launched: &serde_json::Value,
|
|
@@ -182,6 +231,15 @@ pub(super) fn save_launched_team_state(
|
|
|
182
231
|
save_launched_team_state_for_key(workspace, launched, None, None)
|
|
183
232
|
}
|
|
184
233
|
|
|
234
|
+
/// ---
|
|
235
|
+
/// purpose: 保存本次团队状态的实体实现,含团队键钉死、owner 清洗、合并与投影
|
|
236
|
+
/// params:
|
|
237
|
+
/// team_key: 显式团队键,为空则由 state 推算
|
|
238
|
+
/// added_agent_id: 本次新增席位 id,写进写意图
|
|
239
|
+
/// returns: 成功返回空值
|
|
240
|
+
/// errors: 落盘失败时返回 StatePersist
|
|
241
|
+
/// contract_id: lifecycle.state_projection.save_launched_team_state
|
|
242
|
+
/// ---
|
|
185
243
|
pub(super) fn save_launched_team_state_for_key(
|
|
186
244
|
workspace: &Path,
|
|
187
245
|
launched: &serde_json::Value,
|
|
@@ -242,6 +300,11 @@ pub(super) fn save_launched_team_state_for_key(
|
|
|
242
300
|
.map_err(|e| LifecycleError::StatePersist(e.to_string()))
|
|
243
301
|
}
|
|
244
302
|
|
|
303
|
+
/// ---
|
|
304
|
+
/// purpose: 本次状态没写 leader 拓扑字段时,从既有状态里补回来
|
|
305
|
+
/// params:
|
|
306
|
+
/// launched: 就地补 is_external_leader 与 leader_client,已有同名键不覆盖
|
|
307
|
+
/// ---
|
|
245
308
|
pub(super) fn preserve_existing_leader_topology(
|
|
246
309
|
existing: &serde_json::Value,
|
|
247
310
|
launched_key: &str,
|
|
@@ -264,6 +327,11 @@ pub(super) fn preserve_existing_leader_topology(
|
|
|
264
327
|
}
|
|
265
328
|
}
|
|
266
329
|
|
|
330
|
+
/// ---
|
|
331
|
+
/// purpose: 无 leader 身份环境且 owner pane 形如首席 pane 时改种 unbound owner
|
|
332
|
+
/// params:
|
|
333
|
+
/// launched: 就地改写
|
|
334
|
+
/// ---
|
|
267
335
|
pub(super) fn drop_bare_worker_seeded_owner(launched: &mut serde_json::Value, launched_key: &str) {
|
|
268
336
|
if has_positive_caller_leader_env() {
|
|
269
337
|
return;
|
|
@@ -278,6 +346,10 @@ pub(super) fn drop_bare_worker_seeded_owner(launched: &mut serde_json::Value, la
|
|
|
278
346
|
}
|
|
279
347
|
}
|
|
280
348
|
|
|
349
|
+
/// ---
|
|
350
|
+
/// purpose: 以显式团队键把本次状态并进 teams 表
|
|
351
|
+
/// returns: 合并后的 state;既有顶层 session 名为空或团队键相同时保留既有 teams 并覆盖本键,否则以既有状态为底再补进本次团队
|
|
352
|
+
/// ---
|
|
281
353
|
pub(super) fn merge_workspace_team_state_with_key(
|
|
282
354
|
existing: &serde_json::Value,
|
|
283
355
|
launched: &serde_json::Value,
|
|
@@ -362,6 +434,11 @@ mod merge_workspace_team_state_with_key_tests {
|
|
|
362
434
|
}
|
|
363
435
|
}
|
|
364
436
|
|
|
437
|
+
/// ---
|
|
438
|
+
/// purpose: 把 teams 表里本团队的绑定字段提到顶层
|
|
439
|
+
/// params:
|
|
440
|
+
/// launched: 就地补 leader_receiver、team_owner 与 owner_epoch,已有同名键不覆盖
|
|
441
|
+
/// ---
|
|
365
442
|
pub(super) fn promote_launched_binding_from_team_entry(
|
|
366
443
|
launched: &mut serde_json::Value,
|
|
367
444
|
launched_key: &str,
|
|
@@ -385,6 +462,11 @@ pub(super) fn promote_launched_binding_from_team_entry(
|
|
|
385
462
|
}
|
|
386
463
|
}
|
|
387
464
|
|
|
465
|
+
/// ---
|
|
466
|
+
/// purpose: 顶层 owner 的 pane 不像真实 pane 时把顶层绑定字段整组删掉
|
|
467
|
+
/// params:
|
|
468
|
+
/// state: 就地删 leader_receiver、team_owner 与 owner_epoch
|
|
469
|
+
/// ---
|
|
388
470
|
pub(super) fn drop_unbound_top_level_owner(state: &mut serde_json::Value) {
|
|
389
471
|
let pane = state
|
|
390
472
|
.get("team_owner")
|
|
@@ -401,6 +483,12 @@ pub(super) fn drop_unbound_top_level_owner(state: &mut serde_json::Value) {
|
|
|
401
483
|
}
|
|
402
484
|
}
|
|
403
485
|
|
|
486
|
+
/// ---
|
|
487
|
+
/// purpose: 本次 owner 的 pane 已属于别的团队时,改种 unbound owner 或整组删除
|
|
488
|
+
/// params:
|
|
489
|
+
/// existing: 既有 state,用于判断 pane 归属
|
|
490
|
+
/// launched: 就地改写
|
|
491
|
+
/// ---
|
|
404
492
|
pub(super) fn drop_foreign_seeded_owner(
|
|
405
493
|
existing: &serde_json::Value,
|
|
406
494
|
launched_key: &str,
|
|
@@ -436,6 +524,13 @@ pub(super) fn drop_foreign_seeded_owner(
|
|
|
436
524
|
}
|
|
437
525
|
}
|
|
438
526
|
|
|
527
|
+
/// ---
|
|
528
|
+
/// purpose: 识别 owner 是被 worker 自己的 pane 误种的情形并改种 unbound owner
|
|
529
|
+
/// params:
|
|
530
|
+
/// started: 本次起的席位,用于判断 pane 是否属于 worker
|
|
531
|
+
/// worker_tmux_socket: worker 侧 socket 名,与调用方 socket 比对
|
|
532
|
+
/// returns: 只有在无 leader 身份环境、pane 与调用方 TMUX_PANE 相同且看起来是 worker pane 时才改种
|
|
533
|
+
/// ---
|
|
439
534
|
pub(super) fn drop_worker_pane_seeded_owner(
|
|
440
535
|
launched: &mut serde_json::Value,
|
|
441
536
|
launched_key: &str,
|
|
@@ -468,6 +563,10 @@ pub(super) fn drop_worker_pane_seeded_owner(
|
|
|
468
563
|
}
|
|
469
564
|
}
|
|
470
565
|
|
|
566
|
+
/// ---
|
|
567
|
+
/// purpose: 判断某 pane 是否像本次起的 worker 的 pane
|
|
568
|
+
/// returns: 形如首席 pane,或与任一席位目标互为前缀时为 true
|
|
569
|
+
/// ---
|
|
471
570
|
pub(super) fn seeded_pane_looks_like_worker(pane: &str, started: &[StartedAgent]) -> bool {
|
|
472
571
|
pane.ends_with("-first")
|
|
473
572
|
|| started.iter().any(|agent| {
|
|
@@ -477,6 +576,10 @@ pub(super) fn seeded_pane_looks_like_worker(pane: &str, started: &[StartedAgent]
|
|
|
477
576
|
})
|
|
478
577
|
}
|
|
479
578
|
|
|
579
|
+
/// ---
|
|
580
|
+
/// purpose: 给出 worker 侧使用的 tmux socket 名
|
|
581
|
+
/// returns: transport 是 tmux 后端时按 workspace 推出 socket 名,否则 None
|
|
582
|
+
/// ---
|
|
480
583
|
pub(super) fn launched_worker_tmux_socket(
|
|
481
584
|
transport: &dyn Transport,
|
|
482
585
|
workspace: &Path,
|
|
@@ -488,6 +591,10 @@ pub(super) fn launched_worker_tmux_socket(
|
|
|
488
591
|
}
|
|
489
592
|
}
|
|
490
593
|
|
|
594
|
+
/// ---
|
|
595
|
+
/// purpose: 判断两侧 socket 是否一致或不可判
|
|
596
|
+
/// returns: 两侧都已知时比相等;调用方已知而 worker 未知时为 false;调用方未知时一律为 true
|
|
597
|
+
/// ---
|
|
491
598
|
pub(super) fn tmux_sockets_match_or_unknown(
|
|
492
599
|
caller_socket: Option<&str>,
|
|
493
600
|
worker_socket: Option<&str>,
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: worker 进程的环境变量与 argv 占位符处理,以及各 provider 的角色注入落盘
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: inherited_env_with_team_overrides
|
|
6
|
+
//! what: 由当前进程环境按白名单派生 worker spawn 环境,并叠加 team 身份
|
|
7
|
+
//! - name: apply_mcp_auto_approval_env
|
|
8
|
+
//! what: 按 bypass 结论写或清 MCP 自动放行相关变量
|
|
9
|
+
//! - name: apply_copilot_instructions_overlay
|
|
10
|
+
//! what: 把角色提示词写成 per-agent 的 AGENTS.md 并指向它
|
|
11
|
+
//! - name: apply_cursor_agent_rules_overlay
|
|
12
|
+
//! what: 把角色提示词写成 workspace 内 per-agent 的 cursor rules 文件
|
|
13
|
+
//! - name: fill_spawn_placeholders_full
|
|
14
|
+
//! what: 替换 argv 里的 workspace、agent_id 与 team_id 占位符
|
|
15
|
+
//! depends:
|
|
16
|
+
//! - crate::layout::worker_env
|
|
17
|
+
//! - crate::event_log::EventLog
|
|
18
|
+
//! - crate::provider
|
|
19
|
+
//! - std::fs
|
|
20
|
+
//! boundary:
|
|
21
|
+
//! - 不写用户全局配置,角色注入一律落在 workspace 或 runtime 目录下的 per-agent 路径
|
|
22
|
+
//! - 环境里的代理与凭据值只允许记存在与长度,不落值
|
|
23
|
+
//! - 不 spawn 进程,只准备环境与 argv
|
|
24
|
+
//! maturity: wired
|
|
25
|
+
//! ---
|
|
1
26
|
use std::collections::{BTreeMap, BTreeSet};
|
|
2
27
|
use std::path::{Path, PathBuf};
|
|
3
28
|
use std::process::Command;
|
|
@@ -14,10 +39,18 @@ use crate::lifecycle::lock::{acquire_agent_lifecycle_lock, LifecycleLockRequest}
|
|
|
14
39
|
|
|
15
40
|
use super::*;
|
|
16
41
|
|
|
42
|
+
/// ---
|
|
43
|
+
/// purpose: 判断 spec 里的该 agent 是否被标为 paused
|
|
44
|
+
/// returns: paused 字段确为真时 true
|
|
45
|
+
/// ---
|
|
17
46
|
pub(super) fn agent_is_paused(agent: &Value) -> bool {
|
|
18
47
|
matches!(agent.get("paused"), Some(Value::Bool(true)))
|
|
19
48
|
}
|
|
20
49
|
|
|
50
|
+
/// ---
|
|
51
|
+
/// purpose: 给出 spawn 时间戳
|
|
52
|
+
/// returns: 测试固定时间戳环境变量优先,否则取当前 UTC 时间的微秒精度串
|
|
53
|
+
/// ---
|
|
21
54
|
pub(crate) fn spawn_timestamp() -> String {
|
|
22
55
|
match std::env::var("TEAM_AGENT_TEST_FIXED_SPAWNED_AT") {
|
|
23
56
|
Ok(value) => value,
|
|
@@ -27,6 +60,12 @@ pub(crate) fn spawn_timestamp() -> String {
|
|
|
27
60
|
}
|
|
28
61
|
}
|
|
29
62
|
|
|
63
|
+
/// ---
|
|
64
|
+
/// purpose: 给出带偏移的 spawn 时间戳,用于同批席位间保持先后次序
|
|
65
|
+
/// params:
|
|
66
|
+
/// offset_micros: 相对基准时间的微秒偏移,为 0 时等同 spawn_timestamp
|
|
67
|
+
/// returns: 固定时间戳可解析时加上偏移,否则原样返回固定值;无固定值时取当前时间
|
|
68
|
+
/// ---
|
|
30
69
|
pub(super) fn spawn_timestamp_for_agent(offset_micros: u32) -> String {
|
|
31
70
|
if offset_micros == 0 {
|
|
32
71
|
return spawn_timestamp();
|
|
@@ -44,10 +83,17 @@ pub(super) fn spawn_timestamp_for_agent(offset_micros: u32) -> String {
|
|
|
44
83
|
}
|
|
45
84
|
}
|
|
46
85
|
|
|
86
|
+
/// ---
|
|
87
|
+
/// purpose: 替换 argv 里的 workspace 与 agent_id 占位符,不带 team_id
|
|
88
|
+
/// ---
|
|
47
89
|
pub(crate) fn fill_spawn_placeholders(argv: &mut [String], workspace: &Path, agent_id: &str) {
|
|
48
90
|
fill_spawn_placeholders_full(argv, workspace, agent_id, None);
|
|
49
91
|
}
|
|
50
92
|
|
|
93
|
+
/// ---
|
|
94
|
+
/// purpose: 给出 auth_mode 写进环境变量时的稳定字符串
|
|
95
|
+
/// returns: subscription、official_api 或 compatible_api
|
|
96
|
+
/// ---
|
|
51
97
|
/// #229 B-layer worker env contract (`worker_spawn_inherits_parent_process_env_for_proxy_and_ca`):
|
|
52
98
|
/// every worker `transport.spawn_first/into` MUST receive an env map that is the **complete**
|
|
53
99
|
/// `team-agent` process environ (so the child sees the user's PATH ordering, HTTP_PROXY /
|
|
@@ -59,10 +105,26 @@ pub(crate) fn fill_spawn_placeholders(argv: &mut [String], workspace: &Path, age
|
|
|
59
105
|
///
|
|
60
106
|
/// `TMUX` / `TMUX_PANE` are stripped because they bind the inherited shell to the **launching**
|
|
61
107
|
/// tmux pane; leaving them in would point worker-side tmux integrations at the wrong pane.
|
|
108
|
+
pub(crate) fn auth_mode_env_value(mode: AuthMode) -> &'static str {
|
|
109
|
+
match mode {
|
|
110
|
+
AuthMode::Subscription => "subscription",
|
|
111
|
+
AuthMode::OfficialApi => "official_api",
|
|
112
|
+
AuthMode::CompatibleApi => "compatible_api",
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// ---
|
|
117
|
+
/// purpose: 由当前进程环境派生 worker 的 spawn 环境
|
|
118
|
+
/// params:
|
|
119
|
+
/// team_id: 作为 owner team id 重新注入给 worker
|
|
120
|
+
/// auth_mode: 写进环境的 auth_mode 字符串
|
|
121
|
+
/// returns: 白名单过滤后的环境,leader 身份类变量与 TMUX 绑定变量已被剥离
|
|
122
|
+
/// ---
|
|
62
123
|
pub(crate) fn inherited_env_with_team_overrides(
|
|
63
124
|
workspace: &Path,
|
|
64
125
|
agent_id: &str,
|
|
65
126
|
team_id: Option<&str>,
|
|
127
|
+
auth_mode: Option<&str>,
|
|
66
128
|
) -> BTreeMap<String, String> {
|
|
67
129
|
// 0.3.28 Step 3: delegate to `layout::worker_env::worker_spawn_env` which
|
|
68
130
|
// implements Python's whitelist semantics (`providers.py:130-145`). The
|
|
@@ -77,9 +139,22 @@ pub(crate) fn inherited_env_with_team_overrides(
|
|
|
77
139
|
// * Strips `COPILOT_DISABLE_TERMINAL_TITLE` (re-injected per-agent by
|
|
78
140
|
// `apply_copilot_instructions_overlay` based on the WORKER's provider).
|
|
79
141
|
// * Strips `TMUX` / `TMUX_PANE` (would attach worker to leader's pane).
|
|
80
|
-
crate::layout::worker_env::worker_spawn_env(
|
|
142
|
+
crate::layout::worker_env::worker_spawn_env(
|
|
143
|
+
std::env::vars(),
|
|
144
|
+
workspace,
|
|
145
|
+
agent_id,
|
|
146
|
+
team_id,
|
|
147
|
+
auth_mode,
|
|
148
|
+
)
|
|
81
149
|
}
|
|
82
150
|
|
|
151
|
+
/// ---
|
|
152
|
+
/// purpose: 按 bypass 结论设置或清除 MCP 自动放行相关环境变量
|
|
153
|
+
/// params:
|
|
154
|
+
/// env: 就地改写的环境表,六个相关键先被无条件清掉
|
|
155
|
+
/// safety: 只有来源为 leader 进程且确为继承而来时才写入放行变量
|
|
156
|
+
/// returns: 不满足条件时只写一个关闭标记
|
|
157
|
+
/// ---
|
|
83
158
|
pub(crate) fn apply_mcp_auto_approval_env(
|
|
84
159
|
env: &mut BTreeMap<String, String>,
|
|
85
160
|
safety: &DangerousApproval,
|
|
@@ -128,6 +203,14 @@ pub(crate) fn apply_mcp_auto_approval_env(
|
|
|
128
203
|
}
|
|
129
204
|
}
|
|
130
205
|
|
|
206
|
+
/// ---
|
|
207
|
+
/// purpose: 把角色提示词写进 per-agent 的 copilot 指令目录并指向它
|
|
208
|
+
/// params:
|
|
209
|
+
/// system_prompt: 写入 AGENTS.md 的正文
|
|
210
|
+
/// env: 就地写入指令目录与禁用终端标题的变量
|
|
211
|
+
/// returns: 成功返回空值
|
|
212
|
+
/// errors: 建目录或写文件失败时返回 StatePersist,不静默吞
|
|
213
|
+
/// ---
|
|
131
214
|
/// BUG / B2 灵魂件 + C-1-2 + C-6-1 cr verdict — Copilot per-worker AGENTS.md
|
|
132
215
|
/// 写入 + `COPILOT_CUSTOM_INSTRUCTIONS_DIRS` 注入。
|
|
133
216
|
///
|
|
@@ -172,6 +255,50 @@ pub(crate) fn apply_copilot_instructions_overlay(
|
|
|
172
255
|
Ok(())
|
|
173
256
|
}
|
|
174
257
|
|
|
258
|
+
/// ---
|
|
259
|
+
/// purpose: 把角色提示词写成 workspace 内 per-agent 的 cursor rules 文件
|
|
260
|
+
/// params:
|
|
261
|
+
/// system_prompt: 写入 rules 正文,文件头声明 alwaysApply
|
|
262
|
+
/// returns: 成功返回空值
|
|
263
|
+
/// errors: 建目录或写文件失败时返回 StatePersist
|
|
264
|
+
/// ---
|
|
265
|
+
/// 0.5.67 Cursor append-system-prompt 方案 1 变体(冒烟 PASS, see
|
|
266
|
+
/// .team/artifacts/0.5.67-cursor-rules-smoke.md)— Cursor `agent` CLI 无
|
|
267
|
+
/// append/rule CLI flag, 只从 workspace 静态 rules 文件读:
|
|
268
|
+
/// `.cursor/rules/**/*.mdc` (alwaysApply: true) / `AGENTS.md` / `.cursorrules`。
|
|
269
|
+
///
|
|
270
|
+
/// 这里在 launch 路径写 `<workspace>/.cursor/rules/team-agent-role-<agent_id>.mdc`
|
|
271
|
+
/// 并把 role(= compile_worker_system_prompt 输出)放进去, argv 只带
|
|
272
|
+
/// `--workspace <workspace>`(cursor_agent.rs)。cursor CLI 读取该目录即加载 role。
|
|
273
|
+
///
|
|
274
|
+
/// 目录布局为 workspace 内 `.cursor/rules/`(Cursor 唯一 rules 通道; 无法像 copilot
|
|
275
|
+
/// 那样放 `.team/runtime/` —— 那是 Cursor 不读的路径)。文件名含 `<agent_id>`
|
|
276
|
+
/// 保证 per-agent 隔离, 不互相污染。
|
|
277
|
+
pub(crate) fn apply_cursor_agent_rules_overlay(
|
|
278
|
+
workspace: &Path,
|
|
279
|
+
agent_id: &str,
|
|
280
|
+
system_prompt: &str,
|
|
281
|
+
) -> Result<(), LifecycleError> {
|
|
282
|
+
let dir = workspace.join(".cursor").join("rules");
|
|
283
|
+
std::fs::create_dir_all(&dir)
|
|
284
|
+
.map_err(|e| LifecycleError::StatePersist(format!("{}: {e}", dir.display())))?;
|
|
285
|
+
let rules = dir.join(format!("team-agent-role-{agent_id}.mdc"));
|
|
286
|
+
let content = format!(
|
|
287
|
+
"---\ndescription: Team Agent role injection (auto-generated)\nalwaysApply: true\n---\n\n{system_prompt}\n"
|
|
288
|
+
);
|
|
289
|
+
std::fs::write(&rules, content.as_bytes())
|
|
290
|
+
.map_err(|e| LifecycleError::StatePersist(format!("{}: {e}", rules.display())))?;
|
|
291
|
+
Ok(())
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/// ---
|
|
295
|
+
/// purpose: 扫出 copilot 侧残留的 MCP server,对非本框架的逐个追加禁用参数
|
|
296
|
+
/// params:
|
|
297
|
+
/// argv: 就地追加禁用参数
|
|
298
|
+
/// log_dir: 残留清单落盘目录
|
|
299
|
+
/// returns: 成功返回空值;copilot 命令不可用或退出码非零时只记录不阻断
|
|
300
|
+
/// errors: 写残留清单文件失败时返回 StatePersist
|
|
301
|
+
/// ---
|
|
175
302
|
/// C-3-2/C-3-3 cr verdict v2 — Copilot spawn 前调 `copilot mcp list` 扫用户全局
|
|
176
303
|
/// `~/.copilot/mcp-config.json` 与 workspace `.mcp.json` 的 MCP 残留;对每个非
|
|
177
304
|
/// `team_orchestrator` server 追加 `--disable-mcp-server <name>`(main-help:72-73)
|
|
@@ -246,6 +373,12 @@ pub(super) fn apply_copilot_mcp_residual_disables(
|
|
|
246
373
|
Ok(())
|
|
247
374
|
}
|
|
248
375
|
|
|
376
|
+
/// ---
|
|
377
|
+
/// purpose: 从 copilot mcp list 输出里解析 server 名集合
|
|
378
|
+
/// params:
|
|
379
|
+
/// text: 命令原始输出
|
|
380
|
+
/// returns: server 名列表;遇到无配置的提示行立即返回空;只在 servers 段内取缩进行首 token
|
|
381
|
+
/// ---
|
|
249
382
|
/// 解析 `copilot mcp list` 输出取 server 名集合(te 真机实证 v2,1.0.59 形态):
|
|
250
383
|
/// ```text
|
|
251
384
|
/// User servers:
|
|
@@ -318,6 +451,65 @@ pub(super) fn parse_copilot_mcp_list_server_names(text: &str) -> Vec<String> {
|
|
|
318
451
|
out
|
|
319
452
|
}
|
|
320
453
|
|
|
454
|
+
/// Subscription seats inherit parent env, but that is implicit. Cursor cloud
|
|
455
|
+
/// on this host is blocked without a proxy; `profile_launch` copies these
|
|
456
|
+
/// keys only on the compatible-api path. Copy them explicitly here so a
|
|
457
|
+
/// subscription cursor seat sees the same keys. Values may contain
|
|
458
|
+
/// credentials — callers must only log presence/length, never the value.
|
|
459
|
+
const CURSOR_PROXY_KEYS: &[&str] = &[
|
|
460
|
+
"HTTPS_PROXY",
|
|
461
|
+
"HTTP_PROXY",
|
|
462
|
+
"ALL_PROXY",
|
|
463
|
+
"NO_PROXY",
|
|
464
|
+
"https_proxy",
|
|
465
|
+
"http_proxy",
|
|
466
|
+
"all_proxy",
|
|
467
|
+
"no_proxy",
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
471
|
+
pub struct CursorProxyPresence {
|
|
472
|
+
pub https_proxy: bool,
|
|
473
|
+
pub no_proxy: bool,
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/// ---
|
|
477
|
+
/// purpose: 给订阅制 cursor 席位显式补上父进程里的代理变量
|
|
478
|
+
/// params:
|
|
479
|
+
/// env: 就地补键,已有同名键不覆盖
|
|
480
|
+
/// returns: 记录是否存在 https 代理与 no_proxy,只记存在与否不记值
|
|
481
|
+
/// ---
|
|
482
|
+
pub fn apply_cursor_subscription_proxy_env(
|
|
483
|
+
env: &mut BTreeMap<String, String>,
|
|
484
|
+
) -> CursorProxyPresence {
|
|
485
|
+
let mut https_proxy = false;
|
|
486
|
+
let mut no_proxy = false;
|
|
487
|
+
for key in CURSOR_PROXY_KEYS {
|
|
488
|
+
let Ok(value) = std::env::var(key) else {
|
|
489
|
+
continue;
|
|
490
|
+
};
|
|
491
|
+
if value.is_empty() {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
if key.eq_ignore_ascii_case("HTTPS_PROXY") {
|
|
495
|
+
https_proxy = true;
|
|
496
|
+
}
|
|
497
|
+
if key.eq_ignore_ascii_case("NO_PROXY") {
|
|
498
|
+
no_proxy = true;
|
|
499
|
+
}
|
|
500
|
+
env.entry((*key).to_string()).or_insert(value);
|
|
501
|
+
}
|
|
502
|
+
CursorProxyPresence {
|
|
503
|
+
https_proxy,
|
|
504
|
+
no_proxy,
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/// ---
|
|
509
|
+
/// purpose: 把 profile 推出的环境清除与覆盖套用到 spawn 环境上
|
|
510
|
+
/// params:
|
|
511
|
+
/// env: 先按 env_unset 删键,再并入 env_overlay
|
|
512
|
+
/// ---
|
|
321
513
|
pub(crate) fn apply_profile_launch_env(
|
|
322
514
|
env: &mut BTreeMap<String, String>,
|
|
323
515
|
profile_launch: &crate::provider::ProviderProfileLaunch,
|
|
@@ -328,6 +520,11 @@ pub(crate) fn apply_profile_launch_env(
|
|
|
328
520
|
env.extend(profile_launch.env_overlay.clone());
|
|
329
521
|
}
|
|
330
522
|
|
|
523
|
+
/// ---
|
|
524
|
+
/// purpose: 把已 spawn 席位的 profile 相关信息写进该席位的 state 节点
|
|
525
|
+
/// params:
|
|
526
|
+
/// state: 就地写入待定 session id、projects 根与 profile_launch 摘要
|
|
527
|
+
/// ---
|
|
331
528
|
pub(super) fn persist_started_agent_plan_state(
|
|
332
529
|
state: &mut serde_json::Map<String, serde_json::Value>,
|
|
333
530
|
started_agent: &StartedAgent,
|
|
@@ -362,6 +559,12 @@ pub(super) fn persist_started_agent_plan_state(
|
|
|
362
559
|
}
|
|
363
560
|
}
|
|
364
561
|
|
|
562
|
+
/// ---
|
|
563
|
+
/// purpose: 把命令计划与 profile 推出的信息写进该席位的 state 节点
|
|
564
|
+
/// params:
|
|
565
|
+
/// plan: 命令计划,其 projects 根优先于 profile 给出的
|
|
566
|
+
/// profile_launch: profile 推出的启动参数
|
|
567
|
+
/// ---
|
|
365
568
|
pub(crate) fn persist_command_plan_state(
|
|
366
569
|
state: &mut serde_json::Map<String, serde_json::Value>,
|
|
367
570
|
plan: &crate::provider::CommandPlan,
|
|
@@ -399,6 +602,10 @@ pub(crate) fn persist_command_plan_state(
|
|
|
399
602
|
}
|
|
400
603
|
}
|
|
401
604
|
|
|
605
|
+
/// ---
|
|
606
|
+
/// purpose: 判断名字是否是合法的 POSIX shell 标识符
|
|
607
|
+
/// returns: 首字符为字母或下划线且其余为字母数字下划线时为 true
|
|
608
|
+
/// ---
|
|
402
609
|
pub(super) fn is_posix_shell_identifier(name: &str) -> bool {
|
|
403
610
|
let mut chars = name.chars();
|
|
404
611
|
match chars.next() {
|
|
@@ -408,6 +615,12 @@ pub(super) fn is_posix_shell_identifier(name: &str) -> bool {
|
|
|
408
615
|
chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
|
|
409
616
|
}
|
|
410
617
|
|
|
618
|
+
/// ---
|
|
619
|
+
/// purpose: 替换 argv 里的 workspace、agent_id 与 team_id 占位符
|
|
620
|
+
/// params:
|
|
621
|
+
/// argv: 就地改写;整串等于占位符时整体替换,否则按子串替换
|
|
622
|
+
/// team_id: None 时按空串替换
|
|
623
|
+
/// ---
|
|
411
624
|
/// Same as [`fill_spawn_placeholders`] plus `{team_id}` substitution everywhere it
|
|
412
625
|
/// appears as a SUBSTRING (the MCP config encodes it as `mcp_servers.team_orchestrator
|
|
413
626
|
/// .env.TEAM_AGENT_OWNER_TEAM_ID="{team_id}"`, embedded inside `-c key=value` strings,
|