@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
@@ -91,6 +91,21 @@ async function captureConsole(fn) {
91
91
  console.error = original.error;
92
92
  }
93
93
  }
94
+ async function releaseRendererForExternalTui(ctx) {
95
+ const renderer = ctx.renderer;
96
+ if (!renderer)
97
+ return;
98
+ if (renderer.suspend) {
99
+ await renderer.suspend();
100
+ return;
101
+ }
102
+ if (renderer.destroy) {
103
+ await renderer.destroy();
104
+ }
105
+ }
106
+ async function resumeRendererAfterExternalTui(ctx) {
107
+ await ctx.renderer?.resume?.();
108
+ }
94
109
  function arrayFromPayload(value) {
95
110
  if (Array.isArray(value)) {
96
111
  return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
@@ -8882,6 +8897,14 @@ var init__operator_surface = __esm(() => {
8882
8897
  });
8883
8898
 
8884
8899
  // packages/cli/src/commands/_pi-frontend.ts
8900
+ var exports__pi_frontend = {};
8901
+ __export(exports__pi_frontend, {
8902
+ shouldRequireOperatorTranscript: () => shouldRequireOperatorTranscript,
8903
+ runWithProcessExitGuard: () => runWithProcessExitGuard,
8904
+ missingOperatorTranscriptMessage: () => missingOperatorTranscriptMessage,
8905
+ buildOperatorPiEnv: () => buildOperatorPiEnv,
8906
+ attachRunBundledPiFrontend: () => attachRunBundledPiFrontend
8907
+ });
8885
8908
  import { existsSync as existsSync14, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
8886
8909
  import { homedir as homedir6, tmpdir } from "os";
8887
8910
  import { join as join3 } from "path";
@@ -8994,6 +9017,29 @@ function installRigPiTheme() {
8994
9017
  }
8995
9018
  } catch {}
8996
9019
  }
9020
+ async function runWithProcessExitGuard(body) {
9021
+ const realExit = process.exit;
9022
+ let exitCode = 0;
9023
+ let signalQuit = () => {};
9024
+ const quit = new Promise((resolve22) => {
9025
+ signalQuit = resolve22;
9026
+ });
9027
+ const guardedExit = (code) => {
9028
+ exitCode = typeof code === "number" ? code : 0;
9029
+ signalQuit();
9030
+ return;
9031
+ };
9032
+ process.exit = guardedExit;
9033
+ try {
9034
+ await Promise.race([Promise.resolve().then(body), quit]);
9035
+ } finally {
9036
+ process.exit = realExit;
9037
+ }
9038
+ return exitCode;
9039
+ }
9040
+ function runPiMainReturningOnQuit(args, options) {
9041
+ return runWithProcessExitGuard(() => runPiMain(args, options));
9042
+ }
8997
9043
  async function attachRunBundledPiFrontend(context, input) {
8998
9044
  const tempSessionDir = mkdtempSync(join3(tmpdir(), "rig-pi-frontend-sessions-"));
8999
9045
  const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
@@ -9009,16 +9055,20 @@ async function attachRunBundledPiFrontend(context, input) {
9009
9055
  };
9010
9056
  let detached = false;
9011
9057
  try {
9012
- await runPiMain([
9058
+ const piArgs = [
9013
9059
  "--offline",
9014
9060
  "--no-extensions",
9015
9061
  "--no-skills",
9016
9062
  "--no-prompt-templates",
9017
9063
  "--no-context-files",
9018
9064
  ...sessionFileArg
9019
- ], {
9020
- extensionFactories: [piRigExtensionFactory]
9021
- });
9065
+ ];
9066
+ const piOptions = { extensionFactories: [piRigExtensionFactory] };
9067
+ if (input.returnOnQuit) {
9068
+ await runPiMainReturningOnQuit(piArgs, piOptions);
9069
+ } else {
9070
+ await runPiMain(piArgs, piOptions);
9071
+ }
9022
9072
  detached = true;
9023
9073
  } finally {
9024
9074
  restoreEnv();
@@ -14284,390 +14334,6 @@ async function stopFleetRun(ctx, runId) {
14284
14334
  }
14285
14335
  var init_fleet = () => {};
14286
14336
 
14287
- // packages/cli/src/app-opentui/pi-pty-host.ts
14288
- import { fileURLToPath as fileURLToPath2 } from "url";
14289
- import { basename as basename4 } from "path";
14290
- import { RGBA, StyledText, TextAttributes } from "@opentui/core";
14291
- import { Terminal as XtermTerminal2 } from "@xterm/headless";
14292
- function clampCols2(cols) {
14293
- return Math.max(MIN_COLS2, Math.trunc(cols || 100));
14294
- }
14295
- function clampRows2(rows) {
14296
- return Math.max(MIN_ROWS2, Math.min(MAX_ROWS2, Math.trunc(rows || 35)));
14297
- }
14298
- function rgbaFromXtermColor(mode, value) {
14299
- if (mode === 1 || mode === 2 || mode === XTERM_COLOR_MODE_INDEXED_16 || mode === XTERM_COLOR_MODE_INDEXED_256) {
14300
- return RGBA.fromIndex(value);
14301
- }
14302
- if (mode === 3 || mode === XTERM_COLOR_MODE_RGB) {
14303
- return RGBA.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255);
14304
- }
14305
- return;
14306
- }
14307
- function textAttributesFromCell(cell) {
14308
- let attributes = TextAttributes.NONE;
14309
- if (cell.isBold())
14310
- attributes |= TextAttributes.BOLD;
14311
- if (cell.isDim())
14312
- attributes |= TextAttributes.DIM;
14313
- if (cell.isItalic())
14314
- attributes |= TextAttributes.ITALIC;
14315
- if (cell.isUnderline())
14316
- attributes |= TextAttributes.UNDERLINE;
14317
- if (cell.isBlink())
14318
- attributes |= TextAttributes.BLINK;
14319
- if (cell.isInverse())
14320
- attributes |= TextAttributes.INVERSE;
14321
- if (cell.isInvisible())
14322
- attributes |= TextAttributes.HIDDEN;
14323
- if (cell.isStrikethrough())
14324
- attributes |= TextAttributes.STRIKETHROUGH;
14325
- return attributes;
14326
- }
14327
- function sameRgba(a, b) {
14328
- if (!a && !b)
14329
- return true;
14330
- return Boolean(a && b && a.equals(b));
14331
- }
14332
- function sameStyle(a, b) {
14333
- return sameRgba(a.fg, b.fg) && sameRgba(a.bg, b.bg) && (a.attributes ?? 0) === (b.attributes ?? 0);
14334
- }
14335
- function styleFromCell(cell) {
14336
- return {
14337
- fg: rgbaFromXtermColor(cell.getFgColorMode(), cell.getFgColor()),
14338
- bg: rgbaFromXtermColor(cell.getBgColorMode(), cell.getBgColor()),
14339
- attributes: textAttributesFromCell(cell)
14340
- };
14341
- }
14342
- function lineToStyledText(line, cols) {
14343
- if (!line)
14344
- return new StyledText([{ __isChunk: true, text: "" }]);
14345
- const chunks = [];
14346
- let run = "";
14347
- let runStyle = null;
14348
- const flush = () => {
14349
- if (!run)
14350
- return;
14351
- chunks.push({
14352
- __isChunk: true,
14353
- text: run,
14354
- ...runStyle?.fg ? { fg: runStyle.fg } : {},
14355
- ...runStyle?.bg ? { bg: runStyle.bg } : {},
14356
- ...(runStyle?.attributes ?? 0) !== 0 ? { attributes: runStyle.attributes } : {}
14357
- });
14358
- run = "";
14359
- };
14360
- for (let index = 0;index < cols; index += 1) {
14361
- const cell = line.getCell(index);
14362
- if (!cell) {
14363
- if (runStyle !== null)
14364
- flush();
14365
- runStyle = null;
14366
- run += " ";
14367
- continue;
14368
- }
14369
- if (cell.getWidth() === 0)
14370
- continue;
14371
- const style = styleFromCell(cell);
14372
- if (!runStyle || !sameStyle(runStyle, style)) {
14373
- flush();
14374
- runStyle = style;
14375
- }
14376
- run += cell.getChars() || " ";
14377
- }
14378
- flush();
14379
- return new StyledText(chunks.length > 0 ? chunks : [{ __isChunk: true, text: "" }]);
14380
- }
14381
- function childCommandPrefix2() {
14382
- const execName = basename4(process.execPath).toLowerCase();
14383
- const currentEntry = process.argv[1];
14384
- if (execName === "bun" || execName === "bun.exe") {
14385
- return currentEntry ? [process.execPath, currentEntry, "__opentui-pi-host"] : [process.execPath, fallbackChildScriptPath];
14386
- }
14387
- return [process.execPath, "__opentui-pi-host"];
14388
- }
14389
- function withEnv2(base) {
14390
- const env = {};
14391
- for (const [key, value] of Object.entries(base ?? process.env)) {
14392
- if (key === "RIG_PLAIN" || key === "RIG_CLI_PLAIN_HELP" || key === "NO_COLOR")
14393
- continue;
14394
- if (typeof value === "string")
14395
- env[key] = value;
14396
- }
14397
- return {
14398
- ...env,
14399
- TERM: "xterm-256color",
14400
- COLORTERM: "truecolor",
14401
- FORCE_COLOR: env.FORCE_COLOR ?? "1",
14402
- RIG_OPENTUI_PI_HOST: "1"
14403
- };
14404
- }
14405
- async function startPiPtyHost(options) {
14406
- activeHost2?.dispose("replace");
14407
- const host = new PiPtyHost(options);
14408
- activeHost2 = host;
14409
- await host.start();
14410
- return host;
14411
- }
14412
-
14413
- class PiPtyHost {
14414
- runId;
14415
- projectRoot;
14416
- onSnapshot;
14417
- onExit;
14418
- onError;
14419
- terminal;
14420
- disposables = [];
14421
- decoder = new TextDecoder("utf-8");
14422
- proc = null;
14423
- pty = null;
14424
- status = "starting";
14425
- cols;
14426
- rows;
14427
- message = "starting bundled Pi";
14428
- lastResizeError = null;
14429
- exitCode;
14430
- signal;
14431
- notifyTimer = null;
14432
- lastStreamKey = "";
14433
- _disposed = false;
14434
- constructor(options) {
14435
- this.runId = options.runId;
14436
- this.projectRoot = options.projectRoot;
14437
- this.cols = clampCols2(options.cols);
14438
- this.rows = clampRows2(options.rows);
14439
- this.onSnapshot = options.onSnapshot;
14440
- this.onExit = options.onExit;
14441
- this.onError = options.onError;
14442
- this.terminal = new XtermTerminal2({
14443
- allowProposedApi: true,
14444
- cols: this.cols,
14445
- rows: this.rows,
14446
- scrollback: 1000
14447
- });
14448
- this.registerTerminalResponders();
14449
- this.disposables.push(this.terminal.onWriteParsed(() => {
14450
- if (this._disposed)
14451
- return;
14452
- const snapshot = this.createSnapshot();
14453
- const key = snapshot.lines.join(`
14454
- `);
14455
- if (key === this.lastStreamKey)
14456
- return;
14457
- this.lastStreamKey = key;
14458
- this.onSnapshot?.(snapshot);
14459
- }));
14460
- }
14461
- get disposed() {
14462
- return this._disposed;
14463
- }
14464
- get snapshot() {
14465
- return this.createSnapshot();
14466
- }
14467
- async start() {
14468
- if (this._disposed)
14469
- throw new Error("Pi PTY host is disposed.");
14470
- if (typeof Bun.Terminal !== "function") {
14471
- throw new Error("Bun native PTY is unavailable in this runtime. Pi host requires Bun.Terminal.");
14472
- }
14473
- const spawnOptions = {
14474
- cwd: this.projectRoot,
14475
- env: withEnv2(process.env),
14476
- terminal: {
14477
- cols: this.cols,
14478
- rows: this.rows,
14479
- name: "xterm-256color",
14480
- data: (_terminal, data) => this.handlePtyData(data)
14481
- }
14482
- };
14483
- const proc = Bun.spawn([
14484
- ...childCommandPrefix2(),
14485
- "--run-id",
14486
- this.runId,
14487
- "--project-root",
14488
- this.projectRoot
14489
- ], spawnOptions);
14490
- if (!proc.terminal)
14491
- throw new Error("Bun did not attach a terminal to the bundled Pi child process.");
14492
- this.proc = proc;
14493
- this.pty = proc.terminal;
14494
- this.status = "running";
14495
- this.message = "bundled Pi running inside this app";
14496
- this.emitSnapshotSoon(0);
14497
- proc.exited.then((exitCode) => {
14498
- if (this._disposed)
14499
- return;
14500
- this.status = exitCode === 0 ? "exited" : "failed";
14501
- this.exitCode = exitCode;
14502
- this.signal = null;
14503
- this.message = exitCode === 0 ? "bundled Pi exited" : `bundled Pi exited with code ${exitCode}`;
14504
- const snapshot = this.createSnapshot();
14505
- this.onSnapshot?.(snapshot);
14506
- this.onExit?.(snapshot);
14507
- if (activeHost2 === this)
14508
- activeHost2 = null;
14509
- this.dispose("exit", { kill: false, notify: false });
14510
- }).catch((error) => {
14511
- if (this._disposed)
14512
- return;
14513
- this.status = "failed";
14514
- this.message = error instanceof Error ? error.message : String(error);
14515
- const snapshot = this.createSnapshot();
14516
- this.onSnapshot?.(snapshot);
14517
- this.onError?.(error, snapshot);
14518
- if (activeHost2 === this)
14519
- activeHost2 = null;
14520
- this.dispose("error", { kill: false, notify: false });
14521
- });
14522
- }
14523
- write(data) {
14524
- if (this._disposed || !this.pty)
14525
- return;
14526
- try {
14527
- this.pty.write(data);
14528
- } catch (error) {
14529
- this.status = "failed";
14530
- this.message = error instanceof Error ? error.message : String(error);
14531
- const snapshot = this.createSnapshot();
14532
- this.onSnapshot?.(snapshot);
14533
- this.onError?.(error, snapshot);
14534
- }
14535
- }
14536
- resize(cols, rows) {
14537
- const nextCols = clampCols2(cols);
14538
- const nextRows = clampRows2(rows);
14539
- if (nextCols === this.cols && nextRows === this.rows)
14540
- return;
14541
- this.cols = nextCols;
14542
- this.rows = nextRows;
14543
- this.terminal.resize(nextCols, nextRows);
14544
- try {
14545
- this.pty?.resize(nextCols, nextRows);
14546
- this.lastResizeError = null;
14547
- } catch (error) {
14548
- this.lastResizeError = error instanceof Error ? error.message : String(error);
14549
- }
14550
- this.emitSnapshotSoon(0);
14551
- }
14552
- detach() {
14553
- this.dispose("detach");
14554
- return this.createSnapshot("detached from bundled Pi");
14555
- }
14556
- dispose(reason = "dispose", options = {}) {
14557
- if (this._disposed)
14558
- return;
14559
- this._disposed = true;
14560
- if (this.notifyTimer)
14561
- clearTimeout(this.notifyTimer);
14562
- this.notifyTimer = null;
14563
- for (const disposable of this.disposables.splice(0)) {
14564
- try {
14565
- disposable.dispose();
14566
- } catch {}
14567
- }
14568
- if (options.kill !== false) {
14569
- try {
14570
- this.proc?.kill("SIGTERM");
14571
- } catch {}
14572
- }
14573
- try {
14574
- this.pty?.close();
14575
- } catch {}
14576
- try {
14577
- this.terminal.dispose();
14578
- } catch {}
14579
- if (activeHost2 === this)
14580
- activeHost2 = null;
14581
- if (options.notify) {
14582
- this.message = reason;
14583
- this.onSnapshot?.(this.createSnapshot(reason));
14584
- }
14585
- }
14586
- handlePtyData(data) {
14587
- if (this._disposed)
14588
- return;
14589
- const text2 = this.decoder.decode(data, { stream: true });
14590
- this.respondToRawTerminalQueries(text2);
14591
- this.terminal.write(data);
14592
- }
14593
- emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS2) {
14594
- if (this._disposed || this.notifyTimer)
14595
- return;
14596
- this.notifyTimer = setTimeout(() => {
14597
- this.notifyTimer = null;
14598
- if (this._disposed)
14599
- return;
14600
- this.onSnapshot?.(this.createSnapshot());
14601
- }, delayMs);
14602
- }
14603
- createSnapshot(message2 = this.message) {
14604
- const buffer = this.terminal.buffer.active;
14605
- const end = buffer.length;
14606
- const start = Math.max(0, end - MAX_SNAPSHOT_LINES2);
14607
- const styledStart = Math.max(start, end - this.rows - STYLED_SNAPSHOT_MARGIN);
14608
- const lines = [];
14609
- const styledLines = [];
14610
- for (let row = start;row < end; row += 1) {
14611
- const line = buffer.getLine(row);
14612
- lines.push((line?.translateToString(false) ?? "").slice(0, this.cols));
14613
- if (row >= styledStart)
14614
- styledLines[lines.length - 1] = lineToStyledText(line, this.cols);
14615
- }
14616
- while (lines.length < this.rows) {
14617
- lines.push("");
14618
- styledLines[lines.length - 1] = new StyledText([{ __isChunk: true, text: "" }]);
14619
- }
14620
- const resolvedMessage = this.lastResizeError ? `resize degraded: ${this.lastResizeError}` : message2;
14621
- return {
14622
- runId: this.runId,
14623
- status: this.status,
14624
- cols: this.cols,
14625
- rows: this.rows,
14626
- lines,
14627
- styledLines,
14628
- message: resolvedMessage,
14629
- ...this.lastResizeError ? { resizeError: this.lastResizeError } : {},
14630
- ...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
14631
- ...this.signal !== undefined ? { signal: this.signal } : {}
14632
- };
14633
- }
14634
- registerTerminalResponders() {
14635
- this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "c" }, (params) => {
14636
- if (params.length === 0 || params[0] === 0)
14637
- this.write("\x1B[?62;22c");
14638
- return false;
14639
- }));
14640
- this.disposables.push(this.terminal.parser.registerCsiHandler({ prefix: ">", final: "c" }, (params) => {
14641
- if (params.length === 0 || params[0] === 0)
14642
- this.write("\x1B[>0;0;0c");
14643
- return false;
14644
- }));
14645
- this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "n" }, (params) => {
14646
- if (params[0] === 5) {
14647
- this.write("\x1B[0n");
14648
- } else if (params[0] === 6) {
14649
- const row = this.terminal.buffer.active.cursorY + 1;
14650
- const col = this.terminal.buffer.active.cursorX + 1;
14651
- this.write(`\x1B[${row};${col}R`);
14652
- }
14653
- return false;
14654
- }));
14655
- }
14656
- respondToRawTerminalQueries(text2) {
14657
- if (!text2)
14658
- return;
14659
- const decrqm = /\x1b\[\?(\d+)\$p/g;
14660
- let match;
14661
- while ((match = decrqm.exec(text2)) !== null) {
14662
- this.write(`\x1B[?${match[1]};2$y`);
14663
- }
14664
- }
14665
- }
14666
- var MIN_COLS2 = 40, MIN_ROWS2 = 12, MAX_ROWS2 = 300, MAX_SNAPSHOT_LINES2 = 360, STYLED_SNAPSHOT_MARGIN = 6, SNAPSHOT_DELAY_MS2 = 120, fallbackChildScriptPath, activeHost2 = null, XTERM_COLOR_MODE_INDEXED_16 = 16777216, XTERM_COLOR_MODE_INDEXED_256 = 33554432, XTERM_COLOR_MODE_RGB = 50331648;
14667
- var init_pi_pty_host = __esm(() => {
14668
- fallbackChildScriptPath = fileURLToPath2(new URL("./pi-host-child.ts", import.meta.url));
14669
- });
14670
-
14671
14337
  // packages/cli/src/app-opentui/adapters/inspect.ts
