@h-rig/cli 0.0.6-alpha.86 → 0.0.6-alpha.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/bin/rig.js +287 -578
  2. package/dist/src/app-opentui/adapters/common.d.ts +3 -0
  3. package/dist/src/app-opentui/adapters/common.js +4 -0
  4. package/dist/src/app-opentui/adapters/family.js +31 -4
  5. package/dist/src/app-opentui/adapters/pi-attach.d.ts +7 -0
  6. package/dist/src/app-opentui/adapters/pi-attach.js +527 -473
  7. package/dist/src/app-opentui/adapters/tasks.js +82 -468
  8. package/dist/src/app-opentui/bootstrap.js +287 -578
  9. package/dist/src/app-opentui/command-palette.js +1 -0
  10. package/dist/src/app-opentui/drone.js +1 -0
  11. package/dist/src/app-opentui/index.js +127 -446
  12. package/dist/src/app-opentui/keymap.js +2 -387
  13. package/dist/src/app-opentui/list-search.d.ts +5 -1
  14. package/dist/src/app-opentui/list-search.js +2 -2
  15. package/dist/src/app-opentui/pi-host-child.js +31 -4
  16. package/dist/src/app-opentui/pi-pty-host.d.ts +14 -64
  17. package/dist/src/app-opentui/pi-pty-host.js +3 -397
  18. package/dist/src/app-opentui/react/App.js +107 -433
  19. package/dist/src/app-opentui/react/Backdrop.js +1 -0
  20. package/dist/src/app-opentui/react/ChromeHost.js +34 -410
  21. package/dist/src/app-opentui/react/SceneFrameView.js +55 -5
  22. package/dist/src/app-opentui/react/launch.js +171 -472
  23. package/dist/src/app-opentui/react/syntax.js +1 -0
  24. package/dist/src/app-opentui/registry.js +99 -487
  25. package/dist/src/app-opentui/render/graphics.js +1 -0
  26. package/dist/src/app-opentui/render/hover.d.ts +11 -0
  27. package/dist/src/app-opentui/render/hover.js +34 -0
  28. package/dist/src/app-opentui/render/native-host.js +1 -0
  29. package/dist/src/app-opentui/render/panels.js +50 -3
  30. package/dist/src/app-opentui/render/preloader.js +1 -0
  31. package/dist/src/app-opentui/render/scene.js +1 -0
  32. package/dist/src/app-opentui/render/terminal-handoff.d.ts +16 -0
  33. package/dist/src/app-opentui/render/terminal-handoff.js +14 -0
  34. package/dist/src/app-opentui/render/text.d.ts +13 -0
  35. package/dist/src/app-opentui/render/text.js +54 -5
  36. package/dist/src/app-opentui/render/type-bar.js +1 -0
  37. package/dist/src/app-opentui/runtime.js +127 -446
  38. package/dist/src/app-opentui/scenes/command.js +1 -0
  39. package/dist/src/app-opentui/scenes/doctor.js +1 -0
  40. package/dist/src/app-opentui/scenes/error.js +1 -0
  41. package/dist/src/app-opentui/scenes/family-domains/agent.js +1 -0
  42. package/dist/src/app-opentui/scenes/family-domains/browser.js +1 -0
  43. package/dist/src/app-opentui/scenes/family-domains/dist.js +1 -0
  44. package/dist/src/app-opentui/scenes/family-domains/git.js +1 -0
  45. package/dist/src/app-opentui/scenes/family-domains/github.js +1 -0
  46. package/dist/src/app-opentui/scenes/family-domains/harness.js +1 -0
  47. package/dist/src/app-opentui/scenes/family-domains/index.js +1 -0
  48. package/dist/src/app-opentui/scenes/family-domains/kit.js +1 -0
  49. package/dist/src/app-opentui/scenes/family-domains/profile.js +1 -0
  50. package/dist/src/app-opentui/scenes/family-domains/queue.js +1 -0
  51. package/dist/src/app-opentui/scenes/family-domains/remote.js +1 -0
  52. package/dist/src/app-opentui/scenes/family-domains/review.js +1 -0
  53. package/dist/src/app-opentui/scenes/family-domains/setup.js +1 -0
  54. package/dist/src/app-opentui/scenes/family-domains/stats.js +1 -0
  55. package/dist/src/app-opentui/scenes/family.js +1 -0
  56. package/dist/src/app-opentui/scenes/fleet.js +3 -5
  57. package/dist/src/app-opentui/scenes/handoff.js +1 -0
  58. package/dist/src/app-opentui/scenes/help.js +1 -0
  59. package/dist/src/app-opentui/scenes/inbox.js +1 -0
  60. package/dist/src/app-opentui/scenes/init.js +1 -0
  61. package/dist/src/app-opentui/scenes/inspect.js +1 -0
  62. package/dist/src/app-opentui/scenes/main.js +1 -0
  63. package/dist/src/app-opentui/scenes/pi.js +1 -0
  64. package/dist/src/app-opentui/scenes/plugin.js +1 -0
  65. package/dist/src/app-opentui/scenes/repo.js +1 -0
  66. package/dist/src/app-opentui/scenes/run-detail.js +1 -0
  67. package/dist/src/app-opentui/scenes/server.js +1 -0
  68. package/dist/src/app-opentui/scenes/tasks.js +3 -5
  69. package/dist/src/app-opentui/scenes/workspace.js +1 -0
  70. package/dist/src/app-opentui/selectable.js +1 -0
  71. package/dist/src/app-opentui/theme.d.ts +1 -0
  72. package/dist/src/app-opentui/theme.js +1 -0
  73. package/dist/src/commands/_operator-view.js +31 -4
  74. package/dist/src/commands/_pi-frontend.d.ts +25 -0
  75. package/dist/src/commands/_pi-frontend.js +32 -4
  76. package/dist/src/commands/run.js +31 -4
  77. package/dist/src/commands/task.js +31 -4
  78. package/dist/src/commands.js +31 -4
  79. package/dist/src/index.js +31 -4
  80. package/package.json +8 -8
@@ -502,7 +502,7 @@ function reduceAppEvent(state, event) {
502
502
  }
503
503
 
504
504
  // packages/cli/src/app-opentui/runtime.ts
505
- import { BoxRenderable as BoxRenderable3, RGBA as RGBA8, StyledText as StyledText4, TextRenderable as TextRenderable4, createCliRenderer } from "@opentui/core";
505
+ import { BoxRenderable as BoxRenderable3, RGBA as RGBA7, StyledText as StyledText3, TextRenderable as TextRenderable4, createCliRenderer } from "@opentui/core";
506
506
 
