@team-agent/installer 0.5.73 → 0.5.74
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 +19 -13
- package/crates/team-agent/src/cli/emit.rs +6 -3
- package/crates/team-agent/src/cli/mod.rs +151 -0
- package/crates/team-agent/src/cli/tests/leader_watch.rs +28 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +3 -0
- package/crates/team-agent/src/cli/types.rs +6 -0
- package/crates/team-agent/src/compiler.rs +14 -1
- package/crates/team-agent/src/leader/lease.rs +106 -21
- package/crates/team-agent/src/leader/registry.rs +0 -89
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +457 -73
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +16 -6
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +5 -3
- package/crates/team-agent/src/lifecycle/restart/common.rs +0 -11
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +60 -0
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +31 -0
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +25 -23
- package/crates/team-agent/src/messaging/delivery.rs +26 -8
- package/crates/team-agent/src/messaging/tests/runtime.rs +234 -0
- package/crates/team-agent/src/model/spec.rs +81 -7
- package/crates/team-agent/src/provider/adapters/pi.rs +14 -0
- package/crates/team-agent/src/state/persist.rs +272 -3
- package/crates/team-agent/src/state/repository.rs +9 -2
- package/crates/team-agent/src/tmux_backend/tests.rs +64 -0
- package/crates/team-agent/src/tmux_backend.rs +57 -0
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +3 -0
- package/skills/team-agent/command-coverage.json +21 -0
- package/skills/team-agent/references/team-agent-operator.md +9 -2
|
@@ -243,12 +243,6 @@ pub fn register_binding_from_state_best_effort(
|
|
|
243
243
|
);
|
|
244
244
|
let event_log = crate::event_log::EventLog::new(workspace);
|
|
245
245
|
let write_result = write_entry_best_effort(&entry);
|
|
246
|
-
// Fresh quick-start is acquisition-only: it must never displace another
|
|
247
|
-
// same-pane row. Its caller performs a validated-LIVE check before this
|
|
248
|
-
// write; manual/restart ownership paths keep existing behavior.
|
|
249
|
-
if write_result.is_some() && source != "quick-start" {
|
|
250
|
-
let _ = mark_displaced_same_pane_entries_unbound(&entry);
|
|
251
|
-
}
|
|
252
246
|
let status = if let Some(path) = &write_result {
|
|
253
247
|
let _ = event_log.write(
|
|
254
248
|
EVENT_REGISTERED,
|
|
@@ -281,68 +275,6 @@ pub fn register_binding_from_state_best_effort(
|
|
|
281
275
|
})
|
|
282
276
|
}
|
|
283
277
|
|
|
284
|
-
/// Stored registry status after another workspace claimed the same pane.
|
|
285
|
-
pub const REGISTRY_STATUS_UNBOUND: &str = "unbound";
|
|
286
|
-
|
|
287
|
-
/// When workspace B claims a pane, every other attached registry row that
|
|
288
|
-
/// still names that pane is no longer deliverable. Mark those rows unbound.
|
|
289
|
-
/// Does not change pane-side authorization storage.
|
|
290
|
-
pub fn mark_displaced_same_pane_entries_unbound(winner: &LeaderRegistryEntry) -> Vec<PathBuf> {
|
|
291
|
-
let Some(winner_pane) = winner
|
|
292
|
-
.channel
|
|
293
|
-
.get("pane_id")
|
|
294
|
-
.and_then(Value::as_str)
|
|
295
|
-
.filter(|pane| !pane.is_empty())
|
|
296
|
-
else {
|
|
297
|
-
return Vec::new();
|
|
298
|
-
};
|
|
299
|
-
let winner_socket = winner
|
|
300
|
-
.channel
|
|
301
|
-
.get("tmux_socket")
|
|
302
|
-
.and_then(Value::as_str)
|
|
303
|
-
.filter(|socket| !socket.is_empty());
|
|
304
|
-
let mut displaced = Vec::new();
|
|
305
|
-
for (path, mut entry) in read_all_entries() {
|
|
306
|
-
if entry.workspace_hash == winner.workspace_hash && entry.team_key == winner.team_key {
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
if entry.status != "attached" {
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
let Some(pane) = entry
|
|
313
|
-
.channel
|
|
314
|
-
.get("pane_id")
|
|
315
|
-
.and_then(Value::as_str)
|
|
316
|
-
.filter(|pane| !pane.is_empty())
|
|
317
|
-
else {
|
|
318
|
-
continue;
|
|
319
|
-
};
|
|
320
|
-
if pane != winner_pane {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
let Some(socket) = entry
|
|
324
|
-
.channel
|
|
325
|
-
.get("tmux_socket")
|
|
326
|
-
.and_then(Value::as_str)
|
|
327
|
-
.filter(|socket| !socket.is_empty())
|
|
328
|
-
else {
|
|
329
|
-
continue;
|
|
330
|
-
};
|
|
331
|
-
let Some(winner_socket) = winner_socket else {
|
|
332
|
-
continue;
|
|
333
|
-
};
|
|
334
|
-
if socket != winner_socket {
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
entry.status = REGISTRY_STATUS_UNBOUND.to_string();
|
|
338
|
-
entry.updated_at = chrono::Utc::now().to_rfc3339();
|
|
339
|
-
if write_entry_best_effort(&entry).is_some() {
|
|
340
|
-
displaced.push(path);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
displaced
|
|
344
|
-
}
|
|
345
|
-
|
|
346
278
|
fn entry_filename(entry: &LeaderRegistryEntry) -> String {
|
|
347
279
|
format!("{}__{}.json", entry.workspace_hash, entry.team_key)
|
|
348
280
|
}
|
|
@@ -546,27 +478,6 @@ pub fn list_validated_with_gc() -> Vec<(LeaderRegistryEntry, &'static str, Optio
|
|
|
546
478
|
out
|
|
547
479
|
}
|
|
548
480
|
|
|
549
|
-
/// Refuse a fresh quick-start binding when the caller pane already backs a
|
|
550
|
-
/// canonically LIVE receiver for another workspace/team. This is read-only:
|
|
551
|
-
/// quick-start never displaces or takes over an existing binding.
|
|
552
|
-
#[must_use]
|
|
553
|
-
pub(crate) fn live_same_pane_binding_elsewhere(
|
|
554
|
-
pane_id: &str,
|
|
555
|
-
workspace: &Path,
|
|
556
|
-
team_key: &str,
|
|
557
|
-
) -> bool {
|
|
558
|
-
let workspace = std::fs::canonicalize(workspace).unwrap_or_else(|_| workspace.to_path_buf());
|
|
559
|
-
list_validated_no_gc().into_iter().any(|(entry, status, _)| {
|
|
560
|
-
status == "LIVE"
|
|
561
|
-
&& entry
|
|
562
|
-
.channel
|
|
563
|
-
.get("pane_id")
|
|
564
|
-
.and_then(Value::as_str)
|
|
565
|
-
== Some(pane_id)
|
|
566
|
-
&& (entry.workspace != workspace || entry.team_key != team_key)
|
|
567
|
-
})
|
|
568
|
-
}
|
|
569
|
-
|
|
570
481
|
/// Same as `list_validated_with_gc` but preserves all entries. `send
|
|
571
482
|
/// --to-leader` needs to see stale entries so it can refuse with
|
|
572
483
|
/// `registry_stale` (and never silently fall through to
|