@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.
Files changed (83) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +161 -29
  4. package/crates/team-agent/src/cli/diagnose.rs +333 -68
  5. package/crates/team-agent/src/cli/emit.rs +24 -8
  6. package/crates/team-agent/src/cli/mod.rs +543 -98
  7. package/crates/team-agent/src/cli/models.rs +362 -32
  8. package/crates/team-agent/src/cli/named_address.rs +19 -5
  9. package/crates/team-agent/src/cli/profile.rs +35 -4
  10. package/crates/team-agent/src/cli/spec.rs +7 -2
  11. package/crates/team-agent/src/cli/status_port/compact.rs +12 -8
  12. package/crates/team-agent/src/cli/status_port/snapshot.rs +15 -12
  13. package/crates/team-agent/src/cli/status_port/store.rs +1 -1
  14. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +62 -8
  15. package/crates/team-agent/src/cli/tests/named_address.rs +70 -0
  16. package/crates/team-agent/src/cli/tests/verb_profile.rs +81 -6
  17. package/crates/team-agent/src/cli/types.rs +1 -0
  18. package/crates/team-agent/src/leader/lease.rs +492 -33
  19. package/crates/team-agent/src/leader/owner_bind.rs +40 -12
  20. package/crates/team-agent/src/leader/rediscover/tests.rs +65 -0
  21. package/crates/team-agent/src/leader/rediscover.rs +36 -6
  22. package/crates/team-agent/src/leader/start.rs +151 -14
  23. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +15 -9
  24. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +28 -227
  25. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -18
  26. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +94 -227
  27. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +59 -10
  28. package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +65 -18
  29. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +1449 -282
  30. package/crates/team-agent/src/lifecycle/launch/readiness.rs +349 -4
  31. package/crates/team-agent/src/lifecycle/launch/spawn.rs +11 -11
  32. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +35 -3
  33. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +16 -0
  34. package/crates/team-agent/src/lifecycle/launch.rs +30 -7
  35. package/crates/team-agent/src/lifecycle/profile_launch.rs +37 -3
  36. package/crates/team-agent/src/lifecycle/restart/agent.rs +112 -100
  37. package/crates/team-agent/src/lifecycle/restart/common.rs +82 -52
  38. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +996 -66
  39. package/crates/team-agent/src/lifecycle/restart.rs +2 -2
  40. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +3 -0
  41. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +15 -0
  42. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +5 -0
  43. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +11 -13
  44. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +119 -4
  45. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +12 -0
  46. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +22 -0
  47. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +12 -0
  48. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +265 -198
  49. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +14 -30
  50. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +3 -0
  51. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +2 -5
  52. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +10 -0
  53. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +58 -35
  54. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +10 -0
  55. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +9 -0
  56. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -2
  57. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -168
  58. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +145 -212
  59. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +16 -2
  60. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +54 -9
  61. package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +78 -0
  62. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +3 -0
  63. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +51 -10
  64. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +50 -7
  65. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +137 -0
  66. package/crates/team-agent/src/lifecycle/types.rs +8 -0
  67. package/crates/team-agent/src/mcp_server/wire.rs +140 -11
  68. package/crates/team-agent/src/messaging/delivery.rs +67 -8
  69. package/crates/team-agent/src/messaging/leader_channel.rs +56 -0
  70. package/crates/team-agent/src/messaging/tests/runtime.rs +10 -2
  71. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +2 -5
  72. package/crates/team-agent/src/state/persist.rs +97 -1
  73. package/crates/team-agent/src/state/repository.rs +29 -0
  74. package/crates/team-agent/src/test_support/models_timeout_fixture.rs +43 -21
  75. package/crates/team-agent/src/tmux_backend/tests.rs +121 -4
  76. package/crates/team-agent/src/tmux_backend.rs +208 -118
  77. package/crates/team-agent/src/transport.rs +72 -0
  78. package/crates/team-agent/src/transport_factory.rs +53 -0
  79. package/package.json +4 -5
  80. package/skills/team-agent/SKILL.md +45 -17
  81. package/skills/team-agent/command-coverage.json +4 -29
  82. package/npm/check-skill-links.mjs +0 -88
  83. 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
- //! - start path 按 exact pane receipt 回收已 spawn pane;本文件恢复 spec/state,并删除新 Pi 席位的 exact wrapper
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
- // The MCP server already passes the canonical run workspace here.
285
- // Reapplying team_workspace() would strip the scratch root and bind
286
- // the first dynamic worker to the parent workspace's tmux server.
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
- workspace, team,
227
+ &run_workspace, team,
290
228
  )
291
- .unwrap_or_else(|_| crate::tmux_backend::TmuxBackend::for_workspace(workspace));
292
- return add_agent_with_transport_pi_preflight(
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 add_agent_with_pi_preflight(
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 add_agent_with_transport_pi_preflight(
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
- preflight_role_with_pi_model(
588
- run_workspace,
589
- team_dir,
590
- agent_id,
591
- role_file_path,
592
- discover,
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 match wrapper_rollback {
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
- "added_agent_noop",
726
+ "start_agent_noop",
913
727
  );
914
- let error = LifecycleError::RequirementUnmet(format!(
915
- "newly added agent {agent_id} returned start_agent.noop"
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
- let error =
936
- LifecycleError::RequirementUnmet(format!("added agent {agent_id} is paused"));
937
- return match wrapper_rollback {
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!({}));