@team-agent/installer 0.5.84 → 0.5.86
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 +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/mod.rs +0 -1
- package/crates/team-agent/src/cli/profile.rs +4 -12
- package/crates/team-agent/src/cli/tests/verb_profile.rs +66 -0
- package/crates/team-agent/src/compiler/tests.rs +13 -24
- package/crates/team-agent/src/compiler.rs +1 -50
- package/crates/team-agent/src/leader/start.rs +0 -2
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +0 -6
- package/crates/team-agent/src/lifecycle/launch/identity.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/layout.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +1 -89
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +0 -3
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +14 -24
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +4 -8
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch.rs +0 -9
- package/crates/team-agent/src/lifecycle/profile_launch.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/common.rs +6 -9
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +1 -3
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +42 -46
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +209 -52
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +32 -77
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -13
- package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +0 -1
- package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +0 -2
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +14 -85
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +0 -5
- package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +0 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests.rs +0 -1
- package/crates/team-agent/src/lifecycle/types.rs +0 -10
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +4 -248
- package/crates/team-agent/src/messaging/results/collection_tests.rs +719 -0
- package/crates/team-agent/src/messaging/results.rs +104 -27
- package/crates/team-agent/src/model/enums.rs +0 -35
- package/crates/team-agent/src/model/mod.rs +0 -1
- package/crates/team-agent/src/model/spec.rs +23 -84
- package/crates/team-agent/src/provider/adapter.rs +48 -50
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -30
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -25
- package/crates/team-agent/src/provider/adapters/copilot.rs +9 -42
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +4 -8
- package/crates/team-agent/src/provider/adapters/grok.rs +5 -58
- package/crates/team-agent/src/provider/adapters/mod.rs +5 -7
- package/crates/team-agent/src/provider/adapters/pi.rs +1 -56
- package/crates/team-agent/src/provider/bypass_flags.rs +1 -2
- package/crates/team-agent/src/provider/session/capture.rs +4 -4
- package/crates/team-agent/src/provider/tests/adapter.rs +7 -24
- package/crates/team-agent/src/provider/types.rs +1 -1
- package/crates/team-agent/src/state/persist.rs +15 -1
- package/package.json +4 -4
- package/schemas/team.schema.json +4 -9
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +0 -784
- package/crates/team-agent/src/model/permissions.rs +0 -721
|
@@ -31,7 +31,6 @@ use std::process::Command;
|
|
|
31
31
|
use crate::lifecycle::*;
|
|
32
32
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
33
33
|
use crate::model::ids::AgentId;
|
|
34
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
35
34
|
use crate::model::yaml::{self, Value};
|
|
36
35
|
use crate::state::persist::load_runtime_state;
|
|
37
36
|
use crate::transport::{PaneField, PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -4434,7 +4433,7 @@ mod fresh_quick_start_leader_binding_tests {
|
|
|
4434
4433
|
|
|
4435
4434
|
|
|
4436
4435
|
#[test]
|
|
4437
|
-
fn
|
|
4436
|
+
fn pi_tool_category_is_transparently_accepted_by_compiler() {
|
|
4438
4437
|
let root = std::env::temp_dir().join(format!(
|
|
4439
4438
|
"ta-quick-start-pi-tools-{}-{}",
|
|
4440
4439
|
std::process::id(),
|
|
@@ -4453,29 +4452,20 @@ mod fresh_quick_start_leader_binding_tests {
|
|
|
4453
4452
|
)
|
|
4454
4453
|
.unwrap();
|
|
4455
4454
|
|
|
4456
|
-
let
|
|
4457
|
-
|
|
4458
|
-
let
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
)
|
|
4468
|
-
.expect_err("invalid Pi category must fail before quick-start persistence");
|
|
4469
|
-
let error = error.to_string();
|
|
4470
|
-
assert!(error.contains("Pi does not support Team Agent tool category \"provider_builtin\""));
|
|
4471
|
-
assert!(error.contains("remove it from the role's tools"));
|
|
4472
|
-
assert!(
|
|
4473
|
-
!crate::state::persist::runtime_state_path(&root).exists(),
|
|
4474
|
-
"quick-start validation failure must not persist runtime state"
|
|
4475
|
-
);
|
|
4455
|
+
let spec = crate::compiler::compile_team(&team)
|
|
4456
|
+
.expect("tools metadata must be transparently accepted by the compiler");
|
|
4457
|
+
let worker = spec
|
|
4458
|
+
.get("agents")
|
|
4459
|
+
.and_then(Value::as_list)
|
|
4460
|
+
.and_then(|agents| {
|
|
4461
|
+
agents.iter().find(|agent| {
|
|
4462
|
+
agent.get("id").and_then(Value::as_str) == Some("worker")
|
|
4463
|
+
})
|
|
4464
|
+
})
|
|
4465
|
+
.expect("compiled spec must retain the worker role");
|
|
4476
4466
|
assert!(
|
|
4477
|
-
|
|
4478
|
-
"
|
|
4467
|
+
worker.get("tools").is_none(),
|
|
4468
|
+
"tools metadata must not acquire runtime semantics"
|
|
4479
4469
|
);
|
|
4480
4470
|
let _ = std::fs::remove_dir_all(root);
|
|
4481
4471
|
}
|
|
@@ -28,7 +28,6 @@ use std::process::Command;
|
|
|
28
28
|
use crate::lifecycle::*;
|
|
29
29
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
30
30
|
use crate::model::ids::AgentId;
|
|
31
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
32
31
|
use crate::model::yaml::{self, Value};
|
|
33
32
|
use crate::state::persist::load_runtime_state;
|
|
34
33
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -30,7 +30,6 @@ use std::process::Command;
|
|
|
30
30
|
use crate::lifecycle::*;
|
|
31
31
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
32
32
|
use crate::model::ids::AgentId;
|
|
33
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
34
33
|
use crate::model::yaml::{self, Value};
|
|
35
34
|
use crate::state::persist::load_runtime_state;
|
|
36
35
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -32,7 +32,6 @@ use crate::lifecycle::profile_launch::parse_provider;
|
|
|
32
32
|
use crate::lifecycle::*;
|
|
33
33
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
34
34
|
use crate::model::ids::AgentId;
|
|
35
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
36
35
|
use crate::model::yaml::{self, Value};
|
|
37
36
|
use crate::state::persist::load_runtime_state;
|
|
38
37
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -123,11 +122,6 @@ pub(super) fn spawn_agents(
|
|
|
123
122
|
)?;
|
|
124
123
|
let system_prompt =
|
|
125
124
|
crate::lifecycle::worker_command_context::compile_worker_system_prompt(&command_agent)?;
|
|
126
|
-
let tools = crate::lifecycle::worker_command_context::resolved_tool_strings_for_command(
|
|
127
|
-
&command_agent,
|
|
128
|
-
provider,
|
|
129
|
-
)?;
|
|
130
|
-
let resolved_tool_refs: Vec<&str> = tools.iter().map(String::as_str).collect();
|
|
131
125
|
// 0.5.66 bypass 单源:per-agent safety 只服务 env 注入与审计,不参与 argv 决策。
|
|
132
126
|
let safety = effective_runtime_config_for_worker_spawn(agent, provider)?;
|
|
133
127
|
let mcp_team_id = runtime_team_key_for_spec(spec_path, spec, session_name);
|
|
@@ -168,7 +162,10 @@ pub(super) fn spawn_agents(
|
|
|
168
162
|
mcp_config: Some(&mcp_config),
|
|
169
163
|
system_prompt: Some(system_prompt.as_str()),
|
|
170
164
|
model: command_model,
|
|
171
|
-
|
|
165
|
+
dangerously_skip_permissions: matches!(
|
|
166
|
+
agent.get("dangerously_skip_permissions"),
|
|
167
|
+
Some(Value::Bool(true))
|
|
168
|
+
),
|
|
172
169
|
profile_launch: Some(&profile_launch),
|
|
173
170
|
// Layer 1 self-healing (architect probe 2026-06-22): expose
|
|
174
171
|
// agent_id as a display-name hint so Claude / Copilot
|
|
@@ -186,7 +183,6 @@ pub(super) fn spawn_agents(
|
|
|
186
183
|
model: command_model,
|
|
187
184
|
effort: agent_effort,
|
|
188
185
|
system_prompt: &system_prompt,
|
|
189
|
-
tool_categories: &resolved_tool_refs,
|
|
190
186
|
team_mcp_tools: &["send_message", "report_result"],
|
|
191
187
|
mcp_config: &mcp_config,
|
|
192
188
|
session_scope: crate::lifecycle::launch::pi_mcp::PiSessionScope::Isolated,
|
|
@@ -62,7 +62,6 @@ use std::process::Command;
|
|
|
62
62
|
use crate::lifecycle::*;
|
|
63
63
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
64
64
|
use crate::model::ids::AgentId;
|
|
65
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
66
65
|
use crate::model::yaml::{self, Value};
|
|
67
66
|
use crate::state::persist::load_runtime_state;
|
|
68
67
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -37,7 +37,6 @@ use crate::lifecycle::profile_launch::parse_provider;
|
|
|
37
37
|
use crate::lifecycle::*;
|
|
38
38
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
39
39
|
use crate::model::ids::AgentId;
|
|
40
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
41
40
|
use crate::model::yaml::{self, Value};
|
|
42
41
|
use crate::state::persist::load_runtime_state;
|
|
43
42
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -30,7 +30,6 @@ use std::process::Command;
|
|
|
30
30
|
use crate::lifecycle::*;
|
|
31
31
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
32
32
|
use crate::model::ids::AgentId;
|
|
33
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
34
33
|
use crate::model::yaml::{self, Value};
|
|
35
34
|
use crate::state::persist::load_runtime_state;
|
|
36
35
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -17,7 +17,6 @@ use std::process::Command;
|
|
|
17
17
|
|
|
18
18
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
19
19
|
use crate::model::ids::AgentId;
|
|
20
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
21
20
|
use crate::model::yaml::{self, Value};
|
|
22
21
|
use crate::state::persist::load_runtime_state;
|
|
23
22
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -133,13 +132,6 @@ pub fn launch_with_transport_in_workspace(
|
|
|
133
132
|
session_name.as_str()
|
|
134
133
|
)));
|
|
135
134
|
}
|
|
136
|
-
let permissions = spec_agents(&spec)
|
|
137
|
-
.into_iter()
|
|
138
|
-
.map(|agent| PermissionSummary {
|
|
139
|
-
agent_id: agent,
|
|
140
|
-
raw: serde_json::json!({"source": "compiled_spec"}),
|
|
141
|
-
})
|
|
142
|
-
.collect::<Vec<_>>();
|
|
143
135
|
let routes = spec_routes(&spec);
|
|
144
136
|
let started = if dry_run {
|
|
145
137
|
Vec::new()
|
|
@@ -208,7 +200,6 @@ pub fn launch_with_transport_in_workspace(
|
|
|
208
200
|
dry_run,
|
|
209
201
|
tmux_endpoint: transport.tmux_endpoint(),
|
|
210
202
|
routes,
|
|
211
|
-
permissions,
|
|
212
203
|
leader_receiver_attached: false,
|
|
213
204
|
leader_bind_stage: None,
|
|
214
205
|
leader_bind_reason: None,
|
|
@@ -333,7 +333,7 @@ fn push_unique_path(paths: &mut Vec<PathBuf>, path: PathBuf) {
|
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
fn parse_env_text(text: &str) -> BTreeMap<String, String> {
|
|
336
|
+
pub(crate) fn parse_env_text(text: &str) -> BTreeMap<String, String> {
|
|
337
337
|
let mut values = BTreeMap::new();
|
|
338
338
|
for raw in text.lines() {
|
|
339
339
|
let mut line = raw.trim();
|
|
@@ -301,11 +301,6 @@ pub(super) fn spawn_agent_window(
|
|
|
301
301
|
)?;
|
|
302
302
|
let system_prompt =
|
|
303
303
|
crate::lifecycle::worker_command_context::compile_worker_system_prompt(&command_agent)?;
|
|
304
|
-
let tools = crate::lifecycle::worker_command_context::resolved_tool_strings_for_command(
|
|
305
|
-
&command_agent,
|
|
306
|
-
provider,
|
|
307
|
-
)?;
|
|
308
|
-
let resolved_tool_refs: Vec<&str> = tools.iter().map(String::as_str).collect();
|
|
309
304
|
// owner_team_id resolution priority (Issue 2 fix):
|
|
310
305
|
// 1. caller's explicit override (restart paths pass `selected.team_key`)
|
|
311
306
|
// 2. agent row's persisted `owner_team_id` (set by prior launch/restart)
|
|
@@ -343,10 +338,11 @@ pub(super) fn spawn_agent_window(
|
|
|
343
338
|
let mcp_config_path = if provider == crate::provider::Provider::Pi {
|
|
344
339
|
None
|
|
345
340
|
} else {
|
|
346
|
-
Some(crate::lifecycle::launch::
|
|
341
|
+
Some(crate::lifecycle::launch::write_worker_mcp_config_for_provider(
|
|
347
342
|
workspace,
|
|
348
343
|
agent_id.as_str(),
|
|
349
344
|
&mcp_config,
|
|
345
|
+
Some(provider),
|
|
350
346
|
)?)
|
|
351
347
|
};
|
|
352
348
|
let profile_launch =
|
|
@@ -373,7 +369,10 @@ pub(super) fn spawn_agent_window(
|
|
|
373
369
|
mcp_config: Some(&mcp_config),
|
|
374
370
|
system_prompt: Some(system_prompt.as_str()),
|
|
375
371
|
model: command_model,
|
|
376
|
-
|
|
372
|
+
dangerously_skip_permissions: agent
|
|
373
|
+
.get("dangerously_skip_permissions")
|
|
374
|
+
.and_then(serde_json::Value::as_bool)
|
|
375
|
+
.unwrap_or(false),
|
|
377
376
|
profile_launch: Some(&profile_launch),
|
|
378
377
|
agent_id_hint: Some(agent_id.as_str()),
|
|
379
378
|
effort: restart_effort,
|
|
@@ -398,7 +397,6 @@ pub(super) fn spawn_agent_window(
|
|
|
398
397
|
model: command_model,
|
|
399
398
|
effort: restart_effort,
|
|
400
399
|
system_prompt: &system_prompt,
|
|
401
|
-
tool_categories: &resolved_tool_refs,
|
|
402
400
|
team_mcp_tools: &["send_message", "report_result"],
|
|
403
401
|
mcp_config: &mcp_config,
|
|
404
402
|
session_scope: crate::lifecycle::launch::pi_mcp::PiSessionScope::Isolated,
|
|
@@ -743,7 +741,6 @@ fn merge_command_context_fields(
|
|
|
743
741
|
};
|
|
744
742
|
for field in [
|
|
745
743
|
"role",
|
|
746
|
-
"tools",
|
|
747
744
|
"system_prompt",
|
|
748
745
|
"output_contract",
|
|
749
746
|
"provider",
|
|
@@ -97,15 +97,13 @@ fn managed_profile_command_plan_omits_mcp_config_even_when_mcp_config_is_availab
|
|
|
97
97
|
}
|
|
98
98
|
}),
|
|
99
99
|
};
|
|
100
|
-
let tools = ["mcp_team"];
|
|
101
|
-
|
|
102
100
|
let plan = get_adapter(Provider::Claude)
|
|
103
101
|
.build_command_plan(ProviderCommandContext {
|
|
104
102
|
auth_mode: AuthMode::CompatibleApi,
|
|
105
103
|
mcp_config: Some(&config),
|
|
106
104
|
system_prompt: Some("worker prompt requiring native MCP"),
|
|
107
105
|
model: Some("profile-effective-haiku"),
|
|
108
|
-
|
|
106
|
+
dangerously_skip_permissions: false,
|
|
109
107
|
profile_launch: Some(&profile),
|
|
110
108
|
agent_id_hint: None,
|
|
111
109
|
effort: None,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
//! ---
|
|
2
|
-
//! purpose: 回归——clone-agent
|
|
2
|
+
//! purpose: 回归——clone-agent 分身保留源席 tools,编译 spec 不投影 tools
|
|
3
3
|
//! contract:
|
|
4
4
|
//! provides:
|
|
5
5
|
//! - name: clone_agent_preserves_source_tools
|
|
6
|
-
//! what: 真跑 clone-agent 后,dynamic-role-files
|
|
6
|
+
//! what: 真跑 clone-agent 后,dynamic-role-files 保留源席 tools,runtime spec 不投影 tools
|
|
7
7
|
//! requires:
|
|
8
8
|
//! - name: source-six-set-vs-leader-three-set
|
|
9
9
|
//! what: 同一 team 里 leader 三件套 + 源席六件套的共享冲突面
|
|
@@ -275,6 +275,10 @@ fn role_tools(path: &Path) -> BTreeSet<String> {
|
|
|
275
275
|
.collect()
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
fn set_of(items: &[&str]) -> BTreeSet<String> {
|
|
279
|
+
items.iter().map(|s| (*s).to_string()).collect()
|
|
280
|
+
}
|
|
281
|
+
|
|
278
282
|
fn load_runtime_spec(workspace: &Path) -> Value {
|
|
279
283
|
let runtime = workspace.join(".team").join("runtime");
|
|
280
284
|
let spec = std::fs::read_dir(&runtime)
|
|
@@ -287,17 +291,7 @@ fn load_runtime_spec(workspace: &Path) -> Value {
|
|
|
287
291
|
.expect("parse spec")
|
|
288
292
|
}
|
|
289
293
|
|
|
290
|
-
fn
|
|
291
|
-
node.get("tools")
|
|
292
|
-
.and_then(Value::as_list)
|
|
293
|
-
.unwrap_or_else(|| panic!("tools list missing"))
|
|
294
|
-
.iter()
|
|
295
|
-
.filter_map(Value::as_str)
|
|
296
|
-
.map(str::to_string)
|
|
297
|
-
.collect()
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
fn spec_tools(workspace: &Path, agent: &str) -> BTreeSet<String> {
|
|
294
|
+
fn spec_projects_tools(workspace: &Path, agent: &str) -> bool {
|
|
301
295
|
let parsed = load_runtime_spec(workspace);
|
|
302
296
|
let agents = parsed
|
|
303
297
|
.get("agents")
|
|
@@ -305,22 +299,18 @@ fn spec_tools(workspace: &Path, agent: &str) -> BTreeSet<String> {
|
|
|
305
299
|
.expect("spec agents");
|
|
306
300
|
for row in agents {
|
|
307
301
|
if row.get("id").and_then(Value::as_str) == Some(agent) {
|
|
308
|
-
return
|
|
302
|
+
return row.get("tools").is_some();
|
|
309
303
|
}
|
|
310
304
|
}
|
|
311
305
|
panic!("agent {agent} missing from runtime spec");
|
|
312
306
|
}
|
|
313
307
|
|
|
314
|
-
fn
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
fn set_of(items: &[&str]) -> BTreeSet<String> {
|
|
323
|
-
items.iter().map(|s| (*s).to_string()).collect()
|
|
308
|
+
fn leader_spec_projects_tools(workspace: &Path) -> bool {
|
|
309
|
+
load_runtime_spec(workspace)
|
|
310
|
+
.get("leader")
|
|
311
|
+
.expect("spec leader")
|
|
312
|
+
.get("tools")
|
|
313
|
+
.is_some()
|
|
324
314
|
}
|
|
325
315
|
|
|
326
316
|
fn clone_ok(case: &Case, source: &str, dest: &str, phase: &str) {
|
|
@@ -347,7 +337,7 @@ fn clone_ok(case: &Case, source: &str, dest: &str, phase: &str) {
|
|
|
347
337
|
);
|
|
348
338
|
}
|
|
349
339
|
|
|
350
|
-
/// clone 后分身 role
|
|
340
|
+
/// clone 后分身 role 保留源席 tools;编译 spec 不投影 tools。
|
|
351
341
|
#[test]
|
|
352
342
|
fn clone_agent_preserves_source_tools() {
|
|
353
343
|
let case = Case::start();
|
|
@@ -380,21 +370,18 @@ fn clone_agent_preserves_source_tools() {
|
|
|
380
370
|
String::from_utf8_lossy(&qs.stdout)
|
|
381
371
|
);
|
|
382
372
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
set_of(SIX),
|
|
387
|
-
"fixture source must be the six-set"
|
|
373
|
+
assert!(
|
|
374
|
+
!spec_projects_tools(&case.workspace, SOURCE),
|
|
375
|
+
"compiled source spec must not project tools metadata"
|
|
388
376
|
);
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
set_of(THREE),
|
|
393
|
-
"leader must stay the three-set ceiling so the conflict surface exists; leader={leader_spec:?}"
|
|
377
|
+
assert!(
|
|
378
|
+
!leader_spec_projects_tools(&case.workspace),
|
|
379
|
+
"compiled leader spec must not project tools metadata"
|
|
394
380
|
);
|
|
395
381
|
|
|
396
382
|
clone_ok(&case, SOURCE, CLONE, "first_clone");
|
|
397
383
|
|
|
384
|
+
let source_role = role_tools(&case.workspace.join("agents").join(format!("{SOURCE}.md")));
|
|
398
385
|
let clone_role = role_tools(
|
|
399
386
|
&case
|
|
400
387
|
.workspace
|
|
@@ -402,23 +389,32 @@ fn clone_agent_preserves_source_tools() {
|
|
|
402
389
|
.join("dynamic-role-files")
|
|
403
390
|
.join(format!("{CLONE}.md")),
|
|
404
391
|
);
|
|
405
|
-
let clone_spec = spec_tools(&case.workspace, CLONE);
|
|
406
392
|
assert_eq!(
|
|
407
|
-
clone_role,
|
|
408
|
-
"clone role tools must equal source; source={
|
|
393
|
+
clone_role, source_role,
|
|
394
|
+
"clone role tools must equal source; source={source_role:?} clone={clone_role:?}"
|
|
409
395
|
);
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
"clone spec
|
|
396
|
+
assert!(
|
|
397
|
+
!spec_projects_tools(&case.workspace, CLONE),
|
|
398
|
+
"compiled clone spec must not project tools metadata"
|
|
413
399
|
);
|
|
414
400
|
|
|
415
|
-
let
|
|
416
|
-
assert_eq!(
|
|
401
|
+
let narrow_source_role = role_tools(&case.workspace.join("agents").join(format!("{NARROW}.md")));
|
|
402
|
+
assert_eq!(narrow_source_role, set_of(THREE), "narrow source fixture");
|
|
417
403
|
clone_ok(&case, NARROW, NARROW_CLONE, "second_clone");
|
|
418
|
-
let
|
|
404
|
+
let narrow_clone_role = role_tools(
|
|
405
|
+
&case
|
|
406
|
+
.workspace
|
|
407
|
+
.join(".team")
|
|
408
|
+
.join("dynamic-role-files")
|
|
409
|
+
.join(format!("{NARROW_CLONE}.md")),
|
|
410
|
+
);
|
|
419
411
|
assert_eq!(
|
|
420
|
-
|
|
421
|
-
"narrow clone must keep the three-set (preserve, do not widen); got={
|
|
412
|
+
narrow_clone_role, narrow_source_role,
|
|
413
|
+
"narrow clone role must keep the three-set (preserve, do not widen); got={narrow_clone_role:?}"
|
|
414
|
+
);
|
|
415
|
+
assert!(
|
|
416
|
+
!spec_projects_tools(&case.workspace, NARROW_CLONE),
|
|
417
|
+
"compiled narrow clone spec must not project tools metadata"
|
|
422
418
|
);
|
|
423
419
|
|
|
424
420
|
case.shutdown();
|