@team-agent/installer 0.5.60 → 0.5.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +49 -3
- package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
- package/crates/team-agent/src/cli/diagnose.rs +184 -0
- package/crates/team-agent/src/cli/emit.rs +104 -21
- package/crates/team-agent/src/cli/helpers.rs +1 -0
- package/crates/team-agent/src/cli/leader.rs +14 -2
- package/crates/team-agent/src/cli/leaders.rs +2 -0
- package/crates/team-agent/src/cli/mod.rs +296 -8
- package/crates/team-agent/src/cli/named_address.rs +26 -2
- package/crates/team-agent/src/cli/profile.rs +2 -1
- package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
- package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
- package/crates/team-agent/src/cli/send/persist.rs +1 -0
- package/crates/team-agent/src/cli/send/presentation.rs +3 -0
- package/crates/team-agent/src/cli/send/resolve.rs +206 -1
- package/crates/team-agent/src/cli/send.rs +2 -1
- package/crates/team-agent/src/cli/spec.rs +5 -1
- package/crates/team-agent/src/cli/status.rs +2 -1
- package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
- package/crates/team-agent/src/cli/status_port/format.rs +1 -0
- package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
- package/crates/team-agent/src/cli/status_port/store.rs +7 -3
- package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
- package/crates/team-agent/src/cli/types.rs +36 -2
- package/crates/team-agent/src/communication_mode/mod.rs +54 -0
- package/crates/team-agent/src/compiler/tests.rs +5 -5
- package/crates/team-agent/src/compiler.rs +54 -1
- package/crates/team-agent/src/conpty/backend.rs +1 -0
- package/crates/team-agent/src/conpty/mod.rs +1 -0
- package/crates/team-agent/src/coordinator/backoff.rs +5 -8
- package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
- package/crates/team-agent/src/coordinator/health.rs +1 -0
- package/crates/team-agent/src/coordinator/mod.rs +2 -2
- package/crates/team-agent/src/coordinator/orphan.rs +4 -116
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +6 -5
- package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
- package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +0 -9
- package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
- package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -42
- package/crates/team-agent/src/coordinator/tick.rs +24 -28
- package/crates/team-agent/src/coordinator/types.rs +3 -176
- package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
- package/crates/team-agent/src/db/message_store.rs +47 -2
- package/crates/team-agent/src/db/migration.rs +5 -4
- package/crates/team-agent/src/db/mod.rs +1 -0
- package/crates/team-agent/src/db/schema.rs +1 -0
- package/crates/team-agent/src/diagnose/comms.rs +2 -1
- package/crates/team-agent/src/diagnose/mod.rs +1 -0
- package/crates/team-agent/src/diagnose/orphans.rs +1 -0
- package/crates/team-agent/src/fake_worker.rs +21 -1
- package/crates/team-agent/src/layout/manager.rs +3 -7
- package/crates/team-agent/src/layout/mod.rs +2 -2
- package/crates/team-agent/src/layout/overlay.rs +6 -1
- package/crates/team-agent/src/layout/placement.rs +1 -0
- package/crates/team-agent/src/layout/recovery.rs +3 -0
- package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
- package/crates/team-agent/src/layout/sessions.rs +8 -1
- package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
- package/crates/team-agent/src/layout/worker_env.rs +3 -0
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/helpers.rs +1 -0
- package/crates/team-agent/src/leader/incident.rs +1 -0
- package/crates/team-agent/src/leader/lease.rs +27 -22
- package/crates/team-agent/src/leader/mod.rs +2 -3
- package/crates/team-agent/src/leader/owner_bind.rs +13 -3
- package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
- package/crates/team-agent/src/leader/rediscover.rs +4 -17
- package/crates/team-agent/src/leader/registry.rs +3 -15
- package/crates/team-agent/src/leader/start.rs +1072 -186
- package/crates/team-agent/src/leader/takeover.rs +10 -232
- package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
- package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
- package/crates/team-agent/src/leader/tests/identity.rs +71 -59
- package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
- package/crates/team-agent/src/leader/tests/idle.rs +0 -193
- package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
- package/crates/team-agent/src/leader/tests/mod.rs +4 -41
- package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
- package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
- package/crates/team-agent/src/leader/types.rs +1 -28
- package/crates/team-agent/src/lib.rs +7 -0
- package/crates/team-agent/src/lifecycle/display.rs +7 -1
- package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -28
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch.rs +11 -12
- package/crates/team-agent/src/lifecycle/mod.rs +2 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -4
- package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
- package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
- package/crates/team-agent/src/lifecycle/restart.rs +13 -11
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
- package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
- package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
- package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
- package/crates/team-agent/src/lifecycle/tests.rs +59 -0
- package/crates/team-agent/src/lifecycle/types.rs +0 -9
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
- package/crates/team-agent/src/mcp_server/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/normalize.rs +5 -3
- package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
- package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
- package/crates/team-agent/src/mcp_server/tools.rs +101 -66
- package/crates/team-agent/src/mcp_server/types.rs +6 -18
- package/crates/team-agent/src/mcp_server/wire.rs +32 -26
- package/crates/team-agent/src/messaging/activity.rs +1 -0
- package/crates/team-agent/src/messaging/address.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +109 -41
- package/crates/team-agent/src/messaging/helpers.rs +2 -1
- package/crates/team-agent/src/messaging/leader_channel.rs +34 -10
- package/crates/team-agent/src/messaging/leader_receiver.rs +42 -24
- package/crates/team-agent/src/messaging/mod.rs +10 -14
- package/crates/team-agent/src/messaging/peers.rs +2 -0
- package/crates/team-agent/src/messaging/persist.rs +3 -1
- package/crates/team-agent/src/messaging/presentation.rs +111 -1
- package/crates/team-agent/src/messaging/results.rs +166 -17
- package/crates/team-agent/src/messaging/scheduler.rs +1 -0
- package/crates/team-agent/src/messaging/selftest.rs +1 -1
- package/crates/team-agent/src/messaging/send.rs +135 -89
- package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
- package/crates/team-agent/src/messaging/types.rs +7 -2
- package/crates/team-agent/src/messaging/watchers.rs +24 -13
- package/crates/team-agent/src/model/enums.rs +1 -0
- package/crates/team-agent/src/model/errors.rs +1 -0
- package/crates/team-agent/src/model/ids.rs +1 -0
- package/crates/team-agent/src/model/mod.rs +2 -0
- package/crates/team-agent/src/model/name_similarity.rs +1 -0
- package/crates/team-agent/src/model/pane_authority_refusal.rs +359 -0
- package/crates/team-agent/src/model/paths.rs +1 -0
- package/crates/team-agent/src/model/permissions.rs +3 -2
- package/crates/team-agent/src/model/routing.rs +1 -0
- package/crates/team-agent/src/model/spec.rs +17 -0
- package/crates/team-agent/src/model/task_graph.rs +1 -0
- package/crates/team-agent/src/model/yaml/tests.rs +1 -0
- package/crates/team-agent/src/model/yaml.rs +1 -0
- package/crates/team-agent/src/packaging/install.rs +9 -147
- package/crates/team-agent/src/packaging/migrate.rs +2 -0
- package/crates/team-agent/src/packaging/mod.rs +1 -0
- package/crates/team-agent/src/packaging/repair.rs +2 -0
- package/crates/team-agent/src/packaging/tests.rs +29 -218
- package/crates/team-agent/src/packaging/types.rs +8 -15
- package/crates/team-agent/src/platform/argv.rs +4 -0
- package/crates/team-agent/src/platform/errors.rs +10 -1
- package/crates/team-agent/src/platform/file_lock.rs +4 -157
- package/crates/team-agent/src/platform/mod.rs +0 -61
- package/crates/team-agent/src/platform/process.rs +1 -0
- package/crates/team-agent/src/provider/adapter.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
- package/crates/team-agent/src/provider/classify.rs +1 -0
- package/crates/team-agent/src/provider/faults.rs +1 -26
- package/crates/team-agent/src/provider/helpers.rs +1 -0
- package/crates/team-agent/src/provider/mod.rs +1 -1
- package/crates/team-agent/src/provider/session/capture.rs +41 -22
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
- package/crates/team-agent/src/provider/session/mod.rs +2 -4
- package/crates/team-agent/src/provider/session/resume.rs +2 -209
- package/crates/team-agent/src/provider/session_scan/claude.rs +93 -3
- package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
- package/crates/team-agent/src/provider/session_scan/common.rs +24 -7
- package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
- package/crates/team-agent/src/provider/session_scan.rs +6 -42
- package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
- package/crates/team-agent/src/provider/types.rs +1 -0
- package/crates/team-agent/src/provider/wire.rs +1 -0
- package/crates/team-agent/src/state/identity.rs +16 -5
- package/crates/team-agent/src/state/identity_keys.rs +1 -0
- package/crates/team-agent/src/state/mod.rs +2 -0
- package/crates/team-agent/src/state/owner_gate.rs +5 -0
- package/crates/team-agent/src/state/ownership.rs +10 -4
- package/crates/team-agent/src/state/paths.rs +12 -0
- package/crates/team-agent/src/state/persist.rs +9 -3
- package/crates/team-agent/src/state/projection.rs +15 -2
- package/crates/team-agent/src/state/repository/intent.rs +1 -0
- package/crates/team-agent/src/state/repository/tests.rs +1 -0
- package/crates/team-agent/src/state/repository.rs +7 -0
- package/crates/team-agent/src/state/selector.rs +1 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
- package/crates/team-agent/src/tmux_backend.rs +63 -0
- package/crates/team-agent/src/topology.rs +3 -0
- package/crates/team-agent/src/transport.rs +15 -0
- package/package.json +4 -4
- package/skills/team-agent/command-coverage.json +379 -0
- package/crates/team-agent/src/leader/inject.rs +0 -33
- package/crates/team-agent/src/provider/command.rs +0 -80
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! cli · adapters — 每子命令的薄壳 `cmd_*`(commands.py)。委派 status/lifecycle/diagnose/
|
|
2
3
|
//! leader/messaging port,把委派结果包成 [`CmdResult`]。含逻辑的:`cmd_status`(三态互斥)、
|
|
3
4
|
//! `cmd_doctor`(gate/comms/fix-schema/cleanup-orphans 分派)。
|
|
@@ -221,7 +222,8 @@ fn warn_ignored_owner_team_id(team_dir: &std::path::Path) {
|
|
|
221
222
|
|
|
222
223
|
/// `cmd_status`(`commands.py:90`)。三态:`--summary`(xor json,xor agent)→五行文本;
|
|
223
224
|
/// `--json`→`status_port::status(compact=!detail)`;else→`status_port::format_status(agent)`。
|
|
224
|
-
|
|
225
|
+
#[cfg(test)]
|
|
226
|
+
pub(crate) fn cmd_status(args: &StatusArgs) -> Result<CmdResult, CliError> {
|
|
225
227
|
cmd_status_for_team(args, args.team.as_deref())
|
|
226
228
|
}
|
|
227
229
|
|
|
@@ -408,7 +410,8 @@ pub fn cmd_sessions(args: &SessionsArgs) -> Result<CmdResult, CliError> {
|
|
|
408
410
|
}
|
|
409
411
|
|
|
410
412
|
/// `cmd_collect`(`parser.py:292`)。
|
|
411
|
-
|
|
413
|
+
#[cfg(test)]
|
|
414
|
+
pub(crate) fn cmd_collect(args: &CollectArgs) -> Result<CmdResult, CliError> {
|
|
412
415
|
cmd_collect_for_team(args, args.team.as_deref())
|
|
413
416
|
}
|
|
414
417
|
|
|
@@ -483,6 +486,43 @@ pub fn cmd_collect_for_team(args: &CollectArgs, team: Option<&str>) -> Result<Cm
|
|
|
483
486
|
))
|
|
484
487
|
}
|
|
485
488
|
|
|
489
|
+
pub fn cmd_results(args: &ResultsArgs) -> Result<CmdResult, CliError> {
|
|
490
|
+
let selected = match crate::state::selector::resolve_active_team(
|
|
491
|
+
&args.workspace,
|
|
492
|
+
args.team.as_deref(),
|
|
493
|
+
crate::state::selector::SelectorMode::RuntimeOnly,
|
|
494
|
+
) {
|
|
495
|
+
Ok(selected) => selected,
|
|
496
|
+
Err(error) => {
|
|
497
|
+
return Ok(CmdResult::from_json(
|
|
498
|
+
json!({
|
|
499
|
+
"ok": false,
|
|
500
|
+
"error": error.to_string(),
|
|
501
|
+
"workspace": args.workspace.to_string_lossy().to_string(),
|
|
502
|
+
}),
|
|
503
|
+
args.json,
|
|
504
|
+
));
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
let results = messaging::results::results_for_case(
|
|
508
|
+
&selected.run_workspace,
|
|
509
|
+
&args.case_id,
|
|
510
|
+
Some(selected.team_key.as_str()),
|
|
511
|
+
args.team.as_deref(),
|
|
512
|
+
)?;
|
|
513
|
+
let value = json!({
|
|
514
|
+
"ok": true,
|
|
515
|
+
"case_id": args.case_id,
|
|
516
|
+
"results": results,
|
|
517
|
+
"workspace": selected.run_workspace.to_string_lossy().to_string(),
|
|
518
|
+
});
|
|
519
|
+
Ok(if args.json {
|
|
520
|
+
CmdResult::from_ordered_json(value)
|
|
521
|
+
} else {
|
|
522
|
+
CmdResult::from_json(value, false)
|
|
523
|
+
})
|
|
524
|
+
}
|
|
525
|
+
|
|
486
526
|
/// `cmd_allow_peer_talk`(`parser.py allow-peer-talk`).
|
|
487
527
|
pub fn cmd_allow_peer_talk(args: &AllowPeerTalkArgs) -> Result<CmdResult, CliError> {
|
|
488
528
|
if args.team.is_some() {
|
|
@@ -1485,7 +1525,13 @@ pub fn cmd_doctor(args: &DoctorArgs) -> Result<CmdResult, CliError> {
|
|
|
1485
1525
|
} else if args.fix_schema {
|
|
1486
1526
|
diagnose_port::fix_schema(&args.workspace)?
|
|
1487
1527
|
} else {
|
|
1488
|
-
diagnose_port::doctor(&args.workspace, args.spec.as_deref())
|
|
1528
|
+
let mut value = diagnose_port::doctor(&args.workspace, args.spec.as_deref())?;
|
|
1529
|
+
crate::cli::diagnose::append_selected_live_leader_workspace_mismatch(
|
|
1530
|
+
&args.workspace,
|
|
1531
|
+
args.team.as_deref(),
|
|
1532
|
+
&mut value,
|
|
1533
|
+
);
|
|
1534
|
+
value
|
|
1489
1535
|
};
|
|
1490
1536
|
Ok(CmdResult::from_json(value, args.json))
|
|
1491
1537
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! diagnose/preflight/wait-ready CLI helpers.
|
|
2
3
|
use super::*;
|
|
4
|
+
use crate::model::pane_authority_refusal::{
|
|
5
|
+
PaneAuthorityRecoveryAction, PaneAuthorityRecoveryHint, PaneAuthorityRefusal,
|
|
6
|
+
PaneAuthorityRefusalFacts, PaneAuthorityRefusalField, ACTION_FIELD, ACTION_REQUIRED_FIELD,
|
|
7
|
+
HINT_ACTION_FIELD, REASON_FIELD,
|
|
8
|
+
};
|
|
3
9
|
use crate::provider::wire::{command_name, parse_provider, provider_wire};
|
|
4
10
|
use crate::transport::Transport;
|
|
5
11
|
|
|
@@ -195,12 +201,190 @@ pub(crate) fn diagnose_runtime_for_workspace(
|
|
|
195
201
|
backend: &dyn Transport,
|
|
196
202
|
) -> (Value, Value) {
|
|
197
203
|
let (mut issues, mut repairs) = diagnose_runtime(state, backend);
|
|
204
|
+
append_live_leader_workspace_mismatch_issue(
|
|
205
|
+
workspace,
|
|
206
|
+
state,
|
|
207
|
+
backend,
|
|
208
|
+
&mut issues,
|
|
209
|
+
&mut repairs,
|
|
210
|
+
);
|
|
198
211
|
append_legacy_snapshot_issue(workspace, state, &mut issues);
|
|
199
212
|
append_coordinator_health_issue(workspace, state, &mut issues, &mut repairs);
|
|
200
213
|
append_runtime_bindings_stale_after_boot_issue(workspace, state, &mut issues, &mut repairs);
|
|
201
214
|
(issues, repairs)
|
|
202
215
|
}
|
|
203
216
|
|
|
217
|
+
fn append_live_leader_workspace_mismatch_issue(
|
|
218
|
+
workspace: &std::path::Path,
|
|
219
|
+
state: &Value,
|
|
220
|
+
backend: &dyn Transport,
|
|
221
|
+
issues: &mut Value,
|
|
222
|
+
repairs: &mut Value,
|
|
223
|
+
) {
|
|
224
|
+
let Some((issue, repair)) = live_leader_workspace_mismatch(workspace, state, backend) else {
|
|
225
|
+
return;
|
|
226
|
+
};
|
|
227
|
+
if let Some(items) = issues.as_array_mut() {
|
|
228
|
+
items.push(issue);
|
|
229
|
+
}
|
|
230
|
+
if let Some(items) = repairs.as_array_mut() {
|
|
231
|
+
items.push(repair);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
fn live_leader_workspace_mismatch(
|
|
236
|
+
workspace: &std::path::Path,
|
|
237
|
+
state: &Value,
|
|
238
|
+
backend: &dyn Transport,
|
|
239
|
+
) -> Option<(Value, Value)> {
|
|
240
|
+
let receiver = state.get("leader_receiver")?;
|
|
241
|
+
let facts = match crate::messaging::resolve_live_leader_channel(workspace, receiver, backend) {
|
|
242
|
+
crate::messaging::LeaderChannelResolution::Unbound(
|
|
243
|
+
crate::messaging::LeaderChannelUnbound::PaneWorkspaceMismatch(facts),
|
|
244
|
+
) => facts,
|
|
245
|
+
_ => return None,
|
|
246
|
+
};
|
|
247
|
+
let team = state
|
|
248
|
+
.get("team_key")
|
|
249
|
+
.and_then(Value::as_str)
|
|
250
|
+
.filter(|team| !team.is_empty())
|
|
251
|
+
.unwrap_or("current");
|
|
252
|
+
let provider = receiver
|
|
253
|
+
.get("provider")
|
|
254
|
+
.and_then(Value::as_str)
|
|
255
|
+
.filter(|provider| !provider.is_empty())
|
|
256
|
+
.unwrap_or("claude");
|
|
257
|
+
let refusal =
|
|
258
|
+
PaneAuthorityRefusal::new(PaneAuthorityRefusalFacts::PaneWorkspaceMismatch(facts));
|
|
259
|
+
let PaneAuthorityRefusalFacts::PaneWorkspaceMismatch(facts) = &refusal.facts else {
|
|
260
|
+
return None;
|
|
261
|
+
};
|
|
262
|
+
let mut fields = serde_json::Map::new();
|
|
263
|
+
fields.insert(
|
|
264
|
+
REASON_FIELD.to_string(),
|
|
265
|
+
Value::String(refusal.reason().as_str().to_string()),
|
|
266
|
+
);
|
|
267
|
+
fields.insert(
|
|
268
|
+
PaneAuthorityRefusalField::RequestedWorkspace
|
|
269
|
+
.as_str()
|
|
270
|
+
.to_string(),
|
|
271
|
+
Value::String(facts.requested_workspace.to_string_lossy().into_owned()),
|
|
272
|
+
);
|
|
273
|
+
fields.insert(
|
|
274
|
+
PaneAuthorityRefusalField::ObservedPaneId
|
|
275
|
+
.as_str()
|
|
276
|
+
.to_string(),
|
|
277
|
+
Value::String(facts.observed_pane_id.clone()),
|
|
278
|
+
);
|
|
279
|
+
fields.insert(
|
|
280
|
+
PaneAuthorityRefusalField::ObservedPaneWorkspace
|
|
281
|
+
.as_str()
|
|
282
|
+
.to_string(),
|
|
283
|
+
Value::String(facts.observed_pane_workspace.to_string_lossy().into_owned()),
|
|
284
|
+
);
|
|
285
|
+
fields.insert(
|
|
286
|
+
PaneAuthorityRefusalField::Endpoint.as_str().to_string(),
|
|
287
|
+
Value::String(facts.endpoint.clone()),
|
|
288
|
+
);
|
|
289
|
+
let mut issue = Value::Object(fields.clone());
|
|
290
|
+
if let Some(object) = issue.as_object_mut() {
|
|
291
|
+
object.insert(
|
|
292
|
+
"id".to_string(),
|
|
293
|
+
Value::String("leader_channel_workspace_mismatch".to_string()),
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
let mut repair = Value::Object(fields);
|
|
297
|
+
if let Some(object) = repair.as_object_mut() {
|
|
298
|
+
object.insert(
|
|
299
|
+
"issue".to_string(),
|
|
300
|
+
Value::String("leader_channel_workspace_mismatch".to_string()),
|
|
301
|
+
);
|
|
302
|
+
object.insert(
|
|
303
|
+
ACTION_REQUIRED_FIELD.to_string(),
|
|
304
|
+
Value::Bool(refusal.recovery.action_required),
|
|
305
|
+
);
|
|
306
|
+
object.insert("advisory".to_string(), Value::Bool(true));
|
|
307
|
+
object.insert(
|
|
308
|
+
"broken_class".to_string(),
|
|
309
|
+
Value::String("leader_channel_workspace_mismatch".to_string()),
|
|
310
|
+
);
|
|
311
|
+
object.insert(
|
|
312
|
+
HINT_ACTION_FIELD.to_string(),
|
|
313
|
+
Value::String(
|
|
314
|
+
match refusal.recovery.hint_action {
|
|
315
|
+
PaneAuthorityRecoveryHint::AttachLeader => "team-agent attach-leader",
|
|
316
|
+
}
|
|
317
|
+
.to_string(),
|
|
318
|
+
),
|
|
319
|
+
);
|
|
320
|
+
object.insert(
|
|
321
|
+
"dedupe_key".to_string(),
|
|
322
|
+
Value::String(format!("{team}:leader_channel_workspace_mismatch")),
|
|
323
|
+
);
|
|
324
|
+
object.insert(
|
|
325
|
+
ACTION_FIELD.to_string(),
|
|
326
|
+
Value::String(match refusal.recovery.action {
|
|
327
|
+
PaneAuthorityRecoveryAction::OpenTerminalOutsideCurrentTmuxPaneOrAttachFromMatchingPane => {
|
|
328
|
+
format!(
|
|
329
|
+
"open a new terminal window outside the current tmux/pane, change \
|
|
330
|
+
directory to the requested workspace, then run \
|
|
331
|
+
`team-agent attach-leader --team {team} --provider {provider} \
|
|
332
|
+
--confirm --json`; then rerun \
|
|
333
|
+
`team-agent diagnose --team {team} --json`"
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
Some((issue, repair))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
pub(crate) fn append_selected_live_leader_workspace_mismatch(
|
|
343
|
+
workspace: &std::path::Path,
|
|
344
|
+
team: Option<&str>,
|
|
345
|
+
report: &mut Value,
|
|
346
|
+
) {
|
|
347
|
+
let Some((issue, repair)) = selected_live_leader_workspace_mismatch(workspace, team) else {
|
|
348
|
+
return;
|
|
349
|
+
};
|
|
350
|
+
let Some(object) = report.as_object_mut() else {
|
|
351
|
+
return;
|
|
352
|
+
};
|
|
353
|
+
object.insert("issues".to_string(), Value::Array(vec![issue]));
|
|
354
|
+
object.insert("suggested_repairs".to_string(), Value::Array(vec![repair]));
|
|
355
|
+
object.insert("ok".to_string(), Value::Bool(false));
|
|
356
|
+
if object.get("error").is_none_or(Value::is_null) {
|
|
357
|
+
object.insert(
|
|
358
|
+
"error".to_string(),
|
|
359
|
+
Value::String("PaneWorkspaceMismatch".to_string()),
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
fn selected_live_leader_workspace_mismatch(
|
|
365
|
+
workspace: &std::path::Path,
|
|
366
|
+
team: Option<&str>,
|
|
367
|
+
) -> Option<(Value, Value)> {
|
|
368
|
+
let selected = crate::state::selector::resolve_active_team(
|
|
369
|
+
workspace,
|
|
370
|
+
team,
|
|
371
|
+
crate::state::selector::SelectorMode::RuntimeOnly,
|
|
372
|
+
)
|
|
373
|
+
.ok()?;
|
|
374
|
+
let backend: Box<dyn crate::transport::Transport> =
|
|
375
|
+
match crate::transport_factory::resolve_read_only_transport(
|
|
376
|
+
&selected.run_workspace,
|
|
377
|
+
Some(&selected.state),
|
|
378
|
+
crate::transport_factory::TransportPurpose::Diagnose,
|
|
379
|
+
) {
|
|
380
|
+
Ok(resolved) => resolved.backend,
|
|
381
|
+
Err(_) => Box::new(crate::tmux_backend::TmuxBackend::for_workspace(
|
|
382
|
+
&selected.run_workspace,
|
|
383
|
+
)),
|
|
384
|
+
};
|
|
385
|
+
live_leader_workspace_mismatch(&selected.run_workspace, &selected.state, backend.as_ref())
|
|
386
|
+
}
|
|
387
|
+
|
|
204
388
|
/// 0.5.41 Slice 1 (fault-invisibility-locate.md §5/§6.2): read the
|
|
205
389
|
/// coordinator heartbeat sidecar for the last-observed host boot
|
|
206
390
|
/// identity and compare it against the current host boot. If they
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! cli · emit — `emit`(--json vs 人读 dict 逐键)+ 顶层 `run` 调度(parser.py `main`)+
|
|
2
3
|
//! 人读标量/集合渲染(`human_value` / `json_dumps_like`)。
|
|
3
4
|
|
|
@@ -5,17 +6,30 @@ use super::spec::{command_spec, CommandKind, CommandTier, ALL_DISPATCH_KINDS, CO
|
|
|
5
6
|
use super::*;
|
|
6
7
|
use std::io::{ErrorKind, Write as _};
|
|
7
8
|
|
|
9
|
+
///
|
|
8
10
|
/// `emit`(`helpers.py:12-23`):`--json`→`json.dumps(indent=2, ensure_ascii=False, sort_keys=True)`;
|
|
9
11
|
/// 否则 dict 逐键 `key: value`(嵌套 dict/list 内联 compact json,`ensure_ascii=False`)、非 dict 直接 print。
|
|
10
12
|
/// 返回应打印到 stdout 的字符串(bin main 负责实际 println)。
|
|
11
13
|
pub fn emit(output: &CmdOutput, as_json: bool) -> Option<String> {
|
|
14
|
+
emit_with_json_order(output, as_json, false)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn emit_with_json_order(
|
|
18
|
+
output: &CmdOutput,
|
|
19
|
+
as_json: bool,
|
|
20
|
+
preserve_json_order: bool,
|
|
21
|
+
) -> Option<String> {
|
|
12
22
|
match output {
|
|
13
23
|
CmdOutput::None => None,
|
|
14
24
|
CmdOutput::Human(text) => Some(crate::redaction::redact_external_text(text)),
|
|
15
25
|
CmdOutput::Json(value) => {
|
|
16
26
|
let value = crate::redaction::redact_external_value(value);
|
|
17
27
|
if as_json {
|
|
18
|
-
return
|
|
28
|
+
return if preserve_json_order {
|
|
29
|
+
serde_json::to_string_pretty(&value).ok()
|
|
30
|
+
} else {
|
|
31
|
+
serde_json::to_string_pretty(&sort_json(&value)).ok()
|
|
32
|
+
};
|
|
19
33
|
}
|
|
20
34
|
if let Value::Object(obj) = value {
|
|
21
35
|
let lines: Vec<String> = obj
|
|
@@ -30,6 +44,7 @@ pub fn emit(output: &CmdOutput, as_json: bool) -> Option<String> {
|
|
|
30
44
|
}
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
///
|
|
33
48
|
/// `main(argv)`(`parser.py:84`):**CLI 唯一进程入口**。codex/claude/copilot passthrough 早返回 →
|
|
34
49
|
/// 解析 argv 到 subcommand → 调对应 handler → 异常落盘 + 信封 + `ExitCode::Error` →
|
|
35
50
|
/// `consume_leader_inbox_summary` → `emit` → `result.ok is False ? Error : Ok`。
|
|
@@ -84,7 +99,7 @@ fn emit_result(r: CmdResult) -> ExitCode {
|
|
|
84
99
|
.map(ToString::to_string),
|
|
85
100
|
_ => None,
|
|
86
101
|
};
|
|
87
|
-
if let Some(text) =
|
|
102
|
+
if let Some(text) = emit_with_json_order(&r.output, r.as_json, r.preserve_json_order) {
|
|
88
103
|
if let Err(error) = write_stdout_line(&text) {
|
|
89
104
|
if let Some(message_id) = persisted_message_id {
|
|
90
105
|
let stderr = std::io::stderr();
|
|
@@ -180,6 +195,7 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
180
195
|
cmd_collect_for_team(&collect_args(args, cwd)?, parse_args(args).team.as_deref())
|
|
181
196
|
.map(emit_result)
|
|
182
197
|
}
|
|
198
|
+
"results" => cmd_results(&results_args(args, cwd)?).map(emit_result),
|
|
183
199
|
"diagnose" => cmd_diagnose(&diagnose_args(args, cwd)).map(emit_result),
|
|
184
200
|
"preflight" => cmd_preflight(&preflight_args(args, cwd)).map(emit_result),
|
|
185
201
|
"wait-ready" => cmd_wait_ready(&wait_ready_args(args, cwd)).map(emit_result),
|
|
@@ -226,6 +242,7 @@ const DISPATCH_COMMANDS: &[&str] = &[
|
|
|
226
242
|
"install-skill",
|
|
227
243
|
"profile",
|
|
228
244
|
"collect",
|
|
245
|
+
"results",
|
|
229
246
|
"diagnose",
|
|
230
247
|
"preflight",
|
|
231
248
|
"wait-ready",
|
|
@@ -271,7 +288,7 @@ fn default_help() -> String {
|
|
|
271
288
|
append_help_section(
|
|
272
289
|
&mut out,
|
|
273
290
|
"Core",
|
|
274
|
-
&["quick-start", "send", "status", "collect"],
|
|
291
|
+
&["quick-start", "send", "status", "collect", "results"],
|
|
275
292
|
);
|
|
276
293
|
append_help_section(
|
|
277
294
|
&mut out,
|
|
@@ -319,6 +336,7 @@ fn compat_hidden_help(command: &str, usage: &str) -> String {
|
|
|
319
336
|
format!("{usage}\n\nstatus: hidden compatibility command\nsunset: {sunset}\naction: {action}")
|
|
320
337
|
}
|
|
321
338
|
|
|
339
|
+
///
|
|
322
340
|
/// Test-only public accessor for `command_help` — allows integration
|
|
323
341
|
/// tests to grep the help copy without depending on internal parser
|
|
324
342
|
/// machinery.
|
|
@@ -326,6 +344,7 @@ pub fn __test_command_help(command: Option<&str>) -> String {
|
|
|
326
344
|
command_help(command)
|
|
327
345
|
}
|
|
328
346
|
|
|
347
|
+
///
|
|
329
348
|
/// Test-only public accessor for `quick_start_args` — allows
|
|
330
349
|
/// integration tests to exercise the parser without going through
|
|
331
350
|
/// stdio + the full `main` entrypoint.
|
|
@@ -346,10 +365,10 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
346
365
|
Some("send") => concat!(
|
|
347
366
|
"usage: team-agent send TO MESSAGE... ",
|
|
348
367
|
"[--workspace WORKSPACE] [--team TEAM] ",
|
|
349
|
-
"[--
|
|
368
|
+
"[--mailbox] ",
|
|
350
369
|
"[--json]\n\n",
|
|
351
370
|
"TO is a logical recipient; send returns after the message is persisted. ",
|
|
352
|
-
"
|
|
371
|
+
"--mailbox stores durably without live injection; omitted sends to the live conversation."
|
|
353
372
|
)
|
|
354
373
|
.to_string(),
|
|
355
374
|
Some("allow-peer-talk") => "usage: team-agent allow-peer-talk A B [--workspace WORKSPACE] [--json]".to_string(),
|
|
@@ -383,6 +402,7 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
383
402
|
Some("install-skill") => "usage: team-agent install-skill (--source DIR | --uninstall) [--target codex|claude|copilot|all] [--dest DIR] [--dry-run] [--json]".to_string(),
|
|
384
403
|
Some("profile") => "usage: team-agent profile COMMAND NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--json]".to_string(),
|
|
385
404
|
Some("collect") => "usage: team-agent collect [--workspace WORKSPACE] [--team TEAM] [--result-file FILE] [--json]".to_string(),
|
|
405
|
+
Some("results") => "usage: team-agent results --case CASE_ID [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
386
406
|
Some("diagnose") => "usage: team-agent diagnose [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
387
407
|
Some("preflight") => "usage: team-agent preflight [TEAMDIR] [--json]".to_string(),
|
|
388
408
|
Some("wait-ready") => "usage: team-agent wait-ready [--workspace WORKSPACE] [--team TEAM] [--timeout SECONDS] [--json]".to_string(),
|
|
@@ -806,6 +826,7 @@ struct ParsedArgs {
|
|
|
806
826
|
socket: Option<String>,
|
|
807
827
|
thread_id: Option<String>,
|
|
808
828
|
message_id: Option<String>,
|
|
829
|
+
mailbox: bool,
|
|
809
830
|
presentation_sink: Option<String>,
|
|
810
831
|
message_class: Option<String>,
|
|
811
832
|
case_id: Option<String>,
|
|
@@ -899,6 +920,7 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
899
920
|
"--socket" => parsed.socket = next_arg(args, &mut i),
|
|
900
921
|
"--thread-id" => parsed.thread_id = next_arg(args, &mut i),
|
|
901
922
|
"--message-id" => parsed.message_id = next_arg(args, &mut i),
|
|
923
|
+
"--mailbox" => parsed.mailbox = true,
|
|
902
924
|
"--presentation-sink" => parsed.presentation_sink = next_arg(args, &mut i),
|
|
903
925
|
"--message-class" => parsed.message_class = next_arg(args, &mut i),
|
|
904
926
|
"--case-id" => parsed.case_id = next_arg(args, &mut i),
|
|
@@ -1077,6 +1099,7 @@ fn send_args(args: &[String], cwd: &Path) -> Result<SendArgs, CliError> {
|
|
|
1077
1099
|
};
|
|
1078
1100
|
let message_start = usize::from(target.is_some());
|
|
1079
1101
|
let workspace = workspace(&parsed, cwd);
|
|
1102
|
+
let sender = trusted_cli_sender(&workspace, parsed.team.as_deref())?;
|
|
1080
1103
|
let presentation_value = if parsed.presentation_sink.is_some()
|
|
1081
1104
|
|| parsed.message_class.is_some()
|
|
1082
1105
|
|| parsed.case_id.is_some()
|
|
@@ -1089,10 +1112,14 @@ fn send_args(args: &[String], cwd: &Path) -> Result<SendArgs, CliError> {
|
|
|
1089
1112
|
} else {
|
|
1090
1113
|
None
|
|
1091
1114
|
};
|
|
1092
|
-
let (
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1115
|
+
let mailbox_value = parsed.mailbox.then(|| serde_json::json!(true));
|
|
1116
|
+
let normalized = crate::messaging::presentation::normalize_send_presentation(
|
|
1117
|
+
mailbox_value.as_ref(),
|
|
1118
|
+
presentation_value.as_ref(),
|
|
1119
|
+
)
|
|
1120
|
+
.map_err(|error| CliError::Usage(format!("invalid send routing: {error}")))?;
|
|
1121
|
+
if let Some(deprecation) = normalized.deprecation {
|
|
1122
|
+
eprintln!("warning: {deprecation}");
|
|
1096
1123
|
}
|
|
1097
1124
|
Ok(SendArgs {
|
|
1098
1125
|
target,
|
|
@@ -1106,7 +1133,7 @@ fn send_args(args: &[String], cwd: &Path) -> Result<SendArgs, CliError> {
|
|
|
1106
1133
|
workspace,
|
|
1107
1134
|
team: parsed.team,
|
|
1108
1135
|
task: None,
|
|
1109
|
-
sender
|
|
1136
|
+
sender,
|
|
1110
1137
|
no_ack: false,
|
|
1111
1138
|
no_wait: true,
|
|
1112
1139
|
watch_result: false,
|
|
@@ -1114,21 +1141,49 @@ fn send_args(args: &[String], cwd: &Path) -> Result<SendArgs, CliError> {
|
|
|
1114
1141
|
confirm_human: false,
|
|
1115
1142
|
json: parsed.json,
|
|
1116
1143
|
message_id: None,
|
|
1117
|
-
presentation,
|
|
1144
|
+
presentation: normalized.request,
|
|
1118
1145
|
pane: parsed.pane.clone(),
|
|
1119
1146
|
to_name: parsed.to_name.clone(),
|
|
1120
1147
|
to_leader: parsed.to_leader.clone(),
|
|
1121
1148
|
})
|
|
1122
1149
|
}
|
|
1123
1150
|
|
|
1124
|
-
fn trusted_cli_sender() -> TrustedSender {
|
|
1125
|
-
std::env::var("TEAM_AGENT_ID")
|
|
1151
|
+
fn trusted_cli_sender(workspace: &Path, team: Option<&str>) -> Result<TrustedSender, CliError> {
|
|
1152
|
+
let agent_id = std::env::var("TEAM_AGENT_ID")
|
|
1126
1153
|
.ok()
|
|
1127
1154
|
.map(|value| value.trim().to_string())
|
|
1128
|
-
.filter(|value| !value.is_empty())
|
|
1129
|
-
|
|
1130
|
-
.
|
|
1131
|
-
.
|
|
1155
|
+
.filter(|value| !value.is_empty());
|
|
1156
|
+
let worker_context = ["TEAM_AGENT_OWNER_TEAM_ID", "TEAM_AGENT_AGENT_ID"]
|
|
1157
|
+
.into_iter()
|
|
1158
|
+
.any(|key| {
|
|
1159
|
+
std::env::var(key)
|
|
1160
|
+
.ok()
|
|
1161
|
+
.is_some_and(|value| !value.trim().is_empty())
|
|
1162
|
+
});
|
|
1163
|
+
let Some(agent_id) = agent_id else {
|
|
1164
|
+
if worker_context {
|
|
1165
|
+
return Err(CliError::Usage(
|
|
1166
|
+
"send requires framework-injected TEAM_AGENT_ID; refusing leader identity fallback"
|
|
1167
|
+
.to_string(),
|
|
1168
|
+
));
|
|
1169
|
+
}
|
|
1170
|
+
return Ok(TrustedSender::leader());
|
|
1171
|
+
};
|
|
1172
|
+
let source_workspace = std::env::var("TEAM_AGENT_WORKSPACE")
|
|
1173
|
+
.ok()
|
|
1174
|
+
.filter(|value| !value.trim().is_empty())
|
|
1175
|
+
.unwrap_or_else(|| workspace.display().to_string());
|
|
1176
|
+
let source_team = std::env::var("TEAM_AGENT_OWNER_TEAM_ID")
|
|
1177
|
+
.ok()
|
|
1178
|
+
.or_else(|| std::env::var("TEAM_AGENT_TEAM_ID").ok())
|
|
1179
|
+
.or_else(|| team.map(ToOwned::to_owned))
|
|
1180
|
+
.filter(|value| !value.trim().is_empty())
|
|
1181
|
+
.unwrap_or_else(|| "unknown".to_string());
|
|
1182
|
+
Ok(TrustedSender::from_runtime_identity_with_source(
|
|
1183
|
+
crate::model::ids::AgentId::new(agent_id),
|
|
1184
|
+
source_workspace,
|
|
1185
|
+
&source_team,
|
|
1186
|
+
))
|
|
1132
1187
|
}
|
|
1133
1188
|
|
|
1134
1189
|
fn warn_send_legacy_delivery_flags(args: &[String]) {
|
|
@@ -1177,6 +1232,7 @@ fn validate_send_flags(args: &[String]) -> Result<(), CliError> {
|
|
|
1177
1232
|
"--timeout",
|
|
1178
1233
|
"--confirm-human",
|
|
1179
1234
|
"--message-id",
|
|
1235
|
+
"--mailbox",
|
|
1180
1236
|
"--presentation-sink",
|
|
1181
1237
|
"--message-class",
|
|
1182
1238
|
"--case-id",
|
|
@@ -1593,6 +1649,27 @@ fn collect_args(args: &[String], cwd: &Path) -> Result<CollectArgs, CliError> {
|
|
|
1593
1649
|
})
|
|
1594
1650
|
}
|
|
1595
1651
|
|
|
1652
|
+
fn results_args(args: &[String], cwd: &Path) -> Result<ResultsArgs, CliError> {
|
|
1653
|
+
if args
|
|
1654
|
+
.iter()
|
|
1655
|
+
.any(|arg| arg == "--to" || arg.starts_with("--to="))
|
|
1656
|
+
{
|
|
1657
|
+
return Err(CliError::Usage(
|
|
1658
|
+
"results does not accept --to; it is a read-only command".to_string(),
|
|
1659
|
+
));
|
|
1660
|
+
}
|
|
1661
|
+
let parsed = parse_args(args);
|
|
1662
|
+
let case_id = option_value(args, "--case")
|
|
1663
|
+
.filter(|value| !value.is_empty())
|
|
1664
|
+
.ok_or_else(|| CliError::Usage("missing --case".to_string()))?;
|
|
1665
|
+
Ok(ResultsArgs {
|
|
1666
|
+
case_id,
|
|
1667
|
+
workspace: workspace(&parsed, cwd),
|
|
1668
|
+
team: parsed.team,
|
|
1669
|
+
json: parsed.json,
|
|
1670
|
+
})
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1596
1673
|
fn option_value(args: &[String], flag: &str) -> Option<String> {
|
|
1597
1674
|
let prefix = format!("{flag}=");
|
|
1598
1675
|
let mut i = 0usize;
|
|
@@ -2093,8 +2170,14 @@ mod tests {
|
|
|
2093
2170
|
}
|
|
2094
2171
|
|
|
2095
2172
|
#[test]
|
|
2096
|
-
fn
|
|
2173
|
+
fn send_mailbox_and_legacy_progress_map_to_the_one_bit_request() {
|
|
2097
2174
|
let cwd = tmp_workspace();
|
|
2175
|
+
let mailbox = send_args(&cli_argv(&["leader", "progress", "--mailbox"]), &cwd).unwrap();
|
|
2176
|
+
assert_eq!(
|
|
2177
|
+
mailbox.presentation.sink,
|
|
2178
|
+
crate::messaging::presentation::PresentationSink::Casefile
|
|
2179
|
+
);
|
|
2180
|
+
|
|
2098
2181
|
let args = send_args(
|
|
2099
2182
|
&cli_argv(&[
|
|
2100
2183
|
"leader",
|
|
@@ -2115,9 +2198,9 @@ mod tests {
|
|
|
2115
2198
|
);
|
|
2116
2199
|
assert_eq!(
|
|
2117
2200
|
args.presentation.class,
|
|
2118
|
-
crate::messaging::presentation::PresentationClass::
|
|
2201
|
+
crate::messaging::presentation::PresentationClass::Message
|
|
2119
2202
|
);
|
|
2120
|
-
assert_eq!(args.presentation.case_id
|
|
2203
|
+
assert_eq!(args.presentation.case_id, None);
|
|
2121
2204
|
}
|
|
2122
2205
|
|
|
2123
2206
|
#[test]
|
|
@@ -2130,7 +2213,7 @@ mod tests {
|
|
|
2130
2213
|
.unwrap_err();
|
|
2131
2214
|
assert!(matches!(
|
|
2132
2215
|
error,
|
|
2133
|
-
CliError::Usage(message) if message == "invalid
|
|
2216
|
+
CliError::Usage(message) if message == "invalid send routing: missing_class"
|
|
2134
2217
|
));
|
|
2135
2218
|
}
|
|
2136
2219
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! cli · leader — `codex`/`claude`/`copilot` passthrough(`cmd_leader_passthrough` + `_provider_args` /
|
|
2
3
|
//! `_leader_launcher_args`)+ leader fallback inbox 摘要(`consume_leader_inbox_summary` 及
|
|
3
4
|
//! `_leader_inbox_entries` / `_leader_inbox_summary` / `_leader_inbox_entry_title`)。
|
|
@@ -8,6 +9,7 @@ use super::*;
|
|
|
8
9
|
// `codex`/`claude` passthrough 解析(helpers.py `_provider_args`/`_leader_launcher_args`)
|
|
9
10
|
// =============================================================================
|
|
10
11
|
|
|
12
|
+
///
|
|
11
13
|
/// `_provider_args`(`helpers.py:190-193`):剥掉前导 `--`(REMAINDER 第一个 token)。
|
|
12
14
|
pub fn provider_args(values: &[String]) -> Vec<String> {
|
|
13
15
|
match values.first().map(String::as_str) {
|
|
@@ -16,8 +18,9 @@ pub fn provider_args(values: &[String]) -> Vec<String> {
|
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
///
|
|
19
22
|
/// `_leader_launcher_args`(`helpers.py:196-226`):解析 attach 旗标;`--attach-session` 缺值 → Err。
|
|
20
|
-
pub fn leader_launcher_args(values: &[String]) -> Result<LeaderLauncherArgs, CliError> {
|
|
23
|
+
pub(super) fn leader_launcher_args(values: &[String]) -> Result<LeaderLauncherArgs, CliError> {
|
|
21
24
|
let mut out = LeaderLauncherArgs::default();
|
|
22
25
|
let mut idx = 0;
|
|
23
26
|
while idx < values.len() {
|
|
@@ -39,6 +42,8 @@ pub fn leader_launcher_args(values: &[String]) -> Result<LeaderLauncherArgs, Cli
|
|
|
39
42
|
out.confirm_attach = true;
|
|
40
43
|
} else if token == "--external-leader" {
|
|
41
44
|
out.external_leader = true;
|
|
45
|
+
} else if token == "--allow-nested-attach" {
|
|
46
|
+
out.allow_nested_attach = true;
|
|
42
47
|
} else if token == "--attach-session" {
|
|
43
48
|
let Some(value) = values.get(idx + 1) else {
|
|
44
49
|
return Err(CliError::Runtime(
|
|
@@ -60,7 +65,12 @@ pub fn leader_launcher_args(values: &[String]) -> Result<LeaderLauncherArgs, Cli
|
|
|
60
65
|
fn is_leader_launcher_flag(value: &str) -> bool {
|
|
61
66
|
matches!(
|
|
62
67
|
value,
|
|
63
|
-
"--external-leader"
|
|
68
|
+
"--external-leader"
|
|
69
|
+
| "--allow-nested-attach"
|
|
70
|
+
| "--attach"
|
|
71
|
+
| "--attach-existing"
|
|
72
|
+
| "--confirm"
|
|
73
|
+
| "--attach-session"
|
|
64
74
|
) || value.starts_with("--attach-session=")
|
|
65
75
|
}
|
|
66
76
|
|
|
@@ -85,6 +95,7 @@ fn without_leader_json(values: &[String]) -> Vec<String> {
|
|
|
85
95
|
out
|
|
86
96
|
}
|
|
87
97
|
|
|
98
|
+
///
|
|
88
99
|
/// `codex`/`claude`/`copilot` passthrough(`parser.py:86`/`_run_leader_passthrough`):leader 早返回,
|
|
89
100
|
/// **不**进 subparser。`-h`/`--help` 打 usage 直接返回 [`CmdResult::none`]。否则解析 attach
|
|
90
101
|
/// 旗标 + `lifecycle_port::start_leader`。`command` ∈ {codex, claude, copilot}。
|
|
@@ -113,6 +124,7 @@ pub(crate) fn leader_passthrough_provider(command: &str) -> crate::model::enums:
|
|
|
113
124
|
// leader fallback inbox 摘要(helpers.py `consume_leader_inbox_summary`)
|
|
114
125
|
// =============================================================================
|
|
115
126
|
|
|
127
|
+
///
|
|
116
128
|
/// `consume_leader_inbox_summary`(`helpers.py:26-55`):每条命令后读
|
|
117
129
|
/// `.team/runtime/leader-inbox.log`,从游标 `.cursor` 起读新增字节,渲染 N 条 fallback 条目摘要
|
|
118
130
|
/// (`_leader_inbox_summary`,字节预算 budget=500 截断 + `Hint: team-agent inbox leader`),
|