@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.
Files changed (64) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/mod.rs +0 -1
  4. package/crates/team-agent/src/cli/profile.rs +4 -12
  5. package/crates/team-agent/src/cli/tests/verb_profile.rs +66 -0
  6. package/crates/team-agent/src/compiler/tests.rs +13 -24
  7. package/crates/team-agent/src/compiler.rs +1 -50
  8. package/crates/team-agent/src/leader/start.rs +0 -2
  9. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +0 -1
  10. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -1
  11. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +0 -6
  12. package/crates/team-agent/src/lifecycle/launch/identity.rs +0 -1
  13. package/crates/team-agent/src/lifecycle/launch/layout.rs +0 -1
  14. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +0 -1
  15. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +1 -89
  16. package/crates/team-agent/src/lifecycle/launch/ownership.rs +0 -1
  17. package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +0 -3
  18. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +14 -24
  19. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +0 -1
  20. package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -1
  21. package/crates/team-agent/src/lifecycle/launch/spawn.rs +4 -8
  22. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +0 -1
  23. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +0 -1
  24. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +0 -1
  25. package/crates/team-agent/src/lifecycle/launch.rs +0 -9
  26. package/crates/team-agent/src/lifecycle/profile_launch.rs +1 -1
  27. package/crates/team-agent/src/lifecycle/restart/common.rs +6 -9
  28. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +1 -3
  29. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +42 -46
  30. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +209 -52
  31. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +32 -77
  32. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -13
  33. package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +0 -1
  34. package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +0 -2
  35. package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +14 -85
  36. package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -1
  37. package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +0 -5
  38. package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +0 -1
  39. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +4 -4
  40. package/crates/team-agent/src/lifecycle/tests.rs +0 -1
  41. package/crates/team-agent/src/lifecycle/types.rs +0 -10
  42. package/crates/team-agent/src/lifecycle/worker_command_context.rs +4 -248
  43. package/crates/team-agent/src/messaging/results/collection_tests.rs +719 -0
  44. package/crates/team-agent/src/messaging/results.rs +104 -27
  45. package/crates/team-agent/src/model/enums.rs +0 -35
  46. package/crates/team-agent/src/model/mod.rs +0 -1
  47. package/crates/team-agent/src/model/spec.rs +23 -84
  48. package/crates/team-agent/src/provider/adapter.rs +48 -50
  49. package/crates/team-agent/src/provider/adapters/claude.rs +5 -30
  50. package/crates/team-agent/src/provider/adapters/codex.rs +5 -25
  51. package/crates/team-agent/src/provider/adapters/copilot.rs +9 -42
  52. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +4 -8
  53. package/crates/team-agent/src/provider/adapters/grok.rs +5 -58
  54. package/crates/team-agent/src/provider/adapters/mod.rs +5 -7
  55. package/crates/team-agent/src/provider/adapters/pi.rs +1 -56
  56. package/crates/team-agent/src/provider/bypass_flags.rs +1 -2
  57. package/crates/team-agent/src/provider/session/capture.rs +4 -4
  58. package/crates/team-agent/src/provider/tests/adapter.rs +7 -24
  59. package/crates/team-agent/src/provider/types.rs +1 -1
  60. package/crates/team-agent/src/state/persist.rs +15 -1
  61. package/package.json +4 -4
  62. package/schemas/team.schema.json +4 -9
  63. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +0 -784
  64. package/crates/team-agent/src/model/permissions.rs +0 -721
