@team-agent/installer 0.2.8 → 0.2.9
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/package.json
CHANGED
|
@@ -245,34 +245,51 @@ def adaptive_blocked(
|
|
|
245
245
|
return displays
|
|
246
246
|
|
|
247
247
|
|
|
248
|
-
def close_adaptive_display(state: dict[str, Any], event_log: EventLog) ->
|
|
248
|
+
def close_adaptive_display(state: dict[str, Any], event_log: EventLog) -> dict[str, Any]:
|
|
249
249
|
displays = [
|
|
250
250
|
(agent_id, agent_state.get("display") or {})
|
|
251
251
|
for agent_id, agent_state in state.get("agents", {}).items()
|
|
252
252
|
if (agent_state.get("display") or {}).get("backend") == "adaptive"
|
|
253
253
|
]
|
|
254
254
|
if not displays:
|
|
255
|
-
return
|
|
255
|
+
return {"windows": [], "linked_sessions": [], "orphans_detected": {}}
|
|
256
256
|
killed_windows: list[str] = []
|
|
257
257
|
linked_sessions: list[str] = []
|
|
258
|
+
session_name = str(state.get("session_name") or "")
|
|
259
|
+
leader_session = _adaptive_leader_session(state, displays)
|
|
260
|
+
needs_named_fallback = False
|
|
258
261
|
for _agent_id, display in displays:
|
|
259
262
|
linked = display.get("linked_session")
|
|
260
263
|
if linked:
|
|
261
264
|
linked_sessions.append(str(linked))
|
|
265
|
+
if not linked or not display.get("leader_session") or not (display.get("workspace_window") or display.get("window")):
|
|
266
|
+
needs_named_fallback = True
|
|
262
267
|
seen_targets: set[str] = set()
|
|
263
268
|
for _agent_id, display in displays:
|
|
264
|
-
|
|
269
|
+
display_leader_session = str(display.get("leader_session") or "")
|
|
265
270
|
window_name = str(display.get("workspace_window") or display.get("window") or "")
|
|
266
|
-
if not
|
|
271
|
+
if not display_leader_session or not window_name:
|
|
267
272
|
continue
|
|
268
|
-
target = f"{
|
|
273
|
+
target = f"{display_leader_session}:{window_name}"
|
|
269
274
|
if target in seen_targets:
|
|
270
275
|
continue
|
|
271
276
|
seen_targets.add(target)
|
|
272
277
|
if kill_adaptive_window(target):
|
|
273
278
|
killed_windows.append(target)
|
|
274
|
-
|
|
275
|
-
|
|
279
|
+
removed_orphans: dict[str, list[str]] = {}
|
|
280
|
+
if needs_named_fallback and leader_session and session_name:
|
|
281
|
+
named_windows = close_adaptive_windows(leader_session, session_name, event_log)
|
|
282
|
+
killed_windows.extend(named_windows)
|
|
283
|
+
linked_closed = kill_ghostty_workspace_linked_sessions(linked_sessions)
|
|
284
|
+
named_closed, named_failed = _kill_adaptive_named_display_sessions(session_name, [agent_id for agent_id, _display in displays])
|
|
285
|
+
linked_closed.extend(named_closed)
|
|
286
|
+
removed_orphans = _adaptive_orphan_summary(named_closed, named_windows)
|
|
287
|
+
else:
|
|
288
|
+
named_failed = []
|
|
289
|
+
linked_closed = kill_ghostty_workspace_linked_sessions(linked_sessions)
|
|
290
|
+
orphans = _adaptive_orphans(session_name, leader_session, [agent_id for agent_id, _display in displays], named_failed) if needs_named_fallback else {}
|
|
291
|
+
event_log.write("display.adaptive_closed", windows=killed_windows, linked_sessions=linked_closed, orphans_detected=orphans, orphans_removed=removed_orphans)
|
|
292
|
+
return {"windows": killed_windows, "linked_sessions": linked_closed, "orphans_detected": orphans, "orphans_removed": removed_orphans}
|
|
276
293
|
|
|
277
294
|
|
|
278
295
|
def close_adaptive_windows(leader_session: str, session_name: str, event_log: EventLog | None = None) -> list[str]:
|
|
@@ -293,6 +310,75 @@ def close_adaptive_windows(leader_session: str, session_name: str, event_log: Ev
|
|
|
293
310
|
return killed
|
|
294
311
|
|
|
295
312
|
|
|
313
|
+
def _adaptive_leader_session(state: dict[str, Any], displays: list[tuple[str, dict[str, Any]]]) -> str:
|
|
314
|
+
for _agent_id, display in displays:
|
|
315
|
+
if display.get("leader_session"):
|
|
316
|
+
return str(display["leader_session"])
|
|
317
|
+
receiver = state.get("leader_receiver") if isinstance(state.get("leader_receiver"), dict) else {}
|
|
318
|
+
return str(receiver.get("session_name") or "")
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _adaptive_named_display_sessions(session_name: str, agent_ids: list[str], fallback_exact: bool = True) -> list[str]:
|
|
322
|
+
from team_agent.runtime import run_cmd
|
|
323
|
+
if not session_name or not agent_ids:
|
|
324
|
+
return []
|
|
325
|
+
exact = [ghostty_display_session_name(session_name, agent_id) for agent_id in agent_ids]
|
|
326
|
+
proc = run_cmd(["tmux", "list-sessions", "-F", "#{session_name}"], timeout=10)
|
|
327
|
+
if proc.returncode != 0:
|
|
328
|
+
return exact if fallback_exact else []
|
|
329
|
+
prefixes = [ghostty_display_session_name(session_name, agent_id).rsplit("__", 1)[0] + "__" for agent_id in agent_ids]
|
|
330
|
+
matched = [name for name in proc.stdout.splitlines() if any(name.startswith(prefix) for prefix in prefixes)]
|
|
331
|
+
return matched or (exact if fallback_exact else [])
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _kill_adaptive_named_display_sessions(session_name: str, agent_ids: list[str]) -> tuple[list[str], list[str]]:
|
|
335
|
+
from team_agent.runtime import run_cmd
|
|
336
|
+
killed: list[str] = []
|
|
337
|
+
failed: list[str] = []
|
|
338
|
+
for display_session in _adaptive_named_display_sessions(session_name, agent_ids):
|
|
339
|
+
proc = run_cmd(["tmux", "kill-session", "-t", display_session], timeout=10)
|
|
340
|
+
if proc.returncode == 0:
|
|
341
|
+
killed.append(display_session)
|
|
342
|
+
else:
|
|
343
|
+
failed.append(display_session)
|
|
344
|
+
return killed, failed
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _adaptive_orphans(session_name: str, leader_session: str, agent_ids: list[str], failed_sessions: list[str]) -> dict[str, list[str]]:
|
|
348
|
+
display_sessions = sorted(set([*_adaptive_named_display_sessions(session_name, agent_ids, fallback_exact=False), *failed_sessions]))
|
|
349
|
+
windows: list[str] = []
|
|
350
|
+
if leader_session and session_name:
|
|
351
|
+
windows = _adaptive_window_orphans(leader_session, session_name)
|
|
352
|
+
if not display_sessions and not windows:
|
|
353
|
+
return {}
|
|
354
|
+
return {
|
|
355
|
+
"adaptive_display_sessions": sorted(set(display_sessions)),
|
|
356
|
+
"adaptive_overview_windows": sorted(set(windows)),
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _adaptive_orphan_summary(display_sessions: list[str], windows: list[str]) -> dict[str, list[str]]:
|
|
361
|
+
if not display_sessions and not windows:
|
|
362
|
+
return {}
|
|
363
|
+
return {
|
|
364
|
+
"adaptive_display_sessions": sorted(set(display_sessions)),
|
|
365
|
+
"adaptive_overview_windows": sorted(set(windows)),
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _adaptive_window_orphans(leader_session: str, session_name: str) -> list[str]:
|
|
370
|
+
from team_agent.runtime import run_cmd
|
|
371
|
+
prefix = f"team-agent:{session_name}:overview"
|
|
372
|
+
proc = run_cmd(["tmux", "list-windows", "-t", leader_session, "-F", "#{window_name}"], timeout=10)
|
|
373
|
+
if proc.returncode != 0:
|
|
374
|
+
return []
|
|
375
|
+
return [
|
|
376
|
+
f"{leader_session}:{window_name}"
|
|
377
|
+
for window_name in proc.stdout.splitlines()
|
|
378
|
+
if window_name == prefix or window_name.startswith(f"{prefix}-")
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
|
|
296
382
|
def kill_adaptive_window(target: str) -> bool:
|
|
297
383
|
from team_agent.runtime import run_cmd
|
|
298
384
|
proc = run_cmd(["tmux", "kill-window", "-t", target], timeout=10)
|
|
@@ -8,9 +8,10 @@ from team_agent.display.ghostty import ghostty_pids_by_title
|
|
|
8
8
|
from team_agent.display.workspace import kill_ghostty_workspace_linked_sessions
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def close_team_display_backends(state: dict[str, Any], event_log: EventLog) ->
|
|
12
|
-
close_adaptive_display(state, event_log)
|
|
11
|
+
def close_team_display_backends(state: dict[str, Any], event_log: EventLog) -> dict[str, Any]:
|
|
12
|
+
result = close_adaptive_display(state, event_log)
|
|
13
13
|
close_ghostty_workspace(state, event_log)
|
|
14
|
+
return result
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def close_ghostty_display(
|
|
@@ -527,7 +527,7 @@ def shutdown(workspace: Path, keep_logs: bool = True, team: str | None = None) -
|
|
|
527
527
|
if proc.returncode == 0:
|
|
528
528
|
log_path.write_text(proc.stdout, encoding="utf-8")
|
|
529
529
|
captured.append(str(log_path))
|
|
530
|
-
_close_team_display_backends(state, event_log)
|
|
530
|
+
display_cleanup = _close_team_display_backends(state, event_log)
|
|
531
531
|
for agent_id, agent_state in state.get("agents", {}).items():
|
|
532
532
|
_close_ghostty_display(agent_id, agent_state, event_log)
|
|
533
533
|
closed_displays.add(agent_id)
|
|
@@ -541,7 +541,7 @@ def shutdown(workspace: Path, keep_logs: bool = True, team: str | None = None) -
|
|
|
541
541
|
event_log.write("shutdown.kill_session", session=session_name, keep_logs=keep_logs, captured=captured)
|
|
542
542
|
else:
|
|
543
543
|
event_log.write("shutdown.idempotent", session=session_name, reason="session missing")
|
|
544
|
-
_close_team_display_backends(state, event_log)
|
|
544
|
+
display_cleanup = _close_team_display_backends(state, event_log)
|
|
545
545
|
for agent_id, agent_state in state.get("agents", {}).items():
|
|
546
546
|
if agent_id not in closed_displays:
|
|
547
547
|
_close_ghostty_display(agent_id, agent_state, event_log)
|
|
@@ -573,7 +573,7 @@ def shutdown(workspace: Path, keep_logs: bool = True, team: str | None = None) -
|
|
|
573
573
|
archive_path, teams_remaining, new_active = _commit_shutdown_cleanup(
|
|
574
574
|
workspace, str(resolved_team_id or ""), session_name, event_log
|
|
575
575
|
)
|
|
576
|
-
|
|
576
|
+
result = {
|
|
577
577
|
"ok": True,
|
|
578
578
|
"session_name": session_name,
|
|
579
579
|
"team": resolved_team_id,
|
|
@@ -584,6 +584,24 @@ def shutdown(workspace: Path, keep_logs: bool = True, team: str | None = None) -
|
|
|
584
584
|
"new_active_team_key": new_active,
|
|
585
585
|
"cleanup_mode": "synchronous_committed",
|
|
586
586
|
}
|
|
587
|
+
removed_orphans = (display_cleanup or {}).get("orphans_removed") or {}
|
|
588
|
+
remaining_orphans = (display_cleanup or {}).get("orphans_detected") or {}
|
|
589
|
+
if removed_orphans:
|
|
590
|
+
result["orphans_detected"] = removed_orphans
|
|
591
|
+
result["warnings"] = ["Adaptive display tmux objects were found and removed during shutdown cleanup."]
|
|
592
|
+
if remaining_orphans:
|
|
593
|
+
result["cleanup_mode"] = "synchronous_with_orphans"
|
|
594
|
+
result["orphans_detected"] = remaining_orphans
|
|
595
|
+
result["warning"] = "Adaptive display tmux objects remain after shutdown cleanup."
|
|
596
|
+
event_log.write(
|
|
597
|
+
"shutdown.orphans_detected",
|
|
598
|
+
warning=result["warning"],
|
|
599
|
+
message=result["warning"],
|
|
600
|
+
orphans_detected=remaining_orphans,
|
|
601
|
+
adaptive_display_sessions=remaining_orphans.get("adaptive_display_sessions", []),
|
|
602
|
+
adaptive_overview_windows=remaining_orphans.get("adaptive_overview_windows", []),
|
|
603
|
+
)
|
|
604
|
+
return result
|
|
587
605
|
|
|
588
606
|
|
|
589
607
|
def _commit_shutdown_cleanup(
|