@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.
- package/dist/bin/rig.js +287 -578
- package/dist/src/app-opentui/adapters/common.d.ts +3 -0
- package/dist/src/app-opentui/adapters/common.js +4 -0
- package/dist/src/app-opentui/adapters/family.js +31 -4
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +7 -0
- package/dist/src/app-opentui/adapters/pi-attach.js +527 -473
- package/dist/src/app-opentui/adapters/tasks.js +82 -468
- package/dist/src/app-opentui/bootstrap.js +287 -578
- package/dist/src/app-opentui/command-palette.js +1 -0
- package/dist/src/app-opentui/drone.js +1 -0
- package/dist/src/app-opentui/index.js +127 -446
- package/dist/src/app-opentui/keymap.js +2 -387
- package/dist/src/app-opentui/list-search.d.ts +5 -1
- package/dist/src/app-opentui/list-search.js +2 -2
- package/dist/src/app-opentui/pi-host-child.js +31 -4
- package/dist/src/app-opentui/pi-pty-host.d.ts +14 -64
- package/dist/src/app-opentui/pi-pty-host.js +3 -397
- package/dist/src/app-opentui/react/App.js +107 -433
- package/dist/src/app-opentui/react/Backdrop.js +1 -0
- package/dist/src/app-opentui/react/ChromeHost.js +34 -410
- package/dist/src/app-opentui/react/SceneFrameView.js +55 -5
- package/dist/src/app-opentui/react/launch.js +171 -472
- package/dist/src/app-opentui/react/syntax.js +1 -0
- package/dist/src/app-opentui/registry.js +99 -487
- package/dist/src/app-opentui/render/graphics.js +1 -0
- package/dist/src/app-opentui/render/hover.d.ts +11 -0
- package/dist/src/app-opentui/render/hover.js +34 -0
- package/dist/src/app-opentui/render/native-host.js +1 -0
- package/dist/src/app-opentui/render/panels.js +50 -3
- package/dist/src/app-opentui/render/preloader.js +1 -0
- package/dist/src/app-opentui/render/scene.js +1 -0
- package/dist/src/app-opentui/render/terminal-handoff.d.ts +16 -0
- package/dist/src/app-opentui/render/terminal-handoff.js +14 -0
- package/dist/src/app-opentui/render/text.d.ts +13 -0
- package/dist/src/app-opentui/render/text.js +54 -5
- package/dist/src/app-opentui/render/type-bar.js +1 -0
- package/dist/src/app-opentui/runtime.js +127 -446
- package/dist/src/app-opentui/scenes/command.js +1 -0
- package/dist/src/app-opentui/scenes/doctor.js +1 -0
- package/dist/src/app-opentui/scenes/error.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/agent.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/git.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/github.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/index.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/review.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.js +1 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.js +1 -0
- package/dist/src/app-opentui/scenes/family.js +1 -0
- package/dist/src/app-opentui/scenes/fleet.js +3 -5
- package/dist/src/app-opentui/scenes/handoff.js +1 -0
- package/dist/src/app-opentui/scenes/help.js +1 -0
- package/dist/src/app-opentui/scenes/inbox.js +1 -0
- package/dist/src/app-opentui/scenes/init.js +1 -0
- package/dist/src/app-opentui/scenes/inspect.js +1 -0
- package/dist/src/app-opentui/scenes/main.js +1 -0
- package/dist/src/app-opentui/scenes/pi.js +1 -0
- package/dist/src/app-opentui/scenes/plugin.js +1 -0
- package/dist/src/app-opentui/scenes/repo.js +1 -0
- package/dist/src/app-opentui/scenes/run-detail.js +1 -0
- package/dist/src/app-opentui/scenes/server.js +1 -0
- package/dist/src/app-opentui/scenes/tasks.js +3 -5
- package/dist/src/app-opentui/scenes/workspace.js +1 -0
- package/dist/src/app-opentui/selectable.js +1 -0
- package/dist/src/app-opentui/theme.d.ts +1 -0
- package/dist/src/app-opentui/theme.js +1 -0
- package/dist/src/commands/_operator-view.js +31 -4
- package/dist/src/commands/_pi-frontend.d.ts +25 -0
- package/dist/src/commands/_pi-frontend.js +32 -4
- package/dist/src/commands/run.js +31 -4
- package/dist/src/commands/task.js +31 -4
- package/dist/src/commands.js +31 -4
- package/dist/src/index.js +31 -4
- package/package.json +8 -8
|
@@ -65,6 +65,21 @@ function patchData(ctx, data) {
|
|
|
65
65
|
function patchFooter(ctx, footer) {
|
|
66
66
|
ctx.emit({ type: "footer.patch", footer });
|
|
67
67
|
}
|
|
68
|
+
async function releaseRendererForExternalTui(ctx) {
|
|
69
|
+
const renderer = ctx.renderer;
|
|
70
|
+
if (!renderer)
|
|
71
|
+
return;
|
|
72
|
+
if (renderer.suspend) {
|
|
73
|
+
await renderer.suspend();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (renderer.destroy) {
|
|
77
|
+
await renderer.destroy();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function resumeRendererAfterExternalTui(ctx) {
|
|
81
|
+
await ctx.renderer?.resume?.();
|
|
82
|
+
}
|
|
68
83
|
function arrayFromPayload(value) {
|
|
69
84
|
if (Array.isArray(value)) {
|
|
70
85
|
return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
@@ -1714,6 +1729,14 @@ var init__async_ui = __esm(() => {
|
|
|
1714
1729
|
});
|
|
1715
1730
|
|
|
1716
1731
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
1732
|
+
var exports__pi_frontend = {};
|
|
1733
|
+
__export(exports__pi_frontend, {
|
|
1734
|
+
shouldRequireOperatorTranscript: () => shouldRequireOperatorTranscript,
|
|
1735
|
+
runWithProcessExitGuard: () => runWithProcessExitGuard,
|
|
1736
|
+
missingOperatorTranscriptMessage: () => missingOperatorTranscriptMessage,
|
|
1737
|
+
buildOperatorPiEnv: () => buildOperatorPiEnv,
|
|
1738
|
+
attachRunBundledPiFrontend: () => attachRunBundledPiFrontend
|
|
1739
|
+
});
|
|
1717
1740
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1718
1741
|
import { homedir as homedir2, tmpdir } from "os";
|
|
1719
1742
|
import { join } from "path";
|
|
@@ -1826,6 +1849,29 @@ function installRigPiTheme() {
|
|
|
1826
1849
|
}
|
|
1827
1850
|
} catch {}
|
|
1828
1851
|
}
|
|
1852
|
+
async function runWithProcessExitGuard(body) {
|
|
1853
|
+
const realExit = process.exit;
|
|
1854
|
+
let exitCode = 0;
|
|
1855
|
+
let signalQuit = () => {};
|
|
1856
|
+
const quit = new Promise((resolve3) => {
|
|
1857
|
+
signalQuit = resolve3;
|
|
1858
|
+
});
|
|
1859
|
+
const guardedExit = (code) => {
|
|
1860
|
+
exitCode = typeof code === "number" ? code : 0;
|
|
1861
|
+
signalQuit();
|
|
1862
|
+
return;
|
|
1863
|
+
};
|
|
1864
|
+
process.exit = guardedExit;
|
|
1865
|
+
try {
|
|
1866
|
+
await Promise.race([Promise.resolve().then(body), quit]);
|
|
1867
|
+
} finally {
|
|
1868
|
+
process.exit = realExit;
|
|
1869
|
+
}
|
|
1870
|
+
return exitCode;
|
|
1871
|
+
}
|
|
1872
|
+
function runPiMainReturningOnQuit(args, options) {
|
|
1873
|
+
return runWithProcessExitGuard(() => runPiMain(args, options));
|
|
1874
|
+
}
|
|
1829
1875
|
async function attachRunBundledPiFrontend(context, input) {
|
|
1830
1876
|
const tempSessionDir = mkdtempSync(join(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
1831
1877
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -1841,16 +1887,20 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
1841
1887
|
};
|
|
1842
1888
|
let detached = false;
|
|
1843
1889
|
try {
|
|
1844
|
-
|
|
1890
|
+
const piArgs = [
|
|
1845
1891
|
"--offline",
|
|
1846
1892
|
"--no-extensions",
|
|
1847
1893
|
"--no-skills",
|
|
1848
1894
|
"--no-prompt-templates",
|
|
1849
1895
|
"--no-context-files",
|
|
1850
1896
|
...sessionFileArg
|
|
1851
|
-
]
|
|
1852
|
-
|
|
1853
|
-
|
|
1897
|
+
];
|
|
1898
|
+
const piOptions = { extensionFactories: [piRigExtensionFactory] };
|
|
1899
|
+
if (input.returnOnQuit) {
|
|
1900
|
+
await runPiMainReturningOnQuit(piArgs, piOptions);
|
|
1901
|
+
} else {
|
|
1902
|
+
await runPiMain(piArgs, piOptions);
|
|
1903
|
+
}
|
|
1854
1904
|
detached = true;
|
|
1855
1905
|
} finally {
|
|
1856
1906
|
restoreEnv();
|
|
@@ -3238,390 +3288,6 @@ var init_task = __esm(() => {
|
|
|
3238
3288
|
init__connection_state();
|
|
3239
3289
|
});
|
|
3240
3290
|
|
|
3241
|
-
// packages/cli/src/app-opentui/pi-pty-host.ts
|
|
3242
|
-
import { fileURLToPath } from "url";
|
|
3243
|
-
import { basename } from "path";
|
|
3244
|
-
import { RGBA, StyledText, TextAttributes } from "@opentui/core";
|
|
3245
|
-
import { Terminal as XtermTerminal } from "@xterm/headless";
|
|
3246
|
-
function clampCols(cols) {
|
|
3247
|
-
return Math.max(MIN_COLS, Math.trunc(cols || 100));
|
|
3248
|
-
}
|
|
3249
|
-
function clampRows(rows) {
|
|
3250
|
-
return Math.max(MIN_ROWS, Math.min(MAX_ROWS, Math.trunc(rows || 35)));
|
|
3251
|
-
}
|
|
3252
|
-
function rgbaFromXtermColor(mode, value) {
|
|
3253
|
-
if (mode === 1 || mode === 2 || mode === XTERM_COLOR_MODE_INDEXED_16 || mode === XTERM_COLOR_MODE_INDEXED_256) {
|
|
3254
|
-
return RGBA.fromIndex(value);
|
|
3255
|
-
}
|
|
3256
|
-
if (mode === 3 || mode === XTERM_COLOR_MODE_RGB) {
|
|
3257
|
-
return RGBA.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255);
|
|
3258
|
-
}
|
|
3259
|
-
return;
|
|
3260
|
-
}
|
|
3261
|
-
function textAttributesFromCell(cell) {
|
|
3262
|
-
let attributes = TextAttributes.NONE;
|
|
3263
|
-
if (cell.isBold())
|
|
3264
|
-
attributes |= TextAttributes.BOLD;
|
|
3265
|
-
if (cell.isDim())
|
|
3266
|
-
attributes |= TextAttributes.DIM;
|
|
3267
|
-
if (cell.isItalic())
|
|
3268
|
-
attributes |= TextAttributes.ITALIC;
|
|
3269
|
-
if (cell.isUnderline())
|
|
3270
|
-
attributes |= TextAttributes.UNDERLINE;
|
|
3271
|
-
if (cell.isBlink())
|
|
3272
|
-
attributes |= TextAttributes.BLINK;
|
|
3273
|
-
if (cell.isInverse())
|
|
3274
|
-
attributes |= TextAttributes.INVERSE;
|
|
3275
|
-
if (cell.isInvisible())
|
|
3276
|
-
attributes |= TextAttributes.HIDDEN;
|
|
3277
|
-
if (cell.isStrikethrough())
|
|
3278
|
-
attributes |= TextAttributes.STRIKETHROUGH;
|
|
3279
|
-
return attributes;
|
|
3280
|
-
}
|
|
3281
|
-
function sameRgba(a, b) {
|
|
3282
|
-
if (!a && !b)
|
|
3283
|
-
return true;
|
|
3284
|
-
return Boolean(a && b && a.equals(b));
|
|
3285
|
-
}
|
|
3286
|
-
function sameStyle(a, b) {
|
|
3287
|
-
return sameRgba(a.fg, b.fg) && sameRgba(a.bg, b.bg) && (a.attributes ?? 0) === (b.attributes ?? 0);
|
|
3288
|
-
}
|
|
3289
|
-
function styleFromCell(cell) {
|
|
3290
|
-
return {
|
|
3291
|
-
fg: rgbaFromXtermColor(cell.getFgColorMode(), cell.getFgColor()),
|
|
3292
|
-
bg: rgbaFromXtermColor(cell.getBgColorMode(), cell.getBgColor()),
|
|
3293
|
-
attributes: textAttributesFromCell(cell)
|
|
3294
|
-
};
|
|
3295
|
-
}
|
|
3296
|
-
function lineToStyledText(line, cols) {
|
|
3297
|
-
if (!line)
|
|
3298
|
-
return new StyledText([{ __isChunk: true, text: "" }]);
|
|
3299
|
-
const chunks = [];
|
|
3300
|
-
let run = "";
|
|
3301
|
-
let runStyle = null;
|
|
3302
|
-
const flush = () => {
|
|
3303
|
-
if (!run)
|
|
3304
|
-
return;
|
|
3305
|
-
chunks.push({
|
|
3306
|
-
__isChunk: true,
|
|
3307
|
-
text: run,
|
|
3308
|
-
...runStyle?.fg ? { fg: runStyle.fg } : {},
|
|
3309
|
-
...runStyle?.bg ? { bg: runStyle.bg } : {},
|
|
3310
|
-
...(runStyle?.attributes ?? 0) !== 0 ? { attributes: runStyle.attributes } : {}
|
|
3311
|
-
});
|
|
3312
|
-
run = "";
|
|
3313
|
-
};
|
|
3314
|
-
for (let index = 0;index < cols; index += 1) {
|
|
3315
|
-
const cell = line.getCell(index);
|
|
3316
|
-
if (!cell) {
|
|
3317
|
-
if (runStyle !== null)
|
|
3318
|
-
flush();
|
|
3319
|
-
runStyle = null;
|
|
3320
|
-
run += " ";
|
|
3321
|
-
continue;
|
|
3322
|
-
}
|
|
3323
|
-
if (cell.getWidth() === 0)
|
|
3324
|
-
continue;
|
|
3325
|
-
const style = styleFromCell(cell);
|
|
3326
|
-
if (!runStyle || !sameStyle(runStyle, style)) {
|
|
3327
|
-
flush();
|
|
3328
|
-
runStyle = style;
|
|
3329
|
-
}
|
|
3330
|
-
run += cell.getChars() || " ";
|
|
3331
|
-
}
|
|
3332
|
-
flush();
|
|
3333
|
-
return new StyledText(chunks.length > 0 ? chunks : [{ __isChunk: true, text: "" }]);
|
|
3334
|
-
}
|
|
3335
|
-
function childCommandPrefix() {
|
|
3336
|
-
const execName = basename(process.execPath).toLowerCase();
|
|
3337
|
-
const currentEntry = process.argv[1];
|
|
3338
|
-
if (execName === "bun" || execName === "bun.exe") {
|
|
3339
|
-
return currentEntry ? [process.execPath, currentEntry, "__opentui-pi-host"] : [process.execPath, fallbackChildScriptPath];
|
|
3340
|
-
}
|
|
3341
|
-
return [process.execPath, "__opentui-pi-host"];
|
|
3342
|
-
}
|
|
3343
|
-
function withEnv(base) {
|
|
3344
|
-
const env = {};
|
|
3345
|
-
for (const [key, value] of Object.entries(base ?? process.env)) {
|
|
3346
|
-
if (key === "RIG_PLAIN" || key === "RIG_CLI_PLAIN_HELP" || key === "NO_COLOR")
|
|
3347
|
-
continue;
|
|
3348
|
-
if (typeof value === "string")
|
|
3349
|
-
env[key] = value;
|
|
3350
|
-
}
|
|
3351
|
-
return {
|
|
3352
|
-
...env,
|
|
3353
|
-
TERM: "xterm-256color",
|
|
3354
|
-
COLORTERM: "truecolor",
|
|
3355
|
-
FORCE_COLOR: env.FORCE_COLOR ?? "1",
|
|
3356
|
-
RIG_OPENTUI_PI_HOST: "1"
|
|
3357
|
-
};
|
|
3358
|
-
}
|
|
3359
|
-
async function startPiPtyHost(options) {
|
|
3360
|
-
activeHost?.dispose("replace");
|
|
3361
|
-
const host = new PiPtyHost(options);
|
|
3362
|
-
activeHost = host;
|
|
3363
|
-
await host.start();
|
|
3364
|
-
return host;
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
class PiPtyHost {
|
|
3368
|
-
runId;
|
|
3369
|
-
projectRoot;
|
|
3370
|
-
onSnapshot;
|
|
3371
|
-
onExit;
|
|
3372
|
-
onError;
|
|
3373
|
-
terminal;
|
|
3374
|
-
disposables = [];
|
|
3375
|
-
decoder = new TextDecoder("utf-8");
|
|
3376
|
-
proc = null;
|
|
3377
|
-
pty = null;
|
|
3378
|
-
status = "starting";
|
|
3379
|
-
cols;
|
|
3380
|
-
rows;
|
|
3381
|
-
message = "starting bundled Pi";
|
|
3382
|
-
lastResizeError = null;
|
|
3383
|
-
exitCode;
|
|
3384
|
-
signal;
|
|
3385
|
-
notifyTimer = null;
|
|
3386
|
-
lastStreamKey = "";
|
|
3387
|
-
_disposed = false;
|
|
3388
|
-
constructor(options) {
|
|
3389
|
-
this.runId = options.runId;
|
|
3390
|
-
this.projectRoot = options.projectRoot;
|
|
3391
|
-
this.cols = clampCols(options.cols);
|
|
3392
|
-
this.rows = clampRows(options.rows);
|
|
3393
|
-
this.onSnapshot = options.onSnapshot;
|
|
3394
|
-
this.onExit = options.onExit;
|
|
3395
|
-
this.onError = options.onError;
|
|
3396
|
-
this.terminal = new XtermTerminal({
|
|
3397
|
-
allowProposedApi: true,
|
|
3398
|
-
cols: this.cols,
|
|
3399
|
-
rows: this.rows,
|
|
3400
|
-
scrollback: 1000
|
|
3401
|
-
});
|
|
3402
|
-
this.registerTerminalResponders();
|
|
3403
|
-
this.disposables.push(this.terminal.onWriteParsed(() => {
|
|
3404
|
-
if (this._disposed)
|
|
3405
|
-
return;
|
|
3406
|
-
const snapshot = this.createSnapshot();
|
|
3407
|
-
const key = snapshot.lines.join(`
|
|
3408
|
-
`);
|
|
3409
|
-
if (key === this.lastStreamKey)
|
|
3410
|
-
return;
|
|
3411
|
-
this.lastStreamKey = key;
|
|
3412
|
-
this.onSnapshot?.(snapshot);
|
|
3413
|
-
}));
|
|
3414
|
-
}
|
|
3415
|
-
get disposed() {
|
|
3416
|
-
return this._disposed;
|
|
3417
|
-
}
|
|
3418
|
-
get snapshot() {
|
|
3419
|
-
return this.createSnapshot();
|
|
3420
|
-
}
|
|
3421
|
-
async start() {
|
|
3422
|
-
if (this._disposed)
|
|
3423
|
-
throw new Error("Pi PTY host is disposed.");
|
|
3424
|
-
if (typeof Bun.Terminal !== "function") {
|
|
3425
|
-
throw new Error("Bun native PTY is unavailable in this runtime. Pi host requires Bun.Terminal.");
|
|
3426
|
-
}
|
|
3427
|
-
const spawnOptions = {
|
|
3428
|
-
cwd: this.projectRoot,
|
|
3429
|
-
env: withEnv(process.env),
|
|
3430
|
-
terminal: {
|
|
3431
|
-
cols: this.cols,
|
|
3432
|
-
rows: this.rows,
|
|
3433
|
-
name: "xterm-256color",
|
|
3434
|
-
data: (_terminal, data) => this.handlePtyData(data)
|
|
3435
|
-
}
|
|
3436
|
-
};
|
|
3437
|
-
const proc = Bun.spawn([
|
|
3438
|
-
...childCommandPrefix(),
|
|
3439
|
-
"--run-id",
|
|
3440
|
-
this.runId,
|
|
3441
|
-
"--project-root",
|
|
3442
|
-
this.projectRoot
|
|
3443
|
-
], spawnOptions);
|
|
3444
|
-
if (!proc.terminal)
|
|
3445
|
-
throw new Error("Bun did not attach a terminal to the bundled Pi child process.");
|
|
3446
|
-
this.proc = proc;
|
|
3447
|
-
this.pty = proc.terminal;
|
|
3448
|
-
this.status = "running";
|
|
3449
|
-
this.message = "bundled Pi running inside this app";
|
|
3450
|
-
this.emitSnapshotSoon(0);
|
|
3451
|
-
proc.exited.then((exitCode) => {
|
|
3452
|
-
if (this._disposed)
|
|
3453
|
-
return;
|
|
3454
|
-
this.status = exitCode === 0 ? "exited" : "failed";
|
|
3455
|
-
this.exitCode = exitCode;
|
|
3456
|
-
this.signal = null;
|
|
3457
|
-
this.message = exitCode === 0 ? "bundled Pi exited" : `bundled Pi exited with code ${exitCode}`;
|
|
3458
|
-
const snapshot = this.createSnapshot();
|
|
3459
|
-
this.onSnapshot?.(snapshot);
|
|
3460
|
-
this.onExit?.(snapshot);
|
|
3461
|
-
if (activeHost === this)
|
|
3462
|
-
activeHost = null;
|
|
3463
|
-
this.dispose("exit", { kill: false, notify: false });
|
|
3464
|
-
}).catch((error) => {
|
|
3465
|
-
if (this._disposed)
|
|
3466
|
-
return;
|
|
3467
|
-
this.status = "failed";
|
|
3468
|
-
this.message = error instanceof Error ? error.message : String(error);
|
|
3469
|
-
const snapshot = this.createSnapshot();
|
|
3470
|
-
this.onSnapshot?.(snapshot);
|
|
3471
|
-
this.onError?.(error, snapshot);
|
|
3472
|
-
if (activeHost === this)
|
|
3473
|
-
activeHost = null;
|
|
3474
|
-
this.dispose("error", { kill: false, notify: false });
|
|
3475
|
-
});
|
|
3476
|
-
}
|
|
3477
|
-
write(data) {
|
|
3478
|
-
if (this._disposed || !this.pty)
|
|
3479
|
-
return;
|
|
3480
|
-
try {
|
|
3481
|
-
this.pty.write(data);
|
|
3482
|
-
} catch (error) {
|
|
3483
|
-
this.status = "failed";
|
|
3484
|
-
this.message = error instanceof Error ? error.message : String(error);
|
|
3485
|
-
const snapshot = this.createSnapshot();
|
|
3486
|
-
this.onSnapshot?.(snapshot);
|
|
3487
|
-
this.onError?.(error, snapshot);
|
|
3488
|
-
}
|
|
3489
|
-
}
|
|
3490
|
-
resize(cols, rows) {
|
|
3491
|
-
const nextCols = clampCols(cols);
|
|
3492
|
-
const nextRows = clampRows(rows);
|
|
3493
|
-
if (nextCols === this.cols && nextRows === this.rows)
|
|
3494
|
-
return;
|
|
3495
|
-
this.cols = nextCols;
|
|
3496
|
-
this.rows = nextRows;
|
|
3497
|
-
this.terminal.resize(nextCols, nextRows);
|
|
3498
|
-
try {
|
|
3499
|
-
this.pty?.resize(nextCols, nextRows);
|
|
3500
|
-
this.lastResizeError = null;
|
|
3501
|
-
} catch (error) {
|
|
3502
|
-
this.lastResizeError = error instanceof Error ? error.message : String(error);
|
|
3503
|
-
}
|
|
3504
|
-
this.emitSnapshotSoon(0);
|
|
3505
|
-
}
|
|
3506
|
-
detach() {
|
|
3507
|
-
this.dispose("detach");
|
|
3508
|
-
return this.createSnapshot("detached from bundled Pi");
|
|
3509
|
-
}
|
|
3510
|
-
dispose(reason = "dispose", options = {}) {
|
|
3511
|
-
if (this._disposed)
|
|
3512
|
-
return;
|
|
3513
|
-
this._disposed = true;
|
|
3514
|
-
if (this.notifyTimer)
|
|
3515
|
-
clearTimeout(this.notifyTimer);
|
|
3516
|
-
this.notifyTimer = null;
|
|
3517
|
-
for (const disposable of this.disposables.splice(0)) {
|
|
3518
|
-
try {
|
|
3519
|
-
disposable.dispose();
|
|
3520
|
-
} catch {}
|
|
3521
|
-
}
|
|
3522
|
-
if (options.kill !== false) {
|
|
3523
|
-
try {
|
|
3524
|
-
this.proc?.kill("SIGTERM");
|
|
3525
|
-
} catch {}
|
|
3526
|
-
}
|
|
3527
|
-
try {
|
|
3528
|
-
this.pty?.close();
|
|
3529
|
-
} catch {}
|
|
3530
|
-
try {
|
|
3531
|
-
this.terminal.dispose();
|
|
3532
|
-
} catch {}
|
|
3533
|
-
if (activeHost === this)
|
|
3534
|
-
activeHost = null;
|
|
3535
|
-
if (options.notify) {
|
|
3536
|
-
this.message = reason;
|
|
3537
|
-
this.onSnapshot?.(this.createSnapshot(reason));
|
|
3538
|
-
}
|
|
3539
|
-
}
|
|
3540
|
-
handlePtyData(data) {
|
|
3541
|
-
if (this._disposed)
|
|
3542
|
-
return;
|
|
3543
|
-
const text = this.decoder.decode(data, { stream: true });
|
|
3544
|
-
this.respondToRawTerminalQueries(text);
|
|
3545
|
-
this.terminal.write(data);
|
|
3546
|
-
}
|
|
3547
|
-
emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS) {
|
|
3548
|
-
if (this._disposed || this.notifyTimer)
|
|
3549
|
-
return;
|
|
3550
|
-
this.notifyTimer = setTimeout(() => {
|
|
3551
|
-
this.notifyTimer = null;
|
|
3552
|
-
if (this._disposed)
|
|
3553
|
-
return;
|
|
3554
|
-
this.onSnapshot?.(this.createSnapshot());
|
|
3555
|
-
}, delayMs);
|
|
3556
|
-
}
|
|
3557
|
-
createSnapshot(message2 = this.message) {
|
|
3558
|
-
const buffer = this.terminal.buffer.active;
|
|
3559
|
-
const end = buffer.length;
|
|
3560
|
-
const start = Math.max(0, end - MAX_SNAPSHOT_LINES);
|
|
3561
|
-
const styledStart = Math.max(start, end - this.rows - STYLED_SNAPSHOT_MARGIN);
|
|
3562
|
-
const lines = [];
|
|
3563
|
-
const styledLines = [];
|
|
3564
|
-
for (let row = start;row < end; row += 1) {
|
|
3565
|
-
const line = buffer.getLine(row);
|
|
3566
|
-
lines.push((line?.translateToString(false) ?? "").slice(0, this.cols));
|
|
3567
|
-
if (row >= styledStart)
|
|
3568
|
-
styledLines[lines.length - 1] = lineToStyledText(line, this.cols);
|
|
3569
|
-
}
|
|
3570
|
-
while (lines.length < this.rows) {
|
|
3571
|
-
lines.push("");
|
|
3572
|
-
styledLines[lines.length - 1] = new StyledText([{ __isChunk: true, text: "" }]);
|
|
3573
|
-
}
|
|
3574
|
-
const resolvedMessage = this.lastResizeError ? `resize degraded: ${this.lastResizeError}` : message2;
|
|
3575
|
-
return {
|
|
3576
|
-
runId: this.runId,
|
|
3577
|
-
status: this.status,
|
|
3578
|
-
cols: this.cols,
|
|
3579
|
-
rows: this.rows,
|
|
3580
|
-
lines,
|
|
3581
|
-
styledLines,
|
|
3582
|
-
message: resolvedMessage,
|
|
3583
|
-
...this.lastResizeError ? { resizeError: this.lastResizeError } : {},
|
|
3584
|
-
...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
|
|
3585
|
-
...this.signal !== undefined ? { signal: this.signal } : {}
|
|
3586
|
-
};
|
|
3587
|
-
}
|
|
3588
|
-
registerTerminalResponders() {
|
|
3589
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "c" }, (params) => {
|
|
3590
|
-
if (params.length === 0 || params[0] === 0)
|
|
3591
|
-
this.write("\x1B[?62;22c");
|
|
3592
|
-
return false;
|
|
3593
|
-
}));
|
|
3594
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ prefix: ">", final: "c" }, (params) => {
|
|
3595
|
-
if (params.length === 0 || params[0] === 0)
|
|
3596
|
-
this.write("\x1B[>0;0;0c");
|
|
3597
|
-
return false;
|
|
3598
|
-
}));
|
|
3599
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "n" }, (params) => {
|
|
3600
|
-
if (params[0] === 5) {
|
|
3601
|
-
this.write("\x1B[0n");
|
|
3602
|
-
} else if (params[0] === 6) {
|
|
3603
|
-
const row = this.terminal.buffer.active.cursorY + 1;
|
|
3604
|
-
const col = this.terminal.buffer.active.cursorX + 1;
|
|
3605
|
-
this.write(`\x1B[${row};${col}R`);
|
|
3606
|
-
}
|
|
3607
|
-
return false;
|
|
3608
|
-
}));
|
|
3609
|
-
}
|
|
3610
|
-
respondToRawTerminalQueries(text) {
|
|
3611
|
-
if (!text)
|
|
3612
|
-
return;
|
|
3613
|
-
const decrqm = /\x1b\[\?(\d+)\$p/g;
|
|
3614
|
-
let match;
|
|
3615
|
-
while ((match = decrqm.exec(text)) !== null) {
|
|
3616
|
-
this.write(`\x1B[?${match[1]};2$y`);
|
|
3617
|
-
}
|
|
3618
|
-
}
|
|
3619
|
-
}
|
|
3620
|
-
var MIN_COLS = 40, MIN_ROWS = 12, MAX_ROWS = 300, MAX_SNAPSHOT_LINES = 360, STYLED_SNAPSHOT_MARGIN = 6, SNAPSHOT_DELAY_MS = 120, fallbackChildScriptPath, activeHost = null, XTERM_COLOR_MODE_INDEXED_16 = 16777216, XTERM_COLOR_MODE_INDEXED_256 = 33554432, XTERM_COLOR_MODE_RGB = 50331648;
|
|
3621
|
-
var init_pi_pty_host = __esm(() => {
|
|
3622
|
-
fallbackChildScriptPath = fileURLToPath(new URL("./pi-host-child.ts", import.meta.url));
|
|
3623
|
-
});
|
|
3624
|
-
|
|
3625
3291
|
// packages/cli/src/app-opentui/adapters/fleet.ts
|
|
3626
3292
|
function normalizeRunRecord(record) {
|
|
3627
3293
|
const runId = stringField(record, ["runId", "id"]);
|
|
@@ -3887,14 +3553,6 @@ function recordStep(ctx, runId, label, emitLabel) {
|
|
|
3887
3553
|
});
|
|
3888
3554
|
emitProgress(ctx, emitLabel, label);
|
|
3889
3555
|
}
|
|
3890
|
-
function settleSteps(ctx, runId) {
|
|
3891
|
-
const now = Date.now();
|
|
3892
|
-
const previous = currentAttachState(ctx, runId);
|
|
3893
|
-
if (!previous?.steps)
|
|
3894
|
-
return;
|
|
3895
|
-
const steps = previous.steps.map((step) => step.status === "running" ? { ...step, status: "done", endedAtMs: step.endedAtMs ?? now } : step);
|
|
3896
|
-
patchData(ctx, { piAttach: { ...previous, steps } });
|
|
3897
|
-
}
|
|
3898
3556
|
async function preparePiAttachHandoff(ctx, runId) {
|
|
3899
3557
|
const cleanRunId = runId.trim();
|
|
3900
3558
|
const label = `Preparing Pi ${cleanRunId.slice(0, 8)}`;
|
|
@@ -3942,85 +3600,41 @@ async function attachRunWithBundledPi(ctx, runId) {
|
|
|
3942
3600
|
throw error;
|
|
3943
3601
|
}
|
|
3944
3602
|
emitStarted(ctx, label, { piAttach: { runId: cleanRunId, status: "entering-pi" } });
|
|
3945
|
-
patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "
|
|
3603
|
+
patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "handing the terminal to worker Pi\u2026" } });
|
|
3604
|
+
const projectRoot = projectRootOf(ctx);
|
|
3605
|
+
const outputMode = ctx.rig?.outputMode ?? "text";
|
|
3606
|
+
await releaseRendererForExternalTui(ctx);
|
|
3607
|
+
let outcome = null;
|
|
3608
|
+
let attachError = null;
|
|
3946
3609
|
try {
|
|
3947
|
-
|
|
3948
|
-
await
|
|
3949
|
-
patchData(ctx, { lastRefreshError: normalizeAppError(error).message });
|
|
3950
|
-
return null;
|
|
3951
|
-
});
|
|
3952
|
-
recordStep(ctx, cleanRunId, "spawning Bun PTY host for bundled Pi", label);
|
|
3953
|
-
const projectRoot = projectRootOf(ctx);
|
|
3954
|
-
const cols = typeof process.stdout.columns === "number" ? process.stdout.columns : 100;
|
|
3955
|
-
const rows = Math.max(1, (typeof process.stdout.rows === "number" ? process.stdout.rows : 35) - 1);
|
|
3956
|
-
const patchTerminal = (snapshot) => {
|
|
3957
|
-
const previousSteps = currentAttachState(ctx, cleanRunId)?.steps;
|
|
3958
|
-
const failed = snapshot.status === "failed";
|
|
3959
|
-
const reason = failed ? snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}` : undefined;
|
|
3960
|
-
patchData(ctx, {
|
|
3961
|
-
piTerminal: snapshot,
|
|
3962
|
-
piAttach: {
|
|
3963
|
-
runId: cleanRunId,
|
|
3964
|
-
status: failed ? "failed" : snapshot.status === "exited" ? "returned" : "entering-pi",
|
|
3965
|
-
message: snapshot.message ?? "bundled Pi running",
|
|
3966
|
-
result: { runId: cleanRunId, status: snapshot.status, exitCode: snapshot.exitCode },
|
|
3967
|
-
...previousSteps ? { steps: previousSteps } : {},
|
|
3968
|
-
...reason ? { failureReason: reason } : {}
|
|
3969
|
-
}
|
|
3970
|
-
});
|
|
3971
|
-
};
|
|
3972
|
-
recordStep(ctx, cleanRunId, "starting bundled Pi", label);
|
|
3973
|
-
await startPiPtyHost({
|
|
3974
|
-
runId: cleanRunId,
|
|
3975
|
-
projectRoot,
|
|
3976
|
-
cols,
|
|
3977
|
-
rows,
|
|
3978
|
-
onSnapshot: (snapshot) => {
|
|
3979
|
-
if (snapshot.status === "running" && snapshot.lines.some((entry) => entry.trim().length > 0)) {
|
|
3980
|
-
settleSteps(ctx, cleanRunId);
|
|
3981
|
-
}
|
|
3982
|
-
patchTerminal(snapshot);
|
|
3983
|
-
},
|
|
3984
|
-
onExit: (snapshot) => {
|
|
3985
|
-
patchTerminal(snapshot);
|
|
3986
|
-
if (snapshot.status === "failed") {
|
|
3987
|
-
Promise.resolve().then(() => (init_inspect(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
|
|
3988
|
-
emitFailed(ctx, label, new Error(snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}`), { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
|
|
3989
|
-
return;
|
|
3990
|
-
}
|
|
3991
|
-
emitCompleted(ctx, label, { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
|
|
3992
|
-
ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
|
|
3993
|
-
refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
|
|
3994
|
-
},
|
|
3995
|
-
onError: (error, snapshot) => {
|
|
3996
|
-
patchTerminal(snapshot);
|
|
3997
|
-
emitFailed(ctx, label, error, { runId: cleanRunId });
|
|
3998
|
-
}
|
|
3999
|
-
});
|
|
4000
|
-
const record = {
|
|
4001
|
-
runId: cleanRunId,
|
|
4002
|
-
status: "running",
|
|
4003
|
-
rendered: "bundled Pi embedded via Bun.Terminal + @xterm/headless"
|
|
4004
|
-
};
|
|
4005
|
-
emitProgress(ctx, label, "bundled Pi is running", { piAttach: { runId: cleanRunId, status: "entering-pi", message: "bundled Pi running", result: record } });
|
|
4006
|
-
return record;
|
|
3610
|
+
const { attachRunBundledPiFrontend: attachRunBundledPiFrontend2 } = await Promise.resolve().then(() => (init__pi_frontend(), exports__pi_frontend));
|
|
3611
|
+
outcome = await attachRunBundledPiFrontend2({ projectRoot, outputMode }, { runId: cleanRunId, returnOnQuit: true });
|
|
4007
3612
|
} catch (error) {
|
|
4008
|
-
|
|
3613
|
+
attachError = error;
|
|
3614
|
+
} finally {
|
|
3615
|
+
await resumeRendererAfterExternalTui(ctx);
|
|
3616
|
+
}
|
|
3617
|
+
if (attachError) {
|
|
3618
|
+
const reason = normalizeAppError(attachError).message;
|
|
4009
3619
|
patchData(ctx, {
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
status: "failed",
|
|
4013
|
-
message: reason,
|
|
4014
|
-
failureReason: reason,
|
|
4015
|
-
...currentAttachState(ctx, cleanRunId)?.steps ? { steps: currentAttachState(ctx, cleanRunId).steps } : {}
|
|
4016
|
-
}
|
|
3620
|
+
piTerminal: undefined,
|
|
3621
|
+
piAttach: { runId: cleanRunId, status: "failed", message: reason, failureReason: reason }
|
|
4017
3622
|
});
|
|
4018
|
-
|
|
4019
|
-
|
|
3623
|
+
Promise.resolve().then(() => (init_inspect(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
|
|
3624
|
+
emitFailed(ctx, label, attachError, { runId: cleanRunId });
|
|
3625
|
+
throw attachError;
|
|
4020
3626
|
}
|
|
3627
|
+
const detached = outcome?.detached === true;
|
|
3628
|
+
patchData(ctx, {
|
|
3629
|
+
piTerminal: undefined,
|
|
3630
|
+
piAttach: { runId: cleanRunId, status: "returned", message: detached ? "detached from worker Pi" : "returned from worker Pi" }
|
|
3631
|
+
});
|
|
3632
|
+
emitCompleted(ctx, label, { runId: cleanRunId, result: { runId: cleanRunId, detached } });
|
|
3633
|
+
ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
|
|
3634
|
+
refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
|
|
3635
|
+
return { runId: cleanRunId, status: "returned", detached };
|
|
4021
3636
|
}
|
|
4022
3637
|
var init_pi_attach = __esm(() => {
|
|
4023
|
-
init_pi_pty_host();
|
|
4024
3638
|
init_fleet();
|
|
4025
3639
|
});
|
|
4026
3640
|
|