@neotx/cli 0.1.0-alpha.2 → 0.1.0-alpha.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/README.md +383 -0
- package/dist/activity-LWUVGQVN.js +86 -0
- package/dist/activity-LWUVGQVN.js.map +1 -0
- package/dist/{agents-Y6LREFXP.js → agents-PH3P7G7E.js} +2 -2
- package/dist/{chunk-CP54H7WA.js → chunk-3ZP3BQXB.js} +6 -11
- package/dist/chunk-3ZP3BQXB.js.map +1 -0
- package/dist/{chunk-TNJOG54I.js → chunk-F622JUDY.js} +6 -2
- package/dist/{chunk-TNJOG54I.js.map → chunk-F622JUDY.js.map} +1 -1
- package/dist/config-NYF6AJXU.js +282 -0
- package/dist/config-NYF6AJXU.js.map +1 -0
- package/dist/{cost-DNGKT4UC.js → cost-OQGFNBBG.js} +3 -8
- package/dist/cost-OQGFNBBG.js.map +1 -0
- package/dist/daemon/supervisor-worker.js +7 -1
- package/dist/daemon/supervisor-worker.js.map +1 -1
- package/dist/daemon/worker.js +31 -12
- package/dist/daemon/worker.js.map +1 -1
- package/dist/decision-PNZ2S2TU.js +362 -0
- package/dist/decision-PNZ2S2TU.js.map +1 -0
- package/dist/doctor-ZBO73UID.js +337 -0
- package/dist/doctor-ZBO73UID.js.map +1 -0
- package/dist/guide-UQRNA3FC.js +23 -0
- package/dist/guide-UQRNA3FC.js.map +1 -0
- package/dist/index.js +17 -9
- package/dist/index.js.map +1 -1
- package/dist/{init-YNSPTCA3.js → init-UYS6KS5U.js} +4 -20
- package/dist/init-UYS6KS5U.js.map +1 -0
- package/dist/log-PTHLI7ZN.js +141 -0
- package/dist/log-PTHLI7ZN.js.map +1 -0
- package/dist/{mcp-GH6CCW7A.js → mcp-XHZND5A4.js} +6 -1
- package/dist/mcp-XHZND5A4.js.map +1 -0
- package/dist/memory-6R22DFS7.js +292 -0
- package/dist/memory-6R22DFS7.js.map +1 -0
- package/dist/{run-KIU2ZE72.js → run-OF53USMD.js} +46 -20
- package/dist/run-OF53USMD.js.map +1 -0
- package/dist/{runs-CHA2JM5K.js → runs-TAASM3YF.js} +16 -12
- package/dist/runs-TAASM3YF.js.map +1 -0
- package/dist/status-LQOFOJJI.js +90 -0
- package/dist/status-LQOFOJJI.js.map +1 -0
- package/dist/{supervise-KIB2EYY4.js → supervise-J3GYBSOC.js} +33 -28
- package/dist/supervise-J3GYBSOC.js.map +1 -0
- package/dist/supervisor-3RUX5SPH.js +16 -0
- package/dist/supervisor-3RUX5SPH.js.map +1 -0
- package/dist/{tui-QS3RPHKH.js → tui-RYLR4OLF.js} +378 -43
- package/dist/tui-RYLR4OLF.js.map +1 -0
- package/dist/version-XVOAMGDD.js +26 -0
- package/dist/version-XVOAMGDD.js.map +1 -0
- package/dist/webhooks-PUKAHFHE.js +151 -0
- package/dist/webhooks-PUKAHFHE.js.map +1 -0
- package/package.json +22 -4
- package/dist/chunk-CP54H7WA.js.map +0 -1
- package/dist/cost-DNGKT4UC.js.map +0 -1
- package/dist/doctor-GC4NH7H6.js +0 -173
- package/dist/doctor-GC4NH7H6.js.map +0 -1
- package/dist/init-YNSPTCA3.js.map +0 -1
- package/dist/mcp-GH6CCW7A.js.map +0 -1
- package/dist/run-KIU2ZE72.js.map +0 -1
- package/dist/runs-CHA2JM5K.js.map +0 -1
- package/dist/supervise-KIB2EYY4.js.map +0 -1
- package/dist/tui-QS3RPHKH.js.map +0 -1
- /package/dist/{agents-Y6LREFXP.js.map → agents-PH3P7G7E.js.map} +0 -0
|
@@ -4,11 +4,17 @@ import React from "react";
|
|
|
4
4
|
|
|
5
5
|
// src/tui/supervisor-tui.tsx
|
|
6
6
|
import { randomUUID } from "crypto";
|
|
7
|
-
import { appendFile, readFile } from "fs/promises";
|
|
7
|
+
import { appendFile, mkdir, readFile } from "fs/promises";
|
|
8
|
+
import path from "path";
|
|
8
9
|
import {
|
|
10
|
+
DecisionStore,
|
|
9
11
|
getSupervisorActivityPath,
|
|
12
|
+
getSupervisorDecisionsPath,
|
|
13
|
+
getSupervisorDir,
|
|
10
14
|
getSupervisorInboxPath,
|
|
11
|
-
getSupervisorStatePath
|
|
15
|
+
getSupervisorStatePath,
|
|
16
|
+
loadGlobalConfig,
|
|
17
|
+
MemoryStore
|
|
12
18
|
} from "@neotx/core";
|
|
13
19
|
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
|
14
20
|
import TextInput from "ink-text-input";
|
|
@@ -283,39 +289,195 @@ function ActivityRow({
|
|
|
283
289
|
/* @__PURE__ */ jsx(Text, { dimColor: isOld, children: formatTime(entry.timestamp) }),
|
|
284
290
|
/* @__PURE__ */ jsx(Text, { color, dimColor: isOld, bold: isLatest, children: icon }),
|
|
285
291
|
/* @__PURE__ */ jsx(Text, { color, dimColor: isOld, bold: true, children: label }),
|
|
286
|
-
/* @__PURE__ */ jsx(Text, { dimColor: isOld, bold: isLatest,
|
|
292
|
+
/* @__PURE__ */ jsx(Text, { dimColor: isOld, bold: isLatest, children: entry.summary })
|
|
287
293
|
] });
|
|
288
294
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
var TASK_STATUS_COLORS = {
|
|
296
|
+
in_progress: "#60a5fa",
|
|
297
|
+
blocked: "#f87171",
|
|
298
|
+
pending: "#6b7280",
|
|
299
|
+
done: "#4ade80"
|
|
300
|
+
};
|
|
301
|
+
var TASK_STATUS_LABELS = {
|
|
302
|
+
in_progress: "ACTIVE",
|
|
303
|
+
blocked: "BLOCK",
|
|
304
|
+
pending: "\xB7"
|
|
305
|
+
};
|
|
306
|
+
function TaskPanel({ tasks }) {
|
|
307
|
+
const active = tasks.filter((t) => t.outcome !== "done" && t.outcome !== "abandoned");
|
|
308
|
+
const doneCount = tasks.filter((t) => t.outcome === "done").length;
|
|
309
|
+
if (tasks.length === 0) return null;
|
|
310
|
+
const MAX_VISIBLE = 6;
|
|
311
|
+
const visible = active.slice(0, MAX_VISIBLE);
|
|
312
|
+
const overflow = active.length - visible.length;
|
|
299
313
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
300
314
|
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
301
315
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
|
|
302
|
-
/* @__PURE__ */
|
|
303
|
-
|
|
304
|
-
"
|
|
305
|
-
|
|
316
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, bold: true, children: "TASKS" }),
|
|
317
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
318
|
+
"(",
|
|
319
|
+
active.length,
|
|
320
|
+
" active, ",
|
|
321
|
+
doneCount,
|
|
322
|
+
" done)"
|
|
306
323
|
] }),
|
|
307
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(
|
|
324
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(30) })
|
|
308
325
|
] }),
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
326
|
+
visible.map((t) => {
|
|
327
|
+
const status = t.outcome ?? "pending";
|
|
328
|
+
const color = TASK_STATUS_COLORS[status] ?? "#6b7280";
|
|
329
|
+
const label = (TASK_STATUS_LABELS[status] ?? "\xB7").padEnd(6);
|
|
330
|
+
const prio = t.severity ? `[${t.severity.slice(0, 3)}] ` : "";
|
|
331
|
+
const repo = t.scope !== "global" ? path.basename(t.scope) : "";
|
|
332
|
+
const run = t.runId ? `run:${t.runId.slice(0, 4)}` : "";
|
|
333
|
+
const meta = [repo, run].filter(Boolean).join(" ");
|
|
334
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, paddingX: 2, children: [
|
|
335
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
336
|
+
/* @__PURE__ */ jsx(Text, { color, bold: true, children: label }),
|
|
337
|
+
prio && /* @__PURE__ */ jsx(Text, { dimColor: true, children: prio.padEnd(5) }),
|
|
338
|
+
/* @__PURE__ */ jsx(Text, { wrap: "truncate", children: t.content }),
|
|
339
|
+
meta && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
340
|
+
"(",
|
|
341
|
+
meta,
|
|
342
|
+
")"
|
|
343
|
+
] })
|
|
344
|
+
] }, t.id);
|
|
345
|
+
}),
|
|
346
|
+
overflow > 0 && /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
347
|
+
"\u2502 ... +",
|
|
348
|
+
overflow,
|
|
349
|
+
" more pending"
|
|
350
|
+
] }) })
|
|
351
|
+
] });
|
|
352
|
+
}
|
|
353
|
+
function DecisionBanner({ decisions, frame }) {
|
|
354
|
+
if (decisions.length === 0) return null;
|
|
355
|
+
const pulseChars = ["\u2605", "\u2606"];
|
|
356
|
+
const pulse = pulseChars[frame % pulseChars.length];
|
|
357
|
+
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
358
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
|
|
359
|
+
/* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
|
|
360
|
+
pulse,
|
|
361
|
+
" ",
|
|
362
|
+
decisions.length,
|
|
363
|
+
" decision",
|
|
364
|
+
decisions.length > 1 ? "s" : "",
|
|
365
|
+
" pending"
|
|
312
366
|
] }),
|
|
313
|
-
/* @__PURE__ */
|
|
367
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
368
|
+
"\u2014 press ",
|
|
369
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
|
|
370
|
+
" to review"
|
|
371
|
+
] })
|
|
314
372
|
] });
|
|
315
373
|
}
|
|
374
|
+
function DecisionInputPanel({
|
|
375
|
+
decision,
|
|
376
|
+
optionIndex,
|
|
377
|
+
isTextMode,
|
|
378
|
+
textInput,
|
|
379
|
+
onTextChange,
|
|
380
|
+
onSubmit,
|
|
381
|
+
decisionCount,
|
|
382
|
+
decisionIdx,
|
|
383
|
+
frame
|
|
384
|
+
}) {
|
|
385
|
+
const hasOptions = decision.options && decision.options.length > 0;
|
|
386
|
+
const pulseChars = ["\u2605", "\u2606"];
|
|
387
|
+
const pulse = pulseChars[frame % pulseChars.length];
|
|
388
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
389
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
390
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
|
|
391
|
+
/* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
|
|
392
|
+
pulse,
|
|
393
|
+
" DECISION"
|
|
394
|
+
] }),
|
|
395
|
+
decisionCount > 1 && /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", children: [
|
|
396
|
+
"(",
|
|
397
|
+
decisionIdx + 1,
|
|
398
|
+
"/",
|
|
399
|
+
decisionCount,
|
|
400
|
+
")"
|
|
401
|
+
] }),
|
|
402
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(30) })
|
|
403
|
+
] }),
|
|
404
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
405
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
406
|
+
/* @__PURE__ */ jsx(Text, { bold: true, wrap: "truncate-end", children: decision.question })
|
|
407
|
+
] }),
|
|
408
|
+
decision.context && /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
409
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
410
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: decision.context })
|
|
411
|
+
] }),
|
|
412
|
+
hasOptions ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: (decision.options ?? []).map((opt, idx) => {
|
|
413
|
+
const isSelected = idx === optionIndex;
|
|
414
|
+
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
415
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
416
|
+
isSelected ? /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
|
|
417
|
+
"\u25B8 ",
|
|
418
|
+
opt.label
|
|
419
|
+
] }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
420
|
+
" ",
|
|
421
|
+
opt.label
|
|
422
|
+
] }),
|
|
423
|
+
opt.description && isSelected && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
424
|
+
"\u2014 ",
|
|
425
|
+
opt.description
|
|
426
|
+
] })
|
|
427
|
+
] }, opt.key);
|
|
428
|
+
}) }) : /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
429
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
430
|
+
/* @__PURE__ */ jsx(Text, { color: "#fbbf24", bold: true, children: "\u276F" }),
|
|
431
|
+
/* @__PURE__ */ jsx(
|
|
432
|
+
TextInput,
|
|
433
|
+
{
|
|
434
|
+
value: textInput,
|
|
435
|
+
onChange: onTextChange,
|
|
436
|
+
onSubmit,
|
|
437
|
+
focus: isTextMode,
|
|
438
|
+
placeholder: "type your answer..."
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
] }),
|
|
442
|
+
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
443
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2514" }),
|
|
444
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
445
|
+
hasOptions ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
446
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "\u2191\u2193" }),
|
|
447
|
+
" choose \xB7 ",
|
|
448
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
|
|
449
|
+
" confirm"
|
|
450
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
451
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
|
|
452
|
+
" send"
|
|
453
|
+
] }),
|
|
454
|
+
decisionCount > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
455
|
+
" \xB7 ",
|
|
456
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "\u2190\u2192" }),
|
|
457
|
+
" prev/next"
|
|
458
|
+
] }),
|
|
459
|
+
" \xB7 ",
|
|
460
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
|
|
461
|
+
" chat \xB7 ",
|
|
462
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "esc" }),
|
|
463
|
+
" back"
|
|
464
|
+
] })
|
|
465
|
+
] })
|
|
466
|
+
] });
|
|
467
|
+
}
|
|
468
|
+
var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
469
|
+
"heartbeat",
|
|
470
|
+
"decision",
|
|
471
|
+
"action",
|
|
472
|
+
"dispatch",
|
|
473
|
+
"error",
|
|
474
|
+
"event",
|
|
475
|
+
"message"
|
|
476
|
+
]);
|
|
316
477
|
function ActivityPanel({ entries, termHeight }) {
|
|
317
|
-
const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight -
|
|
318
|
-
const
|
|
478
|
+
const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 10));
|
|
479
|
+
const filtered = entries.filter((e) => ACTIVITY_TYPES.has(e.type));
|
|
480
|
+
const visible = filtered.slice(-maxVisible);
|
|
319
481
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
320
482
|
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
321
483
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
|
|
@@ -338,7 +500,8 @@ function InputPanel({
|
|
|
338
500
|
value,
|
|
339
501
|
onChange,
|
|
340
502
|
onSubmit,
|
|
341
|
-
lastSent
|
|
503
|
+
lastSent,
|
|
504
|
+
focus
|
|
342
505
|
}) {
|
|
343
506
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
344
507
|
/* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
|
|
@@ -350,6 +513,7 @@ function InputPanel({
|
|
|
350
513
|
value,
|
|
351
514
|
onChange,
|
|
352
515
|
onSubmit,
|
|
516
|
+
focus,
|
|
353
517
|
placeholder: "message the supervisor..."
|
|
354
518
|
}
|
|
355
519
|
)
|
|
@@ -364,7 +528,7 @@ function InputPanel({
|
|
|
364
528
|
] })
|
|
365
529
|
] });
|
|
366
530
|
}
|
|
367
|
-
function Footer() {
|
|
531
|
+
function Footer({ hasDecisions }) {
|
|
368
532
|
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, justifyContent: "center", children: [
|
|
369
533
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
370
534
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "esc" }),
|
|
@@ -375,6 +539,13 @@ function Footer() {
|
|
|
375
539
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
|
|
376
540
|
" send"
|
|
377
541
|
] }),
|
|
542
|
+
hasDecisions && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
543
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
544
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
545
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
|
|
546
|
+
" decisions"
|
|
547
|
+
] })
|
|
548
|
+
] }),
|
|
378
549
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
379
550
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "daemon keeps running" })
|
|
380
551
|
] });
|
|
@@ -404,16 +575,62 @@ async function readActivity(name, maxEntries) {
|
|
|
404
575
|
return [];
|
|
405
576
|
}
|
|
406
577
|
}
|
|
407
|
-
|
|
408
|
-
|
|
578
|
+
function readTasks(name) {
|
|
579
|
+
try {
|
|
580
|
+
const dir = getSupervisorDir(name);
|
|
581
|
+
const store = new MemoryStore(path.join(dir, "memory.sqlite"));
|
|
582
|
+
const tasks = store.query({ types: ["task"], limit: 20, sortBy: "createdAt" });
|
|
583
|
+
store.close();
|
|
584
|
+
return tasks;
|
|
585
|
+
} catch {
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
async function readDecisions(name) {
|
|
590
|
+
try {
|
|
591
|
+
const store = new DecisionStore(getSupervisorDecisionsPath(name));
|
|
592
|
+
return await store.pending();
|
|
593
|
+
} catch {
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
async function appendToJsonl(filePath, data) {
|
|
598
|
+
const dir = path.dirname(filePath);
|
|
599
|
+
try {
|
|
600
|
+
await mkdir(dir, { recursive: true });
|
|
601
|
+
await appendFile(filePath, `${JSON.stringify(data)}
|
|
602
|
+
`, "utf-8");
|
|
603
|
+
return true;
|
|
604
|
+
} catch (error) {
|
|
605
|
+
console.error(
|
|
606
|
+
`Warning: Failed to write to ${path.basename(filePath)}: ${error instanceof Error ? error.message : String(error)}`
|
|
607
|
+
);
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async function writeToInbox(name, message) {
|
|
612
|
+
const inboxPath = getSupervisorInboxPath(name);
|
|
613
|
+
return appendToJsonl(inboxPath, message);
|
|
614
|
+
}
|
|
615
|
+
async function answerDecision(name, id, answer) {
|
|
616
|
+
const store = new DecisionStore(getSupervisorDecisionsPath(name));
|
|
617
|
+
await store.answer(id, answer);
|
|
618
|
+
const inboxMessage = {
|
|
409
619
|
id: randomUUID(),
|
|
410
620
|
from: "tui",
|
|
411
|
-
text
|
|
621
|
+
text: `decision:answer ${id} ${answer}`,
|
|
412
622
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
413
623
|
};
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
624
|
+
await writeToInbox(name, inboxMessage);
|
|
625
|
+
}
|
|
626
|
+
async function sendMessage(name, text) {
|
|
627
|
+
const id = randomUUID();
|
|
628
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
629
|
+
const message = { id, from: "tui", text, timestamp };
|
|
630
|
+
await writeToInbox(name, message);
|
|
631
|
+
const activityEntry = { id, type: "message", summary: text, timestamp };
|
|
632
|
+
const activityPath = getSupervisorActivityPath(name);
|
|
633
|
+
await appendToJsonl(activityPath, activityEntry);
|
|
417
634
|
}
|
|
418
635
|
function SupervisorTui({ name }) {
|
|
419
636
|
const { exit } = useApp();
|
|
@@ -422,9 +639,16 @@ function SupervisorTui({ name }) {
|
|
|
422
639
|
const clock = useClock();
|
|
423
640
|
const [state, setState] = useState(null);
|
|
424
641
|
const [entries, setEntries] = useState([]);
|
|
642
|
+
const [tasks, setTasks] = useState([]);
|
|
643
|
+
const [decisions, setDecisions] = useState([]);
|
|
644
|
+
const [dailyCap, setDailyCap] = useState(50);
|
|
425
645
|
const [input, setInput] = useState("");
|
|
426
646
|
const [lastSent, setLastSent] = useState("");
|
|
427
647
|
const [termHeight, setTermHeight] = useState(stdout?.rows ?? 30);
|
|
648
|
+
const [decisionIndex, setDecisionIndex] = useState(0);
|
|
649
|
+
const [optionIndex, setOptionIndex] = useState(0);
|
|
650
|
+
const [decisionAnswer, setDecisionAnswer] = useState("");
|
|
651
|
+
const [focusMode, setFocusMode] = useState("input");
|
|
428
652
|
useEffect(() => {
|
|
429
653
|
function onResize() {
|
|
430
654
|
if (stdout) setTermHeight(stdout.rows);
|
|
@@ -434,17 +658,34 @@ function SupervisorTui({ name }) {
|
|
|
434
658
|
stdout?.off("resize", onResize);
|
|
435
659
|
};
|
|
436
660
|
}, [stdout]);
|
|
661
|
+
useEffect(() => {
|
|
662
|
+
loadGlobalConfig().then((cfg) => setDailyCap(cfg.supervisor.dailyCapUsd)).catch((err) => {
|
|
663
|
+
console.debug("[tui] Failed to load global config:", err);
|
|
664
|
+
});
|
|
665
|
+
}, []);
|
|
437
666
|
useEffect(() => {
|
|
438
667
|
let active = true;
|
|
439
668
|
async function poll() {
|
|
440
669
|
if (!active) return;
|
|
441
|
-
const [newState, newEntries] = await Promise.all([
|
|
670
|
+
const [newState, newEntries, newDecisions] = await Promise.all([
|
|
442
671
|
readState(name),
|
|
443
|
-
readActivity(name, MAX_VISIBLE_ENTRIES)
|
|
672
|
+
readActivity(name, MAX_VISIBLE_ENTRIES),
|
|
673
|
+
readDecisions(name)
|
|
444
674
|
]);
|
|
445
675
|
if (!active) return;
|
|
446
676
|
setState(newState);
|
|
447
677
|
setEntries(newEntries);
|
|
678
|
+
setDecisions(newDecisions);
|
|
679
|
+
setTasks(readTasks(name));
|
|
680
|
+
if (newDecisions.length > 0 && decisionIndex >= newDecisions.length) {
|
|
681
|
+
setDecisionIndex(0);
|
|
682
|
+
}
|
|
683
|
+
if (newDecisions.length > 0 && decisions.length === 0) {
|
|
684
|
+
setFocusMode("decisions");
|
|
685
|
+
}
|
|
686
|
+
if (newDecisions.length === 0 && decisions.length > 0) {
|
|
687
|
+
setFocusMode("input");
|
|
688
|
+
}
|
|
448
689
|
}
|
|
449
690
|
poll();
|
|
450
691
|
const interval = setInterval(poll, POLL_INTERVAL_MS);
|
|
@@ -452,10 +693,67 @@ function SupervisorTui({ name }) {
|
|
|
452
693
|
active = false;
|
|
453
694
|
clearInterval(interval);
|
|
454
695
|
};
|
|
455
|
-
}, [name]);
|
|
456
|
-
|
|
696
|
+
}, [name, decisionIndex, decisions.length]);
|
|
697
|
+
const currentDecision = decisions[decisionIndex];
|
|
698
|
+
const currentHasOptions = (currentDecision?.options?.length ?? 0) > 0;
|
|
699
|
+
const submitDecisionAnswer = useCallback(
|
|
700
|
+
async (answer) => {
|
|
701
|
+
if (!answer.trim() || !currentDecision) return;
|
|
702
|
+
try {
|
|
703
|
+
await answerDecision(name, currentDecision.id, answer.trim());
|
|
704
|
+
setLastSent(`Decision ${currentDecision.id.slice(4, 12)}: "${answer.trim()}"`);
|
|
705
|
+
setDecisionAnswer("");
|
|
706
|
+
setOptionIndex(0);
|
|
707
|
+
} catch {
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
[name, currentDecision]
|
|
711
|
+
);
|
|
712
|
+
const handleOptionNav = useCallback(
|
|
713
|
+
(key) => {
|
|
714
|
+
const options = currentDecision?.options;
|
|
715
|
+
if (!options || options.length === 0) return false;
|
|
716
|
+
if (key.upArrow) {
|
|
717
|
+
setOptionIndex((i) => Math.max(0, i - 1));
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
if (key.downArrow) {
|
|
721
|
+
setOptionIndex((i) => Math.min(options.length - 1, i + 1));
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
724
|
+
if (key.return) {
|
|
725
|
+
const opt = options[optionIndex];
|
|
726
|
+
if (opt) submitDecisionAnswer(opt.key);
|
|
727
|
+
return true;
|
|
728
|
+
}
|
|
729
|
+
return false;
|
|
730
|
+
},
|
|
731
|
+
[currentDecision, optionIndex, submitDecisionAnswer]
|
|
732
|
+
);
|
|
733
|
+
useInput((_char, key) => {
|
|
734
|
+
if (key.tab && decisions.length > 0) {
|
|
735
|
+
setFocusMode((m) => m === "input" ? "decisions" : "input");
|
|
736
|
+
setOptionIndex(0);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
457
739
|
if (key.escape) {
|
|
458
|
-
|
|
740
|
+
if (focusMode === "decisions") {
|
|
741
|
+
setFocusMode("input");
|
|
742
|
+
} else {
|
|
743
|
+
exit();
|
|
744
|
+
}
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (focusMode !== "decisions" || decisions.length === 0) return;
|
|
748
|
+
if (currentHasOptions && handleOptionNav(key)) return;
|
|
749
|
+
if (decisions.length > 1) {
|
|
750
|
+
if (key.leftArrow) {
|
|
751
|
+
setDecisionIndex((i) => Math.max(0, i - 1));
|
|
752
|
+
setOptionIndex(0);
|
|
753
|
+
} else if (key.rightArrow) {
|
|
754
|
+
setDecisionIndex((i) => Math.min(decisions.length - 1, i + 1));
|
|
755
|
+
setOptionIndex(0);
|
|
756
|
+
}
|
|
459
757
|
}
|
|
460
758
|
});
|
|
461
759
|
const handleSubmit = useCallback(
|
|
@@ -468,13 +766,50 @@ function SupervisorTui({ name }) {
|
|
|
468
766
|
[name]
|
|
469
767
|
);
|
|
470
768
|
const costHistory = extractCostHistory(entries);
|
|
769
|
+
const activeTaskCount = tasks.filter(
|
|
770
|
+
(t) => t.outcome !== "done" && t.outcome !== "abandoned"
|
|
771
|
+
).length;
|
|
772
|
+
const taskPanelLines = tasks.length > 0 ? Math.min(activeTaskCount, 6) + 2 : 0;
|
|
773
|
+
const decisionPanelLines = focusMode === "decisions" && currentDecision ? (currentHasOptions ? currentDecision.options?.length ?? 0 : 1) + 4 : decisions.length > 0 ? 1 : 0;
|
|
774
|
+
const bottomPanel = focusMode === "decisions" && currentDecision ? /* @__PURE__ */ jsx(
|
|
775
|
+
DecisionInputPanel,
|
|
776
|
+
{
|
|
777
|
+
decision: currentDecision,
|
|
778
|
+
optionIndex,
|
|
779
|
+
isTextMode: !currentHasOptions,
|
|
780
|
+
textInput: decisionAnswer,
|
|
781
|
+
onTextChange: setDecisionAnswer,
|
|
782
|
+
onSubmit: submitDecisionAnswer,
|
|
783
|
+
decisionCount: decisions.length,
|
|
784
|
+
decisionIdx: decisionIndex,
|
|
785
|
+
frame
|
|
786
|
+
}
|
|
787
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
788
|
+
/* @__PURE__ */ jsx(
|
|
789
|
+
InputPanel,
|
|
790
|
+
{
|
|
791
|
+
value: input,
|
|
792
|
+
onChange: setInput,
|
|
793
|
+
onSubmit: handleSubmit,
|
|
794
|
+
lastSent,
|
|
795
|
+
focus: focusMode === "input"
|
|
796
|
+
}
|
|
797
|
+
),
|
|
798
|
+
/* @__PURE__ */ jsx(Footer, { hasDecisions: decisions.length > 0 })
|
|
799
|
+
] });
|
|
471
800
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
472
801
|
/* @__PURE__ */ jsx(HeaderBar, { state, name, frame, clock }),
|
|
473
|
-
/* @__PURE__ */ jsx(BudgetPanel, { state, dailyCap
|
|
474
|
-
/* @__PURE__ */ jsx(
|
|
475
|
-
/* @__PURE__ */ jsx(
|
|
476
|
-
/* @__PURE__ */ jsx(
|
|
477
|
-
|
|
802
|
+
/* @__PURE__ */ jsx(BudgetPanel, { state, dailyCap, costHistory }),
|
|
803
|
+
focusMode !== "decisions" && /* @__PURE__ */ jsx(DecisionBanner, { decisions, frame }),
|
|
804
|
+
/* @__PURE__ */ jsx(TaskPanel, { tasks }),
|
|
805
|
+
/* @__PURE__ */ jsx(
|
|
806
|
+
ActivityPanel,
|
|
807
|
+
{
|
|
808
|
+
entries,
|
|
809
|
+
termHeight: termHeight - taskPanelLines - decisionPanelLines
|
|
810
|
+
}
|
|
811
|
+
),
|
|
812
|
+
bottomPanel
|
|
478
813
|
] });
|
|
479
814
|
}
|
|
480
815
|
|
|
@@ -486,4 +821,4 @@ async function renderSupervisorTui(name) {
|
|
|
486
821
|
export {
|
|
487
822
|
renderSupervisorTui
|
|
488
823
|
};
|
|
489
|
-
//# sourceMappingURL=tui-
|
|
824
|
+
//# sourceMappingURL=tui-RYLR4OLF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui/index.ts","../src/tui/supervisor-tui.tsx"],"sourcesContent":["import { render } from \"ink\";\nimport React from \"react\";\nimport { SupervisorTui } from \"./supervisor-tui.js\";\n\n/**\n * Render the supervisor TUI. Returns a promise that resolves when the user exits.\n */\nexport async function renderSupervisorTui(name: string): Promise<void> {\n const { waitUntilExit } = render(React.createElement(SupervisorTui, { name }));\n await waitUntilExit();\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ActivityEntry,\n Decision,\n InboxMessage,\n MemoryEntry,\n SupervisorDaemonState,\n} from \"@neotx/core\";\nimport {\n DecisionStore,\n getSupervisorActivityPath,\n getSupervisorDecisionsPath,\n getSupervisorDir,\n getSupervisorInboxPath,\n getSupervisorStatePath,\n loadGlobalConfig,\n MemoryStore,\n} from \"@neotx/core\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport TextInput from \"ink-text-input\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n// ─── Constants ───────────────────────────────────────────\n\nconst MAX_VISIBLE_ENTRIES = 24;\nconst POLL_INTERVAL_MS = 1_500;\nconst ANIMATION_TICK_MS = 400;\n\n// ─── Unicode Visual Elements ─────────────────────────────\n\nconst SPARK_CHARS = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"];\nconst BLOCK_FULL = \"█\";\nconst BLOCK_EMPTY = \"░\";\nconst PULSE_FRAMES = [\"◉\", \"◎\", \"○\", \"◎\"];\nconst IDLE_FRAMES = [\"◌\", \"◌\", \"◌\", \"◌\"];\n\nconst TYPE_ICONS: Record<string, string> = {\n heartbeat: \"♥\",\n decision: \"★\",\n action: \"⚡\",\n error: \"✖\",\n event: \"◆\",\n message: \"✉\",\n thinking: \"◇\",\n plan: \"▸\",\n dispatch: \"↗\",\n tool_use: \"⊘\",\n};\n\nconst TYPE_COLORS: Record<string, string> = {\n heartbeat: \"#6ee7b7\",\n decision: \"#fbbf24\",\n action: \"#60a5fa\",\n error: \"#f87171\",\n event: \"#c084fc\",\n message: \"#67e8f9\",\n thinking: \"#a78bfa\",\n plan: \"#34d399\",\n dispatch: \"#f472b6\",\n tool_use: \"#38bdf8\",\n};\n\nconst TYPE_LABELS: Record<string, string> = {\n heartbeat: \"BEAT\",\n decision: \"DECIDE\",\n action: \"ACTION\",\n error: \"ERROR\",\n event: \"EVENT\",\n message: \"MSG\",\n thinking: \"THINK\",\n plan: \"PLAN\",\n dispatch: \"SEND\",\n tool_use: \"TOOL\",\n};\n\n// ─── Helpers ─────────────────────────────────────────────\n\nfunction formatTime(timestamp: string): string {\n return timestamp.slice(11, 19);\n}\n\nfunction formatUptime(startedAt: string): string {\n const ms = Date.now() - new Date(startedAt).getTime();\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n if (days > 0) return `${days}d ${hours % 24}h`;\n if (hours > 0) return `${hours}h ${minutes % 60}m`;\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\n}\n\nfunction formatTimeAgo(timestamp: string): string {\n const ms = Date.now() - new Date(timestamp).getTime();\n const seconds = Math.floor(ms / 1000);\n if (seconds < 60) return `${seconds}s ago`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n return `${hours}h ago`;\n}\n\nfunction buildProgressBar(ratio: number, width: number): { filled: string; empty: string } {\n const clamped = Math.max(0, Math.min(1, ratio));\n const filledCount = Math.round(clamped * width);\n return {\n filled: BLOCK_FULL.repeat(filledCount),\n empty: BLOCK_EMPTY.repeat(width - filledCount),\n };\n}\n\nfunction buildSparkline(values: number[], width: number): string {\n if (values.length === 0) return \"▁\".repeat(width);\n const recent = values.slice(-width);\n const max = Math.max(...recent, 0.001);\n return recent\n .map((v) => {\n const idx = Math.min(\n Math.floor((v / max) * (SPARK_CHARS.length - 1)),\n SPARK_CHARS.length - 1,\n );\n return SPARK_CHARS[idx];\n })\n .join(\"\");\n}\n\nfunction extractCostHistory(entries: ActivityEntry[]): number[] {\n return entries\n .filter((e) => e.type === \"heartbeat\" && e.summary.includes(\"complete\"))\n .map((e) => {\n const detail = e.detail as Record<string, unknown> | undefined;\n return typeof detail?.costUsd === \"number\" ? detail.costUsd : 0;\n });\n}\n\n// ─── Animated Hooks ──────────────────────────────────────\n\nfunction useAnimationFrame(): number {\n const [frame, setFrame] = useState(0);\n useEffect(() => {\n const interval = setInterval(() => setFrame((f) => f + 1), ANIMATION_TICK_MS);\n return () => clearInterval(interval);\n }, []);\n return frame;\n}\n\nfunction useClock(): string {\n const [time, setTime] = useState(() => new Date().toLocaleTimeString());\n useEffect(() => {\n const interval = setInterval(() => setTime(new Date().toLocaleTimeString()), 1000);\n return () => clearInterval(interval);\n }, []);\n return time;\n}\n\n// ─── Components ──────────────────────────────────────────\n\nfunction Logo() {\n return (\n <Box paddingX={1} gap={1}>\n <Text color=\"#c084fc\" bold>\n ◆\n </Text>\n <Text bold>\n <Text color=\"#c084fc\">N</Text>\n <Text color=\"#a78bfa\">E</Text>\n <Text color=\"#818cf8\">O</Text>\n </Text>\n <Text dimColor>SUPERVISOR</Text>\n </Box>\n );\n}\n\nfunction LiveIndicator({ frame, isRunning }: { frame: number; isRunning: boolean }) {\n const frames = isRunning ? PULSE_FRAMES : IDLE_FRAMES;\n const dot = frames[frame % frames.length];\n return (\n <Box paddingX={1}>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {dot}\n </Text>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {\" \"}\n {isRunning ? \"LIVE\" : \"IDLE\"}\n </Text>\n </Box>\n );\n}\n\nfunction HeaderBar({\n state,\n name,\n frame,\n clock,\n}: {\n state: SupervisorDaemonState | null;\n name: string;\n frame: number;\n clock: string;\n}) {\n if (!state) {\n return (\n <Box borderStyle=\"round\" borderColor=\"#6b7280\" paddingX={1} flexDirection=\"column\">\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n <Box paddingX={1}>\n <Text color=\"#fbbf24\">⟳ Connecting to \"{name}\"...</Text>\n </Box>\n </Box>\n );\n }\n\n const isRunning = state.status === \"running\";\n\n return (\n <Box\n borderStyle=\"round\"\n borderColor={isRunning ? \"#6ee7b7\" : \"#f87171\"}\n paddingX={0}\n flexDirection=\"column\"\n >\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box gap={2}>\n <LiveIndicator frame={frame} isRunning={isRunning} />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box paddingX={1} gap={1}>\n <Text dimColor>│</Text>\n <Text>\n <Text dimColor>pid</Text> <Text bold>{state.pid}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>port</Text> <Text bold>:{state.port}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>beats</Text>{\" \"}\n <Text bold color=\"#6ee7b7\">\n ▲{state.heartbeatCount}\n </Text>\n </Text>\n {state.lastHeartbeat && (\n <>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>last</Text> <Text>{formatTimeAgo(state.lastHeartbeat)}</Text>\n </Text>\n </>\n )}\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>up</Text> <Text>{formatUptime(state.startedAt)}</Text>\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction BudgetPanel({\n state,\n dailyCap,\n costHistory,\n}: {\n state: SupervisorDaemonState | null;\n dailyCap: number;\n costHistory: number[];\n}) {\n if (!state) return null;\n\n const todayCost = state.todayCostUsd ?? 0;\n const totalCost = state.totalCostUsd ?? 0;\n const ratio = dailyCap > 0 ? todayCost / dailyCap : 0;\n const barWidth = 20;\n const bar = buildProgressBar(ratio, barWidth);\n const pct = Math.round(ratio * 100);\n\n const barColor = pct < 50 ? \"#4ade80\" : pct < 80 ? \"#fbbf24\" : \"#f87171\";\n\n const sparkline = buildSparkline(costHistory, 12);\n\n return (\n <Box paddingX={2} gap={2}>\n <Box gap={1}>\n <Text dimColor>budget</Text>\n <Text color={barColor}>{bar.filled}</Text>\n <Text dimColor>{bar.empty}</Text>\n <Text bold color={barColor}>\n {pct}%\n </Text>\n <Text dimColor>\n (${todayCost.toFixed(2)}/${dailyCap})\n </Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>total</Text>\n <Text bold>${totalCost.toFixed(2)}</Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>cost/beat</Text>\n <Text color=\"#818cf8\">{sparkline}</Text>\n </Box>\n </Box>\n );\n}\n\nfunction ActivityRow({\n entry,\n isLatest,\n isOld,\n}: {\n entry: ActivityEntry;\n isLatest: boolean;\n isOld: boolean;\n}) {\n const icon = TYPE_ICONS[entry.type] ?? \"·\";\n const color = TYPE_COLORS[entry.type] ?? \"#9ca3af\";\n const label = (TYPE_LABELS[entry.type] ?? (entry.type as string).toUpperCase()).padEnd(7);\n\n return (\n <Box gap={1} paddingX={2}>\n <Text dimColor={isOld}>{isLatest ? \"│\" : \"│\"}</Text>\n <Text dimColor={isOld}>{formatTime(entry.timestamp)}</Text>\n <Text color={color} dimColor={isOld} bold={isLatest}>\n {icon}\n </Text>\n <Text color={color} dimColor={isOld} bold>\n {label}\n </Text>\n <Text dimColor={isOld} bold={isLatest}>\n {entry.summary}\n </Text>\n </Box>\n );\n}\n\nconst TASK_STATUS_COLORS: Record<string, string> = {\n in_progress: \"#60a5fa\",\n blocked: \"#f87171\",\n pending: \"#6b7280\",\n done: \"#4ade80\",\n};\n\nconst TASK_STATUS_LABELS: Record<string, string> = {\n in_progress: \"ACTIVE\",\n blocked: \"BLOCK\",\n pending: \"·\",\n};\n\nfunction TaskPanel({ tasks }: { tasks: MemoryEntry[] }) {\n const active = tasks.filter((t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\");\n const doneCount = tasks.filter((t) => t.outcome === \"done\").length;\n\n if (tasks.length === 0) return null;\n\n const MAX_VISIBLE = 6;\n const visible = active.slice(0, MAX_VISIBLE);\n const overflow = active.length - visible.length;\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n TASKS\n </Text>\n <Text dimColor>\n ({active.length} active, {doneCount} done)\n </Text>\n <Text dimColor>{\"─\".repeat(30)}</Text>\n </Box>\n {visible.map((t) => {\n const status = t.outcome ?? \"pending\";\n const color = TASK_STATUS_COLORS[status] ?? \"#6b7280\";\n const label = (TASK_STATUS_LABELS[status] ?? \"·\").padEnd(6);\n const prio = t.severity ? `[${t.severity.slice(0, 3)}] ` : \"\";\n const repo = t.scope !== \"global\" ? path.basename(t.scope) : \"\";\n const run = t.runId ? `run:${t.runId.slice(0, 4)}` : \"\";\n const meta = [repo, run].filter(Boolean).join(\" \");\n\n return (\n <Box key={t.id} gap={1} paddingX={2}>\n <Text dimColor>│</Text>\n <Text color={color} bold>\n {label}\n </Text>\n {prio && <Text dimColor>{prio.padEnd(5)}</Text>}\n <Text wrap=\"truncate\">{t.content}</Text>\n {meta && <Text dimColor>({meta})</Text>}\n </Box>\n );\n })}\n {overflow > 0 && (\n <Box paddingX={2}>\n <Text dimColor>│ ... +{overflow} more pending</Text>\n </Box>\n )}\n </Box>\n );\n}\n\n/** Compact banner shown above activity when decisions exist but input is focused on chat */\nfunction DecisionBanner({ decisions, frame }: { decisions: Decision[]; frame: number }) {\n if (decisions.length === 0) return null;\n\n const pulseChars = [\"★\", \"☆\"];\n const pulse = pulseChars[frame % pulseChars.length];\n\n return (\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text color=\"#fbbf24\" bold>\n {pulse} {decisions.length} decision{decisions.length > 1 ? \"s\" : \"\"} pending\n </Text>\n <Text dimColor>\n — press <Text bold>tab</Text> to review\n </Text>\n </Box>\n );\n}\n\n/** Full decision input panel — replaces the chat input when focused */\nfunction DecisionInputPanel({\n decision,\n optionIndex,\n isTextMode,\n textInput,\n onTextChange,\n onSubmit,\n decisionCount,\n decisionIdx,\n frame,\n}: {\n decision: Decision;\n optionIndex: number;\n isTextMode: boolean;\n textInput: string;\n onTextChange: (v: string) => void;\n onSubmit: (v: string) => void;\n decisionCount: number;\n decisionIdx: number;\n frame: number;\n}) {\n const hasOptions = decision.options && decision.options.length > 0;\n const pulseChars = [\"★\", \"☆\"];\n const pulse = pulseChars[frame % pulseChars.length];\n\n return (\n <Box flexDirection=\"column\">\n {/* Header */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text color=\"#fbbf24\" bold>\n {pulse} DECISION\n </Text>\n {decisionCount > 1 && (\n <Text color=\"#fbbf24\">\n ({decisionIdx + 1}/{decisionCount})\n </Text>\n )}\n <Text dimColor>{\"─\".repeat(30)}</Text>\n </Box>\n\n {/* Question */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text bold wrap=\"truncate-end\">\n {decision.question}\n </Text>\n </Box>\n\n {/* Context if available */}\n {decision.context && (\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text dimColor wrap=\"truncate-end\">\n {decision.context}\n </Text>\n </Box>\n )}\n\n {/* Option selector or free text */}\n {hasOptions ? (\n <Box flexDirection=\"column\">\n {(decision.options ?? []).map((opt, idx) => {\n const isSelected = idx === optionIndex;\n return (\n <Box key={opt.key} paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n {isSelected ? (\n <Text color=\"#fbbf24\" bold>\n ▸ {opt.label}\n </Text>\n ) : (\n <Text dimColor>\n {\" \"}\n {opt.label}\n </Text>\n )}\n {opt.description && isSelected && <Text dimColor>— {opt.description}</Text>}\n </Box>\n );\n })}\n </Box>\n ) : (\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text color=\"#fbbf24\" bold>\n ❯\n </Text>\n <TextInput\n value={textInput}\n onChange={onTextChange}\n onSubmit={onSubmit}\n focus={isTextMode}\n placeholder=\"type your answer...\"\n />\n </Box>\n )}\n\n {/* Footer hints */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>└</Text>\n <Text dimColor>\n {hasOptions ? (\n <>\n <Text bold>↑↓</Text> choose · <Text bold>enter</Text> confirm\n </>\n ) : (\n <>\n <Text bold>enter</Text> send\n </>\n )}\n {decisionCount > 1 && (\n <>\n {\" · \"}\n <Text bold>←→</Text> prev/next\n </>\n )}\n {\" · \"}\n <Text bold>tab</Text> chat · <Text bold>esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n\n/** Types shown in the activity feed — plan/thinking are internal, not shown */\nconst ACTIVITY_TYPES = new Set([\n \"heartbeat\",\n \"decision\",\n \"action\",\n \"dispatch\",\n \"error\",\n \"event\",\n \"message\",\n]);\n\nfunction ActivityPanel({ entries, termHeight }: { entries: ActivityEntry[]; termHeight: number }) {\n // Reserve lines for header (5), budget (1), separator (1), input (2), footer (1) = 10\n const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 10));\n const filtered = entries.filter((e) => ACTIVITY_TYPES.has(e.type));\n const visible = filtered.slice(-maxVisible);\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n ACTIVITY\n </Text>\n <Text dimColor>{\"─\".repeat(40)}</Text>\n </Box>\n\n {visible.length === 0 ? (\n <Box paddingX={2}>\n <Text dimColor>│ Waiting for heartbeats...</Text>\n </Box>\n ) : (\n visible.map((entry, idx) => (\n <ActivityRow\n key={entry.id}\n entry={entry}\n isLatest={idx === visible.length - 1}\n isOld={idx < visible.length - 5}\n />\n ))\n )}\n\n <Box paddingX={2}>\n <Text dimColor>│</Text>\n </Box>\n </Box>\n );\n}\n\nfunction InputPanel({\n value,\n onChange,\n onSubmit,\n lastSent,\n focus,\n}: {\n value: string;\n onChange: (v: string) => void;\n onSubmit: (v: string) => void;\n lastSent: string;\n focus: boolean;\n}) {\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>└</Text>\n <Text bold color=\"#60a5fa\">\n ❯\n </Text>\n <TextInput\n value={value}\n onChange={onChange}\n onSubmit={onSubmit}\n focus={focus}\n placeholder=\"message the supervisor...\"\n />\n </Box>\n <Box paddingX={2} gap={1}>\n <Text dimColor> </Text>\n {lastSent ? <Text color=\"#6b7280\">✓ \"{lastSent}\"</Text> : null}\n </Box>\n </Box>\n );\n}\n\nfunction Footer({ hasDecisions }: { hasDecisions: boolean }) {\n return (\n <Box paddingX={2} gap={1} justifyContent=\"center\">\n <Text dimColor>\n <Text bold>esc</Text> quit\n </Text>\n <Text dimColor>·</Text>\n <Text dimColor>\n <Text bold>enter</Text> send\n </Text>\n {hasDecisions && (\n <>\n <Text dimColor>·</Text>\n <Text dimColor>\n <Text bold>tab</Text> decisions\n </Text>\n </>\n )}\n <Text dimColor>·</Text>\n <Text dimColor>daemon keeps running</Text>\n </Box>\n );\n}\n\n// ─── Data Fetching ───────────────────────────────────────\n\nasync function readState(name: string): Promise<SupervisorDaemonState | null> {\n try {\n const raw = await readFile(getSupervisorStatePath(name), \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n}\n\nasync function readActivity(name: string, maxEntries: number): Promise<ActivityEntry[]> {\n try {\n const content = await readFile(getSupervisorActivityPath(name), \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const lastLines = lines.slice(-maxEntries);\n const entries: ActivityEntry[] = [];\n for (const line of lastLines) {\n try {\n entries.push(JSON.parse(line) as ActivityEntry);\n } catch {\n // Skip malformed\n }\n }\n return entries;\n } catch {\n return [];\n }\n}\n\nfunction readTasks(name: string): MemoryEntry[] {\n try {\n const dir = getSupervisorDir(name);\n const store = new MemoryStore(path.join(dir, \"memory.sqlite\"));\n const tasks = store.query({ types: [\"task\"], limit: 20, sortBy: \"createdAt\" });\n store.close();\n return tasks;\n } catch {\n return [];\n }\n}\n\nasync function readDecisions(name: string): Promise<Decision[]> {\n try {\n const store = new DecisionStore(getSupervisorDecisionsPath(name));\n return await store.pending();\n } catch {\n return [];\n }\n}\n\n/**\n * Appends a JSON entry to a JSONL file.\n * Creates the parent directory if needed. Returns false on error.\n */\nasync function appendToJsonl(filePath: string, data: unknown): Promise<boolean> {\n const dir = path.dirname(filePath);\n try {\n await mkdir(dir, { recursive: true });\n await appendFile(filePath, `${JSON.stringify(data)}\\n`, \"utf-8\");\n return true;\n } catch (error) {\n console.error(\n `Warning: Failed to write to ${path.basename(filePath)}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return false;\n }\n}\n\n/**\n * Writes a message to the supervisor's inbox.jsonl file.\n * Creates the directory if it doesn't exist and handles write errors gracefully.\n */\nasync function writeToInbox(name: string, message: InboxMessage): Promise<boolean> {\n const inboxPath = getSupervisorInboxPath(name);\n return appendToJsonl(inboxPath, message);\n}\n\nasync function answerDecision(name: string, id: string, answer: string): Promise<void> {\n const store = new DecisionStore(getSupervisorDecisionsPath(name));\n await store.answer(id, answer);\n\n // Wake up the supervisor heartbeat by appending to inbox.jsonl\n const inboxMessage: InboxMessage = {\n id: randomUUID(),\n from: \"tui\",\n text: `decision:answer ${id} ${answer}`,\n timestamp: new Date().toISOString(),\n };\n await writeToInbox(name, inboxMessage);\n}\n\nasync function sendMessage(name: string, text: string): Promise<void> {\n const id = randomUUID();\n const timestamp = new Date().toISOString();\n\n const message: InboxMessage = { id, from: \"tui\", text, timestamp };\n await writeToInbox(name, message);\n\n // Write to activity.jsonl so the message appears in the TUI conversation\n const activityEntry: ActivityEntry = { id, type: \"message\", summary: text, timestamp };\n const activityPath = getSupervisorActivityPath(name);\n await appendToJsonl(activityPath, activityEntry);\n}\n\n// ─── Main Component ──────────────────────────────────────\n\nexport function SupervisorTui({ name }: { name: string }) {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const frame = useAnimationFrame();\n const clock = useClock();\n\n const [state, setState] = useState<SupervisorDaemonState | null>(null);\n const [entries, setEntries] = useState<ActivityEntry[]>([]);\n const [tasks, setTasks] = useState<MemoryEntry[]>([]);\n const [decisions, setDecisions] = useState<Decision[]>([]);\n const [dailyCap, setDailyCap] = useState(50);\n const [input, setInput] = useState(\"\");\n const [lastSent, setLastSent] = useState(\"\");\n const [termHeight, setTermHeight] = useState(stdout?.rows ?? 30);\n\n // Decision interaction state\n const [decisionIndex, setDecisionIndex] = useState(0);\n const [optionIndex, setOptionIndex] = useState(0);\n const [decisionAnswer, setDecisionAnswer] = useState(\"\");\n const [focusMode, setFocusMode] = useState<\"input\" | \"decisions\">(\"input\");\n\n // Track terminal resize\n useEffect(() => {\n function onResize() {\n if (stdout) setTermHeight(stdout.rows);\n }\n stdout?.on(\"resize\", onResize);\n return () => {\n stdout?.off(\"resize\", onResize);\n };\n }, [stdout]);\n\n // Load daily cap from config\n useEffect(() => {\n loadGlobalConfig()\n .then((cfg) => setDailyCap(cfg.supervisor.dailyCapUsd))\n .catch((err) => {\n console.debug(\"[tui] Failed to load global config:\", err);\n });\n }, []);\n\n // Poll state, activity, and decisions\n useEffect(() => {\n let active = true;\n\n async function poll() {\n if (!active) return;\n const [newState, newEntries, newDecisions] = await Promise.all([\n readState(name),\n readActivity(name, MAX_VISIBLE_ENTRIES),\n readDecisions(name),\n ]);\n if (!active) return;\n setState(newState);\n setEntries(newEntries);\n setDecisions(newDecisions);\n setTasks(readTasks(name));\n // Reset decision index if out of bounds\n if (newDecisions.length > 0 && decisionIndex >= newDecisions.length) {\n setDecisionIndex(0);\n }\n // Auto-switch to decisions mode when new decisions appear\n if (newDecisions.length > 0 && decisions.length === 0) {\n setFocusMode(\"decisions\");\n }\n // Return to input mode when all decisions are resolved\n if (newDecisions.length === 0 && decisions.length > 0) {\n setFocusMode(\"input\");\n }\n }\n\n poll();\n const interval = setInterval(poll, POLL_INTERVAL_MS);\n return () => {\n active = false;\n clearInterval(interval);\n };\n }, [name, decisionIndex, decisions.length]);\n\n // Current decision being interacted with\n const currentDecision = decisions[decisionIndex] as Decision | undefined;\n const currentHasOptions = (currentDecision?.options?.length ?? 0) > 0;\n\n // Submit the selected option or free-text answer\n const submitDecisionAnswer = useCallback(\n async (answer: string) => {\n if (!answer.trim() || !currentDecision) return;\n try {\n await answerDecision(name, currentDecision.id, answer.trim());\n setLastSent(`Decision ${currentDecision.id.slice(4, 12)}: \"${answer.trim()}\"`);\n setDecisionAnswer(\"\");\n setOptionIndex(0);\n } catch {\n // Decision may have been answered already\n }\n },\n [name, currentDecision],\n );\n\n const handleOptionNav = useCallback(\n (key: { upArrow: boolean; downArrow: boolean; return: boolean }): boolean => {\n const options = currentDecision?.options;\n if (!options || options.length === 0) return false;\n\n if (key.upArrow) {\n setOptionIndex((i) => Math.max(0, i - 1));\n return true;\n }\n if (key.downArrow) {\n setOptionIndex((i) => Math.min(options.length - 1, i + 1));\n return true;\n }\n if (key.return) {\n const opt = options[optionIndex];\n if (opt) submitDecisionAnswer(opt.key);\n return true;\n }\n return false;\n },\n [currentDecision, optionIndex, submitDecisionAnswer],\n );\n\n useInput((_char, key) => {\n if (key.tab && decisions.length > 0) {\n setFocusMode((m) => (m === \"input\" ? \"decisions\" : \"input\"));\n setOptionIndex(0);\n return;\n }\n\n if (key.escape) {\n if (focusMode === \"decisions\") {\n setFocusMode(\"input\");\n } else {\n exit();\n }\n return;\n }\n\n if (focusMode !== \"decisions\" || decisions.length === 0) return;\n\n if (currentHasOptions && handleOptionNav(key)) return;\n\n // ←→ to switch between decisions when multiple\n if (decisions.length > 1) {\n if (key.leftArrow) {\n setDecisionIndex((i) => Math.max(0, i - 1));\n setOptionIndex(0);\n } else if (key.rightArrow) {\n setDecisionIndex((i) => Math.min(decisions.length - 1, i + 1));\n setOptionIndex(0);\n }\n }\n });\n\n const handleSubmit = useCallback(\n (text: string) => {\n if (!text.trim()) return;\n sendMessage(name, text.trim());\n setLastSent(text.trim());\n setInput(\"\");\n },\n [name],\n );\n\n const costHistory = extractCostHistory(entries);\n\n // Calculate height adjustments for panels\n const activeTaskCount = tasks.filter(\n (t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\",\n ).length;\n const taskPanelLines = tasks.length > 0 ? Math.min(activeTaskCount, 6) + 2 : 0;\n const decisionPanelLines =\n focusMode === \"decisions\" && currentDecision\n ? (currentHasOptions ? (currentDecision.options?.length ?? 0) : 1) + 4\n : decisions.length > 0\n ? 1\n : 0;\n\n // Bottom panel: either decision input or chat input\n const bottomPanel =\n focusMode === \"decisions\" && currentDecision ? (\n <DecisionInputPanel\n decision={currentDecision}\n optionIndex={optionIndex}\n isTextMode={!currentHasOptions}\n textInput={decisionAnswer}\n onTextChange={setDecisionAnswer}\n onSubmit={submitDecisionAnswer}\n decisionCount={decisions.length}\n decisionIdx={decisionIndex}\n frame={frame}\n />\n ) : (\n <>\n <InputPanel\n value={input}\n onChange={setInput}\n onSubmit={handleSubmit}\n lastSent={lastSent}\n focus={focusMode === \"input\"}\n />\n <Footer hasDecisions={decisions.length > 0} />\n </>\n );\n\n return (\n <Box flexDirection=\"column\">\n <HeaderBar state={state} name={name} frame={frame} clock={clock} />\n <BudgetPanel state={state} dailyCap={dailyCap} costHistory={costHistory} />\n {focusMode !== \"decisions\" && <DecisionBanner decisions={decisions} frame={frame} />}\n <TaskPanel tasks={tasks} />\n <ActivityPanel\n entries={entries}\n termHeight={termHeight - taskPanelLines - decisionPanelLines}\n />\n {bottomPanel}\n </Box>\n );\n}\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,OAAO,WAAW;;;ACDlB,SAAS,kBAAkB;AAC3B,SAAS,YAAY,OAAO,gBAAgB;AAC5C,OAAO,UAAU;AAQjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,KAAK,MAAM,QAAQ,UAAU,iBAAiB;AACvD,OAAO,eAAe;AACtB,SAAS,aAAa,WAAW,gBAAgB;AA6I3C,SA4FI,UA5FJ,KAGA,YAHA;AAzIN,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAI1B,IAAM,cAAc,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AAC3D,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,eAAe,CAAC,UAAK,UAAK,UAAK,QAAG;AACxC,IAAM,cAAc,CAAC,UAAK,UAAK,UAAK,QAAG;AAEvC,IAAM,aAAqC;AAAA,EACzC,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AACZ;AAEA,IAAM,cAAsC;AAAA,EAC1C,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AACZ;AAEA,IAAM,cAAsC;AAAA,EAC1C,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AACZ;AAIA,SAAS,WAAW,WAA2B;AAC7C,SAAO,UAAU,MAAM,IAAI,EAAE;AAC/B;AAEA,SAAS,aAAa,WAA2B;AAC/C,QAAM,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,QAAQ;AACpD,QAAM,UAAU,KAAK,MAAM,KAAK,GAAI;AACpC,QAAM,UAAU,KAAK,MAAM,UAAU,EAAE;AACvC,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,QAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,MAAI,OAAO,EAAG,QAAO,GAAG,IAAI,KAAK,QAAQ,EAAE;AAC3C,MAAI,QAAQ,EAAG,QAAO,GAAG,KAAK,KAAK,UAAU,EAAE;AAC/C,MAAI,UAAU,EAAG,QAAO,GAAG,OAAO,KAAK,UAAU,EAAE;AACnD,SAAO,GAAG,OAAO;AACnB;AAEA,SAAS,cAAc,WAA2B;AAChD,QAAM,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,QAAQ;AACpD,QAAM,UAAU,KAAK,MAAM,KAAK,GAAI;AACpC,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,QAAM,UAAU,KAAK,MAAM,UAAU,EAAE;AACvC,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,SAAO,GAAG,KAAK;AACjB;AAEA,SAAS,iBAAiB,OAAe,OAAkD;AACzF,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAC9C,QAAM,cAAc,KAAK,MAAM,UAAU,KAAK;AAC9C,SAAO;AAAA,IACL,QAAQ,WAAW,OAAO,WAAW;AAAA,IACrC,OAAO,YAAY,OAAO,QAAQ,WAAW;AAAA,EAC/C;AACF;AAEA,SAAS,eAAe,QAAkB,OAAuB;AAC/D,MAAI,OAAO,WAAW,EAAG,QAAO,SAAI,OAAO,KAAK;AAChD,QAAM,SAAS,OAAO,MAAM,CAAC,KAAK;AAClC,QAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAK;AACrC,SAAO,OACJ,IAAI,CAAC,MAAM;AACV,UAAM,MAAM,KAAK;AAAA,MACf,KAAK,MAAO,IAAI,OAAQ,YAAY,SAAS,EAAE;AAAA,MAC/C,YAAY,SAAS;AAAA,IACvB;AACA,WAAO,YAAY,GAAG;AAAA,EACxB,CAAC,EACA,KAAK,EAAE;AACZ;AAEA,SAAS,mBAAmB,SAAoC;AAC9D,SAAO,QACJ,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,QAAQ,SAAS,UAAU,CAAC,EACtE,IAAI,CAAC,MAAM;AACV,UAAM,SAAS,EAAE;AACjB,WAAO,OAAO,QAAQ,YAAY,WAAW,OAAO,UAAU;AAAA,EAChE,CAAC;AACL;AAIA,SAAS,oBAA4B;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,CAAC;AACpC,YAAU,MAAM;AACd,UAAM,WAAW,YAAY,MAAM,SAAS,CAAC,MAAM,IAAI,CAAC,GAAG,iBAAiB;AAC5E,WAAO,MAAM,cAAc,QAAQ;AAAA,EACrC,GAAG,CAAC,CAAC;AACL,SAAO;AACT;AAEA,SAAS,WAAmB;AAC1B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,OAAM,oBAAI,KAAK,GAAE,mBAAmB,CAAC;AACtE,YAAU,MAAM;AACd,UAAM,WAAW,YAAY,MAAM,SAAQ,oBAAI,KAAK,GAAE,mBAAmB,CAAC,GAAG,GAAI;AACjF,WAAO,MAAM,cAAc,QAAQ;AAAA,EACrC,GAAG,CAAC,CAAC;AACL,SAAO;AACT;AAIA,SAAS,OAAO;AACd,SACE,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,wBAAC,QAAK,OAAM,WAAU,MAAI,MAAC,oBAE3B;AAAA,IACA,qBAAC,QAAK,MAAI,MACR;AAAA,0BAAC,QAAK,OAAM,WAAU,eAAC;AAAA,MACvB,oBAAC,QAAK,OAAM,WAAU,eAAC;AAAA,MACvB,oBAAC,QAAK,OAAM,WAAU,eAAC;AAAA,OACzB;AAAA,IACA,oBAAC,QAAK,UAAQ,MAAC,wBAAU;AAAA,KAC3B;AAEJ;AAEA,SAAS,cAAc,EAAE,OAAO,UAAU,GAA0C;AAClF,QAAM,SAAS,YAAY,eAAe;AAC1C,QAAM,MAAM,OAAO,QAAQ,OAAO,MAAM;AACxC,SACE,qBAAC,OAAI,UAAU,GACb;AAAA,wBAAC,QAAK,OAAO,YAAY,YAAY,WAAW,MAAI,MACjD,eACH;AAAA,IACA,qBAAC,QAAK,OAAO,YAAY,YAAY,WAAW,MAAI,MACjD;AAAA;AAAA,MACA,YAAY,SAAS;AAAA,OACxB;AAAA,KACF;AAEJ;AAEA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,CAAC,OAAO;AACV,WACE,qBAAC,OAAI,aAAY,SAAQ,aAAY,WAAU,UAAU,GAAG,eAAc,UACxE;AAAA,2BAAC,OAAI,gBAAe,iBAClB;AAAA,4BAAC,QAAK;AAAA,QACN,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,UAAQ,MAAE,iBAAM,GACxB;AAAA,SACF;AAAA,MACA,oBAAC,OAAI,UAAU,GACb,+BAAC,QAAK,OAAM,WAAU;AAAA;AAAA,QAAkB;AAAA,QAAK;AAAA,SAAI,GACnD;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,YAAY,MAAM,WAAW;AAEnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAY;AAAA,MACZ,aAAa,YAAY,YAAY;AAAA,MACrC,UAAU;AAAA,MACV,eAAc;AAAA,MAEd;AAAA,6BAAC,OAAI,gBAAe,iBAClB;AAAA,8BAAC,QAAK;AAAA,UACN,qBAAC,OAAI,KAAK,GACR;AAAA,gCAAC,iBAAc,OAAc,WAAsB;AAAA,YACnD,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,UAAQ,MAAE,iBAAM,GACxB;AAAA,aACF;AAAA,WACF;AAAA,QAEA,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,8BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,UAChB,qBAAC,QACC;AAAA,gCAAC,QAAK,UAAQ,MAAC,iBAAG;AAAA,YAAO;AAAA,YAAC,oBAAC,QAAK,MAAI,MAAE,gBAAM,KAAI;AAAA,aAClD;AAAA,UACA,oBAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,UAChB,qBAAC,QACC;AAAA,gCAAC,QAAK,UAAQ,MAAC,kBAAI;AAAA,YAAO;AAAA,YAAC,qBAAC,QAAK,MAAI,MAAC;AAAA;AAAA,cAAE,MAAM;AAAA,eAAK;AAAA,aACrD;AAAA,UACA,oBAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,UAChB,qBAAC,QACC;AAAA,gCAAC,QAAK,UAAQ,MAAC,mBAAK;AAAA,YAAQ;AAAA,YAC5B,qBAAC,QAAK,MAAI,MAAC,OAAM,WAAU;AAAA;AAAA,cACvB,MAAM;AAAA,eACV;AAAA,aACF;AAAA,UACC,MAAM,iBACL,iCACE;AAAA,gCAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,YAChB,qBAAC,QACC;AAAA,kCAAC,QAAK,UAAQ,MAAC,kBAAI;AAAA,cAAO;AAAA,cAAC,oBAAC,QAAM,wBAAc,MAAM,aAAa,GAAE;AAAA,eACvE;AAAA,aACF;AAAA,UAEF,oBAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,UAChB,qBAAC,QACC;AAAA,gCAAC,QAAK,UAAQ,MAAC,gBAAE;AAAA,YAAO;AAAA,YAAC,oBAAC,QAAM,uBAAa,MAAM,SAAS,GAAE;AAAA,aAChE;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,YAAY,MAAM,gBAAgB;AACxC,QAAM,YAAY,MAAM,gBAAgB;AACxC,QAAM,QAAQ,WAAW,IAAI,YAAY,WAAW;AACpD,QAAM,WAAW;AACjB,QAAM,MAAM,iBAAiB,OAAO,QAAQ;AAC5C,QAAM,MAAM,KAAK,MAAM,QAAQ,GAAG;AAElC,QAAM,WAAW,MAAM,KAAK,YAAY,MAAM,KAAK,YAAY;AAE/D,QAAM,YAAY,eAAe,aAAa,EAAE;AAEhD,SACE,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,yBAAC,OAAI,KAAK,GACR;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAM;AAAA,MACrB,oBAAC,QAAK,OAAO,UAAW,cAAI,QAAO;AAAA,MACnC,oBAAC,QAAK,UAAQ,MAAE,cAAI,OAAM;AAAA,MAC1B,qBAAC,QAAK,MAAI,MAAC,OAAO,UACf;AAAA;AAAA,QAAI;AAAA,SACP;AAAA,MACA,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QACV,UAAU,QAAQ,CAAC;AAAA,QAAE;AAAA,QAAG;AAAA,QAAS;AAAA,SACtC;AAAA,OACF;AAAA,IACA,oBAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,IAChB,qBAAC,OAAI,KAAK,GACR;AAAA,0BAAC,QAAK,UAAQ,MAAC,mBAAK;AAAA,MACpB,qBAAC,QAAK,MAAI,MAAC;AAAA;AAAA,QAAE,UAAU,QAAQ,CAAC;AAAA,SAAE;AAAA,OACpC;AAAA,IACA,oBAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,IAChB,qBAAC,OAAI,KAAK,GACR;AAAA,0BAAC,QAAK,UAAQ,MAAC,uBAAS;AAAA,MACxB,oBAAC,QAAK,OAAM,WAAW,qBAAU;AAAA,OACnC;AAAA,KACF;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,WAAW,MAAM,IAAI,KAAK;AACvC,QAAM,QAAQ,YAAY,MAAM,IAAI,KAAK;AACzC,QAAM,SAAS,YAAY,MAAM,IAAI,KAAM,MAAM,KAAgB,YAAY,GAAG,OAAO,CAAC;AAExF,SACE,qBAAC,OAAI,KAAK,GAAG,UAAU,GACrB;AAAA,wBAAC,QAAK,UAAU,OAAQ,qBAAW,WAAM,UAAI;AAAA,IAC7C,oBAAC,QAAK,UAAU,OAAQ,qBAAW,MAAM,SAAS,GAAE;AAAA,IACpD,oBAAC,QAAK,OAAc,UAAU,OAAO,MAAM,UACxC,gBACH;AAAA,IACA,oBAAC,QAAK,OAAc,UAAU,OAAO,MAAI,MACtC,iBACH;AAAA,IACA,oBAAC,QAAK,UAAU,OAAO,MAAM,UAC1B,gBAAM,SACT;AAAA,KACF;AAEJ;AAEA,IAAM,qBAA6C;AAAA,EACjD,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AACR;AAEA,IAAM,qBAA6C;AAAA,EACjD,aAAa;AAAA,EACb,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,UAAU,EAAE,MAAM,GAA6B;AACtD,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,YAAY,UAAU,EAAE,YAAY,WAAW;AACpF,QAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE;AAE5D,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,cAAc;AACpB,QAAM,UAAU,OAAO,MAAM,GAAG,WAAW;AAC3C,QAAM,WAAW,OAAO,SAAS,QAAQ;AAEzC,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,yBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,UAAQ,MAAC,MAAI,MAAC,mBAEpB;AAAA,MACA,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QACX,OAAO;AAAA,QAAO;AAAA,QAAU;AAAA,QAAU;AAAA,SACtC;AAAA,MACA,oBAAC,QAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,OACjC;AAAA,IACC,QAAQ,IAAI,CAAC,MAAM;AAClB,YAAM,SAAS,EAAE,WAAW;AAC5B,YAAM,QAAQ,mBAAmB,MAAM,KAAK;AAC5C,YAAM,SAAS,mBAAmB,MAAM,KAAK,QAAK,OAAO,CAAC;AAC1D,YAAM,OAAO,EAAE,WAAW,IAAI,EAAE,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO;AAC3D,YAAM,OAAO,EAAE,UAAU,WAAW,KAAK,SAAS,EAAE,KAAK,IAAI;AAC7D,YAAM,MAAM,EAAE,QAAQ,OAAO,EAAE,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK;AACrD,YAAM,OAAO,CAAC,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAEjD,aACE,qBAAC,OAAe,KAAK,GAAG,UAAU,GAChC;AAAA,4BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,QAChB,oBAAC,QAAK,OAAc,MAAI,MACrB,iBACH;AAAA,QACC,QAAQ,oBAAC,QAAK,UAAQ,MAAE,eAAK,OAAO,CAAC,GAAE;AAAA,QACxC,oBAAC,QAAK,MAAK,YAAY,YAAE,SAAQ;AAAA,QAChC,QAAQ,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,UAAE;AAAA,UAAK;AAAA,WAAC;AAAA,WAPxB,EAAE,EAQZ;AAAA,IAEJ,CAAC;AAAA,IACA,WAAW,KACV,oBAAC,OAAI,UAAU,GACb,+BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,MAAQ;AAAA,MAAS;AAAA,OAAa,GAC/C;AAAA,KAEJ;AAEJ;AAGA,SAAS,eAAe,EAAE,WAAW,MAAM,GAA6C;AACtF,MAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,QAAM,aAAa,CAAC,UAAK,QAAG;AAC5B,QAAM,QAAQ,WAAW,QAAQ,WAAW,MAAM;AAElD,SACE,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,wBAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,IAChB,qBAAC,QAAK,OAAM,WAAU,MAAI,MACvB;AAAA;AAAA,MAAM;AAAA,MAAE,UAAU;AAAA,MAAO;AAAA,MAAU,UAAU,SAAS,IAAI,MAAM;AAAA,MAAG;AAAA,OACtE;AAAA,IACA,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,MACL,oBAAC,QAAK,MAAI,MAAC,iBAAG;AAAA,MAAO;AAAA,OAC/B;AAAA,KACF;AAEJ;AAGA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,aAAa,SAAS,WAAW,SAAS,QAAQ,SAAS;AACjE,QAAM,aAAa,CAAC,UAAK,QAAG;AAC5B,QAAM,QAAQ,WAAW,QAAQ,WAAW,MAAM;AAElD,SACE,qBAAC,OAAI,eAAc,UAEjB;AAAA,yBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,qBAAC,QAAK,OAAM,WAAU,MAAI,MACvB;AAAA;AAAA,QAAM;AAAA,SACT;AAAA,MACC,gBAAgB,KACf,qBAAC,QAAK,OAAM,WAAU;AAAA;AAAA,QAClB,cAAc;AAAA,QAAE;AAAA,QAAE;AAAA,QAAc;AAAA,SACpC;AAAA,MAEF,oBAAC,QAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,OACjC;AAAA,IAGA,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,MAAI,MAAC,MAAK,gBACb,mBAAS,UACZ;AAAA,OACF;AAAA,IAGC,SAAS,WACR,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,UAAQ,MAAC,MAAK,gBACjB,mBAAS,SACZ;AAAA,OACF;AAAA,IAID,aACC,oBAAC,OAAI,eAAc,UACf,oBAAS,WAAW,CAAC,GAAG,IAAI,CAAC,KAAK,QAAQ;AAC1C,YAAM,aAAa,QAAQ;AAC3B,aACE,qBAAC,OAAkB,UAAU,GAAG,KAAK,GACnC;AAAA,4BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,QACf,aACC,qBAAC,QAAK,OAAM,WAAU,MAAI,MAAC;AAAA;AAAA,UACtB,IAAI;AAAA,WACT,IAEA,qBAAC,QAAK,UAAQ,MACX;AAAA;AAAA,UACA,IAAI;AAAA,WACP;AAAA,QAED,IAAI,eAAe,cAAc,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,UAAG,IAAI;AAAA,WAAY;AAAA,WAZ5D,IAAI,GAad;AAAA,IAEJ,CAAC,GACH,IAEA,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,OAAM,WAAU,MAAI,MAAC,oBAE3B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU;AAAA,UACV;AAAA,UACA,OAAO;AAAA,UACP,aAAY;AAAA;AAAA,MACd;AAAA,OACF;AAAA,IAIF,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,qBAAC,QAAK,UAAQ,MACX;AAAA,qBACC,iCACE;AAAA,8BAAC,QAAK,MAAI,MAAC,0BAAE;AAAA,UAAO;AAAA,UAAU,oBAAC,QAAK,MAAI,MAAC,mBAAK;AAAA,UAAO;AAAA,WACvD,IAEA,iCACE;AAAA,8BAAC,QAAK,MAAI,MAAC,mBAAK;AAAA,UAAO;AAAA,WACzB;AAAA,QAED,gBAAgB,KACf,iCACG;AAAA;AAAA,UACD,oBAAC,QAAK,MAAI,MAAC,0BAAE;AAAA,UAAO;AAAA,WACtB;AAAA,QAED;AAAA,QACD,oBAAC,QAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,QAAQ,oBAAC,QAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,SACpD;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,cAAc,EAAE,SAAS,WAAW,GAAqD;AAEhG,QAAM,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,qBAAqB,aAAa,EAAE,CAAC;AAC7E,QAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,eAAe,IAAI,EAAE,IAAI,CAAC;AACjE,QAAM,UAAU,SAAS,MAAM,CAAC,UAAU;AAE1C,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,yBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,UAAQ,MAAC,MAAI,MAAC,sBAEpB;AAAA,MACA,oBAAC,QAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,OACjC;AAAA,IAEC,QAAQ,WAAW,IAClB,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,UAAQ,MAAC,8CAA2B,GAC5C,IAEA,QAAQ,IAAI,CAAC,OAAO,QAClB;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA,UAAU,QAAQ,QAAQ,SAAS;AAAA,QACnC,OAAO,MAAM,QAAQ,SAAS;AAAA;AAAA,MAHzB,MAAM;AAAA,IAIb,CACD;AAAA,IAGH,oBAAC,OAAI,UAAU,GACb,8BAAC,QAAK,UAAQ,MAAC,oBAAC,GAClB;AAAA,KACF;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,yBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,oBAAC;AAAA,MAChB,oBAAC,QAAK,MAAI,MAAC,OAAM,WAAU,oBAE3B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAY;AAAA;AAAA,MACd;AAAA,OACF;AAAA,IACA,qBAAC,OAAI,UAAU,GAAG,KAAK,GACrB;AAAA,0BAAC,QAAK,UAAQ,MAAC,eAAC;AAAA,MACf,WAAW,qBAAC,QAAK,OAAM,WAAU;AAAA;AAAA,QAAI;AAAA,QAAS;AAAA,SAAC,IAAU;AAAA,OAC5D;AAAA,KACF;AAEJ;AAEA,SAAS,OAAO,EAAE,aAAa,GAA8B;AAC3D,SACE,qBAAC,OAAI,UAAU,GAAG,KAAK,GAAG,gBAAe,UACvC;AAAA,yBAAC,QAAK,UAAQ,MACZ;AAAA,0BAAC,QAAK,MAAI,MAAC,iBAAG;AAAA,MAAO;AAAA,OACvB;AAAA,IACA,oBAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,IAChB,qBAAC,QAAK,UAAQ,MACZ;AAAA,0BAAC,QAAK,MAAI,MAAC,mBAAK;AAAA,MAAO;AAAA,OACzB;AAAA,IACC,gBACC,iCACE;AAAA,0BAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,MAChB,qBAAC,QAAK,UAAQ,MACZ;AAAA,4BAAC,QAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,SACvB;AAAA,OACF;AAAA,IAEF,oBAAC,QAAK,UAAQ,MAAC,kBAAC;AAAA,IAChB,oBAAC,QAAK,UAAQ,MAAC,kCAAoB;AAAA,KACrC;AAEJ;AAIA,eAAe,UAAU,MAAqD;AAC5E,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,uBAAuB,IAAI,GAAG,OAAO;AAChE,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,aAAa,MAAc,YAA8C;AACtF,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,0BAA0B,IAAI,GAAG,OAAO;AACvE,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,UAAM,YAAY,MAAM,MAAM,CAAC,UAAU;AACzC,UAAM,UAA2B,CAAC;AAClC,eAAW,QAAQ,WAAW;AAC5B,UAAI;AACF,gBAAQ,KAAK,KAAK,MAAM,IAAI,CAAkB;AAAA,MAChD,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,UAAU,MAA6B;AAC9C,MAAI;AACF,UAAM,MAAM,iBAAiB,IAAI;AACjC,UAAM,QAAQ,IAAI,YAAY,KAAK,KAAK,KAAK,eAAe,CAAC;AAC7D,UAAM,QAAQ,MAAM,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,OAAO,IAAI,QAAQ,YAAY,CAAC;AAC7E,UAAM,MAAM;AACZ,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,cAAc,MAAmC;AAC9D,MAAI;AACF,UAAM,QAAQ,IAAI,cAAc,2BAA2B,IAAI,CAAC;AAChE,WAAO,MAAM,MAAM,QAAQ;AAAA,EAC7B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAMA,eAAe,cAAc,UAAkB,MAAiC;AAC9E,QAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,MAAI;AACF,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,WAAW,UAAU,GAAG,KAAK,UAAU,IAAI,CAAC;AAAA,GAAM,OAAO;AAC/D,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,+BAA+B,KAAK,SAAS,QAAQ,CAAC,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACnH;AACA,WAAO;AAAA,EACT;AACF;AAMA,eAAe,aAAa,MAAc,SAAyC;AACjF,QAAM,YAAY,uBAAuB,IAAI;AAC7C,SAAO,cAAc,WAAW,OAAO;AACzC;AAEA,eAAe,eAAe,MAAc,IAAY,QAA+B;AACrF,QAAM,QAAQ,IAAI,cAAc,2BAA2B,IAAI,CAAC;AAChE,QAAM,MAAM,OAAO,IAAI,MAAM;AAG7B,QAAM,eAA6B;AAAA,IACjC,IAAI,WAAW;AAAA,IACf,MAAM;AAAA,IACN,MAAM,mBAAmB,EAAE,IAAI,MAAM;AAAA,IACrC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AACA,QAAM,aAAa,MAAM,YAAY;AACvC;AAEA,eAAe,YAAY,MAAc,MAA6B;AACpE,QAAM,KAAK,WAAW;AACtB,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AAEzC,QAAM,UAAwB,EAAE,IAAI,MAAM,OAAO,MAAM,UAAU;AACjE,QAAM,aAAa,MAAM,OAAO;AAGhC,QAAM,gBAA+B,EAAE,IAAI,MAAM,WAAW,SAAS,MAAM,UAAU;AACrF,QAAM,eAAe,0BAA0B,IAAI;AACnD,QAAM,cAAc,cAAc,aAAa;AACjD;AAIO,SAAS,cAAc,EAAE,KAAK,GAAqB;AACxD,QAAM,EAAE,KAAK,IAAI,OAAO;AACxB,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,QAAM,QAAQ,kBAAkB;AAChC,QAAM,QAAQ,SAAS;AAEvB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuC,IAAI;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,SAA0B,CAAC,CAAC;AAC1D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,CAAC,CAAC;AACpD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAqB,CAAC,CAAC;AACzD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,QAAQ,QAAQ,EAAE;AAG/D,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,CAAC;AACpD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAChD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,EAAE;AACvD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAgC,OAAO;AAGzE,YAAU,MAAM;AACd,aAAS,WAAW;AAClB,UAAI,OAAQ,eAAc,OAAO,IAAI;AAAA,IACvC;AACA,YAAQ,GAAG,UAAU,QAAQ;AAC7B,WAAO,MAAM;AACX,cAAQ,IAAI,UAAU,QAAQ;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,YAAU,MAAM;AACd,qBAAiB,EACd,KAAK,CAAC,QAAQ,YAAY,IAAI,WAAW,WAAW,CAAC,EACrD,MAAM,CAAC,QAAQ;AACd,cAAQ,MAAM,uCAAuC,GAAG;AAAA,IAC1D,CAAC;AAAA,EACL,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACd,QAAI,SAAS;AAEb,mBAAe,OAAO;AACpB,UAAI,CAAC,OAAQ;AACb,YAAM,CAAC,UAAU,YAAY,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC7D,UAAU,IAAI;AAAA,QACd,aAAa,MAAM,mBAAmB;AAAA,QACtC,cAAc,IAAI;AAAA,MACpB,CAAC;AACD,UAAI,CAAC,OAAQ;AACb,eAAS,QAAQ;AACjB,iBAAW,UAAU;AACrB,mBAAa,YAAY;AACzB,eAAS,UAAU,IAAI,CAAC;AAExB,UAAI,aAAa,SAAS,KAAK,iBAAiB,aAAa,QAAQ;AACnE,yBAAiB,CAAC;AAAA,MACpB;AAEA,UAAI,aAAa,SAAS,KAAK,UAAU,WAAW,GAAG;AACrD,qBAAa,WAAW;AAAA,MAC1B;AAEA,UAAI,aAAa,WAAW,KAAK,UAAU,SAAS,GAAG;AACrD,qBAAa,OAAO;AAAA,MACtB;AAAA,IACF;AAEA,SAAK;AACL,UAAM,WAAW,YAAY,MAAM,gBAAgB;AACnD,WAAO,MAAM;AACX,eAAS;AACT,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,eAAe,UAAU,MAAM,CAAC;AAG1C,QAAM,kBAAkB,UAAU,aAAa;AAC/C,QAAM,qBAAqB,iBAAiB,SAAS,UAAU,KAAK;AAGpE,QAAM,uBAAuB;AAAA,IAC3B,OAAO,WAAmB;AACxB,UAAI,CAAC,OAAO,KAAK,KAAK,CAAC,gBAAiB;AACxC,UAAI;AACF,cAAM,eAAe,MAAM,gBAAgB,IAAI,OAAO,KAAK,CAAC;AAC5D,oBAAY,YAAY,gBAAgB,GAAG,MAAM,GAAG,EAAE,CAAC,MAAM,OAAO,KAAK,CAAC,GAAG;AAC7E,0BAAkB,EAAE;AACpB,uBAAe,CAAC;AAAA,MAClB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,CAAC,MAAM,eAAe;AAAA,EACxB;AAEA,QAAM,kBAAkB;AAAA,IACtB,CAAC,QAA4E;AAC3E,YAAM,UAAU,iBAAiB;AACjC,UAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO;AAE7C,UAAI,IAAI,SAAS;AACf,uBAAe,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AACxC,eAAO;AAAA,MACT;AACA,UAAI,IAAI,WAAW;AACjB,uBAAe,CAAC,MAAM,KAAK,IAAI,QAAQ,SAAS,GAAG,IAAI,CAAC,CAAC;AACzD,eAAO;AAAA,MACT;AACA,UAAI,IAAI,QAAQ;AACd,cAAM,MAAM,QAAQ,WAAW;AAC/B,YAAI,IAAK,sBAAqB,IAAI,GAAG;AACrC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,iBAAiB,aAAa,oBAAoB;AAAA,EACrD;AAEA,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,OAAO,UAAU,SAAS,GAAG;AACnC,mBAAa,CAAC,MAAO,MAAM,UAAU,cAAc,OAAQ;AAC3D,qBAAe,CAAC;AAChB;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AACd,UAAI,cAAc,aAAa;AAC7B,qBAAa,OAAO;AAAA,MACtB,OAAO;AACL,aAAK;AAAA,MACP;AACA;AAAA,IACF;AAEA,QAAI,cAAc,eAAe,UAAU,WAAW,EAAG;AAEzD,QAAI,qBAAqB,gBAAgB,GAAG,EAAG;AAG/C,QAAI,UAAU,SAAS,GAAG;AACxB,UAAI,IAAI,WAAW;AACjB,yBAAiB,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAC1C,uBAAe,CAAC;AAAA,MAClB,WAAW,IAAI,YAAY;AACzB,yBAAiB,CAAC,MAAM,KAAK,IAAI,UAAU,SAAS,GAAG,IAAI,CAAC,CAAC;AAC7D,uBAAe,CAAC;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,eAAe;AAAA,IACnB,CAAC,SAAiB;AAChB,UAAI,CAAC,KAAK,KAAK,EAAG;AAClB,kBAAY,MAAM,KAAK,KAAK,CAAC;AAC7B,kBAAY,KAAK,KAAK,CAAC;AACvB,eAAS,EAAE;AAAA,IACb;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAEA,QAAM,cAAc,mBAAmB,OAAO;AAG9C,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,MAAM,EAAE,YAAY,UAAU,EAAE,YAAY;AAAA,EAC/C,EAAE;AACF,QAAM,iBAAiB,MAAM,SAAS,IAAI,KAAK,IAAI,iBAAiB,CAAC,IAAI,IAAI;AAC7E,QAAM,qBACJ,cAAc,eAAe,mBACxB,oBAAqB,gBAAgB,SAAS,UAAU,IAAK,KAAK,IACnE,UAAU,SAAS,IACjB,IACA;AAGR,QAAM,cACJ,cAAc,eAAe,kBAC3B;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV;AAAA,MACA,YAAY,CAAC;AAAA,MACb,WAAW;AAAA,MACX,cAAc;AAAA,MACd,UAAU;AAAA,MACV,eAAe,UAAU;AAAA,MACzB,aAAa;AAAA,MACb;AAAA;AAAA,EACF,IAEA,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA,OAAO,cAAc;AAAA;AAAA,IACvB;AAAA,IACA,oBAAC,UAAO,cAAc,UAAU,SAAS,GAAG;AAAA,KAC9C;AAGJ,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,wBAAC,aAAU,OAAc,MAAY,OAAc,OAAc;AAAA,IACjE,oBAAC,eAAY,OAAc,UAAoB,aAA0B;AAAA,IACxE,cAAc,eAAe,oBAAC,kBAAe,WAAsB,OAAc;AAAA,IAClF,oBAAC,aAAU,OAAc;AAAA,IACzB;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,YAAY,aAAa,iBAAiB;AAAA;AAAA,IAC5C;AAAA,IACC;AAAA,KACH;AAEJ;;;AD59BA,eAAsB,oBAAoB,MAA6B;AACrE,QAAM,EAAE,cAAc,IAAI,OAAO,MAAM,cAAc,eAAe,EAAE,KAAK,CAAC,CAAC;AAC7E,QAAM,cAAc;AACtB;","names":[]}
|