507
507
  // packages/cli/src/app-opentui/command-pty-host.ts
508
508
  import { basename } from "path";
@@ -1309,395 +1309,10 @@ function cycleCompletion(value, state, candidates = commandCandidates()) {
1309
1309
  }
1310
1310
 
1311
1311
  // packages/cli/src/app-opentui/pi-pty-host.ts
1312
- import { fileURLToPath as fileURLToPath2 } from "url";
1313
- import { basename as basename2 } from "path";
1314
- import { RGBA, StyledText, TextAttributes } from "@opentui/core";
1315
- import { Terminal as XtermTerminal2 } from "@xterm/headless";
1316
- var MIN_COLS2 = 40;
1317
- var MIN_ROWS2 = 12;
1318
- var MAX_ROWS2 = 300;
1319
- var MAX_SNAPSHOT_LINES2 = 360;
1320
- var STYLED_SNAPSHOT_MARGIN = 6;
1321
- var SNAPSHOT_DELAY_MS2 = 120;
1322
- var fallbackChildScriptPath = fileURLToPath2(new URL("./pi-host-child.ts", import.meta.url));
1323
- var activeHost2 = null;
1324
- function clampCols2(cols) {
1325
- return Math.max(MIN_COLS2, Math.trunc(cols || 100));
1326
- }
1327
- function clampRows2(rows) {
1328
- return Math.max(MIN_ROWS2, Math.min(MAX_ROWS2, Math.trunc(rows || 35)));
1329
- }
1330
- var XTERM_COLOR_MODE_INDEXED_16 = 16777216;
1331
- var XTERM_COLOR_MODE_INDEXED_256 = 33554432;
1332
- var XTERM_COLOR_MODE_RGB = 50331648;
1333
- function rgbaFromXtermColor(mode, value) {
1334
- if (mode === 1 || mode === 2 || mode === XTERM_COLOR_MODE_INDEXED_16 || mode === XTERM_COLOR_MODE_INDEXED_256) {
1335
- return RGBA.fromIndex(value);
1336
- }
1337
- if (mode === 3 || mode === XTERM_COLOR_MODE_RGB) {
1338
- return RGBA.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255);
1339
- }
1340
- return;
1341
- }
1342
- function textAttributesFromCell(cell) {
1343
- let attributes = TextAttributes.NONE;
1344
- if (cell.isBold())
1345
- attributes |= TextAttributes.BOLD;
1346
- if (cell.isDim())
1347
- attributes |= TextAttributes.DIM;
1348
- if (cell.isItalic())
1349
- attributes |= TextAttributes.ITALIC;
1350
- if (cell.isUnderline())
1351
- attributes |= TextAttributes.UNDERLINE;
1352
- if (cell.isBlink())
1353
- attributes |= TextAttributes.BLINK;
1354
- if (cell.isInverse())
1355
- attributes |= TextAttributes.INVERSE;
1356
- if (cell.isInvisible())
1357
- attributes |= TextAttributes.HIDDEN;
1358
- if (cell.isStrikethrough())
1359
- attributes |= TextAttributes.STRIKETHROUGH;
1360
- return attributes;
1361
- }
1362
- function sameRgba(a, b) {
1363
- if (!a && !b)
1364
- return true;
1365
- return Boolean(a && b && a.equals(b));
1366
- }
1367
- function sameStyle(a, b) {
1368
- return sameRgba(a.fg, b.fg) && sameRgba(a.bg, b.bg) && (a.attributes ?? 0) === (b.attributes ?? 0);
1369
- }
1370
- function styleFromCell(cell) {
1371
- return {
1372
- fg: rgbaFromXtermColor(cell.getFgColorMode(), cell.getFgColor()),
1373
- bg: rgbaFromXtermColor(cell.getBgColorMode(), cell.getBgColor()),
1374
- attributes: textAttributesFromCell(cell)
1375
- };
1376
- }
1377
- function lineToStyledText(line, cols) {
1378
- if (!line)
1379
- return new StyledText([{ __isChunk: true, text: "" }]);
1380
- const chunks = [];
1381
- let run = "";
1382
- let runStyle = null;
1383
- const flush = () => {
1384
- if (!run)
1385
- return;
1386
- chunks.push({
1387
- __isChunk: true,
1388
- text: run,
1389
- ...runStyle?.fg ? { fg: runStyle.fg } : {},
1390
- ...runStyle?.bg ? { bg: runStyle.bg } : {},
1391
- ...(runStyle?.attributes ?? 0) !== 0 ? { attributes: runStyle.attributes } : {}
1392
- });
1393
- run = "";
1394
- };
1395
- for (let index = 0;index < cols; index += 1) {
1396
- const cell = line.getCell(index);
1397
- if (!cell) {
1398
- if (runStyle !== null)
1399
- flush();
1400
- runStyle = null;
1401
- run += " ";
1402
- continue;
1403
- }
1404
- if (cell.getWidth() === 0)
1405
- continue;
1406
- const style = styleFromCell(cell);
1407
- if (!runStyle || !sameStyle(runStyle, style)) {
1408
- flush();
1409
- runStyle = style;
1410
- }
1411
- run += cell.getChars() || " ";
1412
- }
1413
- flush();
1414
- return new StyledText(chunks.length > 0 ? chunks : [{ __isChunk: true, text: "" }]);
1415
- }
1416
- function childCommandPrefix2() {
1417
- const execName = basename2(process.execPath).toLowerCase();
1418
- const currentEntry = process.argv[1];
1419
- if (execName === "bun" || execName === "bun.exe") {
1420
- return currentEntry ? [process.execPath, currentEntry, "__opentui-pi-host"] : [process.execPath, fallbackChildScriptPath];
1421
- }
1422
- return [process.execPath, "__opentui-pi-host"];
1423
- }
1424
- function withEnv2(base) {
1425
- const env = {};
1426
- for (const [key, value] of Object.entries(base ?? process.env)) {
1427
- if (key === "RIG_PLAIN" || key === "RIG_CLI_PLAIN_HELP" || key === "NO_COLOR")
1428
- continue;
1429
- if (typeof value === "string")
1430
- env[key] = value;
1431
- }
1432
- return {
1433
- ...env,
1434
- TERM: "xterm-256color",
1435
- COLORTERM: "truecolor",
1436
- FORCE_COLOR: env.FORCE_COLOR ?? "1",
1437
- RIG_OPENTUI_PI_HOST: "1"
1438
- };
1439
- }
1440
1312
  function getActivePiHost() {
1441
- return activeHost2 && !activeHost2.disposed ? activeHost2 : null;
1442
- }
1443
- function stopActivePiHost(reason = "detach") {
1444
- activeHost2?.dispose(reason);
1445
- activeHost2 = null;
1446
- }
1447
-
1448
- class PiPtyHost {
1449
- runId;
1450
- projectRoot;
1451
- onSnapshot;
1452
- onExit;
1453
- onError;
1454
- terminal;
1455
- disposables = [];
1456
- decoder = new TextDecoder("utf-8");
1457
- proc = null;
1458
- pty = null;
1459
- status = "starting";
1460
- cols;
1461
- rows;
1462
- message = "starting bundled Pi";
1463
- lastResizeError = null;
1464
- exitCode;
1465
- signal;
1466
- notifyTimer = null;
1467
- lastStreamKey = "";
1468
- _disposed = false;
1469
- constructor(options) {
1470
- this.runId = options.runId;
1471
- this.projectRoot = options.projectRoot;
1472
- this.cols = clampCols2(options.cols);
1473
- this.rows = clampRows2(options.rows);
1474
- this.onSnapshot = options.onSnapshot;
1475
- this.onExit = options.onExit;
1476
- this.onError = options.onError;
1477
- this.terminal = new XtermTerminal2({
1478
- allowProposedApi: true,
1479
- cols: this.cols,
1480
- rows: this.rows,
1481
- scrollback: 1000
1482
- });
1483
- this.registerTerminalResponders();
1484
- this.disposables.push(this.terminal.onWriteParsed(() => {
1485
- if (this._disposed)
1486
- return;
1487
- const snapshot = this.createSnapshot();
1488
- const key = snapshot.lines.join(`
1489
- `);
1490
- if (key === this.lastStreamKey)
1491
- return;
1492
- this.lastStreamKey = key;
1493
- this.onSnapshot?.(snapshot);
1494
- }));
1495
- }
1496
- get disposed() {
1497
- return this._disposed;
1498
- }
1499
- get snapshot() {
1500
- return this.createSnapshot();
1501
- }
1502
- async start() {
1503
- if (this._disposed)
1504
- throw new Error("Pi PTY host is disposed.");
1505
- if (typeof Bun.Terminal !== "function") {
1506
- throw new Error("Bun native PTY is unavailable in this runtime. Pi host requires Bun.Terminal.");
1507
- }
1508
- const spawnOptions = {
1509
- cwd: this.projectRoot,
1510
- env: withEnv2(process.env),
1511
- terminal: {
1512
- cols: this.cols,
1513
- rows: this.rows,
1514
- name: "xterm-256color",
1515
- data: (_terminal, data) => this.handlePtyData(data)
1516
- }
1517
- };
1518
- const proc = Bun.spawn([
1519
- ...childCommandPrefix2(),
1520
- "--run-id",
1521
- this.runId,
1522
- "--project-root",
1523
- this.projectRoot
1524
- ], spawnOptions);
1525
- if (!proc.terminal)
1526
- throw new Error("Bun did not attach a terminal to the bundled Pi child process.");
1527
- this.proc = proc;
1528
- this.pty = proc.terminal;
1529
- this.status = "running";
1530
- this.message = "bundled Pi running inside this app";
1531
- this.emitSnapshotSoon(0);
1532
- proc.exited.then((exitCode) => {
1533
- if (this._disposed)
1534
- return;
1535
- this.status = exitCode === 0 ? "exited" : "failed";
1536
- this.exitCode = exitCode;
1537
- this.signal = null;
1538
- this.message = exitCode === 0 ? "bundled Pi exited" : `bundled Pi exited with code ${exitCode}`;
1539
- const snapshot = this.createSnapshot();
1540
- this.onSnapshot?.(snapshot);
1541
- this.onExit?.(snapshot);
1542
- if (activeHost2 === this)
1543
- activeHost2 = null;
1544
- this.dispose("exit", { kill: false, notify: false });
1545
- }).catch((error) => {
1546
- if (this._disposed)
1547
- return;
1548
- this.status = "failed";
1549
- this.message = error instanceof Error ? error.message : String(error);
1550
- const snapshot = this.createSnapshot();
1551
- this.onSnapshot?.(snapshot);
1552
- this.onError?.(error, snapshot);
1553
- if (activeHost2 === this)
1554
- activeHost2 = null;
1555
- this.dispose("error", { kill: false, notify: false });
1556
- });
1557
- }
1558
- write(data) {
1559
- if (this._disposed || !this.pty)
1560
- return;
1561
- try {
1562
- this.pty.write(data);
1563
- } catch (error) {
1564
- this.status = "failed";
1565
- this.message = error instanceof Error ? error.message : String(error);
1566
- const snapshot = this.createSnapshot();
1567
- this.onSnapshot?.(snapshot);
1568
- this.onError?.(error, snapshot);
1569
- }
1570
- }
1571
- resize(cols, rows) {
1572
- const nextCols = clampCols2(cols);
1573
- const nextRows = clampRows2(rows);
1574
- if (nextCols === this.cols && nextRows === this.rows)
1575
- return;
1576
- this.cols = nextCols;
1577
- this.rows = nextRows;
1578
- this.terminal.resize(nextCols, nextRows);
1579
- try {
1580
- this.pty?.resize(nextCols, nextRows);
1581
- this.lastResizeError = null;
1582
- } catch (error) {
1583
- this.lastResizeError = error instanceof Error ? error.message : String(error);
1584
- }
1585
- this.emitSnapshotSoon(0);
1586
- }
1587
- detach() {
1588
- this.dispose("detach");
1589
- return this.createSnapshot("detached from bundled Pi");
1590
- }
1591
- dispose(reason = "dispose", options = {}) {
1592
- if (this._disposed)
1593
- return;
1594
- this._disposed = true;
1595
- if (this.notifyTimer)
1596
- clearTimeout(this.notifyTimer);
1597
- this.notifyTimer = null;
1598
- for (const disposable of this.disposables.splice(0)) {
1599
- try {
1600
- disposable.dispose();
1601
- } catch {}
1602
- }
1603
- if (options.kill !== false) {
1604
- try {
1605
- this.proc?.kill("SIGTERM");
1606
- } catch {}
1607
- }
1608
- try {
1609
- this.pty?.close();
1610
- } catch {}
1611
- try {
1612
- this.terminal.dispose();
1613
- } catch {}
1614
- if (activeHost2 === this)
1615
- activeHost2 = null;
1616
- if (options.notify) {
1617
- this.message = reason;
1618
- this.onSnapshot?.(this.createSnapshot(reason));
1619
- }
1620
- }
1621
- handlePtyData(data) {
1622
- if (this._disposed)
1623
- return;
1624
- const text = this.decoder.decode(data, { stream: true });
1625
- this.respondToRawTerminalQueries(text);
1626
- this.terminal.write(data);
1627
- }
1628
- emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS2) {
1629
- if (this._disposed || this.notifyTimer)
1630
- return;
1631
- this.notifyTimer = setTimeout(() => {
1632
- this.notifyTimer = null;
1633
- if (this._disposed)
1634
- return;
1635
- this.onSnapshot?.(this.createSnapshot());
1636
- }, delayMs);
1637
- }
1638
- createSnapshot(message = this.message) {
1639
- const buffer = this.terminal.buffer.active;
1640
- const end = buffer.length;
1641
- const start = Math.max(0, end - MAX_SNAPSHOT_LINES2);
1642
- const styledStart = Math.max(start, end - this.rows - STYLED_SNAPSHOT_MARGIN);
1643
- const lines = [];
1644
- const styledLines = [];
1645
- for (let row = start;row < end; row += 1) {
1646
- const line = buffer.getLine(row);
1647
- lines.push((line?.translateToString(false) ?? "").slice(0, this.cols));
1648
- if (row >= styledStart)
1649
- styledLines[lines.length - 1] = lineToStyledText(line, this.cols);
1650
- }
1651
- while (lines.length < this.rows) {
1652
- lines.push("");
1653
- styledLines[lines.length - 1] = new StyledText([{ __isChunk: true, text: "" }]);
1654
- }
1655
- const resolvedMessage = this.lastResizeError ? `resize degraded: ${this.lastResizeError}` : message;
1656
- return {
1657
- runId: this.runId,
1658
- status: this.status,
1659
- cols: this.cols,
1660
- rows: this.rows,
1661
- lines,
1662
- styledLines,
1663
- message: resolvedMessage,
1664
- ...this.lastResizeError ? { resizeError: this.lastResizeError } : {},
1665
- ...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
1666
- ...this.signal !== undefined ? { signal: this.signal } : {}
1667
- };
1668
- }
1669
- registerTerminalResponders() {
1670
- this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "c" }, (params) => {
1671
- if (params.length === 0 || params[0] === 0)
1672
- this.write("\x1B[?62;22c");
1673
- return false;
1674
- }));
1675
- this.disposables.push(this.terminal.parser.registerCsiHandler({ prefix: ">", final: "c" }, (params) => {
1676
- if (params.length === 0 || params[0] === 0)
1677
- this.write("\x1B[>0;0;0c");
1678
- return false;
1679
- }));
1680
- this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "n" }, (params) => {
1681
- if (params[0] === 5) {
1682
- this.write("\x1B[0n");
1683
- } else if (params[0] === 6) {
1684
- const row = this.terminal.buffer.active.cursorY + 1;
1685
- const col = this.terminal.buffer.active.cursorX + 1;
1686
- this.write(`\x1B[${row};${col}R`);
1687
- }
1688
- return false;
1689
- }));
1690
- }
1691
- respondToRawTerminalQueries(text) {
1692
- if (!text)
1693
- return;
1694
- const decrqm = /\x1b\[\?(\d+)\$p/g;
1695
- let match;
1696
- while ((match = decrqm.exec(text)) !== null) {
1697
- this.write(`\x1B[?${match[1]};2$y`);
1698
- }
1699
- }
1313
+ return null;
1700
1314
  }
