kfc-code-cli 0.0.1-alpha.17 → 0.0.1-alpha.18

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/main.mjs +798 -309
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -5,7 +5,7 @@ import { createRequire } from "node:module";
5
5
  import { Command, Option } from "commander";
6
6
  import * as nodeFs from "node:fs";
7
7
  import Vt, { chmodSync, closeSync, constants, createReadStream, createWriteStream, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
8
- import jn, { access, appendFile, chmod, lstat, mkdir, mkdtemp, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
8
+ import fs, { access, appendFile, chmod, lstat, mkdir, mkdtemp, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
9
9
  import * as path$2 from "node:path";
10
10
  import path, { basename, dirname, extname, isAbsolute, join, normalize, posix, relative, resolve, sep, win32 } from "node:path";
11
11
  import { finished, pipeline } from "node:stream/promises";
@@ -29,7 +29,7 @@ import * as ks from "zlib";
29
29
  import qr from "zlib";
30
30
  import so from "node:assert";
31
31
  import { parse as parse$1, stringify } from "smol-toml";
32
- import * as fs$1 from "fs/promises";
32
+ import * as fs$2 from "fs/promises";
33
33
  import { writeFile as writeFile$1 } from "fs/promises";
34
34
  import { AsyncLocalStorage } from "node:async_hooks";
35
35
  import { ZipFile } from "yazl";
@@ -23912,7 +23912,7 @@ const IMAGE_MIME_BY_SUFFIX = Object.freeze({
23912
23912
  ".avif": "image/avif",
23913
23913
  ".svgz": "image/svg+xml"
23914
23914
  });
23915
- const VIDEO_MIME_BY_SUFFIX = Object.freeze({
23915
+ const VIDEO_MIME_BY_SUFFIX$1 = Object.freeze({
23916
23916
  ".mp4": "video/mp4",
23917
23917
  ".mpg": "video/mpeg",
23918
23918
  ".mpeg": "video/mpeg",
@@ -24183,9 +24183,9 @@ function detectFileType(path, header) {
24183
24183
  kind: "image",
24184
24184
  mimeType: IMAGE_MIME_BY_SUFFIX[suffix]
24185
24185
  };
24186
- else if (suffix in VIDEO_MIME_BY_SUFFIX) mediaHint = {
24186
+ else if (suffix in VIDEO_MIME_BY_SUFFIX$1) mediaHint = {
24187
24187
  kind: "video",
24188
- mimeType: VIDEO_MIME_BY_SUFFIX[suffix]
24188
+ mimeType: VIDEO_MIME_BY_SUFFIX$1[suffix]
24189
24189
  };
24190
24190
  if (header !== void 0) {
24191
24191
  const buf = toBuffer(header);
@@ -27313,7 +27313,7 @@ K(Un, Hn, Wn, Gn, (s, t) => {
27313
27313
  if (!t?.length) throw new TypeError("no paths specified to add to archive");
27314
27314
  });
27315
27315
  var fr = (process.env.__FAKE_PLATFORM__ || process.platform) === "win32", { O_CREAT: dr, O_NOFOLLOW: ar, O_TRUNC: ur, O_WRONLY: mr } = I.constants, pr = Number(process.env.__FAKE_FS_O_FILENAME__) || I.constants.UV_FS_O_FILEMAP || 0, Kn = fr && !!pr, Vn = 512 * 1024, $n = pr | ur | dr | mr, lr = !fr && typeof ar == "number" ? ar | ur | dr | mr : null, cs = lr !== null ? () => lr : Kn ? (s) => s < Vn ? $n : "w" : () => "w";
27316
- var fs$12 = (s, t, e) => {
27316
+ var fs$13 = (s, t, e) => {
27317
27317
  try {
27318
27318
  return Vt.lchownSync(s, t, e);
27319
27319
  } catch (i) {
@@ -27345,7 +27345,7 @@ var fs$12 = (s, t, e) => {
27345
27345
  for (let l of n) Xn(s, l, t, e, a);
27346
27346
  });
27347
27347
  }, qn = (s, t, e, i) => {
27348
- t.isDirectory() && us(path.resolve(s, t.name), e, i), fs$12(path.resolve(s, t.name), e, i);
27348
+ t.isDirectory() && us(path.resolve(s, t.name), e, i), fs$13(path.resolve(s, t.name), e, i);
27349
27349
  }, us = (s, t, e) => {
27350
27350
  let i;
27351
27351
  try {
@@ -27353,11 +27353,11 @@ var fs$12 = (s, t, e) => {
27353
27353
  } catch (r) {
27354
27354
  let n = r;
27355
27355
  if (n?.code === "ENOENT") return;
27356
- if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP") return fs$12(s, t, e);
27356
+ if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP") return fs$13(s, t, e);
27357
27357
  throw n;
27358
27358
  }
27359
27359
  for (let r of i) qn(s, r, t, e);
27360
- return fs$12(s, t, e);
27360
+ return fs$13(s, t, e);
27361
27361
  };
27362
27362
  var we = class extends Error {
27363
27363
  path;
@@ -27392,7 +27392,7 @@ var Qn = (s, t) => {
27392
27392
  E ? e(E) : x && a ? ds(x, o, h, (xe) => S(xe)) : n ? Vt.chmod(s, r, e) : e();
27393
27393
  };
27394
27394
  if (s === d) return Qn(s, S);
27395
- if (l) return jn.mkdir(s, {
27395
+ if (l) return fs.mkdir(s, {
27396
27396
  mode: r,
27397
27397
  recursive: !0
27398
27398
  }).then((E) => S(null, E ?? void 0), S);
@@ -28151,7 +28151,7 @@ var require_pend = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28151
28151
  //#endregion
28152
28152
  //#region ../../node_modules/.pnpm/yauzl@3.3.0/node_modules/yauzl/fd-slicer.js
28153
28153
  var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28154
- var fs$11 = __require("fs");
28154
+ var fs$12 = __require("fs");
28155
28155
  var util$7 = __require("util");
28156
28156
  var stream$4 = __require("stream");
28157
28157
  var Readable = stream$4.Readable;
@@ -28176,7 +28176,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28176
28176
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
28177
28177
  var self = this;
28178
28178
  self.pend.go(function(cb) {
28179
- fs$11.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
28179
+ fs$12.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
28180
28180
  cb();
28181
28181
  callback(err, bytesRead, buffer);
28182
28182
  });
@@ -28185,7 +28185,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28185
28185
  FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
28186
28186
  var self = this;
28187
28187
  self.pend.go(function(cb) {
28188
- fs$11.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
28188
+ fs$12.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
28189
28189
  cb();
28190
28190
  callback(err, written, buffer);
28191
28191
  });
@@ -28205,7 +28205,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28205
28205
  self.refCount -= 1;
28206
28206
  if (self.refCount > 0) return;
28207
28207
  if (self.refCount < 0) throw new Error("invalid unref");
28208
- if (self.autoClose) fs$11.close(self.fd, onCloseDone);
28208
+ if (self.autoClose) fs$12.close(self.fd, onCloseDone);
28209
28209
  function onCloseDone(err) {
28210
28210
  if (err) self.emit("error", err);
28211
28211
  else self.emit("close");
@@ -28236,7 +28236,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28236
28236
  self.context.pend.go(function(cb) {
28237
28237
  if (self.destroyed) return cb();
28238
28238
  var buffer = Buffer.allocUnsafe(toRead);
28239
- fs$11.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
28239
+ fs$12.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
28240
28240
  if (err) self.destroy(err);
28241
28241
  else if (bytesRead === 0) {
28242
28242
  self.destroyed = true;
@@ -28282,7 +28282,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
28282
28282
  }
28283
28283
  self.context.pend.go(function(cb) {
28284
28284
  if (self.destroyed) return cb();
28285
- fs$11.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) {
28285
+ fs$12.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) {
28286
28286
  if (err) {
28287
28287
  self.destroy();
28288
28288
  cb();
@@ -40102,7 +40102,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40102
40102
  };
40103
40103
  return _setPrototypeOf(o, p);
40104
40104
  }
40105
- var fs$9 = __require("fs");
40105
+ var fs$10 = __require("fs");
40106
40106
  var path$10 = __require("path");
40107
40107
  var Loader = require_loader();
40108
40108
  var PrecompiledLoader = require_precompiled_loader().PrecompiledLoader;
@@ -40126,7 +40126,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40126
40126
  } catch (e) {
40127
40127
  throw new Error("watch requires chokidar to be installed");
40128
40128
  }
40129
- var paths = _this.searchPaths.filter(fs$9.existsSync);
40129
+ var paths = _this.searchPaths.filter(fs$10.existsSync);
40130
40130
  var watcher = chokidar.watch(paths);
40131
40131
  watcher.on("all", function(event, fullname) {
40132
40132
  fullname = path$10.resolve(fullname);
@@ -40145,7 +40145,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40145
40145
  for (var i = 0; i < paths.length; i++) {
40146
40146
  var basePath = path$10.resolve(paths[i]);
40147
40147
  var p = path$10.resolve(paths[i], name);
40148
- if (p.indexOf(basePath) === 0 && fs$9.existsSync(p)) {
40148
+ if (p.indexOf(basePath) === 0 && fs$10.existsSync(p)) {
40149
40149
  fullpath = p;
40150
40150
  break;
40151
40151
  }
@@ -40153,7 +40153,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40153
40153
  if (!fullpath) return null;
40154
40154
  this.pathsToNames[fullpath] = name;
40155
40155
  var source = {
40156
- src: fs$9.readFileSync(fullpath, "utf-8"),
40156
+ src: fs$10.readFileSync(fullpath, "utf-8"),
40157
40157
  path: fullpath,
40158
40158
  noCache: this.noCache
40159
40159
  };
@@ -40201,7 +40201,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40201
40201
  }
40202
40202
  this.pathsToNames[fullpath] = name;
40203
40203
  var source = {
40204
- src: fs$9.readFileSync(fullpath, "utf-8"),
40204
+ src: fs$10.readFileSync(fullpath, "utf-8"),
40205
40205
  path: fullpath,
40206
40206
  noCache: this.noCache
40207
40207
  };
@@ -40945,7 +40945,7 @@ var require_precompile_global = /* @__PURE__ */ __commonJSMin(((exports, module)
40945
40945
  //#endregion
40946
40946
  //#region ../../node_modules/.pnpm/nunjucks@3.2.4/node_modules/nunjucks/src/precompile.js
40947
40947
  var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40948
- var fs$8 = __require("fs");
40948
+ var fs$9 = __require("fs");
40949
40949
  var path$8 = __require("path");
40950
40950
  var _prettifyError = require_lib$1()._prettifyError;
40951
40951
  var compiler = require_compiler();
@@ -40970,27 +40970,27 @@ var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40970
40970
  var env = opts.env || new Environment([]);
40971
40971
  var wrapper = opts.wrapper || precompileGlobal;
40972
40972
  if (opts.isString) return precompileString(input, opts);
40973
- var pathStats = fs$8.existsSync(input) && fs$8.statSync(input);
40973
+ var pathStats = fs$9.existsSync(input) && fs$9.statSync(input);
40974
40974
  var precompiled = [];
40975
40975
  var templates = [];
40976
40976
  function addTemplates(dir) {
40977
- fs$8.readdirSync(dir).forEach(function(file) {
40977
+ fs$9.readdirSync(dir).forEach(function(file) {
40978
40978
  var filepath = path$8.join(dir, file);
40979
40979
  var subpath = filepath.substr(path$8.join(input, "/").length);
40980
- var stat = fs$8.statSync(filepath);
40980
+ var stat = fs$9.statSync(filepath);
40981
40981
  if (stat && stat.isDirectory()) {
40982
40982
  subpath += "/";
40983
40983
  if (!match(subpath, opts.exclude)) addTemplates(filepath);
40984
40984
  } else if (match(subpath, opts.include)) templates.push(filepath);
40985
40985
  });
40986
40986
  }
40987
- if (pathStats.isFile()) precompiled.push(_precompile(fs$8.readFileSync(input, "utf-8"), opts.name || input, env));
40987
+ if (pathStats.isFile()) precompiled.push(_precompile(fs$9.readFileSync(input, "utf-8"), opts.name || input, env));
40988
40988
  else if (pathStats.isDirectory()) {
40989
40989
  addTemplates(input);
40990
40990
  for (var i = 0; i < templates.length; i++) {
40991
40991
  var name = templates[i].replace(path$8.join(input, "/"), "");
40992
40992
  try {
40993
- precompiled.push(_precompile(fs$8.readFileSync(templates[i], "utf-8"), name, env));
40993
+ precompiled.push(_precompile(fs$9.readFileSync(templates[i], "utf-8"), name, env));
40994
40994
  } catch (e) {
40995
40995
  if (opts.force) console.error(e);
40996
40996
  else throw e;
@@ -52227,7 +52227,7 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
52227
52227
  exports.removeUndefinedValuesInObject = removeUndefinedValuesInObject;
52228
52228
  exports.isValidFile = isValidFile;
52229
52229
  exports.getWellKnownCertificateConfigFileLocation = getWellKnownCertificateConfigFileLocation;
52230
- const fs$7 = __require("fs");
52230
+ const fs$8 = __require("fs");
52231
52231
  const os$1 = __require("os");
52232
52232
  const path$6 = __require("path");
52233
52233
  const WELL_KNOWN_CERTIFICATE_CONFIG_FILE = "certificate_config.json";
@@ -52347,7 +52347,7 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
52347
52347
  */
52348
52348
  async function isValidFile(filePath) {
52349
52349
  try {
52350
- return (await fs$7.promises.lstat(filePath)).isFile();
52350
+ return (await fs$8.promises.lstat(filePath)).isFile();
52351
52351
  } catch (e) {
52352
52352
  return false;
52353
52353
  }
@@ -54060,10 +54060,10 @@ var require_getCredentials = /* @__PURE__ */ __commonJSMin(((exports) => {
54060
54060
  Object.defineProperty(exports, "__esModule", { value: true });
54061
54061
  exports.getCredentials = getCredentials;
54062
54062
  const path$5 = __require("path");
54063
- const fs$6 = __require("fs");
54063
+ const fs$7 = __require("fs");
54064
54064
  const util_1$1 = __require("util");
54065
54065
  const errorWithCode_1 = require_errorWithCode();
54066
- const readFile = fs$6.readFile ? (0, util_1$1.promisify)(fs$6.readFile) : async () => {
54066
+ const readFile = fs$7.readFile ? (0, util_1$1.promisify)(fs$7.readFile) : async () => {
54067
54067
  throw new errorWithCode_1.ErrorWithCode("use key rather than keyFile.", "MISSING_CREDENTIALS");
54068
54068
  };
54069
54069
  var ExtensionFiles;
@@ -55610,10 +55610,10 @@ var require_filesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((exports)
55610
55610
  Object.defineProperty(exports, "__esModule", { value: true });
55611
55611
  exports.FileSubjectTokenSupplier = void 0;
55612
55612
  const util_1 = __require("util");
55613
- const fs$5 = __require("fs");
55614
- const readFile = (0, util_1.promisify)(fs$5.readFile ?? (() => {}));
55615
- const realpath = (0, util_1.promisify)(fs$5.realpath ?? (() => {}));
55616
- const lstat = (0, util_1.promisify)(fs$5.lstat ?? (() => {}));
55613
+ const fs$6 = __require("fs");
55614
+ const readFile = (0, util_1.promisify)(fs$6.readFile ?? (() => {}));
55615
+ const realpath = (0, util_1.promisify)(fs$6.realpath ?? (() => {}));
55616
+ const lstat = (0, util_1.promisify)(fs$6.lstat ?? (() => {}));
55617
55617
  /**
55618
55618
  * Internal subject token supplier implementation used when a file location
55619
55619
  * is configured in the credential configuration used to build an {@link IdentityPoolClient}
@@ -55715,7 +55715,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
55715
55715
  Object.defineProperty(exports, "__esModule", { value: true });
55716
55716
  exports.CertificateSubjectTokenSupplier = exports.InvalidConfigurationError = exports.CertificateSourceUnavailableError = exports.CERTIFICATE_CONFIGURATION_ENV_VARIABLE = void 0;
55717
55717
  const util_1 = require_util();
55718
- const fs$4 = __require("fs");
55718
+ const fs$5 = __require("fs");
55719
55719
  const crypto_1 = __require("crypto");
55720
55720
  const https$1 = __require("https");
55721
55721
  exports.CERTIFICATE_CONFIGURATION_ENV_VARIABLE = "GOOGLE_API_CERTIFICATE_CONFIG";
@@ -55810,7 +55810,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
55810
55810
  const configPath = this.certificateConfigPath;
55811
55811
  let fileContents;
55812
55812
  try {
55813
- fileContents = await fs$4.promises.readFile(configPath, "utf8");
55813
+ fileContents = await fs$5.promises.readFile(configPath, "utf8");
55814
55814
  } catch (err) {
55815
55815
  throw new CertificateSourceUnavailableError(`Failed to read certificate config file at: ${configPath}`);
55816
55816
  }
@@ -55835,13 +55835,13 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
55835
55835
  async #getKeyAndCert(certPath, keyPath) {
55836
55836
  let cert, key;
55837
55837
  try {
55838
- cert = await fs$4.promises.readFile(certPath);
55838
+ cert = await fs$5.promises.readFile(certPath);
55839
55839
  new crypto_1.X509Certificate(cert);
55840
55840
  } catch (err) {
55841
55841
  throw new CertificateSourceUnavailableError(`Failed to read certificate file at ${certPath}: ${err instanceof Error ? err.message : String(err)}`);
55842
55842
  }
55843
55843
  try {
55844
- key = await fs$4.promises.readFile(keyPath);
55844
+ key = await fs$5.promises.readFile(keyPath);
55845
55845
  (0, crypto_1.createPrivateKey)(key);
55846
55846
  } catch (err) {
55847
55847
  throw new CertificateSourceUnavailableError(`Failed to read private key file at ${keyPath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -55860,7 +55860,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
55860
55860
  const leafCert = new crypto_1.X509Certificate(leafCertBuffer);
55861
55861
  if (!this.trustChainPath) return JSON.stringify([leafCert.raw.toString("base64")]);
55862
55862
  try {
55863
- const chainCerts = ((await fs$4.promises.readFile(this.trustChainPath, "utf8")).match(/-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----/g) ?? []).map((pem, index) => {
55863
+ const chainCerts = ((await fs$5.promises.readFile(this.trustChainPath, "utf8")).match(/-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----/g) ?? []).map((pem, index) => {
55864
55864
  try {
55865
55865
  return new crypto_1.X509Certificate(pem);
55866
55866
  } catch (err) {
@@ -56520,7 +56520,7 @@ var require_pluggable_auth_handler = /* @__PURE__ */ __commonJSMin(((exports) =>
56520
56520
  exports.PluggableAuthHandler = exports.ExecutableError = void 0;
56521
56521
  const executable_response_1 = require_executable_response();
56522
56522
  const childProcess = __require("child_process");
56523
- const fs$3 = __require("fs");
56523
+ const fs$4 = __require("fs");
56524
56524
  /**
56525
56525
  * Error thrown from the executable run by PluggableAuthClient.
56526
56526
  */
@@ -56597,12 +56597,12 @@ var require_pluggable_auth_handler = /* @__PURE__ */ __commonJSMin(((exports) =>
56597
56597
  if (!this.outputFile || this.outputFile.length === 0) return;
56598
56598
  let filePath;
56599
56599
  try {
56600
- filePath = await fs$3.promises.realpath(this.outputFile);
56600
+ filePath = await fs$4.promises.realpath(this.outputFile);
56601
56601
  } catch {
56602
56602
  return;
56603
56603
  }
56604
- if (!(await fs$3.promises.lstat(filePath)).isFile()) return;
56605
- const responseString = await fs$3.promises.readFile(filePath, { encoding: "utf8" });
56604
+ if (!(await fs$4.promises.lstat(filePath)).isFile()) return;
56605
+ const responseString = await fs$4.promises.readFile(filePath, { encoding: "utf8" });
56606
56606
  if (responseString === "") return;
56607
56607
  try {
56608
56608
  const responseJson = JSON.parse(responseString);
@@ -57024,7 +57024,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
57024
57024
  Object.defineProperty(exports, "__esModule", { value: true });
57025
57025
  exports.GoogleAuth = exports.GoogleAuthExceptionMessages = void 0;
57026
57026
  const child_process_1 = __require("child_process");
57027
- const fs$2 = __require("fs");
57027
+ const fs$3 = __require("fs");
57028
57028
  const gaxios_1 = require_src$3();
57029
57029
  const gcpMetadata = require_src$1();
57030
57030
  const os = __require("os");
@@ -57272,7 +57272,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
57272
57272
  }
57273
57273
  if (location) {
57274
57274
  location = path$4.join(location, "gcloud", "application_default_credentials.json");
57275
- if (!fs$2.existsSync(location)) location = null;
57275
+ if (!fs$3.existsSync(location)) location = null;
57276
57276
  }
57277
57277
  if (!location) return null;
57278
57278
  return await this._getApplicationCredentialsFromFilePath(location, options);
@@ -57286,13 +57286,13 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
57286
57286
  async _getApplicationCredentialsFromFilePath(filePath, options = {}) {
57287
57287
  if (!filePath || filePath.length === 0) throw new Error("The file path is invalid.");
57288
57288
  try {
57289
- filePath = fs$2.realpathSync(filePath);
57290
- if (!fs$2.lstatSync(filePath).isFile()) throw new Error();
57289
+ filePath = fs$3.realpathSync(filePath);
57290
+ if (!fs$3.lstatSync(filePath).isFile()) throw new Error();
57291
57291
  } catch (err) {
57292
57292
  if (err instanceof Error) err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`;
57293
57293
  throw err;
57294
57294
  }
57295
- const readStream = fs$2.createReadStream(filePath);
57295
+ const readStream = fs$3.createReadStream(filePath);
57296
57296
  return this.fromStream(readStream, options);
57297
57297
  }
57298
57298
  /**
@@ -57559,7 +57559,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
57559
57559
  if (this.jsonContent) return this._cacheClientFromJSON(this.jsonContent, this.clientOptions);
57560
57560
  else if (this.keyFilename) {
57561
57561
  const filePath = path$4.resolve(this.keyFilename);
57562
- const stream = fs$2.createReadStream(filePath);
57562
+ const stream = fs$3.createReadStream(filePath);
57563
57563
  return await this.fromStreamAsync(stream, this.clientOptions);
57564
57564
  } else if (this.apiKey) {
57565
57565
  const client = await this.fromAPIKey(this.apiKey, this.clientOptions);
@@ -76069,7 +76069,7 @@ var NodeUploader = class {
76069
76069
  type: void 0
76070
76070
  };
76071
76071
  if (typeof file === "string") {
76072
- fileStat.size = (await fs$1.stat(file)).size;
76072
+ fileStat.size = (await fs$2.stat(file)).size;
76073
76073
  fileStat.type = this.inferMimeType(file);
76074
76074
  return fileStat;
76075
76075
  } else return await getBlobStat(file);
@@ -76202,7 +76202,7 @@ var NodeUploader = class {
76202
76202
  let fileHandle;
76203
76203
  const fileName = path$1$1.basename(file);
76204
76204
  try {
76205
- fileHandle = await fs$1.open(file, "r");
76205
+ fileHandle = await fs$2.open(file, "r");
76206
76206
  if (!fileHandle) throw new Error(`Failed to open file`);
76207
76207
  fileSize = (await fileHandle.stat()).size;
76208
76208
  while (offset < fileSize) {
@@ -92506,7 +92506,7 @@ var require_clone = /* @__PURE__ */ __commonJSMin(((exports, module) => {
92506
92506
  //#endregion
92507
92507
  //#region ../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js
92508
92508
  var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
92509
- var fs = __require("fs");
92509
+ var fs$1 = __require("fs");
92510
92510
  var polyfills = require_polyfills();
92511
92511
  var legacy = require_legacy_streams();
92512
92512
  var clone = require_clone();
@@ -92535,36 +92535,36 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
92535
92535
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
92536
92536
  console.error(m);
92537
92537
  };
92538
- if (!fs[gracefulQueue]) {
92539
- publishQueue(fs, global[gracefulQueue] || []);
92540
- fs.close = (function(fs$close) {
92538
+ if (!fs$1[gracefulQueue]) {
92539
+ publishQueue(fs$1, global[gracefulQueue] || []);
92540
+ fs$1.close = (function(fs$close) {
92541
92541
  function close(fd, cb) {
92542
- return fs$close.call(fs, fd, function(err) {
92542
+ return fs$close.call(fs$1, fd, function(err) {
92543
92543
  if (!err) resetQueue();
92544
92544
  if (typeof cb === "function") cb.apply(this, arguments);
92545
92545
  });
92546
92546
  }
92547
92547
  Object.defineProperty(close, previousSymbol, { value: fs$close });
92548
92548
  return close;
92549
- })(fs.close);
92550
- fs.closeSync = (function(fs$closeSync) {
92549
+ })(fs$1.close);
92550
+ fs$1.closeSync = (function(fs$closeSync) {
92551
92551
  function closeSync(fd) {
92552
- fs$closeSync.apply(fs, arguments);
92552
+ fs$closeSync.apply(fs$1, arguments);
92553
92553
  resetQueue();
92554
92554
  }
92555
92555
  Object.defineProperty(closeSync, previousSymbol, { value: fs$closeSync });
92556
92556
  return closeSync;
92557
- })(fs.closeSync);
92557
+ })(fs$1.closeSync);
92558
92558
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) process.on("exit", function() {
92559
- debug(fs[gracefulQueue]);
92560
- __require("assert").equal(fs[gracefulQueue].length, 0);
92559
+ debug(fs$1[gracefulQueue]);
92560
+ __require("assert").equal(fs$1[gracefulQueue].length, 0);
92561
92561
  });
92562
92562
  }
92563
- if (!global[gracefulQueue]) publishQueue(global, fs[gracefulQueue]);
92564
- module.exports = patch(clone(fs));
92565
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
92566
- module.exports = patch(fs);
92567
- fs.__patched = true;
92563
+ if (!global[gracefulQueue]) publishQueue(global, fs$1[gracefulQueue]);
92564
+ module.exports = patch(clone(fs$1));
92565
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs$1.__patched) {
92566
+ module.exports = patch(fs$1);
92567
+ fs$1.__patched = true;
92568
92568
  }
92569
92569
  function patch(fs) {
92570
92570
  polyfills(fs);
@@ -92819,23 +92819,23 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
92819
92819
  }
92820
92820
  function enqueue(elem) {
92821
92821
  debug("ENQUEUE", elem[0].name, elem[1]);
92822
- fs[gracefulQueue].push(elem);
92822
+ fs$1[gracefulQueue].push(elem);
92823
92823
  retry();
92824
92824
  }
92825
92825
  var retryTimer;
92826
92826
  function resetQueue() {
92827
92827
  var now = Date.now();
92828
- for (var i = 0; i < fs[gracefulQueue].length; ++i) if (fs[gracefulQueue][i].length > 2) {
92829
- fs[gracefulQueue][i][3] = now;
92830
- fs[gracefulQueue][i][4] = now;
92828
+ for (var i = 0; i < fs$1[gracefulQueue].length; ++i) if (fs$1[gracefulQueue][i].length > 2) {
92829
+ fs$1[gracefulQueue][i][3] = now;
92830
+ fs$1[gracefulQueue][i][4] = now;
92831
92831
  }
92832
92832
  retry();
92833
92833
  }
92834
92834
  function retry() {
92835
92835
  clearTimeout(retryTimer);
92836
92836
  retryTimer = void 0;
92837
- if (fs[gracefulQueue].length === 0) return;
92838
- var elem = fs[gracefulQueue].shift();
92837
+ if (fs$1[gracefulQueue].length === 0) return;
92838
+ var elem = fs$1[gracefulQueue].shift();
92839
92839
  var fn = elem[0];
92840
92840
  var args = elem[1];
92841
92841
  var err = elem[2];
@@ -92854,7 +92854,7 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
92854
92854
  if (sinceAttempt >= Math.min(sinceStart * 1.2, 100)) {
92855
92855
  debug("RETRY", fn.name, args);
92856
92856
  fn.apply(null, args.concat([startTime]));
92857
- } else fs[gracefulQueue].push(elem);
92857
+ } else fs$1[gracefulQueue].push(elem);
92858
92858
  }
92859
92859
  if (retryTimer === void 0) retryTimer = setTimeout(retry, 0);
92860
92860
  }
@@ -95803,45 +95803,11 @@ function parseSlashInput(input) {
95803
95803
  };
95804
95804
  }
95805
95805
  //#endregion
95806
- //#region src/tui/components/media/image-thumbnail.ts
95807
- /**
95808
- * Transcript-side rendering of a pasted image.
95809
- *
95810
- * On terminals that speak the Kitty graphics protocol or iTerm2 inline
95811
- * image protocol (detected by pi-tui's `getCapabilities()`), we show
95812
- * the actual image. Everywhere else we fall back to a one-line text
95813
- * marker matching the placeholder the user sees in the input box —
95814
- * this keeps the transcript readable on Terminal.app / Linux default
95815
- * terminals / `script` recordings without extra chrome.
95816
- *
95817
- * Height is capped at ~12 rows so a single screenshot can't monopolize
95818
- * the viewport; pi-tui handles proportional scaling internally.
95819
- */
95820
- const MAX_IMAGE_ROWS = 12;
95821
- var ImageThumbnail = class extends Container {
95822
- constructor(attachment, colors) {
95823
- super();
95824
- const caps = getCapabilities();
95825
- if (!(caps.images === "kitty" || caps.images === "iterm2")) {
95826
- this.addChild(new Text(chalk.hex(colors.accent)(` ${attachment.placeholder}`), 0, 0));
95827
- return;
95828
- }
95829
- const image = new Image(Buffer.from(attachment.bytes).toString("base64"), attachment.mime, { fallbackColor: (s) => chalk.hex(colors.textDim)(s) }, {
95830
- maxHeightCells: MAX_IMAGE_ROWS,
95831
- filename: attachment.placeholder
95832
- }, {
95833
- widthPx: attachment.width,
95834
- heightPx: attachment.height
95835
- });
95836
- this.addChild(image);
95837
- }
95838
- };
95839
- //#endregion
95840
95806
  //#region src/tui/symbols.ts
95841
95807
  const STATUS_BULLET = "⏺︎ ";
95842
95808
  //#endregion
95843
95809
  //#region src/tui/components/messages/assistant-message.ts
95844
- const INDENT$1 = " ";
95810
+ const INDENT$2 = " ";
95845
95811
  var AssistantMessageComponent = class {
95846
95812
  contentContainer;
95847
95813
  markdownTheme;
@@ -95868,18 +95834,36 @@ var AssistantMessageComponent = class {
95868
95834
  }
95869
95835
  render(width) {
95870
95836
  if (this.lastText.trim().length === 0) return [];
95871
- const prefix = this.showBullet ? STATUS_BULLET : INDENT$1;
95837
+ const prefix = this.showBullet ? STATUS_BULLET : INDENT$2;
95872
95838
  const contentWidth = Math.max(1, width - visibleWidth(prefix));
95873
95839
  const contentLines = this.contentContainer.render(contentWidth);
95874
95840
  const lines = [""];
95875
95841
  for (let i = 0; i < contentLines.length; i++) {
95876
- const p = i === 0 && this.showBullet ? chalk.hex(this.bulletColor)(STATUS_BULLET) : INDENT$1;
95842
+ const p = i === 0 && this.showBullet ? chalk.hex(this.bulletColor)(STATUS_BULLET) : INDENT$2;
95877
95843
  lines.push(p + contentLines[i]);
95878
95844
  }
95879
95845
  return lines;
95880
95846
  }
95881
95847
  };
95882
95848
  //#endregion
95849
+ //#region src/tui/components/messages/background-agent-status.ts
95850
+ const INDENT$1 = " ";
95851
+ const FAIL_MARK = "✗ ";
95852
+ var BackgroundAgentStatusComponent = class {
95853
+ constructor(data, colors) {
95854
+ this.data = data;
95855
+ this.colors = colors;
95856
+ }
95857
+ invalidate() {}
95858
+ render(width) {
95859
+ const tone = this.data.phase === "started" ? this.colors.primary : this.data.phase === "completed" ? this.colors.success : this.colors.error;
95860
+ const bullet = this.data.phase === "failed" ? chalk.hex(tone)(FAIL_MARK) : chalk.hex(tone)(STATUS_BULLET);
95861
+ const textComponent = new Text(chalk.hex(tone)(this.data.headline) + (this.data.detail !== void 0 && this.data.detail.length > 0 ? chalk.hex(this.colors.textDim)(` (${this.data.detail})`) : ""), 0, 0);
95862
+ const contentWidth = Math.max(1, width - 2);
95863
+ return ["", ...textComponent.render(contentWidth).map((line, index) => (index === 0 ? bullet : INDENT$1) + line)];
95864
+ }
95865
+ };
95866
+ //#endregion
95883
95867
  //#region src/tui/components/messages/skill-activation.ts
95884
95868
  /**
95885
95869
  * Skill activation card.
@@ -97322,15 +97306,77 @@ function formatActivityLine(verb, toolName, args) {
97322
97306
  return keyArg ? `${verb} ${toolName} (${keyArg})` : `${verb} ${toolName}`;
97323
97307
  }
97324
97308
  //#endregion
97325
- //#region src/tui/components/messages/user-message.ts
97309
+ //#region src/tui/components/media/image-thumbnail.ts
97326
97310
  /**
97327
- * Renders a user message in the transcript.
97311
+ * Transcript-side rendering of a pasted image.
97312
+ *
97313
+ * On terminals that speak the Kitty graphics protocol or iTerm2 inline
97314
+ * image protocol (detected by pi-tui's `getCapabilities()`), we show
97315
+ * the actual image. Everywhere else we fall back to a one-line text
97316
+ * marker matching the placeholder the user sees in the input box —
97317
+ * this keeps the transcript readable on Terminal.app / Linux default
97318
+ * terminals / `script` recordings without extra chrome.
97319
+ *
97320
+ * Height is capped at ~12 rows so a single screenshot can't monopolize
97321
+ * the viewport; pi-tui handles proportional scaling internally.
97328
97322
  */
97329
- var UserMessageComponent = class extends Container {
97330
- constructor(text, colors) {
97323
+ const MAX_IMAGE_ROWS = 12;
97324
+ const MAX_IMAGE_WIDTH = 40;
97325
+ var ImageThumbnail = class extends Container {
97326
+ constructor(attachment, colors) {
97331
97327
  super();
97332
- this.addChild(new Spacer(1));
97333
- this.addChild(new Text(chalk.hex(colors.roleUser).bold("✨ " + text), 0, 0));
97328
+ const caps = getCapabilities();
97329
+ if (!(caps.images === "kitty" || caps.images === "iterm2")) {
97330
+ this.addChild(new Text(chalk.hex(colors.accent)(attachment.placeholder), 0, 0));
97331
+ return;
97332
+ }
97333
+ const image = new Image(Buffer.from(attachment.bytes).toString("base64"), attachment.mime, { fallbackColor: (s) => chalk.hex(colors.textDim)(s) }, {
97334
+ maxHeightCells: MAX_IMAGE_ROWS,
97335
+ maxWidthCells: MAX_IMAGE_WIDTH,
97336
+ filename: attachment.placeholder
97337
+ }, {
97338
+ widthPx: attachment.width,
97339
+ heightPx: attachment.height
97340
+ });
97341
+ this.addChild(image);
97342
+ }
97343
+ };
97344
+ //#endregion
97345
+ //#region src/tui/components/messages/user-message.ts
97346
+ const BULLET = "✨ ";
97347
+ var UserMessageComponent = class {
97348
+ text;
97349
+ color;
97350
+ textComponent;
97351
+ spacerComponent;
97352
+ imageThumbnails;
97353
+ constructor(text, colors, images) {
97354
+ this.text = text;
97355
+ this.color = colors.roleUser;
97356
+ this.textComponent = new Text(chalk.hex(colors.roleUser).bold(text), 0, 0);
97357
+ this.spacerComponent = new Spacer(1);
97358
+ this.imageThumbnails = images?.map((img) => new ImageThumbnail(img, colors)) ?? [];
97359
+ }
97360
+ invalidate() {
97361
+ this.textComponent.invalidate();
97362
+ for (const img of this.imageThumbnails) img.invalidate?.();
97363
+ }
97364
+ render(width) {
97365
+ const bullet = chalk.hex(this.color).bold(BULLET);
97366
+ const bulletWidth = visibleWidth(bullet);
97367
+ const contentWidth = Math.max(1, width - bulletWidth);
97368
+ const lines = [];
97369
+ for (const line of this.spacerComponent.render(width)) lines.push(line);
97370
+ const textLines = this.textComponent.render(contentWidth);
97371
+ for (let i = 0; i < textLines.length; i++) {
97372
+ const prefix = i === 0 ? bullet : " ".repeat(bulletWidth);
97373
+ lines.push(prefix + textLines[i]);
97374
+ }
97375
+ for (const thumbnail of this.imageThumbnails) {
97376
+ const imageLines = thumbnail.render(contentWidth);
97377
+ for (const line of imageLines) lines.push(" ".repeat(bulletWidth) + line);
97378
+ }
97379
+ return lines;
97334
97380
  }
97335
97381
  };
97336
97382
  //#endregion
@@ -97507,17 +97553,8 @@ function pushToast(ectx, notification) {
97507
97553
  function createTranscriptComponent(state, entry) {
97508
97554
  switch (entry.kind) {
97509
97555
  case "user": {
97510
- const msg = new UserMessageComponent(entry.content, state.colors);
97511
- if (entry.imageAttachmentIds !== void 0 && entry.imageAttachmentIds.length > 0) {
97512
- const wrap = new Container();
97513
- wrap.addChild(msg);
97514
- for (const id of entry.imageAttachmentIds) {
97515
- const attachment = state.imageStore.get(id);
97516
- if (attachment !== void 0) wrap.addChild(new ImageThumbnail(attachment, state.colors));
97517
- }
97518
- return wrap;
97519
- }
97520
- return msg;
97556
+ const images = entry.imageAttachmentIds?.map((id) => state.imageStore.get(id)).filter((a) => a?.kind === "image");
97557
+ return new UserMessageComponent(entry.content, state.colors, images);
97521
97558
  }
97522
97559
  case "skill_activation": return new SkillActivationComponent(entry.skillName ?? entry.content, entry.skillArgs, state.colors);
97523
97560
  case "assistant": return createAssistantEntry(state, entry.content);
@@ -97528,8 +97565,11 @@ function createTranscriptComponent(state, entry) {
97528
97565
  if (state.toolOutputExpanded) tc.setExpanded(true);
97529
97566
  return tc;
97530
97567
  }
97568
+ if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.colors);
97569
+ return entry.renderMode === "notice" ? createNoticeEntry(entry.content, entry.detail, state.colors) : createStatusEntry(entry.content, state.colors, entry.color);
97570
+ case "status":
97571
+ if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.colors);
97531
97572
  return entry.renderMode === "notice" ? createNoticeEntry(entry.content, entry.detail, state.colors) : createStatusEntry(entry.content, state.colors, entry.color);
97532
- case "status": return entry.renderMode === "notice" ? createNoticeEntry(entry.content, entry.detail, state.colors) : createStatusEntry(entry.content, state.colors, entry.color);
97533
97573
  default: return null;
97534
97574
  }
97535
97575
  }
@@ -97612,42 +97652,54 @@ function emitMuted(state, message) {
97612
97652
  }
97613
97653
  //#endregion
97614
97654
  //#region src/tui/input/image-placeholder.ts
97615
- const PLACEHOLDER_REGEX = /\[image #(\d+) \((\d+)×(\d+)\)\]/g;
97616
- function extractImageAttachments(text, store) {
97655
+ const PLACEHOLDER_REGEX = /\[(image|video) #(\d+) (?:(\(\d+×\d+\))|([^\]]+))\]/g;
97656
+ function extractMediaAttachments(text, store) {
97617
97657
  const parts = [];
97618
97658
  const cleanedSegments = [];
97619
- const attachmentIds = [];
97659
+ const imageAttachmentIds = [];
97620
97660
  let cursor = 0;
97621
- let hasImages = false;
97661
+ let hasMedia = false;
97622
97662
  PLACEHOLDER_REGEX.lastIndex = 0;
97623
97663
  let match;
97624
97664
  while ((match = PLACEHOLDER_REGEX.exec(text)) !== null) {
97625
- const [literal, idStr] = match;
97665
+ const [literal, kind, idStr] = match;
97666
+ if (kind !== "image" && kind !== "video") continue;
97626
97667
  if (idStr === void 0) continue;
97627
97668
  const id = Number.parseInt(idStr, 10);
97628
97669
  const attachment = store.get(id);
97629
97670
  if (attachment === void 0) continue;
97671
+ if (attachment.kind !== kind) continue;
97630
97672
  const before = text.slice(cursor, match.index);
97631
97673
  pushText(parts, before);
97632
97674
  cleanedSegments.push(before);
97633
- parts.push(buildImagePart(attachment));
97634
- attachmentIds.push(id);
97635
- hasImages = true;
97675
+ if (attachment.kind === "video") {
97676
+ pushText(parts, pathTextForVideo(attachment));
97677
+ cleanedSegments.push(pathTextForVideo(attachment));
97678
+ } else {
97679
+ parts.push(buildImagePart(attachment));
97680
+ imageAttachmentIds.push(id);
97681
+ }
97682
+ hasMedia = true;
97636
97683
  cursor = match.index + literal.length;
97637
97684
  }
97638
97685
  const tail = text.slice(cursor);
97639
97686
  pushText(parts, tail);
97640
97687
  cleanedSegments.push(tail);
97641
97688
  return {
97642
- parts: hasImages ? parts : [],
97643
- hasImages,
97644
- cleanedText: cleanedSegments.join("").replaceAll(/\s+/g, " ").trim(),
97645
- attachmentIds
97689
+ parts: hasMedia ? parts : [],
97690
+ hasMedia,
97691
+ cleanedText: cleanedSegments.join("").trim(),
97692
+ imageAttachmentIds
97646
97693
  };
97647
97694
  }
97648
97695
  function pushText(parts, segment) {
97649
97696
  if (segment.length === 0) return;
97650
97697
  if (segment.trim().length === 0) return;
97698
+ const last = parts.at(-1);
97699
+ if (last?.type === "text") {
97700
+ last.text += segment;
97701
+ return;
97702
+ }
97651
97703
  parts.push({
97652
97704
  type: "text",
97653
97705
  text: segment
@@ -97660,6 +97712,9 @@ function buildImagePart(att) {
97660
97712
  image_url: { url: `data:${att.mime};base64,${base64}` }
97661
97713
  };
97662
97714
  }
97715
+ function pathTextForVideo(att) {
97716
+ return att.sourcePath;
97717
+ }
97663
97718
  //#endregion
97664
97719
  //#region src/tui/theme/colors.ts
97665
97720
  /**
@@ -97893,7 +97948,7 @@ function createMarkdownTheme(colors) {
97893
97948
  linkUrl: (text) => muted(text),
97894
97949
  code: (text) => chalk.hex(colors.primary)(text),
97895
97950
  codeBlock: (text) => text,
97896
- codeBlockBorder: (text) => border(text),
97951
+ codeBlockBorder: (text) => muted(text),
97897
97952
  quote: (text) => dim(text),
97898
97953
  quoteBorder: (text) => dim(text),
97899
97954
  hr: (text) => border(text),
@@ -97956,7 +98011,8 @@ function mutateBottomSlot(state, slot, mutate) {
97956
98011
  const width = state.terminal?.columns ?? 80;
97957
98012
  const previousHeight = renderHeight(slot, width);
97958
98013
  mutate();
97959
- if (previousHeight !== renderHeight(slot, width)) state.ui.requestRender(true);
98014
+ if (previousHeight !== renderHeight(slot, width)) if (state.bottomLayoutState.hasFilledViewport) state.ui.requestRender(true);
98015
+ else state.ui.requestRender();
97960
98016
  else state.ui.requestRender();
97961
98017
  }
97962
98018
  function renderHeight(component, width) {
@@ -98017,6 +98073,7 @@ function clearTranscriptAndRedraw(state) {
98017
98073
  state.pendingToolComponents.clear();
98018
98074
  state.streamingComponent = void 0;
98019
98075
  state.streamingTranscriptEntry = void 0;
98076
+ state.bottomLayoutState.hasFilledViewport = false;
98020
98077
  state.todoPanel.clear();
98021
98078
  state.todoPanelContainer.clear();
98022
98079
  state.imageStore.clear();
@@ -98050,6 +98107,7 @@ function applyTheme(state, theme, hooks, resolved) {
98050
98107
  }
98051
98108
  //#endregion
98052
98109
  //#region src/tui/handlers/subagent.ts
98110
+ const MAX_BACKGROUND_FIELD_LENGTH = 240;
98053
98111
  function handleSubagentSourceEvent(ectx, payload) {
98054
98112
  const tc = ectx.state.pendingToolComponents.get(payload.parent_tool_call_id);
98055
98113
  if (tc === void 0) return;
@@ -98089,7 +98147,10 @@ function handleSubagentSourceEvent(ectx, payload) {
98089
98147
  }
98090
98148
  function handleSubagentSpawned(ectx, data) {
98091
98149
  if (data.run_in_background) {
98150
+ const meta = buildBackgroundAgentMetadata(ectx, data);
98151
+ ectx.state.backgroundAgentMetadata.set(data.agent_id, meta);
98092
98152
  ectx.state.backgroundAgents.add(data.agent_id);
98153
+ appendBackgroundAgentEntry(ectx, "started", meta);
98093
98154
  syncBackgroundAgentBadge(ectx);
98094
98155
  return;
98095
98156
  }
@@ -98109,7 +98170,13 @@ function handleSubagentSpawned(ectx, data) {
98109
98170
  });
98110
98171
  }
98111
98172
  function handleSubagentCompleted(ectx, data) {
98173
+ const backgroundMeta = ectx.state.backgroundAgentMetadata.get(data.agent_id);
98112
98174
  if (ectx.state.backgroundAgents.delete(data.agent_id)) syncBackgroundAgentBadge(ectx);
98175
+ if (backgroundMeta !== void 0) {
98176
+ ectx.state.backgroundAgentMetadata.delete(data.agent_id);
98177
+ appendBackgroundAgentEntry(ectx, "completed", backgroundMeta, { resultSummary: data.result_summary });
98178
+ return;
98179
+ }
98113
98180
  const tc = ectx.state.pendingToolComponents.get(data.parent_tool_call_id);
98114
98181
  if (tc === void 0) return;
98115
98182
  tc.onSubagentCompleted({
@@ -98118,15 +98185,66 @@ function handleSubagentCompleted(ectx, data) {
98118
98185
  });
98119
98186
  }
98120
98187
  function handleSubagentFailed(ectx, data) {
98188
+ const backgroundMeta = ectx.state.backgroundAgentMetadata.get(data.agent_id);
98121
98189
  if (ectx.state.backgroundAgents.delete(data.agent_id)) syncBackgroundAgentBadge(ectx);
98190
+ if (backgroundMeta !== void 0) {
98191
+ ectx.state.backgroundAgentMetadata.delete(data.agent_id);
98192
+ appendBackgroundAgentEntry(ectx, "failed", backgroundMeta, { error: data.error });
98193
+ return;
98194
+ }
98122
98195
  const tc = ectx.state.pendingToolComponents.get(data.parent_tool_call_id);
98123
98196
  if (tc === void 0) return;
98124
98197
  tc.onSubagentFailed({ error: data.error });
98125
98198
  }
98199
+ function buildBackgroundAgentMetadata(ectx, data) {
98200
+ const parent = ectx.state.activeToolCalls.get(data.parent_tool_call_id);
98201
+ return {
98202
+ agentId: data.agent_id,
98203
+ parentToolCallId: data.parent_tool_call_id,
98204
+ agentName: data.agent_name,
98205
+ description: getAgentDescription$1(parent)
98206
+ };
98207
+ }
98208
+ function getAgentDescription$1(toolCall) {
98209
+ if (toolCall === void 0) return void 0;
98210
+ const description = toolCall.args["description"];
98211
+ return typeof description === "string" ? description : void 0;
98212
+ }
98213
+ function appendBackgroundAgentEntry(ectx, phase, meta, extras = void 0) {
98214
+ const status = formatBackgroundAgentTranscript(phase, meta, extras);
98215
+ const entry = {
98216
+ id: nextTranscriptId(),
98217
+ kind: "status",
98218
+ turnId: ectx.state.currentTurnId,
98219
+ renderMode: "plain",
98220
+ content: status.headline,
98221
+ detail: status.detail,
98222
+ backgroundAgentStatus: status
98223
+ };
98224
+ ectx.addTranscriptEntry(entry);
98225
+ }
98126
98226
  function syncBackgroundAgentBadge(ectx) {
98127
98227
  ectx.state.footer.setBackgroundAgentCount(ectx.state.backgroundAgents.size);
98128
98228
  ectx.state.ui.requestRender();
98129
98229
  }
98230
+ function normalizeBackgroundField(value) {
98231
+ if (value === void 0) return void 0;
98232
+ const collapsed = value.trim().replaceAll(/\s+/g, " ");
98233
+ if (collapsed.length === 0) return void 0;
98234
+ if (collapsed.length <= MAX_BACKGROUND_FIELD_LENGTH) return collapsed;
98235
+ return `${collapsed.slice(0, MAX_BACKGROUND_FIELD_LENGTH - 3)}...`;
98236
+ }
98237
+ function formatBackgroundAgentTranscript(phase, meta, extras = void 0) {
98238
+ const subject = normalizeBackgroundField(meta.agentName) !== void 0 ? `${normalizeBackgroundField(meta.agentName)} agent` : "agent";
98239
+ const headline = phase === "started" ? `${subject} started in background` : phase === "completed" ? `${subject} completed in background` : `${subject} failed in background`;
98240
+ const tail = phase === "failed" ? normalizeBackgroundField(extras?.error) : void 0;
98241
+ const detailParts = [normalizeBackgroundField(meta.description), tail].filter((part) => part !== void 0);
98242
+ return {
98243
+ phase,
98244
+ headline,
98245
+ detail: detailParts.length > 0 ? detailParts.join(" · ") : void 0
98246
+ };
98247
+ }
98130
98248
  //#endregion
98131
98249
  //#region src/utils/git/git-ls-files.ts
98132
98250
  /**
@@ -99328,10 +99446,14 @@ var ImageAttachmentStore = class {
99328
99446
  nextId = 1;
99329
99447
  byId = /* @__PURE__ */ new Map();
99330
99448
  add(bytes, mime, width, height) {
99449
+ return this.addImage(bytes, mime, width, height);
99450
+ }
99451
+ addImage(bytes, mime, width, height) {
99331
99452
  const id = this.nextId;
99332
99453
  this.nextId += 1;
99333
99454
  const attachment = {
99334
99455
  id,
99456
+ kind: "image",
99335
99457
  bytes,
99336
99458
  mime,
99337
99459
  width,
@@ -99341,6 +99463,23 @@ var ImageAttachmentStore = class {
99341
99463
  this.byId.set(id, attachment);
99342
99464
  return attachment;
99343
99465
  }
99466
+ addVideo(mime, sourcePath, filename) {
99467
+ const id = this.nextId;
99468
+ this.nextId += 1;
99469
+ const normalizedFilename = basenameLike(filename !== void 0 && filename !== "" ? filename : sourcePath);
99470
+ const label = sanitizeVideoLabel(normalizedFilename.length > 0 ? normalizedFilename : mime);
99471
+ const attachment = {
99472
+ id,
99473
+ kind: "video",
99474
+ mime,
99475
+ filename: normalizedFilename,
99476
+ sourcePath,
99477
+ label,
99478
+ placeholder: formatVideoPlaceholder(id, label)
99479
+ };
99480
+ this.byId.set(id, attachment);
99481
+ return attachment;
99482
+ }
99344
99483
  get(id) {
99345
99484
  return this.byId.get(id);
99346
99485
  }
@@ -99355,6 +99494,21 @@ var ImageAttachmentStore = class {
99355
99494
  function formatPlaceholder(id, width, height) {
99356
99495
  return `[image #${String(id)} (${String(width)}×${String(height)})]`;
99357
99496
  }
99497
+ function formatVideoPlaceholder(id, label) {
99498
+ return `[video #${String(id)} ${sanitizeVideoLabel(label)}]`;
99499
+ }
99500
+ function sanitizeVideoLabel(raw) {
99501
+ let label = "";
99502
+ for (const char of raw) {
99503
+ const code = char.codePointAt(0);
99504
+ label += code < 32 || code === 127 || char === "[" || char === "]" ? "_" : char;
99505
+ }
99506
+ label = label.trim();
99507
+ return label.length > 0 ? label : "video";
99508
+ }
99509
+ function basenameLike(raw) {
99510
+ return raw.split(/[\\/]/).filter((part) => part.length > 0).at(-1) ?? raw;
99511
+ }
99358
99512
  //#endregion
99359
99513
  //#region src/tui/reverse-rpc/base-controller.ts
99360
99514
  var ReverseRpcController = class {
@@ -99461,6 +99615,7 @@ function createTUIState(options) {
99461
99615
  colors,
99462
99616
  styles,
99463
99617
  markdownTheme,
99618
+ bottomLayoutState: { hasFilledViewport: false },
99464
99619
  resolvedTheme,
99465
99620
  appState: { ...initialAppState },
99466
99621
  startupState: "pending",
@@ -99481,6 +99636,7 @@ function createTUIState(options) {
99481
99636
  pendingAgentGroup: null,
99482
99637
  pendingReadGroup: null,
99483
99638
  backgroundAgents: /* @__PURE__ */ new Set(),
99639
+ backgroundAgentMetadata: /* @__PURE__ */ new Map(),
99484
99640
  sessions: [],
99485
99641
  loadingSessions: false,
99486
99642
  showingSessionPicker: false,
@@ -99629,11 +99785,13 @@ function nextQueueId(state) {
99629
99785
  state.queueIdCounter += 1;
99630
99786
  return `q-${String(state.queueIdCounter)}`;
99631
99787
  }
99632
- function enqueueMessage(state, text) {
99788
+ function enqueueMessage(state, text, options) {
99633
99789
  state.queuedMessages.push({
99634
99790
  id: nextQueueId(state),
99635
99791
  kind: "message",
99636
- text
99792
+ text,
99793
+ ...options?.parts !== void 0 ? { parts: options.parts } : {},
99794
+ ...options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? { imageAttachmentIds: options.imageAttachmentIds } : {}
99637
99795
  });
99638
99796
  }
99639
99797
  function queuedMessageText(item) {
@@ -99776,7 +99934,7 @@ function sendSkillActivation(state, addEntry, skillName, skillArgs, fullPrompt)
99776
99934
  /** Send from user input: enqueue if busy, otherwise send immediately. */
99777
99935
  function sendMessage(state, addEntry, input, options) {
99778
99936
  if (state.appState.isStreaming || state.appState.isCompacting) {
99779
- enqueueMessage(state, input);
99937
+ enqueueMessage(state, input, options);
99780
99938
  return;
99781
99939
  }
99782
99940
  sendMessageInternal(state, addEntry, input, options);
@@ -99836,11 +99994,11 @@ function handleUserInput(state, text, hooks, onSlash) {
99836
99994
  sendNormalUserInput(state, text, hooks);
99837
99995
  }
99838
99996
  function sendNormalUserInput(state, text, hooks) {
99839
- const extraction = extractImageAttachments(text, state.imageStore);
99997
+ const extraction = extractMediaAttachments(text, state.imageStore);
99840
99998
  const addEntry = (e) => addTranscriptEntry(state, e);
99841
- if (extraction.hasImages) sendMessage(state, addEntry, text, {
99999
+ if (extraction.hasMedia) sendMessage(state, addEntry, text, {
99842
100000
  parts: extraction.parts,
99843
- imageAttachmentIds: extraction.attachmentIds
100001
+ imageAttachmentIds: extraction.imageAttachmentIds
99844
100002
  });
99845
100003
  else sendMessage(state, addEntry, text);
99846
100004
  hooks.refreshQueuePane();
@@ -100090,6 +100248,7 @@ async function hydrateTranscriptFromReplay(state, hooks, sessionId) {
100090
100248
  const projection = projectReplayRecords(replay.records);
100091
100249
  hydrateProjectedEntries(state, projection.entries);
100092
100250
  state.backgroundAgents = new Set(projection.backgroundAgents);
100251
+ state.backgroundAgentMetadata = new Map(projection.backgroundAgentMetadata);
100093
100252
  state.footer.setBackgroundAgentCount(state.backgroundAgents.size);
100094
100253
  state.ui.requestRender();
100095
100254
  if (replay.warnings !== void 0 && replay.warnings.length > 0) emitError(state, `Replay completed with ${String(replay.warnings.length)} warning(s).`);
@@ -100110,7 +100269,8 @@ function projectReplayRecords(records) {
100110
100269
  thinking: [],
100111
100270
  text: []
100112
100271
  },
100113
- backgroundAgents: /* @__PURE__ */ new Set()
100272
+ backgroundAgents: /* @__PURE__ */ new Set(),
100273
+ backgroundAgentMetadata: /* @__PURE__ */ new Map()
100114
100274
  };
100115
100275
  for (const envelope of records) {
100116
100276
  if (envelope.source?.kind === "subagent") {
@@ -100122,7 +100282,8 @@ function projectReplayRecords(records) {
100122
100282
  flushAssistant(state);
100123
100283
  return {
100124
100284
  entries: state.entries,
100125
- backgroundAgents: state.backgroundAgents
100285
+ backgroundAgents: state.backgroundAgents,
100286
+ backgroundAgentMetadata: state.backgroundAgentMetadata
100126
100287
  };
100127
100288
  }
100128
100289
  function projectMainRecord(state, rawRecord) {
@@ -100170,15 +100331,54 @@ function projectMainRecord(state, rawRecord) {
100170
100331
  if (!isObject(data)) return;
100171
100332
  if (data["run_in_background"] !== true) return;
100172
100333
  const agentId = stringValue(data["agent_id"]);
100334
+ const parentToolCallId = stringValue(data["parent_tool_call_id"]);
100173
100335
  if (agentId !== void 0) state.backgroundAgents.add(agentId);
100336
+ if (agentId === void 0 || parentToolCallId === void 0) return;
100337
+ removeReplayToolCallEntry(state.entries, parentToolCallId);
100338
+ const meta = {
100339
+ agentId,
100340
+ parentToolCallId,
100341
+ agentName: stringValue(data["agent_name"]),
100342
+ description: getAgentDescription(state.toolCalls.get(parentToolCallId))
100343
+ };
100344
+ state.backgroundAgentMetadata.set(agentId, meta);
100345
+ const status = formatBackgroundAgentTranscript("started", meta);
100346
+ state.entries.push(entry("status", status.headline, "plain", {
100347
+ detail: status.detail,
100348
+ backgroundAgentStatus: status
100349
+ }));
100350
+ return;
100351
+ }
100352
+ case "subagent_completed": {
100353
+ const data = record.data;
100354
+ if (!isObject(data)) return;
100355
+ const agentId = stringValue(data["agent_id"]);
100356
+ if (agentId !== void 0) state.backgroundAgents.delete(agentId);
100357
+ if (agentId === void 0) return;
100358
+ const meta = state.backgroundAgentMetadata.get(agentId);
100359
+ if (meta === void 0) return;
100360
+ state.backgroundAgentMetadata.delete(agentId);
100361
+ const status = formatBackgroundAgentTranscript("completed", meta, { resultSummary: stringValue(data["result_summary"]) });
100362
+ state.entries.push(entry("status", status.headline, "plain", {
100363
+ detail: status.detail,
100364
+ backgroundAgentStatus: status
100365
+ }));
100174
100366
  return;
100175
100367
  }
100176
- case "subagent_completed":
100177
100368
  case "subagent_failed": {
100178
100369
  const data = record.data;
100179
100370
  if (!isObject(data)) return;
100180
100371
  const agentId = stringValue(data["agent_id"]);
100181
100372
  if (agentId !== void 0) state.backgroundAgents.delete(agentId);
100373
+ if (agentId === void 0) return;
100374
+ const meta = state.backgroundAgentMetadata.get(agentId);
100375
+ if (meta === void 0) return;
100376
+ state.backgroundAgentMetadata.delete(agentId);
100377
+ const status = formatBackgroundAgentTranscript("failed", meta, { error: stringValue(data["error"]) });
100378
+ state.entries.push(entry("status", status.headline, "plain", {
100379
+ detail: status.detail,
100380
+ backgroundAgentStatus: status
100381
+ }));
100182
100382
  return;
100183
100383
  }
100184
100384
  default: return;
@@ -100294,6 +100494,11 @@ function toolCallFromRecord(record) {
100294
100494
  description: stringValue(data["activity_description"])
100295
100495
  };
100296
100496
  }
100497
+ function getAgentDescription(toolCall) {
100498
+ if (toolCall === void 0) return void 0;
100499
+ const description = toolCall.args["description"];
100500
+ return typeof description === "string" ? description : void 0;
100501
+ }
100297
100502
  function toolResultFromRecord(record) {
100298
100503
  const id = stringValue(record.tool_call_id);
100299
100504
  if (id === void 0) return void 0;
@@ -100318,9 +100523,16 @@ function entry(kind, content, renderMode, extras) {
100318
100523
  renderMode,
100319
100524
  content,
100320
100525
  turnId: extras?.turnId,
100321
- toolCallData: extras?.toolCallData
100526
+ detail: extras?.detail,
100527
+ color: extras?.color,
100528
+ toolCallData: extras?.toolCallData,
100529
+ backgroundAgentStatus: extras?.backgroundAgentStatus
100322
100530
  };
100323
100531
  }
100532
+ function removeReplayToolCallEntry(entries, toolCallId) {
100533
+ const idx = entries.findIndex((entry) => entry.kind === "tool_call" && entry.toolCallData?.id === toolCallId);
100534
+ if (idx >= 0) entries.splice(idx, 1);
100535
+ }
100324
100536
  function userContentToText(content) {
100325
100537
  if (typeof content === "string") return content;
100326
100538
  if (!Array.isArray(content)) return "";
@@ -100568,6 +100780,9 @@ function releaseSessionSideEffects(state) {
100568
100780
  state.queueIdCounter = 0;
100569
100781
  state.activeToolCalls.clear();
100570
100782
  state.streamingToolCallArguments?.clear();
100783
+ state.backgroundAgents.clear();
100784
+ state.backgroundAgentMetadata.clear();
100785
+ state.footer.setBackgroundAgentCount(0);
100571
100786
  state.currentTurnId = void 0;
100572
100787
  state.assistantDraft = "";
100573
100788
  state.assistantStreamActive = false;
@@ -103745,6 +103960,136 @@ function registerReverseRPCHandlers(state, client) {
103745
103960
  return [client.onRequest("approval.request", createApprovalRequestHandler(state)), client.onRequest("question.ask", createQuestionAskHandler(state))];
103746
103961
  }
103747
103962
  //#endregion
103963
+ //#region src/utils/image/image-mime.ts
103964
+ function parseImageMeta(bytes) {
103965
+ if (isPng(bytes)) return parsePng(bytes);
103966
+ if (isJpeg(bytes)) return parseJpeg(bytes);
103967
+ if (isGif(bytes)) return parseGif(bytes);
103968
+ if (isWebp(bytes)) return parseWebp(bytes);
103969
+ return null;
103970
+ }
103971
+ function isPng(b) {
103972
+ return b.length >= 8 && b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71 && b[4] === 13 && b[5] === 10 && b[6] === 26 && b[7] === 10;
103973
+ }
103974
+ function parsePng(b) {
103975
+ if (b.length < 24) return null;
103976
+ const width = readUInt32BE(b, 16);
103977
+ const height = readUInt32BE(b, 20);
103978
+ if (width <= 0 || height <= 0) return null;
103979
+ return {
103980
+ mime: "image/png",
103981
+ width,
103982
+ height
103983
+ };
103984
+ }
103985
+ function isJpeg(b) {
103986
+ return b.length >= 3 && b[0] === 255 && b[1] === 216 && b[2] === 255;
103987
+ }
103988
+ function parseJpeg(b) {
103989
+ let i = 2;
103990
+ while (i < b.length) {
103991
+ if (b[i] !== 255) {
103992
+ i += 1;
103993
+ continue;
103994
+ }
103995
+ while (i < b.length && b[i] === 255) i += 1;
103996
+ if (i >= b.length) return null;
103997
+ const marker = b[i];
103998
+ i += 1;
103999
+ if (marker === 216 || marker === 217) continue;
104000
+ if (i + 1 >= b.length) return null;
104001
+ const segLen = readUInt16BE(b, i);
104002
+ if (isSofMarker(marker)) {
104003
+ if (i + 7 >= b.length) return null;
104004
+ const height = readUInt16BE(b, i + 3);
104005
+ const width = readUInt16BE(b, i + 5);
104006
+ if (width <= 0 || height <= 0) return null;
104007
+ return {
104008
+ mime: "image/jpeg",
104009
+ width,
104010
+ height
104011
+ };
104012
+ }
104013
+ i += segLen;
104014
+ }
104015
+ return null;
104016
+ }
104017
+ function isSofMarker(marker) {
104018
+ if (marker < 192 || marker > 207) return false;
104019
+ return marker !== 196 && marker !== 200 && marker !== 204;
104020
+ }
104021
+ function isGif(b) {
104022
+ return b.length >= 6 && b[0] === 71 && b[1] === 73 && b[2] === 70 && b[3] === 56 && (b[4] === 55 || b[4] === 57) && b[5] === 97;
104023
+ }
104024
+ function parseGif(b) {
104025
+ if (b.length < 10) return null;
104026
+ const width = readUInt16LE(b, 6);
104027
+ const height = readUInt16LE(b, 8);
104028
+ if (width <= 0 || height <= 0) return null;
104029
+ return {
104030
+ mime: "image/gif",
104031
+ width,
104032
+ height
104033
+ };
104034
+ }
104035
+ function isWebp(b) {
104036
+ return b.length >= 12 && b[0] === 82 && b[1] === 73 && b[2] === 70 && b[3] === 70 && b[8] === 87 && b[9] === 69 && b[10] === 66 && b[11] === 80;
104037
+ }
104038
+ function parseWebp(b) {
104039
+ if (b.length < 30) return null;
104040
+ const chunk = String.fromCharCode(b[12], b[13], b[14], b[15]);
104041
+ if (chunk === "VP8 ") {
104042
+ const widthRaw = readUInt16LE(b, 26);
104043
+ const heightRaw = readUInt16LE(b, 28);
104044
+ const width = widthRaw & 16383;
104045
+ const height = heightRaw & 16383;
104046
+ if (width <= 0 || height <= 0) return null;
104047
+ return {
104048
+ mime: "image/webp",
104049
+ width,
104050
+ height
104051
+ };
104052
+ }
104053
+ if (chunk === "VP8L") {
104054
+ if (b[20] !== 47) return null;
104055
+ const b1 = b[21];
104056
+ const b2 = b[22];
104057
+ const b3 = b[23];
104058
+ const b4 = b[24];
104059
+ const width = 1 + ((b2 & 63) << 8 | b1);
104060
+ const height = 1 + ((b4 & 15) << 10 | b3 << 2 | (b2 & 192) >> 6);
104061
+ if (width <= 0 || height <= 0) return null;
104062
+ return {
104063
+ mime: "image/webp",
104064
+ width,
104065
+ height
104066
+ };
104067
+ }
104068
+ if (chunk === "VP8X") {
104069
+ const width = 1 + readUInt24LE(b, 24);
104070
+ const height = 1 + readUInt24LE(b, 27);
104071
+ if (width <= 0 || height <= 0) return null;
104072
+ return {
104073
+ mime: "image/webp",
104074
+ width,
104075
+ height
104076
+ };
104077
+ }
104078
+ return null;
104079
+ }
104080
+ function readUInt16BE(b, off) {
104081
+ return b[off] << 8 | b[off + 1];
104082
+ }
104083
+ function readUInt16LE(b, off) {
104084
+ return b[off] | b[off + 1] << 8;
104085
+ }
104086
+ function readUInt24LE(b, off) {
104087
+ return b[off] | b[off + 1] << 8 | b[off + 2] << 16;
104088
+ }
104089
+ function readUInt32BE(b, off) {
104090
+ return b[off] * 16777216 + (b[off + 1] << 16) + (b[off + 2] << 8) + b[off + 3] >>> 0;
104091
+ }
104092
+ //#endregion
103748
104093
  //#region src/utils/clipboard/clipboard-native.ts
103749
104094
  /**
103750
104095
  * Optional native clipboard binding.
@@ -103766,32 +104111,89 @@ if (process.env["TERMUX_VERSION"] === void 0 && hasDisplay) try {
103766
104111
  //#endregion
103767
104112
  //#region src/utils/clipboard/clipboard-image.ts
103768
104113
  /**
103769
- * Read an image from the system clipboard with graceful platform
104114
+ * Read media from the system clipboard with graceful platform
103770
104115
  * fallbacks. Ported from `libs/pi-mono/packages/coding-agent/src/utils/
103771
- * clipboard-image.ts` and trimmed we don't carry the Photon WASM
103772
- * BMPPNG converter because kimi-core's LLM pipeline only accepts
104116
+ * clipboard-image.ts` and trimmed -- we don't carry the Photon WASM
104117
+ * BMP-to-PNG converter because kimi-core's LLM pipeline only accepts
103773
104118
  * PNG/JPEG/GIF/WebP, and the clipboard sources we query already emit
103774
104119
  * those formats on the supported platforms.
103775
104120
  *
103776
104121
  * Lookup order:
103777
- * macOS / Windows → native `@mariozechner/clipboard`
103778
- * Linux Wayland → wl-paste
103779
- * Linux X11 → xclip
103780
- * WSL (image not on Linux cb)→ PowerShell fallback via wslpath
104122
+ * macOS file clipboard -> osascript/AppKit file URLs
104123
+ * macOS / Windows -> native `@mariozechner/clipboard`
104124
+ * Linux Wayland -> wl-paste
104125
+ * Linux X11 -> xclip
104126
+ * WSL (image not on Linux cb) -> PowerShell fallback via wslpath
103781
104127
  *
103782
- * Returns `null` when no image is available, the format isn't
104128
+ * Returns `null` when no supported media is available, the format isn't
103783
104129
  * supported, or every fallback fails.
103784
104130
  */
104131
+ var ClipboardMediaError = class extends Error {
104132
+ constructor(message) {
104133
+ super(message);
104134
+ this.name = "ClipboardMediaError";
104135
+ }
104136
+ };
103785
104137
  const SUPPORTED_IMAGE_MIME_TYPES = [
103786
104138
  "image/png",
103787
104139
  "image/jpeg",
103788
104140
  "image/webp",
103789
104141
  "image/gif"
103790
104142
  ];
104143
+ const MAX_VIDEO_BYTES = 100 * 1024 * 1024;
104144
+ const VIDEO_MIME_BY_SUFFIX = Object.freeze({
104145
+ ".mp4": "video/mp4",
104146
+ ".mpg": "video/mpeg",
104147
+ ".mpeg": "video/mpeg",
104148
+ ".mkv": "video/x-matroska",
104149
+ ".avi": "video/x-msvideo",
104150
+ ".mov": "video/quicktime",
104151
+ ".ogv": "video/ogg",
104152
+ ".wmv": "video/x-ms-wmv",
104153
+ ".webm": "video/webm",
104154
+ ".m4v": "video/x-m4v",
104155
+ ".flv": "video/x-flv",
104156
+ ".3gp": "video/3gpp",
104157
+ ".3g2": "video/3gpp2"
104158
+ });
103791
104159
  const DEFAULT_LIST_TIMEOUT_MS = 1e3;
103792
104160
  const DEFAULT_READ_TIMEOUT_MS = 3e3;
103793
104161
  const DEFAULT_POWERSHELL_TIMEOUT_MS = 5e3;
103794
104162
  const DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
104163
+ const MACOS_FILE_PATH_SCRIPT = String.raw`
104164
+ ObjC.import('AppKit');
104165
+ ObjC.import('Foundation');
104166
+
104167
+ const out = [];
104168
+ const pb = $.NSPasteboard.generalPasteboard;
104169
+ if (String(pb) !== '[id nil]') {
104170
+ try {
104171
+ const options = $.NSMutableDictionary.dictionary;
104172
+ options.setObjectForKey($.NSNumber.numberWithBool(true), $.NSPasteboardURLReadingFileURLsOnlyKey);
104173
+ const urls = pb.readObjectsForClassesOptions([$.NSURL], options);
104174
+ const count = urls ? urls.count : 0;
104175
+ for (let i = 0; i < count; i++) {
104176
+ const value = urls.objectAtIndex(i).path;
104177
+ const path = value ? ObjC.unwrap(value) : '';
104178
+ if (path) out.push(path);
104179
+ }
104180
+ } catch (error) {}
104181
+
104182
+ if (out.length === 0) {
104183
+ try {
104184
+ const files = ObjC.deepUnwrap(pb.propertyListForType('NSFilenamesPboardType'));
104185
+ if (Array.isArray(files)) {
104186
+ for (const path of files) {
104187
+ if (path) out.push(String(path));
104188
+ }
104189
+ } else if (files) {
104190
+ out.push(String(files));
104191
+ }
104192
+ } catch (error) {}
104193
+ }
104194
+ }
104195
+ out.join('\n');
104196
+ `.trim();
103795
104197
  function isWaylandSession(env) {
103796
104198
  return Boolean(env["WAYLAND_DISPLAY"]) || env["XDG_SESSION_TYPE"] === "wayland";
103797
104199
  }
@@ -103821,6 +104223,90 @@ function selectPreferredImageMimeType(candidates) {
103821
104223
  }
103822
104224
  return normalized.find((t) => t.base.startsWith("image/"))?.raw ?? null;
103823
104225
  }
104226
+ function videoMimeFromPath(path) {
104227
+ const dot = path.lastIndexOf(".");
104228
+ if (dot < 0) return null;
104229
+ return VIDEO_MIME_BY_SUFFIX[path.slice(dot).toLowerCase()] ?? null;
104230
+ }
104231
+ function parseClipboardPaths(text) {
104232
+ return splitClipboardPathLines(text).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map((line) => {
104233
+ if (line.startsWith("file://")) try {
104234
+ return fileURLToPath(line);
104235
+ } catch {
104236
+ return "";
104237
+ }
104238
+ return line;
104239
+ }).filter((line) => line.length > 0 && isAbsolute(line));
104240
+ }
104241
+ function splitClipboardPathLines(text) {
104242
+ const lines = [];
104243
+ let start = 0;
104244
+ for (let i = 0; i < text.length; i += 1) {
104245
+ const char = text[i];
104246
+ if (char === "\r" || char === "\n" || text.codePointAt(i) === 0) {
104247
+ lines.push(text.slice(start, i));
104248
+ start = i + 1;
104249
+ }
104250
+ }
104251
+ lines.push(text.slice(start));
104252
+ return lines;
104253
+ }
104254
+ function readImagePath(path) {
104255
+ let stat;
104256
+ try {
104257
+ stat = statSync(path);
104258
+ } catch {
104259
+ return null;
104260
+ }
104261
+ if (!stat.isFile()) return null;
104262
+ let bytes;
104263
+ try {
104264
+ bytes = readFileSync(path);
104265
+ } catch {
104266
+ return null;
104267
+ }
104268
+ if (bytes.length === 0) return null;
104269
+ const meta = parseImageMeta(bytes);
104270
+ if (meta === null) return null;
104271
+ return {
104272
+ kind: "image",
104273
+ bytes: new Uint8Array(bytes),
104274
+ mimeType: meta.mime
104275
+ };
104276
+ }
104277
+ function readVideoPath(path) {
104278
+ const mimeType = videoMimeFromPath(path);
104279
+ if (mimeType === null) return null;
104280
+ let stat;
104281
+ try {
104282
+ stat = statSync(path);
104283
+ } catch {
104284
+ return null;
104285
+ }
104286
+ if (!stat.isFile()) return null;
104287
+ if (stat.size > MAX_VIDEO_BYTES) throw new ClipboardMediaError(`Video is ${(stat.size / 1024 / 1024).toFixed(1)} MB; maximum supported size is 100 MB.`);
104288
+ return {
104289
+ kind: "video",
104290
+ mimeType,
104291
+ filename: basename(path),
104292
+ sourcePath: path
104293
+ };
104294
+ }
104295
+ function readMediaPath(path) {
104296
+ const video = readVideoPath(path);
104297
+ if (video !== null) return video;
104298
+ return readImagePath(path);
104299
+ }
104300
+ function readMediaFromPaths(paths) {
104301
+ for (const path of paths) {
104302
+ const media = readMediaPath(path);
104303
+ if (media !== null) return media;
104304
+ }
104305
+ return null;
104306
+ }
104307
+ function readMediaFromText(text) {
104308
+ return readMediaFromPaths(parseClipboardPaths(text));
104309
+ }
103824
104310
  function runCommand(command, args, options) {
103825
104311
  const result = spawnSync(command, args, {
103826
104312
  timeout: options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS,
@@ -103836,10 +104322,25 @@ function runCommand(command, args, options) {
103836
104322
  stdout: Buffer.isBuffer(result.stdout) ? result.stdout : Buffer.from(result.stdout ?? "")
103837
104323
  };
103838
104324
  }
104325
+ function parseTargetList(output) {
104326
+ return output.toString("utf-8").split(/\r?\n/).map((t) => t.trim()).filter((t) => t.length > 0);
104327
+ }
104328
+ function readClipboardFileMediaViaWlPaste() {
104329
+ const list = runCommand("wl-paste", ["--list-types"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
104330
+ if (!list.ok) return null;
104331
+ const uriType = parseTargetList(list.stdout).find((t) => baseMimeType(t) === "text/uri-list");
104332
+ if (uriType === void 0) return null;
104333
+ const uris = runCommand("wl-paste", [
104334
+ "--type",
104335
+ uriType,
104336
+ "--no-newline"
104337
+ ]);
104338
+ return uris.ok ? readMediaFromText(uris.stdout.toString("utf-8")) : null;
104339
+ }
103839
104340
  function readClipboardImageViaWlPaste() {
103840
104341
  const list = runCommand("wl-paste", ["--list-types"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
103841
104342
  if (!list.ok) return null;
103842
- const selected = selectPreferredImageMimeType(list.stdout.toString("utf-8").split(/\r?\n/).map((t) => t.trim()).filter((t) => t.length > 0));
104343
+ const selected = selectPreferredImageMimeType(parseTargetList(list.stdout));
103843
104344
  if (selected === null) return null;
103844
104345
  const data = runCommand("wl-paste", [
103845
104346
  "--type",
@@ -103848,10 +104349,31 @@ function readClipboardImageViaWlPaste() {
103848
104349
  ]);
103849
104350
  if (!data.ok || data.stdout.length === 0) return null;
103850
104351
  return {
104352
+ kind: "image",
103851
104353
  bytes: data.stdout,
103852
104354
  mimeType: baseMimeType(selected)
103853
104355
  };
103854
104356
  }
104357
+ function readClipboardFileMediaViaXclip() {
104358
+ const targets = runCommand("xclip", [
104359
+ "-selection",
104360
+ "clipboard",
104361
+ "-t",
104362
+ "TARGETS",
104363
+ "-o"
104364
+ ], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
104365
+ if (!targets.ok) return null;
104366
+ const uriType = parseTargetList(targets.stdout).find((t) => baseMimeType(t) === "text/uri-list");
104367
+ if (uriType === void 0) return null;
104368
+ const uris = runCommand("xclip", [
104369
+ "-selection",
104370
+ "clipboard",
104371
+ "-t",
104372
+ uriType,
104373
+ "-o"
104374
+ ]);
104375
+ return uris.ok ? readMediaFromText(uris.stdout.toString("utf-8")) : null;
104376
+ }
103855
104377
  function readClipboardImageViaXclip() {
103856
104378
  const targets = runCommand("xclip", [
103857
104379
  "-selection",
@@ -103860,7 +104382,7 @@ function readClipboardImageViaXclip() {
103860
104382
  "TARGETS",
103861
104383
  "-o"
103862
104384
  ], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
103863
- const candidates = targets.ok ? targets.stdout.toString("utf-8").split(/\r?\n/).map((t) => t.trim()).filter((t) => t.length > 0) : [];
104385
+ const candidates = targets.ok ? parseTargetList(targets.stdout) : [];
103864
104386
  const preferred = candidates.length > 0 ? selectPreferredImageMimeType(candidates) : null;
103865
104387
  const tryTypes = preferred !== null ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];
103866
104388
  for (const mime of tryTypes) {
@@ -103872,6 +104394,7 @@ function readClipboardImageViaXclip() {
103872
104394
  "-o"
103873
104395
  ]);
103874
104396
  if (data.ok && data.stdout.length > 0) return {
104397
+ kind: "image",
103875
104398
  bytes: data.stdout,
103876
104399
  mimeType: baseMimeType(mime)
103877
104400
  };
@@ -103913,6 +104436,7 @@ function readClipboardImageViaPowerShell() {
103913
104436
  const bytes = readFileSync(tmpFile);
103914
104437
  if (bytes.length === 0) return null;
103915
104438
  return {
104439
+ kind: "image",
103916
104440
  bytes: new Uint8Array(bytes),
103917
104441
  mimeType: "image/png"
103918
104442
  };
@@ -103924,12 +104448,66 @@ function readClipboardImageViaPowerShell() {
103924
104448
  } catch {}
103925
104449
  }
103926
104450
  }
103927
- async function readClipboardImageViaNative() {
103928
- if (clipboard === null || !clipboard.hasImage()) return null;
104451
+ function readClipboardFilePathsViaMacOs(run) {
104452
+ const result = run("osascript", [
104453
+ "-l",
104454
+ "JavaScript",
104455
+ "-e",
104456
+ MACOS_FILE_PATH_SCRIPT
104457
+ ], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
104458
+ if (!result.ok || result.stdout.length === 0) return [];
104459
+ return parseClipboardPaths(result.stdout.toString("utf-8"));
104460
+ }
104461
+ function isFileLikeNativeFormat(format) {
104462
+ const f = format.toLowerCase();
104463
+ const base = baseMimeType(format);
104464
+ return f.includes("file-url") || f.includes("file url") || f.includes("nsfilenames") || f.includes("com.apple.finder") || base === "text/uri-list" || base === "public.url";
104465
+ }
104466
+ function safeAvailableFormats(clip) {
104467
+ if (clip?.availableFormats === void 0) return [];
104468
+ try {
104469
+ return clip.availableFormats();
104470
+ } catch {
104471
+ return [];
104472
+ }
104473
+ }
104474
+ async function readClipboardFileMediaViaNativeText(clip) {
104475
+ if (clip === null) return {
104476
+ media: null,
104477
+ lookedFileLike: false
104478
+ };
104479
+ const lookedFileLike = safeAvailableFormats(clip).some(isFileLikeNativeFormat);
104480
+ if (!lookedFileLike || clip.getText === void 0) return {
104481
+ media: null,
104482
+ lookedFileLike
104483
+ };
104484
+ try {
104485
+ return {
104486
+ media: readMediaFromText(await clip.getText()),
104487
+ lookedFileLike
104488
+ };
104489
+ } catch (error) {
104490
+ if (error instanceof ClipboardMediaError) throw error;
104491
+ return {
104492
+ media: null,
104493
+ lookedFileLike
104494
+ };
104495
+ }
104496
+ }
104497
+ async function readClipboardImageViaNative(clip = clipboard) {
104498
+ if (clip === null) return null;
104499
+ let hasImage = false;
103929
104500
  try {
103930
- const data = await clipboard.getImageBinary();
104501
+ hasImage = clip.hasImage();
104502
+ } catch {
104503
+ return null;
104504
+ }
104505
+ if (!hasImage) return null;
104506
+ try {
104507
+ const data = await clip.getImageBinary();
103931
104508
  if (data.length === 0) return null;
103932
104509
  return {
104510
+ kind: "image",
103933
104511
  bytes: Uint8Array.from(data),
103934
104512
  mimeType: "image/png"
103935
104513
  };
@@ -103937,151 +104515,41 @@ async function readClipboardImageViaNative() {
103937
104515
  return null;
103938
104516
  }
103939
104517
  }
103940
- async function readClipboardImage(options) {
104518
+ async function readClipboardMedia(options) {
103941
104519
  const env = options?.env ?? process.env;
103942
104520
  const platform = options?.platform ?? process.platform;
104521
+ const clip = options?.clipboard ?? clipboard;
104522
+ const run = options?.runCommand ?? runCommand;
103943
104523
  if (env["TERMUX_VERSION"] !== void 0) return null;
103944
104524
  let image = null;
103945
104525
  if (platform === "linux") {
103946
104526
  const wayland = isWaylandSession(env);
103947
104527
  const wsl = isWSL(env);
103948
- if (wayland || wsl) image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();
104528
+ if (wayland || wsl) {
104529
+ const fileMedia = readClipboardFileMediaViaWlPaste() ?? readClipboardFileMediaViaXclip();
104530
+ if (fileMedia !== null) return fileMedia;
104531
+ image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();
104532
+ }
103949
104533
  if (image === null && wsl) image = readClipboardImageViaPowerShell();
103950
- if (image === null && !wayland) image = await readClipboardImageViaNative();
103951
- } else image = await readClipboardImageViaNative();
103952
- if (image === null) return null;
103953
- if (!isSupportedImageMimeType(image.mimeType)) return null;
103954
- return image;
103955
- }
103956
- //#endregion
103957
- //#region src/utils/image/image-mime.ts
103958
- function parseImageMeta(bytes) {
103959
- if (isPng(bytes)) return parsePng(bytes);
103960
- if (isJpeg(bytes)) return parseJpeg(bytes);
103961
- if (isGif(bytes)) return parseGif(bytes);
103962
- if (isWebp(bytes)) return parseWebp(bytes);
103963
- return null;
103964
- }
103965
- function isPng(b) {
103966
- return b.length >= 8 && b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71 && b[4] === 13 && b[5] === 10 && b[6] === 26 && b[7] === 10;
103967
- }
103968
- function parsePng(b) {
103969
- if (b.length < 24) return null;
103970
- const width = readUInt32BE(b, 16);
103971
- const height = readUInt32BE(b, 20);
103972
- if (width <= 0 || height <= 0) return null;
103973
- return {
103974
- mime: "image/png",
103975
- width,
103976
- height
103977
- };
103978
- }
103979
- function isJpeg(b) {
103980
- return b.length >= 3 && b[0] === 255 && b[1] === 216 && b[2] === 255;
103981
- }
103982
- function parseJpeg(b) {
103983
- let i = 2;
103984
- while (i < b.length) {
103985
- if (b[i] !== 255) {
103986
- i += 1;
103987
- continue;
104534
+ if (image === null && !wayland) {
104535
+ const nativeFileMedia = await readClipboardFileMediaViaNativeText(clip);
104536
+ if (nativeFileMedia.media !== null) return nativeFileMedia.media;
104537
+ if (nativeFileMedia.lookedFileLike) return null;
104538
+ image = await readClipboardImageViaNative(clip);
103988
104539
  }
103989
- while (i < b.length && b[i] === 255) i += 1;
103990
- if (i >= b.length) return null;
103991
- const marker = b[i];
103992
- i += 1;
103993
- if (marker === 216 || marker === 217) continue;
103994
- if (i + 1 >= b.length) return null;
103995
- const segLen = readUInt16BE(b, i);
103996
- if (isSofMarker(marker)) {
103997
- if (i + 7 >= b.length) return null;
103998
- const height = readUInt16BE(b, i + 3);
103999
- const width = readUInt16BE(b, i + 5);
104000
- if (width <= 0 || height <= 0) return null;
104001
- return {
104002
- mime: "image/jpeg",
104003
- width,
104004
- height
104005
- };
104540
+ } else {
104541
+ if (platform === "darwin") {
104542
+ const fileMedia = readMediaFromPaths(readClipboardFilePathsViaMacOs(run));
104543
+ if (fileMedia !== null) return fileMedia;
104006
104544
  }
104007
- i += segLen;
104545
+ const nativeFileMedia = await readClipboardFileMediaViaNativeText(clip);
104546
+ if (nativeFileMedia.media !== null) return nativeFileMedia.media;
104547
+ if (platform === "darwin" && nativeFileMedia.lookedFileLike) return null;
104548
+ image = await readClipboardImageViaNative(clip);
104008
104549
  }
104009
- return null;
104010
- }
104011
- function isSofMarker(marker) {
104012
- if (marker < 192 || marker > 207) return false;
104013
- return marker !== 196 && marker !== 200 && marker !== 204;
104014
- }
104015
- function isGif(b) {
104016
- return b.length >= 6 && b[0] === 71 && b[1] === 73 && b[2] === 70 && b[3] === 56 && (b[4] === 55 || b[4] === 57) && b[5] === 97;
104017
- }
104018
- function parseGif(b) {
104019
- if (b.length < 10) return null;
104020
- const width = readUInt16LE(b, 6);
104021
- const height = readUInt16LE(b, 8);
104022
- if (width <= 0 || height <= 0) return null;
104023
- return {
104024
- mime: "image/gif",
104025
- width,
104026
- height
104027
- };
104028
- }
104029
- function isWebp(b) {
104030
- return b.length >= 12 && b[0] === 82 && b[1] === 73 && b[2] === 70 && b[3] === 70 && b[8] === 87 && b[9] === 69 && b[10] === 66 && b[11] === 80;
104031
- }
104032
- function parseWebp(b) {
104033
- if (b.length < 30) return null;
104034
- const chunk = String.fromCharCode(b[12], b[13], b[14], b[15]);
104035
- if (chunk === "VP8 ") {
104036
- const widthRaw = readUInt16LE(b, 26);
104037
- const heightRaw = readUInt16LE(b, 28);
104038
- const width = widthRaw & 16383;
104039
- const height = heightRaw & 16383;
104040
- if (width <= 0 || height <= 0) return null;
104041
- return {
104042
- mime: "image/webp",
104043
- width,
104044
- height
104045
- };
104046
- }
104047
- if (chunk === "VP8L") {
104048
- if (b[20] !== 47) return null;
104049
- const b1 = b[21];
104050
- const b2 = b[22];
104051
- const b3 = b[23];
104052
- const b4 = b[24];
104053
- const width = 1 + ((b2 & 63) << 8 | b1);
104054
- const height = 1 + ((b4 & 15) << 10 | b3 << 2 | (b2 & 192) >> 6);
104055
- if (width <= 0 || height <= 0) return null;
104056
- return {
104057
- mime: "image/webp",
104058
- width,
104059
- height
104060
- };
104061
- }
104062
- if (chunk === "VP8X") {
104063
- const width = 1 + readUInt24LE(b, 24);
104064
- const height = 1 + readUInt24LE(b, 27);
104065
- if (width <= 0 || height <= 0) return null;
104066
- return {
104067
- mime: "image/webp",
104068
- width,
104069
- height
104070
- };
104071
- }
104072
- return null;
104073
- }
104074
- function readUInt16BE(b, off) {
104075
- return b[off] << 8 | b[off + 1];
104076
- }
104077
- function readUInt16LE(b, off) {
104078
- return b[off] | b[off + 1] << 8;
104079
- }
104080
- function readUInt24LE(b, off) {
104081
- return b[off] | b[off + 1] << 8 | b[off + 2] << 16;
104082
- }
104083
- function readUInt32BE(b, off) {
104084
- return b[off] * 16777216 + (b[off + 1] << 16) + (b[off + 2] << 8) + b[off + 3] >>> 0;
104550
+ if (image === null) return null;
104551
+ if (!isSupportedImageMimeType(image.mimeType)) return null;
104552
+ return image;
104085
104553
  }
104086
104554
  //#endregion
104087
104555
  //#region src/tui/components/editor/file-mention-provider.ts
@@ -104278,15 +104746,18 @@ function toItem(path) {
104278
104746
  //#endregion
104279
104747
  //#region src/tui/components/layout/bottom-pinned-layout.ts
104280
104748
  var BottomPinnedLayout = class {
104281
- constructor(terminal, body, bottom) {
104749
+ constructor(terminal, body, bottom, state) {
104282
104750
  this.terminal = terminal;
104283
104751
  this.body = body;
104284
104752
  this.bottom = bottom;
104753
+ this.state = state;
104285
104754
  }
104286
104755
  render(width) {
104287
104756
  const bodyLines = this.body.render(width);
104288
104757
  const bottomLines = this.bottom.flatMap((component) => component.render(width));
104289
- if (bodyLines.length + bottomLines.length < this.terminal.rows) return [...bodyLines, ...bottomLines];
104758
+ const totalHeight = bodyLines.length + bottomLines.length;
104759
+ if (!this.state.hasFilledViewport && totalHeight < this.terminal.rows) return [...bodyLines, ...bottomLines];
104760
+ this.state.hasFilledViewport = true;
104290
104761
  const spacerHeight = Math.max(0, this.terminal.rows - bodyLines.length - bottomLines.length);
104291
104762
  return [
104292
104763
  ...bodyLines,
@@ -104387,11 +104858,26 @@ function setupEditor(state, cb) {
104387
104858
  editor.onPasteImage = async () => handleClipboardImagePaste(state);
104388
104859
  }
104389
104860
  async function handleClipboardImagePaste(state) {
104390
- const image = await readClipboardImage();
104391
- if (image === null) return false;
104392
- const meta = parseImageMeta(image.bytes);
104861
+ let media;
104862
+ try {
104863
+ media = await readClipboardMedia();
104864
+ } catch (error) {
104865
+ if (error instanceof ClipboardMediaError) {
104866
+ emitError(state, error.message);
104867
+ return true;
104868
+ }
104869
+ return false;
104870
+ }
104871
+ if (media === null) return false;
104872
+ if (media.kind === "video") {
104873
+ const attachment = state.imageStore.addVideo(media.mimeType, media.sourcePath, media.filename);
104874
+ state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
104875
+ state.ui.requestRender();
104876
+ return true;
104877
+ }
104878
+ const meta = parseImageMeta(media.bytes);
104393
104879
  if (meta === null) return false;
104394
- const attachment = state.imageStore.add(image.bytes, meta.mime, meta.width, meta.height);
104880
+ const attachment = state.imageStore.addImage(media.bytes, meta.mime, meta.width, meta.height);
104395
104881
  state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
104396
104882
  state.ui.requestRender();
104397
104883
  return true;
@@ -104410,7 +104896,7 @@ function buildLayout(state) {
104410
104896
  state.queueContainer,
104411
104897
  state.editorContainer,
104412
104898
  state.footer
104413
- ]));
104899
+ ], state.bottomLayoutState));
104414
104900
  }
104415
104901
  /**
104416
104902
  * Register the file-mention + slash-command autocomplete provider on
@@ -104677,7 +105163,10 @@ var KimiTUI = class {
104677
105163
  sendSkillActivation(this.state, (e) => this.addEntry(e), item.skillName, item.skillArgs, item.fullPrompt);
104678
105164
  return;
104679
105165
  }
104680
- sendMessageInternal(this.state, (e) => this.addEntry(e), item.text);
105166
+ sendMessageInternal(this.state, (e) => this.addEntry(e), item.text, {
105167
+ ...item.parts !== void 0 ? { parts: item.parts } : {},
105168
+ ...item.imageAttachmentIds !== void 0 ? { imageAttachmentIds: item.imageAttachmentIds } : {}
105169
+ });
104681
105170
  };
104682
105171
  subscribeToWire(this.state, (event) => {
104683
105172
  dispatchEvent(event, ectx, sendQueued);