package/Cargo.lock CHANGED
@@ -581,7 +581,7 @@ dependencies = [
581
581
 
582
582
  [[package]]
583
583
  name = "team-agent"
584
- version = "0.5.84"
584
+ version = "0.5.86"
585
585
  dependencies = [
586
586
  "anyhow",
587
587
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.84"
12
+ version = "0.5.86"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -3646,7 +3646,6 @@ pub mod lifecycle_port {
3646
3646
  dry_run: false,
3647
3647
  tmux_endpoint: None,
3648
3648
  routes: Vec::new(),
3649
- permissions: Vec::new(),
3650
3649
  leader_receiver_attached: true,
3651
3650
  leader_bind_stage: None,
3652
3651
  leader_bind_reason: None,
@@ -222,18 +222,10 @@ fn set_owner_only_permissions(path: &Path) -> Result<(), CliError> {
222
222
 
223
223
  fn read_profile_env(path: &Path) -> Result<Map<String, Value>, CliError> {
224
224
  let raw = std::fs::read_to_string(path)?;
225
- let mut values = Map::new();
226
- for line in raw.lines() {
227
- let trimmed = line.trim();
228
- if trimmed.is_empty() || trimmed.starts_with('#') {
229
- continue;
230
- }
231
- let Some((key, value)) = trimmed.split_once('=') else {
232
- continue;
233
- };
234
- values.insert(key.to_string(), Value::String(value.to_string()));
235
- }
236
- Ok(values)
225
+ Ok(crate::lifecycle::profile_launch::parse_env_text(&raw)
226
+ .into_iter()
227
+ .map(|(key, value)| (key, Value::String(value)))
228
+ .collect())
237
229
  }
238
230
 
239
231
  fn redacted_values(values: &Map<String, Value>) -> Value {
@@ -322,3 +322,69 @@ fn profile_show_routes_and_preserves_redacted_secret_contract() {
322
322
  );
323
323
  let _ = std::fs::remove_dir_all(&ws);
324
324
  }
325
+
326
+ #[test]
327
+ fn config_authority_t04_show_doctor_and_runtime_parse_the_same_profile_bytes() {
328
+ let ws = tmp_workspace();
329
+ let runtime_dir = ws.join(".team/runtime");
330
+ std::fs::remove_dir(&runtime_dir).unwrap();
331
+ assert!(
332
+ !runtime_dir.exists(),
333
+ "T04 fixture must start without a runtime directory"
334
+ );
335
+ let dir = profiles_dir(&ws);
336
+ std::fs::create_dir_all(&dir).unwrap();
337
+ let body = "# synthetic fixture\nexport AUTH_MODE = 'compatible_api'\nPROXY_MODE=inherit\nexport PROXY_MODE = \"direct\"\nMODEL = 'synthetic-model'\nBASE_URL = \"http://127.0.0.1:9/v1\"\nexport API_KEY = 'synthetic-secret-placeholder'\nPLAIN=plain\nBAD-KEY=ignored\n1BAD=ignored\nMISSING_EQUALS\n";
338
+ std::fs::write(dir.join("syntax.env"), body).unwrap();
339
+ let runtime = crate::lifecycle::profile_launch::load_profile(&ws, "syntax", None).unwrap();
340
+ assert!(
341
+ !runtime_dir.exists(),
342
+ "load_profile must not create the runtime directory"
343
+ );
344
+ for (key, value) in [
345
+ ("AUTH_MODE", "compatible_api"),
346
+ ("PROXY_MODE", "direct"),
347
+ ("MODEL", "synthetic-model"),
348
+ ("PLAIN", "plain"),
349
+ ] {
350
+ assert_eq!(runtime.values.get(key).map(String::as_str), Some(value));
351
+ }
352
+ assert!(!runtime.values.contains_key("BAD-KEY"));
353
+ assert!(!runtime.values.contains_key("1BAD"));
354
+ for command in ["show", "doctor"] {
355
+ let result = cmd_profile(&ProfileArgs {
356
+ command: command.into(),
357
+ name: "syntax".into(),
358
+ workspace: ws.clone(),
359
+ team: None,
360
+ auth_mode: None,
361
+ proxy_mode: None,
362
+ json: true,
363
+ })
364
+ .unwrap();
365
+ let CmdOutput::Json(output) = result.output else {
366
+ panic!("expected JSON")
367
+ };
368
+ assert!(
369
+ !runtime_dir.exists(),
370
+ "profile {command} must not create the runtime directory"
371
+ );
372
+ assert_eq!(output["auth_mode"], runtime.values["AUTH_MODE"]);
373
+ assert_eq!(output["proxy_mode"], runtime.values["PROXY_MODE"]);
374
+ assert_eq!(output["credential_present"], true);
375
+ assert_eq!(output["secret_values_printed"], false);
376
+ assert!(!output.to_string().contains("synthetic-secret-placeholder"));
377
+ assert!(!output.to_string().contains("BAD-KEY"));
378
+ if command == "show" {
379
+ assert_eq!(output["values"]["MODEL"]["value"], "synthetic-model");
380
+ assert_eq!(output["values"]["API_KEY"]["redacted"], true);
381
+ assert_eq!(output["missing_common"], serde_json::json!([]));
382
+ }
383
+ }
384
+ assert_eq!(
385
+ std::fs::read_to_string(dir.join("syntax.env")).unwrap(),
386
+ body
387
+ );
388
+ assert!(!dir.join("syntax.example.env").exists());
389
+ assert!(!ws.join(".team/runtime").exists());
390
+ }
@@ -190,7 +190,7 @@ fn front_matter_non_object_errors() {
190
190
  // separators=(",",":"))` with the workspace path templated to __WS__.
191
191
  // (team-agent-public v0.2.11, /tmp/probe_compiler.py.)
192
192
 
193
- const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"tools":["fs_read","fs_write","execute_bash","mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
193
+ const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
194
194
 
195
195
  #[test]
196
196
  fn compile_base_noprofile_matches_python_dict_order_and_values() {
@@ -261,7 +261,7 @@ dangerously_skip_permissions: false
261
261
  Implement bounded tasks.
262
262
  ";
263
263
 
264
- const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["fs_read","mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
264
+ const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
265
265
 
266
266
  #[test]
267
267
  fn compile_runtime_front_matter_defaults_match_python() {
@@ -302,7 +302,7 @@ dangerously_skip_permissions: false
302
302
  Edit and defend the argument.
303
303
  ";
304
304
 
305
- const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"tools":["mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
305
+ const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
306
306
 
307
307
  #[test]
308
308
  fn compile_provider_models_claude_code_falls_back_to_claude_alias() {
@@ -336,7 +336,7 @@ tools:
336
336
  Implement bounded tasks.
337
337
  ";
338
338
 
339
- const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
339
+ const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
340
340
 
341
341
  #[test]
342
342
  fn compile_subscription_without_model_uses_builtin_provider_default() {
@@ -378,7 +378,7 @@ tools:
378
378
  Bravo body.
379
379
  ";
380
380
 
381
- const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"tools":["mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"tools":["mcp_team"],"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
381
+ const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"dangerously_skip_permissions":false,"communication_mode":"leader_centric","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
382
382
 
383
383
  #[test]
384
384
  fn compile_two_agents_sorted_by_filename_with_routing_and_startup_order() {
@@ -633,36 +633,25 @@ fn fix_a5_session_name_override_wins() {
633
633
  // ── A6 tools ──
634
634
 
635
635
  #[test]
636
- fn fix_a6_tools_shell_maps_to_execute_bash() {
637
- let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - shell\n - mcp_team\n---\nb\n";
636
+ fn fix_a6_tools_are_transparent_compatibility_metadata() {
637
+ let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - shell\n - provider_builtin\n---\nb\n";
638
638
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
639
- let spec = compile_team(&team).expect("shell must normalize to execute_bash and compile");
640
- assert_eq!(
641
- agent0(&spec).get("tools"),
642
- Some(&list_str(vec!["execute_bash", "mcp_team"]))
643
- );
639
+ let spec = compile_team(&team).expect("tools metadata must not gate compilation");
640
+ assert!(agent0(&spec).get("tools").is_none());
644
641
  }
645
642
 
646
643
  #[test]
647
- fn fix_a6_missing_tools_errors() {
644
+ fn fix_a6_missing_tools_is_allowed() {
648
645
  let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\n---\nb\n";
649
646
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
650
- let err = compile_team(&team).unwrap_err();
651
- assert!(
652
- err.to_string().contains("missing front matter field tools"),
653
- "got: {err}"
654
- );
647
+ compile_team(&team).expect("omitted tools metadata must compile");
655
648
  }
656
649
 
657
650
  #[test]
658
- fn fix_a6_tools_not_a_list_errors() {
651
+ fn fix_a6_tools_non_list_is_transparent() {
659
652
  let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools: justastring\n---\nb\n";
660
653
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
661
- let err = compile_team(&team).unwrap_err();
662
- assert!(
663
- err.to_string().contains("tools must be a list"),
664
- "got: {err}"
665
- );
654
+ compile_team(&team).expect("any YAML tools metadata must compile");
666
655
  }
667
656
 
668
657
  // ── A7 system_prompt inline ──
@@ -30,8 +30,7 @@ use std::path::Path;
30
30
  use crate::communication_mode::CommunicationMode;
31
31
  use crate::model::enums::{Provider, ProviderEffort};
32
32
  use crate::model::yaml::Value;
33
- use crate::model::{paths, permissions, spec, yaml, ModelError};
34
- use crate::provider::adapters::pi::first_unsupported_pi_tool_category;
33
+ use crate::model::{paths, spec, yaml, ModelError};
35
34
  use crate::provider::wire::{
36
35
  builtin_provider_model as wire_builtin_provider_model, is_claude_family,
37
36
  parse_canonical_provider, provider_model_keys,
@@ -233,7 +232,6 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
233
232
  ("role", Value::Str(leader_role)),
234
233
  ("provider", Value::Str(leader_provider)),
235
234
  ("model", leader_model),
236
- ("tools", list_str(vec!["fs_read", "fs_list", "mcp_team"])),
237
235
  (
238
236
  "context_policy",
239
237
  map(vec![
@@ -526,7 +524,6 @@ fn compile_role_agent_with_mode(
526
524
  role_path.display(),
527
525
  )));
528
526
  }
529
- let tools = required_tools(&meta, role_path)?;
530
527
  let prompt_inline = non_empty_trimmed(&body).unwrap_or_else(|| role.clone());
531
528
  let mut agent_items = vec![
532
529
  ("id", Value::Str(id.clone())),
@@ -542,7 +539,6 @@ fn compile_role_agent_with_mode(
542
539
  ("file", Value::Null),
543
540
  ]),
544
541
  ),
545
- ("tools", list_str(tools)),
546
542
  // 0.5.66 bypass 单源:compiler 透传角色 md 的 `dangerously_skip_permissions`
547
543
  // (必填 bool,spec 校验保证存在)。取代旧"恒发 permission_mode: restricted"。
548
544
  (
@@ -758,25 +754,6 @@ fn validate_pi_role_fields(meta: &Value, path: &Path, provider: &str) -> Result<
758
754
  )));
759
755
  }
760
756
  }
761
- let tools = required_tools(meta, path)?;
762
- if !tools.iter().any(|tool| tool == "mcp_team") {
763
- return Err(ModelError::Validation(format!(
764
- "{}: Pi roles require mcp_team",
765
- path.display()
766
- )));
767
- }
768
- let expanded = permissions::expand_tool_strings(tools.iter().map(String::as_str));
769
- if let Some(category) = first_unsupported_pi_tool_category(
770
- expanded
771
- .iter()
772
- .filter(|category| permissions::is_canonical_tool(category))
773
- .map(String::as_str),
774
- ) {
775
- return Err(ModelError::Validation(format!(
776
- "{}: Pi does not support Team Agent tool category {category:?}; remove it from the role's tools",
777
- path.display()
778
- )));
779
- }
780
757
  Ok(())
781
758
  }
782
759
 
@@ -876,32 +853,6 @@ fn py_int_value(value: &Value) -> Option<i64> {
876
853
  }
877
854
  }
878
855
 
879
- fn required_tools(meta: &Value, path: &Path) -> Result<Vec<String>, ModelError> {
880
- let Some(value) = meta.get("tools") else {
881
- return Err(ModelError::Validation(format!(
882
- "{}: missing front matter field tools",
883
- path.display()
884
- )));
885
- };
886
- let Some(items) = value.as_list() else {
887
- return Err(ModelError::Validation(format!(
888
- "{}: tools must be a list",
889
- path.display()
890
- )));
891
- };
892
- Ok(items
893
- .iter()
894
- .filter_map(Value::as_str)
895
- .map(|tool| {
896
- if tool == "shell" {
897
- "execute_bash".to_string()
898
- } else {
899
- tool.to_string()
900
- }
901
- })
902
- .collect())
903
- }
904
-
905
856
  fn resolve_model(role_meta: &Value, team_meta: &Value, provider: &str) -> Value {
906
857
  if let Some(model) = string_field(role_meta, "model") {
907
858
  return Value::Str(model);
@@ -304,7 +304,6 @@ fn leader_start_plan_with_ambient_authority(
304
304
  identity.team_id.as_str(),
305
305
  );
306
306
  let prompt = crate::lifecycle::worker_command_context::compile_pi_leader_system_prompt();
307
- let tools = ["mcp_team", "fs_read", "fs_list", "fs_write", "execute_bash"];
308
307
  let team_mcp_tools = [
309
308
  "assign_task",
310
309
  "send_message",
@@ -327,7 +326,6 @@ fn leader_start_plan_with_ambient_authority(
327
326
  model: parsed.model.as_deref(),
328
327
  effort: parsed.effort,
329
328
  system_prompt: &prompt,
330
- tool_categories: &tools,
331
329
  team_mcp_tools: &team_mcp_tools,
332
330
  mcp_config: &mcp_config,
333
331
  session_scope: crate::lifecycle::launch::pi_mcp::pi_leader_session_scope(
@@ -31,7 +31,6 @@ use std::time::{SystemTime, UNIX_EPOCH};
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::{PaneId, SessionName, Target, Transport, WindowName};
@@ -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};
@@ -24,7 +24,6 @@ use std::process::Command;
24
24
  use crate::lifecycle::*;
25
25
  use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
26
26
  use crate::model::ids::AgentId;
27
- use crate::model::permissions::{self, AgentPermissionInput};
28
27
  use crate::model::yaml::{self, Value};
29
28
  use crate::state::persist::load_runtime_state;
30
29
  use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
@@ -106,11 +105,6 @@ pub(super) fn running_agent_state(
106
105
  "mcp_config".to_string(),
107
106
  serde_json::json!(mcp_config_path.to_string_lossy().to_string()),
108
107
  );
109
- state.insert(
110
- "permissions".to_string(),
111
- permissions_json(agent, id, provider)
112
- .map_err(|e| LifecycleError::Compile(e.to_string()))?,
113
- );
114
108
  // 0.5.66 bypass 单源:policy 从 agent 字段派生,不再用全队 `DangerousApproval`。
115
109
  persist_effective_approval_policy_from_yaml_agent(&mut state, agent, provider);
116
110
  // 0.5.66 bypass 单源 §2.6:fresh spawn 记录运行面 bypass 值(供 restart drift 挡板)。
@@ -33,7 +33,6 @@ use std::process::Command;
33
33
  use crate::lifecycle::*;
34
34
  use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
35
35
  use crate::model::ids::AgentId;
36
- use crate::model::permissions::{self, AgentPermissionInput};
37
36
  use crate::model::yaml::{self, Value};
38
37
  use crate::state::persist::load_runtime_state;
39
38
  use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
@@ -25,7 +25,6 @@ use std::process::Command;
25
25
  use crate::lifecycle::*;
26
26
  use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
27
27
  use crate::model::ids::AgentId;
28
- use crate::model::permissions::{self, AgentPermissionInput};
29
28
  use crate::model::yaml::{self, Value};
30
29
  use crate::state::persist::load_runtime_state;
31
30
  use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
@@ -31,7 +31,6 @@ use crate::lifecycle::profile_launch::parse_provider;
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::{PaneId, SessionName, Target, Transport, WindowName};
@@ -16,7 +16,6 @@
16
16
  //! what: 把 argv 里的 MCP 配置参数改指到已落盘的文件
17
17
  //! depends:
18
18
  //! - crate::provider::McpConfig
19
- //! - crate::model::permissions
20
19
  //! - crate::event_log::EventLog
21
20
  //! - crate::lifecycle::profile_launch
22
21
  //! - std::fs
@@ -33,8 +32,6 @@ use std::process::Command;
33
32
 
34
33
  use crate::lifecycle::*;
35
34
  use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
36
- use crate::model::ids::AgentId;
37
- use crate::model::permissions::{self, AgentPermissionInput};
38
35
  use crate::model::yaml::{self, Value};
39
36
  use crate::state::persist::load_runtime_state;
40
37
  use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
@@ -135,7 +132,7 @@ pub(crate) fn write_worker_mcp_config_for_provider(
135
132
  .map_err(|e| LifecycleError::StatePersist(format!("{}: {e}", parent.display())))?;
136
133
  }
137
134
  let raw = if matches!(provider, Some(Provider::Copilot)) {
138
- copilot_translate_mcp_servers(&config.raw)
135
+ crate::provider::adapters::copilot::copilot_translate_mcp_config(&config.raw)
139
136
  } else {
140
137
  config.raw.clone()
141
138
  };
@@ -610,36 +607,6 @@ fn upsert_toml_table_prefixes(existing: &str, tables: &[&str], stanza: &str) ->
610
607
  }
611
608
  }
612
609
 
613
- /// ---
614
- /// purpose: 把 MCP 配置里每个 server 的 type 字段名换成 transport
615
- /// returns: 同结构的新值,其余字段全部保留;非对象原样返回
616
- /// ---
617
- /// C-3-4 cr verdict v2 — McpConfig.raw 是 `{name: {type, command, args, env}}` 形;
618
- /// copilot mcp add schema 取 `transport` 替 `type`(stdio|http|sse 同值)。仅
619
- /// 字段名变换,其余字段全保留。
620
- pub(super) fn copilot_translate_mcp_servers(raw: &serde_json::Value) -> serde_json::Value {
621
- let Some(servers) = raw.as_object() else {
622
- return raw.clone();
623
- };
624
- let mut translated = serde_json::Map::new();
625
- for (name, server) in servers {
626
- let Some(obj) = server.as_object() else {
627
- translated.insert(name.clone(), server.clone());
628
- continue;
629
- };
630
- let mut out = serde_json::Map::new();
631
- for (key, value) in obj {
632
- if key == "type" {
633
- out.insert("transport".to_string(), value.clone());
634
- } else {
635
- out.insert(key.clone(), value.clone());
636
- }
637
- }
638
- translated.insert(name.clone(), serde_json::Value::Object(out));
639
- }
640
- serde_json::Value::Object(translated)
641
- }
642
-
643
610
  /// ---
644
611
  /// purpose: 把 argv 里 provider 原生的 MCP 配置参数改指到已落盘的文件
645
612
  /// params:
@@ -674,58 +641,3 @@ pub(crate) fn point_native_mcp_config_at_file(
674
641
  _ => {}
675
642
  }
676
643
  }
677
-
678
- /// ---
679
- /// purpose: 解析该席位的权限并序列化成 JSON
680
- /// returns: 含 agent_id、provider、排序后的工具串、逐工具的执行强度与是否有仅提示项
681
- /// errors: 权限解析失败时返回 ModelError
682
- /// ---
683
- pub(super) fn permissions_json(
684
- agent: &Value,
685
- id: &str,
686
- provider: Provider,
687
- ) -> Result<serde_json::Value, crate::model::ModelError> {
688
- let tools = agent.get("tools").and_then(Value::as_list).map(|items| {
689
- items
690
- .iter()
691
- .filter_map(Value::as_str)
692
- .map(str::to_string)
693
- .collect::<Vec<_>>()
694
- });
695
- let resolved = permissions::resolve_permissions(&AgentPermissionInput {
696
- id: Some(AgentId::new(id)),
697
- provider,
698
- role: agent
699
- .get("role")
700
- .and_then(Value::as_str)
701
- .map(str::to_string),
702
- tools,
703
- })?;
704
- let mut out = serde_json::Map::new();
705
- out.insert("agent_id".to_string(), serde_json::json!(id));
706
- out.insert("provider".to_string(), serde_json::json!(provider));
707
- out.insert(
708
- "tools".to_string(),
709
- serde_json::json!(resolved.sorted_tool_strings()),
710
- );
711
- out.insert(
712
- "resolved_tools".to_string(),
713
- serde_json::Value::Array(
714
- resolved
715
- .resolved_tools
716
- .iter()
717
- .map(|tool| {
718
- serde_json::json!({
719
- "tool": tool.tool,
720
- "enforcement": tool.enforcement,
721
- })
722
- })
723
- .collect(),
724
- ),
725
- );
726
- out.insert(
727
- "has_prompt_only".to_string(),
728
- serde_json::json!(resolved.has_prompt_only),
729
- );
730
- Ok(serde_json::Value::Object(out))
731
- }
@@ -25,7 +25,6 @@ use std::process::Command;
25
25
  use crate::lifecycle::*;
26
26
  use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
27
27
  use crate::model::ids::AgentId;
28
- use crate::model::permissions::{self, AgentPermissionInput};
29
28
  use crate::model::yaml::{self, Value};
30
29
  use crate::state::persist::load_runtime_state;
31
30
  use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
@@ -995,7 +995,6 @@ pub(crate) struct PiMaterializeRequest<'a> {
995
995
  pub model: Option<&'a str>,
996
996
  pub effort: Option<ProviderEffort>,
997
997
  pub system_prompt: &'a str,
998
- pub tool_categories: &'a [&'a str],
999
998
  pub team_mcp_tools: &'a [&'a str],
1000
999
  pub mcp_config: &'a McpConfig,
1001
1000
  pub session_scope: PiSessionScope,
@@ -1093,7 +1092,6 @@ fn materialize_pi_plan_with_session(
1093
1092
  model: model.as_deref(),
1094
1093
  effort: request.effort,
1095
1094
  system_prompt: request.system_prompt,
1096
- tool_categories: request.tool_categories,
1097
1095
  session_dir,
1098
1096
  session: PiSessionSelector::Resume { path: &exact_path },
1099
1097
  agent_id: request.agent_id,
@@ -1106,7 +1104,6 @@ fn materialize_pi_plan_with_session(
1106
1104
  model: model.as_deref(),
1107
1105
  effort: request.effort,
1108
1106
  system_prompt: request.system_prompt,
1109
- tool_categories: request.tool_categories,
1110
1107
  session_dir,
1111
1108
  session: PiSessionSelector::Fresh {
1112
1109
  session_id: session_id.as_str(),