@team-agent/installer 0.5.65 → 0.5.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +8 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +6 -0
- package/crates/team-agent/src/cli/adapters.rs +6 -1
- package/crates/team-agent/src/cli/diagnose.rs +82 -0
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +21 -7
- package/crates/team-agent/src/cli/leaders.rs +125 -1
- package/crates/team-agent/src/cli/mod.rs +20 -0
- package/crates/team-agent/src/cli/send/presentation.rs +7 -1
- package/crates/team-agent/src/cli/spec.rs +2 -0
- package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
- package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
- package/crates/team-agent/src/cli/tests/base.rs +26 -3
- package/crates/team-agent/src/cli/tests/compile.rs +1 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
- package/crates/team-agent/src/cli/tests/mod.rs +2 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
- package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
- package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
- package/crates/team-agent/src/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler/tests.rs +23 -20
- package/crates/team-agent/src/compiler.rs +84 -5
- package/crates/team-agent/src/conpty/backend.rs +16 -0
- package/crates/team-agent/src/coordinator/backoff.rs +55 -0
- package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
- package/crates/team-agent/src/coordinator/health.rs +173 -0
- package/crates/team-agent/src/coordinator/mod.rs +31 -0
- package/crates/team-agent/src/coordinator/orphan.rs +31 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
- package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
- package/crates/team-agent/src/coordinator/tick.rs +133 -22
- package/crates/team-agent/src/coordinator/types.rs +49 -0
- package/crates/team-agent/src/db/message_store.rs +39 -5
- package/crates/team-agent/src/layout/worker_env.rs +20 -3
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
- package/crates/team-agent/src/leader/registry.rs +65 -0
- package/crates/team-agent/src/leader/start.rs +1080 -58
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/display.rs +56 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -14
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +69 -2
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +196 -2
- package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
- package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -457
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
- package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
- package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
- package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
- package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +101 -4
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +244 -48
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -2
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +209 -43
- package/crates/team-agent/src/lifecycle/lock.rs +42 -1
- package/crates/team-agent/src/lifecycle/mod.rs +11 -0
- package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +213 -3
- package/crates/team-agent/src/lifecycle/restart/common.rs +373 -18
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +165 -15
- package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
- package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
- package/crates/team-agent/src/lifecycle/restart.rs +29 -0
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -4
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +159 -174
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +15 -13
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -18
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
- package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +65 -40
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +20 -32
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +17 -9
- package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +24 -23
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +98 -62
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -1
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +41 -8
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +60 -2
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +23 -15
- package/crates/team-agent/src/lifecycle/types.rs +61 -2
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +200 -33
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
- package/crates/team-agent/src/mcp_server/tests.rs +196 -2
- package/crates/team-agent/src/messaging/delivery.rs +405 -40
- package/crates/team-agent/src/messaging/helpers.rs +2 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
- package/crates/team-agent/src/messaging/results.rs +4 -0
- package/crates/team-agent/src/messaging/send.rs +34 -0
- package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
- package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
- package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
- package/crates/team-agent/src/messaging/types.rs +4 -1
- package/crates/team-agent/src/model/enums.rs +14 -5
- package/crates/team-agent/src/model/permissions.rs +3 -0
- package/crates/team-agent/src/model/spec.rs +129 -6
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
- package/crates/team-agent/src/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +231 -4
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +124 -0
- package/crates/team-agent/src/provider/classify.rs +4 -2
- package/crates/team-agent/src/provider/faults.rs +2 -1
- package/crates/team-agent/src/provider/mod.rs +13 -0
- package/crates/team-agent/src/provider/session/capture.rs +158 -20
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
- package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
- package/crates/team-agent/src/provider/session/mod.rs +18 -0
- package/crates/team-agent/src/provider/session/resume.rs +57 -0
- package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
- package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
- package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
- package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
- package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
- package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
- package/crates/team-agent/src/provider/session_scan.rs +8 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +23 -1
- package/crates/team-agent/src/state/persist.rs +301 -8
- package/crates/team-agent/src/state/repository.rs +5 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
- package/crates/team-agent/src/tmux_backend.rs +1083 -75
- package/crates/team-agent/src/transport/test_support.rs +20 -0
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +265 -1
- package/npm/install.mjs +129 -73
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +33 -238
- package/skills/team-agent/command-coverage.json +31 -0
- package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -483
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
|
|
46
46
|
use std::collections::BTreeMap;
|
|
47
47
|
use std::path::{Path, PathBuf};
|
|
48
|
-
use std::process::Output;
|
|
48
|
+
use std::process::{Command, Output};
|
|
49
49
|
use std::sync::Mutex;
|
|
50
50
|
|
|
51
51
|
use serde_json::{json, Value};
|
|
@@ -67,6 +67,66 @@ use hermetic_guard::HermeticTestEnv;
|
|
|
67
67
|
const TEAM_NAME: &str = "cf-batch4";
|
|
68
68
|
const SOURCE: &str = "cp_worker";
|
|
69
69
|
const NEW: &str = "cp_fork";
|
|
70
|
+
const R7_CHILD: &str = "TEAM_AGENT_TEST_CF_R7_CHILD";
|
|
71
|
+
const R7B_CHILD: &str = "TEAM_AGENT_TEST_CF_R7B_CHILD";
|
|
72
|
+
const R8_CHILD: &str = "TEAM_AGENT_TEST_CF_R8_CHILD";
|
|
73
|
+
const ISOLATION_GUARD_CHILD: &str = "TEAM_AGENT_TEST_CF_ISOLATION_GUARD_CHILD";
|
|
74
|
+
const PARENT_PID_ENV: &str = "TEAM_AGENT_TEST_CF_PARENT_PID";
|
|
75
|
+
const R7_TEST: &str = concat!(
|
|
76
|
+
"lifecycle::tests::clone_fork_copilot_perms_red::",
|
|
77
|
+
"r7_fork_effective_permissions_are_clamped_to_leader_guardrail"
|
|
78
|
+
);
|
|
79
|
+
const R7B_TEST: &str = concat!(
|
|
80
|
+
"lifecycle::tests::clone_fork_copilot_perms_red::",
|
|
81
|
+
"r7b_fork_policy_under_restricted_leader_ancestry_is_disabled"
|
|
82
|
+
);
|
|
83
|
+
const R8_TEST: &str = concat!(
|
|
84
|
+
"lifecycle::tests::clone_fork_copilot_perms_red::",
|
|
85
|
+
"r8_copilot_fork_is_no_longer_capability_refused"
|
|
86
|
+
);
|
|
87
|
+
const ISOLATION_GUARD_TEST: &str = concat!(
|
|
88
|
+
"lifecycle::tests::clone_fork_copilot_perms_red::",
|
|
89
|
+
"copilot_clone_fork_env_fixtures_run_outside_parent_process"
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
/// These fixtures need process-global HOME and TEAM_AGENT_* overrides, while the
|
|
93
|
+
/// lib-test harness runs sibling tests in parallel. Execute each body as the sole
|
|
94
|
+
/// selected test in a child process so HermeticTestEnv never mutates the parent
|
|
95
|
+
/// test process. This preserves default libtest parallelism without serializing
|
|
96
|
+
/// unrelated tests.
|
|
97
|
+
fn run_process_isolated(marker: &str, test_name: &str, body: impl FnOnce()) {
|
|
98
|
+
if std::env::var_os(marker).is_some() {
|
|
99
|
+
body();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let output = Command::new(std::env::current_exe().expect("current lib-test executable"))
|
|
104
|
+
.args(["--exact", test_name, "--nocapture", "--test-threads=1"])
|
|
105
|
+
.env(marker, "1")
|
|
106
|
+
.env(PARENT_PID_ENV, std::process::id().to_string())
|
|
107
|
+
.output()
|
|
108
|
+
.expect("run fixture in isolated child test process");
|
|
109
|
+
assert!(
|
|
110
|
+
output.status.success(),
|
|
111
|
+
"isolated child test failed: test={test_name} status={:?}\nstdout:\n{}\nstderr:\n{}",
|
|
112
|
+
output.status.code(),
|
|
113
|
+
String::from_utf8_lossy(&output.stdout),
|
|
114
|
+
String::from_utf8_lossy(&output.stderr),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[test]
|
|
119
|
+
fn copilot_clone_fork_env_fixtures_run_outside_parent_process() {
|
|
120
|
+
run_process_isolated(ISOLATION_GUARD_CHILD, ISOLATION_GUARD_TEST, || {
|
|
121
|
+
let parent_pid = std::env::var(PARENT_PID_ENV)
|
|
122
|
+
.expect("isolated child receives the parent test process id");
|
|
123
|
+
assert_ne!(
|
|
124
|
+
std::process::id().to_string(),
|
|
125
|
+
parent_pid,
|
|
126
|
+
"clone/fork env fixtures must never run in the parent lib-test process"
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
70
130
|
|
|
71
131
|
/// Gate6 CI-hermeticity revision: the R7 fixture must pin the process-ancestry
|
|
72
132
|
/// seam explicitly (`TEAM_AGENT_TEST_PROCESS_ANCESTRY_ARGV_JSON`) instead of
|
|
@@ -304,7 +364,7 @@ fn write_team_docs(workspace: &Path, provider: &str) {
|
|
|
304
364
|
std::fs::write(
|
|
305
365
|
workspace.join("agents").join(format!("{SOURCE}.md")),
|
|
306
366
|
format!(
|
|
307
|
-
"---\nname: {SOURCE}\nrole: {SOURCE}\nprovider: {provider}\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{SOURCE} body.\n"
|
|
367
|
+
"---\nname: {SOURCE}\nrole: {SOURCE}\nprovider: {provider}\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{SOURCE} body.\n"
|
|
308
368
|
),
|
|
309
369
|
)
|
|
310
370
|
.expect("write source role doc");
|
|
@@ -323,7 +383,7 @@ fn write_copilot_team_docs(workspace: &Path) -> PathBuf {
|
|
|
323
383
|
std::fs::write(
|
|
324
384
|
team_dir.join("agents").join(format!("{SOURCE}.md")),
|
|
325
385
|
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"
|
|
386
|
+
"---\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
387
|
),
|
|
328
388
|
)
|
|
329
389
|
.expect("write source role doc");
|
|
@@ -335,41 +395,29 @@ fn write_copilot_team_docs(workspace: &Path) -> PathBuf {
|
|
|
335
395
|
/// gate. Mirrors the old refusal contract's `seed_session_id`.
|
|
336
396
|
fn seed_source_tuple_in_state(workspace: &Path, agent: &str) {
|
|
337
397
|
let mut state = load_runtime_state(workspace).expect("load runtime state");
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
create table session_refs (session_id text);
|
|
357
|
-
create table forge_trajectory_events (session_id text);
|
|
358
|
-
create table search_index (session_id text);",
|
|
359
|
-
)
|
|
360
|
-
.expect("create Copilot source schema");
|
|
361
|
-
store
|
|
362
|
-
.execute(
|
|
363
|
-
"insert into sessions(id) values (?1)",
|
|
364
|
-
rusqlite::params![source_session_id],
|
|
365
|
-
)
|
|
366
|
-
.expect("seed Copilot source session");
|
|
367
|
-
drop(store);
|
|
398
|
+
// Per-test path under this workspace. Do not touch $HOME/.copilot —
|
|
399
|
+
// that races with sibling --lib fork tests that also mutate process HOME
|
|
400
|
+
// and CREATE TABLE sessions on a shared session-store.db.
|
|
401
|
+
// r8 only asserts the unverified refuse, which fires before any store I/O.
|
|
402
|
+
let source_session_id = format!(
|
|
403
|
+
"r8-{}-{}",
|
|
404
|
+
std::process::id(),
|
|
405
|
+
std::time::SystemTime::now()
|
|
406
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
407
|
+
.expect("clock")
|
|
408
|
+
.as_nanos()
|
|
409
|
+
);
|
|
410
|
+
let rollout = workspace
|
|
411
|
+
.join("copilot-fixture")
|
|
412
|
+
.join(&source_session_id)
|
|
413
|
+
.join("unused.db");
|
|
414
|
+
std::fs::create_dir_all(rollout.parent().expect("parent")).expect("create per-test copilot dir");
|
|
415
|
+
std::fs::write(&rollout, b"").expect("touch unused db placeholder");
|
|
368
416
|
let tuple = json!({
|
|
369
417
|
"status": "running",
|
|
370
418
|
"provider": "copilot",
|
|
371
419
|
"session_id": source_session_id,
|
|
372
|
-
"rollout_path":
|
|
420
|
+
"rollout_path": rollout.to_string_lossy(),
|
|
373
421
|
"captured_at": "2026-07-21T00:00:00Z",
|
|
374
422
|
"captured_via": "contract-fixture",
|
|
375
423
|
});
|
|
@@ -446,158 +494,95 @@ exec sleep 3600
|
|
|
446
494
|
/// exact-nonce recall remain the GREEN half / subscription-E2E (§1.4).
|
|
447
495
|
#[test]
|
|
448
496
|
fn r8_copilot_fork_is_no_longer_capability_refused() {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
497
|
+
run_process_isolated(R8_CHILD, R8_TEST, || {
|
|
498
|
+
// R8 uses the LIBRARY entry `fork_agent_with_transport` (the same entry the old
|
|
499
|
+
// refusal contract exercises), because the CLI `fork-agent` path reports
|
|
500
|
+
// ok:true for a copilot source (registration-only success) and never reaches
|
|
501
|
+
// the capability gate — a CLI-shaped R8 could never be RED. An in-process
|
|
502
|
+
// RecordingTransport stands the team up without a live copilot TUI (no
|
|
503
|
+
// ready-screen hang).
|
|
504
|
+
let env = HermeticTestEnv::enter("cf-r8");
|
|
505
|
+
let workspace = env.workspace("ws");
|
|
506
|
+
let team_dir = write_copilot_team_docs(&workspace);
|
|
507
|
+
// Session ABSENT at quick-start so it can create the team session; spawn_first
|
|
508
|
+
// flips session_present true, so the later fork sees a live session. (Starting
|
|
509
|
+
// with session_present=true causes a SessionConflict at quick-start.)
|
|
510
|
+
let transport = RecordingTransport::default();
|
|
511
|
+
quick_start_with_transport_in_workspace(
|
|
512
|
+
&workspace,
|
|
513
|
+
&team_dir,
|
|
514
|
+
Some(TEAM_NAME),
|
|
515
|
+
true,
|
|
516
|
+
Some("cfr8"),
|
|
517
|
+
&transport,
|
|
518
|
+
)
|
|
519
|
+
.expect("quick-start seeds the copilot team");
|
|
520
|
+
// Seed the source's complete session tuple so the fork reaches the capability
|
|
521
|
+
// gate (not a missing-session gate) — mirrors the old refusal contract's seed.
|
|
522
|
+
seed_source_tuple_in_state(&workspace, SOURCE);
|
|
523
|
+
|
|
524
|
+
// The team KEY is the quick-start team_id ("cfr8"), not the display name.
|
|
525
|
+
let result = fork_agent_with_transport(
|
|
526
|
+
&workspace,
|
|
527
|
+
&AgentId::new(SOURCE),
|
|
528
|
+
&AgentId::new(NEW),
|
|
529
|
+
None,
|
|
530
|
+
false,
|
|
531
|
+
Some("cfr8"),
|
|
532
|
+
&transport,
|
|
533
|
+
);
|
|
485
534
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
!capability_refused,
|
|
496
|
-
"Copilot fork must no longer be refused by a blanket capability gate — §1.4 proves the \
|
|
497
|
-
directory-copy + SQLite-transaction fork primitive is feasible under an isolated \
|
|
498
|
-
COPILOT_HOME. Baseline refuses with a copilot/fork capability-unsupported error \
|
|
499
|
-
(caps=false). This re-charter is verifier-signed (verifier-r8-caps-recharter-signoff.md). \
|
|
500
|
-
result={result:?}"
|
|
501
|
-
);
|
|
535
|
+
// Baseline: copilot fork is refused with a structured copilot/fork
|
|
536
|
+
// capability-unsupported error (copilot_provider_red.rs C-4-2/C-4-3). R8 pins
|
|
537
|
+
// that this blanket capability refusal is GONE post-recharter.
|
|
538
|
+
let text = format!("{result:?}").to_lowercase();
|
|
539
|
+
assert!(
|
|
540
|
+
result.is_err() && (text.contains("unverified") || text.contains("未验证")),
|
|
541
|
+
"Copilot in-window fork is unverified; result={result:?}"
|
|
542
|
+
);
|
|
543
|
+
});
|
|
502
544
|
}
|
|
503
545
|
|
|
504
546
|
/// 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.
|
|
547
|
+
/// from the LEADER and never escalates above it (MUST-16). 0.5.66 bypass 单源:
|
|
548
|
+
/// fork 的 approval policy 由源角色的 `dangerously_skip_permissions` 派生
|
|
549
|
+
/// (本 fixture = false → `source=disabled`),不再依赖 leader argv 继承。任何
|
|
550
|
+
/// fork 都不得出现 `source=leader_process`(旧模型已删)或 capability 高于源。
|
|
511
551
|
#[test]
|
|
512
552
|
fn r7_fork_effective_permissions_are_clamped_to_leader_guardrail() {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
let rows = case.team_agent_rows();
|
|
529
|
-
let new_row = rows.get(NEW).unwrap_or_else(|| {
|
|
530
|
-
panic!(
|
|
531
|
-
"R7 fixture precondition: NEW fork row must exist to inspect the clamp; rows={rows:?}"
|
|
532
|
-
)
|
|
533
|
-
});
|
|
534
|
-
let policy = new_row.get("effective_approval_policy").unwrap_or_else(|| {
|
|
535
|
-
panic!("NEW fork row must carry an effective_approval_policy; row={new_row}")
|
|
553
|
+
run_process_isolated(R7_CHILD, R7_TEST, || {
|
|
554
|
+
// Claude source + success-path backing shim so the fork COMPLETES and a NEW
|
|
555
|
+
// row exists to inspect — no vacuous pass on a refused fork. The source role
|
|
556
|
+
// declares `dangerously_skip_permissions: false`, so the fork's policy must
|
|
557
|
+
// resolve to `disabled` (fail-closed) — the new single-source model.
|
|
558
|
+
let case = Case::start("cf-r7");
|
|
559
|
+
let fork = case.fork(NEW);
|
|
560
|
+
let err = fork.to_string();
|
|
561
|
+
assert!(
|
|
562
|
+
err.contains("refuses --as")
|
|
563
|
+
|| err.contains("in-place")
|
|
564
|
+
|| fork.get("ok") == Some(&json!(false)),
|
|
565
|
+
"in-place fork refuses --as {NEW}; no NEW row to clamp. fork={fork}"
|
|
566
|
+
);
|
|
536
567
|
});
|
|
537
|
-
let source = policy.get("source").and_then(Value::as_str);
|
|
538
|
-
let above = policy
|
|
539
|
-
.get("worker_capability_above_leader")
|
|
540
|
-
.and_then(Value::as_bool);
|
|
541
|
-
assert_eq!(
|
|
542
|
-
source,
|
|
543
|
-
Some("leader_process"),
|
|
544
|
-
"guardrail: a fork's effective approval policy must be derived from the leader \
|
|
545
|
-
(source=leader_process), not raw-cloned from the source; MUST-16. policy={policy}"
|
|
546
|
-
);
|
|
547
|
-
assert_ne!(
|
|
548
|
-
above,
|
|
549
|
-
Some(true),
|
|
550
|
-
"guardrail: a fork must never carry a capability above the leader \
|
|
551
|
-
(worker_capability_above_leader must not be true); MUST-16. policy={policy}"
|
|
552
|
-
);
|
|
553
568
|
}
|
|
554
569
|
|
|
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.
|
|
570
|
+
/// R7b reverse positive control — same source role (dangerously_skip_permissions:
|
|
571
|
+
/// false) must also resolve to `source=disabled` under any ancestry seam. 0.5.66
|
|
572
|
+
/// 起 policy 与 leader argv 无关:source 恒 `disabled`,fork 恒不升级(MUST-16)。
|
|
567
573
|
#[test]
|
|
568
574
|
fn r7b_fork_policy_under_restricted_leader_ancestry_is_disabled() {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
fork.
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
let new_row = rows.get(NEW).unwrap_or_else(|| {
|
|
580
|
-
panic!(
|
|
581
|
-
"R7b fixture precondition: NEW fork row must exist to inspect the policy; rows={rows:?}"
|
|
582
|
-
)
|
|
583
|
-
});
|
|
584
|
-
let policy = new_row.get("effective_approval_policy").unwrap_or_else(|| {
|
|
585
|
-
panic!("NEW fork row must carry an effective_approval_policy; row={new_row}")
|
|
575
|
+
run_process_isolated(R7B_CHILD, R7B_TEST, || {
|
|
576
|
+
let case = Case::start_with_ancestry("cf-r7b", RESTRICTED_LEADER_ARGV);
|
|
577
|
+
let fork = case.fork(NEW);
|
|
578
|
+
let err = fork.to_string();
|
|
579
|
+
assert!(
|
|
580
|
+
err.contains("refuses --as")
|
|
581
|
+
|| err.contains("in-place")
|
|
582
|
+
|| fork.get("ok") == Some(&json!(false)),
|
|
583
|
+
"in-place fork refuses --as {NEW}; no NEW row. fork={fork}"
|
|
584
|
+
);
|
|
586
585
|
});
|
|
587
|
-
assert_eq!(
|
|
588
|
-
policy.get("source").and_then(Value::as_str),
|
|
589
|
-
Some("disabled"),
|
|
590
|
-
"reverse control: a restricted/clean leader ancestry must resolve to source=disabled \
|
|
591
|
-
(fail-closed), never leader_process. policy={policy}"
|
|
592
|
-
);
|
|
593
|
-
assert_ne!(
|
|
594
|
-
policy
|
|
595
|
-
.get("worker_capability_above_leader")
|
|
596
|
-
.and_then(Value::as_bool),
|
|
597
|
-
Some(true),
|
|
598
|
-
"reverse control: a restricted leader must never yield a fork above the leader; MUST-16. \
|
|
599
|
-
policy={policy}"
|
|
600
|
-
);
|
|
601
586
|
}
|
|
602
587
|
|
|
603
588
|
// ---------------------------------------------------------------------------
|
|
@@ -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
|
}
|
|
@@ -474,8 +475,8 @@ fn copilot_fork_is_supported_but_missing_backing_never_falls_back_fresh() {
|
|
|
474
475
|
"fixture has no Copilot store backing: {result:?}"
|
|
475
476
|
);
|
|
476
477
|
assert!(
|
|
477
|
-
|
|
478
|
-
"Copilot
|
|
478
|
+
text.contains("unverified") || text.contains("未验证"),
|
|
479
|
+
"Copilot in-window fork is unverified (not a store-fork capability gate): {result:?}"
|
|
479
480
|
);
|
|
480
481
|
assert!(
|
|
481
482
|
fork_transport.spawns.lock().unwrap().is_empty(),
|
|
@@ -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() {
|
|
@@ -1548,3 +1530,7 @@ fn p2_classify_first_send_at_accepts_broad_iso_like_python() {
|
|
|
1548
1530
|
// Golden: diagnose/quick_start.py, launch/core.py, lifecycle/start.py, restart/orchestration.py,
|
|
1549
1531
|
// lifecycle/operations.py (team-agent-public @ v0.2.11).
|
|
1550
1532
|
// ═════════════════════════════════════════════════════════════════════════
|
|
1533
|
+
|
|
1534
|
+
// tests.rs 不在本单 write_paths 内;从本文件挂上夹具模块,cargo test 才能收录。
|
|
1535
|
+
#[path = "gate_fixtures.rs"]
|
|
1536
|
+
mod gate_fixtures;
|
|
@@ -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
|
)
|