@team-agent/installer 0.5.65 → 0.5.66
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/Cargo.toml +5 -0
- package/crates/team-agent/src/cli/adapters.rs +1 -1
- package/crates/team-agent/src/cli/tests/compile.rs +1 -1
- package/crates/team-agent/src/cli/tests/mod.rs +2 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
- package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
- package/crates/team-agent/src/compiler/tests.rs +23 -20
- package/crates/team-agent/src/compiler.rs +25 -5
- package/crates/team-agent/src/conpty/backend.rs +16 -0
- package/crates/team-agent/src/leader/start.rs +167 -2
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +0 -2
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +7 -2
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +137 -2
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -2
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +5 -0
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +39 -2
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +105 -48
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +0 -2
- package/crates/team-agent/src/lifecycle/launch.rs +117 -21
- package/crates/team-agent/src/lifecycle/restart/agent.rs +89 -3
- package/crates/team-agent/src/lifecycle/restart/common.rs +6 -9
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +59 -15
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +24 -32
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +13 -11
- package/crates/team-agent/src/lifecycle/tests/core.rs +0 -18
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +17 -30
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests.rs +0 -2
- package/crates/team-agent/src/lifecycle/types.rs +0 -2
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +115 -22
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
- package/crates/team-agent/src/model/spec.rs +129 -6
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
- package/crates/team-agent/src/provider/bypass_flags.rs +80 -0
- package/crates/team-agent/src/provider/mod.rs +2 -0
- package/crates/team-agent/src/tmux_backend.rs +19 -0
- package/crates/team-agent/src/transport/test_support.rs +20 -0
- package/crates/team-agent/src/transport.rs +17 -0
- package/package.json +4 -4
- package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
|
@@ -270,7 +270,6 @@ fn restart_with_selected_team_and_transport(
|
|
|
270
270
|
let spec_workspace = runtime_spec.parent().ok_or_else(|| {
|
|
271
271
|
LifecycleError::TeamSelect("active team spec workspace not found".to_string())
|
|
272
272
|
})?;
|
|
273
|
-
let safety = crate::lifecycle::launch::effective_runtime_config(&spec)?;
|
|
274
273
|
// Bug 1 (0.4.2 P0): the rebuilt spec is the single source of truth for the
|
|
275
274
|
// active roster. Any agent in state.agents that is NOT in the rebuilt
|
|
276
275
|
// spec is a stale leftover (role doc was deleted between sessions) and
|
|
@@ -526,7 +525,6 @@ fn restart_with_selected_team_and_transport(
|
|
|
526
525
|
&selected.team_key,
|
|
527
526
|
&session_name,
|
|
528
527
|
transport,
|
|
529
|
-
&safety,
|
|
530
528
|
tmux_endpoint_source,
|
|
531
529
|
&state,
|
|
532
530
|
)
|
|
@@ -551,12 +549,25 @@ fn restart_with_selected_team_and_transport(
|
|
|
551
549
|
if let Some(parallel_result) = parallel_result {
|
|
552
550
|
match parallel_result {
|
|
553
551
|
Ok(pspawn) => {
|
|
552
|
+
let raw_agent = state
|
|
553
|
+
.get("agents")
|
|
554
|
+
.and_then(|v| v.get(decision.agent_id.as_str()))
|
|
555
|
+
.cloned()
|
|
556
|
+
.unwrap_or(serde_json::Value::Null);
|
|
557
|
+
let rehydrated = rehydrate_agent_command_context_from_spec(
|
|
558
|
+
spec_workspace,
|
|
559
|
+
&decision.agent_id,
|
|
560
|
+
&raw_agent,
|
|
561
|
+
);
|
|
562
|
+
let launched_bypass = matches!(
|
|
563
|
+
rehydrated.get("dangerously_skip_permissions"),
|
|
564
|
+
Some(serde_json::Value::Bool(true))
|
|
565
|
+
);
|
|
554
566
|
apply_marked_respawn(
|
|
555
567
|
&selected.run_workspace,
|
|
556
568
|
&selected.team_key,
|
|
557
569
|
&mut state,
|
|
558
570
|
transport,
|
|
559
|
-
&safety,
|
|
560
571
|
&phase_timer,
|
|
561
572
|
decision,
|
|
562
573
|
&pspawn.spawn,
|
|
@@ -565,6 +576,7 @@ fn restart_with_selected_team_and_transport(
|
|
|
565
576
|
&mut successful_agents,
|
|
566
577
|
&mut failed_agents,
|
|
567
578
|
&mut fatal_resume_failure,
|
|
579
|
+
launched_bypass,
|
|
568
580
|
);
|
|
569
581
|
}
|
|
570
582
|
Err(error) => {
|
|
@@ -709,7 +721,7 @@ fn restart_with_selected_team_and_transport(
|
|
|
709
721
|
session_id,
|
|
710
722
|
session_live,
|
|
711
723
|
transport,
|
|
712
|
-
|
|
724
|
+
None,
|
|
713
725
|
layout_placement.as_ref(),
|
|
714
726
|
None,
|
|
715
727
|
tmux_endpoint_source,
|
|
@@ -737,6 +749,10 @@ fn restart_with_selected_team_and_transport(
|
|
|
737
749
|
}
|
|
738
750
|
};
|
|
739
751
|
let verify_start = std::time::Instant::now();
|
|
752
|
+
let launched_bypass = matches!(
|
|
753
|
+
agent.get("dangerously_skip_permissions"),
|
|
754
|
+
Some(serde_json::Value::Bool(true))
|
|
755
|
+
);
|
|
740
756
|
if let Err(error) = verify_spawned_agent_live(&decision.agent_id, &spawn, transport)
|
|
741
757
|
.and_then(|_| {
|
|
742
758
|
mark_agent_respawned(
|
|
@@ -745,7 +761,7 @@ fn restart_with_selected_team_and_transport(
|
|
|
745
761
|
decision.restart_mode,
|
|
746
762
|
&spawn,
|
|
747
763
|
transport,
|
|
748
|
-
|
|
764
|
+
launched_bypass,
|
|
749
765
|
)
|
|
750
766
|
})
|
|
751
767
|
{
|
|
@@ -787,7 +803,16 @@ fn restart_with_selected_team_and_transport(
|
|
|
787
803
|
.and_then(|agents| agents.get_mut(decision.agent_id.as_str()))
|
|
788
804
|
.and_then(serde_json::Value::as_object_mut)
|
|
789
805
|
{
|
|
790
|
-
|
|
806
|
+
// 0.5.66 bypass 单源:policy 从 agent 行字段派生。
|
|
807
|
+
let agent_provider = agent
|
|
808
|
+
.get("provider")
|
|
809
|
+
.and_then(serde_json::Value::as_str)
|
|
810
|
+
.and_then(crate::provider::wire::parse_canonical_provider)
|
|
811
|
+
.unwrap_or(crate::model::enums::Provider::Codex);
|
|
812
|
+
crate::lifecycle::launch::persist_effective_approval_policy_from_agent(
|
|
813
|
+
agent,
|
|
814
|
+
agent_provider,
|
|
815
|
+
);
|
|
791
816
|
}
|
|
792
817
|
// 0.5.32 (`.team/artifacts/restart-resumed-stale-activity-locate.md` §5):
|
|
793
818
|
// pair the state-side activity clear with a DB `agent_health` clear so
|
|
@@ -1958,7 +1983,7 @@ fn mark_agent_respawned(
|
|
|
1958
1983
|
restart_mode: StartMode,
|
|
1959
1984
|
spawn: &SpawnedAgentWindow,
|
|
1960
1985
|
transport: &dyn crate::transport::Transport,
|
|
1961
|
-
|
|
1986
|
+
launched_bypass: bool,
|
|
1962
1987
|
) -> Result<(), LifecycleError> {
|
|
1963
1988
|
let Some(agent) = state
|
|
1964
1989
|
.get_mut("agents")
|
|
@@ -2081,7 +2106,18 @@ fn mark_agent_respawned(
|
|
|
2081
2106
|
}
|
|
2082
2107
|
}
|
|
2083
2108
|
crate::lifecycle::launch::persist_command_plan_state(agent, &spawn.plan, &spawn.profile_launch);
|
|
2084
|
-
|
|
2109
|
+
// 0.5.66 bypass 单源:policy 从 agent 行字段派生,不再用全队 `DangerousApproval`。
|
|
2110
|
+
let agent_provider = agent
|
|
2111
|
+
.get("provider")
|
|
2112
|
+
.and_then(serde_json::Value::as_str)
|
|
2113
|
+
.and_then(crate::provider::wire::parse_canonical_provider)
|
|
2114
|
+
.unwrap_or(crate::model::enums::Provider::Codex);
|
|
2115
|
+
crate::lifecycle::launch::persist_effective_approval_policy_from_agent(agent, agent_provider);
|
|
2116
|
+
// 0.5.66 bypass 单源 §2.6:fresh spawn(restart)记录运行面 bypass 值。
|
|
2117
|
+
agent.insert(
|
|
2118
|
+
"as_launched_dangerously_skip_permissions".to_string(),
|
|
2119
|
+
serde_json::json!(launched_bypass),
|
|
2120
|
+
);
|
|
2085
2121
|
if let Some(placement) = spawn.layout_placement.as_ref() {
|
|
2086
2122
|
agent.insert(
|
|
2087
2123
|
"layout_window".to_string(),
|
|
@@ -2510,7 +2546,6 @@ fn run_bounded_parallel_worker_spawns(
|
|
|
2510
2546
|
team_key: &str,
|
|
2511
2547
|
session_name: &SessionName,
|
|
2512
2548
|
transport: &(dyn crate::transport::Transport),
|
|
2513
|
-
safety: &DangerousApproval,
|
|
2514
2549
|
tmux_endpoint_source: Option<&str>,
|
|
2515
2550
|
state: &serde_json::Value,
|
|
2516
2551
|
) -> Vec<Option<Result<ParallelSpawnResult, String>>> {
|
|
@@ -2589,7 +2624,7 @@ fn run_bounded_parallel_worker_spawns(
|
|
|
2589
2624
|
first_input.session_id.as_ref(),
|
|
2590
2625
|
first_session_live,
|
|
2591
2626
|
transport,
|
|
2592
|
-
|
|
2627
|
+
None,
|
|
2593
2628
|
first_input.layout_placement.as_ref(),
|
|
2594
2629
|
None,
|
|
2595
2630
|
tmux_endpoint_source,
|
|
@@ -2673,7 +2708,7 @@ fn run_bounded_parallel_worker_spawns(
|
|
|
2673
2708
|
input.session_id.as_ref(),
|
|
2674
2709
|
/* into_existing_session */ true,
|
|
2675
2710
|
transport,
|
|
2676
|
-
|
|
2711
|
+
None,
|
|
2677
2712
|
input.layout_placement.as_ref(),
|
|
2678
2713
|
None,
|
|
2679
2714
|
tmux_endpoint_source,
|
|
@@ -2716,7 +2751,6 @@ fn apply_marked_respawn(
|
|
|
2716
2751
|
team_key: &str,
|
|
2717
2752
|
state: &mut serde_json::Value,
|
|
2718
2753
|
transport: &(dyn crate::transport::Transport),
|
|
2719
|
-
safety: &DangerousApproval,
|
|
2720
2754
|
phase_timer: &RestartPhaseTimer,
|
|
2721
2755
|
decision: &RestartedAgent,
|
|
2722
2756
|
spawn: &SpawnedAgentWindow,
|
|
@@ -2725,6 +2759,7 @@ fn apply_marked_respawn(
|
|
|
2725
2759
|
successful_agents: &mut Vec<RestartedAgent>,
|
|
2726
2760
|
failed_agents: &mut Vec<RestartFailedAgent>,
|
|
2727
2761
|
fatal_resume_failure: &mut bool,
|
|
2762
|
+
launched_bypass: bool,
|
|
2728
2763
|
) {
|
|
2729
2764
|
let verify_start = std::time::Instant::now();
|
|
2730
2765
|
if let Err(error) =
|
|
@@ -2735,7 +2770,7 @@ fn apply_marked_respawn(
|
|
|
2735
2770
|
decision.restart_mode,
|
|
2736
2771
|
spawn,
|
|
2737
2772
|
transport,
|
|
2738
|
-
|
|
2773
|
+
launched_bypass,
|
|
2739
2774
|
)
|
|
2740
2775
|
})
|
|
2741
2776
|
{
|
|
@@ -2776,7 +2811,16 @@ fn apply_marked_respawn(
|
|
|
2776
2811
|
.and_then(|agents| agents.get_mut(decision.agent_id.as_str()))
|
|
2777
2812
|
.and_then(serde_json::Value::as_object_mut)
|
|
2778
2813
|
{
|
|
2779
|
-
|
|
2814
|
+
// 0.5.66 bypass 单源:policy 从 agent 行字段派生。
|
|
2815
|
+
let agent_provider = agent
|
|
2816
|
+
.get("provider")
|
|
2817
|
+
.and_then(serde_json::Value::as_str)
|
|
2818
|
+
.and_then(crate::provider::wire::parse_canonical_provider)
|
|
2819
|
+
.unwrap_or(crate::model::enums::Provider::Codex);
|
|
2820
|
+
crate::lifecycle::launch::persist_effective_approval_policy_from_agent(
|
|
2821
|
+
agent,
|
|
2822
|
+
agent_provider,
|
|
2823
|
+
);
|
|
2780
2824
|
}
|
|
2781
2825
|
let _ = crate::db::agent_health_capture::clear_agent_health_observation(
|
|
2782
2826
|
run_workspace,
|
|
@@ -3728,7 +3772,7 @@ tasks:
|
|
|
3728
3772
|
StartMode::Resumed,
|
|
3729
3773
|
&spawn,
|
|
3730
3774
|
&RespawnEpochTransport,
|
|
3731
|
-
|
|
3775
|
+
false,
|
|
3732
3776
|
)
|
|
3733
3777
|
.expect("mark respawned");
|
|
3734
3778
|
|
|
@@ -393,7 +393,7 @@ fn write_min_team(ws: &Path, name: &str) -> PathBuf {
|
|
|
393
393
|
.unwrap();
|
|
394
394
|
std::fs::write(
|
|
395
395
|
team.join("agents/worker_a.md"),
|
|
396
|
-
"---\nname: worker_a\nrole: Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker.\n",
|
|
396
|
+
"---\nname: worker_a\nrole: Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker.\n",
|
|
397
397
|
)
|
|
398
398
|
.unwrap();
|
|
399
399
|
team
|
|
@@ -330,7 +330,7 @@ fn add_agent_joins_w2_into_running_roster_and_existing_session() {
|
|
|
330
330
|
let role_file = team_dir.join("w2-role.md");
|
|
331
331
|
std::fs::write(
|
|
332
332
|
&role_file,
|
|
333
|
-
"---\nname: w2\nrole: Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker two.\n",
|
|
333
|
+
"---\nname: w2\nrole: Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker two.\n",
|
|
334
334
|
)
|
|
335
335
|
.unwrap();
|
|
336
336
|
let transport = OfflineTransport::new().with_session_present(true);
|
|
@@ -528,7 +528,7 @@ fn write_team(workspace: &Path, fixture: &TeamFixture<'_>) -> PathBuf {
|
|
|
528
528
|
std::fs::write(
|
|
529
529
|
team.join("agents").join(format!("{}.md", agent.id)),
|
|
530
530
|
format!(
|
|
531
|
-
"---\nname: {}\nrole: {}\nprovider: {}\n{model}auth_mode: {}\n{profile}
|
|
531
|
+
"---\nname: {}\nrole: {}\nprovider: {}\n{model}auth_mode: {}\n{profile}dangerously_skip_permissions: false\ntools:\n{tools}---\n\n{}\n",
|
|
532
532
|
agent.id, agent.role, agent.provider, agent.auth_mode, agent.body
|
|
533
533
|
),
|
|
534
534
|
)
|
|
@@ -152,14 +152,14 @@ fn write_claude_profile_team(ws: &Path, team_key: &str, agent_id: &str) -> PathB
|
|
|
152
152
|
std::fs::write(
|
|
153
153
|
team.join("TEAM.md"),
|
|
154
154
|
format!(
|
|
155
|
-
"---\nname: {team_key}\nobjective: Claude compatible config contract.\nprovider: claude\nauth_mode: compatible_api\n---\n\nTeam.\n"
|
|
155
|
+
"---\nname: {team_key}\nobjective: Claude compatible config contract.\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
156
156
|
),
|
|
157
157
|
)
|
|
158
158
|
.unwrap();
|
|
159
159
|
std::fs::write(
|
|
160
160
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
161
161
|
format!(
|
|
162
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
162
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
163
163
|
),
|
|
164
164
|
)
|
|
165
165
|
.unwrap();
|
|
@@ -218,14 +218,14 @@ fn write_claude_profile_team(ws: &Path, team_key: &str, agent_id: &str) -> PathB
|
|
|
218
218
|
std::fs::write(
|
|
219
219
|
team.join("TEAM.md"),
|
|
220
220
|
format!(
|
|
221
|
-
"---\nname: {team_key}\nobjective: Claude compatible profile launch contract.\nprovider: claude\nauth_mode: compatible_api\n---\n\nTeam.\n"
|
|
221
|
+
"---\nname: {team_key}\nobjective: Claude compatible profile launch contract.\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
222
222
|
),
|
|
223
223
|
)
|
|
224
224
|
.unwrap();
|
|
225
225
|
std::fs::write(
|
|
226
226
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
227
227
|
format!(
|
|
228
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
228
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
229
229
|
),
|
|
230
230
|
)
|
|
231
231
|
.unwrap();
|
|
@@ -247,14 +247,14 @@ fn write_claude_subscription_profile_team(ws: &Path, team_key: &str, agent_id: &
|
|
|
247
247
|
std::fs::write(
|
|
248
248
|
team.join("TEAM.md"),
|
|
249
249
|
format!(
|
|
250
|
-
"---\nname: {team_key}\nobjective: Claude subscription profile launch contract.\nprovider: claude\nauth_mode: subscription\n---\n\nTeam.\n"
|
|
250
|
+
"---\nname: {team_key}\nobjective: Claude subscription profile launch contract.\nprovider: claude\nauth_mode: subscription\ndangerously_skip_permissions: false\n---\n\nTeam.\n"
|
|
251
251
|
),
|
|
252
252
|
)
|
|
253
253
|
.unwrap();
|
|
254
254
|
std::fs::write(
|
|
255
255
|
team.join("agents").join(format!("{agent_id}.md")),
|
|
256
256
|
format!(
|
|
257
|
-
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: subscription\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
257
|
+
"---\nname: {agent_id}\nrole: Claude Worker\nprovider: claude\nauth_mode: subscription\ndangerously_skip_permissions: false\nprofile: local\nmodel: null\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
258
258
|
),
|
|
259
259
|
)
|
|
260
260
|
.unwrap();
|
|
@@ -304,7 +304,7 @@ fn write_team_docs(workspace: &Path, provider: &str) {
|
|
|
304
304
|
std::fs::write(
|
|
305
305
|
workspace.join("agents").join(format!("{SOURCE}.md")),
|
|
306
306
|
format!(
|
|
307
|
-
"---\nname: {SOURCE}\nrole: {SOURCE}\nprovider: {provider}\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{SOURCE} body.\n"
|
|
307
|
+
"---\nname: {SOURCE}\nrole: {SOURCE}\nprovider: {provider}\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{SOURCE} body.\n"
|
|
308
308
|
),
|
|
309
309
|
)
|
|
310
310
|
.expect("write source role doc");
|
|
@@ -323,7 +323,7 @@ fn write_copilot_team_docs(workspace: &Path) -> PathBuf {
|
|
|
323
323
|
std::fs::write(
|
|
324
324
|
team_dir.join("agents").join(format!("{SOURCE}.md")),
|
|
325
325
|
format!(
|
|
326
|
-
"---\nname: {SOURCE}\nrole: Copilot Worker\nprovider: copilot\nmodel: gpt-5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nCopilot source body.\n"
|
|
326
|
+
"---\nname: {SOURCE}\nrole: Copilot Worker\nprovider: copilot\nmodel: gpt-5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nCopilot source body.\n"
|
|
327
327
|
),
|
|
328
328
|
)
|
|
329
329
|
.expect("write source role doc");
|
|
@@ -502,20 +502,16 @@ fn r8_copilot_fork_is_no_longer_capability_refused() {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
/// R7 permission-clamp GUARDRAIL — a fork's effective approval policy is derived
|
|
505
|
-
/// from the LEADER and never escalates above it (MUST-16).
|
|
506
|
-
///
|
|
507
|
-
///
|
|
508
|
-
///
|
|
509
|
-
/// leader trips it. The true escalation scenario (a source declaring capability
|
|
510
|
-
/// above the leader) is a real-machine concern.
|
|
505
|
+
/// from the LEADER and never escalates above it (MUST-16). 0.5.66 bypass 单源:
|
|
506
|
+
/// fork 的 approval policy 由源角色的 `dangerously_skip_permissions` 派生
|
|
507
|
+
/// (本 fixture = false → `source=disabled`),不再依赖 leader argv 继承。任何
|
|
508
|
+
/// fork 都不得出现 `source=leader_process`(旧模型已删)或 capability 高于源。
|
|
511
509
|
#[test]
|
|
512
510
|
fn r7_fork_effective_permissions_are_clamped_to_leader_guardrail() {
|
|
513
511
|
// Claude source + success-path backing shim so the fork COMPLETES and a NEW
|
|
514
|
-
// row exists to inspect — no vacuous pass on a refused fork. The
|
|
515
|
-
//
|
|
516
|
-
// `
|
|
517
|
-
// actually detected, so the fixture must supply one instead of borrowing
|
|
518
|
-
// the host's.
|
|
512
|
+
// row exists to inspect — no vacuous pass on a refused fork. The source role
|
|
513
|
+
// declares `dangerously_skip_permissions: false`, so the fork's policy must
|
|
514
|
+
// resolve to `disabled` (fail-closed) — the new single-source model.
|
|
519
515
|
let case = Case::start("cf-r7");
|
|
520
516
|
let fork = case.fork(NEW);
|
|
521
517
|
assert_eq!(
|
|
@@ -538,11 +534,17 @@ fn r7_fork_effective_permissions_are_clamped_to_leader_guardrail() {
|
|
|
538
534
|
let above = policy
|
|
539
535
|
.get("worker_capability_above_leader")
|
|
540
536
|
.and_then(Value::as_bool);
|
|
541
|
-
|
|
537
|
+
assert_ne!(
|
|
542
538
|
source,
|
|
543
539
|
Some("leader_process"),
|
|
544
|
-
"
|
|
545
|
-
|
|
540
|
+
"0.5.66: fork policy must never be leader_process (old ancestry model removed); \
|
|
541
|
+
policy={policy}"
|
|
542
|
+
);
|
|
543
|
+
assert_eq!(
|
|
544
|
+
source,
|
|
545
|
+
Some("disabled"),
|
|
546
|
+
"guardrail: a fork's approval policy derives from the role's dangerously_skip_permissions \
|
|
547
|
+
(false → disabled), never raw-cloned escalation; MUST-16. policy={policy}"
|
|
546
548
|
);
|
|
547
549
|
assert_ne!(
|
|
548
550
|
above,
|
|
@@ -552,18 +554,9 @@ fn r7_fork_effective_permissions_are_clamped_to_leader_guardrail() {
|
|
|
552
554
|
);
|
|
553
555
|
}
|
|
554
556
|
|
|
555
|
-
/// R7b reverse positive control —
|
|
556
|
-
///
|
|
557
|
-
///
|
|
558
|
-
/// clamp (a clean runner == no dangerous ancestor) and proves r7 does not pass
|
|
559
|
-
/// by constant behavior: the same fixture flips leader_process↔disabled purely
|
|
560
|
-
/// on the pinned seam. Mirrors the deterministic product contract
|
|
561
|
-
/// `lifecycle/tests/core.rs` (clean mocked ancestry → Disabled).
|
|
562
|
-
///
|
|
563
|
-
/// NOTE deliberately NOT asserted with the seam UNSET: unpinned, the policy is
|
|
564
|
-
/// a function of the host process tree (the exact non-hermeticity this
|
|
565
|
-
/// revision removes), so an unset-seam assertion would be red on any host
|
|
566
|
-
/// whose own leader runs dangerously.
|
|
557
|
+
/// R7b reverse positive control — same source role (dangerously_skip_permissions:
|
|
558
|
+
/// false) must also resolve to `source=disabled` under any ancestry seam. 0.5.66
|
|
559
|
+
/// 起 policy 与 leader argv 无关:source 恒 `disabled`,fork 恒不升级(MUST-16)。
|
|
567
560
|
#[test]
|
|
568
561
|
fn r7b_fork_policy_under_restricted_leader_ancestry_is_disabled() {
|
|
569
562
|
let case = Case::start_with_ancestry("cf-r7b", RESTRICTED_LEADER_ARGV);
|
|
@@ -587,16 +580,15 @@ fn r7b_fork_policy_under_restricted_leader_ancestry_is_disabled() {
|
|
|
587
580
|
assert_eq!(
|
|
588
581
|
policy.get("source").and_then(Value::as_str),
|
|
589
582
|
Some("disabled"),
|
|
590
|
-
"
|
|
591
|
-
|
|
583
|
+
"fail-closed: source role declares dangerously_skip_permissions=false → fork policy must \
|
|
584
|
+
be disabled; policy={policy}"
|
|
592
585
|
);
|
|
593
586
|
assert_ne!(
|
|
594
587
|
policy
|
|
595
588
|
.get("worker_capability_above_leader")
|
|
596
589
|
.and_then(Value::as_bool),
|
|
597
590
|
Some(true),
|
|
598
|
-
"
|
|
599
|
-
policy={policy}"
|
|
591
|
+
"a fork must never yield a capability above the source; MUST-16. policy={policy}"
|
|
600
592
|
);
|
|
601
593
|
}
|
|
602
594
|
|
|
@@ -246,7 +246,7 @@ fn fixture(tag: &str, team_mode: Option<&str>) -> PathBuf {
|
|
|
246
246
|
std::fs::write(
|
|
247
247
|
root.join("agents").join(format!("worker_{id}.md")),
|
|
248
248
|
format!(
|
|
249
|
-
"---\nname: worker_{id}\nrole: Communication Worker\nprovider: claude\ncommunication_mode: {id}\ntools:\n - mcp_team\n---\n\nROLE BODY SENTINEL {id}\n"
|
|
249
|
+
"---\nname: worker_{id}\nrole: Communication Worker\nprovider: claude\ndangerously_skip_permissions: false\ncommunication_mode: {id}\ntools:\n - mcp_team\n---\n\nROLE BODY SENTINEL {id}\n"
|
|
250
250
|
),
|
|
251
251
|
)
|
|
252
252
|
.unwrap();
|
|
@@ -265,7 +265,7 @@ fn default_fixture(tag: &str) -> PathBuf {
|
|
|
265
265
|
}
|
|
266
266
|
std::fs::write(
|
|
267
267
|
root.join("agents").join("worker_default.md"),
|
|
268
|
-
"---\nname: worker_default\nrole: Communication Worker\nprovider: claude\ntools:\n - mcp_team\n---\n\nROLE BODY SENTINEL default\n",
|
|
268
|
+
"---\nname: worker_default\nrole: Communication Worker\nprovider: claude\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nROLE BODY SENTINEL default\n",
|
|
269
269
|
)
|
|
270
270
|
.unwrap();
|
|
271
271
|
root
|
|
@@ -229,8 +229,9 @@ team_orchestrator or @<.team/runtime/mcp/worker_a.json>; got {value:?}"
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
/// Face 1 dangerous tier (C-5-1, verdict `dangerous_auto_approve_argv_contains_allow_all`):
|
|
232
|
-
///
|
|
233
|
-
/// parity, paths+urls included) — NOT the
|
|
232
|
+
/// role `dangerously_skip_permissions: true` must map to `--allow-all` (claude
|
|
233
|
+
/// `--dangerously-skip-permissions` parity, paths+urls included) — NOT the
|
|
234
|
+
/// silently-narrower `--allow-all-tools`. 0.5.66 bypass 单源:bypass 由角色字段驱动。
|
|
234
235
|
#[test]
|
|
235
236
|
#[serial(env)]
|
|
236
237
|
fn copilot_argv_dangerous_maps_to_allow_all() {
|
|
@@ -254,7 +255,7 @@ fn copilot_argv_dangerous_maps_to_allow_all() {
|
|
|
254
255
|
let mut failures = Vec::new();
|
|
255
256
|
if !argv.iter().any(|arg| arg == "--allow-all") {
|
|
256
257
|
failures.push(format!(
|
|
257
|
-
"C-5-1:
|
|
258
|
+
"C-5-1: dangerously_skip_permissions=true must produce `--allow-all` (=--yolo, claude \
|
|
258
259
|
parity incl. paths+urls); argv={argv:?}"
|
|
259
260
|
));
|
|
260
261
|
}
|
|
@@ -1101,8 +1102,8 @@ fn copilot_subscription_model_precedence_role_over_profile() {
|
|
|
1101
1102
|
// point the agent at the profile
|
|
1102
1103
|
let agent_md = team_dir.join("agents/worker_a.md");
|
|
1103
1104
|
let body = std::fs::read_to_string(&agent_md).unwrap().replace(
|
|
1104
|
-
"auth_mode: subscription\n",
|
|
1105
|
-
"auth_mode: subscription\nprofile: subm\n",
|
|
1105
|
+
"auth_mode: subscription\ndangerously_skip_permissions: false\n",
|
|
1106
|
+
"auth_mode: subscription\ndangerously_skip_permissions: false\nprofile: subm\n",
|
|
1106
1107
|
);
|
|
1107
1108
|
std::fs::write(&agent_md, body).unwrap();
|
|
1108
1109
|
seed_healthy_coordinator(&ws);
|
|
@@ -1387,7 +1388,7 @@ fn write_copilot_byok_team(ws: &Path, name: &str, model: Option<&str>) -> PathBu
|
|
|
1387
1388
|
std::fs::write(
|
|
1388
1389
|
team.join("agents/worker_a.md"),
|
|
1389
1390
|
format!(
|
|
1390
|
-
"---\nname: worker_a\nrole: Copilot Worker\nprovider: copilot\n{model_field}auth_mode: compatible_api\nprofile: byok\ntools:\n - mcp_team\n---\n\nCOPILOT ROLE BODY SENTINEL: BYOK worker.\n"
|
|
1391
|
+
"---\nname: worker_a\nrole: Copilot Worker\nprovider: copilot\n{model_field}auth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: byok\ntools:\n - mcp_team\n---\n\nCOPILOT ROLE BODY SENTINEL: BYOK worker.\n"
|
|
1391
1392
|
),
|
|
1392
1393
|
)
|
|
1393
1394
|
.unwrap();
|
|
@@ -1412,15 +1413,16 @@ fn write_copilot_team(ws: &Path, name: &str, tools: &[&str], dangerous: bool) ->
|
|
|
1412
1413
|
let _ = TeamOpts;
|
|
1413
1414
|
let team = ws.join(name);
|
|
1414
1415
|
std::fs::create_dir_all(team.join("agents")).unwrap();
|
|
1415
|
-
|
|
1416
|
-
|
|
1416
|
+
// 0.5.66 bypass 单源:bypass 由角色字段驱动,不再是 TEAM.md dangerous_auto_approve。
|
|
1417
|
+
let role_bypass = if dangerous {
|
|
1418
|
+
"true"
|
|
1417
1419
|
} else {
|
|
1418
|
-
""
|
|
1420
|
+
"false"
|
|
1419
1421
|
};
|
|
1420
1422
|
std::fs::write(
|
|
1421
1423
|
team.join("TEAM.md"),
|
|
1422
1424
|
format!(
|
|
1423
|
-
"---\nname: {name}\nobjective: copilot provider contract fixture.\nprovider: copilot\n
|
|
1425
|
+
"---\nname: {name}\nobjective: copilot provider contract fixture.\nprovider: copilot\n---\n\nTeam fixture.\n"
|
|
1424
1426
|
),
|
|
1425
1427
|
)
|
|
1426
1428
|
.unwrap();
|
|
@@ -1431,7 +1433,7 @@ fn write_copilot_team(ws: &Path, name: &str, tools: &[&str], dangerous: bool) ->
|
|
|
1431
1433
|
std::fs::write(
|
|
1432
1434
|
team.join("agents/worker_a.md"),
|
|
1433
1435
|
format!(
|
|
1434
|
-
"---\nname: worker_a\nrole: Copilot Worker\nprovider: copilot\nmodel: gpt-5\nauth_mode: subscription\ntools:\n{tool_lines}---\n\nCOPILOT ROLE BODY SENTINEL: serve the copilot adapter contract.\n"
|
|
1436
|
+
"---\nname: worker_a\nrole: Copilot Worker\nprovider: copilot\nmodel: gpt-5\nauth_mode: subscription\ndangerously_skip_permissions: {role_bypass}\ntools:\n{tool_lines}---\n\nCOPILOT ROLE BODY SENTINEL: serve the copilot adapter contract.\n"
|
|
1435
1437
|
),
|
|
1436
1438
|
)
|
|
1437
1439
|
.unwrap();
|
|
@@ -1010,24 +1010,6 @@ fn quick_start_empty_dir_returns_typed_report_not_error_path_only() {
|
|
|
1010
1010
|
}
|
|
1011
1011
|
}
|
|
1012
1012
|
|
|
1013
|
-
// ───────────────────────────────────────────────────────────────────────
|
|
1014
|
-
// detect_dangerous_approval — launch/config.py
|
|
1015
|
-
// 默认进程(无 --dangerously-* 祖先)→ enabled=false / source=Disabled / inherited=false。
|
|
1016
|
-
// launch 在 inherited=false 且无 --yes 时 raise DangerousApprovalRequired(core.py:120)。
|
|
1017
|
-
// ───────────────────────────────────────────────────────────────────────
|
|
1018
|
-
|
|
1019
|
-
#[test]
|
|
1020
|
-
#[serial_test::serial(env)]
|
|
1021
|
-
fn detect_dangerous_approval_clean_process_is_disabled() {
|
|
1022
|
-
// Explicit mock ancestry keeps the test independent from the real Codex/CI
|
|
1023
|
-
// process tree that runs cargo.
|
|
1024
|
-
let _ancestry = EnvVarGuard::set("TEAM_AGENT_TEST_PROCESS_ANCESTRY_ARGV_JSON", "[]");
|
|
1025
|
-
let got = detect_dangerous_approval().expect("探测祖先链应 Ok");
|
|
1026
|
-
assert!(!got.enabled, "干净进程不应启用危险审批");
|
|
1027
|
-
assert_eq!(got.source, DangerousApprovalSource::Disabled);
|
|
1028
|
-
assert!(!got.inherited);
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
1013
|
#[test]
|
|
1032
1014
|
#[serial_test::serial(env)]
|
|
1033
1015
|
fn leader_pane_env_absent_pane_fails_fast() {
|
|
@@ -746,7 +746,7 @@ fn write_team(
|
|
|
746
746
|
std::fs::write(
|
|
747
747
|
team.join("agents").join(format!("{}.md", agent.id)),
|
|
748
748
|
format!(
|
|
749
|
-
"---\nname: {}\nrole: {}\nprovider: {}\nmodel: fake\nauth_mode: subscription\ntools:\n{}---\n\n{}\n",
|
|
749
|
+
"---\nname: {}\nrole: {}\nprovider: {}\nmodel: fake\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n{}---\n\n{}\n",
|
|
750
750
|
agent.id, agent.role, agent.provider, tools, agent.body
|
|
751
751
|
),
|
|
752
752
|
)
|
|
@@ -358,7 +358,7 @@ impl DisplayFixture {
|
|
|
358
358
|
std::fs::write(
|
|
359
359
|
team.join("agents").join(format!("{worker}.md")),
|
|
360
360
|
format!(
|
|
361
|
-
"---\nname: {worker}\nrole: Adaptive fake worker {worker}\nprovider: fake\nmodel: fake\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
361
|
+
"---\nname: {worker}\nrole: Adaptive fake worker {worker}\nprovider: fake\nmodel: fake\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker.\n"
|
|
362
362
|
),
|
|
363
363
|
)
|
|
364
364
|
.unwrap();
|
|
@@ -27,7 +27,7 @@ static SEQ: AtomicU32 = AtomicU32::new(0);
|
|
|
27
27
|
|
|
28
28
|
const TEAM_MD: &str =
|
|
29
29
|
"---\nname: f032team\nobjective: F032 lifecycle prompt fault probe.\nprovider: codex\n---\n\nF032.\n";
|
|
30
|
-
const ROLE_MD: &str = "---\nname: implementer\nrole: Implementation Engineer\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nImplement.\n";
|
|
30
|
+
const ROLE_MD: &str = "---\nname: implementer\nrole: Implementation Engineer\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nImplement.\n";
|
|
31
31
|
|
|
32
32
|
#[test]
|
|
33
33
|
fn f032_launch_spawn_path_treats_startup_prompt_panic_as_best_effort() {
|
|
@@ -422,7 +422,10 @@ check behind it = false green); it must reflect an actual doctor result"
|
|
|
422
422
|
/// T3-2 (claude_auth_hint parse failure): when `claude auth status` output is
|
|
423
423
|
/// unparseable / unsuccessful, the hint must not default to Present (auth misreported
|
|
424
424
|
/// as available). PATH-shims a `claude` that prints garbage and exits non-zero.
|
|
425
|
+
/// Mutates the process-global PATH/HOME — must not race host_cotenant's ps/tmux
|
|
426
|
+
/// shims (P0 pid-probe isolation), hence `#[serial(pid_probe)]`.
|
|
425
427
|
#[test]
|
|
428
|
+
#[serial(pid_probe)]
|
|
426
429
|
fn t3_claude_auth_hint_parse_failure_is_not_present() {
|
|
427
430
|
let home = tmp_ws("t3-auth-home");
|
|
428
431
|
let shim_dir = home.join("bin");
|
|
@@ -65,7 +65,7 @@ const POLLUTED_CALLER_AUTHORITY_ENVS: &[&str] = &[
|
|
|
65
65
|
];
|
|
66
66
|
|
|
67
67
|
#[test]
|
|
68
|
-
#[serial(env)]
|
|
68
|
+
#[serial(env, pid_probe)]
|
|
69
69
|
fn polluted_caller_env_never_authorizes_teardown_to_kill_foreign_tmux() {
|
|
70
70
|
let env = hermetic_guard::HermeticTestEnv::enter("p0-caller-env-sentinel");
|
|
71
71
|
let shim_dir = env.root().join("bin");
|
|
@@ -150,7 +150,7 @@ exec "$TEAM_AGENT_TEST_REAL_TMUX" "$@"
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
#[test]
|
|
153
|
-
#[serial(env)]
|
|
153
|
+
#[serial(env, pid_probe)]
|
|
154
154
|
fn restart_allow_fresh_does_not_leave_same_role_host_cotenants() {
|
|
155
155
|
let mut failures = Vec::new();
|
|
156
156
|
let (env, workspace) = team_case("p0-restart", &["developer", "test-engineer", "arch-reviewer"]);
|
|
@@ -677,7 +677,7 @@ fn write_team_docs(workspace: &Path, workers: &[(&str, &str)]) {
|
|
|
677
677
|
fs::create_dir_all(workspace.join("agents")).unwrap();
|
|
678
678
|
fs::write(workspace.join("TEAM.md"), "---\nname: current\nobjective: P0 host co-tenant contract.\nprovider: codex\n---\n").unwrap();
|
|
679
679
|
for (worker, model) in workers {
|
|
680
|
-
let role = format!("---\nname: {worker}\nrole: {worker}\nprovider: codex\nmodel: {model}\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{worker}.\n");
|
|
680
|
+
let role = format!("---\nname: {worker}\nrole: {worker}\nprovider: codex\nmodel: {model}\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{worker}.\n");
|
|
681
681
|
fs::write(workspace.join("agents").join(format!("{worker}.md")), role).unwrap();
|
|
682
682
|
}
|
|
683
683
|
}
|
|
@@ -3,7 +3,7 @@ use super::*;
|
|
|
3
3
|
|
|
4
4
|
// ═════════════════════════════════════════════════════════════════════════
|
|
5
5
|
|
|
6
|
-
const DELEG_ROLE_ALPHA_COMPAT: &str = "---\nname: alpha\nrole: Alpha Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: compatible_api\nprofile: alpha-compat\ntools:\n - mcp_team\n---\n\nAlpha.\n";
|
|
6
|
+
const DELEG_ROLE_ALPHA_COMPAT: &str = "---\nname: alpha\nrole: Alpha Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: compatible_api\ndangerously_skip_permissions: false\nprofile: alpha-compat\ntools:\n - mcp_team\n---\n\nAlpha.\n";
|
|
7
7
|
|
|
8
8
|
type LaneKills = std::sync::Arc<std::sync::Mutex<Vec<String>>>;
|
|
9
9
|
pub(super) type LaneSpawns = std::sync::Arc<std::sync::Mutex<Vec<(String, Vec<String>)>>>;
|
|
@@ -816,7 +816,7 @@ fn current_alias_authority_does_not_leak_into_real_sibling_same_id_retirement()
|
|
|
816
816
|
);
|
|
817
817
|
}
|
|
818
818
|
|
|
819
|
-
const CHARLIE_ROLE: &str = "---\nname: charlie\nrole: Charlie Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nCharlie.\n";
|
|
819
|
+
const CHARLIE_ROLE: &str = "---\nname: charlie\nrole: Charlie Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nCharlie.\n";
|
|
820
820
|
|
|
821
821
|
struct HermeticTestEnv {
|
|
822
822
|
root: std::path::PathBuf,
|