1315
+ function stopActivePiHost(_reason) {}
1701
1316
 
1702
1317
  // packages/cli/src/app-opentui/keymap.ts
1703
1318
  var autocompleteState;
@@ -2283,13 +1898,14 @@ import {
2283
1898
  dim as otuiDim,
2284
1899
  fg as otuiFg,
2285
1900
  t,
2286
- TextAttributes as TextAttributes2
1901
+ TextAttributes
2287
1902
  } from "@opentui/core";
2288
1903
  var RIG_UI = {
2289
1904
  bg: "#070809",
2290
1905
  bg2: "#0b0c0e",
2291
1906
  panel: "#101115",
2292
1907
  panel2: "#14161b",
1908
+ hover: "#181b24",
2293
1909
  glass: "#1e2230",
2294
1910
  border: "#2a2e3a",
2295
1911
  ink: "#f4f5f8",
@@ -2318,7 +1934,7 @@ var styles = {
2318
1934
  };
2319
1935
 
2320
1936
  // packages/cli/src/app-opentui/drone.ts
2321
- import { RGBA as RGBA2, StyledText as StyledText2, TextAttributes as TextAttributes3 } from "@opentui/core";
1937
+ import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
2322
1938
  var MINI_DRONE = [
2323
1939
  "(!!!) (!!!)",
2324
1940
  " \\%==%/ ",
@@ -2334,13 +1950,13 @@ var LEAD_MARK = [
2334
1950
  var BLADE_FRAMES = ["---", "\\\\\\", "|||", "///"];
2335
1951
  var EYE_FRAMES = ["o", "@", "\u2022", "."];
2336
1952
  var COLOR = {
2337
- body: RGBA2.fromHex(RIG_UI.lime),
2338
- mini: RGBA2.fromHex(RIG_UI.limeDim),
2339
- rotor: RGBA2.fromHex(RIG_UI.cyan),
2340
- path: RGBA2.fromHex(RIG_UI.cyan),
2341
- eye: RGBA2.fromHex(RIG_UI.ink),
2342
- dim: RGBA2.fromHex(RIG_UI.ink4),
2343
- ink: RGBA2.fromHex(RIG_UI.ink2)
1953
+ body: RGBA.fromHex(RIG_UI.lime),
1954
+ mini: RGBA.fromHex(RIG_UI.limeDim),
1955
+ rotor: RGBA.fromHex(RIG_UI.cyan),
1956
+ path: RGBA.fromHex(RIG_UI.cyan),
1957
+ eye: RGBA.fromHex(RIG_UI.ink),
1958
+ dim: RGBA.fromHex(RIG_UI.ink4),
1959
+ ink: RGBA.fromHex(RIG_UI.ink2)
2344
1960
  };
2345
1961
  function bladeForTick(tick, phase = 0) {
2346
1962
  return BLADE_FRAMES[(Math.floor(tick / 3) + phase) % BLADE_FRAMES.length];
@@ -2350,12 +1966,12 @@ function eyeForTick(tick, phase = 0) {
2350
1966
  return pulse > 0.55 ? EYE_FRAMES[1] : pulse > 0.1 ? EYE_FRAMES[0] : pulse > -0.45 ? EYE_FRAMES[2] : EYE_FRAMES[3];
2351
1967
  }
2352
1968
  function chunk(text, fg, bold = false, dim = false) {
2353
- let attributes = TextAttributes3.NONE;
1969
+ let attributes = TextAttributes2.NONE;
2354
1970
  if (bold)
2355
- attributes |= TextAttributes3.BOLD;
1971
+ attributes |= TextAttributes2.BOLD;
2356
1972
  if (dim)
2357
- attributes |= TextAttributes3.DIM;
2358
- return { __isChunk: true, text, fg, ...attributes !== TextAttributes3.NONE ? { attributes } : {} };
1973
+ attributes |= TextAttributes2.DIM;
1974
+ return { __isChunk: true, text, fg, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
2359
1975
  }
2360
1976
  function styledLine(text, colorFor) {
2361
1977
  const chunks = [];
@@ -2376,7 +1992,7 @@ function styledLine(text, colorFor) {
2376
1992
  run += char;
2377
1993
  }
2378
1994
  flush();
2379
- return new StyledText2(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
1995
+ return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
2380
1996
  }
2381
1997
  function droneColor(char) {
2382
1998
  if (char === "?" || char === "o" || char === "@" || char === "\u2022")
@@ -2468,7 +2084,7 @@ function makeSceneFrame(input) {
2468
2084
  }
2469
2085
 
2470
2086
  // packages/cli/src/app-opentui/render/graphics.ts
2471
- import { FrameBufferRenderable, RGBA as RGBA3 } from "@opentui/core";
2087
+ import { FrameBufferRenderable, RGBA as RGBA2 } from "@opentui/core";
2472
2088
 
2473
2089
  // packages/cli/src/app-opentui/render/ascii-fleet.ts
2474
2090
  var LEAD_DRONE = [
@@ -2612,13 +2228,13 @@ var GLOW_FALLOFF_EXP_ASCII = 2.2;
2612
2228
  // packages/cli/src/app-opentui/render/graphics.ts
2613
2229
  var BRAILLE_SAMPLES_X = 2;
2614
2230
  var BRAILLE_SAMPLES_Y = 4;
2615
- var TRANSPARENT = RGBA3.fromValues(0, 0, 0, 0);
2616
- var BACKDROP = RGBA3.fromHex(RIG_UI.bg);
2617
- var PANEL_BG = RGBA3.fromInts(16, 17, 21, 184);
2618
- var PANEL_HEADER_BG = RGBA3.fromInts(16, 17, 21, 188);
2619
- var PANEL_LINE = RGBA3.fromInts(255, 255, 255, 20);
2620
- var PANEL_LINE_DIM = RGBA3.fromInts(255, 255, 255, 8);
2621
- var PANEL_TEXT_DIM = RGBA3.fromInts(108, 110, 121, 255);
2231
+ var TRANSPARENT = RGBA2.fromValues(0, 0, 0, 0);
2232
+ var BACKDROP = RGBA2.fromHex(RIG_UI.bg);
2233
+ var PANEL_BG = RGBA2.fromInts(16, 17, 21, 184);
2234
+ var PANEL_HEADER_BG = RGBA2.fromInts(16, 17, 21, 188);
2235
+ var PANEL_LINE = RGBA2.fromInts(255, 255, 255, 20);
2236
+ var PANEL_LINE_DIM = RGBA2.fromInts(255, 255, 255, 8);
2237
+ var PANEL_TEXT_DIM = RGBA2.fromInts(108, 110, 121, 255);
2622
2238
  var AC_RGB = [204, 255, 77];
2623
2239
  var C2_RGB = [86, 216, 255];
2624
2240
  var MG_RGB = [255, 121, 176];
@@ -2723,7 +2339,7 @@ function paletteColor(ac, c2, mg, ink) {
2723
2339
  const b = (AC_RGB[2] * ac + C2_RGB[2] * c2 + MG_RGB[2] * mg + INK_RGB[2] * ink) / total;
2724
2340
  const intensity = Math.min(1, total / 4);
2725
2341
  const lift = 0.34 + intensity * 0.66;
2726
- return RGBA3.fromInts(Math.round(r * lift), Math.round(g * lift), Math.round(b * lift), 255);
2342
+ return RGBA2.fromInts(Math.round(r * lift), Math.round(g * lift), Math.round(b * lift), 255);
2727
2343
  }
2728
2344
  function clearCanvas(canvas) {
2729
2345
  canvas.ac.fill(0);
@@ -3078,8 +2694,8 @@ function staticFleetTick(scene) {
3078
2694
  }
3079
2695
  function withAlpha(hex, alpha) {
3080
2696
  const a = Math.max(0, Math.min(255, Math.round(alpha * 255)));
3081
- const [r, g, b] = RGBA3.fromHex(hex).toInts();
3082
- return RGBA3.fromInts(r, g, b, a);
2697
+ const [r, g, b] = RGBA2.fromHex(hex).toInts();
2698
+ return RGBA2.fromInts(r, g, b, a);
3083
2699
  }
3084
2700
  function asciiFleetColor(char, row, alpha) {
3085
2701
  if (char === "@" || char === "$" || char === "o")
@@ -3087,7 +2703,7 @@ function asciiFleetColor(char, row, alpha) {
3087
2703
  if (char === "%" || char === "!" || char === "/" || char === "\\" || char === "|")
3088
2704
  return withAlpha(RIG_UI.cyan, alpha);
3089
2705
  if (char === "." || char === "'" || char === "_" || row < 3 || row > FLEET_GRID_HEIGHT - 4) {
3090
- return RGBA3.fromInts(108, 110, 121, Math.min(170, Math.max(0, Math.min(255, Math.round(alpha * 255)))));
2706
+ return RGBA2.fromInts(108, 110, 121, Math.min(170, Math.max(0, Math.min(255, Math.round(alpha * 255)))));
3091
2707
  }
3092
2708
  return withAlpha(RIG_UI.limeDim, alpha);
3093
2709
  }
@@ -3200,16 +2816,70 @@ function sparklineString(values, width) {
3200
2816
  }
3201
2817
 
3202
2818
  // packages/cli/src/app-opentui/render/text.ts
3203
- import { RGBA as RGBA4, TextAttributes as TextAttributes4, TextRenderable } from "@opentui/core";
3204
- var TRANSPARENT2 = RGBA4.fromInts(0, 0, 0, 0);
2819
+ import { RGBA as RGBA3, TextAttributes as TextAttributes3, TextRenderable } from "@opentui/core";
2820
+
2821
+ // packages/cli/src/app-opentui/render/hover.ts
2822
+ var hoveredId;
2823
+ var listeners = new Set;
2824
+ function getHoveredSelectableId() {
2825
+ return hoveredId;
2826
+ }
2827
+ function isHovered(id) {
2828
+ return id !== undefined && id === hoveredId;
2829
+ }
2830
+ function setHoveredSelectableId(id) {
2831
+ if (hoveredId === id)
2832
+ return;
2833
+ hoveredId = id;
2834
+ for (const listener of listeners)
2835
+ listener();
2836
+ }
2837
+ function clearHoveredSelectableId(id) {
2838
+ if (id !== undefined && hoveredId === id)
2839
+ setHoveredSelectableId(undefined);
2840
+ }
2841
+ function subscribeHover(listener) {
2842
+ listeners.add(listener);
2843
+ return () => {
2844
+ listeners.delete(listener);
2845
+ };
2846
+ }
2847
+
2848
+ // packages/cli/src/app-opentui/render/text.ts
2849
+ var TRANSPARENT2 = RGBA3.fromInts(0, 0, 0, 0);
2850
+ var HOVER_BG = RGBA3.fromHex(RIG_UI.hover);
2851
+ function lineIsClickable(line2) {
2852
+ return line2?.selectable !== undefined || line2?.selectableIndex !== undefined;
2853
+ }
2854
+ function lineSelectableId(line2) {
2855
+ return line2?.selectable?.id ?? line2?.selectableId;
2856
+ }
2857
+ function lineBackground(line2) {
2858
+ if (line2?.bg)
2859
+ return RGBA3.fromHex(line2.bg);
2860
+ const id = lineSelectableId(line2);
2861
+ if (id !== undefined && isHovered(id))
2862
+ return HOVER_BG;
2863
+ return TRANSPARENT2;
2864
+ }
3205
2865
  function selectableMouseHandler(currentLineRef, onLineMouseDown) {
3206
2866
  return (event) => {
3207
2867
  const currentLine = currentLineRef();
3208
- if (currentLine?.selectableIndex === undefined)
2868
+ if (!lineIsClickable(currentLine))
3209
2869
  return;
3210
2870
  onLineMouseDown?.(currentLine, event);
3211
2871
  };
3212
2872
  }
2873
+ function hoverHandlers(currentLineRef) {
2874
+ return {
2875
+ onMouseOver: () => {
2876
+ const id = lineSelectableId(currentLineRef());
2877
+ if (id !== undefined)
2878
+ setHoveredSelectableId(id);
2879
+ },
2880
+ onMouseOut: () => clearHoveredSelectableId(lineSelectableId(currentLineRef()))
2881
+ };
2882
+ }
3213
2883
  function createFlowTextLine(renderer, id, onLineMouseDown) {
3214
2884
  let currentLine;
3215
2885
  const renderable = new TextRenderable(renderer, {
@@ -3220,7 +2890,8 @@ function createFlowTextLine(renderer, id, onLineMouseDown) {
3220
2890
  flexShrink: 0,
3221
2891
  fg: RIG_UI.ink2,
3222
2892
  selectable: true,
3223
- onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown)
2893
+ onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown),
2894
+ ...hoverHandlers(() => currentLine)
3224
2895
  });
3225
2896
  renderable.setRigSceneLine = (line2) => {
3226
2897
  currentLine = line2;
@@ -3234,13 +2905,13 @@ function applyFlowTextLine(renderable, line2, width) {
3234
2905
  renderable.width = Math.max(1, width);
3235
2906
  renderable.content = line2?.styledText ?? line2?.text ?? "";
3236
2907
  renderable.fg = line2?.fg ?? RIG_UI.ink2;
3237
- renderable.bg = line2?.bg ?? TRANSPARENT2;
3238
- renderable.attributes = line2?.bold ? TextAttributes4.BOLD : line2?.dim ? TextAttributes4.DIM : 0;
2908
+ renderable.bg = lineBackground(line2);
2909
+ renderable.attributes = line2?.bold ? TextAttributes3.BOLD : line2?.dim ? TextAttributes3.DIM : 0;
3239
2910
  }
3240
2911
 
3241
2912
  // packages/cli/src/app-opentui/render/panels.ts
3242
- import { RGBA as RGBA5, ScrollBoxRenderable } from "@opentui/core";
3243
- var TRANSPARENT3 = RGBA5.fromInts(0, 0, 0, 0);
2913
+ import { RGBA as RGBA4, ScrollBoxRenderable } from "@opentui/core";
2914
+ var TRANSPARENT3 = RGBA4.fromInts(0, 0, 0, 0);
3244
2915
  var MAX_PANEL_LINES = 420;
3245
2916
  var PANEL_OPAQUE_ALPHA = 255;
3246
2917
  var PANEL_BORDER = hexToRgba(RIG_UI.border, 255);
@@ -3249,8 +2920,8 @@ function hexToRgba(hex, alpha) {
3249
2920
  const full = clean.length === 3 ? clean.split("").map((part) => `${part}${part}`).join("") : clean;
3250
2921
  const value = Number.parseInt(full, 16);
3251
2922
  if (!Number.isFinite(value))
3252
- return RGBA5.fromInts(14, 15, 17, alpha);
3253
- return RGBA5.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
2923
+ return RGBA4.fromInts(14, 15, 17, alpha);
2924
+ return RGBA4.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
3254
2925
  }
3255
2926
  function panelBackground(panel) {
3256
2927
  return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, PANEL_OPAQUE_ALPHA);
@@ -3365,9 +3036,9 @@ function applyScrollPanels(panels, layout, scenePanels) {
3365
3036
  }
3366
3037
 
3367
3038
  // packages/cli/src/app-opentui/render/type-bar.ts
3368
- import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA as RGBA6, StyledText as StyledText3, TextRenderable as TextRenderable2 } from "@opentui/core";
3369
- var TYPEBAR_BG = RGBA6.fromInts(20, 25, 14, 224);
3370
- var TYPEBAR_BORDER = RGBA6.fromInts(204, 255, 77, 92);
3039
+ import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA as RGBA5, StyledText as StyledText2, TextRenderable as TextRenderable2 } from "@opentui/core";
3040
+ var TYPEBAR_BG = RGBA5.fromInts(20, 25, 14, 224);
3041
+ var TYPEBAR_BORDER = RGBA5.fromInts(204, 255, 77, 92);
3371
3042
  function createTypeBar(renderer) {
3372
3043
  const background = new BoxRenderable(renderer, {
3373
3044
  id: "typebar-card",
@@ -3515,7 +3186,7 @@ function formatFooter(footer, width) {
3515
3186
  chunks.push(cell.style(text));
3516
3187
  used += visibleWidth(text);
3517
3188
  });
3518
- return new StyledText3(chunks);
3189
+ return new StyledText2(chunks);
3519
3190
  }
3520
3191
 
3521
3192
  // packages/cli/src/app-opentui/render/native-host.ts
@@ -3523,7 +3194,7 @@ import {
3523
3194
  BoxRenderable as BoxRenderable2,
3524
3195
  CodeRenderable,
3525
3196
  DiffRenderable,
3526
- RGBA as RGBA7,
3197
+ RGBA as RGBA6,
3527
3198
  ScrollBoxRenderable as ScrollBoxRenderable2,
3528
3199
  SyntaxStyle,
3529
3200
  TextRenderable as TextRenderable3,
@@ -3534,19 +3205,19 @@ function rigSyntaxStyle() {
3534
3205
  if (syntaxStyle)
3535
3206
  return syntaxStyle;
3536
3207
  syntaxStyle = SyntaxStyle.fromStyles({
3537
- keyword: { fg: RGBA7.fromHex(RIG_UI.magenta), bold: true },
3538
- string: { fg: RGBA7.fromHex(RIG_UI.lime) },
3539
- number: { fg: RGBA7.fromHex(RIG_UI.cyan) },
3540
- comment: { fg: RGBA7.fromHex(RIG_UI.ink4), italic: true },
3541
- function: { fg: RGBA7.fromHex(RIG_UI.cyan) },
3542
- type: { fg: RGBA7.fromHex(RIG_UI.limeDim) },
3543
- constant: { fg: RGBA7.fromHex(RIG_UI.yellow) },
3544
- default: { fg: RGBA7.fromHex(RIG_UI.ink2) }
3208
+ keyword: { fg: RGBA6.fromHex(RIG_UI.magenta), bold: true },
3209
+ string: { fg: RGBA6.fromHex(RIG_UI.lime) },
3210
+ number: { fg: RGBA6.fromHex(RIG_UI.cyan) },
3211
+ comment: { fg: RGBA6.fromHex(RIG_UI.ink4), italic: true },
3212
+ function: { fg: RGBA6.fromHex(RIG_UI.cyan) },
3213
+ type: { fg: RGBA6.fromHex(RIG_UI.limeDim) },
3214
+ constant: { fg: RGBA6.fromHex(RIG_UI.yellow) },
3215
+ default: { fg: RGBA6.fromHex(RIG_UI.ink2) }
3545
3216
  });
3546
3217
  return syntaxStyle;
3547
3218
  }
3548
3219
  function tableContent(rows) {
3549
- return rows.map((row, rowIndex) => row.map((cell) => [{ __isChunk: true, text: cell, fg: RGBA7.fromHex(rowIndex === 0 ? RIG_UI.ink3 : RIG_UI.ink2) }]));
3220
+ return rows.map((row, rowIndex) => row.map((cell) => [{ __isChunk: true, text: cell, fg: RGBA6.fromHex(rowIndex === 0 ? RIG_UI.ink3 : RIG_UI.ink2) }]));
3550
3221
  }
3551
3222
  function createNativeHost(renderer) {
3552
3223
  try {
@@ -3990,7 +3661,7 @@ function renderMainScene(state, layout) {
3990
3661
  }
3991
3662
 
3992
3663
  // packages/cli/src/app-opentui/runtime.ts
3993
- var PRELOADER_BACKDROP = RGBA8.fromHex(RIG_UI.bg);
3664
+ var PRELOADER_BACKDROP = RGBA7.fromHex(RIG_UI.bg);
3994
3665
  function inboxPendingCount(state) {
3995
3666
  const inbox = state.data.inbox;
3996
3667
  if (!inbox || typeof inbox !== "object" || Array.isArray(inbox))
@@ -4094,7 +3765,7 @@ function buildNavStrip(state) {
4094
3765
  chunks.push(otuiBold(styles.yellow(String(badgeCount))));
4095
3766
  }
4096
3767
  });
4097
- return new StyledText4(chunks);
3768
+ return new StyledText3(chunks);
4098
3769
  }
4099
3770
  function renderedItemsOrStateItems(_state, renderedItems) {
4100
3771
  return renderedItems ? [...renderedItems] : [];
@@ -4178,7 +3849,7 @@ async function activateSelection(runtime, renderedItems) {
4178
3849
  }
4179
3850
 
4180
3851
  // packages/cli/src/app-opentui/react/App.tsx
4181
- import { useMemo, useRef as useRef4 } from "react";
3852
+ import { useMemo, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
4182
3853
  import { useKeyboard, useRenderer as useRenderer4, useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
4183
3854
 
4184
3855
  // packages/cli/src/app-opentui/react/Backdrop.tsx
@@ -4234,7 +3905,7 @@ function Backdrop(props) {
4234
3905
  // packages/cli/src/app-opentui/react/SceneFrameView.tsx
4235
3906
  import { useEffect as useEffect2, useRef as useRef2 } from "react";
4236
3907
  import { useRenderer as useRenderer2 } from "@opentui/react";
4237
- import { TextAttributes as TextAttributes5 } from "@opentui/core";
3908
+ import { TextAttributes as TextAttributes4 } from "@opentui/core";
4238
3909
 
4239
3910
  // packages/cli/src/app-opentui/react/scroll.ts
4240
3911
  var registries = new Set;
@@ -4256,20 +3927,23 @@ function scrollActiveBody(delta) {
4256
3927
  // packages/cli/src/app-opentui/react/SceneFrameView.tsx
4257
3928
  import { jsxDEV, Fragment } from "@opentui/react/jsx-dev-runtime";
4258
3929
  function lineAttributes(line2) {
4259
- return line2?.bold ? TextAttributes5.BOLD : line2?.dim ? TextAttributes5.DIM : 0;
3930
+ return line2?.bold ? TextAttributes4.BOLD : line2?.dim ? TextAttributes4.DIM : 0;
4260
3931
  }
4261
3932
  function lineContent(line2) {
4262
3933
  return line2.styledText ?? line2.text ?? "";
4263
3934
  }
4264
3935
  function LineView(props) {
4265
3936
  const { line: line2, onLineClick } = props;
3937
+ const id = lineSelectableId(line2);
4266
3938
  return /* @__PURE__ */ jsxDEV("text", {
4267
3939
  style: { position: "absolute", left: props.left, top: props.top, width: props.width, zIndex: 5 },
4268
3940
  fg: line2.fg ?? RIG_UI.ink2,
4269
- bg: line2.bg ?? TRANSPARENT2,
3941
+ bg: lineBackground(line2),
4270
3942
  attributes: lineAttributes(line2),
4271
3943
  content: lineContent(line2),
4272
- onMouseDown: onLineClick ? () => onLineClick(line2) : undefined
3944
+ onMouseDown: onLineClick ? () => onLineClick(line2) : undefined,
3945
+ onMouseOver: id !== undefined ? () => setHoveredSelectableId(id) : undefined,
3946
+ onMouseOut: id !== undefined ? () => clearHoveredSelectableId(id) : undefined
4273
3947
  }, undefined, false, undefined, this);
4274
3948
  }
4275
3949
  function PanelHost(props) {
@@ -4511,6 +4185,7 @@ function App(props) {
4511
4185
  const runAppAction = useRunAppAction();
4512
4186
  const store = useStore();
4513
4187
  const renderer = useRenderer4();
4188
+ useSyncExternalStore2(subscribeHover, getHoveredSelectableId, getHoveredSelectableId);
4514
4189
  const dims = useTerminalDimensions2();
4515
4190
  const layout = computeStageLayout(dims.width, dims.height);
4516
4191
  const registry = useMemo(() => ({ ...BUILTIN, ...props.sceneRenderers ?? {} }), [props.sceneRenderers]);
@@ -4545,8 +4220,7 @@ function App(props) {
4545
4220
  } else {
4546
4221
  return;
4547
4222
  }
4548
- if (line2.activateOnClick)
4549
- runAppAction("Activate selection", () => activateSelection(runtime, items));
4223
+ runAppAction("Activate selection", () => activateSelection(runtime, items));
4550
4224
  };
4551
4225
  return /* @__PURE__ */ jsxDEV3("box", {
4552
4226
  style: { position: "absolute", left: 0, top: 0, width: "100%", height: "100%" },
@@ -4593,8 +4267,48 @@ async function launchRigReactApp(options) {
4593
4267
  const store = createAppStore(initialState);
4594
4268
  const events = createAppEventBus();
4595
4269
  let renderer = null;
4270
+ let root = null;
4596
4271
  let runnerPromise = null;
4597
4272
  let suppressHistoryPush = false;
4273
+ let resolveExit = () => {};
4274
+ const appExit = new Promise((resolve3) => {
4275
+ resolveExit = resolve3;
4276
+ });
4277
+ let relaunching = false;
4278
+ const mountRenderer = async () => {
4279
+ renderer = await createCliRenderer2({
4280
+ screenMode: "alternate-screen",
4281
+ exitOnCtrlC: false,
4282
+ targetFps: 30,
4283
+ maxFps: 30,
4284
+ useMouse: true,
4285
+ autoFocus: false,
4286
+ useKittyKeyboard: { disambiguate: true }
4287
+ });
4288
+ renderer.on("destroy", () => {
4289
+ if (!relaunching)
4290
+ resolveExit();
4291
+ });
4292
+ root = createRoot(renderer);
4293
+ root.render(/* @__PURE__ */ jsxDEV4(RigAppProvider, {
4294
+ value: { store, runtime, runAppAction },
4295
+ children: /* @__PURE__ */ jsxDEV4(App, {
4296
+ sceneRenderers: options.sceneRenderers
4297
+ }, undefined, false, undefined, this)
4298
+ }, undefined, false, undefined, this));
4299
+ relaunching = false;
4300
+ };
4301
+ const teardownRenderer = () => {
4302
+ relaunching = true;
4303
+ try {
4304
+ root?.unmount();
4305
+ } catch {}
4306
+ root = null;
4307
+ try {
4308
+ renderer?.destroy();
4309
+ } catch {}
4310
+ renderer = null;
4311
+ };
4598
4312
  const runAppAction = (label, action) => {
4599
4313
  action().catch((error) => {
4600
4314
  const n = normalizeError(error);
@@ -4636,8 +4350,10 @@ async function launchRigReactApp(options) {
4636
4350
  runnerPromise ??= options.initializeRuntime();
4637
4351
  return runnerPromise;
4638
4352
  },
4639
- suspend: () => renderer?.suspend(),
4640
- resume: () => renderer?.resume(),
4353
+ suspend: () => teardownRenderer(),
4354
+ resume: async () => {
4355
+ await mountRenderer();
4356
+ },
4641
4357
  destroy: () => renderer?.destroy()
4642
4358
  };
4643
4359
  events.subscribe((event) => store.patch(reduceAppEvent(store.getState(), event)));
@@ -4645,15 +4361,7 @@ async function launchRigReactApp(options) {
4645
4361
  if (typeof tick.unref === "function") {
4646
4362
  tick.unref();
4647
4363
  }
4648
- renderer = await createCliRenderer2({
4649
- screenMode: "alternate-screen",
4650
- exitOnCtrlC: false,
4651
- targetFps: 30,
4652
- maxFps: 30,
4653
- useMouse: true,
4654
- autoFocus: false,
4655
- useKittyKeyboard: { disambiguate: true }
4656
- });
4364
+ await mountRenderer();
4657
4365
  let liveEvents = null;
4658
4366
  const canAutoRefresh = (state) => {
4659
4367
  if (state.status === "action" || state.status === "loading")
@@ -4684,12 +4392,6 @@ async function launchRigReactApp(options) {
4684
4392
  }, FALLBACK_REFRESH_MS);
4685
4393
  if (typeof poll.unref === "function")
4686
4394
  poll.unref();
4687
- createRoot(renderer).render(/* @__PURE__ */ jsxDEV4(RigAppProvider, {
4688
- value: { store, runtime, runAppAction },
4689
- children: /* @__PURE__ */ jsxDEV4(App, {
4690
- sceneRenderers: options.sceneRenderers
4691
- }, undefined, false, undefined, this)
4692
- }, undefined, false, undefined, this));
4693
4395
  queueMicrotask(() => {
4694
4396
  (async () => {
4695
4397
  try {
@@ -4717,14 +4419,11 @@ async function launchRigReactApp(options) {
4717
4419
  }
4718
4420
  })();
4719
4421
  });
4720
- await new Promise((resolve3) => {
4721
- renderer?.on("destroy", () => {
4722
- clearInterval(tick);
4723
- clearInterval(poll);
4724
- liveEvents?.close();
4725
- resolve3();
4726
- });
4727
- });
4422
+ await appExit;
4423
+ clearInterval(tick);
4424
+ clearInterval(poll);
4425
+ liveEvents?.close();
4426
+ teardownRenderer();
4728
4427
  }
4729
4428
  export {
4730
4429
  launchRigReactApp