@team-agent/installer 0.5.41 → 0.5.43
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 +129 -54
- package/crates/team-agent/src/cli/diagnose.rs +1 -2
- package/crates/team-agent/src/cli/emit.rs +1 -7
- package/crates/team-agent/src/cli/helpers.rs +3 -1
- package/crates/team-agent/src/cli/leader.rs +2 -1
- package/crates/team-agent/src/cli/mod.rs +27 -7
- package/crates/team-agent/src/cli/named_address.rs +14 -5
- package/crates/team-agent/src/cli/profile.rs +19 -7
- package/crates/team-agent/src/cli/send.rs +9 -3
- package/crates/team-agent/src/cli/status.rs +8 -30
- package/crates/team-agent/src/cli/status_port.rs +1341 -1272
- package/crates/team-agent/src/cli/tests/base.rs +738 -660
- package/crates/team-agent/src/cli/tests/compile.rs +45 -18
- package/crates/team-agent/src/cli/tests/divergence.rs +462 -444
- package/crates/team-agent/src/cli/tests/lane_c.rs +365 -282
- package/crates/team-agent/src/cli/tests/leader_watch.rs +356 -329
- package/crates/team-agent/src/cli/tests/main_preserved.rs +672 -564
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +284 -224
- package/crates/team-agent/src/cli/tests/mod.rs +17 -7
- package/crates/team-agent/src/cli/tests/named_address.rs +8 -2
- package/crates/team-agent/src/cli/tests/peer_allow.rs +10 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +314 -273
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +26 -15
- package/crates/team-agent/src/cli/tests/status_send.rs +707 -629
- package/crates/team-agent/src/cli/tests/verb_install_skill.rs +20 -4
- package/crates/team-agent/src/cli/tests/verb_profile.rs +46 -17
- package/crates/team-agent/src/cli/tests/verb_validate.rs +15 -3
- package/crates/team-agent/src/codex_app_server.rs +2 -5
- package/crates/team-agent/src/compiler/tests.rs +139 -33
- package/crates/team-agent/src/compiler.rs +55 -22
- package/crates/team-agent/src/conpty/backend.rs +23 -33
- package/crates/team-agent/src/coordinator/backoff.rs +2 -7
- package/crates/team-agent/src/coordinator/conpty_shim.rs +55 -67
- package/crates/team-agent/src/coordinator/health.rs +46 -31
- package/crates/team-agent/src/coordinator/mod.rs +3 -3
- package/crates/team-agent/src/coordinator/orphan.rs +22 -10
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +47 -52
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +55 -19
- package/crates/team-agent/src/coordinator/tests/basics.rs +179 -41
- package/crates/team-agent/src/coordinator/tests/daemon.rs +53 -13
- package/crates/team-agent/src/coordinator/tests/health_sync.rs +78 -19
- package/crates/team-agent/src/coordinator/tests/main_preserved.rs +61 -11
- package/crates/team-agent/src/coordinator/tests/mod.rs +33 -39
- package/crates/team-agent/src/coordinator/tests/spine.rs +52 -12
- package/crates/team-agent/src/coordinator/tests/takeover.rs +73 -15
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +50 -15
- package/crates/team-agent/src/coordinator/tests/watch.rs +74 -20
- package/crates/team-agent/src/coordinator/tick.rs +19 -1
- package/crates/team-agent/src/db/message_store.rs +138 -30
- package/crates/team-agent/src/db/migration.rs +249 -61
- package/crates/team-agent/src/db/schema.rs +303 -82
- package/crates/team-agent/src/diagnose/comms.rs +9 -2
- package/crates/team-agent/src/diagnose/mod.rs +1 -3
- package/crates/team-agent/src/diagnose/orphans.rs +79 -61
- package/crates/team-agent/src/event_log.rs +70 -16
- package/crates/team-agent/src/layout/manager.rs +15 -4
- package/crates/team-agent/src/layout/mod.rs +4 -4
- package/crates/team-agent/src/layout/overlay.rs +10 -3
- package/crates/team-agent/src/layout/placement.rs +5 -1
- package/crates/team-agent/src/layout/recovery.rs +4 -2
- package/crates/team-agent/src/layout/runtime_sessions.rs +7 -7
- package/crates/team-agent/src/layout/sessions.rs +17 -9
- package/crates/team-agent/src/layout/tmux_endpoint.rs +1 -1
- package/crates/team-agent/src/layout/worker_env.rs +52 -19
- package/crates/team-agent/src/leader/helpers.rs +7 -1
- package/crates/team-agent/src/leader/lease.rs +195 -82
- package/crates/team-agent/src/leader/owner_bind.rs +55 -22
- package/crates/team-agent/src/leader/rediscover/tests.rs +88 -24
- package/crates/team-agent/src/leader/rediscover.rs +74 -25
- package/crates/team-agent/src/leader/start.rs +75 -54
- package/crates/team-agent/src/leader/takeover.rs +46 -11
- package/crates/team-agent/src/leader/tests/basics.rs +320 -167
- package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
- package/crates/team-agent/src/leader/tests/identity.rs +428 -356
- package/crates/team-agent/src/leader/tests/idle.rs +285 -254
- package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
- package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
- package/crates/team-agent/src/leader/tests/mod.rs +115 -99
- package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
- package/crates/team-agent/src/lib.rs +4 -4
- package/crates/team-agent/src/lifecycle/display.rs +7 -3
- package/crates/team-agent/src/lifecycle/launch.rs +6 -1
- package/crates/team-agent/src/lifecycle/mod.rs +9 -1
- package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
- package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
- package/crates/team-agent/src/lifecycle/tests.rs +2 -2
- package/crates/team-agent/src/main.rs +4 -4
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
- package/crates/team-agent/src/mcp_server/mod.rs +11 -2
- package/crates/team-agent/src/mcp_server/types.rs +14 -3
- package/crates/team-agent/src/mcp_server/wire.rs +230 -68
- package/crates/team-agent/src/messaging/delivery.rs +20 -18
- package/crates/team-agent/src/messaging/helpers.rs +25 -4
- package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
- package/crates/team-agent/src/messaging/mod.rs +2 -3
- package/crates/team-agent/src/messaging/selftest.rs +46 -26
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
- package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
- package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
- package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
- package/crates/team-agent/src/messaging/trust.rs +25 -2
- package/crates/team-agent/src/messaging/watchers.rs +37 -9
- package/crates/team-agent/src/model/enums.rs +65 -16
- package/crates/team-agent/src/model/ids.rs +12 -3
- package/crates/team-agent/src/model/paths.rs +28 -7
- package/crates/team-agent/src/model/permissions.rs +176 -33
- package/crates/team-agent/src/model/routing.rs +66 -20
- package/crates/team-agent/src/model/spec.rs +365 -69
- package/crates/team-agent/src/model/task_graph.rs +36 -9
- package/crates/team-agent/src/model/yaml/tests.rs +24 -6
- package/crates/team-agent/src/model/yaml.rs +7 -6
- package/crates/team-agent/src/packaging/install.rs +23 -9
- package/crates/team-agent/src/packaging/migrate.rs +5 -7
- package/crates/team-agent/src/packaging/mod.rs +9 -1
- package/crates/team-agent/src/packaging/repair.rs +13 -6
- package/crates/team-agent/src/packaging/tests.rs +63 -16
- package/crates/team-agent/src/packaging/types.rs +22 -7
- package/crates/team-agent/src/platform/argv.rs +4 -1
- package/crates/team-agent/src/platform/file_lock.rs +22 -8
- package/crates/team-agent/src/platform/process.rs +21 -22
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
- package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
- package/crates/team-agent/src/provider/classify.rs +127 -42
- package/crates/team-agent/src/provider/faults.rs +17 -5
- package/crates/team-agent/src/provider/helpers.rs +6 -5
- package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
- package/crates/team-agent/src/state/repository.rs +27 -14
- package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
- package/crates/team-agent/src/tmux_backend.rs +80 -44
- package/crates/team-agent/src/topology.rs +27 -20
- package/crates/team-agent/src/transport/test_support.rs +20 -23
- package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
- package/crates/team-agent/src/transport/tests/mod.rs +178 -187
- package/crates/team-agent/src/transport/tests/wire.rs +561 -525
- package/crates/team-agent/src/transport.rs +12 -17
- package/crates/team-agent/src/transport_factory.rs +29 -14
- package/package.json +4 -4
|
@@ -12,8 +12,8 @@ use super::helpers::{json_dumps_default, object_fields};
|
|
|
12
12
|
use super::normalize::normalize_result_status;
|
|
13
13
|
use super::tools::TeamOrchestratorTools;
|
|
14
14
|
use super::types::{
|
|
15
|
-
McpError, McpTool, RpcError, RpcId, RpcMethod, RpcResponse, Scope, SendOutcome,
|
|
16
|
-
ToolError, ToolErrorReason, ToolOk, ToolResult,
|
|
15
|
+
McpError, McpTool, RpcError, RpcId, RpcMethod, RpcResponse, Scope, SendOutcome,
|
|
16
|
+
ServerRunReport, ToolError, ToolErrorReason, ToolOk, ToolResult,
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -38,10 +38,7 @@ pub fn tools_contract() -> Vec<Value> {
|
|
|
38
38
|
McpTool::StuckList,
|
|
39
39
|
McpTool::StuckCancel,
|
|
40
40
|
];
|
|
41
|
-
tools
|
|
42
|
-
.into_iter()
|
|
43
|
-
.map(tool_contract)
|
|
44
|
-
.collect()
|
|
41
|
+
tools.into_iter().map(tool_contract).collect()
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -58,7 +55,11 @@ pub fn dispatch(tools: &TeamOrchestratorTools, request: &Value) -> ToolResult {
|
|
|
58
55
|
let tool_value = request
|
|
59
56
|
.get("tool")
|
|
60
57
|
.filter(|v| !v.as_str().is_some_and(str::is_empty))
|
|
61
|
-
.or_else(||
|
|
58
|
+
.or_else(|| {
|
|
59
|
+
request
|
|
60
|
+
.get("name")
|
|
61
|
+
.filter(|v| !v.as_str().is_some_and(str::is_empty))
|
|
62
|
+
})
|
|
62
63
|
.or_else(|| request.get("method"));
|
|
63
64
|
let name = tool_value.and_then(Value::as_str);
|
|
64
65
|
let args = request
|
|
@@ -95,7 +96,10 @@ pub fn dispatch(tools: &TeamOrchestratorTools, request: &Value) -> ToolResult {
|
|
|
95
96
|
/// frame.
|
|
96
97
|
///
|
|
97
98
|
/// [`ToolCallResult`]: super::ToolCallResult
|
|
98
|
-
pub fn handle_mcp(
|
|
99
|
+
pub fn handle_mcp(
|
|
100
|
+
tools: &TeamOrchestratorTools,
|
|
101
|
+
request: &Value,
|
|
102
|
+
) -> Result<Option<RpcResponse>, McpError> {
|
|
99
103
|
let id = rpc_id_from_request(request);
|
|
100
104
|
let method = request.get("method").and_then(Value::as_str).unwrap_or("");
|
|
101
105
|
match RpcMethod::classify(method) {
|
|
@@ -106,7 +110,10 @@ pub fn handle_mcp(tools: &TeamOrchestratorTools, request: &Value) -> Result<Opti
|
|
|
106
110
|
.and_then(Value::as_str)
|
|
107
111
|
.unwrap_or("2024-11-05");
|
|
108
112
|
let mut result = serde_json::Map::new();
|
|
109
|
-
result.insert(
|
|
113
|
+
result.insert(
|
|
114
|
+
"protocolVersion".to_string(),
|
|
115
|
+
Value::String(protocol.to_string()),
|
|
116
|
+
);
|
|
110
117
|
result.insert("capabilities".to_string(), serde_json::json!({"tools": {}}));
|
|
111
118
|
result.insert(
|
|
112
119
|
"serverInfo".to_string(),
|
|
@@ -130,7 +137,10 @@ pub fn handle_mcp(tools: &TeamOrchestratorTools, request: &Value) -> Result<Opti
|
|
|
130
137
|
let body = match dispatch(tools, params) {
|
|
131
138
|
Ok(ok) => {
|
|
132
139
|
let value = Value::Object(ok.fields);
|
|
133
|
-
tool_call_result_value(
|
|
140
|
+
tool_call_result_value(
|
|
141
|
+
value.get("ok").and_then(Value::as_bool) == Some(false),
|
|
142
|
+
&value,
|
|
143
|
+
)
|
|
134
144
|
}
|
|
135
145
|
Err(err) => tool_call_result_value(true, &err.to_envelope()),
|
|
136
146
|
};
|
|
@@ -247,7 +257,9 @@ fn handle_stdin_line(
|
|
|
247
257
|
|
|
248
258
|
fn rpc_id_from_request(request: &Value) -> RpcId {
|
|
249
259
|
match request.get("id") {
|
|
250
|
-
Some(Value::Number(n)) => n
|
|
260
|
+
Some(Value::Number(n)) => n
|
|
261
|
+
.as_i64()
|
|
262
|
+
.map_or_else(|| RpcId::Number(n.clone()), RpcId::Int),
|
|
251
263
|
Some(Value::String(s)) => RpcId::Str(s.clone()),
|
|
252
264
|
_ => RpcId::Null,
|
|
253
265
|
}
|
|
@@ -385,56 +397,172 @@ fn tool_properties(tool: McpTool) -> serde_json::Map<String, Value> {
|
|
|
385
397
|
let mut properties = serde_json::Map::new();
|
|
386
398
|
match tool {
|
|
387
399
|
McpTool::AssignTask => {
|
|
388
|
-
insert_property(
|
|
389
|
-
|
|
400
|
+
insert_property(
|
|
401
|
+
&mut properties,
|
|
402
|
+
"task",
|
|
403
|
+
object_property("Task object to add or update."),
|
|
404
|
+
);
|
|
405
|
+
insert_property(
|
|
406
|
+
&mut properties,
|
|
407
|
+
"message",
|
|
408
|
+
string_property("Optional message to deliver with the task."),
|
|
409
|
+
);
|
|
390
410
|
}
|
|
391
411
|
McpTool::SendMessage => {
|
|
392
|
-
insert_property(
|
|
412
|
+
insert_property(
|
|
413
|
+
&mut properties,
|
|
414
|
+
"to",
|
|
415
|
+
string_property("Target agent id, 'leader', or '*' for broadcast."),
|
|
416
|
+
);
|
|
393
417
|
insert_property(&mut properties, "content", string_property("Message body."));
|
|
394
|
-
insert_property(
|
|
395
|
-
|
|
396
|
-
|
|
418
|
+
insert_property(
|
|
419
|
+
&mut properties,
|
|
420
|
+
"task_id",
|
|
421
|
+
string_property("Optional task id to associate with the message."),
|
|
422
|
+
);
|
|
423
|
+
insert_property(
|
|
424
|
+
&mut properties,
|
|
425
|
+
"sender",
|
|
426
|
+
string_property("Optional sender override."),
|
|
427
|
+
);
|
|
428
|
+
insert_property(
|
|
429
|
+
&mut properties,
|
|
430
|
+
"requires_ack",
|
|
431
|
+
boolean_property("Whether the recipient should acknowledge delivery."),
|
|
432
|
+
);
|
|
397
433
|
}
|
|
398
434
|
McpTool::ReportResult => {
|
|
399
|
-
insert_property(
|
|
400
|
-
|
|
435
|
+
insert_property(
|
|
436
|
+
&mut properties,
|
|
437
|
+
"envelope",
|
|
438
|
+
object_property("Optional full result envelope."),
|
|
439
|
+
);
|
|
440
|
+
insert_property(
|
|
441
|
+
&mut properties,
|
|
442
|
+
"summary",
|
|
443
|
+
string_property("Short result summary."),
|
|
444
|
+
);
|
|
401
445
|
insert_property(&mut properties, "status", string_property("Result status."));
|
|
402
|
-
insert_property(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
insert_property(
|
|
408
|
-
|
|
446
|
+
insert_property(
|
|
447
|
+
&mut properties,
|
|
448
|
+
"changes",
|
|
449
|
+
array_property("Changed files or artifacts."),
|
|
450
|
+
);
|
|
451
|
+
insert_property(
|
|
452
|
+
&mut properties,
|
|
453
|
+
"tests",
|
|
454
|
+
array_property("Tests or checks performed."),
|
|
455
|
+
);
|
|
456
|
+
insert_property(
|
|
457
|
+
&mut properties,
|
|
458
|
+
"risks",
|
|
459
|
+
array_property("Risks or blockers."),
|
|
460
|
+
);
|
|
461
|
+
insert_property(
|
|
462
|
+
&mut properties,
|
|
463
|
+
"artifacts",
|
|
464
|
+
array_property("Artifact references."),
|
|
465
|
+
);
|
|
466
|
+
insert_property(
|
|
467
|
+
&mut properties,
|
|
468
|
+
"next_actions",
|
|
469
|
+
array_property("Suggested next actions."),
|
|
470
|
+
);
|
|
471
|
+
insert_property(
|
|
472
|
+
&mut properties,
|
|
473
|
+
"task_id",
|
|
474
|
+
string_property("Optional task id override."),
|
|
475
|
+
);
|
|
476
|
+
insert_property(
|
|
477
|
+
&mut properties,
|
|
478
|
+
"agent_id",
|
|
479
|
+
string_property("Optional reporting agent id override."),
|
|
480
|
+
);
|
|
409
481
|
}
|
|
410
482
|
McpTool::UpdateState => {
|
|
411
|
-
insert_property(
|
|
483
|
+
insert_property(
|
|
484
|
+
&mut properties,
|
|
485
|
+
"note",
|
|
486
|
+
string_property("Note to append to team state."),
|
|
487
|
+
);
|
|
412
488
|
}
|
|
413
489
|
McpTool::GetTeamStatus | McpTool::StuckList => {}
|
|
414
490
|
McpTool::StopAgent => {
|
|
415
|
-
insert_property(
|
|
491
|
+
insert_property(
|
|
492
|
+
&mut properties,
|
|
493
|
+
"agent_id",
|
|
494
|
+
string_property("Agent id to stop."),
|
|
495
|
+
);
|
|
416
496
|
}
|
|
417
497
|
McpTool::ResetAgent => {
|
|
418
|
-
insert_property(
|
|
419
|
-
|
|
498
|
+
insert_property(
|
|
499
|
+
&mut properties,
|
|
500
|
+
"agent_id",
|
|
501
|
+
string_property("Agent id to reset."),
|
|
502
|
+
);
|
|
503
|
+
insert_property(
|
|
504
|
+
&mut properties,
|
|
505
|
+
"discard_session",
|
|
506
|
+
boolean_property("Whether to discard the existing provider session."),
|
|
507
|
+
);
|
|
420
508
|
}
|
|
421
509
|
McpTool::AddAgent => {
|
|
422
|
-
insert_property(
|
|
423
|
-
|
|
510
|
+
insert_property(
|
|
511
|
+
&mut properties,
|
|
512
|
+
"new_agent_id",
|
|
513
|
+
string_property("New agent id."),
|
|
514
|
+
);
|
|
515
|
+
insert_property(
|
|
516
|
+
&mut properties,
|
|
517
|
+
"role_file_path",
|
|
518
|
+
string_property("Workspace-relative role file path."),
|
|
519
|
+
);
|
|
424
520
|
}
|
|
425
521
|
McpTool::ForkAgent => {
|
|
426
|
-
insert_property(
|
|
427
|
-
|
|
428
|
-
|
|
522
|
+
insert_property(
|
|
523
|
+
&mut properties,
|
|
524
|
+
"source_agent_id",
|
|
525
|
+
string_property("Agent id to fork from."),
|
|
526
|
+
);
|
|
527
|
+
insert_property(
|
|
528
|
+
&mut properties,
|
|
529
|
+
"as_agent_id",
|
|
530
|
+
string_property("Agent id for the forked worker."),
|
|
531
|
+
);
|
|
532
|
+
insert_property(
|
|
533
|
+
&mut properties,
|
|
534
|
+
"label",
|
|
535
|
+
string_property("Optional display label."),
|
|
536
|
+
);
|
|
429
537
|
}
|
|
430
538
|
McpTool::RequestHuman => {
|
|
431
|
-
insert_property(
|
|
432
|
-
|
|
433
|
-
|
|
539
|
+
insert_property(
|
|
540
|
+
&mut properties,
|
|
541
|
+
"question",
|
|
542
|
+
string_property("Question to ask the human."),
|
|
543
|
+
);
|
|
544
|
+
insert_property(
|
|
545
|
+
&mut properties,
|
|
546
|
+
"task_id",
|
|
547
|
+
string_property("Optional related task id."),
|
|
548
|
+
);
|
|
549
|
+
insert_property(
|
|
550
|
+
&mut properties,
|
|
551
|
+
"agent_id",
|
|
552
|
+
string_property("Optional requesting agent id."),
|
|
553
|
+
);
|
|
434
554
|
}
|
|
435
555
|
McpTool::StuckCancel => {
|
|
436
|
-
insert_property(
|
|
437
|
-
|
|
556
|
+
insert_property(
|
|
557
|
+
&mut properties,
|
|
558
|
+
"agent_id",
|
|
559
|
+
string_property("Agent id whose stuck alerts should be suppressed."),
|
|
560
|
+
);
|
|
561
|
+
insert_property(
|
|
562
|
+
&mut properties,
|
|
563
|
+
"alert_type",
|
|
564
|
+
string_property("Alert type to suppress, or all."),
|
|
565
|
+
);
|
|
438
566
|
}
|
|
439
567
|
}
|
|
440
568
|
properties
|
|
@@ -460,12 +588,19 @@ fn array_property(description: &str) -> Value {
|
|
|
460
588
|
serde_json::json!({"type": "array", "description": description, "items": {"type": "object", "additionalProperties": true}})
|
|
461
589
|
}
|
|
462
590
|
|
|
463
|
-
pub(crate) fn dispatch_tool(
|
|
591
|
+
pub(crate) fn dispatch_tool(
|
|
592
|
+
tools: &TeamOrchestratorTools,
|
|
593
|
+
tool: McpTool,
|
|
594
|
+
args: &Value,
|
|
595
|
+
) -> ToolResult {
|
|
464
596
|
if scope_ceiling_tool(tool) {
|
|
465
597
|
tools.validate_rpc_scope_args(tool.wire_name(), args)?;
|
|
466
598
|
}
|
|
467
599
|
match tool {
|
|
468
|
-
McpTool::AssignTask => tools.assign_task(
|
|
600
|
+
McpTool::AssignTask => tools.assign_task(
|
|
601
|
+
args.get("task").unwrap_or(args),
|
|
602
|
+
args.get("message").and_then(Value::as_str),
|
|
603
|
+
),
|
|
469
604
|
McpTool::SendMessage => {
|
|
470
605
|
let target = message_target_from_value(args.get("to"));
|
|
471
606
|
let content = args.get("content").and_then(Value::as_str).unwrap_or("");
|
|
@@ -490,36 +625,61 @@ pub(crate) fn dispatch_tool(tools: &TeamOrchestratorTools, tool: McpTool, args:
|
|
|
490
625
|
// cr verdict (T3-1 refined): an unknown status literal normalizes to
|
|
491
626
|
// Partial and is OBSERVABLE at this ingestion boundary, never silent.
|
|
492
627
|
{
|
|
493
|
-
let (status, unknown) =
|
|
494
|
-
|
|
495
|
-
|
|
628
|
+
let (status, unknown) =
|
|
629
|
+
crate::mcp_server::normalize::normalize_result_status_observed(
|
|
630
|
+
args.get("status").and_then(Value::as_str),
|
|
631
|
+
);
|
|
496
632
|
if let Some(raw) = unknown {
|
|
497
633
|
tools.note_unknown_result_status(&raw);
|
|
498
634
|
}
|
|
499
635
|
status
|
|
500
636
|
},
|
|
501
|
-
args.get("changes")
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
args.get("
|
|
505
|
-
|
|
637
|
+
args.get("changes")
|
|
638
|
+
.and_then(Value::as_array)
|
|
639
|
+
.map(Vec::as_slice),
|
|
640
|
+
args.get("tests")
|
|
641
|
+
.and_then(Value::as_array)
|
|
642
|
+
.map(Vec::as_slice),
|
|
643
|
+
args.get("risks")
|
|
644
|
+
.and_then(Value::as_array)
|
|
645
|
+
.map(Vec::as_slice),
|
|
646
|
+
args.get("artifacts")
|
|
647
|
+
.and_then(Value::as_array)
|
|
648
|
+
.map(Vec::as_slice),
|
|
649
|
+
args.get("next_actions")
|
|
650
|
+
.and_then(Value::as_array)
|
|
651
|
+
.map(Vec::as_slice),
|
|
506
652
|
args.get("task_id").and_then(Value::as_str),
|
|
507
653
|
args.get("agent_id").and_then(Value::as_str),
|
|
508
654
|
),
|
|
509
|
-
McpTool::UpdateState =>
|
|
655
|
+
McpTool::UpdateState => {
|
|
656
|
+
tools.update_state(args.get("note").and_then(Value::as_str).unwrap_or(""))
|
|
657
|
+
}
|
|
510
658
|
McpTool::GetTeamStatus => tools.get_team_status(),
|
|
511
|
-
McpTool::StopAgent =>
|
|
659
|
+
McpTool::StopAgent => {
|
|
660
|
+
tools.stop_agent(args.get("agent_id").and_then(Value::as_str).unwrap_or(""))
|
|
661
|
+
}
|
|
512
662
|
McpTool::ResetAgent => tools.reset_agent(
|
|
513
663
|
args.get("agent_id").and_then(Value::as_str).unwrap_or(""),
|
|
514
|
-
args.get("discard_session")
|
|
664
|
+
args.get("discard_session")
|
|
665
|
+
.and_then(Value::as_bool)
|
|
666
|
+
.unwrap_or(false),
|
|
515
667
|
),
|
|
516
668
|
McpTool::AddAgent => tools.add_agent(
|
|
517
|
-
args.get("new_agent_id")
|
|
518
|
-
|
|
669
|
+
args.get("new_agent_id")
|
|
670
|
+
.and_then(Value::as_str)
|
|
671
|
+
.unwrap_or(""),
|
|
672
|
+
args.get("role_file_path")
|
|
673
|
+
.and_then(Value::as_str)
|
|
674
|
+
.unwrap_or(""),
|
|
519
675
|
),
|
|
520
676
|
McpTool::ForkAgent => tools.fork_agent(
|
|
521
|
-
args.get("source_agent_id")
|
|
522
|
-
|
|
677
|
+
args.get("source_agent_id")
|
|
678
|
+
.and_then(Value::as_str)
|
|
679
|
+
.unwrap_or(""),
|
|
680
|
+
args.get("as_agent_id")
|
|
681
|
+
.and_then(Value::as_str)
|
|
682
|
+
.unwrap_or(""),
|
|
523
683
|
args.get("label").and_then(Value::as_str),
|
|
524
684
|
),
|
|
525
685
|
McpTool::RequestHuman => tools.request_human(
|
|
@@ -531,7 +691,9 @@ pub(crate) fn dispatch_tool(tools: &TeamOrchestratorTools, tool: McpTool, args:
|
|
|
531
691
|
McpTool::StuckCancel => tools.stuck_cancel(
|
|
532
692
|
args.get("agent_id").and_then(Value::as_str).unwrap_or(""),
|
|
533
693
|
// tools.py:351 — the MCP default alert_type is "stuck", not "all".
|
|
534
|
-
args.get("alert_type")
|
|
694
|
+
args.get("alert_type")
|
|
695
|
+
.and_then(Value::as_str)
|
|
696
|
+
.unwrap_or("stuck"),
|
|
535
697
|
),
|
|
536
698
|
}
|
|
537
699
|
}
|
|
@@ -598,7 +760,10 @@ mod e23_lifecycle_marker_tests {
|
|
|
598
760
|
assert_eq!(events[0]["event"], serde_json::json!("mcp.server_started"));
|
|
599
761
|
assert_eq!(events[1]["event"], serde_json::json!("mcp.server_exit"));
|
|
600
762
|
assert_eq!(events[1]["reason"], serde_json::json!("stdin_eof"));
|
|
601
|
-
assert_eq!(
|
|
763
|
+
assert_eq!(
|
|
764
|
+
events[1]["workspace"],
|
|
765
|
+
serde_json::json!(ws.display().to_string())
|
|
766
|
+
);
|
|
602
767
|
assert_eq!(events[1]["pid"], serde_json::json!(std::process::id()));
|
|
603
768
|
assert!(events[1].get("ppid").is_some());
|
|
604
769
|
let _ = std::fs::remove_dir_all(&ws);
|
|
@@ -618,9 +783,8 @@ mod e23_lifecycle_marker_tests {
|
|
|
618
783
|
}
|
|
619
784
|
|
|
620
785
|
let ws = marker_ws("fatal");
|
|
621
|
-
let input =
|
|
622
|
-
br#"{"jsonrpc":"2.0","id":1,"method":"initialize"}"#.to_vec()
|
|
623
|
-
);
|
|
786
|
+
let input =
|
|
787
|
+
std::io::Cursor::new(br#"{"jsonrpc":"2.0","id":1,"method":"initialize"}"#.to_vec());
|
|
624
788
|
|
|
625
789
|
let err = run_stdio_loop(&ws, input, FailingWriter).expect_err("writer failure");
|
|
626
790
|
|
|
@@ -629,12 +793,10 @@ mod e23_lifecycle_marker_tests {
|
|
|
629
793
|
assert_eq!(events[0]["event"], serde_json::json!("mcp.server_started"));
|
|
630
794
|
assert_eq!(events[1]["event"], serde_json::json!("mcp.server_exit"));
|
|
631
795
|
assert_eq!(events[1]["reason"], serde_json::json!("fatal_error"));
|
|
632
|
-
assert!(
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
.contains("simulated stdout failure")
|
|
637
|
-
);
|
|
796
|
+
assert!(events[1]["error"]
|
|
797
|
+
.as_str()
|
|
798
|
+
.unwrap_or_default()
|
|
799
|
+
.contains("simulated stdout failure"));
|
|
638
800
|
let _ = std::fs::remove_dir_all(&ws);
|
|
639
801
|
}
|
|
640
802
|
}
|
|
@@ -362,7 +362,10 @@ pub fn deliver_pending_message(
|
|
|
362
362
|
}
|
|
363
363
|
let resolved = resolve_inject_target(state, &message.recipient, transport, &live_targets);
|
|
364
364
|
if let Some(stale) = resolved.stale_binding.as_ref() {
|
|
365
|
-
event_log.write(
|
|
365
|
+
event_log.write(
|
|
366
|
+
"worker_pane_binding_stale",
|
|
367
|
+
stale.as_event_payload(message_id, &message.recipient),
|
|
368
|
+
)?;
|
|
366
369
|
}
|
|
367
370
|
let target = resolved.target.clone();
|
|
368
371
|
if let Some(outcome) = block_missing_worker_target(
|
|
@@ -1232,7 +1235,11 @@ fn resolve_inject_target(
|
|
|
1232
1235
|
}) {
|
|
1233
1236
|
return ResolvedInjectTarget {
|
|
1234
1237
|
target: Target::Pane(pane),
|
|
1235
|
-
metadata: Some(target_metadata(
|
|
1238
|
+
metadata: Some(target_metadata(
|
|
1239
|
+
transport,
|
|
1240
|
+
live_pane,
|
|
1241
|
+
"validated_cached_pane",
|
|
1242
|
+
)),
|
|
1236
1243
|
stale_binding: None,
|
|
1237
1244
|
};
|
|
1238
1245
|
}
|
|
@@ -1259,15 +1266,13 @@ fn live_pane_for_session_window<'a>(
|
|
|
1259
1266
|
session: &str,
|
|
1260
1267
|
window: &str,
|
|
1261
1268
|
) -> Option<&'a PaneInfo> {
|
|
1262
|
-
targets
|
|
1263
|
-
.
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
.is_some_and(|name| name.as_str() == window)
|
|
1270
|
-
})
|
|
1269
|
+
targets.iter().find(|target| {
|
|
1270
|
+
target.session.as_str() == session
|
|
1271
|
+
&& target
|
|
1272
|
+
.window_name
|
|
1273
|
+
.as_ref()
|
|
1274
|
+
.is_some_and(|name| name.as_str() == window)
|
|
1275
|
+
})
|
|
1271
1276
|
}
|
|
1272
1277
|
|
|
1273
1278
|
fn stale_worker_pane_binding(
|
|
@@ -2221,8 +2226,7 @@ fn record_turn_open_if_leader_to_worker_scoped(
|
|
|
2221
2226
|
save_scoped_state_reapplying_after_conflict(workspace, &state, owner_team_id, |latest| {
|
|
2222
2227
|
arm_turn_open(latest, recipient, &delivered.message_id);
|
|
2223
2228
|
})?;
|
|
2224
|
-
let mut event =
|
|
2225
|
-
serde_json::json!({"agent_id": recipient, "message_id": delivered.message_id});
|
|
2229
|
+
let mut event = serde_json::json!({"agent_id": recipient, "message_id": delivered.message_id});
|
|
2226
2230
|
if let Some(metadata) = metadata {
|
|
2227
2231
|
append_target_metadata(&mut event, metadata);
|
|
2228
2232
|
}
|
|
@@ -2256,11 +2260,9 @@ fn arm_turn_open(state: &mut serde_json::Value, recipient: &str, message_id: &Op
|
|
|
2256
2260
|
// (whitelisted for the transition) and `mcp_server/helpers.rs`; other
|
|
2257
2261
|
// messaging/lifecycle/mcp_server code MUST NOT treat this as
|
|
2258
2262
|
// authoritative task state.
|
|
2259
|
-
let field = message_id
|
|
2260
|
-
.
|
|
2261
|
-
|
|
2262
|
-
serde_json::Value::String(id.clone())
|
|
2263
|
-
});
|
|
2263
|
+
let field = message_id.as_ref().map_or(serde_json::Value::Null, |id| {
|
|
2264
|
+
serde_json::Value::String(id.clone())
|
|
2265
|
+
});
|
|
2264
2266
|
agent.insert("current_turn_message_id".to_string(), field);
|
|
2265
2267
|
}
|
|
2266
2268
|
}
|
|
@@ -122,7 +122,10 @@ pub(crate) fn working_seconds(scrollback: &str) -> Option<u64> {
|
|
|
122
122
|
// `❯ Run /review`, `Worked for 8m 34s`, or an empty composer prompt,
|
|
123
123
|
// there is no LIVE working indicator and we return None — handing off
|
|
124
124
|
// to the structural latest_prompt_signal / IRON LAW Uncertain path.
|
|
125
|
-
let last_non_empty = scrollback
|
|
125
|
+
let last_non_empty = scrollback
|
|
126
|
+
.lines()
|
|
127
|
+
.rev()
|
|
128
|
+
.find(|line| !line.trim().is_empty())?;
|
|
126
129
|
let lower = last_non_empty.to_ascii_lowercase();
|
|
127
130
|
let start = lower.find("working (")?;
|
|
128
131
|
let rest = last_non_empty.get(start + "Working (".len()..)?;
|
|
@@ -193,9 +196,27 @@ pub(crate) fn latest_prompt_signal(scrollback: &str) -> Option<AgentActivity> {
|
|
|
193
196
|
// and Claude Code tool-progress verbs. We look for STRUCTURAL
|
|
194
197
|
// composer/status signals in the active region only.
|
|
195
198
|
if [
|
|
196
|
-
"working (",
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
+
"working (",
|
|
200
|
+
"thinking",
|
|
201
|
+
"⠋",
|
|
202
|
+
"⠙",
|
|
203
|
+
"⠹",
|
|
204
|
+
"⠸",
|
|
205
|
+
"⠼",
|
|
206
|
+
"⠴",
|
|
207
|
+
"⠦",
|
|
208
|
+
"⠧",
|
|
209
|
+
"⠇",
|
|
210
|
+
"⠏",
|
|
211
|
+
"✶",
|
|
212
|
+
"✢",
|
|
213
|
+
"✻",
|
|
214
|
+
"analyzing",
|
|
215
|
+
"reading",
|
|
216
|
+
"writing",
|
|
217
|
+
"searching",
|
|
218
|
+
"running",
|
|
219
|
+
"editing",
|
|
199
220
|
]
|
|
200
221
|
.iter()
|
|
201
222
|
.any(|needle| lower.contains(needle))
|
|
@@ -8,7 +8,9 @@ use serde_json::Value;
|
|
|
8
8
|
use crate::event_log::EventLog;
|
|
9
9
|
use crate::message_store::{MessageStore, NotificationClaimParams};
|
|
10
10
|
use crate::model::ids::TaskId;
|
|
11
|
-
use crate::transport::{
|
|
11
|
+
use crate::transport::{
|
|
12
|
+
InjectPayload, InjectReport, Key, PaneId, Target, Transport, TransportError,
|
|
13
|
+
};
|
|
12
14
|
|
|
13
15
|
use super::helpers::MessageStatusShadow;
|
|
14
16
|
use super::{DeliveryOutcome, DeliveryRefusal, DeliveryStage, DeliveryStatus, MessagingError};
|
|
@@ -405,10 +407,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
405
407
|
// Row status is left untouched so status/monitor surfaces the
|
|
406
408
|
// pending notification until the operator rebinds the leader.
|
|
407
409
|
let (status, channel) = if socket_bound {
|
|
408
|
-
(
|
|
409
|
-
DeliveryStatus::Blocked,
|
|
410
|
-
"rebind_required".to_string(),
|
|
411
|
-
)
|
|
410
|
+
(DeliveryStatus::Blocked, "rebind_required".to_string())
|
|
412
411
|
} else {
|
|
413
412
|
(DeliveryStatus::Failed, "fallback_pane".to_string())
|
|
414
413
|
};
|
|
@@ -103,9 +103,8 @@ pub use types::{
|
|
|
103
103
|
CheckKind, CheckStatus, ContractSuiteCheck, DeliveryOutcome, DeliveryRefusal, DeliveryStage,
|
|
104
104
|
DeliveryStatus, IdleEvaluation, LeaderNotificationKey, LeaderReceiver, PaneWidthQuery,
|
|
105
105
|
ProviderSdkCalls, ReceiverMode, ScheduledKind, SelftestCheck, SelftestReport, SendEventPayload,
|
|
106
|
-
TrustRetryPayload, WatcherNotice, WorkerRuntimeState,
|
|
107
|
-
|
|
108
|
-
TRUST_RETRY_BACKOFF_SECONDS, TRUST_RETRY_MAX_ATTEMPTS,
|
|
106
|
+
TrustRetryPayload, WatcherNotice, WorkerRuntimeState, RESULT_DELIVERY_MAX_ATTEMPTS,
|
|
107
|
+
SEND_RETRY_MAX_ATTEMPTS, TRUST_RETRY_BACKOFF_SECONDS, TRUST_RETRY_MAX_ATTEMPTS,
|
|
109
108
|
};
|
|
110
109
|
pub use watchers::{
|
|
111
110
|
delivered_result_message, format_result_watcher_notification, notify_result_watchers,
|