@goah/cli 0.13.2 → 0.13.3

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 (2) hide show
  1. package/dist/cli.js +561 -26
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -51,7 +51,7 @@ import "./chunk-XPQKM3L7.js";
51
51
 
52
52
  // node_modules/.dist-original/cli.js
53
53
  import { spawn as spawn4 } from "node:child_process";
54
- import { closeSync as closeSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
54
+ import { closeSync as closeSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, writeFileSync } from "node:fs";
55
55
  import { join as join7, resolve as resolve3 } from "node:path";
56
56
 
57
57
  // ../../node_modules/marked/lib/marked.esm.js
@@ -3035,6 +3035,92 @@ var _kittyProtocolActive = false;
3035
3035
  function setKittyProtocolActive(active) {
3036
3036
  _kittyProtocolActive = active;
3037
3037
  }
3038
+ var Key = {
3039
+ // Special keys
3040
+ escape: "escape",
3041
+ esc: "esc",
3042
+ enter: "enter",
3043
+ return: "return",
3044
+ tab: "tab",
3045
+ space: "space",
3046
+ backspace: "backspace",
3047
+ delete: "delete",
3048
+ insert: "insert",
3049
+ clear: "clear",
3050
+ home: "home",
3051
+ end: "end",
3052
+ pageUp: "pageUp",
3053
+ pageDown: "pageDown",
3054
+ up: "up",
3055
+ down: "down",
3056
+ left: "left",
3057
+ right: "right",
3058
+ f1: "f1",
3059
+ f2: "f2",
3060
+ f3: "f3",
3061
+ f4: "f4",
3062
+ f5: "f5",
3063
+ f6: "f6",
3064
+ f7: "f7",
3065
+ f8: "f8",
3066
+ f9: "f9",
3067
+ f10: "f10",
3068
+ f11: "f11",
3069
+ f12: "f12",
3070
+ // Symbol keys
3071
+ backtick: "`",
3072
+ hyphen: "-",
3073
+ equals: "=",
3074
+ leftbracket: "[",
3075
+ rightbracket: "]",
3076
+ backslash: "\\",
3077
+ semicolon: ";",
3078
+ quote: "'",
3079
+ comma: ",",
3080
+ period: ".",
3081
+ slash: "/",
3082
+ exclamation: "!",
3083
+ at: "@",
3084
+ hash: "#",
3085
+ dollar: "$",
3086
+ percent: "%",
3087
+ caret: "^",
3088
+ ampersand: "&",
3089
+ asterisk: "*",
3090
+ leftparen: "(",
3091
+ rightparen: ")",
3092
+ underscore: "_",
3093
+ plus: "+",
3094
+ pipe: "|",
3095
+ tilde: "~",
3096
+ leftbrace: "{",
3097
+ rightbrace: "}",
3098
+ colon: ":",
3099
+ lessthan: "<",
3100
+ greaterthan: ">",
3101
+ question: "?",
3102
+ // Single modifiers
3103
+ ctrl: (key) => `ctrl+${key}`,
3104
+ shift: (key) => `shift+${key}`,
3105
+ alt: (key) => `alt+${key}`,
3106
+ super: (key) => `super+${key}`,
3107
+ // Combined modifiers
3108
+ ctrlShift: (key) => `ctrl+shift+${key}`,
3109
+ shiftCtrl: (key) => `shift+ctrl+${key}`,
3110
+ ctrlAlt: (key) => `ctrl+alt+${key}`,
3111
+ altCtrl: (key) => `alt+ctrl+${key}`,
3112
+ shiftAlt: (key) => `shift+alt+${key}`,
3113
+ altShift: (key) => `alt+shift+${key}`,
3114
+ ctrlSuper: (key) => `ctrl+super+${key}`,
3115
+ superCtrl: (key) => `super+ctrl+${key}`,
3116
+ shiftSuper: (key) => `shift+super+${key}`,
3117
+ superShift: (key) => `super+shift+${key}`,
3118
+ altSuper: (key) => `alt+super+${key}`,
3119
+ superAlt: (key) => `super+alt+${key}`,
3120
+ // Triple modifiers
3121
+ ctrlShiftAlt: (key) => `ctrl+shift+alt+${key}`,
3122
+ ctrlShiftSuper: (key) => `ctrl+shift+super+${key}`
3123
+ };
3038
3124
  var SYMBOL_KEYS = /* @__PURE__ */ new Set([
3039
3125
  "`",
3040
3126
  "-",
@@ -4064,8 +4150,14 @@ function parseTerminalColorSchemeReport(data) {
4064
4150
 
4065
4151
  // ../../node_modules/@earendil-works/pi-tui/dist/terminal-image.js
4066
4152
  import { execSync } from "node:child_process";
4153
+ import { homedir as homedir2 } from "node:os";
4154
+ import { isAbsolute } from "node:path";
4155
+ import { pathToFileURL } from "node:url";
4067
4156
  var cachedCapabilities = null;
4068
4157
  var cellDimensions = { widthPx: 9, heightPx: 18 };
4158
+ function getCellDimensions() {
4159
+ return cellDimensions;
4160
+ }
4069
4161
  function setCellDimensions(dims) {
4070
4162
  cellDimensions = dims;
4071
4163
  }
@@ -4143,6 +4235,41 @@ function isImageLine(line) {
4143
4235
  }
4144
4236
  return line.includes(KITTY_PREFIX) || line.includes(ITERM2_PREFIX);
4145
4237
  }
4238
+ function allocateImageId() {
4239
+ return Math.floor(Math.random() * 4294967294) + 1;
4240
+ }
4241
+ function encodeKitty(base64Data, options = {}) {
4242
+ const CHUNK_SIZE = 4096;
4243
+ const params = ["a=T", "f=100", "q=2"];
4244
+ if (options.moveCursor === false)
4245
+ params.push("C=1");
4246
+ if (options.columns)
4247
+ params.push(`c=${options.columns}`);
4248
+ if (options.rows)
4249
+ params.push(`r=${options.rows}`);
4250
+ if (options.imageId)
4251
+ params.push(`i=${options.imageId}`);
4252
+ if (base64Data.length <= CHUNK_SIZE) {
4253
+ return `\x1B_G${params.join(",")};${base64Data}\x1B\\`;
4254
+ }
4255
+ const chunks = [];
4256
+ let offset = 0;
4257
+ let isFirst = true;
4258
+ while (offset < base64Data.length) {
4259
+ const chunk = base64Data.slice(offset, offset + CHUNK_SIZE);
4260
+ const isLast = offset + CHUNK_SIZE >= base64Data.length;
4261
+ if (isFirst) {
4262
+ chunks.push(`\x1B_G${params.join(",")},m=1;${chunk}\x1B\\`);
4263
+ isFirst = false;
4264
+ } else if (isLast) {
4265
+ chunks.push(`\x1B_Gm=0;${chunk}\x1B\\`);
4266
+ } else {
4267
+ chunks.push(`\x1B_Gm=1;${chunk}\x1B\\`);
4268
+ }
4269
+ offset += CHUNK_SIZE;
4270
+ }
4271
+ return chunks.join("");
4272
+ }
4146
4273
  function deleteKittyImage(imageId) {
4147
4274
  return `\x1B_Ga=d,d=I,i=${imageId},q=2\x1B\\`;
4148
4275
  }
@@ -4152,7 +4279,36 @@ function deleteAllKittyImages() {
4152
4279
  function deleteAllKittyPlacements() {
4153
4280
  return "\x1B_Ga=d,d=a,q=2\x1B\\";
4154
4281
  }
4282
+ function encodeITerm2(base64Data, options = {}) {
4283
+ const params = [
4284
+ `inline=${options.inline !== false ? 1 : 0}`,
4285
+ `size=${Buffer.byteLength(base64Data, "base64")}`
4286
+ ];
4287
+ if (options.width !== void 0)
4288
+ params.push(`width=${options.width}`);
4289
+ if (options.height !== void 0)
4290
+ params.push(`height=${options.height}`);
4291
+ if (options.name) {
4292
+ const nameBase64 = Buffer.from(options.name).toString("base64");
4293
+ params.push(`name=${nameBase64}`);
4294
+ }
4295
+ if (options.preserveAspectRatio === false) {
4296
+ params.push("preserveAspectRatio=0");
4297
+ }
4298
+ return `\x1B]1337;File=${params.join(";")}:${base64Data}\x07`;
4299
+ }
4155
4300
  var kittyImageMetadata = /* @__PURE__ */ new Map();
4301
+ var kittyTransmissionGeneration = 0;
4302
+ function registerKittyImageMetadata(metadata) {
4303
+ kittyTransmissionGeneration += 1;
4304
+ kittyImageMetadata.delete(metadata.imageId);
4305
+ kittyImageMetadata.set(metadata.imageId, { ...metadata, transmissionGeneration: kittyTransmissionGeneration });
4306
+ if (kittyImageMetadata.size > 1e3) {
4307
+ const oldestImageId = kittyImageMetadata.keys().next().value;
4308
+ if (oldestImageId !== void 0)
4309
+ kittyImageMetadata.delete(oldestImageId);
4310
+ }
4311
+ }
4156
4312
  function getRegisteredKittyImageMetadata(line) {
4157
4313
  const controls = /\x1b_G([^;]*);/.exec(line)?.[1];
4158
4314
  if (!controls)
@@ -4240,9 +4396,203 @@ function cropKittyImageLine(line, hiddenRows, visibleRows) {
4240
4396
  controls.push(`y=${sourceY}`, `h=${sourceHeight}`, `r=${croppedRows}`);
4241
4397
  return `${line.slice(0, match.index)}\x1B_G${controls.join(",")};${line.slice(match.index + match[0].length)}`;
4242
4398
  }
4399
+ function calculateImageCellSize(imageDimensions, maxWidthCells, maxHeightCells, cellDimensions2 = { widthPx: 9, heightPx: 18 }) {
4400
+ const maxWidth = Math.max(1, Math.floor(maxWidthCells));
4401
+ const maxHeight = maxHeightCells === void 0 ? void 0 : Math.max(1, Math.floor(maxHeightCells));
4402
+ const imageWidth = Math.max(1, imageDimensions.widthPx);
4403
+ const imageHeight = Math.max(1, imageDimensions.heightPx);
4404
+ const widthScale = maxWidth * cellDimensions2.widthPx / imageWidth;
4405
+ const heightScale = maxHeight === void 0 ? widthScale : maxHeight * cellDimensions2.heightPx / imageHeight;
4406
+ const scale = Math.min(widthScale, heightScale);
4407
+ const scaledWidthPx = imageWidth * scale;
4408
+ const scaledHeightPx = imageHeight * scale;
4409
+ const columns = Math.ceil(scaledWidthPx / cellDimensions2.widthPx);
4410
+ const rows = Math.ceil(scaledHeightPx / cellDimensions2.heightPx);
4411
+ return {
4412
+ columns: Math.max(1, Math.min(maxWidth, columns)),
4413
+ rows: Math.max(1, maxHeight === void 0 ? rows : Math.min(maxHeight, rows))
4414
+ };
4415
+ }
4416
+ function getPngDimensions(base64Data) {
4417
+ try {
4418
+ const buffer = Buffer.from(base64Data, "base64");
4419
+ if (buffer.length < 24) {
4420
+ return null;
4421
+ }
4422
+ if (buffer[0] !== 137 || buffer[1] !== 80 || buffer[2] !== 78 || buffer[3] !== 71) {
4423
+ return null;
4424
+ }
4425
+ const width = buffer.readUInt32BE(16);
4426
+ const height = buffer.readUInt32BE(20);
4427
+ return { widthPx: width, heightPx: height };
4428
+ } catch {
4429
+ return null;
4430
+ }
4431
+ }
4432
+ function getJpegDimensions(base64Data) {
4433
+ try {
4434
+ const buffer = Buffer.from(base64Data, "base64");
4435
+ if (buffer.length < 2) {
4436
+ return null;
4437
+ }
4438
+ if (buffer[0] !== 255 || buffer[1] !== 216) {
4439
+ return null;
4440
+ }
4441
+ let offset = 2;
4442
+ while (offset < buffer.length - 9) {
4443
+ if (buffer[offset] !== 255) {
4444
+ offset++;
4445
+ continue;
4446
+ }
4447
+ const marker = buffer[offset + 1];
4448
+ if (marker >= 192 && marker <= 194) {
4449
+ const height = buffer.readUInt16BE(offset + 5);
4450
+ const width = buffer.readUInt16BE(offset + 7);
4451
+ return { widthPx: width, heightPx: height };
4452
+ }
4453
+ if (offset + 3 >= buffer.length) {
4454
+ return null;
4455
+ }
4456
+ const length = buffer.readUInt16BE(offset + 2);
4457
+ if (length < 2) {
4458
+ return null;
4459
+ }
4460
+ offset += 2 + length;
4461
+ }
4462
+ return null;
4463
+ } catch {
4464
+ return null;
4465
+ }
4466
+ }
4467
+ function getGifDimensions(base64Data) {
4468
+ try {
4469
+ const buffer = Buffer.from(base64Data, "base64");
4470
+ if (buffer.length < 10) {
4471
+ return null;
4472
+ }
4473
+ const sig = buffer.slice(0, 6).toString("ascii");
4474
+ if (sig !== "GIF87a" && sig !== "GIF89a") {
4475
+ return null;
4476
+ }
4477
+ const width = buffer.readUInt16LE(6);
4478
+ const height = buffer.readUInt16LE(8);
4479
+ return { widthPx: width, heightPx: height };
4480
+ } catch {
4481
+ return null;
4482
+ }
4483
+ }
4484
+ function getWebpDimensions(base64Data) {
4485
+ try {
4486
+ const buffer = Buffer.from(base64Data, "base64");
4487
+ if (buffer.length < 30) {
4488
+ return null;
4489
+ }
4490
+ const riff = buffer.slice(0, 4).toString("ascii");
4491
+ const webp = buffer.slice(8, 12).toString("ascii");
4492
+ if (riff !== "RIFF" || webp !== "WEBP") {
4493
+ return null;
4494
+ }
4495
+ const chunk = buffer.slice(12, 16).toString("ascii");
4496
+ if (chunk === "VP8 ") {
4497
+ if (buffer.length < 30)
4498
+ return null;
4499
+ const width = buffer.readUInt16LE(26) & 16383;
4500
+ const height = buffer.readUInt16LE(28) & 16383;
4501
+ return { widthPx: width, heightPx: height };
4502
+ } else if (chunk === "VP8L") {
4503
+ if (buffer.length < 25)
4504
+ return null;
4505
+ const bits = buffer.readUInt32LE(21);
4506
+ const width = (bits & 16383) + 1;
4507
+ const height = (bits >> 14 & 16383) + 1;
4508
+ return { widthPx: width, heightPx: height };
4509
+ } else if (chunk === "VP8X") {
4510
+ if (buffer.length < 30)
4511
+ return null;
4512
+ const width = (buffer[24] | buffer[25] << 8 | buffer[26] << 16) + 1;
4513
+ const height = (buffer[27] | buffer[28] << 8 | buffer[29] << 16) + 1;
4514
+ return { widthPx: width, heightPx: height };
4515
+ }
4516
+ return null;
4517
+ } catch {
4518
+ return null;
4519
+ }
4520
+ }
4521
+ function getImageDimensions(base64Data, mimeType) {
4522
+ if (mimeType === "image/png") {
4523
+ return getPngDimensions(base64Data);
4524
+ }
4525
+ if (mimeType === "image/jpeg") {
4526
+ return getJpegDimensions(base64Data);
4527
+ }
4528
+ if (mimeType === "image/gif") {
4529
+ return getGifDimensions(base64Data);
4530
+ }
4531
+ if (mimeType === "image/webp") {
4532
+ return getWebpDimensions(base64Data);
4533
+ }
4534
+ return null;
4535
+ }
4536
+ function renderImage(base64Data, imageDimensions, options = {}) {
4537
+ const caps = getCapabilities();
4538
+ if (!caps.images) {
4539
+ return null;
4540
+ }
4541
+ const maxWidth = options.maxWidthCells ?? 80;
4542
+ const size = calculateImageCellSize(imageDimensions, maxWidth, options.maxHeightCells, getCellDimensions());
4543
+ if (caps.images === "kitty") {
4544
+ if (options.imageId !== void 0) {
4545
+ registerKittyImageMetadata({
4546
+ imageId: options.imageId,
4547
+ columns: size.columns,
4548
+ rows: size.rows,
4549
+ widthPx: imageDimensions.widthPx,
4550
+ heightPx: imageDimensions.heightPx
4551
+ });
4552
+ }
4553
+ const sequence = encodeKitty(base64Data, {
4554
+ columns: size.columns,
4555
+ rows: size.rows,
4556
+ imageId: options.imageId,
4557
+ moveCursor: options.moveCursor
4558
+ });
4559
+ return { sequence, columns: size.columns, rows: size.rows, imageId: options.imageId };
4560
+ }
4561
+ if (caps.images === "iterm2") {
4562
+ const sequence = encodeITerm2(base64Data, {
4563
+ width: size.columns,
4564
+ height: "auto",
4565
+ preserveAspectRatio: options.preserveAspectRatio ?? true
4566
+ });
4567
+ return { sequence, columns: size.columns, rows: size.rows };
4568
+ }
4569
+ return null;
4570
+ }
4243
4571
  function hyperlink(text, url) {
4244
4572
  return `\x1B]8;;${url}\x1B\\${text}\x1B]8;;\x1B\\`;
4245
4573
  }
4574
+ function shortenImagePath(filename) {
4575
+ const home = homedir2();
4576
+ if (home && (filename === home || filename.startsWith(`${home}/`) || filename.startsWith(`${home}\\`))) {
4577
+ return `~${filename.slice(home.length)}`;
4578
+ }
4579
+ return filename;
4580
+ }
4581
+ function imageFallback(mimeType, dimensions, filename) {
4582
+ const parts = [];
4583
+ if (filename) {
4584
+ const display = shortenImagePath(filename);
4585
+ if (getCapabilities().hyperlinks && isAbsolute(filename)) {
4586
+ parts.push(hyperlink(display, pathToFileURL(filename).href));
4587
+ } else {
4588
+ parts.push(display);
4589
+ }
4590
+ }
4591
+ parts.push(`[${mimeType}]`);
4592
+ if (dimensions)
4593
+ parts.push(`${dimensions.widthPx}x${dimensions.heightPx}`);
4594
+ return `[Image: ${parts.join(" ")}]`;
4595
+ }
4246
4596
 
4247
4597
  // ../../node_modules/@earendil-works/pi-tui/dist/tui.js
4248
4598
  function isFocusable(component) {
@@ -7062,6 +7412,125 @@ function allocateStackSizes(entries, intrinsicSizes, availableSize, gap) {
7062
7412
  return sizes;
7063
7413
  }
7064
7414
 
7415
+ // ../../node_modules/@earendil-works/pi-tui/dist/components/h-stack.js
7416
+ var HStack = class extends Stack {
7417
+ layoutType = "hstack";
7418
+ constructor(children = [], options = {}) {
7419
+ super(children, options);
7420
+ }
7421
+ render(width) {
7422
+ const safeWidth = Math.max(1, width);
7423
+ const viewport = { width: safeWidth, height: Number.MAX_SAFE_INTEGER };
7424
+ const entries = visibleStackEntries(this.entries, viewport);
7425
+ if (entries.length === 0)
7426
+ return [];
7427
+ const intrinsicWidths = entries.map((entry) => {
7428
+ const lines = entry.component.render(safeWidth);
7429
+ return lines.reduce((max, line) => Math.max(max, visibleWidth(line)), 0);
7430
+ });
7431
+ const widths = allocateStackSizes(entries, intrinsicWidths, safeWidth, this.gap);
7432
+ const rendered = entries.map((entry, index) => widths[index] === 0 ? [] : entry.component.render(widths[index]));
7433
+ const height = rendered.reduce((max, lines) => Math.max(max, lines.length), 0);
7434
+ const result = Array.from({ length: height }, () => "");
7435
+ let x2 = 0;
7436
+ for (let index = 0; index < rendered.length; index++) {
7437
+ const lines = rendered[index];
7438
+ const childWidth = widths[index];
7439
+ let offset = 0;
7440
+ if (this.align === "center")
7441
+ offset = Math.floor((height - lines.length) / 2);
7442
+ else if (this.align === "end")
7443
+ offset = height - lines.length;
7444
+ for (let row = 0; row < lines.length; row++) {
7445
+ const target = row + offset;
7446
+ if (target < 0 || target >= result.length)
7447
+ continue;
7448
+ result[target] = compositeTuiLine(result[target], lines[row], x2, childWidth, safeWidth);
7449
+ }
7450
+ x2 += childWidth + this.gap;
7451
+ }
7452
+ return result;
7453
+ }
7454
+ };
7455
+
7456
+ // ../../node_modules/@earendil-works/pi-tui/dist/components/image.js
7457
+ var Image = class {
7458
+ base64Data;
7459
+ mimeType;
7460
+ dimensions;
7461
+ theme;
7462
+ options;
7463
+ imageId;
7464
+ cachedLines;
7465
+ cachedWidth;
7466
+ constructor(base64Data, mimeType, theme2, options = {}, dimensions) {
7467
+ this.base64Data = base64Data;
7468
+ this.mimeType = mimeType;
7469
+ this.theme = theme2;
7470
+ this.options = options;
7471
+ this.dimensions = dimensions || getImageDimensions(base64Data, mimeType) || { widthPx: 800, heightPx: 600 };
7472
+ this.imageId = options.imageId;
7473
+ }
7474
+ /** Get the Kitty image ID used by this image (if any). */
7475
+ getImageId() {
7476
+ return this.imageId;
7477
+ }
7478
+ invalidate() {
7479
+ this.cachedLines = void 0;
7480
+ this.cachedWidth = void 0;
7481
+ }
7482
+ render(width) {
7483
+ if (this.cachedLines && this.cachedWidth === width) {
7484
+ return this.cachedLines;
7485
+ }
7486
+ const maxWidth = Math.max(1, Math.min(width - 2, this.options.maxWidthCells ?? 60));
7487
+ const cellDimensions2 = getCellDimensions();
7488
+ const defaultMaxHeight = Math.max(1, Math.ceil(maxWidth * cellDimensions2.widthPx / cellDimensions2.heightPx));
7489
+ const maxHeight = this.options.maxHeightCells ?? defaultMaxHeight;
7490
+ const caps = getCapabilities();
7491
+ let lines;
7492
+ if (caps.images) {
7493
+ if (caps.images === "kitty" && this.imageId === void 0) {
7494
+ this.imageId = allocateImageId();
7495
+ }
7496
+ const result = renderImage(this.base64Data, this.dimensions, {
7497
+ maxWidthCells: maxWidth,
7498
+ maxHeightCells: maxHeight,
7499
+ imageId: this.imageId,
7500
+ moveCursor: false
7501
+ });
7502
+ if (result) {
7503
+ if (result.imageId) {
7504
+ this.imageId = result.imageId;
7505
+ }
7506
+ if (caps.images === "kitty") {
7507
+ lines = [result.sequence];
7508
+ for (let i = 0; i < result.rows - 1; i++) {
7509
+ lines.push("");
7510
+ }
7511
+ } else {
7512
+ lines = [];
7513
+ for (let i = 0; i < result.rows - 1; i++) {
7514
+ lines.push("");
7515
+ }
7516
+ const rowOffset = result.rows - 1;
7517
+ const moveUp = rowOffset > 0 ? `\x1B[${rowOffset}A` : "";
7518
+ lines.push(moveUp + result.sequence);
7519
+ }
7520
+ } else {
7521
+ const fallback = imageFallback(this.mimeType, this.dimensions, this.options.filename);
7522
+ lines = [truncateToWidth(this.theme.fallbackColor(fallback), width)];
7523
+ }
7524
+ } else {
7525
+ const fallback = imageFallback(this.mimeType, this.dimensions, this.options.filename);
7526
+ lines = [truncateToWidth(this.theme.fallbackColor(fallback), width)];
7527
+ }
7528
+ this.cachedLines = lines;
7529
+ this.cachedWidth = width;
7530
+ return lines;
7531
+ }
7532
+ };
7533
+
7065
7534
  // ../../node_modules/@earendil-works/pi-tui/dist/components/input.js
7066
7535
  var segmenter = getGraphemeSegmenter();
7067
7536
  var Input = class {
@@ -11854,10 +12323,12 @@ var WELCOME_TEAM_SLOTS = 3;
11854
12323
  var WELCOME_HANDOFF_SLOTS = 2;
11855
12324
  var WELCOME_CONVERSATION_SLOTS = 240;
11856
12325
  var GOAH_TERMINAL_MARK = [
11857
- " \u256D\u2500\u2500\u2500\u2500\u256E",
11858
- " \u256D\u2500\u2500\u2500\u256F \u25CF \u2570\u2500\u2500\u2500\u256E",
11859
- " \u2570\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256F",
11860
- " \u2570\u2500\u2500\u2500\u2500\u256F"
12326
+ "\u2800\u2800\u2800\u2880\u28F4\u281F\u281B\u2832\u2840\u2800\u2800\u2800",
12327
+ "\u2800\u2800\u2880\u28FF\u28E5\u2836\u2836\u281E\u28BB\u281B\u2812\u2800",
12328
+ "\u28F0\u281E\u28BB\u284F\u28F0\u28FE\u28F6\u2844\u28B8\u285F\u28B3\u2844",
12329
+ "\u283B\u28E6\u28F8\u28C7\u28D9\u28FF\u28DF\u28C1\u28FF\u28F4\u283E\u2803",
12330
+ "\u2800\u2800\u2809\u28BF\u2849\u2809\u28C9\u28FF\u2803\u2800\u2800\u2800",
12331
+ "\u2800\u2800\u2800\u2808\u281B\u281B\u280B\u2801\u2800\u2800\u2800\u2800"
11861
12332
  ];
11862
12333
  function welcomeSnapshot(stateDir, runner) {
11863
12334
  const database = join5(stateDir, "ledger.sqlite");
@@ -11880,7 +12351,7 @@ function welcomeSnapshot(stateDir, runner) {
11880
12351
  return [{ agent: row.actor, result: "" }];
11881
12352
  }
11882
12353
  });
11883
- const itemRows = db.prepare("SELECT i.type,i.data FROM turn_items i JOIN turns t ON t.id=i.turn_id JOIN threads th ON th.id=t.thread_id WHERE th.agent='ceo' AND t.trigger_kind='user_message' AND t.status<>'in_progress' AND i.status='completed' AND i.type IN ('user_message','assistant_message') AND (i.type='user_message' OR t.goal_id IS NULL OR EXISTS (SELECT 1 FROM events e WHERE e.stream_id='turn:'||t.id AND e.type='response.committed' AND json_extract(e.data,'$.messageItemId')=i.id)) ORDER BY i.rowid DESC LIMIT ?").all(WELCOME_CONVERSATION_SLOTS);
12354
+ const itemRows = db.prepare("SELECT i.type,i.data FROM turn_items i JOIN turns t ON t.id=i.turn_id JOIN threads th ON th.id=t.thread_id WHERE th.agent='ceo' AND t.trigger_kind='user_message' AND t.status='completed' AND i.status='completed' AND i.type IN ('user_message','assistant_message') AND (i.type='user_message' OR t.goal_id IS NULL OR EXISTS (SELECT 1 FROM events e WHERE e.stream_id='turn:'||t.id AND e.type='response.committed' AND json_extract(e.data,'$.messageItemId')=i.id)) ORDER BY i.rowid DESC LIMIT ?").all(WELCOME_CONVERSATION_SLOTS);
11884
12355
  const conversation = itemRows.reverse().flatMap((row) => {
11885
12356
  try {
11886
12357
  const data = JSON.parse(row.data);
@@ -11894,15 +12365,6 @@ function welcomeSnapshot(stateDir, runner) {
11894
12365
  db.close();
11895
12366
  }
11896
12367
  }
11897
- function renderWelcome(snapshot, hasHistory) {
11898
- const lines = ["", ...GOAH_TERMINAL_MARK.map((line) => tuiTheme.accent(line)), "", ` ${tuiTheme.strong(hasHistory ? "Welcome back." : "Ready when you are.")}`, ` ${tuiTheme.accent(snapshot.target)} ${tuiTheme.muted(`\xB7 ${snapshot.runner}`)}`];
11899
- if (!snapshot.root)
11900
- lines.push(` ${tuiTheme.muted("Chat normally \xB7 /goal for durable work \xB7 /help")}`);
11901
- if (snapshot.team.length)
11902
- lines.push(` ${tuiTheme.muted(`${snapshot.team.length} Goal Agent${snapshot.team.length === 1 ? "" : "s"} in the organization`)}`);
11903
- lines.push("");
11904
- return lines;
11905
- }
11906
12368
 
11907
12369
  // node_modules/.dist-original/setup-wizard.js
11908
12370
  import { spawn as spawn2 } from "node:child_process";
@@ -12147,7 +12609,7 @@ function openUrl(url) {
12147
12609
 
12148
12610
  // node_modules/.dist-original/tui.js
12149
12611
  import { spawn as spawn3 } from "node:child_process";
12150
- import { closeSync, existsSync as existsSync2, mkdirSync, openSync } from "node:fs";
12612
+ import { closeSync, existsSync as existsSync2, mkdirSync, openSync, readFileSync as readFileSync2 } from "node:fs";
12151
12613
  import { join as join6, resolve as resolve2 } from "node:path";
12152
12614
  var HeaderBar = class {
12153
12615
  runner;
@@ -12202,7 +12664,10 @@ var ConversationView = class {
12202
12664
  liveThinking = "";
12203
12665
  thinkingActive = false;
12204
12666
  constructor(initial) {
12205
- this.entries = [{ kind: "text", content: initial.join("\n") }];
12667
+ this.entries = initial.length ? [{ kind: "text", content: initial.join("\n") }] : [];
12668
+ }
12669
+ addComponent(component) {
12670
+ this.entries.push({ kind: "component", component });
12206
12671
  }
12207
12672
  addText(content) {
12208
12673
  this.entries.push({ kind: "text", content });
@@ -12277,7 +12742,7 @@ var ConversationView = class {
12277
12742
  this.entries.splice(1, this.entries.length - 240);
12278
12743
  }
12279
12744
  render(width) {
12280
- const rendered = this.entries.flatMap((entry) => entry.kind === "markdown" ? [...new Markdown(entry.content, 2, 0, markdownTheme).render(width), ""] : entry.kind === "user" ? renderUserMessage(entry.content, width) : entry.kind === "thinking" ? [tuiTheme.muted(" thinking"), ...new Markdown(entry.content, 2, 0, markdownTheme, { color: tuiTheme.muted, italic: true }).render(width), ""] : entry.kind === "tool" ? new Text(toolActivityLine(entry), 2, 0).render(width) : new Text(entry.content, 2, 0).render(width));
12745
+ const rendered = this.entries.flatMap((entry) => entry.kind === "component" ? entry.component.render(width) : entry.kind === "markdown" ? [...new Markdown(entry.content, 2, 0, markdownTheme).render(width), ""] : entry.kind === "user" ? renderUserMessage(entry.content, width) : entry.kind === "thinking" ? [tuiTheme.muted(" thinking"), ...new Markdown(entry.content, 2, 0, markdownTheme, { color: tuiTheme.muted, italic: true }).render(width), ""] : entry.kind === "tool" ? new Text(toolActivityLine(entry), 2, 0).render(width) : new Text(entry.content, 2, 0).render(width));
12281
12746
  if (this.liveThinking)
12282
12747
  rendered.push(tuiTheme.muted(" thinking"), ...new Markdown(this.liveThinking, 2, 0, markdownTheme, { color: tuiTheme.muted, italic: true }).render(width));
12283
12748
  else if (this.thinkingActive)
@@ -12289,6 +12754,48 @@ var ConversationView = class {
12289
12754
  invalidate() {
12290
12755
  }
12291
12756
  };
12757
+ var WelcomeLockup = class {
12758
+ mark;
12759
+ details;
12760
+ horizontal;
12761
+ constructor(snapshot, hasHistory, imageData = null) {
12762
+ this.mark = imageData ? new Image(imageData, "image/png", { fallbackColor: tuiTheme.accent }, { maxWidthCells: 10, maxHeightCells: 5, filename: "Goah" }) : new Text(GOAH_TERMINAL_MARK.map((line) => tuiTheme.accent(line)).join("\n"), 0, 0);
12763
+ const lines = [
12764
+ tuiTheme.strong(hasHistory ? "Welcome back." : "Ready when you are."),
12765
+ `${tuiTheme.accent(snapshot.target)} ${tuiTheme.muted(`\xB7 ${snapshot.runner}`)}`
12766
+ ];
12767
+ if (!snapshot.root)
12768
+ lines.push(tuiTheme.muted("Chat normally \xB7 /goal for durable work \xB7 /help"));
12769
+ if (snapshot.team.length)
12770
+ lines.push(tuiTheme.muted(`${snapshot.team.length} Goal Agent${snapshot.team.length === 1 ? "" : "s"} in the organization`));
12771
+ this.details = new Text(lines.join("\n"), 0, 0);
12772
+ this.horizontal = new HStack([
12773
+ { component: this.mark, basis: 14, shrink: 0 },
12774
+ { component: this.details, grow: 1, minSize: 24 }
12775
+ ], { gap: 2, align: "center" });
12776
+ }
12777
+ render(width) {
12778
+ const contentWidth = Math.max(1, width - 4);
12779
+ if (width < 58) {
12780
+ return ["", ...this.mark.render(Math.min(14, contentWidth)).map((line) => ` ${line}`), "", ...this.details.render(contentWidth).map((line) => ` ${line}`), ""];
12781
+ }
12782
+ return ["", ...this.horizontal.render(contentWidth).map((line) => ` ${line}`), ""];
12783
+ }
12784
+ invalidate() {
12785
+ this.mark.invalidate();
12786
+ this.details.invalidate();
12787
+ this.horizontal.invalidate();
12788
+ }
12789
+ };
12790
+ function terminalLogoData() {
12791
+ if (getCapabilities().images !== "kitty")
12792
+ return null;
12793
+ try {
12794
+ return readFileSync2(new URL("./console/goah-orbital-mark.png", import.meta.url)).toString("base64");
12795
+ } catch {
12796
+ return null;
12797
+ }
12798
+ }
12292
12799
  var StreamCoordinator = class {
12293
12800
  #active = null;
12294
12801
  #pending = null;
@@ -12402,7 +12909,7 @@ function renderTuiCommandHelp() {
12402
12909
  return [tuiTheme.strong("Commands"), ...TUI_COMMANDS.map((command) => {
12403
12910
  const invocation = `/${command.name}${command.argumentHint ? ` ${command.argumentHint}` : ""}`;
12404
12911
  return ` ${invocation.padEnd(28)} ${tuiTheme.muted(command.description ?? "")}`;
12405
- }), ""].join("\n");
12912
+ }), "", tuiTheme.strong("Keyboard"), ` ${"Ctrl+C".padEnd(28)} ${tuiTheme.muted("Clear input \xB7 interrupt current Turn \xB7 exit when idle")}`, ` ${"Ctrl+D".padEnd(28)} ${tuiTheme.muted("Exit when idle")}`, ""].join("\n");
12406
12913
  }
12407
12914
  function classifyTuiInput(value, busy) {
12408
12915
  const text = value.trim();
@@ -12418,12 +12925,24 @@ function classifyTuiInput(value, busy) {
12418
12925
  return { action: "unknown", text };
12419
12926
  return { action: busy ? "steer" : "send", text };
12420
12927
  }
12928
+ function classifyTuiControlKey(data, inputText, busy) {
12929
+ if (isKeyRelease(data))
12930
+ return "forward";
12931
+ if (matchesKey(data, Key.ctrl("c"))) {
12932
+ if (inputText.length > 0)
12933
+ return "clear";
12934
+ return busy ? "interrupt" : "exit";
12935
+ }
12936
+ if (matchesKey(data, Key.ctrl("d")) && !inputText && !busy)
12937
+ return "exit";
12938
+ return "forward";
12939
+ }
12421
12940
  async function runGoahTui(configPath, stateDir, initialMessage) {
12422
12941
  if (!process.stdout.isTTY || !process.stdin.isTTY)
12423
12942
  return runNonInteractive(configPath, stateDir, initialMessage);
12424
12943
  const runner = readRunnerDisplay(configPath);
12425
12944
  const snapshot = welcomeSnapshot(stateDir, runner);
12426
- const welcome = renderWelcome(snapshot, Boolean(snapshot.root || snapshot.handoffs.length || snapshot.conversation.length));
12945
+ const hasHistory = Boolean(snapshot.root || snapshot.handoffs.length || snapshot.conversation.length);
12427
12946
  await ensureDaemon(configPath, stateDir);
12428
12947
  const liveSnapshot = await requestControl(stateDir, { op: "status" }).catch(() => null);
12429
12948
  const liveTurns = liveSnapshot && typeof liveSnapshot === "object" && !Array.isArray(liveSnapshot) && Array.isArray(liveSnapshot.turns) ? liveSnapshot.turns : [];
@@ -12432,7 +12951,8 @@ async function runGoahTui(configPath, stateDir, initialMessage) {
12432
12951
  const tui = new TuiAltScreen(terminal, true, void 0, { mouse: true });
12433
12952
  terminal.setTitle(`Goah \xB7 ${runner.target}`);
12434
12953
  const headerView = new HeaderBar(runner.runner, runner.target, installedVersion());
12435
- const transcriptView = new ConversationView(welcome);
12954
+ const transcriptView = new ConversationView([]);
12955
+ transcriptView.addComponent(new WelcomeLockup(snapshot, hasHistory, terminalLogoData()));
12436
12956
  for (const row of snapshot.conversation)
12437
12957
  if (row.speaker === "You")
12438
12958
  transcriptView.addUser(row.text);
@@ -12461,6 +12981,7 @@ async function runGoahTui(configPath, stateDir, initialMessage) {
12461
12981
  let steeringTail = Promise.resolve();
12462
12982
  let configuring = false;
12463
12983
  let exiting = false;
12984
+ let interrupting = false;
12464
12985
  const push = (line) => {
12465
12986
  transcriptView.addText(line);
12466
12987
  tui.requestRender();
@@ -12493,6 +13014,7 @@ async function runGoahTui(configPath, stateDir, initialMessage) {
12493
13014
  };
12494
13015
  const finishIdle = async () => {
12495
13016
  busy.active = false;
13017
+ interrupting = false;
12496
13018
  await refreshGoalBar(stateDir, goalView, tui);
12497
13019
  statusView.setText(statusText(queuedTurnIds.length || queued.length ? "queued" : "ready", queuedTurnIds.length + queued.length));
12498
13020
  continuePending();
@@ -12608,6 +13130,7 @@ async function runGoahTui(configPath, stateDir, initialMessage) {
12608
13130
  if (!streams.complete(controller))
12609
13131
  return;
12610
13132
  busy.active = false;
13133
+ interrupting = false;
12611
13134
  await refreshGoalBar(stateDir, goalView, tui);
12612
13135
  statusView.setText(statusText("ready"));
12613
13136
  continuePending();
@@ -12796,10 +13319,22 @@ async function runGoahTui(configPath, stateDir, initialMessage) {
12796
13319
  tui.setFocus(input);
12797
13320
  const { promise: exited, resolve: resolveExit } = Promise.withResolvers();
12798
13321
  tui.addInputListener((data) => {
12799
- if (data !== "")
13322
+ const action = classifyTuiControlKey(data, input.getText(), busy.active);
13323
+ if (action === "forward")
12800
13324
  return void 0;
13325
+ if (action === "clear") {
13326
+ input.setText("");
13327
+ tui.requestRender();
13328
+ return { consume: true };
13329
+ }
13330
+ if (action === "interrupt" && !interrupting) {
13331
+ interrupting = true;
13332
+ statusView.setText(`${tuiTheme.warning("stopping")} ${tuiTheme.muted("press Ctrl+C again to exit")}`);
13333
+ tui.requestRender();
13334
+ void stopCeoWake(stateDir, push);
13335
+ return { consume: true };
13336
+ }
12801
13337
  exiting = true;
12802
- push(busy.active ? "Detached \u2014 the current Turn continues in the daemon. Use /stop before detaching when you intend to cancel it." : "Detached.");
12803
13338
  streams.abortAll();
12804
13339
  tui.stop();
12805
13340
  resolveExit();
@@ -13725,7 +14260,7 @@ async function runRunnerManagement(config, configPath) {
13725
14260
  throw new Error("usage: goah runner profile assign AGENT PROFILE");
13726
14261
  if (!config.runnerProfiles?.some((profile) => profile.id === profileId))
13727
14262
  throw new Error(`Runner Profile not found: ${profileId}`);
13728
- const raw = JSON.parse(readFileSync2(resolve3(configPath), "utf8"));
14263
+ const raw = JSON.parse(readFileSync3(resolve3(configPath), "utf8"));
13729
14264
  const target = raw.profiles?.find((profile) => profile.agent === agent);
13730
14265
  if (!target)
13731
14266
  throw new Error(`Agent profile not found: ${agent}`);
@@ -13771,7 +14306,7 @@ async function runDaemonCommand(config, configPath) {
13771
14306
  console.log(`No daemon log at ${path4}`);
13772
14307
  return;
13773
14308
  }
13774
- console.log(readFileSync2(path4, "utf8").split("\n").slice(-100).join("\n"));
14309
+ console.log(readFileSync3(path4, "utf8").split("\n").slice(-100).join("\n"));
13775
14310
  return;
13776
14311
  }
13777
14312
  if (action === "stop" || action === "restart") {
@@ -13804,7 +14339,7 @@ function stdioInteraction() {
13804
14339
  };
13805
14340
  }
13806
14341
  function packageVersion() {
13807
- return JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8")).version;
14342
+ return JSON.parse(readFileSync3(new URL("../package.json", import.meta.url), "utf8")).version;
13808
14343
  }
13809
14344
  function closestCommand(value) {
13810
14345
  let best = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goah/cli",
3
- "version": "0.13.2",
3
+ "version": "0.13.3",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",