@team-agent/installer 0.5.77 → 0.5.78
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 +161 -29
- package/crates/team-agent/src/cli/diagnose.rs +333 -68
- package/crates/team-agent/src/cli/emit.rs +24 -8
- package/crates/team-agent/src/cli/mod.rs +543 -98
- package/crates/team-agent/src/cli/models.rs +362 -32
- package/crates/team-agent/src/cli/named_address.rs +19 -5
- package/crates/team-agent/src/cli/profile.rs +35 -4
- package/crates/team-agent/src/cli/spec.rs +7 -2
- package/crates/team-agent/src/cli/status_port/compact.rs +12 -8
- package/crates/team-agent/src/cli/status_port/snapshot.rs +15 -12
- package/crates/team-agent/src/cli/status_port/store.rs +1 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +62 -8
- package/crates/team-agent/src/cli/tests/named_address.rs +70 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +81 -6
- package/crates/team-agent/src/cli/types.rs +1 -0
- package/crates/team-agent/src/leader/lease.rs +492 -33
- package/crates/team-agent/src/leader/owner_bind.rs +40 -12
- package/crates/team-agent/src/leader/rediscover/tests.rs +65 -0
- package/crates/team-agent/src/leader/rediscover.rs +36 -6
- package/crates/team-agent/src/leader/start.rs +151 -14
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +15 -9
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +28 -227
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -18
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +94 -227
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +59 -10
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +65 -18
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +1449 -282
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +349 -4
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +11 -11
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +35 -3
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +16 -0
- package/crates/team-agent/src/lifecycle/launch.rs +30 -7
- package/crates/team-agent/src/lifecycle/profile_launch.rs +37 -3
- package/crates/team-agent/src/lifecycle/restart/agent.rs +112 -100
- package/crates/team-agent/src/lifecycle/restart/common.rs +82 -52
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +996 -66
- package/crates/team-agent/src/lifecycle/restart.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +15 -0
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +5 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +11 -13
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +119 -4
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +12 -0
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +22 -0
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +12 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +265 -198
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +14 -30
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +2 -5
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +10 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +58 -35
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +10 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +9 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -168
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +145 -212
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +16 -2
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +54 -9
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +78 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +51 -10
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +50 -7
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +137 -0
- package/crates/team-agent/src/lifecycle/types.rs +8 -0
- package/crates/team-agent/src/mcp_server/wire.rs +140 -11
- package/crates/team-agent/src/messaging/delivery.rs +67 -8
- package/crates/team-agent/src/messaging/leader_channel.rs +56 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +10 -2
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +2 -5
- package/crates/team-agent/src/state/persist.rs +97 -1
- package/crates/team-agent/src/state/repository.rs +29 -0
- package/crates/team-agent/src/test_support/models_timeout_fixture.rs +43 -21
- package/crates/team-agent/src/tmux_backend/tests.rs +121 -4
- package/crates/team-agent/src/tmux_backend.rs +208 -118
- package/crates/team-agent/src/transport.rs +72 -0
- package/crates/team-agent/src/transport_factory.rs +53 -0
- package/package.json +4 -5
- package/skills/team-agent/SKILL.md +45 -17
- package/skills/team-agent/command-coverage.json +4 -29
- package/npm/check-skill-links.mjs +0 -88
- package/skills/team-agent/references/team-agent-operator.md +0 -672
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
//! boundary:
|
|
21
21
|
//! - 不拷贝外部角色文件进 team 目录,就地读取编译
|
|
22
22
|
//! - 起席一律走 restart 的 start_agent_at_paths,本文件不直接 spawn
|
|
23
|
-
//! -
|
|
23
|
+
//! - 回滚只恢复 spec 字节与 runtime state,不回收已 spawn 的 pane
|
|
24
24
|
//! maturity: wired
|
|
25
25
|
//! ---
|
|
26
26
|
use std::collections::{BTreeMap, BTreeSet};
|
|
@@ -93,51 +93,6 @@ impl Drop for AgentReservation {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
fn discover_pi_model_candidates(requested: &str) -> Result<Vec<String>, ()> {
|
|
97
|
-
crate::lifecycle::launch::pi_mcp::pi_model_candidates(requested).map_err(|_| ())
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
fn preflight_role_with_pi_model(
|
|
101
|
-
run_workspace: &Path,
|
|
102
|
-
team_dir: &Path,
|
|
103
|
-
agent_id: &AgentId,
|
|
104
|
-
role_file_path: &Path,
|
|
105
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
106
|
-
) -> Result<(), LifecycleError> {
|
|
107
|
-
if !role_file_path.exists() {
|
|
108
|
-
return Err(LifecycleError::Compile(format!(
|
|
109
|
-
"role file not found: {}",
|
|
110
|
-
role_file_path.display()
|
|
111
|
-
)));
|
|
112
|
-
}
|
|
113
|
-
let (meta, _) = crate::compiler::read_front_matter(role_file_path)
|
|
114
|
-
.map_err(|error| LifecycleError::Compile(error.to_string()))?;
|
|
115
|
-
crate::compiler::preflight_pi_role_model_with(&meta, discover).map_err(|error| {
|
|
116
|
-
LifecycleError::PiModelPreflight {
|
|
117
|
-
requested: error.requested,
|
|
118
|
-
candidates: error.candidates,
|
|
119
|
-
action: error.action,
|
|
120
|
-
not_ready: error.not_ready,
|
|
121
|
-
}
|
|
122
|
-
})?;
|
|
123
|
-
let team_meta = crate::compiler::read_front_matter(&team_dir.join("TEAM.md"))
|
|
124
|
-
.map(|(meta, _)| meta)
|
|
125
|
-
.unwrap_or(Value::Null);
|
|
126
|
-
let compiled = crate::compiler::compile_role_agent(
|
|
127
|
-
role_file_path,
|
|
128
|
-
&team_meta,
|
|
129
|
-
&run_workspace.display().to_string(),
|
|
130
|
-
)
|
|
131
|
-
.map_err(|error| LifecycleError::Compile(error.to_string()))?;
|
|
132
|
-
if compiled.id != agent_id.as_str() {
|
|
133
|
-
return Err(LifecycleError::Compile(format!(
|
|
134
|
-
"role file declares name '{}' but add-agent id is '{}'",
|
|
135
|
-
compiled.id, agent_id
|
|
136
|
-
)));
|
|
137
|
-
}
|
|
138
|
-
Ok(())
|
|
139
|
-
}
|
|
140
|
-
|
|
141
96
|
fn reserve_agent_slot(
|
|
142
97
|
workspace: &Path,
|
|
143
98
|
team: Option<&str>,
|
|
@@ -254,25 +209,6 @@ pub fn add_agent(
|
|
|
254
209
|
role_file_path: &Path,
|
|
255
210
|
open_display: bool,
|
|
256
211
|
team: Option<&str>,
|
|
257
|
-
) -> Result<AddAgentReport, LifecycleError> {
|
|
258
|
-
let mut discover = discover_pi_model_candidates;
|
|
259
|
-
add_agent_with_pi_preflight(
|
|
260
|
-
workspace,
|
|
261
|
-
agent_id,
|
|
262
|
-
role_file_path,
|
|
263
|
-
open_display,
|
|
264
|
-
team,
|
|
265
|
-
&mut discover,
|
|
266
|
-
)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
fn add_agent_with_pi_preflight(
|
|
270
|
-
workspace: &Path,
|
|
271
|
-
agent_id: &AgentId,
|
|
272
|
-
role_file_path: &Path,
|
|
273
|
-
open_display: bool,
|
|
274
|
-
team: Option<&str>,
|
|
275
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
276
212
|
) -> Result<AddAgentReport, LifecycleError> {
|
|
277
213
|
let selected = match crate::state::selector::resolve_active_team(
|
|
278
214
|
workspace,
|
|
@@ -281,22 +217,25 @@ fn add_agent_with_pi_preflight(
|
|
|
281
217
|
) {
|
|
282
218
|
Ok(selected) => selected,
|
|
283
219
|
Err(_) if workspace.join("TEAM.md").exists() => {
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
// the
|
|
220
|
+
// TEAM.md lives in the run workspace. `team_workspace()` always walks
|
|
221
|
+
// to the parent and would spawn on a hash socket of the scratch parent.
|
|
222
|
+
// Use the idempotent run-workspace so persisted `tmux_endpoint` wins.
|
|
223
|
+
let run_workspace = crate::model::paths::canonical_run_workspace(workspace)
|
|
224
|
+
.map_err(|e| LifecycleError::StatePersist(e.to_string()))?;
|
|
287
225
|
let transport =
|
|
288
226
|
crate::lifecycle::restart::lifecycle_worker_tmux_backend_for_selected_state(
|
|
289
|
-
|
|
227
|
+
&run_workspace, team,
|
|
290
228
|
)
|
|
291
|
-
.unwrap_or_else(|_|
|
|
292
|
-
|
|
229
|
+
.unwrap_or_else(|_| {
|
|
230
|
+
crate::tmux_backend::TmuxBackend::for_workspace(&run_workspace)
|
|
231
|
+
});
|
|
232
|
+
return add_agent_with_transport(
|
|
293
233
|
workspace,
|
|
294
234
|
agent_id,
|
|
295
235
|
role_file_path,
|
|
296
236
|
open_display,
|
|
297
237
|
team,
|
|
298
238
|
&transport,
|
|
299
|
-
discover,
|
|
300
239
|
);
|
|
301
240
|
}
|
|
302
241
|
Err(error) => return Err(LifecycleError::TeamSelect(error.to_string())),
|
|
@@ -307,13 +246,6 @@ fn add_agent_with_pi_preflight(
|
|
|
307
246
|
team: Some(selected.team_key.as_str()),
|
|
308
247
|
agent_id: Some(agent_id),
|
|
309
248
|
})?;
|
|
310
|
-
preflight_role_with_pi_model(
|
|
311
|
-
&selected.run_workspace,
|
|
312
|
-
&selected.team_dir,
|
|
313
|
-
agent_id,
|
|
314
|
-
role_file_path,
|
|
315
|
-
discover,
|
|
316
|
-
)?;
|
|
317
249
|
let reservation = reserve_agent_slot(
|
|
318
250
|
&selected.run_workspace,
|
|
319
251
|
Some(selected.team_key.as_str()),
|
|
@@ -364,38 +296,9 @@ pub fn add_agent_force(
|
|
|
364
296
|
open_display: bool,
|
|
365
297
|
team: Option<&str>,
|
|
366
298
|
force: bool,
|
|
367
|
-
) -> Result<AddAgentReport, LifecycleError> {
|
|
368
|
-
let mut discover = discover_pi_model_candidates;
|
|
369
|
-
add_agent_force_with_pi_preflight(
|
|
370
|
-
workspace,
|
|
371
|
-
agent_id,
|
|
372
|
-
role_file_path,
|
|
373
|
-
open_display,
|
|
374
|
-
team,
|
|
375
|
-
force,
|
|
376
|
-
&mut discover,
|
|
377
|
-
)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
#[allow(clippy::too_many_arguments)]
|
|
381
|
-
fn add_agent_force_with_pi_preflight(
|
|
382
|
-
workspace: &Path,
|
|
383
|
-
agent_id: &AgentId,
|
|
384
|
-
role_file_path: &Path,
|
|
385
|
-
open_display: bool,
|
|
386
|
-
team: Option<&str>,
|
|
387
|
-
force: bool,
|
|
388
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
389
299
|
) -> Result<AddAgentReport, LifecycleError> {
|
|
390
300
|
if !force {
|
|
391
|
-
return
|
|
392
|
-
workspace,
|
|
393
|
-
agent_id,
|
|
394
|
-
role_file_path,
|
|
395
|
-
open_display,
|
|
396
|
-
team,
|
|
397
|
-
discover,
|
|
398
|
-
);
|
|
301
|
+
return add_agent(workspace, agent_id, role_file_path, open_display, team);
|
|
399
302
|
}
|
|
400
303
|
let selected = crate::state::selector::resolve_active_team(
|
|
401
304
|
workspace,
|
|
@@ -423,7 +326,6 @@ fn add_agent_force_with_pi_preflight(
|
|
|
423
326
|
open_display,
|
|
424
327
|
Some(canonical_team_key.as_str()),
|
|
425
328
|
&transport,
|
|
426
|
-
discover,
|
|
427
329
|
)
|
|
428
330
|
}
|
|
429
331
|
|
|
@@ -442,28 +344,6 @@ pub(crate) fn add_agent_with_transport(
|
|
|
442
344
|
open_display: bool,
|
|
443
345
|
team: Option<&str>,
|
|
444
346
|
transport: &dyn Transport,
|
|
445
|
-
) -> Result<AddAgentReport, LifecycleError> {
|
|
446
|
-
let mut discover = discover_pi_model_candidates;
|
|
447
|
-
add_agent_with_transport_pi_preflight(
|
|
448
|
-
workspace,
|
|
449
|
-
agent_id,
|
|
450
|
-
role_file_path,
|
|
451
|
-
open_display,
|
|
452
|
-
team,
|
|
453
|
-
transport,
|
|
454
|
-
&mut discover,
|
|
455
|
-
)
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
#[allow(clippy::too_many_arguments)]
|
|
459
|
-
pub(crate) fn add_agent_with_transport_pi_preflight(
|
|
460
|
-
workspace: &Path,
|
|
461
|
-
agent_id: &AgentId,
|
|
462
|
-
role_file_path: &Path,
|
|
463
|
-
open_display: bool,
|
|
464
|
-
team: Option<&str>,
|
|
465
|
-
transport: &dyn Transport,
|
|
466
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
467
347
|
) -> Result<AddAgentReport, LifecycleError> {
|
|
468
348
|
let run_workspace = crate::model::paths::canonical_run_workspace(workspace)
|
|
469
349
|
.map_err(|e| LifecycleError::StatePersist(e.to_string()))?;
|
|
@@ -473,13 +353,6 @@ pub(crate) fn add_agent_with_transport_pi_preflight(
|
|
|
473
353
|
team,
|
|
474
354
|
agent_id: Some(agent_id),
|
|
475
355
|
})?;
|
|
476
|
-
preflight_role_with_pi_model(
|
|
477
|
-
&run_workspace,
|
|
478
|
-
workspace,
|
|
479
|
-
agent_id,
|
|
480
|
-
role_file_path,
|
|
481
|
-
discover,
|
|
482
|
-
)?;
|
|
483
356
|
let reservation = reserve_agent_slot(&run_workspace, team, agent_id)?;
|
|
484
357
|
drop(lifecycle_lock);
|
|
485
358
|
add_agent_with_transport_at_paths_reserved(
|
|
@@ -511,40 +384,15 @@ pub(crate) fn add_agent_with_transport_force(
|
|
|
511
384
|
team: Option<&str>,
|
|
512
385
|
force: bool,
|
|
513
386
|
transport: &dyn Transport,
|
|
514
|
-
) -> Result<AddAgentReport, LifecycleError> {
|
|
515
|
-
let mut discover = discover_pi_model_candidates;
|
|
516
|
-
add_agent_with_transport_force_pi_preflight(
|
|
517
|
-
workspace,
|
|
518
|
-
agent_id,
|
|
519
|
-
role_file_path,
|
|
520
|
-
open_display,
|
|
521
|
-
team,
|
|
522
|
-
force,
|
|
523
|
-
transport,
|
|
524
|
-
&mut discover,
|
|
525
|
-
)
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
#[allow(clippy::too_many_arguments)]
|
|
529
|
-
pub(crate) fn add_agent_with_transport_force_pi_preflight(
|
|
530
|
-
workspace: &Path,
|
|
531
|
-
agent_id: &AgentId,
|
|
532
|
-
role_file_path: &Path,
|
|
533
|
-
open_display: bool,
|
|
534
|
-
team: Option<&str>,
|
|
535
|
-
force: bool,
|
|
536
|
-
transport: &dyn Transport,
|
|
537
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
538
387
|
) -> Result<AddAgentReport, LifecycleError> {
|
|
539
388
|
if !force {
|
|
540
|
-
return
|
|
389
|
+
return add_agent_with_transport(
|
|
541
390
|
workspace,
|
|
542
391
|
agent_id,
|
|
543
392
|
role_file_path,
|
|
544
393
|
open_display,
|
|
545
394
|
team,
|
|
546
395
|
transport,
|
|
547
|
-
discover,
|
|
548
396
|
);
|
|
549
397
|
}
|
|
550
398
|
let run_workspace = crate::model::paths::canonical_run_workspace(workspace)
|
|
@@ -563,7 +411,6 @@ pub(crate) fn add_agent_with_transport_force_pi_preflight(
|
|
|
563
411
|
open_display,
|
|
564
412
|
team,
|
|
565
413
|
transport,
|
|
566
|
-
discover,
|
|
567
414
|
)
|
|
568
415
|
}
|
|
569
416
|
|
|
@@ -572,7 +419,6 @@ pub(crate) fn add_agent_with_transport_force_pi_preflight(
|
|
|
572
419
|
/// returns: 新席报告;成功后还要过快照的一致性校验
|
|
573
420
|
/// errors: 角色文件不存在先行返回 Compile;摘除、加回或一致性校验失败时按快照恢复并返回错误
|
|
574
421
|
/// ---
|
|
575
|
-
#[allow(clippy::too_many_arguments)]
|
|
576
422
|
pub(super) fn force_recreate_with_transport_locked(
|
|
577
423
|
run_workspace: &Path,
|
|
578
424
|
team_dir: &Path,
|
|
@@ -581,16 +427,15 @@ pub(super) fn force_recreate_with_transport_locked(
|
|
|
581
427
|
open_display: bool,
|
|
582
428
|
team: Option<&str>,
|
|
583
429
|
transport: &dyn Transport,
|
|
584
|
-
discover: &mut dyn FnMut(&str) -> Result<Vec<String>, ()>,
|
|
585
430
|
) -> Result<AddAgentReport, LifecycleError> {
|
|
586
431
|
// Reject an unusable replacement source before consuming the old seat.
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
432
|
+
// Deeper compile/spawn failures remain covered by the transaction snapshot.
|
|
433
|
+
if !role_file_path.exists() {
|
|
434
|
+
return Err(LifecycleError::Compile(format!(
|
|
435
|
+
"role file not found: {}",
|
|
436
|
+
role_file_path.display()
|
|
437
|
+
)));
|
|
438
|
+
}
|
|
594
439
|
let snapshot = crate::lifecycle::restart::remove::ForceRecreateSnapshot::capture(
|
|
595
440
|
run_workspace,
|
|
596
441
|
agent_id,
|
|
@@ -671,28 +516,6 @@ pub(super) fn maybe_fail_force_recreate_after_spawn() -> Result<(), LifecycleErr
|
|
|
671
516
|
)))
|
|
672
517
|
}
|
|
673
518
|
|
|
674
|
-
fn rollback_added_pi_wrapper(
|
|
675
|
-
run_workspace: &Path,
|
|
676
|
-
team_key: &str,
|
|
677
|
-
agent_id: &AgentId,
|
|
678
|
-
role_meta: &Value,
|
|
679
|
-
) -> Result<(), LifecycleError> {
|
|
680
|
-
if role_meta.get("provider").and_then(Value::as_str) != Some("pi") {
|
|
681
|
-
return Ok(());
|
|
682
|
-
}
|
|
683
|
-
let wrapper =
|
|
684
|
-
crate::lifecycle::launch::pi_mcp::pi_seat_paths(run_workspace, team_key, agent_id.as_str())
|
|
685
|
-
.wrapper;
|
|
686
|
-
match std::fs::remove_file(&wrapper) {
|
|
687
|
-
Ok(()) => Ok(()),
|
|
688
|
-
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
|
|
689
|
-
Err(error) => Err(LifecycleError::StatePersist(format!(
|
|
690
|
-
"failed to roll back added Pi wrapper {}: {error}",
|
|
691
|
-
wrapper.display()
|
|
692
|
-
))),
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
519
|
/// ---
|
|
697
520
|
/// purpose: 加席的实体实现,含 owner 门、重名拒绝、重编译 spec 原子写、席位 state upsert 与起席
|
|
698
521
|
/// params:
|
|
@@ -878,8 +701,6 @@ fn add_agent_with_transport_at_paths_reserved(
|
|
|
878
701
|
) {
|
|
879
702
|
Ok(started) => started,
|
|
880
703
|
Err(error) => {
|
|
881
|
-
let wrapper_rollback =
|
|
882
|
-
rollback_added_pi_wrapper(run_workspace, &canonical_team_key, agent_id, &meta);
|
|
883
704
|
rollback_add_agent_atomic(
|
|
884
705
|
run_workspace,
|
|
885
706
|
&spec_path,
|
|
@@ -888,12 +709,7 @@ fn add_agent_with_transport_at_paths_reserved(
|
|
|
888
709
|
agent_id,
|
|
889
710
|
"start_agent_failed",
|
|
890
711
|
);
|
|
891
|
-
return
|
|
892
|
-
Ok(()) => Err(error),
|
|
893
|
-
Err(rollback_error) => Err(LifecycleError::StatePersist(format!(
|
|
894
|
-
"{error}; {rollback_error}"
|
|
895
|
-
))),
|
|
896
|
-
};
|
|
712
|
+
return Err(error);
|
|
897
713
|
}
|
|
898
714
|
};
|
|
899
715
|
let (env, start_mode) = match started {
|
|
@@ -901,29 +717,19 @@ fn add_agent_with_transport_at_paths_reserved(
|
|
|
901
717
|
env, start_mode, ..
|
|
902
718
|
} => (env, start_mode),
|
|
903
719
|
StartAgentOutcome::Noop { .. } => {
|
|
904
|
-
let wrapper_rollback =
|
|
905
|
-
rollback_added_pi_wrapper(run_workspace, &canonical_team_key, agent_id, &meta);
|
|
906
720
|
rollback_add_agent_atomic(
|
|
907
721
|
run_workspace,
|
|
908
722
|
&spec_path,
|
|
909
723
|
pre_spec_text.as_deref(),
|
|
910
724
|
None,
|
|
911
725
|
agent_id,
|
|
912
|
-
"
|
|
726
|
+
"start_agent_noop",
|
|
913
727
|
);
|
|
914
|
-
|
|
915
|
-
"newly added agent {agent_id}
|
|
916
|
-
));
|
|
917
|
-
return match wrapper_rollback {
|
|
918
|
-
Ok(()) => Err(error),
|
|
919
|
-
Err(rollback_error) => Err(LifecycleError::StatePersist(format!(
|
|
920
|
-
"{error}; {rollback_error}"
|
|
921
|
-
))),
|
|
922
|
-
};
|
|
728
|
+
return Err(LifecycleError::RequirementUnmet(format!(
|
|
729
|
+
"start_agent.noop: newly added agent {agent_id} must spawn, not reuse a live window"
|
|
730
|
+
)));
|
|
923
731
|
}
|
|
924
732
|
StartAgentOutcome::Paused { .. } => {
|
|
925
|
-
let wrapper_rollback =
|
|
926
|
-
rollback_added_pi_wrapper(run_workspace, &canonical_team_key, agent_id, &meta);
|
|
927
733
|
rollback_add_agent_atomic(
|
|
928
734
|
run_workspace,
|
|
929
735
|
&spec_path,
|
|
@@ -932,14 +738,9 @@ fn add_agent_with_transport_at_paths_reserved(
|
|
|
932
738
|
agent_id,
|
|
933
739
|
"added_agent_paused",
|
|
934
740
|
);
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
Ok(()) => Err(error),
|
|
939
|
-
Err(rollback_error) => Err(LifecycleError::StatePersist(format!(
|
|
940
|
-
"{error}; {rollback_error}"
|
|
941
|
-
))),
|
|
942
|
-
};
|
|
741
|
+
return Err(LifecycleError::RequirementUnmet(format!(
|
|
742
|
+
"added agent {agent_id} is paused"
|
|
743
|
+
)));
|
|
943
744
|
}
|
|
944
745
|
};
|
|
945
746
|
if let Some(reservation) = reservation {
|
|
@@ -167,24 +167,6 @@ pub(super) fn upsert_agent_state_from_role(
|
|
|
167
167
|
"runtime state root is not an object".to_string(),
|
|
168
168
|
));
|
|
169
169
|
};
|
|
170
|
-
if !root
|
|
171
|
-
.get("session_name")
|
|
172
|
-
.and_then(serde_json::Value::as_str)
|
|
173
|
-
.is_some_and(|session| !session.is_empty())
|
|
174
|
-
{
|
|
175
|
-
if let Some(owner_session) = root
|
|
176
|
-
.get("leader_receiver")
|
|
177
|
-
.and_then(|receiver| receiver.get("session_name"))
|
|
178
|
-
.and_then(serde_json::Value::as_str)
|
|
179
|
-
.filter(|session| !session.is_empty())
|
|
180
|
-
.map(str::to_string)
|
|
181
|
-
{
|
|
182
|
-
root.insert(
|
|
183
|
-
"session_name".to_string(),
|
|
184
|
-
serde_json::Value::String(owner_session),
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
170
|
let agents = root
|
|
189
171
|
.entry("agents".to_string())
|
|
190
172
|
.or_insert_with(|| serde_json::json!({}));
|