agent-dag 1.35.20 → 1.35.21
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/bin/deck.js
CHANGED
|
@@ -9,8 +9,8 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
10
|
import { dieOfSignal } from "../src/server/supervisor.mjs";
|
|
11
11
|
import {
|
|
12
|
-
CURSOR_HIDE, CURSOR_SHOW, colorProfile, fit, glyphs, labelColumn, link, motionOK,
|
|
13
|
-
pulseText, spinnerFrames, statusLine, supportsHyperlinks, termColumns, unicodeOK,
|
|
12
|
+
CURSOR_HIDE, CURSOR_SHOW, colorProfile, fit, glyphs, labelColumn, link, motionOK, oneLine,
|
|
13
|
+
palette, pulseText, spinnerFrames, statusLine, supportsHyperlinks, termColumns, unicodeOK,
|
|
14
14
|
unregisteredDetail, wordmark,
|
|
15
15
|
} from "../src/server/term.mjs";
|
|
16
16
|
import { PRODUCT } from "../src/server/brand.mjs";
|
|
@@ -101,7 +101,7 @@ const { installHooks, keepDiscovery, removeDiscovery, hasCodexInstalled } =
|
|
|
101
101
|
// the watcher tails, and the watcher lives in that module. Recomputing the path
|
|
102
102
|
// here is how the banner came to print ~/.codex/sessions on machines whose
|
|
103
103
|
// sessions are somewhere else entirely — see the row further down.
|
|
104
|
-
const { startServer, hookToken, releaseRestart, CODEX_SESSIONS_DIR, canonicalWorkspace } =
|
|
104
|
+
const { startServer, hookToken, releaseRestart, markDeckReady, CODEX_SESSIONS_DIR, canonicalWorkspace } =
|
|
105
105
|
await import(pathToFileURL(join(PKG_ROOT, "src/server/index.mjs")).href);
|
|
106
106
|
|
|
107
107
|
// Resolved here rather than left as typed, for the reason the events log above
|
|
@@ -445,32 +445,116 @@ let restarting = false;
|
|
|
445
445
|
const UPGRADE_ANSWER_MS = 150_000;
|
|
446
446
|
let upgradeTimer = null;
|
|
447
447
|
|
|
448
|
+
// Whether the rest of this file has finished running.
|
|
449
|
+
//
|
|
450
|
+
// The server below starts accepting connections from inside startServer, before
|
|
451
|
+
// that call has returned — so /api/restart is reachable for the whole of the
|
|
452
|
+
// boot that follows it: the port report to the supervisor, the discovery file
|
|
453
|
+
// and its first fsynced write, and on a cold start the browser spawn. A restart
|
|
454
|
+
// landing in that window used to reach `shutdown` before the binding holding it
|
|
455
|
+
// was initialised and die of a ReferenceError, having already set the latch
|
|
456
|
+
// above, with nothing left to clear it — after which every restart from every
|
|
457
|
+
// tab was answered "ok" and did nothing, for the life of the process (#448).
|
|
458
|
+
//
|
|
459
|
+
// So an ask that arrives too early is held rather than run: the window is
|
|
460
|
+
// bounded and short, the user asked for something this deck can genuinely give
|
|
461
|
+
// a second later, and refusing outright would put back the same silence in a
|
|
462
|
+
// politer form. BOOT_RESTART_MS is the outer bound, for the reason
|
|
463
|
+
// UPGRADE_ANSWER_MS above is one: a boot that has not finished in ten seconds is
|
|
464
|
+
// itself the fault, and the restart is the answer to it rather than a casualty
|
|
465
|
+
// of it.
|
|
466
|
+
let booted = false;
|
|
467
|
+
let heldRestart = null;
|
|
468
|
+
let bootTimer = null;
|
|
469
|
+
const BOOT_RESTART_MS = 10_000;
|
|
470
|
+
|
|
448
471
|
const requestRestart = (mode) => {
|
|
449
472
|
if (restarting) return;
|
|
450
473
|
restarting = true;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
upgradeTimer = setTimeout(() => abandonUpgrade("no answer from the supervisor"), UPGRADE_ANSWER_MS);
|
|
461
|
-
upgradeTimer.unref?.();
|
|
462
|
-
// Armed before the ask, not after: a send that throws is a supervisor that
|
|
463
|
-
// can no longer answer, and the deck has to come back out of the latch on
|
|
464
|
-
// its own rather than wait out an answer that cannot arrive.
|
|
465
|
-
try { process.send({ type: "upgrade" }); }
|
|
466
|
-
catch (err) { abandonUpgrade(err?.message ?? "the supervisor is no longer listening"); }
|
|
474
|
+
if (!booted) {
|
|
475
|
+
heldRestart = { mode };
|
|
476
|
+
bootTimer = setTimeout(() => { bootTimer = null; runHeldRestart(); }, BOOT_RESTART_MS);
|
|
477
|
+
bootTimer.unref?.();
|
|
478
|
+
// Said out loud for the same reason abandonUpgrade below is: the tab has
|
|
479
|
+
// already been told its restart was accepted, and a second of nothing
|
|
480
|
+
// happening on this terminal is otherwise indistinguishable from the bug
|
|
481
|
+
// this replaces.
|
|
482
|
+
write(`\n ${P.warn}${G.restart}${P.reset} ${P.muted}restart queued ${G.dash} still starting up${P.reset}\n`);
|
|
467
483
|
return;
|
|
468
484
|
}
|
|
469
|
-
|
|
470
|
-
write(`\n ${P.warn}${G.restart}${P.reset} ${P.muted}restarting${to ? ` ${G.arrow} v${to}` : ""}${G.ellipsis}${P.reset}\n`);
|
|
471
|
-
shutdown(RESTART_CODE);
|
|
485
|
+
beginRestart(mode);
|
|
472
486
|
};
|
|
473
487
|
|
|
488
|
+
// The restart itself, once there is a booted deck to end. Split out of
|
|
489
|
+
// requestRestart so the held ask above can re-enter it without tripping the
|
|
490
|
+
// latch it is already holding.
|
|
491
|
+
//
|
|
492
|
+
// Everything here runs inside one try: the whole point of #448 is that a throw
|
|
493
|
+
// on this path is not merely a failed restart but a permanent one, because the
|
|
494
|
+
// latch it leaves behind outlives it. There is no line in here worth dying for.
|
|
495
|
+
function beginRestart(mode) {
|
|
496
|
+
try {
|
|
497
|
+
// "npx" means the newer code is not on this disk at all, so it has to be
|
|
498
|
+
// fetched — and this process keeps serving while that happens. Exiting first
|
|
499
|
+
// is what made every failed upgrade an outage: the SSE stream dropped, hook
|
|
500
|
+
// events fired into the gap were lost outright (hook/hook.js is
|
|
501
|
+
// fire-and-forget with a 1s timeout and no retry), and the canvas came back
|
|
502
|
+
// with whatever was in flight stuck until the stale sweeper reaped it — all
|
|
503
|
+
// of it paid before anyone knew whether npm could even resolve the version.
|
|
504
|
+
// Nothing is torn down here now; the supervisor answers when it knows.
|
|
505
|
+
if (mode === "npx") {
|
|
506
|
+
upgradeTimer = setTimeout(() => abandonUpgrade("no answer from the supervisor"), UPGRADE_ANSWER_MS);
|
|
507
|
+
upgradeTimer.unref?.();
|
|
508
|
+
// Armed before the ask, not after: a send that throws is a supervisor that
|
|
509
|
+
// can no longer answer, and the deck has to come back out of the latch on
|
|
510
|
+
// its own rather than wait out an answer that cannot arrive.
|
|
511
|
+
try { process.send({ type: "upgrade" }); }
|
|
512
|
+
catch (err) { abandonUpgrade(err?.message ?? "the supervisor is no longer listening"); }
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const to = restartTarget();
|
|
516
|
+
write(`\n ${P.warn}${G.restart}${P.reset} ${P.muted}restarting${to ? ` ${G.arrow} v${to}` : ""}${G.ellipsis}${P.reset}\n`);
|
|
517
|
+
shutdown(RESTART_CODE);
|
|
518
|
+
} catch (err) {
|
|
519
|
+
abandonRestart(err);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// The ask that was waiting for the boot to finish, now that it has. Safe to
|
|
524
|
+
// call when nothing is waiting, which is every ordinary boot.
|
|
525
|
+
function runHeldRestart() {
|
|
526
|
+
if (!heldRestart) return;
|
|
527
|
+
const { mode } = heldRestart;
|
|
528
|
+
heldRestart = null;
|
|
529
|
+
clearTimeout(bootTimer);
|
|
530
|
+
bootTimer = null;
|
|
531
|
+
beginRestart(mode);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// A restart that could not be started, said out loud and then let go of.
|
|
535
|
+
//
|
|
536
|
+
// Both halves of the latch have to come down — this file's and the server's —
|
|
537
|
+
// because a latch nothing clears is precisely how one failed request turned
|
|
538
|
+
// into a deck that refused every restart afterwards while answering "ok" to
|
|
539
|
+
// each one (#448). The reason is folded onto one line by oneLine: the terminal
|
|
540
|
+
// under this is repainted every 800ms by the pulse, and a stack written into
|
|
541
|
+
// that is a stack nobody can read (#432).
|
|
542
|
+
//
|
|
543
|
+
// A declaration rather than a const, like `shutdown` below and for the same
|
|
544
|
+
// reason: this is the handler for a binding that was not there yet, and it must
|
|
545
|
+
// not be capable of becoming the next one.
|
|
546
|
+
function abandonRestart(err) {
|
|
547
|
+
clearTimeout(bootTimer);
|
|
548
|
+
bootTimer = null;
|
|
549
|
+
heldRestart = null;
|
|
550
|
+
restarting = false;
|
|
551
|
+
releaseRestart();
|
|
552
|
+
write(
|
|
553
|
+
`\n ${P.err}${G.fail}${P.reset} ${P.muted}restart failed ${G.dash} still on ${P.reset}v${PKG_VERSION}\n` +
|
|
554
|
+
` ${P.muted}${oneLine(err?.stack ?? err, Math.max(20, cols() - 6), G.ellipsis)}${P.reset}\n`,
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
474
558
|
// The upgrade did not happen and this deck is still the deck. Said out loud
|
|
475
559
|
// because the terminal has just printed that a fetch was starting, and left
|
|
476
560
|
// unsaid it reads as a restart that hung.
|
|
@@ -508,13 +592,24 @@ function restartTarget() {
|
|
|
508
592
|
catch { return null; }
|
|
509
593
|
}
|
|
510
594
|
|
|
595
|
+
// The three things `shutdown` has to tear down, named before the boot that
|
|
596
|
+
// fills them in rather than by it. From the line below onwards this process is
|
|
597
|
+
// answering HTTP, and /api/restart can therefore reach `shutdown` at any moment
|
|
598
|
+
// after it — including moments at which none of these exist yet. `let … = null`
|
|
599
|
+
// is what makes that a question shutdown can ask instead of a ReferenceError it
|
|
600
|
+
// dies of; the boot queue in requestRestart is what makes it a question it
|
|
601
|
+
// almost never has to ask. See #448.
|
|
602
|
+
let server = null;
|
|
603
|
+
let discovery = null;
|
|
604
|
+
let discoveryFile = null;
|
|
605
|
+
|
|
511
606
|
const starting = startServer({
|
|
512
607
|
port, persist, workspace, codex: wantCodex, claude: wantClaude,
|
|
513
608
|
// Withheld when nothing is supervising us: without a parent, exiting is just
|
|
514
609
|
// exiting, and /api/restart answers 501 so the UI hides the control.
|
|
515
610
|
onRestart: SUPERVISED ? requestRestart : null,
|
|
516
611
|
});
|
|
517
|
-
|
|
612
|
+
server = await (RESPAWN ? starting : step(`starting server${G.ellipsis}`, starting)).catch(err => {
|
|
518
613
|
// stderr, not a row: a deck that could not bind is not a status line, and
|
|
519
614
|
// whatever launched it reads this stream.
|
|
520
615
|
console.error(`${PRODUCT}: server failed: ${err.message}`);
|
|
@@ -564,7 +659,7 @@ if (RESPAWN) {
|
|
|
564
659
|
// rollout files this deck tails itself, which a --no-codex deck must never be
|
|
565
660
|
// elected to record. See writesCodexLog in src/server/log-writer.mjs.
|
|
566
661
|
let registered = null;
|
|
567
|
-
|
|
662
|
+
discovery = keepDiscovery({
|
|
568
663
|
port: realPort,
|
|
569
664
|
workspace,
|
|
570
665
|
token: hookToken(),
|
|
@@ -577,7 +672,7 @@ const discovery = keepDiscovery({
|
|
|
577
672
|
else if (!first) reportReregistered(state);
|
|
578
673
|
},
|
|
579
674
|
});
|
|
580
|
-
|
|
675
|
+
discoveryFile = discovery.file;
|
|
581
676
|
// Now, not in five seconds: nothing should reach the pulse line below without
|
|
582
677
|
// the deck knowing whether the hooks can see it.
|
|
583
678
|
await discovery.check();
|
|
@@ -612,33 +707,78 @@ if (MOTION) {
|
|
|
612
707
|
}, 800).unref();
|
|
613
708
|
}
|
|
614
709
|
|
|
615
|
-
|
|
710
|
+
// Boot is over. Everything `shutdown` tears down exists, so a restart can be
|
|
711
|
+
// run rather than held — and the server is told, so /api/restart stops
|
|
712
|
+
// describing a deck that is still assembling itself. This line is exactly where
|
|
713
|
+
// the window opened at the top of this file closes; see requestRestart.
|
|
714
|
+
booted = true;
|
|
715
|
+
markDeckReady();
|
|
716
|
+
runHeldRestart();
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* A declaration, not the `const` arrow this was for eight months.
|
|
720
|
+
*
|
|
721
|
+
* The difference is the whole of #448: a const is in its temporal dead zone
|
|
722
|
+
* until the line declaring it runs, and every line above — the port report, the
|
|
723
|
+
* discovery file, the browser spawn — executes with the server already
|
|
724
|
+
* accepting connections. A restart arriving in that window called this and got
|
|
725
|
+
* `ReferenceError: Cannot access 'shutdown' before initialization`, and the
|
|
726
|
+
* latch it had already set is what made that permanent. A declaration is
|
|
727
|
+
* hoisted, so from the first instruction of this module there is a function
|
|
728
|
+
* here to call.
|
|
729
|
+
*
|
|
730
|
+
* Hoisting alone would only have moved the fault one line down, onto `server`,
|
|
731
|
+
* `discovery` and `discoveryFile` — which is why those are `let … = null` above
|
|
732
|
+
* and asked about rather than assumed here. Between them, this is callable at
|
|
733
|
+
* any instant of this process's life and cannot end in a throw for the caller
|
|
734
|
+
* to lose.
|
|
735
|
+
*/
|
|
736
|
+
async function shutdown(code = 0) {
|
|
616
737
|
// Also set as exitCode, not only passed to exit(): if the event loop empties
|
|
617
738
|
// on its own before either timer runs, Node would otherwise exit 0 and the
|
|
618
739
|
// supervisor would take that as "done" instead of "bring me back".
|
|
619
740
|
process.exitCode = code;
|
|
620
|
-
//
|
|
621
|
-
//
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
741
|
+
// Nothing inside a shutdown is worth staying alive for, and this one is
|
|
742
|
+
// called from three places that cannot handle a rejection — a signal handler,
|
|
743
|
+
// an IPC message handler, and a restart. An unhandled one there ends the
|
|
744
|
+
// process on Node's terms rather than ours, which is to say with the wrong
|
|
745
|
+
// exit code and therefore, half the time, without the supervisor bringing the
|
|
746
|
+
// deck back.
|
|
747
|
+
try {
|
|
748
|
+
// Before anything that can take time: a Ctrl+C the user has to watch for a
|
|
749
|
+
// second and a half is a second and a half without a cursor.
|
|
750
|
+
showCursor();
|
|
751
|
+
if (tty && code !== RESTART_CODE && code !== UPGRADE_CODE) {
|
|
752
|
+
write(`\n\n ${P.warn}${G.stop} shutting down${G.ellipsis}${P.reset}\n`);
|
|
753
|
+
}
|
|
754
|
+
// Stopped first, always: a tick landing after the unlink would re-register a
|
|
755
|
+
// deck that is on its way out, and leave the file behind for the hooks to
|
|
756
|
+
// find once nothing is listening.
|
|
757
|
+
//
|
|
758
|
+
// Guarded on its own, because a discovery file this process cannot remove is
|
|
759
|
+
// a nuisance the next boot's stale sweep clears up — worth carrying on to
|
|
760
|
+
// the orderly close below rather than skipping to the abrupt one.
|
|
761
|
+
try {
|
|
762
|
+
discovery?.stop();
|
|
763
|
+
if (discoveryFile) await removeDiscovery(discoveryFile);
|
|
764
|
+
} catch { /* the sweep at the next boot gets it */ }
|
|
765
|
+
// No server yet means nothing to drain and nothing to hand the port over to,
|
|
766
|
+
// so the exit is the whole of the shutdown.
|
|
767
|
+
if (!server) return process.exit(code);
|
|
768
|
+
server.close(() => process.exit(code));
|
|
769
|
+
// SSE connections never end by themselves, so close() alone would sit out the
|
|
770
|
+
// full 1500ms fallback on every restart. Hanging them up is safe — the stream
|
|
771
|
+
// sets retry: 1500 and replays from Last-Event-ID, so each tab reconnects and
|
|
772
|
+
// catches up without being told anything.
|
|
773
|
+
try { server.closeAllConnections?.(); } catch { /* Node < 18.2 */ }
|
|
774
|
+
setTimeout(() => process.exit(code), 1500).unref();
|
|
775
|
+
} catch {
|
|
776
|
+
process.exit(code);
|
|
625
777
|
}
|
|
626
|
-
|
|
627
|
-
// deck that is on its way out, and leave the file behind for the hooks to
|
|
628
|
-
// find once nothing is listening.
|
|
629
|
-
discovery.stop();
|
|
630
|
-
await removeDiscovery(discoveryFile);
|
|
631
|
-
server.close(() => process.exit(code));
|
|
632
|
-
// SSE connections never end by themselves, so close() alone would sit out the
|
|
633
|
-
// full 1500ms fallback on every restart. Hanging them up is safe — the stream
|
|
634
|
-
// sets retry: 1500 and replays from Last-Event-ID, so each tab reconnects and
|
|
635
|
-
// catches up without being told anything.
|
|
636
|
-
try { server.closeAllConnections?.(); } catch { /* Node < 18.2 */ }
|
|
637
|
-
setTimeout(() => process.exit(code), 1500).unref();
|
|
638
|
-
};
|
|
778
|
+
}
|
|
639
779
|
process.on("SIGINT", () => shutdown(0));
|
|
640
780
|
process.on("SIGTERM", () => shutdown(0));
|
|
641
|
-
process.on("beforeExit", () => { discovery
|
|
781
|
+
process.on("beforeExit", () => { discovery?.stop(); if (discoveryFile) removeDiscovery(discoveryFile); });
|
|
642
782
|
|
|
643
783
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
644
784
|
|
|
@@ -69,7 +69,7 @@ Claude Code turns only. The sound is a Stop hook Claude Code runs itself when a
|
|
|
69
69
|
|
|
70
70
|
${n.clash} sound hook${n.clash>1?"s":""} of your own in settings.json also run${n.clash>1?"":"s"} here.`:"",l=n.parked>0?`
|
|
71
71
|
|
|
72
|
-
${n.parked} of your own sound hook${n.parked>1?"s were":" was"} set aside so this switch actually controls the sound. Nothing was deleted — shift-click to put ${n.parked>1?"them":"it"} back.`:"";return r+i+o+l}function LT(e){const n=Math.max(0,Math.floor(e));return`${n} event${n===1?"":"s"}`}function b5(e){return e.connected?e.paused?{tone:"paused",label:"paused",title:e.held>0?`Connected — ${LT(e.held)} held until you resume (Space)`:"Connected — updates held until you resume (Space)"}:{tone:"live",label:"live",title:"Receiving events"}:{tone:"dead",label:"offline",title:e.paused?"SSE disconnected — and the canvas is paused, so resuming will not bring events back until it reconnects":"SSE disconnected"}}function S5(e){return e.paused?e.held<=0?{label:"Resume",title:"Nothing has arrived since you paused. Resume to follow the canvas again (Space)"}:{label:`Resume · ${e.held} held`,title:`${LT(e.held)} arrived while paused and will be applied in order when you resume (Space)`}:{label:"Pause",title:"Pause live updates — events keep arriving and are applied when you resume (Space)"}}function $T(e,n){return e!==""&&n>0}function k5(e,n,r){return e===""?{active:!1,matched:n,total:r,count:null,empty:!1,message:null,dim:!1}:{active:!0,matched:n,total:r,count:`${n} of ${r}`,empty:n===0,message:n===0?`No agents match “${e}”`:null,dim:$T(e,n)}}const E5="Search agents, tools, model…";function qT(e,n){var i,o,l,u;if(!n)return!0;const r=n.toLowerCase();if(e.label.toLowerCase().includes(r)||(i=e.cwd)!=null&&i.toLowerCase().includes(r)||(o=e.cwdBasename)!=null&&o.toLowerCase().includes(r)||e.sessionId.toLowerCase().includes(r)||(l=e.firstPrompt)!=null&&l.toLowerCase().includes(r)||e.model&&(e.model.toLowerCase().includes(r)||js(e.model).toLowerCase().includes(r))||(u=e.provider)!=null&&u.toLowerCase().startsWith(r))return!0;for(const c of e.tools)if(c.name.toLowerCase().includes(r))return!0;return!1}function Pv(e){const n=Math.max(0,Math.floor(e/1e3));return n<60?"just now":n<3600?`${Math.floor(n/60)}m ago`:n<86400?`${Math.floor(n/3600)}h ago`:`${Math.floor(n/86400)}d ago`}function N5(e,n){return e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()&&e.getDate()===n.getDate()}function C5(e,n,r){const i=new Date(e),o=Pv(n-e);return{label:N5(i,new Date(n))?o:`${o} · ${i.toLocaleDateString(r,{month:"short",day:"numeric"})}`,title:i.toLocaleString(r,{dateStyle:"medium",timeStyle:"medium"})}}function ua(e){return typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue(e).trim()||""}const T5={agent:QP,sessionGroup:dL},DT="react-flow__node";function OE(e){var n,r;return!!e&&((r=(n=e.classList)==null?void 0:n.contains)==null?void 0:r.call(n,DT))===!0}function R5(e){try{const n=document.querySelector(`.${DT}[data-id="${CSS.escape(e)}"]`);n==null||n.focus({preventScroll:!0})}catch{}}const j5=["a[href]","button:not(:disabled)","input:not(:disabled)","select:not(:disabled)","textarea:not(:disabled)","summary","[tabindex]"].join(","),A5=420,au=18,I5=200,M5=5*6e4,O5=6,P5=2*6e4,ky="agent-dag.layout",Ey="agent-dag.viewport",FT="agent-dag.summariesDismissed",zT="agent-dag.sessionListOpen",BT="agent-dag.detailOpen",UT="agent-dag.usagePanelOpen",PE="agent-dag.accountsPanelOpen",LE="agent-dag.versionNoticeDismissed",$E="agent-dag.oldNameNoticeDismissed",L5=15*6e4,qE={git_checkout:"this deck runs from a git checkout — pull instead:",npx:"npx runs from a cache that cannot be upgraded in place — run:",not_writable:"the install directory is not writable by this user — run:",opted_out:"installs are off (AGENTS_DECK_NO_INSTALL=1) — run:"},DE="agent-dag.autoRestart",FE="agent-dag.bundleReloadedFor";function $5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(zT)==="1"}catch{return!1}}function q5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(zT,e?"1":"0")}catch{}}function D5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(BT)==="1"}catch{return!1}}function F5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(BT,e?"1":"0")}catch{}}function z5(){const e=MC(UT);return e===null?!0:e==="1"}function B5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(UT,e?"1":"0")}catch{}}function U5(){if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(FT);if(!e)return new Set;const n=JSON.parse(e);return new Set(Array.isArray(n)?n.filter(r=>typeof r=="string"):[])}catch{return new Set}}function zE(e){if(!(typeof window>"u"))try{const n=Array.from(e),r=n.length>200?n.slice(-200):n;window.localStorage.setItem(FT,JSON.stringify(r))}catch{}}function H5(){const e={positions:[],pins:[]};if(typeof window>"u")return e;try{const n=window.localStorage.getItem(ky);if(!n)return e;const r=JSON.parse(n);if(!("v"in r)){const o=Object.entries(r).filter(([,l])=>l&&typeof l.x=="number"&&typeof l.y=="number");return{positions:o,pins:o.map(([l])=>l)}}return{positions:Object.entries(r.positions??{}).filter(([,o])=>o&&typeof o.x=="number"&&typeof o.y=="number"),pins:Array.isArray(r.pins)?r.pins:[]}}catch{return e}}function dv(e,n){if(!(typeof window>"u"))try{const r={};for(const[i,o]of e)r[i]=o;for(const[i,o]of n)r[i]=o;window.localStorage.setItem(ky,JSON.stringify({v:2,positions:r,pins:Array.from(n.keys())}))}catch{}}function W5(){if(typeof window>"u")return null;try{const e=window.localStorage.getItem(Ey);if(!e)return null;const n=JSON.parse(e);return typeof(n==null?void 0:n.x)!="number"||typeof(n==null?void 0:n.y)!="number"||typeof(n==null?void 0:n.zoom)!="number"?null:n}catch{return null}}function V5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(Ey,JSON.stringify(e))}catch{}}function BE(){if(!(typeof window>"u")){try{window.localStorage.removeItem(ky)}catch{}try{window.localStorage.removeItem(Ey)}catch{}}}function G5(e,n){const r=e.agents.get(n);if(!r)return;const i=[];for(const d of e.agents.values())d.sessionId===n&&i.push(d);const o={schemaVersion:1,exportedAt:new Date().toISOString(),sessionId:n,label:r.label,cwd:r.cwd,startedAt:r.startedAt,endedAt:r.endedAt,model:r.model,agents:i.map(d=>({id:d.id,kind:d.kind,label:d.label,parentId:d.parentId,state:d.state,startedAt:d.startedAt,endedAt:d.endedAt,model:d.model,cwd:d.cwd,usage:d.usage,prompts:d.prompts,tools:d.tools.map(m=>({id:m.id,name:m.name,inputPreview:m.inputPreview,startedAt:m.startedAt,endedAt:m.endedAt,ok:m.ok,errorPreview:m.errorPreview,usage:m.usage}))}))},l=JSON.stringify(o,null,2),u=new Blob([l],{type:"application/json"}),c=URL.createObjectURL(u),h=document.createElement("a"),p=(r.label||"session").replace(/[^a-z0-9._-]/gi,"_");h.href=c,h.download=`${en}-${p}-${n.slice(0,8)}.json`,document.body.appendChild(h),h.click(),document.body.removeChild(h),setTimeout(()=>URL.revokeObjectURL(c),1e3)}const Lv={file:"📁",shell:"⚡",web:"🌐",agent:"🤖",task:"📋",plan:"🧭",mcp:"🔌",other:"✨"},$v={file:"file",shell:"shell",web:"web",agent:"agent",task:"task",plan:"plan",mcp:"mcp",other:"other"},HT=kC;function Y5(e,n){if(!n)return null;const r=new Set([n]);let i=n;for(;i;){const l=e.agents.get(i);if(!(l!=null&&l.parentId)||r.has(l.parentId))break;r.add(l.parentId),i=l.parentId}let o=!0;for(;o;){o=!1;for(const l of e.agents.values())l.parentId&&r.has(l.parentId)&&!r.has(l.id)&&(r.add(l.id),o=!0)}return r}function K5(e,n,r,i,o,l,u,c,h,p,d,m,y,w,N,_,b,S,k){const E=[],T=[],I=new Set;if(l)for(const B of e.agents.values())S.has(B.id)&&qT(B,l)&&I.add(B.id);const O=$T(l,I.size);for(const B of e.agents.values()){if(!S.has(B.id))continue;const C=O&&!I.has(B.id),q=B.exitAt!=null,L=b!=null&&!b.has(B.id),re=[C?"rf-dim":"",q?"rf-exiting":"",L?"rf-spotlit-out":""].filter(Boolean).join(" ")||void 0,J=u.get(B.id);if(E.push({id:B.id,type:"agent",position:{x:0,y:0},data:{...B,now:n,onOpenContext:k},className:re,...J?{width:J.width,height:J.height}:null}),B.parentId&&S.has(B.parentId)){const W=ny(B.sessionId),Z=l&&!I.has(B.id)&&!I.has(B.parentId),M=q,G=_.size>0&&(_.has(B.id)||_.has(B.parentId)),K=b!=null&&!b.has(B.id)&&!b.has(B.parentId),$=B.state==="active"?2:1.5,Q=G?$+1.5:$,ne=Z||M?.2:K?.12:1,ae=["sess-edge",B.state==="active"?"sess-live":"sess-idle",M?"rf-edge-exiting":"",G?"rf-edge-selected":""].filter(Boolean).join(" ");T.push({id:`e:${B.parentId}->${B.id}`,source:B.parentId,target:B.id,animated:(B.state==="active"||G)&&!Z&&!M,type:"smoothstep",style:{"--session-hue":W,strokeWidth:Q,opacity:ne,transition:"var(--edge-transition)"},className:ae})}}const A=new Map;for(const B of e.agents.values())B.tools.length>0&&A.set(B.id,Math.min(4,B.tools.length));const U=`${w}#lanes:${J4(A)}`,z=E.filter(B=>c$(B.id,o,m,y));if(z.length>0||U!==N.current){if(z.length>0){const B=t5(E,T,{direction:"LR",pinned:o,measured:u,availableWidth:r,availableHeight:i,lanes:A});for(const C of B)IC(C.id,m,y)&&f$(C.id,C.position,m,y);r5(E,m,o,u,new Set(z.map(C=>C.id)),A)}n5(E,m,o,u,A),N.current=U}const P=s5(E,m,o,u,c,!p||d,A);P.length>0&&h(P),ru(m,e.agents),ru(y,e.agents),ru(o,e.agents),ru(u,u$(e.agents.values()));const D=[];let V=!1;for(const B of E){let C=o.get(B.id)??m.get(B.id);C||(C=d$(B.id,m,y),V=!0),D.push({...B,position:C})}return V&&(N.current=""),{nodes:D,edges:T}}function X5(){return g.jsx(ty,{children:g.jsx(Q5,{})})}function Q5(){var Va,Ga,Ya,Ka;const e=ja(),n=j.useRef(Tv()),[,r]=j.useState(0),i=j.useCallback(()=>r(H=>H+1),[]),[o,l]=j.useState(()=>new Set),[u,c]=j.useState(null),[h,p]=j.useState(null),d=j.useCallback((H,Y)=>{l(oe=>{if(!Y)return new Set([H]);const de=new Set(oe);return de.has(H)?de.delete(H):de.add(H),de}),c(oe=>Y&&oe===H?oe:H)},[]),m=j.useCallback(()=>{l(new Set),c(null)},[]),[y,w]=j.useState(null),[N,_]=j.useState(null),b=j.useCallback(H=>_(H),[]),[S,k]=j.useState(!1),E=j.useRef(U5()),[T,I]=j.useState($5);j.useEffect(()=>{q5(T)},[T]);const[O,A]=j.useState(D5);j.useEffect(()=>{F5(O)},[O]);const[U,z]=j.useState(z5);j.useEffect(()=>{B5(U)},[U]);const[P,D]=j.useState(()=>{try{const H=window.localStorage.getItem(PE);return H===null?!0:H==="1"}catch{return!0}});j.useEffect(()=>{try{window.localStorage.setItem(PE,P?"1":"0")}catch{}},[P]);const[V,B]=j.useState(null),[C,q]=j.useState(!1),[L,re]=j.useState(0),[J,W]=j.useState(0);j.useEffect(()=>{fetch("/api/sound-hook").then(H=>H.ok?H.json():null).then(H=>{H!=null&&H.ok&&(B(H.enabled===!0),re((H.foreign??[]).filter(Y=>Y.worksHere).length),W(typeof H.parked=="number"?H.parked:0))}).catch(()=>{})},[]);const Z=j.useCallback(async()=>{q(!0);try{const Y=await(await fetch("/api/sound-hook",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:!V})})).json().catch(()=>null);Y!=null&&Y.ok&&B(Y.enabled===!0),fetch("/api/sound-hook").then(oe=>oe.ok?oe.json():null).then(oe=>{oe!=null&&oe.ok&&(re((oe.foreign??[]).filter(de=>de.worksHere).length),W(typeof oe.parked=="number"?oe.parked:0))}).catch(()=>{})}catch{}finally{q(!1)}},[V]),[M,G]=j.useState(!1),[K,$]=j.useState(null),[Q,ne]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem(LE)??""}catch{return""}}),[ae,fe]=j.useState(!1),te=j.useRef(0),[ce,Ce]=j.useState(!1),ve=j.useCallback((H=!1)=>{H&&(te.current=Date.now(),Ce(!0)),fetch(H?"/api/version?refresh=1":"/api/version").then(Y=>Y.ok?Y.json():null).then(Y=>{Y&&$(Y)}).catch(()=>{}).finally(()=>{H&&Ce(!1)})},[]),je=j.useCallback(()=>{ve(Date.now()-te.current>=L5)},[ve]);j.useEffect(()=>{ve();const H=window.setInterval(je,5*6e4),Y=()=>{document.visibilityState==="visible"&&je()};return document.addEventListener("visibilitychange",Y),()=>{window.clearInterval(H),document.removeEventListener("visibilitychange",Y)}},[ve,je]),j.useEffect(()=>{M&&ve()},[M,ve]);const ye=(K==null?void 0:K.notice)??null,[Ee,Ye]=j.useState(null),[we,_e]=j.useState(Ov);j.useEffect(()=>{let H=!1;return fetch("/api/health").then(Y=>Y.ok?Y.json():null).then(Y=>{H||(_e(m5(Y)),!(!Y||typeof Y.workspace!="string")&&Ye(Y.workspace))}).catch(()=>{}),()=>{H=!0}},[M]);const Be=j.useRef(we);Be.current=we;const it=ye?`${ye.kind}:${ye.to}`:"",ft=ye!=null&&Q!==it,Ze=j.useCallback(()=>{if(!ye)return;const H=Q===it?"":it;ne(H);try{window.localStorage.setItem(LE,H)}catch{}},[ye,it,Q]),[De,Je]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem($E)??""}catch{return""}}),Xe=K!=null&&K.invokedAs&&K.invokedAs!==en?K.invokedAs:null,Mt=Xe!=null&&De!==Xe,lt=j.useCallback(()=>{if(Xe){Je(Xe);try{window.localStorage.setItem($E,Xe)}catch{}}},[Xe]),Qe=((Va=K==null?void 0:K.upgrade)==null?void 0:Va.state)??"idle",Ot=Z3(K==null?void 0:K.upgrade),zt=j.useCallback(async()=>{try{await fetch("/api/upgrade",{method:"POST"})}catch{}ve()},[ve]);j.useEffect(()=>{if(Qe!=="running")return;const H=window.setInterval(ve,3e3);return()=>window.clearInterval(H)},[Qe,ve]);const et=j.useCallback(async()=>{var oe;const H=K==null?void 0:K.command;if(!H)return;let Y=!1;try{Y=await Promise.race([((oe=navigator.clipboard)==null?void 0:oe.writeText(H).then(()=>!0))??Promise.resolve(!1),new Promise(de=>window.setTimeout(()=>de(!1),500))])}catch{Y=!1}if(!Y)try{const de=document.createElement("textarea");de.value=H,de.setAttribute("readonly",""),de.style.cssText="position:fixed;top:0;left:0;opacity:0",document.body.appendChild(de),de.select(),Y=document.execCommand("copy"),de.remove()}catch{Y=!1}Y&&(fe(!0),window.setTimeout(()=>fe(!1),1600))},[K==null?void 0:K.command]),bt=j.useCallback(()=>{I(H=>(H||D(!1),!H))},[]),ht=j.useCallback(()=>{D(H=>(H||I(!1),!H))},[]),[vt,hn]=j.useState(!1),[Gt,Pt]=j.useState(0),bn=j.useRef(null),[gr,Sn]=j.useState(!1),Bt=j.useRef(null),[Fn,pn]=j.useState(0),vr=j.useRef(g$()),[Hr,xi]=j.useState(!1),Wr=j.useCallback(()=>{const H=vr.current,Y=H.setPaused(!H.paused);for(const oe of Y)n.current=Fx(n.current,oe);xi(H.paused)},[]),[ut,_i]=j.useState(Date.now()),[mn,Is]=j.useState(()=>{if(typeof window>"u")return!0;try{return window.localStorage.getItem(DE)!=="0"}catch{return!0}}),yr=j.useCallback(()=>{Is(H=>{const Y=!H;try{window.localStorage.setItem(DE,Y?"1":"0")}catch{}return Y})},[]),[zn,kn]=j.useState(!1),[Vr,Gr]=j.useState("restart"),[Yr,bi]=j.useState(null),sr=j.useRef(!1),Ms=j.useRef(null),En=j.useRef(0),wr=j.useCallback(async H=>{if(sr.current)return;const Y=(H==null?void 0:H.upgrade)===!0;sr.current=!0,Ms.current=Ot;const oe=++En.current;Gr(Y?"npx":"restart"),kn(!0);try{window.sessionStorage.setItem("agent-dag.restartPending",(ye==null?void 0:ye.to)??"")}catch{}try{await fetch("/api/restart",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({upgrade:Y})})}catch{}window.setTimeout(()=>{if(En.current===oe&&sr.current){sr.current=!1,kn(!1);try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}}},Y?18e4:3e4)},[ye==null?void 0:ye.to,Ot]),Os=j.useRef(null);j.useEffect(()=>{let H=!1;for(const oe of n.current.agents.values())if(oe.state==="active"){H=!0;break}const Y=e$({enabled:mn,kind:ye==null?void 0:ye.kind,canRestart:(K==null?void 0:K.canRestart)===!0,busy:H,idleSince:Os.current,now:ut});Os.current=Y.idleSince,Y.restart&&wr()},[mn,ye==null?void 0:ye.kind,K==null?void 0:K.canRestart,ut,wr]),j.useEffect(()=>{const H=K==null?void 0:K.running;let Y=null,oe=null;try{Y=window.sessionStorage.getItem("agent-dag.restartPending"),oe=window.sessionStorage.getItem(FE)}catch{return}const de=Q3({bundle:"1.35.20",running:H,pending:Y,lastTried:oe});if(de==="reload"){try{window.sessionStorage.setItem(FE,H??"")}catch{return}window.location.reload();return}if(de!=="confirm")return;try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1),bi(H??null);const xe=window.setTimeout(()=>bi(null),6e3);return()=>window.clearTimeout(xe)},[K==null?void 0:K.running]),j.useEffect(()=>{if(zn&&J3({asked:Ms.current,reported:Ot})){try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1)}},[zn,Ot]);const Ps=j.useRef(H5()).current;j.useRef(!1);const Tt=j.useRef(new Map(Ps.positions.filter(([H])=>Ps.pins.includes(H)))),xr=j.useRef(null),_r=j.useState(()=>W5())[0],[Yt,Kr]=j.useState(""),[Si,nt]=j.useState(()=>new Set),[br,Xr]=j.useState(_$),[Ls,Qr]=j.useState(!1),Zr=j.useRef(null);j.useEffect(()=>{document.documentElement.dataset.theme=br;try{window.localStorage.setItem(OC,br)}catch{}},[br]),j.useEffect(()=>{if(!_r)return;const H=window.setTimeout(()=>{try{e.setViewport(_r,{duration:0})}catch{}},60);return()=>window.clearTimeout(H)},[e,_r]);const $s=j.useRef(!0);j.useEffect(()=>{const H=new EventSource("/events"),Y=m$(i,{now:()=>Date.now(),setTimeout:(oe,de)=>window.setTimeout(oe,de),clearTimeout:oe=>window.clearTimeout(oe)});return H.addEventListener("open",()=>{G(!0),Qr(!0)}),H.addEventListener("error",()=>G(!1)),H.addEventListener("replay-end",()=>{$s.current=!1,Y.flush()}),H.addEventListener("hook",oe=>{try{const de=JSON.parse(oe.data);if(!vr.current.accept(de))return;n.current=Fx(n.current,de),de.replay===!0||$s.current||Date.now()-de.receivedAt>3e4?Y.replay():Y.live()}catch{}}),()=>{H.close(),Y.cancel()}},[i]),j.useEffect(()=>{const H=setInterval(()=>{const Y=Date.now();_i(Y);let oe=mP(n.current,Y,Dx);gP(n.current,Y,Dx)&&(oe=!0),hP(n.current,Y,I5,M5)&&(oe=!0),pP(n.current,Y,O5,P5)&&(oe=!0),oe&&i()},250);return()=>clearInterval(H)},[i]);const ir=j.useRef(null),St=j.useRef(0),qs=420,pt=j.useCallback((H=500)=>{try{const Se=document.querySelector(".canvas-wrap"),Pe=Array.from(document.querySelectorAll(".react-flow__node")).filter(wt=>wt.offsetWidth>0);if(!Se||Pe.length===0)return;const Fe=Se.getBoundingClientRect(),Ge=e.getViewport();if(!Number.isFinite(Ge.zoom)||Ge.zoom<=0)return;const We=wt=>(wt-Fe.left-Ge.x)/Ge.zoom,ze=wt=>(wt-Fe.top-Ge.y)/Ge.zoom,Tn=Pe.map(wt=>wt.getBoundingClientRect()),Ys=Math.min(...Tn.map(wt=>We(wt.left))),Ao=Math.max(...Tn.map(wt=>We(wt.right))),Ks=Math.min(...Tn.map(wt=>ze(wt.top))),Io=Math.max(...Tn.map(wt=>ze(wt.bottom))),Xa=Ao-Ys,us=Io-Ks;if(!(Xa>0&&us>0))return;const Qt=Math.max(.2,Math.min(1,(Fe.width-160)/(Xa+qs)*.86,(Fe.height-160)/us*.86));e.setViewport({x:80-Ys*Qt,y:Math.max(80,(Fe.height-us*Qt)/2)-Ks*Qt,zoom:Qt},{duration:H}),St.current=Date.now(),window.setTimeout(()=>{try{const wt={x:80-Ys*Qt,y:Math.max(80,(Fe.height-us*Qt)/2)-Ks*Qt,zoom:Qt},Mo=e.getViewport();(Math.abs(Mo.zoom-Qt)>.01||Math.abs(Mo.x-wt.x)>2)&&e.setViewport(wt,{duration:0})}catch{}},H+60)}catch{}},[e]),ko=j.useRef(""),Eo=j.useRef(null),qa=j.useRef(0),Sr=j.useCallback(()=>{qa.current=Date.now()},[]),Jr="agent-dag.autoFitDisabled",gn=j.useRef((()=>{if(typeof window>"u")return!1;try{return window.localStorage.getItem(Jr)==="1"}catch{return!1}})()),[Ds,Da]=j.useState(gn.current),Fa=j.useCallback(()=>{if(!gn.current){gn.current=!0,Da(!0);try{window.localStorage.setItem(Jr,"1")}catch{}}},[]),No=j.useCallback(()=>{gn.current=!1,Da(!1);try{window.localStorage.removeItem(Jr)}catch{}pt(400)},[e,pt]);j.useEffect(()=>{const H=setInterval(()=>{if(gn.current||Date.now()-qa.current<800)return;const Y=n.current,oe=Date.now(),de=[];for(const We of Y.agents.values())Mv(We,oe)&&de.push({id:We.id});if(de.length===0)return;const xe=e.getViewport(),Se=window.innerWidth-360,Pe=window.innerHeight-52;let Fe=!1,Ge=!1;for(const{id:We}of de){const ze=or.current.get(We),Tn=Tt.current.get(We)??Kt.current.get(We);if(!ze||!Tn)continue;Ge=!0;const Ys=Tn.x*xe.zoom+xe.x,Ao=Tn.y*xe.zoom+xe.y,Ks=(Tn.x+ze.width)*xe.zoom+xe.x,Io=(Tn.y+ze.height)*xe.zoom+xe.y;if(Ks>0&&Ys<Se&&Io>0&&Ao<Pe){Fe=!0;break}}Ge&&!Fe&&pt(600)},1500);return()=>clearInterval(H)},[e]);const ki=j.useRef(!1),or=j.useRef(new Map),es=j.useRef(0),ec=j.useCallback(H=>{const Y=or.current;let oe=!1;for(const de of H.nodeInternals.values()){const xe=de.width,Se=de.height;if(xe==null||Se==null)continue;const Pe=Y.get(de.id);Pe?(Math.abs(Pe.height-Se)>4||Math.abs(Pe.width-xe)>4)&&(Y.set(de.id,{width:xe,height:Se}),oe=!0):(Y.set(de.id,{width:xe,height:Se}),oe=!0)}return oe&&(es.current+=1),es.current},[]),Ei=Ke(ec),[He,za]=j.useState(0);j.useEffect(()=>{let H=0;const Y=()=>{const de=or.current;let xe=!1;for(const Se of document.querySelectorAll(".react-flow__node[data-id]")){const Pe=Se.getAttribute("data-id");if(!Pe)continue;const Fe=Se.offsetWidth,Ge=Se.offsetHeight;if(!Fe||!Ge)continue;const We=de.get(Pe);(!We||Math.abs(We.width-Fe)>4||Math.abs(We.height-Ge)>4)&&(de.set(Pe,{width:Fe,height:Ge}),xe=!0)}xe&&za(Se=>Se+1)};if(ki.current)return;let oe=0;return document.visibilityState==="hidden"?oe=window.setTimeout(Y,32):H=requestAnimationFrame(Y),()=>{cancelAnimationFrame(H),window.clearTimeout(oe)}});const Kt=j.useRef(new Map(Ps.positions)),Co=j.useRef(new Set),Ni=j.useRef(""),kr=j.useMemo(()=>{const H=[];for(const Y of n.current.agents.values())Mv(Y,ut)&&H.push(Y.id+(Y.parentId?`>${Y.parentId}`:""));return H.sort(),`${H.join("|")}#sv${Ei}.${He}`},[n.current,n.current.lastSeq,ut,Ei,He]),ts=j.useRef(null);j.useEffect(()=>(ts.current!=null&&window.clearTimeout(ts.current),ts.current=window.setTimeout(()=>{dv(Kt.current,Tt.current)},1500),()=>{ts.current!=null&&window.clearTimeout(ts.current)}),[kr]),j.useEffect(()=>{if(ko.current===kr)return;const H=ko.current;if(ko.current=kr,!H||gn.current)return;Date.now()-St.current>1200&&pt(400),ir.current&&window.clearTimeout(ir.current),ir.current=window.setTimeout(()=>{gn.current||pt(500)},280)},[kr,e,pt]);const Fs=j.useMemo(()=>{if(o.size===0)return null;const H=new Set;for(const Y of o){const oe=Y5(n.current,Y);if(oe)for(const de of oe)H.add(de)}return H.size>0?H:null},[n.current,n.current.lastSeq,o]),Nn=j.useMemo(()=>o5(n.current,ut),[n.current,n.current.lastSeq,ut]),Bn=j.useRef(null),[vn,Un]=j.useState({w:0,h:0});j.useEffect(()=>{const H=Bn.current;if(!H||typeof ResizeObserver>"u")return;const Y=new ResizeObserver(oe=>{var xe;const de=(xe=oe[0])==null?void 0:xe.contentRect;de&&Un(Se=>Math.abs(Se.w-de.width)>40||Math.abs(Se.h-de.height)>40?{w:de.width,h:de.height}:Se)});return Y.observe(H),Un({w:H.clientWidth,h:H.clientHeight}),()=>Y.disconnect()},[]);const zs=j.useCallback(H=>{var oe,de;const Y=H.target;!(Y!=null&&Y.closest)||Y.closest(j5)!==H.currentTarget||(H.preventDefault(),(de=(oe=document.activeElement)==null?void 0:oe.blur)==null||de.call(oe))},[]),Bs=j.useRef(new Map),[Hn,tc]=j.useState(!1);j.useEffect(()=>{const H=window.setTimeout(()=>tc(!0),2500);return()=>window.clearTimeout(H)},[]);const[Ba,Er]=j.useState(!1),ar=j.useRef(null),[Ci,Us]=j.useState(!1),Ua=j.useCallback(()=>{ar.current&&(window.clearTimeout(ar.current),ar.current=null),Er(!1)},[]),nc=j.useCallback(H=>{H.length!==0&&queueMicrotask(()=>{Er(!0),ar.current&&window.clearTimeout(ar.current),ar.current=window.setTimeout(()=>Er(!1),A5+80)})},[]);j.useEffect(()=>()=>{ar.current&&window.clearTimeout(ar.current)},[]);const ns=vn.w>0?vn.w*.92:0,rs=vn.h>0?vn.h:0,{nodes:Xt,edges:Ti}=j.useMemo(()=>K5(n.current,ut,ns,rs,Tt.current,Yt,or.current,Bs.current,nc,Hn,Ci,Kt.current,Co.current,kr,Ni,o,Fs,Nn,b),[n.current,n.current.lastSeq,ut,ns,rs,Hn,Ci,Yt,kr,o,Fs,Nn,b,Gt]),Ha=j.useMemo(()=>{const H=new Map;for(const oe of Xt){const de=oe.data;if(!(de!=null&&de.sessionId)||de.exitAt!=null)continue;const xe=oe.width,Se=oe.height;if(xe==null||Se==null)continue;const Pe=oe.position.x,Fe=oe.position.y,Ge=Pe+xe,We=Fe+Se,ze=H.get(de.sessionId);ze?(ze.minX=Math.min(ze.minX,Pe),ze.minY=Math.min(ze.minY,Fe),ze.maxX=Math.max(ze.maxX,Ge),ze.maxY=Math.max(ze.maxY,We)):H.set(de.sessionId,{minX:Pe,minY:Fe,maxX:Ge,maxY:We})}const Y=[];for(const[oe,de]of H){const xe=de.maxX-de.minX+au*2,Se=de.maxY-de.minY+au*2;Y.push({id:`group:${oe}`,type:PT,position:{x:de.minX-au,y:de.minY-au},data:{sessionId:oe,w:xe,h:Se},width:xe,height:Se,style:{width:xe,height:Se},zIndex:-1,draggable:!0,selectable:!1,focusable:!1,deletable:!1,connectable:!1})}return Y},[Xt,ut]),rc=j.useMemo(()=>{const H=[...Ha,...Xt],Y=Bt.current;return!Y||Y.size===0?H:H.map(oe=>{const de=Y.get(oe.id);return de?{...oe,position:de}:oe})},[Ha,Xt,Fn]),Nr=j.useMemo(()=>{if(!Yt)return null;const H=new Set;for(const Y of n.current.agents.values())Nn.has(Y.id)&&qT(Y,Yt)&&H.add(Y.id);return H},[n.current,n.current.lastSeq,Yt,Nn]),Cn=j.useMemo(()=>k5(Yt,(Nr==null?void 0:Nr.size)??0,Nn.size),[Yt,Nr,Nn]),ss=j.useMemo(()=>{const H=new Set;for(const Y of n.current.agents.values())for(const oe of Y.tools)H.add(HT(oe.name));return Object.keys(Lv).filter(Y=>H.has(Y))},[n.current,n.current.lastSeq]);j.useEffect(()=>{if(ss.length<=1){Sn(!1);return}let H=0;const Y=()=>{const oe=bn.current;if(oe&&!document.hidden){const de=oe.getBoundingClientRect(),xe=Array.from(document.querySelectorAll(".react-flow__node, .tool-burst")).map(Pe=>Pe.getBoundingClientRect()),Se=l5(de,xe,8);Sn(Pe=>Pe===Se?Pe:Se)}H=window.setTimeout(Y,300)};return Y(),()=>window.clearTimeout(H)},[ss.length]);const is=j.useMemo(()=>{const H=new Map;for(const oe of n.current.agents.values())for(const de of oe.tools){if(!de.name.startsWith("mcp__"))continue;const xe=de.name.slice(5),Se=xe.indexOf("__"),Pe=Se>0?xe.slice(0,Se):xe;H.set(Pe,(H.get(Pe)??0)+1)}const Y=[];for(const[oe,de]of H){let xe=5381;for(let Se=0;Se<oe.length;Se++)xe=(xe<<5)+xe^oe.charCodeAt(Se);Y.push({server:oe,count:de,hue:Math.abs(xe)%360})}return Y.sort((oe,de)=>de.count-oe.count),Y},[n.current,n.current.lastSeq]),lr=j.useCallback(H=>{nt(Y=>{const oe=new Set(Y);return oe.has(H)?oe.delete(H):oe.add(H),oe})},[]),Rt=u?n.current.agents.get(u):null,os=h?Array.from(n.current.agents.values()).flatMap(H=>H.tools).find(H=>H.id===h)??null:null,To=j.useCallback(async()=>{try{await fetch("/api/clear",{method:"POST"})}catch{}n.current=Tv(),Tt.current.clear(),or.current.clear(),Kt.current.clear(),Ni.current="",BE(),m(),i()},[i,m]),Hs=j.useRef(S);Hs.current=S;const Ws=j.useRef(!1);Ws.current=os!=null||vt||N!=null||y!=null;const Vs=j.useCallback(H=>{const Y=n$(H,{confirmOpen:Hs.current,modalOpen:Ws.current});Y==="confirm"?k(!0):Y==="clear"&&(k(!1),To())},[To]),Lt=j.useCallback(()=>{Tt.current.clear(),Kt.current.clear(),Ni.current="",BE(),i(),window.setTimeout(()=>pt(500),80)},[i,e,pt]),Cr=j.useCallback(()=>pt(500),[pt]),as=j.useRef(Xt);as.current=Xt;const ls=j.useRef(u);ls.current=u;const Ro=j.useCallback(H=>{const Y=as.current,oe=s$(Y.map(Se=>({id:Se.id,x:Se.position.x,y:Se.position.y})),ls.current,H),de=oe?Y.find(Se=>Se.id===oe):void 0;if(!de)return;const xe=OE(document.activeElement);d(de.id,!1),window.setTimeout(()=>{try{e.fitView({padding:.35,duration:350,nodes:[de]})}catch{}St.current=Date.now(),xe&&R5(de.id)},30)},[d,e]),Ri=j.useCallback(H=>{d(H,!1),window.setTimeout(()=>{try{const Y=as.current.find(oe=>oe.id===H);Y&&e.fitView({padding:.3,duration:500,nodes:[Y]}),St.current=Date.now()}catch{}},60)},[d,e]);j.useEffect(()=>{const H=Y=>{var Fe,Ge,We;const oe=Y.target,de={tagName:oe==null?void 0:oe.tagName,isContentEditable:oe==null?void 0:oe.isContentEditable,role:(Fe=oe==null?void 0:oe.getAttribute)==null?void 0:Fe.call(oe,"role"),type:oe==null?void 0:oe.type};if(Y.key==="Escape"){const ze=PP({overlayOpen:Eu.depth()>0,typing:ry(de)});ze==="dismiss"?Eu.dismissTop():ze==="blur"?oe==null||oe.blur():(l$(de)&&(oe==null||oe.blur()),m());return}if(_C(Y))return;const xe=OE(oe)?(Ge=oe==null?void 0:oe.getAttribute)==null?void 0:Ge.call(oe,"data-id"):null,Se=xe&&as.current.some(ze=>ze.id===xe)?xe:null,Pe=o$(Y,Se);if(Pe.kind==="activate"){Y.preventDefault(),d(Pe.nodeId,Pe.additive);return}if(Pe.kind!=="node"&&!(Pe.nodeId==null&&UP(de))){if(Y.key==="/"){Y.preventDefault(),(We=Zr.current)==null||We.focus();return}Y.key===" "&&(Y.preventDefault(),Wr()),(Y.key==="c"||Y.key==="C")&&Vs("shortcut"),(Y.key==="r"||Y.key==="R")&&Lt(),(Y.key==="f"||Y.key==="F")&&Cr(),(Y.key==="l"||Y.key==="L")&&bt(),(Y.key==="h"||Y.key==="H")&&hn(ze=>!ze),(Y.key==="u"||Y.key==="U")&&z(ze=>!ze),(Y.key==="a"||Y.key==="A")&&Be.current.claude&&ht(),(Y.key==="j"||Y.key==="J")&&Ro(1),(Y.key==="k"||Y.key==="K")&&Ro(-1),(Y.key==="t"||Y.key==="T")&&Xr(ze=>ze==="dark"?"light":"dark")}};return window.addEventListener("keydown",H),()=>window.removeEventListener("keydown",H)},[Vs,Lt,Cr,m,d,Ro,Wr]);const Tr=n.current.agents.size,Gs=new Set(Array.from(n.current.agents.values()).map(H=>H.sessionId)).size,tn=j.useMemo(()=>JL(n.current.agents.values()),[n.current,n.current.lastSeq]),jo=j.useMemo(()=>e3(n.current.agents.values()),[n.current,n.current.lastSeq]),Wa=j.useRef(null);j.useEffect(()=>{const H=b$({waiting:tn.length,running:jo}),Y=Wa.current;if(Wa.current=H,(Y==null?void 0:Y.title)!==H.title&&(document.title=H.title),(Y==null?void 0:Y.icon)!==H.icon){const oe=document.querySelector('link[rel="icon"]');oe&&(oe.href=S$[H.icon])}},[tn.length,jo]);const[sc,ic]=j.useState(""),ji=E$(tn);j.useEffect(()=>{ic(H=>N$(H,ji))},[ji]);const nn=j.useMemo(()=>{let H=0,Y=0,oe=0,de=0,xe=0,Se=0,Pe=0,Fe=0,Ge=0;for(const We of n.current.agents.values()){H+=We.usage.inputTokens,Y+=We.usage.outputTokens,oe+=We.usage.cacheReadTokens,de+=We.usage.cacheCreateTokens;const ze=dn(We.usage,We.model);xe+=ze.total,Se+=ze.input,Pe+=ze.output,Fe+=ze.cacheRead,Ge+=ze.cacheWrite}return{inT:H,outT:Y,cacheR:oe,cacheC:de,sum:H+Y,cost:{total:xe,input:Se,output:Pe,cacheRead:Fe,cacheWrite:Ge}}},[n.current,n.current.lastSeq]);return g.jsxs("div",{className:"app",children:[g.jsx("a",{className:"skip-link",href:"#canvas",children:"Skip to the canvas"}),g.jsxs("header",{className:"topbar",children:[g.jsxs("div",{className:"brand",children:[g.jsx("span",{className:"logo"}),g.jsx("h1",{children:en}),ye?g.jsxs("button",{type:"button",className:"v stale",onClick:Ze,"aria-label":h5({...ye,open:ft}),title:ye.kind==="restart"?`Running v${ye.from}; v${ye.to} is installed on disk. Restart to pick it up.`:`Running v${ye.from}; v${ye.to} is on npm.`,children:["v",ye.from,g.jsx("span",{className:"v-dot","aria-hidden":!0})]}):(()=>{const H={running:(K==null?void 0:K.running)??"1.35.20",latest:K==null?void 0:K.latest,latestPending:K==null?void 0:K.latestPending,checkedAgo:K!=null&&K.checkedAt?Pv(ut-K.checkedAt):null,checkDisabled:K==null?void 0:K.checkDisabled,checking:ce};return g.jsxs("button",{type:"button",className:ce?"v checking":"v",onClick:()=>ve(!0),"aria-busy":ce||void 0,"aria-label":f5(H),title:d5(H),children:["v",H.running]})})()]}),Rt&&(()=>{const H=dn(Rt.usage,Rt.model),Y=Math.max(0,((Rt.endedAt??ut)-Rt.startedAt)/1e3),oe=Rt.state==="active"?ku(H.total,Y):null,de=o.size-1;return g.jsxs("button",{type:"button",className:"selected-ribbon",title:`Fit view to ${Rt.label}`,onClick:()=>{try{const xe=Xt.find(Se=>Se.id===Rt.id);xe&&e.fitView({padding:.35,duration:500,nodes:[xe]}),St.current=Date.now()}catch{}},children:[g.jsx("span",{className:`state-pill state-${Rt.state}`,children:Rt.state==="active"?"live":Rt.state}),g.jsx("span",{className:"selected-label",children:Rt.label}),H.total>0&&g.jsxs("span",{className:"selected-cost",children:[qe(H.total),oe?g.jsxs("span",{className:"selected-rate",children:[" · ",oe]}):null]}),de>0&&g.jsxs("span",{className:"selected-extra",children:["+",de]}),g.jsx("span",{"aria-hidden":!0,className:"selected-close",onClick:xe=>{xe.stopPropagation(),m()},children:"×"})]})})(),g.jsxs("div",{className:"actions",children:[g.jsxs("div",{className:"search",children:[g.jsx("span",{className:"search-icon","aria-hidden":!0,children:"⌕"}),g.jsx("input",{ref:Zr,type:"text",placeholder:E5,value:Yt,onChange:H=>Kr(H.target.value),spellCheck:!1,"aria-label":"Filter the graph"}),Yt?g.jsx("button",{className:"search-clear","aria-label":"Clear search",onClick:()=>Kr(""),children:"×"}):g.jsx("kbd",{className:"search-kbd","aria-hidden":!0,children:"/"}),Cn.count&&g.jsx("span",{className:`search-count${Cn.empty?" none":""}`,"aria-live":"polite",title:`${Cn.count} agents on the canvas match “${Yt}”`,children:Cn.count})]}),g.jsxs("span",{className:"status",children:[(()=>{const H=b5({connected:M,paused:Hr,held:vr.current.size});return g.jsx("span",{className:`pill ${H.tone}`,title:H.title,children:H.label})})(),g.jsxs("span",{className:"stat",title:y5(we),children:[g.jsx("span",{className:"count",children:Gs}),g.jsx("span",{className:"lbl",children:"sessions"})]}),g.jsxs("span",{className:"stat",title:"Total agents (root + subagents)",children:[g.jsx("span",{className:"count",children:Tr}),g.jsx("span",{className:"lbl",children:"agents"})]}),g.jsxs("span",{className:"stat",title:w5(we),children:[g.jsx("span",{className:"count",children:n.current.totalEvents}),g.jsx("span",{className:"lbl",children:"events"})]}),nn.sum>0&&g.jsxs("span",{className:"stat",title:`in:${nn.inT.toLocaleString()} out:${nn.outT.toLocaleString()} cache-r:${nn.cacheR.toLocaleString()} cache-c:${nn.cacheC.toLocaleString()}`,children:[g.jsx("span",{className:"count",children:Dt(nn.sum)}),g.jsx("span",{className:"lbl",children:"tokens"})]}),is.length>0&&g.jsxs("span",{className:"stat mcp-legend",title:`MCP servers seen this session:
|
|
72
|
+
${n.parked} of your own sound hook${n.parked>1?"s were":" was"} set aside so this switch actually controls the sound. Nothing was deleted — shift-click to put ${n.parked>1?"them":"it"} back.`:"";return r+i+o+l}function LT(e){const n=Math.max(0,Math.floor(e));return`${n} event${n===1?"":"s"}`}function b5(e){return e.connected?e.paused?{tone:"paused",label:"paused",title:e.held>0?`Connected — ${LT(e.held)} held until you resume (Space)`:"Connected — updates held until you resume (Space)"}:{tone:"live",label:"live",title:"Receiving events"}:{tone:"dead",label:"offline",title:e.paused?"SSE disconnected — and the canvas is paused, so resuming will not bring events back until it reconnects":"SSE disconnected"}}function S5(e){return e.paused?e.held<=0?{label:"Resume",title:"Nothing has arrived since you paused. Resume to follow the canvas again (Space)"}:{label:`Resume · ${e.held} held`,title:`${LT(e.held)} arrived while paused and will be applied in order when you resume (Space)`}:{label:"Pause",title:"Pause live updates — events keep arriving and are applied when you resume (Space)"}}function $T(e,n){return e!==""&&n>0}function k5(e,n,r){return e===""?{active:!1,matched:n,total:r,count:null,empty:!1,message:null,dim:!1}:{active:!0,matched:n,total:r,count:`${n} of ${r}`,empty:n===0,message:n===0?`No agents match “${e}”`:null,dim:$T(e,n)}}const E5="Search agents, tools, model…";function qT(e,n){var i,o,l,u;if(!n)return!0;const r=n.toLowerCase();if(e.label.toLowerCase().includes(r)||(i=e.cwd)!=null&&i.toLowerCase().includes(r)||(o=e.cwdBasename)!=null&&o.toLowerCase().includes(r)||e.sessionId.toLowerCase().includes(r)||(l=e.firstPrompt)!=null&&l.toLowerCase().includes(r)||e.model&&(e.model.toLowerCase().includes(r)||js(e.model).toLowerCase().includes(r))||(u=e.provider)!=null&&u.toLowerCase().startsWith(r))return!0;for(const c of e.tools)if(c.name.toLowerCase().includes(r))return!0;return!1}function Pv(e){const n=Math.max(0,Math.floor(e/1e3));return n<60?"just now":n<3600?`${Math.floor(n/60)}m ago`:n<86400?`${Math.floor(n/3600)}h ago`:`${Math.floor(n/86400)}d ago`}function N5(e,n){return e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()&&e.getDate()===n.getDate()}function C5(e,n,r){const i=new Date(e),o=Pv(n-e);return{label:N5(i,new Date(n))?o:`${o} · ${i.toLocaleDateString(r,{month:"short",day:"numeric"})}`,title:i.toLocaleString(r,{dateStyle:"medium",timeStyle:"medium"})}}function ua(e){return typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue(e).trim()||""}const T5={agent:QP,sessionGroup:dL},DT="react-flow__node";function OE(e){var n,r;return!!e&&((r=(n=e.classList)==null?void 0:n.contains)==null?void 0:r.call(n,DT))===!0}function R5(e){try{const n=document.querySelector(`.${DT}[data-id="${CSS.escape(e)}"]`);n==null||n.focus({preventScroll:!0})}catch{}}const j5=["a[href]","button:not(:disabled)","input:not(:disabled)","select:not(:disabled)","textarea:not(:disabled)","summary","[tabindex]"].join(","),A5=420,au=18,I5=200,M5=5*6e4,O5=6,P5=2*6e4,ky="agent-dag.layout",Ey="agent-dag.viewport",FT="agent-dag.summariesDismissed",zT="agent-dag.sessionListOpen",BT="agent-dag.detailOpen",UT="agent-dag.usagePanelOpen",PE="agent-dag.accountsPanelOpen",LE="agent-dag.versionNoticeDismissed",$E="agent-dag.oldNameNoticeDismissed",L5=15*6e4,qE={git_checkout:"this deck runs from a git checkout — pull instead:",npx:"npx runs from a cache that cannot be upgraded in place — run:",not_writable:"the install directory is not writable by this user — run:",opted_out:"installs are off (AGENTS_DECK_NO_INSTALL=1) — run:"},DE="agent-dag.autoRestart",FE="agent-dag.bundleReloadedFor";function $5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(zT)==="1"}catch{return!1}}function q5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(zT,e?"1":"0")}catch{}}function D5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(BT)==="1"}catch{return!1}}function F5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(BT,e?"1":"0")}catch{}}function z5(){const e=MC(UT);return e===null?!0:e==="1"}function B5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(UT,e?"1":"0")}catch{}}function U5(){if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(FT);if(!e)return new Set;const n=JSON.parse(e);return new Set(Array.isArray(n)?n.filter(r=>typeof r=="string"):[])}catch{return new Set}}function zE(e){if(!(typeof window>"u"))try{const n=Array.from(e),r=n.length>200?n.slice(-200):n;window.localStorage.setItem(FT,JSON.stringify(r))}catch{}}function H5(){const e={positions:[],pins:[]};if(typeof window>"u")return e;try{const n=window.localStorage.getItem(ky);if(!n)return e;const r=JSON.parse(n);if(!("v"in r)){const o=Object.entries(r).filter(([,l])=>l&&typeof l.x=="number"&&typeof l.y=="number");return{positions:o,pins:o.map(([l])=>l)}}return{positions:Object.entries(r.positions??{}).filter(([,o])=>o&&typeof o.x=="number"&&typeof o.y=="number"),pins:Array.isArray(r.pins)?r.pins:[]}}catch{return e}}function dv(e,n){if(!(typeof window>"u"))try{const r={};for(const[i,o]of e)r[i]=o;for(const[i,o]of n)r[i]=o;window.localStorage.setItem(ky,JSON.stringify({v:2,positions:r,pins:Array.from(n.keys())}))}catch{}}function W5(){if(typeof window>"u")return null;try{const e=window.localStorage.getItem(Ey);if(!e)return null;const n=JSON.parse(e);return typeof(n==null?void 0:n.x)!="number"||typeof(n==null?void 0:n.y)!="number"||typeof(n==null?void 0:n.zoom)!="number"?null:n}catch{return null}}function V5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(Ey,JSON.stringify(e))}catch{}}function BE(){if(!(typeof window>"u")){try{window.localStorage.removeItem(ky)}catch{}try{window.localStorage.removeItem(Ey)}catch{}}}function G5(e,n){const r=e.agents.get(n);if(!r)return;const i=[];for(const d of e.agents.values())d.sessionId===n&&i.push(d);const o={schemaVersion:1,exportedAt:new Date().toISOString(),sessionId:n,label:r.label,cwd:r.cwd,startedAt:r.startedAt,endedAt:r.endedAt,model:r.model,agents:i.map(d=>({id:d.id,kind:d.kind,label:d.label,parentId:d.parentId,state:d.state,startedAt:d.startedAt,endedAt:d.endedAt,model:d.model,cwd:d.cwd,usage:d.usage,prompts:d.prompts,tools:d.tools.map(m=>({id:m.id,name:m.name,inputPreview:m.inputPreview,startedAt:m.startedAt,endedAt:m.endedAt,ok:m.ok,errorPreview:m.errorPreview,usage:m.usage}))}))},l=JSON.stringify(o,null,2),u=new Blob([l],{type:"application/json"}),c=URL.createObjectURL(u),h=document.createElement("a"),p=(r.label||"session").replace(/[^a-z0-9._-]/gi,"_");h.href=c,h.download=`${en}-${p}-${n.slice(0,8)}.json`,document.body.appendChild(h),h.click(),document.body.removeChild(h),setTimeout(()=>URL.revokeObjectURL(c),1e3)}const Lv={file:"📁",shell:"⚡",web:"🌐",agent:"🤖",task:"📋",plan:"🧭",mcp:"🔌",other:"✨"},$v={file:"file",shell:"shell",web:"web",agent:"agent",task:"task",plan:"plan",mcp:"mcp",other:"other"},HT=kC;function Y5(e,n){if(!n)return null;const r=new Set([n]);let i=n;for(;i;){const l=e.agents.get(i);if(!(l!=null&&l.parentId)||r.has(l.parentId))break;r.add(l.parentId),i=l.parentId}let o=!0;for(;o;){o=!1;for(const l of e.agents.values())l.parentId&&r.has(l.parentId)&&!r.has(l.id)&&(r.add(l.id),o=!0)}return r}function K5(e,n,r,i,o,l,u,c,h,p,d,m,y,w,N,_,b,S,k){const E=[],T=[],I=new Set;if(l)for(const B of e.agents.values())S.has(B.id)&&qT(B,l)&&I.add(B.id);const O=$T(l,I.size);for(const B of e.agents.values()){if(!S.has(B.id))continue;const C=O&&!I.has(B.id),q=B.exitAt!=null,L=b!=null&&!b.has(B.id),re=[C?"rf-dim":"",q?"rf-exiting":"",L?"rf-spotlit-out":""].filter(Boolean).join(" ")||void 0,J=u.get(B.id);if(E.push({id:B.id,type:"agent",position:{x:0,y:0},data:{...B,now:n,onOpenContext:k},className:re,...J?{width:J.width,height:J.height}:null}),B.parentId&&S.has(B.parentId)){const W=ny(B.sessionId),Z=l&&!I.has(B.id)&&!I.has(B.parentId),M=q,G=_.size>0&&(_.has(B.id)||_.has(B.parentId)),K=b!=null&&!b.has(B.id)&&!b.has(B.parentId),$=B.state==="active"?2:1.5,Q=G?$+1.5:$,ne=Z||M?.2:K?.12:1,ae=["sess-edge",B.state==="active"?"sess-live":"sess-idle",M?"rf-edge-exiting":"",G?"rf-edge-selected":""].filter(Boolean).join(" ");T.push({id:`e:${B.parentId}->${B.id}`,source:B.parentId,target:B.id,animated:(B.state==="active"||G)&&!Z&&!M,type:"smoothstep",style:{"--session-hue":W,strokeWidth:Q,opacity:ne,transition:"var(--edge-transition)"},className:ae})}}const A=new Map;for(const B of e.agents.values())B.tools.length>0&&A.set(B.id,Math.min(4,B.tools.length));const U=`${w}#lanes:${J4(A)}`,z=E.filter(B=>c$(B.id,o,m,y));if(z.length>0||U!==N.current){if(z.length>0){const B=t5(E,T,{direction:"LR",pinned:o,measured:u,availableWidth:r,availableHeight:i,lanes:A});for(const C of B)IC(C.id,m,y)&&f$(C.id,C.position,m,y);r5(E,m,o,u,new Set(z.map(C=>C.id)),A)}n5(E,m,o,u,A),N.current=U}const P=s5(E,m,o,u,c,!p||d,A);P.length>0&&h(P),ru(m,e.agents),ru(y,e.agents),ru(o,e.agents),ru(u,u$(e.agents.values()));const D=[];let V=!1;for(const B of E){let C=o.get(B.id)??m.get(B.id);C||(C=d$(B.id,m,y),V=!0),D.push({...B,position:C})}return V&&(N.current=""),{nodes:D,edges:T}}function X5(){return g.jsx(ty,{children:g.jsx(Q5,{})})}function Q5(){var Va,Ga,Ya,Ka;const e=ja(),n=j.useRef(Tv()),[,r]=j.useState(0),i=j.useCallback(()=>r(H=>H+1),[]),[o,l]=j.useState(()=>new Set),[u,c]=j.useState(null),[h,p]=j.useState(null),d=j.useCallback((H,Y)=>{l(oe=>{if(!Y)return new Set([H]);const de=new Set(oe);return de.has(H)?de.delete(H):de.add(H),de}),c(oe=>Y&&oe===H?oe:H)},[]),m=j.useCallback(()=>{l(new Set),c(null)},[]),[y,w]=j.useState(null),[N,_]=j.useState(null),b=j.useCallback(H=>_(H),[]),[S,k]=j.useState(!1),E=j.useRef(U5()),[T,I]=j.useState($5);j.useEffect(()=>{q5(T)},[T]);const[O,A]=j.useState(D5);j.useEffect(()=>{F5(O)},[O]);const[U,z]=j.useState(z5);j.useEffect(()=>{B5(U)},[U]);const[P,D]=j.useState(()=>{try{const H=window.localStorage.getItem(PE);return H===null?!0:H==="1"}catch{return!0}});j.useEffect(()=>{try{window.localStorage.setItem(PE,P?"1":"0")}catch{}},[P]);const[V,B]=j.useState(null),[C,q]=j.useState(!1),[L,re]=j.useState(0),[J,W]=j.useState(0);j.useEffect(()=>{fetch("/api/sound-hook").then(H=>H.ok?H.json():null).then(H=>{H!=null&&H.ok&&(B(H.enabled===!0),re((H.foreign??[]).filter(Y=>Y.worksHere).length),W(typeof H.parked=="number"?H.parked:0))}).catch(()=>{})},[]);const Z=j.useCallback(async()=>{q(!0);try{const Y=await(await fetch("/api/sound-hook",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:!V})})).json().catch(()=>null);Y!=null&&Y.ok&&B(Y.enabled===!0),fetch("/api/sound-hook").then(oe=>oe.ok?oe.json():null).then(oe=>{oe!=null&&oe.ok&&(re((oe.foreign??[]).filter(de=>de.worksHere).length),W(typeof oe.parked=="number"?oe.parked:0))}).catch(()=>{})}catch{}finally{q(!1)}},[V]),[M,G]=j.useState(!1),[K,$]=j.useState(null),[Q,ne]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem(LE)??""}catch{return""}}),[ae,fe]=j.useState(!1),te=j.useRef(0),[ce,Ce]=j.useState(!1),ve=j.useCallback((H=!1)=>{H&&(te.current=Date.now(),Ce(!0)),fetch(H?"/api/version?refresh=1":"/api/version").then(Y=>Y.ok?Y.json():null).then(Y=>{Y&&$(Y)}).catch(()=>{}).finally(()=>{H&&Ce(!1)})},[]),je=j.useCallback(()=>{ve(Date.now()-te.current>=L5)},[ve]);j.useEffect(()=>{ve();const H=window.setInterval(je,5*6e4),Y=()=>{document.visibilityState==="visible"&&je()};return document.addEventListener("visibilitychange",Y),()=>{window.clearInterval(H),document.removeEventListener("visibilitychange",Y)}},[ve,je]),j.useEffect(()=>{M&&ve()},[M,ve]);const ye=(K==null?void 0:K.notice)??null,[Ee,Ye]=j.useState(null),[we,_e]=j.useState(Ov);j.useEffect(()=>{let H=!1;return fetch("/api/health").then(Y=>Y.ok?Y.json():null).then(Y=>{H||(_e(m5(Y)),!(!Y||typeof Y.workspace!="string")&&Ye(Y.workspace))}).catch(()=>{}),()=>{H=!0}},[M]);const Be=j.useRef(we);Be.current=we;const it=ye?`${ye.kind}:${ye.to}`:"",ft=ye!=null&&Q!==it,Ze=j.useCallback(()=>{if(!ye)return;const H=Q===it?"":it;ne(H);try{window.localStorage.setItem(LE,H)}catch{}},[ye,it,Q]),[De,Je]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem($E)??""}catch{return""}}),Xe=K!=null&&K.invokedAs&&K.invokedAs!==en?K.invokedAs:null,Mt=Xe!=null&&De!==Xe,lt=j.useCallback(()=>{if(Xe){Je(Xe);try{window.localStorage.setItem($E,Xe)}catch{}}},[Xe]),Qe=((Va=K==null?void 0:K.upgrade)==null?void 0:Va.state)??"idle",Ot=Z3(K==null?void 0:K.upgrade),zt=j.useCallback(async()=>{try{await fetch("/api/upgrade",{method:"POST"})}catch{}ve()},[ve]);j.useEffect(()=>{if(Qe!=="running")return;const H=window.setInterval(ve,3e3);return()=>window.clearInterval(H)},[Qe,ve]);const et=j.useCallback(async()=>{var oe;const H=K==null?void 0:K.command;if(!H)return;let Y=!1;try{Y=await Promise.race([((oe=navigator.clipboard)==null?void 0:oe.writeText(H).then(()=>!0))??Promise.resolve(!1),new Promise(de=>window.setTimeout(()=>de(!1),500))])}catch{Y=!1}if(!Y)try{const de=document.createElement("textarea");de.value=H,de.setAttribute("readonly",""),de.style.cssText="position:fixed;top:0;left:0;opacity:0",document.body.appendChild(de),de.select(),Y=document.execCommand("copy"),de.remove()}catch{Y=!1}Y&&(fe(!0),window.setTimeout(()=>fe(!1),1600))},[K==null?void 0:K.command]),bt=j.useCallback(()=>{I(H=>(H||D(!1),!H))},[]),ht=j.useCallback(()=>{D(H=>(H||I(!1),!H))},[]),[vt,hn]=j.useState(!1),[Gt,Pt]=j.useState(0),bn=j.useRef(null),[gr,Sn]=j.useState(!1),Bt=j.useRef(null),[Fn,pn]=j.useState(0),vr=j.useRef(g$()),[Hr,xi]=j.useState(!1),Wr=j.useCallback(()=>{const H=vr.current,Y=H.setPaused(!H.paused);for(const oe of Y)n.current=Fx(n.current,oe);xi(H.paused)},[]),[ut,_i]=j.useState(Date.now()),[mn,Is]=j.useState(()=>{if(typeof window>"u")return!0;try{return window.localStorage.getItem(DE)!=="0"}catch{return!0}}),yr=j.useCallback(()=>{Is(H=>{const Y=!H;try{window.localStorage.setItem(DE,Y?"1":"0")}catch{}return Y})},[]),[zn,kn]=j.useState(!1),[Vr,Gr]=j.useState("restart"),[Yr,bi]=j.useState(null),sr=j.useRef(!1),Ms=j.useRef(null),En=j.useRef(0),wr=j.useCallback(async H=>{if(sr.current)return;const Y=(H==null?void 0:H.upgrade)===!0;sr.current=!0,Ms.current=Ot;const oe=++En.current;Gr(Y?"npx":"restart"),kn(!0);try{window.sessionStorage.setItem("agent-dag.restartPending",(ye==null?void 0:ye.to)??"")}catch{}try{await fetch("/api/restart",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({upgrade:Y})})}catch{}window.setTimeout(()=>{if(En.current===oe&&sr.current){sr.current=!1,kn(!1);try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}}},Y?18e4:3e4)},[ye==null?void 0:ye.to,Ot]),Os=j.useRef(null);j.useEffect(()=>{let H=!1;for(const oe of n.current.agents.values())if(oe.state==="active"){H=!0;break}const Y=e$({enabled:mn,kind:ye==null?void 0:ye.kind,canRestart:(K==null?void 0:K.canRestart)===!0,busy:H,idleSince:Os.current,now:ut});Os.current=Y.idleSince,Y.restart&&wr()},[mn,ye==null?void 0:ye.kind,K==null?void 0:K.canRestart,ut,wr]),j.useEffect(()=>{const H=K==null?void 0:K.running;let Y=null,oe=null;try{Y=window.sessionStorage.getItem("agent-dag.restartPending"),oe=window.sessionStorage.getItem(FE)}catch{return}const de=Q3({bundle:"1.35.21",running:H,pending:Y,lastTried:oe});if(de==="reload"){try{window.sessionStorage.setItem(FE,H??"")}catch{return}window.location.reload();return}if(de!=="confirm")return;try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1),bi(H??null);const xe=window.setTimeout(()=>bi(null),6e3);return()=>window.clearTimeout(xe)},[K==null?void 0:K.running]),j.useEffect(()=>{if(zn&&J3({asked:Ms.current,reported:Ot})){try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1)}},[zn,Ot]);const Ps=j.useRef(H5()).current;j.useRef(!1);const Tt=j.useRef(new Map(Ps.positions.filter(([H])=>Ps.pins.includes(H)))),xr=j.useRef(null),_r=j.useState(()=>W5())[0],[Yt,Kr]=j.useState(""),[Si,nt]=j.useState(()=>new Set),[br,Xr]=j.useState(_$),[Ls,Qr]=j.useState(!1),Zr=j.useRef(null);j.useEffect(()=>{document.documentElement.dataset.theme=br;try{window.localStorage.setItem(OC,br)}catch{}},[br]),j.useEffect(()=>{if(!_r)return;const H=window.setTimeout(()=>{try{e.setViewport(_r,{duration:0})}catch{}},60);return()=>window.clearTimeout(H)},[e,_r]);const $s=j.useRef(!0);j.useEffect(()=>{const H=new EventSource("/events"),Y=m$(i,{now:()=>Date.now(),setTimeout:(oe,de)=>window.setTimeout(oe,de),clearTimeout:oe=>window.clearTimeout(oe)});return H.addEventListener("open",()=>{G(!0),Qr(!0)}),H.addEventListener("error",()=>G(!1)),H.addEventListener("replay-end",()=>{$s.current=!1,Y.flush()}),H.addEventListener("hook",oe=>{try{const de=JSON.parse(oe.data);if(!vr.current.accept(de))return;n.current=Fx(n.current,de),de.replay===!0||$s.current||Date.now()-de.receivedAt>3e4?Y.replay():Y.live()}catch{}}),()=>{H.close(),Y.cancel()}},[i]),j.useEffect(()=>{const H=setInterval(()=>{const Y=Date.now();_i(Y);let oe=mP(n.current,Y,Dx);gP(n.current,Y,Dx)&&(oe=!0),hP(n.current,Y,I5,M5)&&(oe=!0),pP(n.current,Y,O5,P5)&&(oe=!0),oe&&i()},250);return()=>clearInterval(H)},[i]);const ir=j.useRef(null),St=j.useRef(0),qs=420,pt=j.useCallback((H=500)=>{try{const Se=document.querySelector(".canvas-wrap"),Pe=Array.from(document.querySelectorAll(".react-flow__node")).filter(wt=>wt.offsetWidth>0);if(!Se||Pe.length===0)return;const Fe=Se.getBoundingClientRect(),Ge=e.getViewport();if(!Number.isFinite(Ge.zoom)||Ge.zoom<=0)return;const We=wt=>(wt-Fe.left-Ge.x)/Ge.zoom,ze=wt=>(wt-Fe.top-Ge.y)/Ge.zoom,Tn=Pe.map(wt=>wt.getBoundingClientRect()),Ys=Math.min(...Tn.map(wt=>We(wt.left))),Ao=Math.max(...Tn.map(wt=>We(wt.right))),Ks=Math.min(...Tn.map(wt=>ze(wt.top))),Io=Math.max(...Tn.map(wt=>ze(wt.bottom))),Xa=Ao-Ys,us=Io-Ks;if(!(Xa>0&&us>0))return;const Qt=Math.max(.2,Math.min(1,(Fe.width-160)/(Xa+qs)*.86,(Fe.height-160)/us*.86));e.setViewport({x:80-Ys*Qt,y:Math.max(80,(Fe.height-us*Qt)/2)-Ks*Qt,zoom:Qt},{duration:H}),St.current=Date.now(),window.setTimeout(()=>{try{const wt={x:80-Ys*Qt,y:Math.max(80,(Fe.height-us*Qt)/2)-Ks*Qt,zoom:Qt},Mo=e.getViewport();(Math.abs(Mo.zoom-Qt)>.01||Math.abs(Mo.x-wt.x)>2)&&e.setViewport(wt,{duration:0})}catch{}},H+60)}catch{}},[e]),ko=j.useRef(""),Eo=j.useRef(null),qa=j.useRef(0),Sr=j.useCallback(()=>{qa.current=Date.now()},[]),Jr="agent-dag.autoFitDisabled",gn=j.useRef((()=>{if(typeof window>"u")return!1;try{return window.localStorage.getItem(Jr)==="1"}catch{return!1}})()),[Ds,Da]=j.useState(gn.current),Fa=j.useCallback(()=>{if(!gn.current){gn.current=!0,Da(!0);try{window.localStorage.setItem(Jr,"1")}catch{}}},[]),No=j.useCallback(()=>{gn.current=!1,Da(!1);try{window.localStorage.removeItem(Jr)}catch{}pt(400)},[e,pt]);j.useEffect(()=>{const H=setInterval(()=>{if(gn.current||Date.now()-qa.current<800)return;const Y=n.current,oe=Date.now(),de=[];for(const We of Y.agents.values())Mv(We,oe)&&de.push({id:We.id});if(de.length===0)return;const xe=e.getViewport(),Se=window.innerWidth-360,Pe=window.innerHeight-52;let Fe=!1,Ge=!1;for(const{id:We}of de){const ze=or.current.get(We),Tn=Tt.current.get(We)??Kt.current.get(We);if(!ze||!Tn)continue;Ge=!0;const Ys=Tn.x*xe.zoom+xe.x,Ao=Tn.y*xe.zoom+xe.y,Ks=(Tn.x+ze.width)*xe.zoom+xe.x,Io=(Tn.y+ze.height)*xe.zoom+xe.y;if(Ks>0&&Ys<Se&&Io>0&&Ao<Pe){Fe=!0;break}}Ge&&!Fe&&pt(600)},1500);return()=>clearInterval(H)},[e]);const ki=j.useRef(!1),or=j.useRef(new Map),es=j.useRef(0),ec=j.useCallback(H=>{const Y=or.current;let oe=!1;for(const de of H.nodeInternals.values()){const xe=de.width,Se=de.height;if(xe==null||Se==null)continue;const Pe=Y.get(de.id);Pe?(Math.abs(Pe.height-Se)>4||Math.abs(Pe.width-xe)>4)&&(Y.set(de.id,{width:xe,height:Se}),oe=!0):(Y.set(de.id,{width:xe,height:Se}),oe=!0)}return oe&&(es.current+=1),es.current},[]),Ei=Ke(ec),[He,za]=j.useState(0);j.useEffect(()=>{let H=0;const Y=()=>{const de=or.current;let xe=!1;for(const Se of document.querySelectorAll(".react-flow__node[data-id]")){const Pe=Se.getAttribute("data-id");if(!Pe)continue;const Fe=Se.offsetWidth,Ge=Se.offsetHeight;if(!Fe||!Ge)continue;const We=de.get(Pe);(!We||Math.abs(We.width-Fe)>4||Math.abs(We.height-Ge)>4)&&(de.set(Pe,{width:Fe,height:Ge}),xe=!0)}xe&&za(Se=>Se+1)};if(ki.current)return;let oe=0;return document.visibilityState==="hidden"?oe=window.setTimeout(Y,32):H=requestAnimationFrame(Y),()=>{cancelAnimationFrame(H),window.clearTimeout(oe)}});const Kt=j.useRef(new Map(Ps.positions)),Co=j.useRef(new Set),Ni=j.useRef(""),kr=j.useMemo(()=>{const H=[];for(const Y of n.current.agents.values())Mv(Y,ut)&&H.push(Y.id+(Y.parentId?`>${Y.parentId}`:""));return H.sort(),`${H.join("|")}#sv${Ei}.${He}`},[n.current,n.current.lastSeq,ut,Ei,He]),ts=j.useRef(null);j.useEffect(()=>(ts.current!=null&&window.clearTimeout(ts.current),ts.current=window.setTimeout(()=>{dv(Kt.current,Tt.current)},1500),()=>{ts.current!=null&&window.clearTimeout(ts.current)}),[kr]),j.useEffect(()=>{if(ko.current===kr)return;const H=ko.current;if(ko.current=kr,!H||gn.current)return;Date.now()-St.current>1200&&pt(400),ir.current&&window.clearTimeout(ir.current),ir.current=window.setTimeout(()=>{gn.current||pt(500)},280)},[kr,e,pt]);const Fs=j.useMemo(()=>{if(o.size===0)return null;const H=new Set;for(const Y of o){const oe=Y5(n.current,Y);if(oe)for(const de of oe)H.add(de)}return H.size>0?H:null},[n.current,n.current.lastSeq,o]),Nn=j.useMemo(()=>o5(n.current,ut),[n.current,n.current.lastSeq,ut]),Bn=j.useRef(null),[vn,Un]=j.useState({w:0,h:0});j.useEffect(()=>{const H=Bn.current;if(!H||typeof ResizeObserver>"u")return;const Y=new ResizeObserver(oe=>{var xe;const de=(xe=oe[0])==null?void 0:xe.contentRect;de&&Un(Se=>Math.abs(Se.w-de.width)>40||Math.abs(Se.h-de.height)>40?{w:de.width,h:de.height}:Se)});return Y.observe(H),Un({w:H.clientWidth,h:H.clientHeight}),()=>Y.disconnect()},[]);const zs=j.useCallback(H=>{var oe,de;const Y=H.target;!(Y!=null&&Y.closest)||Y.closest(j5)!==H.currentTarget||(H.preventDefault(),(de=(oe=document.activeElement)==null?void 0:oe.blur)==null||de.call(oe))},[]),Bs=j.useRef(new Map),[Hn,tc]=j.useState(!1);j.useEffect(()=>{const H=window.setTimeout(()=>tc(!0),2500);return()=>window.clearTimeout(H)},[]);const[Ba,Er]=j.useState(!1),ar=j.useRef(null),[Ci,Us]=j.useState(!1),Ua=j.useCallback(()=>{ar.current&&(window.clearTimeout(ar.current),ar.current=null),Er(!1)},[]),nc=j.useCallback(H=>{H.length!==0&&queueMicrotask(()=>{Er(!0),ar.current&&window.clearTimeout(ar.current),ar.current=window.setTimeout(()=>Er(!1),A5+80)})},[]);j.useEffect(()=>()=>{ar.current&&window.clearTimeout(ar.current)},[]);const ns=vn.w>0?vn.w*.92:0,rs=vn.h>0?vn.h:0,{nodes:Xt,edges:Ti}=j.useMemo(()=>K5(n.current,ut,ns,rs,Tt.current,Yt,or.current,Bs.current,nc,Hn,Ci,Kt.current,Co.current,kr,Ni,o,Fs,Nn,b),[n.current,n.current.lastSeq,ut,ns,rs,Hn,Ci,Yt,kr,o,Fs,Nn,b,Gt]),Ha=j.useMemo(()=>{const H=new Map;for(const oe of Xt){const de=oe.data;if(!(de!=null&&de.sessionId)||de.exitAt!=null)continue;const xe=oe.width,Se=oe.height;if(xe==null||Se==null)continue;const Pe=oe.position.x,Fe=oe.position.y,Ge=Pe+xe,We=Fe+Se,ze=H.get(de.sessionId);ze?(ze.minX=Math.min(ze.minX,Pe),ze.minY=Math.min(ze.minY,Fe),ze.maxX=Math.max(ze.maxX,Ge),ze.maxY=Math.max(ze.maxY,We)):H.set(de.sessionId,{minX:Pe,minY:Fe,maxX:Ge,maxY:We})}const Y=[];for(const[oe,de]of H){const xe=de.maxX-de.minX+au*2,Se=de.maxY-de.minY+au*2;Y.push({id:`group:${oe}`,type:PT,position:{x:de.minX-au,y:de.minY-au},data:{sessionId:oe,w:xe,h:Se},width:xe,height:Se,style:{width:xe,height:Se},zIndex:-1,draggable:!0,selectable:!1,focusable:!1,deletable:!1,connectable:!1})}return Y},[Xt,ut]),rc=j.useMemo(()=>{const H=[...Ha,...Xt],Y=Bt.current;return!Y||Y.size===0?H:H.map(oe=>{const de=Y.get(oe.id);return de?{...oe,position:de}:oe})},[Ha,Xt,Fn]),Nr=j.useMemo(()=>{if(!Yt)return null;const H=new Set;for(const Y of n.current.agents.values())Nn.has(Y.id)&&qT(Y,Yt)&&H.add(Y.id);return H},[n.current,n.current.lastSeq,Yt,Nn]),Cn=j.useMemo(()=>k5(Yt,(Nr==null?void 0:Nr.size)??0,Nn.size),[Yt,Nr,Nn]),ss=j.useMemo(()=>{const H=new Set;for(const Y of n.current.agents.values())for(const oe of Y.tools)H.add(HT(oe.name));return Object.keys(Lv).filter(Y=>H.has(Y))},[n.current,n.current.lastSeq]);j.useEffect(()=>{if(ss.length<=1){Sn(!1);return}let H=0;const Y=()=>{const oe=bn.current;if(oe&&!document.hidden){const de=oe.getBoundingClientRect(),xe=Array.from(document.querySelectorAll(".react-flow__node, .tool-burst")).map(Pe=>Pe.getBoundingClientRect()),Se=l5(de,xe,8);Sn(Pe=>Pe===Se?Pe:Se)}H=window.setTimeout(Y,300)};return Y(),()=>window.clearTimeout(H)},[ss.length]);const is=j.useMemo(()=>{const H=new Map;for(const oe of n.current.agents.values())for(const de of oe.tools){if(!de.name.startsWith("mcp__"))continue;const xe=de.name.slice(5),Se=xe.indexOf("__"),Pe=Se>0?xe.slice(0,Se):xe;H.set(Pe,(H.get(Pe)??0)+1)}const Y=[];for(const[oe,de]of H){let xe=5381;for(let Se=0;Se<oe.length;Se++)xe=(xe<<5)+xe^oe.charCodeAt(Se);Y.push({server:oe,count:de,hue:Math.abs(xe)%360})}return Y.sort((oe,de)=>de.count-oe.count),Y},[n.current,n.current.lastSeq]),lr=j.useCallback(H=>{nt(Y=>{const oe=new Set(Y);return oe.has(H)?oe.delete(H):oe.add(H),oe})},[]),Rt=u?n.current.agents.get(u):null,os=h?Array.from(n.current.agents.values()).flatMap(H=>H.tools).find(H=>H.id===h)??null:null,To=j.useCallback(async()=>{try{await fetch("/api/clear",{method:"POST"})}catch{}n.current=Tv(),Tt.current.clear(),or.current.clear(),Kt.current.clear(),Ni.current="",BE(),m(),i()},[i,m]),Hs=j.useRef(S);Hs.current=S;const Ws=j.useRef(!1);Ws.current=os!=null||vt||N!=null||y!=null;const Vs=j.useCallback(H=>{const Y=n$(H,{confirmOpen:Hs.current,modalOpen:Ws.current});Y==="confirm"?k(!0):Y==="clear"&&(k(!1),To())},[To]),Lt=j.useCallback(()=>{Tt.current.clear(),Kt.current.clear(),Ni.current="",BE(),i(),window.setTimeout(()=>pt(500),80)},[i,e,pt]),Cr=j.useCallback(()=>pt(500),[pt]),as=j.useRef(Xt);as.current=Xt;const ls=j.useRef(u);ls.current=u;const Ro=j.useCallback(H=>{const Y=as.current,oe=s$(Y.map(Se=>({id:Se.id,x:Se.position.x,y:Se.position.y})),ls.current,H),de=oe?Y.find(Se=>Se.id===oe):void 0;if(!de)return;const xe=OE(document.activeElement);d(de.id,!1),window.setTimeout(()=>{try{e.fitView({padding:.35,duration:350,nodes:[de]})}catch{}St.current=Date.now(),xe&&R5(de.id)},30)},[d,e]),Ri=j.useCallback(H=>{d(H,!1),window.setTimeout(()=>{try{const Y=as.current.find(oe=>oe.id===H);Y&&e.fitView({padding:.3,duration:500,nodes:[Y]}),St.current=Date.now()}catch{}},60)},[d,e]);j.useEffect(()=>{const H=Y=>{var Fe,Ge,We;const oe=Y.target,de={tagName:oe==null?void 0:oe.tagName,isContentEditable:oe==null?void 0:oe.isContentEditable,role:(Fe=oe==null?void 0:oe.getAttribute)==null?void 0:Fe.call(oe,"role"),type:oe==null?void 0:oe.type};if(Y.key==="Escape"){const ze=PP({overlayOpen:Eu.depth()>0,typing:ry(de)});ze==="dismiss"?Eu.dismissTop():ze==="blur"?oe==null||oe.blur():(l$(de)&&(oe==null||oe.blur()),m());return}if(_C(Y))return;const xe=OE(oe)?(Ge=oe==null?void 0:oe.getAttribute)==null?void 0:Ge.call(oe,"data-id"):null,Se=xe&&as.current.some(ze=>ze.id===xe)?xe:null,Pe=o$(Y,Se);if(Pe.kind==="activate"){Y.preventDefault(),d(Pe.nodeId,Pe.additive);return}if(Pe.kind!=="node"&&!(Pe.nodeId==null&&UP(de))){if(Y.key==="/"){Y.preventDefault(),(We=Zr.current)==null||We.focus();return}Y.key===" "&&(Y.preventDefault(),Wr()),(Y.key==="c"||Y.key==="C")&&Vs("shortcut"),(Y.key==="r"||Y.key==="R")&&Lt(),(Y.key==="f"||Y.key==="F")&&Cr(),(Y.key==="l"||Y.key==="L")&&bt(),(Y.key==="h"||Y.key==="H")&&hn(ze=>!ze),(Y.key==="u"||Y.key==="U")&&z(ze=>!ze),(Y.key==="a"||Y.key==="A")&&Be.current.claude&&ht(),(Y.key==="j"||Y.key==="J")&&Ro(1),(Y.key==="k"||Y.key==="K")&&Ro(-1),(Y.key==="t"||Y.key==="T")&&Xr(ze=>ze==="dark"?"light":"dark")}};return window.addEventListener("keydown",H),()=>window.removeEventListener("keydown",H)},[Vs,Lt,Cr,m,d,Ro,Wr]);const Tr=n.current.agents.size,Gs=new Set(Array.from(n.current.agents.values()).map(H=>H.sessionId)).size,tn=j.useMemo(()=>JL(n.current.agents.values()),[n.current,n.current.lastSeq]),jo=j.useMemo(()=>e3(n.current.agents.values()),[n.current,n.current.lastSeq]),Wa=j.useRef(null);j.useEffect(()=>{const H=b$({waiting:tn.length,running:jo}),Y=Wa.current;if(Wa.current=H,(Y==null?void 0:Y.title)!==H.title&&(document.title=H.title),(Y==null?void 0:Y.icon)!==H.icon){const oe=document.querySelector('link[rel="icon"]');oe&&(oe.href=S$[H.icon])}},[tn.length,jo]);const[sc,ic]=j.useState(""),ji=E$(tn);j.useEffect(()=>{ic(H=>N$(H,ji))},[ji]);const nn=j.useMemo(()=>{let H=0,Y=0,oe=0,de=0,xe=0,Se=0,Pe=0,Fe=0,Ge=0;for(const We of n.current.agents.values()){H+=We.usage.inputTokens,Y+=We.usage.outputTokens,oe+=We.usage.cacheReadTokens,de+=We.usage.cacheCreateTokens;const ze=dn(We.usage,We.model);xe+=ze.total,Se+=ze.input,Pe+=ze.output,Fe+=ze.cacheRead,Ge+=ze.cacheWrite}return{inT:H,outT:Y,cacheR:oe,cacheC:de,sum:H+Y,cost:{total:xe,input:Se,output:Pe,cacheRead:Fe,cacheWrite:Ge}}},[n.current,n.current.lastSeq]);return g.jsxs("div",{className:"app",children:[g.jsx("a",{className:"skip-link",href:"#canvas",children:"Skip to the canvas"}),g.jsxs("header",{className:"topbar",children:[g.jsxs("div",{className:"brand",children:[g.jsx("span",{className:"logo"}),g.jsx("h1",{children:en}),ye?g.jsxs("button",{type:"button",className:"v stale",onClick:Ze,"aria-label":h5({...ye,open:ft}),title:ye.kind==="restart"?`Running v${ye.from}; v${ye.to} is installed on disk. Restart to pick it up.`:`Running v${ye.from}; v${ye.to} is on npm.`,children:["v",ye.from,g.jsx("span",{className:"v-dot","aria-hidden":!0})]}):(()=>{const H={running:(K==null?void 0:K.running)??"1.35.21",latest:K==null?void 0:K.latest,latestPending:K==null?void 0:K.latestPending,checkedAgo:K!=null&&K.checkedAt?Pv(ut-K.checkedAt):null,checkDisabled:K==null?void 0:K.checkDisabled,checking:ce};return g.jsxs("button",{type:"button",className:ce?"v checking":"v",onClick:()=>ve(!0),"aria-busy":ce||void 0,"aria-label":f5(H),title:d5(H),children:["v",H.running]})})()]}),Rt&&(()=>{const H=dn(Rt.usage,Rt.model),Y=Math.max(0,((Rt.endedAt??ut)-Rt.startedAt)/1e3),oe=Rt.state==="active"?ku(H.total,Y):null,de=o.size-1;return g.jsxs("button",{type:"button",className:"selected-ribbon",title:`Fit view to ${Rt.label}`,onClick:()=>{try{const xe=Xt.find(Se=>Se.id===Rt.id);xe&&e.fitView({padding:.35,duration:500,nodes:[xe]}),St.current=Date.now()}catch{}},children:[g.jsx("span",{className:`state-pill state-${Rt.state}`,children:Rt.state==="active"?"live":Rt.state}),g.jsx("span",{className:"selected-label",children:Rt.label}),H.total>0&&g.jsxs("span",{className:"selected-cost",children:[qe(H.total),oe?g.jsxs("span",{className:"selected-rate",children:[" · ",oe]}):null]}),de>0&&g.jsxs("span",{className:"selected-extra",children:["+",de]}),g.jsx("span",{"aria-hidden":!0,className:"selected-close",onClick:xe=>{xe.stopPropagation(),m()},children:"×"})]})})(),g.jsxs("div",{className:"actions",children:[g.jsxs("div",{className:"search",children:[g.jsx("span",{className:"search-icon","aria-hidden":!0,children:"⌕"}),g.jsx("input",{ref:Zr,type:"text",placeholder:E5,value:Yt,onChange:H=>Kr(H.target.value),spellCheck:!1,"aria-label":"Filter the graph"}),Yt?g.jsx("button",{className:"search-clear","aria-label":"Clear search",onClick:()=>Kr(""),children:"×"}):g.jsx("kbd",{className:"search-kbd","aria-hidden":!0,children:"/"}),Cn.count&&g.jsx("span",{className:`search-count${Cn.empty?" none":""}`,"aria-live":"polite",title:`${Cn.count} agents on the canvas match “${Yt}”`,children:Cn.count})]}),g.jsxs("span",{className:"status",children:[(()=>{const H=b5({connected:M,paused:Hr,held:vr.current.size});return g.jsx("span",{className:`pill ${H.tone}`,title:H.title,children:H.label})})(),g.jsxs("span",{className:"stat",title:y5(we),children:[g.jsx("span",{className:"count",children:Gs}),g.jsx("span",{className:"lbl",children:"sessions"})]}),g.jsxs("span",{className:"stat",title:"Total agents (root + subagents)",children:[g.jsx("span",{className:"count",children:Tr}),g.jsx("span",{className:"lbl",children:"agents"})]}),g.jsxs("span",{className:"stat",title:w5(we),children:[g.jsx("span",{className:"count",children:n.current.totalEvents}),g.jsx("span",{className:"lbl",children:"events"})]}),nn.sum>0&&g.jsxs("span",{className:"stat",title:`in:${nn.inT.toLocaleString()} out:${nn.outT.toLocaleString()} cache-r:${nn.cacheR.toLocaleString()} cache-c:${nn.cacheC.toLocaleString()}`,children:[g.jsx("span",{className:"count",children:Dt(nn.sum)}),g.jsx("span",{className:"lbl",children:"tokens"})]}),is.length>0&&g.jsxs("span",{className:"stat mcp-legend",title:`MCP servers seen this session:
|
|
73
73
|
${is.map(H=>` ${H.server}: ${H.count} call${H.count===1?"":"s"}`).join(`
|
|
74
74
|
`)}`,children:[is.slice(0,6).map(H=>g.jsx("span",{className:"mcp-dot",style:{"--mcp-hue":H.hue}},H.server)),is.length>6&&g.jsxs("span",{className:"mcp-more",children:["+",is.length-6]}),g.jsx("span",{className:"lbl",children:"mcp"})]}),nn.cost.total>0&&(()=>{let H=0,Y=0;for(const xe of n.current.agents.values()){if(xe.state!=="active")continue;const Se=dn(xe.usage,xe.model);H+=Se.total,Y=Math.max(Y,((xe.endedAt??ut)-xe.startedAt)/1e3)}const oe=Y>0?ku(H,Y):null,de=`input ${qe(nn.cost.input)} + output ${qe(nn.cost.output)} + cache r ${qe(nn.cost.cacheRead)} + cache w ${qe(nn.cost.cacheWrite)}${oe?`
|
|
75
75
|
active burn: ${oe}`:""}`;return g.jsxs("span",{className:"stat",title:de,children:[g.jsx("span",{className:"count",children:qe(nn.cost.total)}),g.jsxs("span",{className:"lbl",children:["cost",oe?` · ${oe}`:""]})]})})()]}),g.jsx("div",{className:"vis-hidden",role:"status","aria-atomic":"true",children:sc}),tn.length>0&&g.jsxs("button",{type:"button",className:"waiting-stat",onClick:()=>Ri(tn[0].id),title:`Blocked waiting for you — click to go to the one that has been stuck longest:
|
package/dist/web/index.html
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
document.documentElement.setAttribute("data-theme", stored === "light" ? "light" : "dark");
|
|
41
41
|
})();
|
|
42
42
|
</script>
|
|
43
|
-
<script type="module" crossorigin src="/assets/index-
|
|
43
|
+
<script type="module" crossorigin src="/assets/index-DGYih2FE.js"></script>
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/index-hLBidJXz.css">
|
|
45
45
|
</head>
|
|
46
46
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "1.35.
|
|
3
|
+
"version": "1.35.21",
|
|
4
4
|
"description": "Live deck of Claude Code and Codex agents — watch tool calls, token spend and every Claude Code subagent on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/server/index.mjs
CHANGED
|
@@ -2205,9 +2205,31 @@ async function handleRestart(req, res) {
|
|
|
2205
2205
|
|
|
2206
2206
|
if (_restarting) return send(res, 202, { ok: true, already: true });
|
|
2207
2207
|
_restarting = true;
|
|
2208
|
-
|
|
2208
|
+
// Accepted either way — the ask is good and the launcher holds on to it — but
|
|
2209
|
+
// the two are not the same event and answering 200 to both would be this
|
|
2210
|
+
// window's second untruth rather than its first. Between this listener
|
|
2211
|
+
// accepting its first connection and bin/deck.js finishing the rest of its
|
|
2212
|
+
// startup there is a real stretch during which a restart cannot be run yet,
|
|
2213
|
+
// and a caller that reads the body should be able to tell that it is waiting
|
|
2214
|
+
// on a boot rather than on a supervisor. See markDeckReady, and requestRestart
|
|
2215
|
+
// in bin/deck.js for the half that does the waiting.
|
|
2216
|
+
if (_deckReady) send(res, 200, { ok: true, mode });
|
|
2217
|
+
else send(res, 202, { ok: true, mode, booting: true, detail: "the deck is still starting up; the restart runs as soon as it has finished booting" });
|
|
2209
2218
|
// Let the response flush before the listener goes away.
|
|
2210
|
-
setTimeout(() => {
|
|
2219
|
+
setTimeout(() => {
|
|
2220
|
+
try { _onRestart(mode); }
|
|
2221
|
+
catch (err) {
|
|
2222
|
+
// This catch is where #448 lived: it released the server's half of the
|
|
2223
|
+
// latch and said nothing, while the launcher's half stayed set with
|
|
2224
|
+
// nothing left to clear it, and every later restart answered "ok" and did
|
|
2225
|
+
// nothing for the rest of the process's life. The launcher now owns its
|
|
2226
|
+
// own failures; this stays as the outer net, and it says so — one line,
|
|
2227
|
+
// message only, because the terminal underneath is repainted every 800ms
|
|
2228
|
+
// by the pulse and a stack dumped into it is a stack nobody can read.
|
|
2229
|
+
_restarting = false;
|
|
2230
|
+
console.error(`${PRODUCT}: restart request failed: ${err?.message ?? err}`);
|
|
2231
|
+
}
|
|
2232
|
+
}, 120).unref();
|
|
2211
2233
|
}
|
|
2212
2234
|
|
|
2213
2235
|
/** The other end of the latch above, for the upgrade that never happened.
|
|
@@ -2221,6 +2243,22 @@ export function releaseRestart() {
|
|
|
2221
2243
|
_restarting = false;
|
|
2222
2244
|
}
|
|
2223
2245
|
|
|
2246
|
+
/** The launcher saying its boot is over: everything a shutdown would have to
|
|
2247
|
+
* tear down now exists.
|
|
2248
|
+
*
|
|
2249
|
+
* This server starts accepting from inside startServer, before that call has
|
|
2250
|
+
* even returned to bin/deck.js — so /api/restart is answerable for the whole
|
|
2251
|
+
* of the startup that follows it, which on a cold boot includes the discovery
|
|
2252
|
+
* file's first fsynced write and spawning the browser. The listener cannot see
|
|
2253
|
+
* any of that from here; it has to be told. Called once, from bin/deck.js.
|
|
2254
|
+
*
|
|
2255
|
+
* Only /api/restart reads it, and only to answer honestly. Nothing is refused
|
|
2256
|
+
* on the strength of it: the restart is still handed to the launcher, which
|
|
2257
|
+
* holds it until it can run it (#448). */
|
|
2258
|
+
export function markDeckReady() {
|
|
2259
|
+
_deckReady = true;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2224
2262
|
async function handleQuota(req, res) {
|
|
2225
2263
|
const { fetchClaudeQuota } = await import(
|
|
2226
2264
|
pathToFileURL(join(PKG_ROOT, "src/server/quota.mjs")).href
|
|
@@ -2878,10 +2916,19 @@ let _onRestart = null;
|
|
|
2878
2916
|
// A restart is in flight. Several browser tabs watching the same deck will each
|
|
2879
2917
|
// ask; the second ask must not re-enter the shutdown.
|
|
2880
2918
|
let _restarting = false;
|
|
2919
|
+
// Whether the launcher has finished booting — see markDeckReady. False for the
|
|
2920
|
+
// whole window between this listener accepting its first connection and
|
|
2921
|
+
// bin/deck.js reaching the end of its startup, which is a window /api/restart
|
|
2922
|
+
// is reachable in and cannot answer for on its own.
|
|
2923
|
+
let _deckReady = false;
|
|
2881
2924
|
|
|
2882
2925
|
export async function startServer({ port = 4317, host = "127.0.0.1", persist = null, portRange = [4318, 4400], workspace = "", codex = true, claude = true, onRestart = null } = {}) {
|
|
2883
2926
|
_onRestart = typeof onRestart === "function" ? onRestart : null;
|
|
2884
2927
|
_canRestart = _onRestart != null && persist != null;
|
|
2928
|
+
// A new listener is a new boot, whatever a previous one had got as far as
|
|
2929
|
+
// reporting. Nothing but bin/deck.js ever sets this, and it does so once, at
|
|
2930
|
+
// the end of the startup that begins with this call.
|
|
2931
|
+
_deckReady = false;
|
|
2885
2932
|
_workspace = typeof workspace === "string" ? workspace : "";
|
|
2886
2933
|
// `!== false` rather than a cast: a caller that omits the field means "yes",
|
|
2887
2934
|
// which is how every embedder that predates this option keeps working.
|