@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
|
@@ -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>)>>>;
|
|
@@ -201,7 +201,13 @@ impl crate::transport::Transport for LaneTransport {
|
|
|
201
201
|
r: crate::transport::CaptureRange,
|
|
202
202
|
) -> Result<crate::transport::CapturedText, crate::transport::TransportError> {
|
|
203
203
|
Ok(crate::transport::CapturedText {
|
|
204
|
-
|
|
204
|
+
// A fresh worker has reached the ready prompt by the time this
|
|
205
|
+
// deterministic lifecycle replay observes its pane. Returning
|
|
206
|
+
// the stable ready marker keeps the replay focused on the
|
|
207
|
+
// single-lock transaction instead of burning the provider's
|
|
208
|
+
// bounded startup-prompt polling interval on an unobservable
|
|
209
|
+
// empty screen.
|
|
210
|
+
text: "OpenAI Codex\n›".to_string(),
|
|
205
211
|
range: r,
|
|
206
212
|
})
|
|
207
213
|
}
|
|
@@ -816,7 +822,7 @@ fn current_alias_authority_does_not_leak_into_real_sibling_same_id_retirement()
|
|
|
816
822
|
);
|
|
817
823
|
}
|
|
818
824
|
|
|
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";
|
|
825
|
+
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
826
|
|
|
821
827
|
struct HermeticTestEnv {
|
|
822
828
|
root: std::path::PathBuf,
|
|
@@ -1390,9 +1396,11 @@ fn remove_preserves_external_role_source_for_both_flag_forms() {
|
|
|
1390
1396
|
}
|
|
1391
1397
|
}
|
|
1392
1398
|
|
|
1393
|
-
// A-28
|
|
1394
|
-
//
|
|
1395
|
-
//
|
|
1399
|
+
// A-28 was: default remove must preserve registered managed markdown.
|
|
1400
|
+
// ledger.seat-supply-prereq overturned that for files under
|
|
1401
|
+
// `.team/dynamic-role-files/` (framework materialization, not user asset).
|
|
1402
|
+
// Keep the test name; flip the assertion. External --role-file is covered
|
|
1403
|
+
// by `remove_preserves_external_role_source_for_both_flag_forms`.
|
|
1396
1404
|
#[test]
|
|
1397
1405
|
fn remove_agent_preserves_registered_role_markdown_by_default() {
|
|
1398
1406
|
let ws = lanea_ws_agents(json!({
|
|
@@ -1417,15 +1425,13 @@ fn remove_agent_preserves_registered_role_markdown_by_default() {
|
|
|
1417
1425
|
None,
|
|
1418
1426
|
&LaneTransport::new("team-laneateam", &[]),
|
|
1419
1427
|
);
|
|
1420
|
-
assert!(result.is_ok(), "remove-agent should unregister the seat: {result:?}");
|
|
1421
1428
|
assert!(
|
|
1422
|
-
|
|
1423
|
-
"
|
|
1429
|
+
result.is_ok(),
|
|
1430
|
+
"remove-agent should unregister the seat: {result:?}"
|
|
1424
1431
|
);
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
"A-28: remove-agent must preserve the registered role markdown by default"
|
|
1432
|
+
assert!(
|
|
1433
|
+
!role.exists(),
|
|
1434
|
+
"managed role markdown must be gone after remove-agent so the next same-id clone is not blocked"
|
|
1429
1435
|
);
|
|
1430
1436
|
}
|
|
1431
1437
|
|
|
@@ -1455,7 +1461,35 @@ fn remove_preserves_managed_path_symlink_escape() {
|
|
|
1455
1461
|
);
|
|
1456
1462
|
assert!(result.is_ok(), "remove failed: {result:?}");
|
|
1457
1463
|
assert_eq!(std::fs::read(&external).unwrap(), b"external target\n");
|
|
1458
|
-
assert!(
|
|
1464
|
+
assert!(
|
|
1465
|
+
!managed.symlink_metadata().is_ok(),
|
|
1466
|
+
"managed symlink must be unlinked; must not follow and delete the external target"
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
#[test]
|
|
1471
|
+
fn remove_agent_deletes_unrecorded_default_managed_role() {
|
|
1472
|
+
let ws = lanea_ws_agents(json!({
|
|
1473
|
+
"alpha": { "status": "stopped", "provider": "codex", "window": "alpha" },
|
|
1474
|
+
"bravo": { "status": "stopped", "provider": "codex", "window": "bravo" }
|
|
1475
|
+
}));
|
|
1476
|
+
let role = ws.join(".team").join("dynamic-role-files").join("alpha.md");
|
|
1477
|
+
std::fs::create_dir_all(role.parent().unwrap()).unwrap();
|
|
1478
|
+
std::fs::write(&role, b"unrecorded default managed copy\n").unwrap();
|
|
1479
|
+
|
|
1480
|
+
let result = remove_agent_with_transport(
|
|
1481
|
+
&ws,
|
|
1482
|
+
&aid("alpha"),
|
|
1483
|
+
true,
|
|
1484
|
+
true,
|
|
1485
|
+
None,
|
|
1486
|
+
&LaneTransport::new("team-laneateam", &[]),
|
|
1487
|
+
);
|
|
1488
|
+
assert!(result.is_ok(), "remove failed: {result:?}");
|
|
1489
|
+
assert!(
|
|
1490
|
+
!role.exists(),
|
|
1491
|
+
"default managed path must be cleared even when state.dynamic_role_file is unset"
|
|
1492
|
+
);
|
|
1459
1493
|
}
|
|
1460
1494
|
|
|
1461
1495
|
#[test]
|
|
@@ -1659,9 +1693,8 @@ fn lanea_fork_dup_target_leader_id_is_already_exists() {
|
|
|
1659
1693
|
fork_agent_with_transport(&ws, &aid("alpha"), &aid("leader"), None, false, None, &tx)
|
|
1660
1694
|
);
|
|
1661
1695
|
assert!(
|
|
1662
|
-
text.contains("
|
|
1663
|
-
"
|
|
1664
|
-
'agent id already exists: leader'; Rust skips the dup guard for the leader id and proceeds. got {text}"
|
|
1696
|
+
text.contains("unverified") || text.contains("未验证") || text.contains("refuses --as"),
|
|
1697
|
+
"codex in-window fork is unverified; leader-id duplicate is not reached. got {text}"
|
|
1665
1698
|
);
|
|
1666
1699
|
}
|
|
1667
1700
|
|
|
@@ -1679,9 +1712,11 @@ fn lanea_fork_window_already_exists_guard_before_spec_mutation() {
|
|
|
1679
1712
|
fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx)
|
|
1680
1713
|
);
|
|
1681
1714
|
assert!(
|
|
1682
|
-
text.contains("
|
|
1683
|
-
|
|
1684
|
-
|
|
1715
|
+
text.contains("unverified")
|
|
1716
|
+
|| text.contains("未验证")
|
|
1717
|
+
|| text.contains("refuses --as")
|
|
1718
|
+
|| text.contains("tmux window already exists for fork target: team-laneateam:newfork"),
|
|
1719
|
+
"codex in-window fork is unverified; window-exists guard is not reached. got {text}"
|
|
1685
1720
|
);
|
|
1686
1721
|
let spec_text = std::fs::read_to_string(ws.join("team.spec.yaml")).unwrap();
|
|
1687
1722
|
assert!(
|
|
@@ -1705,9 +1740,8 @@ fn lanea_fork_gate_error_text_and_spec_rollback_on_adapter_arm() {
|
|
|
1705
1740
|
fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx);
|
|
1706
1741
|
let text = format!("{result:?}");
|
|
1707
1742
|
assert!(
|
|
1708
|
-
text.contains("
|
|
1709
|
-
"
|
|
1710
|
-
fork'; Rust surfaces the generic 'capability unsupported: Codex:fork'. got {text}"
|
|
1743
|
+
text.contains("unverified") || text.contains("未验证"),
|
|
1744
|
+
"codex is unverified (any auth), not 'does not support'. got {text}"
|
|
1711
1745
|
);
|
|
1712
1746
|
let spec_text = std::fs::read_to_string(ws.join("team.spec.yaml")).unwrap();
|
|
1713
1747
|
assert!(
|
|
@@ -1736,25 +1770,16 @@ fn lanea_fork_report_session_id_is_not_pane_id() {
|
|
|
1736
1770
|
json!(discoverable_source.to_string_lossy().to_string());
|
|
1737
1771
|
crate::state::persist::save_runtime_state(&ws, &state).unwrap();
|
|
1738
1772
|
let tx = LaneTransport::new("team-laneateam", &[]);
|
|
1739
|
-
let
|
|
1740
|
-
fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx)
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
"golden operations.py:399,408: report.session_id is the captured provider session id / None, NEVER the \
|
|
1746
|
-
tmux pane id; Rust returns Some(pane_id='%newfork')"
|
|
1747
|
-
);
|
|
1773
|
+
let result =
|
|
1774
|
+
fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx);
|
|
1775
|
+
let err = match result {
|
|
1776
|
+
Err(error) => error.to_string(),
|
|
1777
|
+
Ok(_) => panic!("codex in-window fork is unverified and must refuse"),
|
|
1778
|
+
};
|
|
1748
1779
|
assert!(
|
|
1749
|
-
|
|
1750
|
-
"
|
|
1780
|
+
err.contains("unverified") || err.contains("未验证"),
|
|
1781
|
+
"codex must refuse as unverified; got {err}"
|
|
1751
1782
|
);
|
|
1752
|
-
let state = crate::state::persist::load_runtime_state(&ws).unwrap();
|
|
1753
|
-
let row = &state["agents"]["newfork"];
|
|
1754
|
-
assert!(row["spawned_at"]
|
|
1755
|
-
.as_str()
|
|
1756
|
-
.is_some_and(|value| chrono::DateTime::parse_from_rfc3339(value).is_ok()));
|
|
1757
|
-
assert_eq!(row["spawn_epoch"], serde_json::json!(1));
|
|
1758
1783
|
}
|
|
1759
1784
|
|
|
1760
1785
|
#[test]
|
|
@@ -31,8 +31,8 @@ struct HermeticTestEnv;
|
|
|
31
31
|
|
|
32
32
|
const QS_TEAM_MD: &str =
|
|
33
33
|
"---\nname: quickteam\nobjective: Quick start.\nprovider: codex\n---\n\nQuick-start team.\n";
|
|
34
|
-
pub(super) const QS_VALID_ROLE: &str = "---\nname: implementer\nrole: Implementation Engineer\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nImplement bounded tasks.\n";
|
|
35
|
-
const QS_ROLE_NO_PROVIDER: &str = "---\nname: implementer\nrole: Implementation Engineer\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nImplement bounded tasks.\n";
|
|
34
|
+
pub(super) const QS_VALID_ROLE: &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 bounded tasks.\n";
|
|
35
|
+
const QS_ROLE_NO_PROVIDER: &str = "---\nname: implementer\nrole: Implementation Engineer\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nImplement bounded tasks.\n";
|
|
36
36
|
|
|
37
37
|
/// A REAL team dir `<base>/teamdir/{TEAM.md, agents/implementer.md}` — already in team-dir
|
|
38
38
|
/// layout, so quick_start's prepare_quick_start_team returns it as-is and writes the compiled
|
|
@@ -57,7 +57,7 @@ fn quick_start_team_dir_with_roles(role_docs: &[(&str, &str)]) -> PathBuf {
|
|
|
57
57
|
|
|
58
58
|
fn role_doc(id: &str) -> String {
|
|
59
59
|
format!(
|
|
60
|
-
"---\nname: {id}\nrole: {id} Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{id} worker.\n"
|
|
60
|
+
"---\nname: {id}\nrole: {id} Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{id} worker.\n"
|
|
61
61
|
)
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -448,7 +448,7 @@ fn add_agent_proceeds_past_owner_gate_and_reaches_recompile() {
|
|
|
448
448
|
let role = ws.join("w2-role.md");
|
|
449
449
|
std::fs::write(
|
|
450
450
|
&role,
|
|
451
|
-
"---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nSecond worker.\n",
|
|
451
|
+
"---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nSecond worker.\n",
|
|
452
452
|
)
|
|
453
453
|
.unwrap();
|
|
454
454
|
let transport = OfflineTransport::new();
|
|
@@ -617,23 +617,8 @@ fn spine_quick_start_seeds_state_under_team_workspace_not_team_dir() {
|
|
|
617
617
|
);
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
// #10 — launch dry-run safety
|
|
621
|
-
//
|
|
622
|
-
#[test]
|
|
623
|
-
fn spine_launch_dry_run_safety_reflects_spec_dangerous() {
|
|
624
|
-
let team = quick_start_team_dir_custom(QS_TEAM_MD_DANGEROUS, QS_VALID_ROLE);
|
|
625
|
-
let spec_path = compiled_spec_path(&team);
|
|
626
|
-
let report = launch(&spec_path, true, false, true).expect("dry_run launch");
|
|
627
|
-
assert!(
|
|
628
|
-
report.safety.enabled,
|
|
629
|
-
"safety must reflect spec.runtime.dangerous_auto_approve=true"
|
|
630
|
-
);
|
|
631
|
-
assert_eq!(
|
|
632
|
-
report.safety.source,
|
|
633
|
-
DangerousApprovalSource::RuntimeConfig,
|
|
634
|
-
"safety source must be runtime_config when spec-declared"
|
|
635
|
-
);
|
|
636
|
-
}
|
|
620
|
+
// #10 removed — launch dry-run safety was derived from spec.runtime.dangerous_auto_approve.
|
|
621
|
+
// 0.5.66 bypass 单源:该字段废弃,safety 改由 per-agent `dangerously_skip_permissions` 派生。
|
|
637
622
|
|
|
638
623
|
// #12 — launch dry-run produces one RoutingDecision PER spec.task via route_task, with the real task id
|
|
639
624
|
// and the route_task reason taxonomy — not one synthetic 'default_assignee' route. Golden core.py:77-88.
|
|
@@ -709,7 +694,7 @@ fn e5_add_agent_does_not_copy_role_into_platform_dir_and_injects_into_spec() {
|
|
|
709
694
|
seed_canonical_team_identity(&team, "teamdir");
|
|
710
695
|
// External role file OUTSIDE team_dir/agents, with recognizable body content.
|
|
711
696
|
let role = team.parent().unwrap().join("w2-external-role.md");
|
|
712
|
-
let role_body = "---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nUNIQUE-E5-BUG1-MARKER body for w2.\n";
|
|
697
|
+
let role_body = "---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nUNIQUE-E5-BUG1-MARKER body for w2.\n";
|
|
713
698
|
std::fs::write(&role, role_body).unwrap();
|
|
714
699
|
let transport = OfflineTransport::new();
|
|
715
700
|
// The spawn may not complete under OfflineTransport; we only assert the no-copy + spec-inject
|
|
@@ -749,7 +734,7 @@ fn e5_restart_rebuilds_runtime_spec_from_role_docs() {
|
|
|
749
734
|
// Edit a role doc AFTER initial compile: change alpha's role text.
|
|
750
735
|
std::fs::write(
|
|
751
736
|
ws.join("agents").join("alpha.md"),
|
|
752
|
-
"---\nname: alpha\nrole: RENAMED Alpha Role\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nAlpha edited.\n",
|
|
737
|
+
"---\nname: alpha\nrole: RENAMED Alpha Role\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nAlpha edited.\n",
|
|
753
738
|
)
|
|
754
739
|
.unwrap();
|
|
755
740
|
let transport = OfflineTransport::new();
|
|
@@ -974,7 +959,7 @@ fn e5_add_agent_resolves_team_dir_to_role_dir_when_runtime_spec_exists() {
|
|
|
974
959
|
let role = team.join("w2-role.md");
|
|
975
960
|
std::fs::write(
|
|
976
961
|
&role,
|
|
977
|
-
"---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nw2.\n",
|
|
962
|
+
"---\nname: w2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nw2.\n",
|
|
978
963
|
)
|
|
979
964
|
.unwrap();
|
|
980
965
|
let transport = OfflineTransport::new();
|
|
@@ -1563,9 +1548,9 @@ fn quick_start_fresh_ws_spawns_resident_tmux_and_coordinator() {
|
|
|
1563
1548
|
// Golden: restart/orchestration.py (Route-B resume spawn), lifecycle/start.py, lifecycle/operations.py.
|
|
1564
1549
|
// ═════════════════════════════════════════════════════════════════════════
|
|
1565
1550
|
|
|
1566
|
-
pub(super) const DELEG_ROLE_ALPHA: &str = "---\nname: alpha\nrole: Alpha Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nAlpha.\n";
|
|
1567
|
-
pub(super) const DELEG_ROLE_BRAVO: &str = "---\nname: bravo\nrole: Bravo Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nBravo.\n";
|
|
1568
|
-
const DELEG_ROLE_WORKER2: &str = "---\nname: worker2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nSecond worker.\n";
|
|
1551
|
+
pub(super) const DELEG_ROLE_ALPHA: &str = "---\nname: alpha\nrole: Alpha Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nAlpha.\n";
|
|
1552
|
+
pub(super) const DELEG_ROLE_BRAVO: &str = "---\nname: bravo\nrole: Bravo Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nBravo.\n";
|
|
1553
|
+
const DELEG_ROLE_WORKER2: &str = "---\nname: worker2\nrole: Second Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nSecond worker.\n";
|
|
1569
1554
|
|
|
1570
1555
|
/// A workspace (= self-contained team dir) with a compiled 2-agent spec + state listing alpha/bravo as
|
|
1571
1556
|
/// RESUMABLE (running, valid first_send_at, session_id) + a seeded HEALTHY coordinator.
|
|
@@ -2437,7 +2422,7 @@ fn restart_allow_fresh_copilot_keeps_session_id_null_until_capture_confirms() {
|
|
|
2437
2422
|
.unwrap();
|
|
2438
2423
|
std::fs::write(
|
|
2439
2424
|
ws.join("agents").join("alpha.md"),
|
|
2440
|
-
"---\nname: alpha\nrole: Alpha Worker\nprovider: copilot\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nAlpha.\n",
|
|
2425
|
+
"---\nname: alpha\nrole: Alpha Worker\nprovider: copilot\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nAlpha.\n",
|
|
2441
2426
|
)
|
|
2442
2427
|
.unwrap();
|
|
2443
2428
|
let spec = crate::compiler::compile_team(&ws).expect("compile copilot team");
|
|
@@ -2541,7 +2526,7 @@ fn restart_allow_fresh_claude_clears_poisoned_session_id() {
|
|
|
2541
2526
|
.unwrap();
|
|
2542
2527
|
std::fs::write(
|
|
2543
2528
|
ws.join("agents").join("alpha.md"),
|
|
2544
|
-
"---\nname: alpha\nrole: Alpha\nprovider: claude\nmodel: sonnet\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nAlpha.\n",
|
|
2529
|
+
"---\nname: alpha\nrole: Alpha\nprovider: claude\nmodel: sonnet\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nAlpha.\n",
|
|
2545
2530
|
)
|
|
2546
2531
|
.unwrap();
|
|
2547
2532
|
let spec = crate::compiler::compile_team(&ws).expect("compile");
|
|
@@ -2612,7 +2597,7 @@ fn fork_refuses_source_with_partial_tuple() {
|
|
|
2612
2597
|
.unwrap();
|
|
2613
2598
|
std::fs::write(
|
|
2614
2599
|
ws.join("agents").join("src.md"),
|
|
2615
|
-
"---\nname: src\nrole: Source\nprovider: codex\nmodel: gpt\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nSrc.\n",
|
|
2600
|
+
"---\nname: src\nrole: Source\nprovider: codex\nmodel: gpt\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nSrc.\n",
|
|
2616
2601
|
)
|
|
2617
2602
|
.unwrap();
|
|
2618
2603
|
let spec = crate::compiler::compile_team(&ws).expect("compile");
|
|
@@ -2653,10 +2638,11 @@ fn fork_refuses_source_with_partial_tuple() {
|
|
|
2653
2638
|
);
|
|
2654
2639
|
let err = result.unwrap_err().to_string();
|
|
2655
2640
|
assert!(
|
|
2656
|
-
err.contains("
|
|
2641
|
+
err.contains("unverified")
|
|
2642
|
+
|| err.contains("未验证")
|
|
2657
2643
|
|| err.contains("backing")
|
|
2658
2644
|
|| err.contains("incomplete"),
|
|
2659
|
-
"0.4.6:
|
|
2645
|
+
"0.4.6/in-window: unverified providers refuse before backing check; got error={err}"
|
|
2660
2646
|
);
|
|
2661
2647
|
}
|
|
2662
2648
|
|
|
@@ -3084,6 +3070,8 @@ fn quick_start_running_agent_state_shape_after_spawn_is_golden() {
|
|
|
3084
3070
|
"mcp_config",
|
|
3085
3071
|
"permissions",
|
|
3086
3072
|
"effective_approval_policy",
|
|
3073
|
+
// 0.5.66 bypass 单源:fresh spawn 记录运行面 bypass 值(restart drift 挡板)。
|
|
3074
|
+
"as_launched_dangerously_skip_permissions",
|
|
3087
3075
|
"session_id",
|
|
3088
3076
|
"rollout_path",
|
|
3089
3077
|
"captured_at",
|
|
@@ -92,23 +92,31 @@ fn fork_agent_rollback_cleans_spawned_window_spec_state_and_mcp_after_post_spawn
|
|
|
92
92
|
|
|
93
93
|
assert!(
|
|
94
94
|
result.is_err(),
|
|
95
|
-
"
|
|
95
|
+
"in-window fork on this fixture must refuse before spawn; result={result:?}"
|
|
96
96
|
);
|
|
97
|
+
let err = format!("{result:?}");
|
|
97
98
|
assert!(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
err.contains("unverified") || err.contains("未验证") || err.contains("refuses --as"),
|
|
100
|
+
"codex in-window fork is unverified / --as is refused; no spawn to roll back. result={result:?}"
|
|
101
|
+
);
|
|
102
|
+
assert!(
|
|
103
|
+
transport.killed().is_empty(),
|
|
104
|
+
"unverified/in-place fork must not spawn a window to kill; killed={:?} result={result:?}",
|
|
102
105
|
transport.killed()
|
|
103
106
|
);
|
|
104
107
|
assert_eq!(
|
|
105
108
|
spec_after, spec_before,
|
|
106
|
-
"
|
|
109
|
+
"refused in-window fork must not mutate team.spec.yaml; result={result:?}"
|
|
110
|
+
);
|
|
111
|
+
assert!(
|
|
112
|
+
state_after
|
|
113
|
+
.pointer("/agents/newfork")
|
|
114
|
+
.is_none(),
|
|
115
|
+
"refused in-window fork must not create a newfork row; state={state_after}"
|
|
107
116
|
);
|
|
108
|
-
assert_failed_fork_has_only_target_tombstone(&state_after, "newfork", "rollbackteam");
|
|
109
117
|
assert!(
|
|
110
118
|
!mcp_path.exists(),
|
|
111
|
-
"
|
|
119
|
+
"refused in-window fork must not write MCP config; leaked={}",
|
|
112
120
|
mcp_path.display()
|
|
113
121
|
);
|
|
114
122
|
|
|
@@ -410,7 +418,7 @@ impl RollbackFixture {
|
|
|
410
418
|
|
|
411
419
|
fn agent_doc(name: &str, role: &str) -> String {
|
|
412
420
|
format!(
|
|
413
|
-
"---\nname: {name}\nrole: {role}\nprovider: codex\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{role}.\n"
|
|
421
|
+
"---\nname: {name}\nrole: {role}\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{role}.\n"
|
|
414
422
|
)
|
|
415
423
|
}
|
|
416
424
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//! purpose: worker 契约里的 MCP 工具名必须按 provider 实测书写形式渲染
|
|
2
|
+
//! contract:
|
|
3
|
+
//! claude → mcp__team_orchestrator__send_message / mcp__team_orchestrator__report_result
|
|
4
|
+
//! grok → team_orchestrator__send_message / team_orchestrator__report_result
|
|
5
|
+
//! 已验证 provider 的渲染结果不得再含 `team_orchestrator.` 点号
|
|
6
|
+
//! boundary: 只钉 compile_worker_system_prompt 字面;未验证 provider 不在此猜形式
|
|
7
|
+
|
|
8
|
+
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
9
|
+
|
|
10
|
+
use crate::lifecycle::worker_command_context::{compile_worker_system_prompt, WorkerCommandAgent};
|
|
11
|
+
use crate::model::enums::Provider;
|
|
12
|
+
|
|
13
|
+
fn compiled_prompt(provider: Provider) -> String {
|
|
14
|
+
let agent = WorkerCommandAgent::from_json(
|
|
15
|
+
&serde_json::json!({
|
|
16
|
+
"id": "w",
|
|
17
|
+
"role": "developer",
|
|
18
|
+
"tools": ["mcp_team"],
|
|
19
|
+
"output_contract": {"format": "result_envelope_v1"},
|
|
20
|
+
}),
|
|
21
|
+
Some("w"),
|
|
22
|
+
provider,
|
|
23
|
+
)
|
|
24
|
+
.expect("test agent");
|
|
25
|
+
compile_worker_system_prompt(&agent).expect("compile prompt")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[test]
|
|
29
|
+
fn claude_runtime_contract_pins_mcp_double_underscore_literals() {
|
|
30
|
+
for provider in [Provider::Claude, Provider::ClaudeCode] {
|
|
31
|
+
let prompt = compiled_prompt(provider);
|
|
32
|
+
assert!(
|
|
33
|
+
prompt.contains("mcp__team_orchestrator__report_result"),
|
|
34
|
+
"{provider:?} must render the claude transcript literal mcp__team_orchestrator__report_result; prompt={prompt}"
|
|
35
|
+
);
|
|
36
|
+
assert!(
|
|
37
|
+
prompt.contains("mcp__team_orchestrator__send_message"),
|
|
38
|
+
"{provider:?} must render the claude transcript literal mcp__team_orchestrator__send_message; prompt={prompt}"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[test]
|
|
44
|
+
fn grok_runtime_contract_pins_server_double_underscore_literals() {
|
|
45
|
+
let prompt = compiled_prompt(Provider::Grok);
|
|
46
|
+
assert!(
|
|
47
|
+
prompt.contains("team_orchestrator__report_result"),
|
|
48
|
+
"grok must render team_orchestrator__report_result; prompt={prompt}"
|
|
49
|
+
);
|
|
50
|
+
assert!(
|
|
51
|
+
prompt.contains("team_orchestrator__send_message"),
|
|
52
|
+
"grok must render team_orchestrator__send_message; prompt={prompt}"
|
|
53
|
+
);
|
|
54
|
+
assert!(
|
|
55
|
+
!prompt.contains("mcp__team_orchestrator"),
|
|
56
|
+
"grok must not use the claude mcp__ prefix; prompt={prompt}"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[test]
|
|
61
|
+
fn verified_provider_contracts_do_not_teach_dotted_tool_names() {
|
|
62
|
+
for provider in [Provider::Claude, Provider::ClaudeCode, Provider::Grok] {
|
|
63
|
+
let prompt = compiled_prompt(provider);
|
|
64
|
+
assert!(
|
|
65
|
+
!prompt.contains("team_orchestrator."),
|
|
66
|
+
"{provider:?} contract must not contain the dotted form team_orchestrator.; prompt={prompt}"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -204,17 +204,21 @@ fn add_fork_remove_share_lifecycle_lock_behavior() {
|
|
|
204
204
|
Duration::from_millis(120),
|
|
205
205
|
Duration::from_secs(5),
|
|
206
206
|
);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
207
|
+
let fork_held = crate::lifecycle::fork_agent_with_transport(
|
|
208
|
+
&fork_workspace,
|
|
209
|
+
&aid("alpha"),
|
|
210
|
+
&fork_agent,
|
|
211
|
+
None,
|
|
212
|
+
false,
|
|
213
|
+
None,
|
|
214
|
+
&fork_transport,
|
|
215
|
+
);
|
|
216
|
+
let fork_held_text = format!("{fork_held:?}");
|
|
217
|
+
assert!(
|
|
218
|
+
fork_held_text.contains("unverified")
|
|
219
|
+
|| fork_held_text.contains("未验证")
|
|
220
|
+
|| fork_held_text.contains("LifecycleLockTimeout"),
|
|
221
|
+
"codex in-window fork is unverified (lock is not reached); got {fork_held:?}"
|
|
218
222
|
);
|
|
219
223
|
assert!(
|
|
220
224
|
fork_transport.spawns().is_empty(),
|
|
@@ -232,7 +236,7 @@ fn add_fork_remove_share_lifecycle_lock_behavior() {
|
|
|
232
236
|
);
|
|
233
237
|
drop(override_guard);
|
|
234
238
|
drop(held);
|
|
235
|
-
crate::lifecycle::fork_agent_with_transport(
|
|
239
|
+
let fork_after = crate::lifecycle::fork_agent_with_transport(
|
|
236
240
|
&fork_workspace,
|
|
237
241
|
&aid("alpha"),
|
|
238
242
|
&fork_agent,
|
|
@@ -240,14 +244,11 @@ fn add_fork_remove_share_lifecycle_lock_behavior() {
|
|
|
240
244
|
false,
|
|
241
245
|
None,
|
|
242
246
|
&fork_transport,
|
|
243
|
-
)
|
|
244
|
-
|
|
247
|
+
);
|
|
248
|
+
let fork_after_text = format!("{fork_after:?}");
|
|
245
249
|
assert!(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.pointer("/agents/newfork")
|
|
249
|
-
.is_some(),
|
|
250
|
-
"released fork-agent must add the fork row"
|
|
250
|
+
fork_after_text.contains("unverified") || fork_after_text.contains("未验证"),
|
|
251
|
+
"codex in-window fork stays unverified after lock release; got {fork_after:?}"
|
|
251
252
|
);
|
|
252
253
|
|
|
253
254
|
let remove_workspace = lanea_team_ws("stopped");
|
|
@@ -463,8 +464,8 @@ fn team_dir_with_roles(role_docs: &[(&str, &str)]) -> PathBuf {
|
|
|
463
464
|
}
|
|
464
465
|
|
|
465
466
|
fn breal_workspace() -> (PathBuf, PathBuf) {
|
|
466
|
-
let w1 = "---\nname: w1\nrole: Phase B Real Worker One\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker one body.\n";
|
|
467
|
-
let w2 = "---\nname: w2\nrole: Phase B Real Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker two body.\n";
|
|
467
|
+
let w1 = "---\nname: w1\nrole: Phase B Real Worker One\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker one body.\n";
|
|
468
|
+
let w2 = "---\nname: w2\nrole: Phase B Real Worker Two\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker two body.\n";
|
|
468
469
|
let team = team_dir_with_roles(&[("w1.md", w1), ("w2.md", w2)]);
|
|
469
470
|
let workspace = team.parent().expect("team workspace").to_path_buf();
|
|
470
471
|
seed_healthy_coordinator(&workspace);
|
|
@@ -483,7 +484,7 @@ fn breal_workspace() -> (PathBuf, PathBuf) {
|
|
|
483
484
|
}
|
|
484
485
|
|
|
485
486
|
fn breal_one_worker_workspace() -> (PathBuf, PathBuf) {
|
|
486
|
-
let w1 = "---\nname: w1\nrole: Phase B Real Worker One\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\nWorker one body.\n";
|
|
487
|
+
let w1 = "---\nname: w1\nrole: Phase B Real Worker One\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\nWorker one body.\n";
|
|
487
488
|
let team = team_dir_with_roles(&[("w1.md", w1)]);
|
|
488
489
|
let workspace = team.parent().expect("team workspace").to_path_buf();
|
|
489
490
|
seed_healthy_coordinator(&workspace);
|
|
@@ -526,7 +527,7 @@ fn strip_runtime_command_context(workspace: &std::path::Path) {
|
|
|
526
527
|
|
|
527
528
|
fn role_doc(id: &str) -> String {
|
|
528
529
|
format!(
|
|
529
|
-
"---\nname: {id}\nrole: {id} Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ntools:\n - mcp_team\n---\n\n{id} worker.\n"
|
|
530
|
+
"---\nname: {id}\nrole: {id} Worker\nprovider: codex\nmodel: gpt-5.5\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - mcp_team\n---\n\n{id} worker.\n"
|
|
530
531
|
)
|
|
531
532
|
}
|
|
532
533
|
|