@team-agent/installer 0.5.66 → 0.5.69
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 +1 -0
- package/crates/team-agent/src/cli/adapters.rs +5 -0
- package/crates/team-agent/src/cli/diagnose.rs +156 -0
- package/crates/team-agent/src/cli/emit.rs +6 -5
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +22 -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 +3 -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/missing_subcommands.rs +129 -19
- 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/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler.rs +121 -5
- 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 +31 -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 +3 -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 +973 -75
- 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 +398 -26
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +80 -0
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +60 -0
- 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 +548 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp_iso.rs +120 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +208 -456
- 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 +482 -1
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +830 -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 +87 -3
- 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 +127 -25
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +140 -0
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -0
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +107 -29
- 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 +99 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +52 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +214 -160
- package/crates/team-agent/src/lifecycle/restart/common.rs +513 -37
- 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 +106 -0
- package/crates/team-agent/src/lifecycle/restart/remove.rs +233 -6
- 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/agent_ops.rs +2 -3
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +24 -3
- 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 +150 -157
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +464 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +247 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_list_models_g0.stdout.txt +222 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +787 -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 +485 -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 +1 -1
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +63 -38
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +16 -8
- 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 +20 -19
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +97 -61
- package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +97 -0
- package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +128 -0
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +207 -0
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +838 -0
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +320 -0
- package/crates/team-agent/src/lifecycle/tests/pi_lifecycle_doctor_red.rs +98 -0
- package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +216 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +40 -7
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +59 -1
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +30 -13
- package/crates/team-agent/src/lifecycle/types.rs +61 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +143 -12
- 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 +430 -41
- 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/mod.rs +1 -0
- package/crates/team-agent/src/messaging/types.rs +4 -1
- package/crates/team-agent/src/model/enums.rs +17 -6
- package/crates/team-agent/src/model/permissions.rs +3 -0
- package/crates/team-agent/src/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +259 -6
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +89 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +3 -0
- package/crates/team-agent/src/provider/adapters/pi.rs +152 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +47 -2
- 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 +11 -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 +78 -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 +205 -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/pi.rs +172 -0
- package/crates/team-agent/src/provider/session_scan.rs +12 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +384 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +29 -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 +1116 -75
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +248 -1
- package/npm/install.mjs +129 -73
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +32 -239
- package/skills/team-agent/command-coverage.json +31 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -488
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 冷启路径的 worker spawn 执行器,按 spec 逐个起席并汇总启动结果
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: spawn_agents
|
|
6
|
+
//! what: 按 spec 顺序起各非 paused 席位,返回已起席位清单
|
|
7
|
+
//! - name: agent_id_spec_source_path
|
|
8
|
+
//! what: 尽力还原某席位角色文档的路径,用于审计事件
|
|
9
|
+
//! depends:
|
|
10
|
+
//! - crate::transport::Transport
|
|
11
|
+
//! - crate::provider
|
|
12
|
+
//! - crate::state::persist
|
|
13
|
+
//! - crate::lifecycle::profile_launch
|
|
14
|
+
//! - crate::lifecycle::worker_command_context
|
|
15
|
+
//! boundary:
|
|
16
|
+
//! - 只负责起席与收集结果,state 落盘由 state_projection 负责
|
|
17
|
+
//! - 启动提示按掉与 fast 模式启用都是尽力而为,失败不阻断
|
|
18
|
+
//! maturity: wired
|
|
19
|
+
//! ---
|
|
1
20
|
//!
|
|
2
21
|
//! unit-8 (Stage 3) — `lifecycle::launch::spawn` phase boundary.
|
|
3
22
|
//!
|
|
@@ -22,6 +41,14 @@ use crate::lifecycle::lock::{acquire_agent_lifecycle_lock, LifecycleLockRequest}
|
|
|
22
41
|
|
|
23
42
|
use super::*;
|
|
24
43
|
|
|
44
|
+
/// ---
|
|
45
|
+
/// purpose: 按 spec 顺序起各席位
|
|
46
|
+
/// params:
|
|
47
|
+
/// spec_path: spec 路径,team 目录优先取 state 里的 team_dir
|
|
48
|
+
/// session_name: 目标 tmux session
|
|
49
|
+
/// returns: 已起席位清单,含目标 pane、启动模式、布局与显示信息;spawn 后 pane 已死的席位被跳过
|
|
50
|
+
/// errors: 命令拼装或 transport spawn 失败时返回 LifecycleError
|
|
51
|
+
/// ---
|
|
25
52
|
pub(super) fn spawn_agents(
|
|
26
53
|
workspace: &Path,
|
|
27
54
|
spec_path: &Path,
|
|
@@ -108,12 +135,16 @@ pub(super) fn spawn_agents(
|
|
|
108
135
|
.mcp_config(auth_mode)
|
|
109
136
|
.map_err(|e| LifecycleError::Provider(e.to_string()))?;
|
|
110
137
|
let mcp_config = resolve_mcp_config(mcp_config, workspace, agent_id_raw, &mcp_team_id);
|
|
111
|
-
let mcp_config_path =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
let mcp_config_path = if provider == Provider::Pi {
|
|
139
|
+
None
|
|
140
|
+
} else {
|
|
141
|
+
Some(write_worker_mcp_config_for_provider(
|
|
142
|
+
workspace,
|
|
143
|
+
agent_id_raw,
|
|
144
|
+
&mcp_config,
|
|
145
|
+
Some(provider),
|
|
146
|
+
)?)
|
|
147
|
+
};
|
|
117
148
|
let profile_dir = team_dir.join("profiles");
|
|
118
149
|
let profile_launch =
|
|
119
150
|
crate::lifecycle::profile_launch::prepare_provider_profile_launch_with_profile_dir(
|
|
@@ -132,24 +163,54 @@ pub(super) fn spawn_agents(
|
|
|
132
163
|
let _ = crate::event_log::EventLog::new(workspace)
|
|
133
164
|
.write("provider.effort_unsupported", event_value);
|
|
134
165
|
}
|
|
135
|
-
let
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
.
|
|
166
|
+
let command_context = crate::provider::ProviderCommandContext {
|
|
167
|
+
auth_mode,
|
|
168
|
+
mcp_config: Some(&mcp_config),
|
|
169
|
+
system_prompt: Some(system_prompt.as_str()),
|
|
170
|
+
model: command_model,
|
|
171
|
+
tools: &resolved_tool_refs,
|
|
172
|
+
profile_launch: Some(&profile_launch),
|
|
173
|
+
// Layer 1 self-healing (architect probe 2026-06-22): expose
|
|
174
|
+
// agent_id as a display-name hint so Claude / Copilot
|
|
175
|
+
// adapters can pass `--name <agent_id>`. Codex has no
|
|
176
|
+
// equivalent flag and ignores the hint.
|
|
177
|
+
agent_id_hint: Some(agent_id_raw),
|
|
178
|
+
effort: agent_effort,
|
|
179
|
+
};
|
|
180
|
+
let mut plan = if provider == Provider::Pi {
|
|
181
|
+
let model = command_model.ok_or_else(|| {
|
|
182
|
+
LifecycleError::RequirementUnmet(
|
|
183
|
+
"Pi launch requires an explicit qualified model".to_string(),
|
|
184
|
+
)
|
|
185
|
+
})?;
|
|
186
|
+
let effort = agent_effort.ok_or_else(|| {
|
|
187
|
+
LifecycleError::RequirementUnmet(
|
|
188
|
+
"Pi launch requires an explicit thinking effort".to_string(),
|
|
189
|
+
)
|
|
190
|
+
})?;
|
|
191
|
+
crate::lifecycle::launch::pi_mcp::materialize_pi_plan(
|
|
192
|
+
crate::lifecycle::launch::pi_mcp::PiMaterializeRequest {
|
|
193
|
+
workspace,
|
|
194
|
+
team_id: &mcp_team_id,
|
|
195
|
+
agent_id: agent_id_raw,
|
|
196
|
+
model,
|
|
197
|
+
effort,
|
|
198
|
+
system_prompt: &system_prompt,
|
|
199
|
+
tool_categories: &resolved_tool_refs,
|
|
200
|
+
team_mcp_tools: &["send_message", "report_result"],
|
|
201
|
+
mcp_config: &mcp_config,
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
.map_err(|e| LifecycleError::Provider(e.to_string()))?
|
|
205
|
+
} else {
|
|
206
|
+
adapter
|
|
207
|
+
.build_command_plan(command_context)
|
|
208
|
+
.map_err(|e| LifecycleError::Provider(e.to_string()))?
|
|
209
|
+
};
|
|
151
210
|
if !plan.managed_mcp_config && !profile_launch.managed_mcp_config {
|
|
152
|
-
|
|
211
|
+
if let Some(mcp_config_path) = mcp_config_path.as_ref() {
|
|
212
|
+
point_native_mcp_config_at_file(&mut plan.argv, provider, mcp_config_path);
|
|
213
|
+
}
|
|
153
214
|
}
|
|
154
215
|
// C-A-4 cr verdict v2 — Copilot BYOK(compatible_api)硬性校验:
|
|
155
216
|
// "A model is required for BYOK"(help-providers 原文)。检查 agent
|
|
@@ -207,8 +268,12 @@ pub(super) fn spawn_agents(
|
|
|
207
268
|
)?;
|
|
208
269
|
}
|
|
209
270
|
fill_spawn_placeholders_full(&mut plan.argv, workspace, agent_id_raw, Some(&mcp_team_id));
|
|
210
|
-
let mut env =
|
|
211
|
-
|
|
271
|
+
let mut env = inherited_env_with_team_overrides(
|
|
272
|
+
workspace,
|
|
273
|
+
agent_id_raw,
|
|
274
|
+
Some(&mcp_team_id),
|
|
275
|
+
Some(auth_mode_env_value(auth_mode)),
|
|
276
|
+
);
|
|
212
277
|
apply_profile_launch_env(&mut env, &profile_launch);
|
|
213
278
|
apply_mcp_auto_approval_env(&mut env, &safety);
|
|
214
279
|
// Python providers.py:145 + launch/core.py:253 — fresh launch runs the worker
|
|
@@ -256,6 +321,39 @@ pub(super) fn spawn_agents(
|
|
|
256
321
|
);
|
|
257
322
|
}
|
|
258
323
|
}
|
|
324
|
+
// Cursor: role 经 .cursor/rules。MCP 身份默认写 provider-config/<id>/cursor
|
|
325
|
+
// (不继承父进程 TEAM_AGENT_*)。--workspace 指该工程根,--add-dir 真 workspace。
|
|
326
|
+
// 隔离关闭时仍拒绝第二席(共用 mcp.json last-writer)。不改 HOME。
|
|
327
|
+
if matches!(provider, Provider::CursorAgent) {
|
|
328
|
+
refuse_second_cursor_occupant(workspace, agent_id_raw, Some(spec))?;
|
|
329
|
+
apply_cursor_agent_rules_overlay(workspace, agent_id_raw, system_prompt.as_str())?;
|
|
330
|
+
apply_cursor_mcp_overlay(workspace, &mcp_config)?;
|
|
331
|
+
let project = if crate::lifecycle::launch::cursor_mcp_isolation_enabled() {
|
|
332
|
+
Some(crate::lifecycle::launch::cursor_mcp_project_dir(
|
|
333
|
+
workspace,
|
|
334
|
+
agent_id_raw,
|
|
335
|
+
)?)
|
|
336
|
+
} else {
|
|
337
|
+
None
|
|
338
|
+
};
|
|
339
|
+
enable_cursor_workspace_mcp(workspace, project.as_deref())?;
|
|
340
|
+
apply_cursor_spawn_workspace_pointers(&mut plan.argv, workspace, agent_id_raw)?;
|
|
341
|
+
let proxy = apply_cursor_subscription_proxy_env(&mut env);
|
|
342
|
+
let event_log = crate::event_log::EventLog::new(workspace);
|
|
343
|
+
let _ = event_log.write(
|
|
344
|
+
"provider.cursor.proxy_presence",
|
|
345
|
+
serde_json::json!({
|
|
346
|
+
"agent_id": agent_id_raw,
|
|
347
|
+
"https_proxy": proxy.https_proxy,
|
|
348
|
+
"no_proxy": proxy.no_proxy,
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
// Grok 无 --mcp-config;写 <cwd>/.grok/config.toml 让 CLI 读到 team-agent。
|
|
353
|
+
if matches!(provider, Provider::Grok) {
|
|
354
|
+
ensure_grok_login_and_folder_trust(workspace)?;
|
|
355
|
+
apply_grok_mcp_overlay(workspace, &mcp_config)?;
|
|
356
|
+
}
|
|
259
357
|
let spawn_epoch = u64::try_from(started.len()).unwrap_or(u64::MAX);
|
|
260
358
|
let spawned_at = spawn_timestamp_for_agent(u32::try_from(spawn_epoch).unwrap_or(u32::MAX));
|
|
261
359
|
// E6 层1 实证3 + 诊断留痕:落最终 worker argv(spawn 前的真实形态)。
|
|
@@ -401,6 +499,10 @@ pub(super) fn spawn_agents(
|
|
|
401
499
|
Ok(started)
|
|
402
500
|
}
|
|
403
501
|
|
|
502
|
+
/// ---
|
|
503
|
+
/// purpose: 尽力还原某席位角色文档的路径
|
|
504
|
+
/// returns: state 里有 team_dir 时用它下的 agents 目录,否则退到 workspace 下的当前团队目录
|
|
505
|
+
/// ---
|
|
404
506
|
/// 0.5.66 bypass 单源 §2.7:审计事件里角色 md 的 spec 来源路径(尽力解析,失败空串)。
|
|
405
507
|
pub(crate) fn agent_id_spec_source_path(workspace: &Path, agent_id: &str) -> String {
|
|
406
508
|
let team_dir = crate::state::persist::load_runtime_state(workspace)
|
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: spec 的读取改写与 runtime state 初值物化,含 quick-start 的 owner 种入
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: initial_runtime_state
|
|
6
|
+
//! what: 由 spec 生成首份 runtime state 树,并种入 launched owner
|
|
7
|
+
//! - name: write_spec_atomic
|
|
8
|
+
//! what: 先写同目录临时文件再 rename,避免留下半截 spec
|
|
9
|
+
//! - name: spec_session_name
|
|
10
|
+
//! what: 取 runtime.session_name,缺省由 team 名派生
|
|
11
|
+
//! - name: spec_agents
|
|
12
|
+
//! what: 取 spec 里全部 agent id
|
|
13
|
+
//! - name: spec_routes
|
|
14
|
+
//! what: 对 spec 里每个 task 算出路由决策
|
|
15
|
+
//! - name: effective_runtime_config_for_worker_spawn
|
|
16
|
+
//! what: 由单个 agent 的 dangerously_skip_permissions 定出 bypass 审批结论
|
|
17
|
+
//! depends:
|
|
18
|
+
//! - crate::state::projection
|
|
19
|
+
//! - crate::state::identity
|
|
20
|
+
//! - crate::state::ownership
|
|
21
|
+
//! - crate::model::yaml
|
|
22
|
+
//! - crate::model::routing
|
|
23
|
+
//! - crate::provider::bypass_flags
|
|
24
|
+
//! - crate::lifecycle::launch::identity
|
|
25
|
+
//! - crate::lifecycle::launch::leader_context
|
|
26
|
+
//! - crate::lifecycle::launch::worker_env
|
|
27
|
+
//! boundary:
|
|
28
|
+
//! - 只生成与改写数据,不 spawn 进程也不开显示
|
|
29
|
+
//! - bypass 只认单个 agent 自己的声明,不从 runtime 配置或 leader argv 全队继承
|
|
30
|
+
//! - spec 写盘一律走原子替换,不做就地截断写
|
|
31
|
+
//! maturity: wired
|
|
32
|
+
//! ---
|
|
1
33
|
//!
|
|
2
34
|
//! unit-8 (Stage 3) — `lifecycle::launch::spec_state` phase boundary.
|
|
3
35
|
//!
|
|
@@ -40,6 +72,12 @@ use super::leader_context::{
|
|
|
40
72
|
};
|
|
41
73
|
use super::worker_env::spawn_timestamp;
|
|
42
74
|
|
|
75
|
+
/// ---
|
|
76
|
+
/// purpose: 由 spec 生成首份 runtime state 树
|
|
77
|
+
/// params:
|
|
78
|
+
/// team_key: 本团队的 runtime 键
|
|
79
|
+
/// returns: 含 spec_path、workspace、team_dir、session_name、leader、agents、tasks 与 display_backend 的 state;随后按环境种入 launched owner,种不到则种一份 unbound owner
|
|
80
|
+
/// ---
|
|
43
81
|
pub(super) fn initial_runtime_state(
|
|
44
82
|
spec: &Value,
|
|
45
83
|
spec_path: &Path,
|
|
@@ -113,6 +151,12 @@ pub(super) fn initial_runtime_state(
|
|
|
113
151
|
state
|
|
114
152
|
}
|
|
115
153
|
|
|
154
|
+
/// ---
|
|
155
|
+
/// purpose: 从环境里的 caller 身份种入 launched owner
|
|
156
|
+
/// params:
|
|
157
|
+
/// state: 待改写的 state,成功时写入 owner 与 leader receiver
|
|
158
|
+
/// returns: true 表示已种入,取不到 caller 身份或无 pane 时为 false
|
|
159
|
+
/// ---
|
|
116
160
|
pub(super) fn seed_launched_owner_from_env(state: &mut serde_json::Value) -> bool {
|
|
117
161
|
let team_id = crate::state::projection::team_state_key(state);
|
|
118
162
|
let Ok(caller) = crate::state::identity::caller_identity_from_env(
|
|
@@ -130,6 +174,13 @@ pub(super) fn seed_launched_owner_from_env(state: &mut serde_json::Value) -> boo
|
|
|
130
174
|
)
|
|
131
175
|
}
|
|
132
176
|
|
|
177
|
+
/// ---
|
|
178
|
+
/// purpose: 用给定的 caller 身份与 pane provider 查询函数种入 owner 与 leader receiver
|
|
179
|
+
/// params:
|
|
180
|
+
/// caller: 调用方身份,pane_id 为空则不种
|
|
181
|
+
/// lookup_pane_provider: 由 pane 反查 provider 的函数,便于测试替换
|
|
182
|
+
/// returns: true 表示已写入 owner 记录
|
|
183
|
+
/// ---
|
|
133
184
|
pub(super) fn seed_launched_owner_from_caller_with_provider_lookup(
|
|
134
185
|
state: &mut serde_json::Value,
|
|
135
186
|
caller: crate::state::owner_gate::CallerIdentity,
|
|
@@ -186,6 +237,10 @@ pub(super) fn seed_launched_owner_from_caller_with_provider_lookup(
|
|
|
186
237
|
true
|
|
187
238
|
}
|
|
188
239
|
|
|
240
|
+
/// ---
|
|
241
|
+
/// purpose: 判断环境里是否带有任一 leader 身份变量
|
|
242
|
+
/// returns: pane id、session uuid、其 override 或 provider 任一非空即 true
|
|
243
|
+
/// ---
|
|
189
244
|
pub(super) fn has_positive_caller_leader_env() -> bool {
|
|
190
245
|
env_nonempty("TEAM_AGENT_LEADER_PANE_ID")
|
|
191
246
|
|| env_nonempty("TEAM_AGENT_LEADER_SESSION_UUID")
|
|
@@ -193,12 +248,20 @@ pub(super) fn has_positive_caller_leader_env() -> bool {
|
|
|
193
248
|
|| env_nonempty("TEAM_AGENT_LEADER_PROVIDER")
|
|
194
249
|
}
|
|
195
250
|
|
|
251
|
+
/// ---
|
|
252
|
+
/// purpose: 判断某环境变量存在且非空
|
|
253
|
+
/// returns: 存在且非空为 true
|
|
254
|
+
/// ---
|
|
196
255
|
pub(super) fn env_nonempty(key: &str) -> bool {
|
|
197
256
|
std::env::var(key)
|
|
198
257
|
.ok()
|
|
199
258
|
.is_some_and(|value| !value.is_empty())
|
|
200
259
|
}
|
|
201
260
|
|
|
261
|
+
/// ---
|
|
262
|
+
/// purpose: 把 spec 的 tasks 列表转成 JSON 数组
|
|
263
|
+
/// returns: 转换后的数组,没有 tasks 时为空数组
|
|
264
|
+
/// ---
|
|
202
265
|
pub(super) fn spec_tasks_json(spec: &Value) -> serde_json::Value {
|
|
203
266
|
spec.get("tasks")
|
|
204
267
|
.and_then(Value::as_list)
|
|
@@ -206,6 +269,10 @@ pub(super) fn spec_tasks_json(spec: &Value) -> serde_json::Value {
|
|
|
206
269
|
.unwrap_or_else(|| serde_json::json!([]))
|
|
207
270
|
}
|
|
208
271
|
|
|
272
|
+
/// ---
|
|
273
|
+
/// purpose: 把 YAML 值递归转成等价 JSON 值
|
|
274
|
+
/// returns: 结构与标量一一对应的 JSON
|
|
275
|
+
/// ---
|
|
209
276
|
pub(super) fn yaml_value_to_json(value: &Value) -> serde_json::Value {
|
|
210
277
|
match value {
|
|
211
278
|
Value::Null => serde_json::Value::Null,
|
|
@@ -226,6 +293,11 @@ pub(super) fn yaml_value_to_json(value: &Value) -> serde_json::Value {
|
|
|
226
293
|
}
|
|
227
294
|
}
|
|
228
295
|
|
|
296
|
+
/// ---
|
|
297
|
+
/// purpose: 原子写 spec,先写带进程号后缀的临时文件再 rename 覆盖
|
|
298
|
+
/// returns: 成功返回空值
|
|
299
|
+
/// errors: 建父目录、写临时文件或 rename 失败时返回 StatePersist;rename 失败会删掉临时文件且原 spec 不动
|
|
300
|
+
/// ---
|
|
229
301
|
///
|
|
230
302
|
/// Set `runtime.session_name` on the compiled spec to `session_name`, creating the
|
|
231
303
|
/// `runtime` map and/or the `session_name` entry if absent. Used by quick-start to
|
|
@@ -252,10 +324,18 @@ pub(crate) fn write_spec_atomic(spec_path: &Path, spec: &Value) -> Result<(), Li
|
|
|
252
324
|
Ok(())
|
|
253
325
|
}
|
|
254
326
|
|
|
327
|
+
/// ---
|
|
328
|
+
/// purpose: 就地把 spec 的 runtime.session_name 改成给定值
|
|
329
|
+
/// ---
|
|
255
330
|
pub(crate) fn override_spec_session_name(spec: &mut Value, session_name: &str) {
|
|
256
331
|
override_spec_runtime_str(spec, "session_name", session_name);
|
|
257
332
|
}
|
|
258
333
|
|
|
334
|
+
/// ---
|
|
335
|
+
/// purpose: 就地把 spec 里 team.workspace 与各 agent 的 working_directory 改成给定路径
|
|
336
|
+
/// params:
|
|
337
|
+
/// spec: 非 Map 时不动;只改已存在的字段,不新建
|
|
338
|
+
/// ---
|
|
259
339
|
pub(crate) fn override_spec_workspace(spec: &mut Value, workspace: &Path) {
|
|
260
340
|
let workspace_s = workspace.to_string_lossy().to_string();
|
|
261
341
|
let Value::Map(root) = spec else { return };
|
|
@@ -276,10 +356,19 @@ pub(crate) fn override_spec_workspace(spec: &mut Value, workspace: &Path) {
|
|
|
276
356
|
}
|
|
277
357
|
}
|
|
278
358
|
|
|
359
|
+
/// ---
|
|
360
|
+
/// purpose: 就地把 spec 的 runtime.display_backend 改成给定值
|
|
361
|
+
/// ---
|
|
279
362
|
pub(super) fn override_spec_display_backend(spec: &mut Value, display_backend: &str) {
|
|
280
363
|
override_spec_runtime_str(spec, "display_backend", display_backend);
|
|
281
364
|
}
|
|
282
365
|
|
|
366
|
+
/// ---
|
|
367
|
+
/// purpose: 就地写 spec 的 runtime 段下某个字符串字段
|
|
368
|
+
/// params:
|
|
369
|
+
/// spec: 非 Map 时不动
|
|
370
|
+
/// returns: runtime 段缺失则新建,已存在同名键则覆盖,runtime 是非 Map 值则整段替换
|
|
371
|
+
/// ---
|
|
283
372
|
pub(super) fn override_spec_runtime_str(spec: &mut Value, key: &str, value: &str) {
|
|
284
373
|
let Value::Map(root) = spec else { return };
|
|
285
374
|
let runtime_slot = root
|
|
@@ -306,6 +395,10 @@ pub(super) fn override_spec_runtime_str(spec: &mut Value, key: &str, value: &str
|
|
|
306
395
|
}
|
|
307
396
|
}
|
|
308
397
|
|
|
398
|
+
/// ---
|
|
399
|
+
/// purpose: 定出本 spec 的 tmux session 名
|
|
400
|
+
/// returns: runtime.session_name 的非空值;缺失时由 team.name 派生,team 名也缺失时用 agent 兜底
|
|
401
|
+
/// ---
|
|
309
402
|
pub(super) fn spec_session_name(spec: &Value) -> SessionName {
|
|
310
403
|
if let Some(name) = spec
|
|
311
404
|
.get("runtime")
|
|
@@ -325,6 +418,10 @@ pub(super) fn spec_session_name(spec: &Value) -> SessionName {
|
|
|
325
418
|
SessionName::new(format!("team-{team_name}"))
|
|
326
419
|
}
|
|
327
420
|
|
|
421
|
+
/// ---
|
|
422
|
+
/// purpose: 把 spec_session_name 以更宽可见性转出,供 layout 复用同一份实现
|
|
423
|
+
/// returns: 同 spec_session_name
|
|
424
|
+
/// ---
|
|
328
425
|
///
|
|
329
426
|
/// 0.3.28 layout step 1: pub re-export of `spec_session_name` for the new
|
|
330
427
|
/// `layout::sessions::worker_session_name` to delegate to. Single underlying
|
|
@@ -333,6 +430,10 @@ pub fn worker_session_name_pub(spec: &Value) -> SessionName {
|
|
|
333
430
|
spec_session_name(spec)
|
|
334
431
|
}
|
|
335
432
|
|
|
433
|
+
/// ---
|
|
434
|
+
/// purpose: 取出 spec 里全部 agent id
|
|
435
|
+
/// returns: 按 spec 顺序的 agent id,无 id 字段的条目被跳过
|
|
436
|
+
/// ---
|
|
336
437
|
pub(super) fn spec_agents(spec: &Value) -> Vec<AgentId> {
|
|
337
438
|
spec_agent_values(spec)
|
|
338
439
|
.into_iter()
|
|
@@ -340,6 +441,10 @@ pub(super) fn spec_agents(spec: &Value) -> Vec<AgentId> {
|
|
|
340
441
|
.collect()
|
|
341
442
|
}
|
|
342
443
|
|
|
444
|
+
/// ---
|
|
445
|
+
/// purpose: 取出 spec 里全部 agent id 的集合,便于成员判定
|
|
446
|
+
/// returns: 有序集合
|
|
447
|
+
/// ---
|
|
343
448
|
///
|
|
344
449
|
/// Bug 1 (0.4.2): expose spec agent id set so the restart path can filter
|
|
345
450
|
/// state.agents to only the agents currently defined in the rebuilt spec.
|
|
@@ -351,6 +456,10 @@ pub(crate) fn spec_agent_id_set(spec: &Value) -> std::collections::BTreeSet<Stri
|
|
|
351
456
|
.collect()
|
|
352
457
|
}
|
|
353
458
|
|
|
459
|
+
/// ---
|
|
460
|
+
/// purpose: 取出 spec 的 agents 列表原始节点
|
|
461
|
+
/// returns: 节点引用列表,字段缺失或类型不对时为空
|
|
462
|
+
/// ---
|
|
354
463
|
pub(super) fn spec_agent_values(spec: &Value) -> Vec<&Value> {
|
|
355
464
|
spec.get("agents")
|
|
356
465
|
.and_then(Value::as_list)
|
|
@@ -358,6 +467,10 @@ pub(super) fn spec_agent_values(spec: &Value) -> Vec<&Value> {
|
|
|
358
467
|
.unwrap_or_default()
|
|
359
468
|
}
|
|
360
469
|
|
|
470
|
+
/// ---
|
|
471
|
+
/// purpose: 对 spec 里每个 task 算出路由决策
|
|
472
|
+
/// returns: 每个 task 的选中 agent 与理由,manual_override 恒为 false
|
|
473
|
+
/// ---
|
|
361
474
|
pub(super) fn spec_routes(spec: &Value) -> Vec<RoutingDecision> {
|
|
362
475
|
spec.get("tasks")
|
|
363
476
|
.and_then(Value::as_list)
|
|
@@ -378,6 +491,10 @@ pub(super) fn spec_routes(spec: &Value) -> Vec<RoutingDecision> {
|
|
|
378
491
|
.unwrap_or_default()
|
|
379
492
|
}
|
|
380
493
|
|
|
494
|
+
/// ---
|
|
495
|
+
/// purpose: 定出默认承接人
|
|
496
|
+
/// returns: routing.default_assignee,缺失时取第一个 agent
|
|
497
|
+
/// ---
|
|
381
498
|
pub(super) fn spec_default_assignee(spec: &Value) -> Option<AgentId> {
|
|
382
499
|
spec.get("routing")
|
|
383
500
|
.and_then(|v| v.get("default_assignee"))
|
|
@@ -386,6 +503,12 @@ pub(super) fn spec_default_assignee(spec: &Value) -> Option<AgentId> {
|
|
|
386
503
|
.or_else(|| spec_agents(spec).into_iter().next())
|
|
387
504
|
}
|
|
388
505
|
|
|
506
|
+
/// ---
|
|
507
|
+
/// purpose: 由单个 YAML agent 的 dangerously_skip_permissions 定出 bypass 审批结论
|
|
508
|
+
/// returns: 字段为 true 时 enabled 且来源记 RuntimeConfig,并带上该 provider 的 bypass argv;否则 Disabled
|
|
509
|
+
/// errors: 当前实现不产生 Err
|
|
510
|
+
/// contract_id: lifecycle.spec_state.effective_runtime_config
|
|
511
|
+
/// ---
|
|
389
512
|
/// 0.5.66 bypass 单源:从**单个 agent**(yaml spec)的 `dangerously_skip_permissions` 构造
|
|
390
513
|
/// `DangerousApproval`(取代旧"runtime config + leader argv"全队一份)。
|
|
391
514
|
/// true → source=RuntimeConfig(角色声明即用户明确同意,coordinator 的
|
|
@@ -423,6 +546,12 @@ pub(crate) fn effective_runtime_config_for_worker_spawn(
|
|
|
423
546
|
})
|
|
424
547
|
}
|
|
425
548
|
|
|
549
|
+
/// ---
|
|
550
|
+
/// purpose: 同上,但读的是 runtime state 里的 JSON agent 节点
|
|
551
|
+
/// returns: 同 YAML 版
|
|
552
|
+
/// errors: 当前实现不产生 Err
|
|
553
|
+
/// contract_id: lifecycle.spec_state.effective_runtime_config
|
|
554
|
+
/// ---
|
|
426
555
|
/// 0.5.66 bypass 单源:restart/state 路径的 serde_json 版(agent 来自 state JSON)。
|
|
427
556
|
pub(crate) fn effective_runtime_config_for_worker_spawn_json(
|
|
428
557
|
agent: &serde_json::Value,
|
|
@@ -457,6 +586,10 @@ pub(crate) fn effective_runtime_config_for_worker_spawn_json(
|
|
|
457
586
|
})
|
|
458
587
|
}
|
|
459
588
|
|
|
589
|
+
/// ---
|
|
590
|
+
/// purpose: 给出 provider 的稳定 wire 名
|
|
591
|
+
/// returns: 与 spec 写法一致的小写下划线名
|
|
592
|
+
/// ---
|
|
460
593
|
pub(crate) fn provider_display_str(provider: Provider) -> &'static str {
|
|
461
594
|
match provider {
|
|
462
595
|
Provider::Claude => "claude",
|
|
@@ -464,10 +597,17 @@ pub(crate) fn provider_display_str(provider: Provider) -> &'static str {
|
|
|
464
597
|
Provider::Codex => "codex",
|
|
465
598
|
Provider::Copilot => "copilot",
|
|
466
599
|
Provider::GeminiCli => "gemini_cli",
|
|
600
|
+
Provider::Grok => "grok",
|
|
601
|
+
Provider::CursorAgent => "cursor_agent",
|
|
602
|
+
Provider::Pi => "pi",
|
|
467
603
|
Provider::Fake => "fake",
|
|
468
604
|
}
|
|
469
605
|
}
|
|
470
606
|
|
|
607
|
+
/// ---
|
|
608
|
+
/// purpose: 由 team 目录推出 workspace 根
|
|
609
|
+
/// returns: 解析成功用解析值,失败时退到 team 目录的父目录,没有父目录则用 team 目录本身
|
|
610
|
+
/// ---
|
|
471
611
|
pub(super) fn team_workspace(team_dir: &Path) -> PathBuf {
|
|
472
612
|
crate::model::paths::team_workspace(team_dir).unwrap_or_else(|_| {
|
|
473
613
|
team_dir
|