14672
14338
  var exports_inspect = {};
14673
14339
  __export(exports_inspect, {
@@ -14890,14 +14556,6 @@ function recordStep(ctx, runId, label, emitLabel) {
14890
14556
  });
14891
14557
  emitProgress(ctx, emitLabel, label);
14892
14558
  }
14893
- function settleSteps(ctx, runId) {
14894
- const now = Date.now();
14895
- const previous = currentAttachState(ctx, runId);
14896
- if (!previous?.steps)
14897
- return;
14898
- const steps = previous.steps.map((step) => step.status === "running" ? { ...step, status: "done", endedAtMs: step.endedAtMs ?? now } : step);
14899
- patchData(ctx, { piAttach: { ...previous, steps } });
14900
- }
14901
14559
  async function preparePiAttachHandoff(ctx, runId) {
14902
14560
  const cleanRunId = runId.trim();
14903
14561
  const label = `Preparing Pi ${cleanRunId.slice(0, 8)}`;
@@ -14945,85 +14603,41 @@ async function attachRunWithBundledPi(ctx, runId) {
14945
14603
  throw error;
14946
14604
  }
14947
14605
  emitStarted(ctx, label, { piAttach: { runId: cleanRunId, status: "entering-pi" } });
14948
- patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "starting bundled Pi", steps: [] } });
14606
+ patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "handing the terminal to worker Pi\u2026" } });
14607
+ const projectRoot = projectRootOf(ctx);
14608
+ const outputMode = ctx.rig?.outputMode ?? "text";
14609
+ await releaseRendererForExternalTui(ctx);
14610
+ let outcome = null;
14611
+ let attachError = null;
14949
14612
  try {
14950
- recordStep(ctx, cleanRunId, "connecting to server and fetching run transcript", label);
14951
- await preparePiAttachHandoff(ctx, cleanRunId).catch((error) => {
14952
- patchData(ctx, { lastRefreshError: normalizeAppError(error).message });
14953
- return null;
14954
- });
14955
- recordStep(ctx, cleanRunId, "spawning Bun PTY host for bundled Pi", label);
14956
- const projectRoot = projectRootOf(ctx);
14957
- const cols = typeof process.stdout.columns === "number" ? process.stdout.columns : 100;
14958
- const rows = Math.max(1, (typeof process.stdout.rows === "number" ? process.stdout.rows : 35) - 1);
14959
- const patchTerminal = (snapshot) => {
14960
- const previousSteps = currentAttachState(ctx, cleanRunId)?.steps;
14961
- const failed = snapshot.status === "failed";
14962
- const reason = failed ? snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}` : undefined;
14963
- patchData(ctx, {
14964
- piTerminal: snapshot,
14965
- piAttach: {
14966
- runId: cleanRunId,
14967
- status: failed ? "failed" : snapshot.status === "exited" ? "returned" : "entering-pi",
14968
- message: snapshot.message ?? "bundled Pi running",
14969
- result: { runId: cleanRunId, status: snapshot.status, exitCode: snapshot.exitCode },
14970
- ...previousSteps ? { steps: previousSteps } : {},
14971
- ...reason ? { failureReason: reason } : {}
14972
- }
14973
- });
14974
- };
14975
- recordStep(ctx, cleanRunId, "starting bundled Pi", label);
14976
- await startPiPtyHost({
14977
- runId: cleanRunId,
14978
- projectRoot,
14979
- cols,
14980
- rows,
14981
- onSnapshot: (snapshot) => {
14982
- if (snapshot.status === "running" && snapshot.lines.some((entry) => entry.trim().length > 0)) {
14983
- settleSteps(ctx, cleanRunId);
14984
- }
14985
- patchTerminal(snapshot);
14986
- },
14987
- onExit: (snapshot) => {
14988
- patchTerminal(snapshot);
14989
- if (snapshot.status === "failed") {
14990
- Promise.resolve().then(() => (init_inspect2(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
14991
- emitFailed(ctx, label, new Error(snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}`), { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
14992
- return;
14993
- }
14994
- emitCompleted(ctx, label, { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
14995
- ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
14996
- refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
14997
- },
14998
- onError: (error, snapshot) => {
14999
- patchTerminal(snapshot);
15000
- emitFailed(ctx, label, error, { runId: cleanRunId });
15001
- }
15002
- });
15003
- const record = {
15004
- runId: cleanRunId,
15005
- status: "running",
15006
- rendered: "bundled Pi embedded via Bun.Terminal + @xterm/headless"
15007
- };
15008
- emitProgress(ctx, label, "bundled Pi is running", { piAttach: { runId: cleanRunId, status: "entering-pi", message: "bundled Pi running", result: record } });
15009
- return record;
14613
+ const { attachRunBundledPiFrontend: attachRunBundledPiFrontend2 } = await Promise.resolve().then(() => (init__pi_frontend(), exports__pi_frontend));
14614
+ outcome = await attachRunBundledPiFrontend2({ projectRoot, outputMode }, { runId: cleanRunId, returnOnQuit: true });
15010
14615
  } catch (error) {
15011
- const reason = error instanceof Error ? error.message : String(error);
14616
+ attachError = error;
14617
+ } finally {
14618
+ await resumeRendererAfterExternalTui(ctx);
14619
+ }
14620
+ if (attachError) {
14621
+ const reason = normalizeAppError(attachError).message;
15012
14622
  patchData(ctx, {
15013
- piAttach: {
15014
- runId: cleanRunId,
15015
- status: "failed",
15016
- message: reason,
15017
- failureReason: reason,
15018
- ...currentAttachState(ctx, cleanRunId)?.steps ? { steps: currentAttachState(ctx, cleanRunId).steps } : {}
15019
- }
14623
+ piTerminal: undefined,
14624
+ piAttach: { runId: cleanRunId, status: "failed", message: reason, failureReason: reason }
15020
14625
  });
15021
- emitFailed(ctx, label, error, { runId: cleanRunId });
15022
- throw error;
14626
+ Promise.resolve().then(() => (init_inspect2(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
14627
+ emitFailed(ctx, label, attachError, { runId: cleanRunId });
14628
+ throw attachError;
15023
14629
  }
14630
+ const detached = outcome?.detached === true;
14631
+ patchData(ctx, {
14632
+ piTerminal: undefined,
14633
+ piAttach: { runId: cleanRunId, status: "returned", message: detached ? "detached from worker Pi" : "returned from worker Pi" }
14634
+ });
14635
+ emitCompleted(ctx, label, { runId: cleanRunId, result: { runId: cleanRunId, detached } });
14636
+ ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
14637
+ refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
14638
+ return { runId: cleanRunId, status: "returned", detached };
15024
14639
  }
15025
14640
  var init_pi_attach = __esm(() => {
15026
- init_pi_pty_host();
15027
14641
  init_fleet();
15028
14642
  });
15029
14643
  // packages/cli/src/app-opentui/command-pty-host.ts
@@ -17038,13 +16652,14 @@ import {
17038
16652
  dim as otuiDim,
17039
16653
  fg as otuiFg,
17040
16654
  t,
17041
- TextAttributes as TextAttributes2
16655
+ TextAttributes
17042
16656
  } from "@opentui/core";
17043
16657
  var RIG_UI = {
17044
16658
  bg: "#070809",
17045
16659
  bg2: "#0b0c0e",
17046
16660
  panel: "#101115",
17047
16661
  panel2: "#14161b",
16662
+ hover: "#181b24",
17048
16663
  glass: "#1e2230",
17049
16664
  border: "#2a2e3a",
17050
16665
  ink: "#f4f5f8",
@@ -17139,7 +16754,7 @@ function statusLabel(status) {
17139
16754
  }
17140
16755
 
17141
16756
  // packages/cli/src/app-opentui/drone.ts
17142
- import { RGBA as RGBA2, StyledText as StyledText2, TextAttributes as TextAttributes3 } from "@opentui/core";
16757
+ import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
17143
16758
  var MINI_DRONE = [
17144
16759
  "(!!!) (!!!)",
17145
16760
  " \\%==%/ ",
@@ -17155,13 +16770,13 @@ var LEAD_MARK = [
17155
16770
  var BLADE_FRAMES2 = ["---", "\\\\\\", "|||", "///"];
17156
16771
  var EYE_FRAMES2 = ["o", "@", "\u2022", "."];
17157
16772
  var COLOR = {
17158
- body: RGBA2.fromHex(RIG_UI.lime),
17159
- mini: RGBA2.fromHex(RIG_UI.limeDim),
17160
- rotor: RGBA2.fromHex(RIG_UI.cyan),
17161
- path: RGBA2.fromHex(RIG_UI.cyan),
17162
- eye: RGBA2.fromHex(RIG_UI.ink),
17163
- dim: RGBA2.fromHex(RIG_UI.ink4),
17164
- ink: RGBA2.fromHex(RIG_UI.ink2)
16773
+ body: RGBA.fromHex(RIG_UI.lime),
16774
+ mini: RGBA.fromHex(RIG_UI.limeDim),
16775
+ rotor: RGBA.fromHex(RIG_UI.cyan),
16776
+ path: RGBA.fromHex(RIG_UI.cyan),
16777
+ eye: RGBA.fromHex(RIG_UI.ink),
16778
+ dim: RGBA.fromHex(RIG_UI.ink4),
16779
+ ink: RGBA.fromHex(RIG_UI.ink2)
17165
16780
  };
17166
16781
  function bladeForTick(tick, phase = 0) {
17167
16782
  return BLADE_FRAMES2[(Math.floor(tick / 3) + phase) % BLADE_FRAMES2.length];
@@ -17171,12 +16786,12 @@ function eyeForTick(tick, phase = 0) {
17171
16786
  return pulse > 0.55 ? EYE_FRAMES2[1] : pulse > 0.1 ? EYE_FRAMES2[0] : pulse > -0.45 ? EYE_FRAMES2[2] : EYE_FRAMES2[3];
17172
16787
  }
17173
16788
  function chunk(text2, fg2, bold2 = false, dim = false) {
17174
- let attributes = TextAttributes3.NONE;
16789
+ let attributes = TextAttributes2.NONE;
17175
16790
  if (bold2)
17176
- attributes |= TextAttributes3.BOLD;
16791
+ attributes |= TextAttributes2.BOLD;
17177
16792
  if (dim)
17178
- attributes |= TextAttributes3.DIM;
17179
- return { __isChunk: true, text: text2, fg: fg2, ...attributes !== TextAttributes3.NONE ? { attributes } : {} };
16793
+ attributes |= TextAttributes2.DIM;
16794
+ return { __isChunk: true, text: text2, fg: fg2, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
17180
16795
  }
17181
16796
  function styledLine(text2, colorFor) {
17182
16797
  const chunks = [];
@@ -17197,7 +16812,7 @@ function styledLine(text2, colorFor) {
17197
16812
  run += char;
17198
16813
  }
17199
16814
  flush();
17200
- return new StyledText2(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
16815
+ return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
17201
16816
  }
17202
16817
  function droneColor(char) {
17203
16818
  if (char === "?" || char === "o" || char === "@" || char === "\u2022")
@@ -19347,11 +18962,8 @@ function renderFamilyScene(state, layout) {
19347
18962
  }
19348
18963
 
19349
18964
  // packages/cli/src/app-opentui/list-search.ts
19350
- function isListSearchScene(scene) {
19351
- return scene === "fleet" || scene === "tasks";
19352
- }
19353
- function listSearchQuery(state) {
19354
- return isListSearchScene(state.scene) ? state.typeBar.value.trim() : "";
18965
+ function listSearchQuery(_state) {
18966
+ return "";
19355
18967
  }
19356
18968
  function valueText(value) {
19357
18969
  if (value === undefined || value === null)