@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 14a · mcp_server::wire — stdio loop + JSON-RPC route + tool dispatch + contracts.
|
|
2
3
|
|
|
3
4
|
use std::io::{BufRead, Write};
|
|
@@ -9,7 +10,6 @@ use crate::event_log::EventLog;
|
|
|
9
10
|
use crate::messaging::MessageTarget;
|
|
10
11
|
|
|
11
12
|
use super::helpers::{json_dumps_default, object_fields};
|
|
12
|
-
use super::normalize::normalize_result_status;
|
|
13
13
|
use super::tools::TeamOrchestratorTools;
|
|
14
14
|
use super::types::{
|
|
15
15
|
McpError, McpTool, RpcError, RpcId, RpcMethod, RpcResponse, Scope, SendOutcome,
|
|
@@ -87,16 +87,15 @@ pub fn dispatch(tools: &TeamOrchestratorTools, request: &Value) -> ToolResult {
|
|
|
87
87
|
/// `handle_mcp(tools, request)` (`server.py:46-91`): the JSON-RPC router.
|
|
88
88
|
/// - `initialize` → serverInfo `team_orchestrator` v0.1.4 + echoed protocolVersion.
|
|
89
89
|
/// - `tools/list` → `{tools: TOOLS}`.
|
|
90
|
-
/// - `tools/call` → run [`dispatch`], wrap
|
|
91
|
-
/// dispatch returned `Err`); the
|
|
92
|
-
/// 69-72`) classifies a caught
|
|
93
|
-
/// `InternalRuntimeError`.
|
|
90
|
+
/// - `tools/call` → run [`dispatch`], wrap through the live
|
|
91
|
+
/// `tool_call_result_value` path (`isError` = dispatch returned `Err`); the
|
|
92
|
+
/// arg-vs-runtime exception split (`server.py:69-72`) classifies a caught
|
|
93
|
+
/// failure into `InvalidToolArguments` vs `InternalRuntimeError`.
|
|
94
94
|
/// - `notifications/*` → `Ok(None)` (no frame; **must not** emit to stdout).
|
|
95
95
|
/// - unknown method → `-32601` error frame.
|
|
96
96
|
/// Returns `Ok(None)` only for the notifications path; every other branch yields a
|
|
97
97
|
/// frame.
|
|
98
98
|
///
|
|
99
|
-
/// [`ToolCallResult`]: super::ToolCallResult
|
|
100
99
|
pub fn handle_mcp(
|
|
101
100
|
tools: &TeamOrchestratorTools,
|
|
102
101
|
request: &Value,
|
|
@@ -369,7 +368,7 @@ fn python_repr(value: &str) -> String {
|
|
|
369
368
|
fn tool_contract(tool: McpTool) -> Value {
|
|
370
369
|
let (description, required) = match tool {
|
|
371
370
|
McpTool::SendMessage => (
|
|
372
|
-
"Send a message to a teammate, the leader, or '*' for all other team members.
|
|
371
|
+
"Send a message to a teammate, the leader, or '*' for all other team members. mailbox=true stores durably without live injection; the default is live delivery.",
|
|
373
372
|
vec!["to", "content"],
|
|
374
373
|
),
|
|
375
374
|
McpTool::AssignTask => ("Assign or update a task in the team graph and deliver it to its assignee.", vec!["task"]),
|
|
@@ -404,11 +403,7 @@ fn tool_properties(tool: McpTool) -> serde_json::Map<String, Value> {
|
|
|
404
403
|
let mut properties = serde_json::Map::new();
|
|
405
404
|
match tool {
|
|
406
405
|
McpTool::AssignTask => {
|
|
407
|
-
insert_property(
|
|
408
|
-
&mut properties,
|
|
409
|
-
"task",
|
|
410
|
-
object_property("Task object to add or update."),
|
|
411
|
-
);
|
|
406
|
+
insert_property(&mut properties, "task", task_property());
|
|
412
407
|
insert_property(
|
|
413
408
|
&mut properties,
|
|
414
409
|
"message",
|
|
@@ -424,8 +419,10 @@ fn tool_properties(tool: McpTool) -> serde_json::Map<String, Value> {
|
|
|
424
419
|
insert_property(&mut properties, "content", string_property("Message body."));
|
|
425
420
|
insert_property(
|
|
426
421
|
&mut properties,
|
|
427
|
-
"
|
|
428
|
-
|
|
422
|
+
"mailbox",
|
|
423
|
+
boolean_property(
|
|
424
|
+
"Set true to store durably without live injection; omit for default live delivery.",
|
|
425
|
+
),
|
|
429
426
|
);
|
|
430
427
|
}
|
|
431
428
|
McpTool::ReportResult => {
|
|
@@ -603,6 +600,25 @@ fn object_property(description: &str) -> Value {
|
|
|
603
600
|
serde_json::json!({"type": "object", "description": description, "additionalProperties": true})
|
|
604
601
|
}
|
|
605
602
|
|
|
603
|
+
fn task_property() -> Value {
|
|
604
|
+
serde_json::json!({
|
|
605
|
+
"type": "object",
|
|
606
|
+
"description": "Task object to add or update.",
|
|
607
|
+
"properties": {
|
|
608
|
+
"result_route": {
|
|
609
|
+
"type": "string",
|
|
610
|
+
"enum": crate::messaging::results::ResultRoute::ALL
|
|
611
|
+
.iter()
|
|
612
|
+
.map(|route| route.as_str())
|
|
613
|
+
.collect::<Vec<_>>(),
|
|
614
|
+
"default": crate::messaging::results::ResultRoute::default().as_str(),
|
|
615
|
+
"description": "Result destination chosen by the task assigner."
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
"additionalProperties": true
|
|
619
|
+
})
|
|
620
|
+
}
|
|
621
|
+
|
|
606
622
|
fn presentation_property(description: &str) -> Value {
|
|
607
623
|
serde_json::json!({
|
|
608
624
|
"type": "object",
|
|
@@ -646,6 +662,7 @@ pub(crate) fn dispatch_tool(
|
|
|
646
662
|
None,
|
|
647
663
|
None,
|
|
648
664
|
None,
|
|
665
|
+
args.get("mailbox"),
|
|
649
666
|
args.get("presentation"),
|
|
650
667
|
)?;
|
|
651
668
|
match outcome {
|
|
@@ -658,18 +675,7 @@ pub(crate) fn dispatch_tool(
|
|
|
658
675
|
McpTool::ReportResult => tools.report_result_with_presentation(
|
|
659
676
|
args.get("envelope"),
|
|
660
677
|
args.get("summary").and_then(Value::as_str),
|
|
661
|
-
|
|
662
|
-
// Partial and is OBSERVABLE at this ingestion boundary, never silent.
|
|
663
|
-
{
|
|
664
|
-
let (status, unknown) =
|
|
665
|
-
crate::mcp_server::normalize::normalize_result_status_observed(
|
|
666
|
-
args.get("status").and_then(Value::as_str),
|
|
667
|
-
);
|
|
668
|
-
if let Some(raw) = unknown {
|
|
669
|
-
tools.note_unknown_result_status(&raw);
|
|
670
|
-
}
|
|
671
|
-
status
|
|
672
|
-
},
|
|
678
|
+
args.get("status").and_then(Value::as_str),
|
|
673
679
|
args.get("changes")
|
|
674
680
|
.and_then(Value::as_array)
|
|
675
681
|
.map(Vec::as_slice),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! internal_delivery.py + delivery.py — coordinator/调度器侧 thin wrapper + 单条 tmux 注入投递
|
|
2
3
|
//! + trust 有界重试 + turn-open arm (card §16/§65)。
|
|
3
4
|
|
|
@@ -93,7 +94,7 @@ pub fn deliver_persisted_message(
|
|
|
93
94
|
|
|
94
95
|
/// `_tmux_pane_width` (`delivery.py:20`):查询 pane 列宽。**fail-safe** (bug-064/082):失败
|
|
95
96
|
/// 返回 [`PaneWidthQuery::Failed`],**绝不**给默认宽度。借 step 9 transport 的 query。
|
|
96
|
-
pub fn tmux_pane_width(transport: &dyn Transport, target: &Target) -> PaneWidthQuery {
|
|
97
|
+
pub(crate) fn tmux_pane_width(transport: &dyn Transport, target: &Target) -> PaneWidthQuery {
|
|
97
98
|
let queried = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
|
98
99
|
transport.query(target, crate::transport::PaneField::PaneWidth)
|
|
99
100
|
}));
|
|
@@ -220,7 +221,12 @@ pub fn deliver_pending_message(
|
|
|
220
221
|
}
|
|
221
222
|
_ => state,
|
|
222
223
|
};
|
|
223
|
-
if message.recipient == "leader"
|
|
224
|
+
if message.recipient == "leader"
|
|
225
|
+
&& matches!(
|
|
226
|
+
message.status.as_str(),
|
|
227
|
+
"submitted_pending_acceptance" | "injected_awaiting_receipt"
|
|
228
|
+
)
|
|
229
|
+
{
|
|
224
230
|
return observe_pending_leader_acceptance(store, event_log, state, message_id);
|
|
225
231
|
}
|
|
226
232
|
if message.recipient == "leader" && message.status == "queued_until_leader_attach" {
|
|
@@ -341,6 +347,12 @@ pub fn deliver_pending_message(
|
|
|
341
347
|
.get("status")
|
|
342
348
|
.and_then(serde_json::Value::as_str)
|
|
343
349
|
.unwrap_or("unbound");
|
|
350
|
+
let refusal = match &reason {
|
|
351
|
+
crate::messaging::LeaderChannelUnbound::PaneWorkspaceMismatch(_) => {
|
|
352
|
+
DeliveryRefusal::PaneWorkspaceMismatch
|
|
353
|
+
}
|
|
354
|
+
_ => DeliveryRefusal::LeaderNotAttached,
|
|
355
|
+
};
|
|
344
356
|
store.mark(message_id, "failed", Some("leader_not_attached"))?;
|
|
345
357
|
event_log.write(
|
|
346
358
|
"leader_receiver.delivery_blocked",
|
|
@@ -349,7 +361,7 @@ pub fn deliver_pending_message(
|
|
|
349
361
|
"sender": message.sender,
|
|
350
362
|
"reason": "leader_receiver_not_attached",
|
|
351
363
|
"error": "leader_not_attached",
|
|
352
|
-
"channel_reason":
|
|
364
|
+
"channel_reason": reason.reason_code(),
|
|
353
365
|
"channel": "rebind_required",
|
|
354
366
|
"action": "run team-agent attach-leader or team-agent takeover",
|
|
355
367
|
"status": receiver_status,
|
|
@@ -364,7 +376,7 @@ pub fn deliver_pending_message(
|
|
|
364
376
|
"run team-agent attach-leader or team-agent takeover".to_string(),
|
|
365
377
|
),
|
|
366
378
|
stage: None,
|
|
367
|
-
reason: Some(
|
|
379
|
+
reason: Some(refusal),
|
|
368
380
|
channel: Some("rebind_required".to_string()),
|
|
369
381
|
});
|
|
370
382
|
}
|
|
@@ -711,19 +723,30 @@ pub fn deliver_pending_message(
|
|
|
711
723
|
}
|
|
712
724
|
if is_leader_recipient {
|
|
713
725
|
store.record_delivery_submission(message_id, readback_verified)?;
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
"message_id": message_id,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
message_id,
|
|
725
|
-
|
|
726
|
-
|
|
726
|
+
match observe_leader_receipt(state, message_id) {
|
|
727
|
+
LeaderReceiptObservation::SourceUnavailable => {
|
|
728
|
+
store.mark_injected_awaiting_receipt(message_id)?;
|
|
729
|
+
event_log.write(
|
|
730
|
+
"leader_receiver.receipt_source_unavailable",
|
|
731
|
+
serde_json::json!({"message_id": message_id}),
|
|
732
|
+
)?;
|
|
733
|
+
return Ok(leader_receipt_source_unavailable_outcome(message_id));
|
|
734
|
+
}
|
|
735
|
+
LeaderReceiptObservation::TokenAbsent => {
|
|
736
|
+
store.mark(message_id, "submitted_pending_acceptance", None)?;
|
|
737
|
+
event_log.write(
|
|
738
|
+
"leader_receiver.acceptance_pending",
|
|
739
|
+
serde_json::json!({
|
|
740
|
+
"message_id": message_id,
|
|
741
|
+
"reason": "provider_receipt_not_observed",
|
|
742
|
+
}),
|
|
743
|
+
)?;
|
|
744
|
+
return Ok(leader_acceptance_pending_outcome(
|
|
745
|
+
message_id,
|
|
746
|
+
"submitted_pending_acceptance",
|
|
747
|
+
));
|
|
748
|
+
}
|
|
749
|
+
LeaderReceiptObservation::TokenObserved => {}
|
|
727
750
|
}
|
|
728
751
|
store.mark_delivered_with_receipt(message_id)?;
|
|
729
752
|
} else {
|
|
@@ -2041,15 +2064,36 @@ fn leader_rollout_path(state: &serde_json::Value) -> Option<std::path::PathBuf>
|
|
|
2041
2064
|
.map(std::path::PathBuf::from)
|
|
2042
2065
|
}
|
|
2043
2066
|
|
|
2044
|
-
|
|
2067
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
2068
|
+
pub(crate) enum LeaderReceiptObservation {
|
|
2069
|
+
SourceUnavailable,
|
|
2070
|
+
TokenAbsent,
|
|
2071
|
+
TokenObserved,
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
pub(crate) fn observe_leader_receipt(
|
|
2075
|
+
state: &serde_json::Value,
|
|
2076
|
+
message_id: &str,
|
|
2077
|
+
) -> LeaderReceiptObservation {
|
|
2045
2078
|
let Some(path) = leader_rollout_path(state) else {
|
|
2046
|
-
return
|
|
2079
|
+
return LeaderReceiptObservation::SourceUnavailable;
|
|
2047
2080
|
};
|
|
2048
|
-
|
|
2081
|
+
let Ok(observed) = rollout_tail_contains_result(
|
|
2049
2082
|
&path,
|
|
2050
2083
|
&format!("[team-agent-token:{message_id}]"),
|
|
2051
2084
|
64 * 1024,
|
|
2052
|
-
)
|
|
2085
|
+
) else {
|
|
2086
|
+
return LeaderReceiptObservation::SourceUnavailable;
|
|
2087
|
+
};
|
|
2088
|
+
if observed {
|
|
2089
|
+
LeaderReceiptObservation::TokenObserved
|
|
2090
|
+
} else {
|
|
2091
|
+
LeaderReceiptObservation::TokenAbsent
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
pub(crate) fn leader_transcript_has_token(state: &serde_json::Value, message_id: &str) -> bool {
|
|
2096
|
+
observe_leader_receipt(state, message_id) == LeaderReceiptObservation::TokenObserved
|
|
2053
2097
|
}
|
|
2054
2098
|
|
|
2055
2099
|
fn leader_acceptance_pending_outcome(message_id: &str, status: &str) -> DeliveryOutcome {
|
|
@@ -2065,17 +2109,41 @@ fn leader_acceptance_pending_outcome(message_id: &str, status: &str) -> Delivery
|
|
|
2065
2109
|
}
|
|
2066
2110
|
}
|
|
2067
2111
|
|
|
2112
|
+
pub(crate) fn leader_receipt_source_unavailable_outcome(message_id: &str) -> DeliveryOutcome {
|
|
2113
|
+
DeliveryOutcome {
|
|
2114
|
+
ok: true,
|
|
2115
|
+
status: DeliveryStatus::Blocked,
|
|
2116
|
+
message_status: MessageStatusShadow("injected_awaiting_receipt".to_string()),
|
|
2117
|
+
message_id: Some(message_id.to_string()),
|
|
2118
|
+
verification: Some("leader_receipt_source_unavailable".to_string()),
|
|
2119
|
+
stage: Some(DeliveryStage::Submit),
|
|
2120
|
+
reason: None,
|
|
2121
|
+
channel: Some("leader_receipt_source_unavailable".to_string()),
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2068
2125
|
fn observe_pending_leader_acceptance(
|
|
2069
2126
|
store: &MessageStore,
|
|
2070
2127
|
event_log: &EventLog,
|
|
2071
2128
|
state: &serde_json::Value,
|
|
2072
2129
|
message_id: &str,
|
|
2073
2130
|
) -> Result<DeliveryOutcome, MessagingError> {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
message_id
|
|
2077
|
-
|
|
2078
|
-
|
|
2131
|
+
match observe_leader_receipt(state, message_id) {
|
|
2132
|
+
LeaderReceiptObservation::SourceUnavailable => {
|
|
2133
|
+
store.mark_injected_awaiting_receipt(message_id)?;
|
|
2134
|
+
event_log.write(
|
|
2135
|
+
"leader_receiver.receipt_source_unavailable",
|
|
2136
|
+
serde_json::json!({"message_id": message_id}),
|
|
2137
|
+
)?;
|
|
2138
|
+
return Ok(leader_receipt_source_unavailable_outcome(message_id));
|
|
2139
|
+
}
|
|
2140
|
+
LeaderReceiptObservation::TokenAbsent => {
|
|
2141
|
+
return Ok(leader_acceptance_pending_outcome(
|
|
2142
|
+
message_id,
|
|
2143
|
+
"submitted_pending_acceptance",
|
|
2144
|
+
));
|
|
2145
|
+
}
|
|
2146
|
+
LeaderReceiptObservation::TokenObserved => {}
|
|
2079
2147
|
}
|
|
2080
2148
|
store.mark_delivered_with_receipt(message_id)?;
|
|
2081
2149
|
event_log.write(
|
|
@@ -2187,7 +2255,7 @@ pub fn execute_trust_retry(
|
|
|
2187
2255
|
|
|
2188
2256
|
/// `_record_turn_open_if_leader_to_worker` (`delivery.py:430`):**take-over arm 来自真实投递**
|
|
2189
2257
|
/// (card §121) —— 仅 leader→worker 注入/投递成功后才 arm,绝不凭空 arm。
|
|
2190
|
-
pub fn record_turn_open_if_leader_to_worker(
|
|
2258
|
+
pub(crate) fn record_turn_open_if_leader_to_worker(
|
|
2191
2259
|
workspace: &Path,
|
|
2192
2260
|
state: &serde_json::Value,
|
|
2193
2261
|
sender: &str,
|
|
@@ -2346,7 +2414,7 @@ fn arm_turn_open(state: &mut serde_json::Value, recipient: &str, message_id: &Op
|
|
|
2346
2414
|
|
|
2347
2415
|
/// `_stamp_first_send_at_if_leader_to_worker` (`delivery.py:380`):首次 leader→worker 投递戳
|
|
2348
2416
|
/// `first_send_at` (step 13 restart Route B atomicity 决策读它)。
|
|
2349
|
-
pub fn stamp_first_send_at_if_leader_to_worker(
|
|
2417
|
+
pub(crate) fn stamp_first_send_at_if_leader_to_worker(
|
|
2350
2418
|
workspace: &Path,
|
|
2351
2419
|
state: &serde_json::Value,
|
|
2352
2420
|
sender: &str,
|
|
@@ -2744,22 +2812,22 @@ fn claude_recipient_rollout(
|
|
|
2744
2812
|
/// Silent on read errors — callers treat missing/unreadable as "token not
|
|
2745
2813
|
/// present" which forces the unverified path.
|
|
2746
2814
|
fn rollout_tail_contains(path: &std::path::Path, needle: &str, tail_bytes: u64) -> bool {
|
|
2815
|
+
rollout_tail_contains_result(path, needle, tail_bytes).unwrap_or(false)
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
fn rollout_tail_contains_result(
|
|
2819
|
+
path: &std::path::Path,
|
|
2820
|
+
needle: &str,
|
|
2821
|
+
tail_bytes: u64,
|
|
2822
|
+
) -> std::io::Result<bool> {
|
|
2747
2823
|
use std::io::{Read, Seek, SeekFrom};
|
|
2748
|
-
let
|
|
2749
|
-
|
|
2750
|
-
};
|
|
2751
|
-
let Ok(metadata) = file.metadata() else {
|
|
2752
|
-
return false;
|
|
2753
|
-
};
|
|
2824
|
+
let mut file = std::fs::File::open(path)?;
|
|
2825
|
+
let metadata = file.metadata()?;
|
|
2754
2826
|
let len = metadata.len();
|
|
2755
2827
|
let start = len.saturating_sub(tail_bytes);
|
|
2756
|
-
|
|
2757
|
-
return false;
|
|
2758
|
-
}
|
|
2828
|
+
file.seek(SeekFrom::Start(start))?;
|
|
2759
2829
|
let mut buf = Vec::with_capacity(tail_bytes.min(len) as usize);
|
|
2760
|
-
|
|
2761
|
-
return false;
|
|
2762
|
-
}
|
|
2830
|
+
file.take(tail_bytes).read_to_end(&mut buf)?;
|
|
2763
2831
|
let haystack = String::from_utf8_lossy(&buf);
|
|
2764
|
-
haystack.contains(needle)
|
|
2832
|
+
Ok(haystack.contains(needle))
|
|
2765
2833
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! 私有内部 helpers (status wire / envelope 校验 / scheduled kind 解析 / activity 信号
|
|
2
3
|
//! 解析 / id 生成 / MessageStatusShadow 占位)。跨子模块/测试可见者升 `pub(crate)`。
|
|
3
4
|
|
|
@@ -268,7 +269,7 @@ fn idle_activity() -> AgentActivity {
|
|
|
268
269
|
/// outcome **不被视为 success**(I-3 反向断言要求 `leader_receiver.rs` 源文件不得含
|
|
269
270
|
/// `DeliveryStatus::FallbackLog` 或 `fallback_inbox` 字面量,所以本函数从 `leader_receiver.rs`
|
|
270
271
|
/// 搬到本 helpers 模块,字面量在此被允许)。
|
|
271
|
-
pub fn fail_leader_delivery(
|
|
272
|
+
pub(crate) fn fail_leader_delivery(
|
|
272
273
|
workspace: &std::path::Path,
|
|
273
274
|
payload: &serde_json::Value,
|
|
274
275
|
reason: DeliveryRefusal,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
//!
|
|
1
2
|
use std::path::Path;
|
|
2
3
|
|
|
3
4
|
use serde_json::Value;
|
|
4
5
|
|
|
5
6
|
use crate::codex_app_server::AppServerBinding;
|
|
7
|
+
use crate::model::pane_authority_refusal::PaneWorkspaceMismatchFacts;
|
|
6
8
|
use crate::transport::{PaneInfo, Transport};
|
|
7
9
|
|
|
8
10
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
@@ -26,7 +28,7 @@ pub enum LeaderChannelResolution {
|
|
|
26
28
|
ProbeFailed(String),
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
#[derive(Debug, Clone,
|
|
31
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
30
32
|
pub enum LeaderChannelUnbound {
|
|
31
33
|
ReceiverNotAttached,
|
|
32
34
|
TransportConflict,
|
|
@@ -34,10 +36,25 @@ pub enum LeaderChannelUnbound {
|
|
|
34
36
|
NonCanonicalTmuxSocket,
|
|
35
37
|
EndpointMismatch,
|
|
36
38
|
PaneNotLive,
|
|
37
|
-
PaneWorkspaceMismatch,
|
|
39
|
+
PaneWorkspaceMismatch(PaneWorkspaceMismatchFacts),
|
|
38
40
|
AppServerBindingInvalid,
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
impl LeaderChannelUnbound {
|
|
44
|
+
pub const fn reason_code(&self) -> &'static str {
|
|
45
|
+
match self {
|
|
46
|
+
Self::ReceiverNotAttached => "ReceiverNotAttached",
|
|
47
|
+
Self::TransportConflict => "TransportConflict",
|
|
48
|
+
Self::MissingPaneId => "MissingPaneId",
|
|
49
|
+
Self::NonCanonicalTmuxSocket => "NonCanonicalTmuxSocket",
|
|
50
|
+
Self::EndpointMismatch => "EndpointMismatch",
|
|
51
|
+
Self::PaneNotLive => "PaneNotLive",
|
|
52
|
+
Self::PaneWorkspaceMismatch(_) => "PaneWorkspaceMismatch",
|
|
53
|
+
Self::AppServerBindingInvalid => "AppServerBindingInvalid",
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
/// Resolve the canonical receiver's live physical channel without mutating
|
|
42
59
|
/// ownership. For direct tmux, `(absolute socket, pane id)` plus an available
|
|
43
60
|
/// pane cwd inside the target workspace is the authority. Session/window/tty/
|
|
@@ -79,11 +96,12 @@ pub fn resolve_live_leader_channel(
|
|
|
79
96
|
.get("tmux_socket")
|
|
80
97
|
.and_then(Value::as_str)
|
|
81
98
|
.filter(|socket| !socket.is_empty());
|
|
99
|
+
let transport_endpoint = transport.tmux_endpoint();
|
|
82
100
|
if tmux_socket.is_some_and(|socket| !std::path::Path::new(socket).is_absolute()) {
|
|
83
101
|
return LeaderChannelResolution::Unbound(LeaderChannelUnbound::NonCanonicalTmuxSocket);
|
|
84
102
|
}
|
|
85
103
|
if let Some(expected) = tmux_socket {
|
|
86
|
-
if
|
|
104
|
+
if transport_endpoint.as_deref() != Some(expected) {
|
|
87
105
|
return LeaderChannelResolution::Unbound(LeaderChannelUnbound::EndpointMismatch);
|
|
88
106
|
}
|
|
89
107
|
}
|
|
@@ -97,13 +115,19 @@ pub fn resolve_live_leader_channel(
|
|
|
97
115
|
else {
|
|
98
116
|
return LeaderChannelResolution::Unbound(LeaderChannelUnbound::PaneNotLive);
|
|
99
117
|
};
|
|
100
|
-
if observed
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
if let Some(observed_pane_workspace) = observed.current_path.clone() {
|
|
119
|
+
if !path_is_in_workspace(&observed_pane_workspace, workspace)
|
|
120
|
+
&& !explicit_claim_authority_matches(workspace, receiver, &observed)
|
|
121
|
+
{
|
|
122
|
+
return LeaderChannelResolution::Unbound(LeaderChannelUnbound::PaneWorkspaceMismatch(
|
|
123
|
+
PaneWorkspaceMismatchFacts {
|
|
124
|
+
requested_workspace: canonical_path(workspace),
|
|
125
|
+
observed_pane_id: observed.pane_id.as_str().to_string(),
|
|
126
|
+
observed_pane_workspace,
|
|
127
|
+
endpoint: transport_endpoint.unwrap_or_else(|| "default".to_string()),
|
|
128
|
+
},
|
|
129
|
+
));
|
|
130
|
+
}
|
|
107
131
|
}
|
|
108
132
|
let metadata_drift = receiver_metadata_drift(receiver, &observed);
|
|
109
133
|
LeaderChannelResolution::Live(LiveLeaderChannel::DirectTmux(DirectTmuxLeaderChannel {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! leader.py — leader pane 注入边界 + 恰好一次去重门 (card §21/§72)。
|
|
2
3
|
|
|
3
4
|
use std::path::Path;
|
|
@@ -59,7 +60,7 @@ pub fn send_to_leader_receiver(
|
|
|
59
60
|
/// stable message id for transport-fallback retries. The public function above
|
|
60
61
|
/// keeps the existing call surface unchanged.
|
|
61
62
|
#[allow(clippy::too_many_arguments)]
|
|
62
|
-
pub fn send_to_leader_receiver_with_message_id(
|
|
63
|
+
pub(crate) fn send_to_leader_receiver_with_message_id(
|
|
63
64
|
workspace: &Path,
|
|
64
65
|
state: &serde_json::Value,
|
|
65
66
|
leader_id: &str,
|
|
@@ -397,29 +398,46 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
397
398
|
let readback_ok = super::delivery::pane_readback_verified(&report);
|
|
398
399
|
if submit_ok {
|
|
399
400
|
store.record_delivery_submission(message_id, readback_ok)?;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
401
|
+
match super::delivery::observe_leader_receipt(state, message_id) {
|
|
402
|
+
super::delivery::LeaderReceiptObservation::SourceUnavailable => {
|
|
403
|
+
store.mark_injected_awaiting_receipt(message_id)?;
|
|
404
|
+
event_log.write(
|
|
405
|
+
"leader_receiver.receipt_source_unavailable",
|
|
406
|
+
serde_json::json!({
|
|
407
|
+
"message_id": message_id,
|
|
408
|
+
"result_id": result_id,
|
|
409
|
+
"channel": "fallback_pane",
|
|
410
|
+
}),
|
|
411
|
+
)?;
|
|
412
|
+
return Ok(super::delivery::leader_receipt_source_unavailable_outcome(
|
|
413
|
+
message_id,
|
|
414
|
+
));
|
|
415
|
+
}
|
|
416
|
+
super::delivery::LeaderReceiptObservation::TokenAbsent => {
|
|
417
|
+
store.mark(message_id, "submitted_pending_acceptance", None)?;
|
|
418
|
+
event_log.write(
|
|
419
|
+
"leader_receiver.acceptance_pending",
|
|
420
|
+
serde_json::json!({
|
|
421
|
+
"message_id": message_id,
|
|
422
|
+
"result_id": result_id,
|
|
423
|
+
"reason": "provider_receipt_not_observed",
|
|
424
|
+
"channel": "fallback_pane",
|
|
425
|
+
}),
|
|
426
|
+
)?;
|
|
427
|
+
return Ok(DeliveryOutcome {
|
|
428
|
+
ok: true,
|
|
429
|
+
status: DeliveryStatus::RetryScheduled,
|
|
430
|
+
message_status: MessageStatusShadow(
|
|
431
|
+
"submitted_pending_acceptance".to_string(),
|
|
432
|
+
),
|
|
433
|
+
message_id: Some(message_id.to_string()),
|
|
434
|
+
verification: Some("provider_receipt_not_observed".to_string()),
|
|
435
|
+
stage: Some(DeliveryStage::Submit),
|
|
436
|
+
reason: None,
|
|
437
|
+
channel: Some("leader_acceptance_pending".to_string()),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
super::delivery::LeaderReceiptObservation::TokenObserved => {}
|
|
423
441
|
}
|
|
424
442
|
store.mark_delivered_with_receipt(message_id)?;
|
|
425
443
|
event_log.write(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 11 · messaging — delivery / scheduler / results / collect / report_result /
|
|
2
3
|
//! watchers / leader-receiver / selftest 编排状态机 (ROUND-0 SKELETON).
|
|
3
4
|
//!
|
|
@@ -83,11 +84,8 @@ pub use address::{parse_logical_address, LogicalAddress, LogicalAddressTarget};
|
|
|
83
84
|
pub use delivery::{
|
|
84
85
|
deliver_pending_message, deliver_pending_messages, deliver_persisted_message,
|
|
85
86
|
deliver_stored_message, execute_trust_retry, handle_trust_retry_needed,
|
|
86
|
-
|
|
87
|
-
retry_injection_after_trust_auto_answer, stamp_first_send_at_if_leader_to_worker,
|
|
88
|
-
tmux_pane_width,
|
|
87
|
+
retry_injection_after_trust_auto_answer,
|
|
89
88
|
};
|
|
90
|
-
pub use helpers::fail_leader_delivery;
|
|
91
89
|
pub use leader_channel::{
|
|
92
90
|
resolve_live_leader_channel, DirectTmuxLeaderChannel, LeaderChannelResolution,
|
|
93
91
|
LeaderChannelUnbound, LiveLeaderChannel,
|
|
@@ -95,7 +93,7 @@ pub use leader_channel::{
|
|
|
95
93
|
pub use leader_receiver::{
|
|
96
94
|
deliver_to_leader_fallback_pane, enqueue_leader_mailbox_until_attach,
|
|
97
95
|
mirror_peer_message_to_leader, send_to_leader_receiver,
|
|
98
|
-
|
|
96
|
+
send_to_leader_receiver_with_presentation,
|
|
99
97
|
};
|
|
100
98
|
pub use peers::allow_peer_talk;
|
|
101
99
|
pub use persist::{
|
|
@@ -107,24 +105,22 @@ pub use results::{
|
|
|
107
105
|
report_result_for_owner_team, report_result_for_owner_team_with_primary_error,
|
|
108
106
|
};
|
|
109
107
|
pub use scheduler::{detect_stuck_agents, fire_due_scheduled_events, stuck_cancel, stuck_list};
|
|
110
|
-
pub use selftest::{
|
|
108
|
+
pub use selftest::{run_comms_selftest, CommsSelftestDriver};
|
|
111
109
|
pub use send::{
|
|
112
|
-
apply_worker_sender_bypass, send_message,
|
|
113
|
-
TrustedSender,
|
|
110
|
+
apply_worker_sender_bypass, send_message, MessageTarget, SendOptions, TrustedSender,
|
|
114
111
|
};
|
|
115
112
|
pub use trust::{attempt_trust_auto_answer, TrustAnswerOutcome};
|
|
116
113
|
pub use types::{
|
|
117
|
-
ActivityStatus, AgentActivity,
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
ActivityStatus, AgentActivity, AlertType, CheckEvidence, CheckKind, CheckStatus,
|
|
115
|
+
ContractSuiteCheck, DeliveryOutcome, DeliveryRefusal, DeliveryStage, DeliveryStatus,
|
|
116
|
+
IdleEvaluation, LeaderNotificationKey, LeaderReceiver, PaneWidthQuery,
|
|
120
117
|
ProviderSdkCalls, ReceiverMode, ScheduledKind, SelftestCheck, SelftestReport, SendEventPayload,
|
|
121
118
|
TrustRetryPayload, WatcherNotice, WorkerRuntimeState, RESULT_DELIVERY_MAX_ATTEMPTS,
|
|
122
119
|
SEND_RETRY_MAX_ATTEMPTS, TRUST_RETRY_BACKOFF_SECONDS, TRUST_RETRY_MAX_ATTEMPTS,
|
|
123
120
|
};
|
|
124
121
|
pub use watchers::{
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
retry_result_deliveries,
|
|
122
|
+
format_result_watcher_notification, requeue_after_claim_leader,
|
|
123
|
+
requeue_delivery_exhausted_watchers, result_id_from_text, retry_result_deliveries,
|
|
128
124
|
};
|
|
129
125
|
|
|
130
126
|
// `MessageStatusShadow` 是 [`DeliveryOutcome::message_status`] 的公有字段类型,原在模块根
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! peer messaging compatibility helpers.
|
|
2
3
|
|
|
3
4
|
use std::path::Path;
|
|
@@ -7,6 +8,7 @@ use crate::message_store::MessageStore;
|
|
|
7
8
|
|
|
8
9
|
use super::MessagingError;
|
|
9
10
|
|
|
11
|
+
///
|
|
10
12
|
/// `leader.py:allow_peer_talk`: persist a bidirectional peer allowlist entry.
|
|
11
13
|
pub fn allow_peer_talk(
|
|
12
14
|
workspace: &Path,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! Durable boundary between resolved logical addressing and delivery/recovery.
|
|
2
3
|
|
|
3
4
|
use std::path::{Path, PathBuf};
|
|
@@ -152,6 +153,7 @@ pub enum PersistResolution {
|
|
|
152
153
|
Duplicate(String),
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
///
|
|
155
157
|
/// The only production entry point that creates a durable message row.
|
|
156
158
|
pub fn persist_resolved_send(
|
|
157
159
|
intent: &ResolvedSendIntent,
|
|
@@ -168,7 +170,7 @@ pub fn persist_resolved_send(
|
|
|
168
170
|
message_id: intent.requested_message_id.as_deref(),
|
|
169
171
|
owner_team_id: intent.owner_team_id.as_ref().map(TeamKey::as_str),
|
|
170
172
|
task_id: intent.task_id.as_ref().map(TaskId::as_str),
|
|
171
|
-
sender: intent.sender.
|
|
173
|
+
sender: intent.sender.display_name(),
|
|
172
174
|
recipient: intent.recipient.as_str(),
|
|
173
175
|
reply_to: intent.reply_to.as_deref(),
|
|
174
176
|
requires_ack: intent.requires_ack,
|