blun-king-cli 9.1.615 → 9.1.616

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/blun.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:57a7160081cd6a2ce9e3535b31b87f9410c0dafd58da9629b68cb0042a8e57e5
2
+ // BLUN_BUILD_INPUT_SHA256:8034cba54fd011bf9ce255483d60f6d12f8cdb9862b405ccf424ae40ac14b7c5
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
6
6
  const __dirname = __cjsShimDirname(__filename);
7
7
  import { createRequire } from "node:module";
8
8
  import crypto$1, { createHash, createHmac, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
9
- import * as fs$16 from "node:fs";
9
+ import * as fs$17 from "node:fs";
10
10
  import Kt, { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, opendirSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
11
- import * as path$16 from "node:path";
11
+ import * as path$17 from "node:path";
12
12
  import path, { basename, dirname, extname, isAbsolute, join, normalize, parse, posix, relative, resolve, sep, win32 } from "node:path";
13
13
  import { Blob as Blob$1, Buffer as Buffer$1, File as File$1 } from "node:buffer";
14
14
  import ro, { access, appendFile, chmod, constants as constants$1, copyFile, cp, link, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
@@ -2271,11 +2271,11 @@ var init_blun_files = __esmMin((() => {
2271
2271
  async uploadVideo(input, options) {
2272
2272
  let file;
2273
2273
  if (typeof input === "string") {
2274
- if (!fs$16.existsSync(input)) throw new ChatProviderError(`Video file not found: ${input}`);
2275
- const filename = path$16.basename(input);
2274
+ if (!fs$17.existsSync(input)) throw new ChatProviderError(`Video file not found: ${input}`);
2275
+ const filename = path$17.basename(input);
2276
2276
  const mimeType = guessMimeTypeFromExt(filename);
2277
2277
  if (mimeType === void 0 || !mimeType.startsWith("video/")) throw new ChatProviderError(`BlunFiles.uploadVideo: file extension does not indicate a video type: ${filename}`);
2278
- const data = await fs$16.promises.readFile(input);
2278
+ const data = await fs$17.promises.readFile(input);
2279
2279
  file = new File$1([new Blob$1([new Uint8Array(data)], { type: mimeType })], filename, { type: mimeType });
2280
2280
  } else {
2281
2281
  if (!input.mimeType.startsWith("video/")) throw new ChatProviderError(`Expected a video mime type, got ${input.mimeType}`);
@@ -10501,7 +10501,17 @@ async function canonicalWriterPath(target) {
10501
10501
  async function readOwner(lockDirectory) {
10502
10502
  const directory = await lstat(lockDirectory);
10503
10503
  if (!directory.isDirectory() || directory.isSymbolicLink()) throw unavailable();
10504
- const names = await readdir(lockDirectory);
10504
+ let names;
10505
+ try {
10506
+ names = await readdir(lockDirectory);
10507
+ } catch (error) {
10508
+ if (process.platform === "win32" && codeOf(error) === "EPERM") try {
10509
+ await lstat(lockDirectory);
10510
+ } catch (inspectionError) {
10511
+ if (codeOf(inspectionError) === "ENOENT") throw inspectionError;
10512
+ }
10513
+ throw error;
10514
+ }
10505
10515
  if (names.length === 0) return void 0;
10506
10516
  const name = names[0];
10507
10517
  const match = markerPattern.exec(name);
@@ -10576,7 +10586,10 @@ async function reclaimDeadOwner(lockDirectory) {
10576
10586
  }
10577
10587
  }
10578
10588
  /** A local-host writer claim. It never expires based on age or missed heartbeats. */
10579
- async function acquireSessionWriter(sessionDirectory) {
10589
+ async function acquireSessionWriter(sessionDirectory, options = {}) {
10590
+ const waitForBusyMs = options.waitForBusyMs ?? 0;
10591
+ if (!Number.isFinite(waitForBusyMs) || waitForBusyMs < 0 || waitForBusyMs > 5e3) throw new RangeError("Writer contention budget must be between 0 and 5000 milliseconds");
10592
+ const deadline = performance.now() + waitForBusyMs;
10580
10593
  let staged;
10581
10594
  let name;
10582
10595
  try {
@@ -10595,7 +10608,8 @@ async function acquireSessionWriter(sessionDirectory) {
10595
10608
  flag: "wx",
10596
10609
  mode: 384
10597
10610
  });
10598
- for (let attempt = 0; attempt < 8; attempt += 1) {
10611
+ let unownedCollisions = 0;
10612
+ for (;;) {
10599
10613
  try {
10600
10614
  await rename(staged, lockDirectory);
10601
10615
  } catch (error) {
@@ -10605,7 +10619,19 @@ async function acquireSessionWriter(sessionDirectory) {
10605
10619
  "EPERM",
10606
10620
  "EACCES"
10607
10621
  ].includes(codeOf(error) ?? "")) throw error;
10608
- await reclaimDeadOwner(lockDirectory);
10622
+ try {
10623
+ await reclaimDeadOwner(lockDirectory);
10624
+ } catch (ownershipError) {
10625
+ if (!(ownershipError instanceof BlunError) || ownershipError.code !== ErrorCodes.SESSION_WRITER_BUSY) throw ownershipError;
10626
+ const remaining = deadline - performance.now();
10627
+ if (waitForBusyMs === 0 || remaining <= 0) throw ownershipError;
10628
+ await new Promise((resolve) => {
10629
+ setTimeout(resolve, Math.min(25, remaining));
10630
+ });
10631
+ unownedCollisions = 0;
10632
+ continue;
10633
+ }
10634
+ if (++unownedCollisions >= 8) throw unavailable();
10609
10635
  continue;
10610
10636
  }
10611
10637
  let released = false;
@@ -10628,7 +10654,6 @@ async function acquireSessionWriter(sessionDirectory) {
10628
10654
  }
10629
10655
  };
10630
10656
  }
10631
- throw unavailable();
10632
10657
  } catch (error) {
10633
10658
  if (error instanceof BlunError) throw error;
10634
10659
  throw unavailable(error);
@@ -11959,7 +11984,7 @@ var require_clone$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
11959
11984
  //#endregion
11960
11985
  //#region ../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js
11961
11986
  var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
11962
- var fs$15 = __require("fs");
11987
+ var fs$16 = __require("fs");
11963
11988
  var polyfills = require_polyfills();
11964
11989
  var legacy = require_legacy_streams();
11965
11990
  var clone = require_clone$1();
@@ -11988,36 +12013,36 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
11988
12013
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
11989
12014
  console.error(m);
11990
12015
  };
11991
- if (!fs$15[gracefulQueue]) {
11992
- publishQueue(fs$15, global[gracefulQueue] || []);
11993
- fs$15.close = (function(fs$close) {
12016
+ if (!fs$16[gracefulQueue]) {
12017
+ publishQueue(fs$16, global[gracefulQueue] || []);
12018
+ fs$16.close = (function(fs$close) {
11994
12019
  function close(fd, cb) {
11995
- return fs$close.call(fs$15, fd, function(err) {
12020
+ return fs$close.call(fs$16, fd, function(err) {
11996
12021
  if (!err) resetQueue();
11997
12022
  if (typeof cb === "function") cb.apply(this, arguments);
11998
12023
  });
11999
12024
  }
12000
12025
  Object.defineProperty(close, previousSymbol, { value: fs$close });
12001
12026
  return close;
12002
- })(fs$15.close);
12003
- fs$15.closeSync = (function(fs$closeSync) {
12027
+ })(fs$16.close);
12028
+ fs$16.closeSync = (function(fs$closeSync) {
12004
12029
  function closeSync(fd) {
12005
- fs$closeSync.apply(fs$15, arguments);
12030
+ fs$closeSync.apply(fs$16, arguments);
12006
12031
  resetQueue();
12007
12032
  }
12008
12033
  Object.defineProperty(closeSync, previousSymbol, { value: fs$closeSync });
12009
12034
  return closeSync;
12010
- })(fs$15.closeSync);
12035
+ })(fs$16.closeSync);
12011
12036
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) process.on("exit", function() {
12012
- debug(fs$15[gracefulQueue]);
12013
- __require("assert").equal(fs$15[gracefulQueue].length, 0);
12037
+ debug(fs$16[gracefulQueue]);
12038
+ __require("assert").equal(fs$16[gracefulQueue].length, 0);
12014
12039
  });
12015
12040
  }
12016
- if (!global[gracefulQueue]) publishQueue(global, fs$15[gracefulQueue]);
12017
- module.exports = patch(clone(fs$15));
12018
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs$15.__patched) {
12019
- module.exports = patch(fs$15);
12020
- fs$15.__patched = true;
12041
+ if (!global[gracefulQueue]) publishQueue(global, fs$16[gracefulQueue]);
12042
+ module.exports = patch(clone(fs$16));
12043
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs$16.__patched) {
12044
+ module.exports = patch(fs$16);
12045
+ fs$16.__patched = true;
12021
12046
  }
12022
12047
  function patch(fs) {
12023
12048
  polyfills(fs);
@@ -12272,23 +12297,23 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
12272
12297
  }
12273
12298
  function enqueue(elem) {
12274
12299
  debug("ENQUEUE", elem[0].name, elem[1]);
12275
- fs$15[gracefulQueue].push(elem);
12300
+ fs$16[gracefulQueue].push(elem);
12276
12301
  retry();
12277
12302
  }
12278
12303
  var retryTimer;
12279
12304
  function resetQueue() {
12280
12305
  var now = Date.now();
12281
- for (var i = 0; i < fs$15[gracefulQueue].length; ++i) if (fs$15[gracefulQueue][i].length > 2) {
12282
- fs$15[gracefulQueue][i][3] = now;
12283
- fs$15[gracefulQueue][i][4] = now;
12306
+ for (var i = 0; i < fs$16[gracefulQueue].length; ++i) if (fs$16[gracefulQueue][i].length > 2) {
12307
+ fs$16[gracefulQueue][i][3] = now;
12308
+ fs$16[gracefulQueue][i][4] = now;
12284
12309
  }
12285
12310
  retry();
12286
12311
  }
12287
12312
  function retry() {
12288
12313
  clearTimeout(retryTimer);
12289
12314
  retryTimer = void 0;
12290
- if (fs$15[gracefulQueue].length === 0) return;
12291
- var elem = fs$15[gracefulQueue].shift();
12315
+ if (fs$16[gracefulQueue].length === 0) return;
12316
+ var elem = fs$16[gracefulQueue].shift();
12292
12317
  var fn = elem[0];
12293
12318
  var args = elem[1];
12294
12319
  var err = elem[2];
@@ -12307,7 +12332,7 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
12307
12332
  if (sinceAttempt >= Math.min(sinceStart * 1.2, 100)) {
12308
12333
  debug("RETRY", fn.name, args);
12309
12334
  fn.apply(null, args.concat([startTime]));
12310
- } else fs$15[gracefulQueue].push(elem);
12335
+ } else fs$16[gracefulQueue].push(elem);
12311
12336
  }
12312
12337
  if (retryTimer === void 0) retryTimer = setTimeout(retry, 0);
12313
12338
  }
@@ -12659,7 +12684,7 @@ var require_mtime_precision = /* @__PURE__ */ __commonJSMin(((exports, module) =
12659
12684
  //#endregion
12660
12685
  //#region ../../node_modules/.pnpm/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/lockfile.js
12661
12686
  var require_lockfile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
12662
- const path$15 = __require("path");
12687
+ const path$16 = __require("path");
12663
12688
  const fs = require_graceful_fs();
12664
12689
  const retry = require_retry$3();
12665
12690
  const onExit = require_signal_exit();
@@ -12669,7 +12694,7 @@ var require_lockfile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
12669
12694
  return options.lockfilePath || `${file}.lock`;
12670
12695
  }
12671
12696
  function resolveCanonicalPath(file, options, callback) {
12672
- if (!options.realpath) return callback(null, path$15.resolve(file));
12697
+ if (!options.realpath) return callback(null, path$16.resolve(file));
12673
12698
  options.fs.realpath(file, callback);
12674
12699
  }
12675
12700
  function acquireLock(file, options, callback) {
@@ -15185,7 +15210,7 @@ async function syncDir(dirPath) {
15185
15210
  */
15186
15211
  function syncFd(fd) {
15187
15212
  return new Promise((resolve, reject) => {
15188
- fs$16.fsync(fd, (err) => {
15213
+ fs$17.fsync(fd, (err) => {
15189
15214
  if (err) {
15190
15215
  reject(err);
15191
15216
  return;
@@ -16932,16 +16957,11 @@ function configWriterError(error) {
16932
16957
  return error;
16933
16958
  }
16934
16959
  async function acquireConfigWriter(filePath) {
16935
- const deadline = performance.now() + 5e3;
16936
- for (;;) try {
16937
- return await acquireSessionWriter(filePath);
16960
+ try {
16961
+ return await acquireSessionWriter(filePath, { waitForBusyMs: 5e3 });
16938
16962
  } catch (error) {
16939
16963
  if (!(error instanceof BlunError) || error.code !== ErrorCodes.SESSION_WRITER_BUSY) throw error;
16940
- const remaining = deadline - performance.now();
16941
- if (remaining <= 0) throw new BlunError(ErrorCodes.CONFIG_WRITE_BUSY, "Another configuration change is still being saved", { cause: error });
16942
- await new Promise((resolve) => {
16943
- setTimeout(resolve, Math.min(25, remaining));
16944
- });
16964
+ throw new BlunError(ErrorCodes.CONFIG_WRITE_BUSY, "Another configuration change is still being saved", { cause: error });
16945
16965
  }
16946
16966
  }
16947
16967
  /** Keep transforms synchronous; credential validation and discovery belong before this boundary. */
@@ -26235,7 +26255,7 @@ var require_loader = /* @__PURE__ */ __commonJSMin(((exports, module) => {
26235
26255
  };
26236
26256
  return _setPrototypeOf(o, p);
26237
26257
  }
26238
- var path$14 = __require("path");
26258
+ var path$15 = __require("path");
26239
26259
  module.exports = /* @__PURE__ */ function(_EmitterObj) {
26240
26260
  _inheritsLoose(Loader, _EmitterObj);
26241
26261
  function Loader() {
@@ -26243,7 +26263,7 @@ var require_loader = /* @__PURE__ */ __commonJSMin(((exports, module) => {
26243
26263
  }
26244
26264
  var _proto = Loader.prototype;
26245
26265
  _proto.resolve = function resolve(from, to) {
26246
- return path$14.resolve(path$14.dirname(from), to);
26266
+ return path$15.resolve(path$15.dirname(from), to);
26247
26267
  };
26248
26268
  _proto.isRelative = function isRelative(filename) {
26249
26269
  return filename.indexOf("./") === 0 || filename.indexOf("../") === 0;
@@ -27899,8 +27919,8 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27899
27919
  };
27900
27920
  return _setPrototypeOf(o, p);
27901
27921
  }
27902
- var fs$14 = __require("fs");
27903
- var path$13 = __require("path");
27922
+ var fs$15 = __require("fs");
27923
+ var path$14 = __require("path");
27904
27924
  var Loader = require_loader();
27905
27925
  var PrecompiledLoader = require_precompiled_loader().PrecompiledLoader;
27906
27926
  var chokidar;
@@ -27915,7 +27935,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27915
27935
  _this.noCache = !!opts.noCache;
27916
27936
  if (searchPaths) {
27917
27937
  searchPaths = Array.isArray(searchPaths) ? searchPaths : [searchPaths];
27918
- _this.searchPaths = searchPaths.map(path$13.normalize);
27938
+ _this.searchPaths = searchPaths.map(path$14.normalize);
27919
27939
  } else _this.searchPaths = ["."];
27920
27940
  if (opts.watch) {
27921
27941
  try {
@@ -27923,10 +27943,10 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27923
27943
  } catch (e) {
27924
27944
  throw new Error("watch requires chokidar to be installed");
27925
27945
  }
27926
- var paths = _this.searchPaths.filter(fs$14.existsSync);
27946
+ var paths = _this.searchPaths.filter(fs$15.existsSync);
27927
27947
  var watcher = chokidar.watch(paths);
27928
27948
  watcher.on("all", function(event, fullname) {
27929
- fullname = path$13.resolve(fullname);
27949
+ fullname = path$14.resolve(fullname);
27930
27950
  if (event === "change" && fullname in _this.pathsToNames) _this.emit("update", _this.pathsToNames[fullname], fullname);
27931
27951
  });
27932
27952
  watcher.on("error", function(error) {
@@ -27940,9 +27960,9 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27940
27960
  var fullpath = null;
27941
27961
  var paths = this.searchPaths;
27942
27962
  for (var i = 0; i < paths.length; i++) {
27943
- var basePath = path$13.resolve(paths[i]);
27944
- var p = path$13.resolve(paths[i], name);
27945
- if (p.indexOf(basePath) === 0 && fs$14.existsSync(p)) {
27963
+ var basePath = path$14.resolve(paths[i]);
27964
+ var p = path$14.resolve(paths[i], name);
27965
+ if (p.indexOf(basePath) === 0 && fs$15.existsSync(p)) {
27946
27966
  fullpath = p;
27947
27967
  break;
27948
27968
  }
@@ -27950,7 +27970,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27950
27970
  if (!fullpath) return null;
27951
27971
  this.pathsToNames[fullpath] = name;
27952
27972
  var source = {
27953
- src: fs$14.readFileSync(fullpath, "utf-8"),
27973
+ src: fs$15.readFileSync(fullpath, "utf-8"),
27954
27974
  path: fullpath,
27955
27975
  noCache: this.noCache
27956
27976
  };
@@ -27998,7 +28018,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
27998
28018
  }
27999
28019
  this.pathsToNames[fullpath] = name;
28000
28020
  var source = {
28001
- src: fs$14.readFileSync(fullpath, "utf-8"),
28021
+ src: fs$15.readFileSync(fullpath, "utf-8"),
28002
28022
  path: fullpath,
28003
28023
  noCache: this.noCache
28004
28024
  };
@@ -28300,13 +28320,13 @@ var require_globals = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28300
28320
  //#endregion
28301
28321
  //#region ../../node_modules/.pnpm/nunjucks@3.2.4_chokidar@4.0.3/node_modules/nunjucks/src/express-app.js
28302
28322
  var require_express_app = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28303
- var path$12 = __require("path");
28323
+ var path$13 = __require("path");
28304
28324
  module.exports = function express(env, app) {
28305
28325
  function NunjucksView(name, opts) {
28306
28326
  this.name = name;
28307
28327
  this.path = name;
28308
28328
  this.defaultEngine = opts.defaultEngine;
28309
- this.ext = path$12.extname(name);
28329
+ this.ext = path$13.extname(name);
28310
28330
  if (!this.ext && !this.defaultEngine) throw new Error("No default engine was specified and no extension was provided.");
28311
28331
  if (!this.ext) this.name += this.ext = (this.defaultEngine[0] !== "." ? "." : "") + this.defaultEngine;
28312
28332
  }
@@ -28742,8 +28762,8 @@ var require_precompile_global = /* @__PURE__ */ __commonJSMin(((exports, module)
28742
28762
  //#endregion
28743
28763
  //#region ../../node_modules/.pnpm/nunjucks@3.2.4_chokidar@4.0.3/node_modules/nunjucks/src/precompile.js
28744
28764
  var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28745
- var fs$13 = __require("fs");
28746
- var path$11 = __require("path");
28765
+ var fs$14 = __require("fs");
28766
+ var path$12 = __require("path");
28747
28767
  var _prettifyError = require_lib$8()._prettifyError;
28748
28768
  var compiler = require_compiler();
28749
28769
  var Environment = require_environment().Environment;
@@ -28767,27 +28787,27 @@ var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28767
28787
  var env = opts.env || new Environment([]);
28768
28788
  var wrapper = opts.wrapper || precompileGlobal;
28769
28789
  if (opts.isString) return precompileString(input, opts);
28770
- var pathStats = fs$13.existsSync(input) && fs$13.statSync(input);
28790
+ var pathStats = fs$14.existsSync(input) && fs$14.statSync(input);
28771
28791
  var precompiled = [];
28772
28792
  var templates = [];
28773
28793
  function addTemplates(dir) {
28774
- fs$13.readdirSync(dir).forEach(function(file) {
28775
- var filepath = path$11.join(dir, file);
28776
- var subpath = filepath.substr(path$11.join(input, "/").length);
28777
- var stat = fs$13.statSync(filepath);
28794
+ fs$14.readdirSync(dir).forEach(function(file) {
28795
+ var filepath = path$12.join(dir, file);
28796
+ var subpath = filepath.substr(path$12.join(input, "/").length);
28797
+ var stat = fs$14.statSync(filepath);
28778
28798
  if (stat && stat.isDirectory()) {
28779
28799
  subpath += "/";
28780
28800
  if (!match(subpath, opts.exclude)) addTemplates(filepath);
28781
28801
  } else if (match(subpath, opts.include)) templates.push(filepath);
28782
28802
  });
28783
28803
  }
28784
- if (pathStats.isFile()) precompiled.push(_precompile(fs$13.readFileSync(input, "utf-8"), opts.name || input, env));
28804
+ if (pathStats.isFile()) precompiled.push(_precompile(fs$14.readFileSync(input, "utf-8"), opts.name || input, env));
28785
28805
  else if (pathStats.isDirectory()) {
28786
28806
  addTemplates(input);
28787
28807
  for (var i = 0; i < templates.length; i++) {
28788
- var name = templates[i].replace(path$11.join(input, "/"), "");
28808
+ var name = templates[i].replace(path$12.join(input, "/"), "");
28789
28809
  try {
28790
- precompiled.push(_precompile(fs$13.readFileSync(templates[i], "utf-8"), name, env));
28810
+ precompiled.push(_precompile(fs$14.readFileSync(templates[i], "utf-8"), name, env));
28791
28811
  } catch (e) {
28792
28812
  if (opts.force) console.error(e);
28793
28813
  else throw e;
@@ -30623,7 +30643,7 @@ var init_persistence = __esmMin((() => {
30623
30643
  async *readFrom(offset, recordCount) {
30624
30644
  if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(recordCount) || recordCount < 0) throw new Error("Invalid Wire replay offset");
30625
30645
  await this.flush();
30626
- let line = "";
30646
+ const fragments = [];
30627
30647
  let lineNumber = recordCount;
30628
30648
  let byteLength = offset;
30629
30649
  const stream = createReadStream(this.filePath, {
@@ -30632,29 +30652,36 @@ var init_persistence = __esmMin((() => {
30632
30652
  });
30633
30653
  try {
30634
30654
  for await (const chunk of stream) {
30635
- line += chunk;
30636
- let newlineIndex = line.indexOf("\n");
30655
+ let start = 0;
30656
+ let newlineIndex = chunk.indexOf("\n", start);
30637
30657
  while (newlineIndex !== -1) {
30638
- const rawLine = line.slice(0, newlineIndex);
30639
- line = line.slice(newlineIndex + 1);
30658
+ const part = chunk.slice(start, newlineIndex);
30659
+ let rawLine = part;
30660
+ if (fragments.length > 0) {
30661
+ fragments.push(part);
30662
+ rawLine = fragments.join("");
30663
+ fragments.length = 0;
30664
+ }
30640
30665
  lineNumber++;
30641
30666
  byteLength += Buffer.byteLength(rawLine, "utf8") + 1;
30642
30667
  const record = parseRecordLine(rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine, lineNumber, this.filePath, false);
30643
30668
  if (record !== void 0) yield record;
30644
- newlineIndex = line.indexOf("\n");
30669
+ start = newlineIndex + 1;
30670
+ newlineIndex = chunk.indexOf("\n", start);
30645
30671
  }
30672
+ if (start < chunk.length) fragments.push(chunk.slice(start));
30646
30673
  }
30647
30674
  } catch (error) {
30648
30675
  if (error.code === "ENOENT") return;
30649
30676
  throw error;
30650
30677
  }
30651
- if (line.length > 0) {
30678
+ if (fragments.length > 0) {
30652
30679
  lineNumber++;
30653
- const record = parseRecordLine(line, lineNumber, this.filePath, true);
30680
+ const record = parseRecordLine(fragments.join(""), lineNumber, this.filePath, true);
30654
30681
  if (record !== void 0) yield record;
30655
30682
  }
30656
30683
  this.persistedRecordCount = lineNumber;
30657
- this.persistedByteLength = line.length === 0 ? byteLength : void 0;
30684
+ this.persistedByteLength = fragments.length === 0 ? byteLength : void 0;
30658
30685
  }
30659
30686
  append(input) {
30660
30687
  this.throwIfError();
@@ -32828,7 +32855,7 @@ var require_buffer_from = /* @__PURE__ */ __commonJSMin(((exports, module) => {
32828
32855
  //#region ../../node_modules/.pnpm/source-map-support@0.5.21/node_modules/source-map-support/source-map-support.js
32829
32856
  var require_source_map_support = /* @__PURE__ */ __commonJSMin(((exports, module) => {
32830
32857
  var SourceMapConsumer = require_source_map().SourceMapConsumer;
32831
- var path$10 = __require("path");
32858
+ var path$11 = __require("path");
32832
32859
  var fs;
32833
32860
  try {
32834
32861
  fs = __require("fs");
@@ -32905,15 +32932,15 @@ var require_source_map_support = /* @__PURE__ */ __commonJSMin(((exports, module
32905
32932
  });
32906
32933
  function supportRelativeURL(file, url) {
32907
32934
  if (!file) return url;
32908
- var dir = path$10.dirname(file);
32935
+ var dir = path$11.dirname(file);
32909
32936
  var match = /^\w+:\/\/[^\/]*/.exec(dir);
32910
32937
  var protocol = match ? match[0] : "";
32911
32938
  var startPath = dir.slice(protocol.length);
32912
32939
  if (protocol && /^\/\w\:/.test(startPath)) {
32913
32940
  protocol += "/";
32914
- return protocol + path$10.resolve(dir.slice(protocol.length), url).replace(/\\/g, "/");
32941
+ return protocol + path$11.resolve(dir.slice(protocol.length), url).replace(/\\/g, "/");
32915
32942
  }
32916
- return protocol + path$10.resolve(dir.slice(protocol.length), url);
32943
+ return protocol + path$11.resolve(dir.slice(protocol.length), url);
32917
32944
  }
32918
32945
  function retrieveSourceMapURL(source) {
32919
32946
  var fileData;
@@ -192321,7 +192348,7 @@ var require_gifframe = /* @__PURE__ */ __commonJSMin(((exports) => {
192321
192348
  //#region ../../node_modules/.pnpm/gifwrap@0.10.1/node_modules/gifwrap/src/gifutil.js
192322
192349
  var require_gifutil = /* @__PURE__ */ __commonJSMin(((exports) => {
192323
192350
  /** @namespace GifUtil */
192324
- const fs$12 = __require("fs");
192351
+ const fs$13 = __require("fs");
192325
192352
  const ImageQ = require_image_q();
192326
192353
  const BitmapImage = require_bitmapimage();
192327
192354
  const { GifFrame } = require_gifframe();
@@ -192588,7 +192615,7 @@ var require_gifutil = /* @__PURE__ */ __commonJSMin(((exports) => {
192588
192615
  }
192589
192616
  function _readBinary(path) {
192590
192617
  return new Promise((resolve, reject) => {
192591
- fs$12.readFile(path, (err, buffer) => {
192618
+ fs$13.readFile(path, (err, buffer) => {
192592
192619
  if (err) return reject(err);
192593
192620
  return resolve(buffer);
192594
192621
  });
@@ -192596,7 +192623,7 @@ var require_gifutil = /* @__PURE__ */ __commonJSMin(((exports) => {
192596
192623
  }
192597
192624
  function _writeBinary(path, buffer) {
192598
192625
  return new Promise((resolve, reject) => {
192599
- fs$12.writeFile(path, buffer, (err) => {
192626
+ fs$13.writeFile(path, buffer, (err) => {
192600
192627
  if (err) return reject(err);
192601
192628
  return resolve();
192602
192629
  });
@@ -229305,6 +229332,8 @@ async function compressImageForModel(bytes, mimeType, options = {}) {
229305
229332
  if (bytes.length <= byteBudget && (longestEdge > 0 && longestEdge <= maxEdge || longestEdge === 0)) return passthrough();
229306
229333
  if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return passthrough();
229307
229334
  if (bytes.length > maxDecodeBytes) return passthrough();
229335
+ const detected = detectFileType("", bytes.subarray(0, 512), "media");
229336
+ if (!RECODABLE_MIME.has(detected.mimeType)) return passthrough();
229308
229337
  try {
229309
229338
  const { Jimp } = await Promise.resolve().then(() => (init_esm$13(), esm_exports$3));
229310
229339
  const image = await Jimp.fromBuffer(Buffer.from(bytes));
@@ -232344,12 +232373,13 @@ function publicCronRun(run) {
232344
232373
  coalescedCount: receipt.coalescedCount,
232345
232374
  toolCalls: receipt.toolSummary.calls,
232346
232375
  toolErrors: receipt.toolSummary.errors,
232376
+ providerUsage: receipt.providerUsage ?? null,
232347
232377
  outputCount: receipt.outputs.length,
232348
232378
  finalMessageAvailable: run.finalMessage !== null,
232349
232379
  durable: run.durable
232350
232380
  };
232351
232381
  }
232352
- var CRON_RUN_OUTPUT_CHARS, CRON_RUN_TRUNCATION_MARKER, CronRunIdSchema, CronJobIdSchema, CronRunStatusSchema, counter, timestamp$1, CronRunReceiptSchema, CronFinalMessageSchema;
232382
+ var CRON_RUN_OUTPUT_CHARS, CRON_RUN_TRUNCATION_MARKER, CronRunIdSchema, CronJobIdSchema, CronRunStatusSchema, counter, timestamp$1, CronProviderUsageSchema, CronRunReceiptSchema, CronFinalMessageSchema;
232353
232383
  var init_run_types = __esmMin((() => {
232354
232384
  init_zod$1();
232355
232385
  CRON_RUN_OUTPUT_CHARS = 16 * 1024;
@@ -232367,6 +232397,13 @@ var init_run_types = __esmMin((() => {
232367
232397
  ]);
232368
232398
  counter = number$1().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
232369
232399
  timestamp$1 = string().datetime();
232400
+ CronProviderUsageSchema = object$1({
232401
+ inputOther: counter,
232402
+ inputCacheRead: counter,
232403
+ inputCacheCreation: counter,
232404
+ output: counter,
232405
+ outputReasoning: counter.optional()
232406
+ }).strict();
232370
232407
  CronRunReceiptSchema = object$1({
232371
232408
  runId: CronRunIdSchema,
232372
232409
  jobId: CronJobIdSchema,
@@ -232387,6 +232424,7 @@ var init_run_types = __esmMin((() => {
232387
232424
  names: array(string().regex(/^[\w.:-]{1,160}$/)).max(64),
232388
232425
  excessNames: counter
232389
232426
  }).strict(),
232427
+ providerUsage: CronProviderUsageSchema.nullable().optional(),
232390
232428
  outputs: array(object$1({
232391
232429
  rootRef: string().regex(/^(workspace|additional:[0-9]+)$/),
232392
232430
  path: string().min(1).max(1024).refine((value) => Buffer.byteLength(value) <= 1024 && !value.startsWith("/") && !value.includes("\\") && !value.includes(":") && !value.split("/").some((part) => part === ".." || part === ".") && !/[\u0000-\u001F\u007F]/.test(value))
@@ -232600,6 +232638,7 @@ function prefix(text) {
232600
232638
  }
232601
232639
  var CronRunOutputCollector;
232602
232640
  var init_run_output = __esmMin((() => {
232641
+ init_src$4();
232603
232642
  init_run_types();
232604
232643
  CronRunOutputCollector = class {
232605
232644
  roots;
@@ -232613,6 +232652,8 @@ var init_run_output = __esmMin((() => {
232613
232652
  errors = 0;
232614
232653
  excessNames = 0;
232615
232654
  outputs = [];
232655
+ providerUsage;
232656
+ usageComplete = true;
232616
232657
  invalid = false;
232617
232658
  constructor(roots) {
232618
232659
  this.roots = roots;
@@ -232633,6 +232674,7 @@ var init_run_output = __esmMin((() => {
232633
232674
  }
232634
232675
  if (event.type === "step.retrying") {
232635
232676
  if (event.turnId !== String(this.turnId)) return;
232677
+ this.usageComplete = false;
232636
232678
  if (this.step === void 0 || this.step.id !== event.stepUuid || this.step.step !== event.step || this.step.tools) this.invalid = true;
232637
232679
  else {
232638
232680
  this.step = {
@@ -232701,19 +232743,29 @@ var init_run_output = __esmMin((() => {
232701
232743
  } else if (event.type === "step.end") {
232702
232744
  const step = this.step;
232703
232745
  if (step === void 0 || event.uuid !== step.id || event.step !== step.step) this.invalid = true;
232704
- else if (event.finishReason === "end_turn" && !step.tools && !this.invalid) {
232705
- const clipped = prefix(step.text);
232706
- const truncated = step.chars > clipped.length;
232707
- const text = clipped + (truncated ? CRON_RUN_TRUNCATION_MARKER : "");
232708
- if (text) this.candidate = {
232709
- stepId: step.id,
232710
- turnId: this.turnId,
232711
- message: {
232712
- text,
232713
- truncated,
232714
- chars: step.chars
232715
- }
232716
- };
232746
+ else {
232747
+ const usage = event.usage === void 0 ? void 0 : CronProviderUsageSchema.safeParse(event.usage);
232748
+ if (usage?.success !== true) this.usageComplete = false;
232749
+ else {
232750
+ const total = this.providerUsage === void 0 ? usage.data : addUsage$1(this.providerUsage, usage.data);
232751
+ const checked = CronProviderUsageSchema.safeParse(total);
232752
+ if (checked.success) this.providerUsage = checked.data;
232753
+ else this.usageComplete = false;
232754
+ }
232755
+ if (event.finishReason === "end_turn" && !step.tools && !this.invalid) {
232756
+ const clipped = prefix(step.text);
232757
+ const truncated = step.chars > clipped.length;
232758
+ const text = clipped + (truncated ? CRON_RUN_TRUNCATION_MARKER : "");
232759
+ if (text) this.candidate = {
232760
+ stepId: step.id,
232761
+ turnId: this.turnId,
232762
+ message: {
232763
+ text,
232764
+ truncated,
232765
+ chars: step.chars
232766
+ }
232767
+ };
232768
+ }
232717
232769
  }
232718
232770
  this.step = void 0;
232719
232771
  }
@@ -232728,6 +232780,7 @@ var init_run_output = __esmMin((() => {
232728
232780
  excessNames: this.excessNames
232729
232781
  },
232730
232782
  outputs: structuredClone(this.outputs),
232783
+ providerUsage: complete && this.usageComplete && this.providerUsage !== void 0 ? structuredClone(this.providerUsage) : null,
232731
232784
  final: complete ? this.candidate : void 0,
232732
232785
  complete
232733
232786
  };
@@ -233875,6 +233928,7 @@ var init_manager$3 = __esmMin((() => {
233875
233928
  status,
233876
233929
  endedAt: new Date(this.clocks.wallNow()).toISOString(),
233877
233930
  toolSummary: result.toolSummary,
233931
+ providerUsage: completed ? result.providerUsage : null,
233878
233932
  outputs: result.outputs,
233879
233933
  finalMessageRef: final === void 0 ? null : {
233880
233934
  stepId: final.stepId,
@@ -234062,6 +234116,7 @@ var init_manager$3 = __esmMin((() => {
234062
234116
  names: [],
234063
234117
  excessNames: 0
234064
234118
  },
234119
+ providerUsage: null,
234065
234120
  outputs: [],
234066
234121
  finalMessageRef: null,
234067
234122
  unavailableReason
@@ -235138,6 +235193,10 @@ function project(history, options) {
235138
235193
  function repairToolExchangeAdjacency(messages, options) {
235139
235194
  let lastNonToolIndex = messages.length - 1;
235140
235195
  while (lastNonToolIndex >= 0 && messages[lastNonToolIndex]?.role === "tool") lastNonToolIndex -= 1;
235196
+ let remainingResults;
235197
+ const consumeResult = (toolCallId) => {
235198
+ if (remainingResults !== void 0) remainingResults.set(toolCallId, (remainingResults.get(toolCallId) ?? 0) - 1);
235199
+ };
235141
235200
  const out = [];
235142
235201
  const consumed = /* @__PURE__ */ new Set();
235143
235202
  for (let i = 0; i < messages.length; i++) {
@@ -235145,12 +235204,15 @@ function repairToolExchangeAdjacency(messages, options) {
235145
235204
  const message = messages[i];
235146
235205
  if (message.role !== "assistant" || message.toolCalls.length === 0) {
235147
235206
  out.push(message);
235207
+ if (message.role === "tool" && message.toolCallId !== void 0) consumeResult(message.toolCallId);
235148
235208
  continue;
235149
235209
  }
235150
235210
  out.push(message);
235151
235211
  const pending = new Set(message.toolCalls.map((toolCall) => toolCall.id));
235212
+ const counts = remainingResults;
235213
+ let searchable = counts === void 0 ? void 0 : new Set([...pending].filter((id) => (counts.get(id) ?? 0) > 0));
235152
235214
  let foreignBetween = false;
235153
- for (let j = i + 1; j < messages.length && pending.size > 0; j++) {
235215
+ for (let j = i + 1; j < messages.length && (searchable ?? pending).size > 0; j++) {
235154
235216
  if (consumed.has(j)) continue;
235155
235217
  const next = messages[j];
235156
235218
  const toolCallId = next.toolCallId;
@@ -235158,11 +235220,25 @@ function repairToolExchangeAdjacency(messages, options) {
235158
235220
  out.push(next);
235159
235221
  consumed.add(j);
235160
235222
  pending.delete(toolCallId);
235223
+ searchable?.delete(toolCallId);
235224
+ consumeResult(toolCallId);
235161
235225
  if (foreignBetween) options?.onAnomaly?.({
235162
235226
  kind: "tool_result_reordered",
235163
235227
  toolCallId
235164
235228
  });
235165
- } else foreignBetween = true;
235229
+ } else {
235230
+ foreignBetween = true;
235231
+ if (remainingResults === void 0) {
235232
+ remainingResults = /* @__PURE__ */ new Map();
235233
+ for (let index = j; index < messages.length; index += 1) {
235234
+ if (consumed.has(index)) continue;
235235
+ const result = messages[index];
235236
+ if (result.role === "tool" && result.toolCallId !== void 0) remainingResults.set(result.toolCallId, (remainingResults.get(result.toolCallId) ?? 0) + 1);
235237
+ }
235238
+ }
235239
+ const counts = remainingResults;
235240
+ searchable ??= new Set([...pending].filter((id) => (counts.get(id) ?? 0) > 0));
235241
+ }
235166
235242
  }
235167
235243
  const isMidHistory = i < lastNonToolIndex;
235168
235244
  if (options?.synthesizeMissing === true || isMidHistory) for (const missingId of pending) {
@@ -235618,17 +235694,29 @@ var init_context$2 = __esmMin((() => {
235618
235694
  deferredIndexes: [...deferredIndexes]
235619
235695
  });
235620
235696
  const removedMessages = /* @__PURE__ */ new Set();
235697
+ let shiftedSlots = -historyIndexes.size * (historyIndexes.size - 1) / 2;
235698
+ for (const index of historyIndexes) shiftedSlots += this._history.length - 1 - index;
235699
+ const compactHistory = shiftedSlots > this._history.length * 64;
235621
235700
  for (let i = this._history.length - 1; i >= 0; i--) {
235622
235701
  const message = this._history[i];
235623
235702
  if (message === void 0 || !historyIndexes.has(i)) continue;
235624
235703
  removedMessages.add(message);
235625
- this._history.splice(i, 1);
235704
+ if (!compactHistory) this._history.splice(i, 1);
235626
235705
  this.agent.injection.onContextMessageRemoved(i);
235627
235706
  if (i < this.tokenCountCoveredMessageCount) {
235628
235707
  this.tokenCountCoveredMessageCount--;
235629
235708
  this._tokenCount -= estimateTokensForMessages([message]);
235630
235709
  }
235631
235710
  }
235711
+ if (compactHistory) {
235712
+ let retained = 0;
235713
+ for (let index = 0; index < this._history.length; index++) {
235714
+ if (historyIndexes.has(index)) continue;
235715
+ if (retained !== index) this._history[retained] = this._history[index];
235716
+ retained++;
235717
+ }
235718
+ this._history.length = retained;
235719
+ }
235632
235720
  this.deferredMessages = this.deferredMessages.filter((message, index) => {
235633
235721
  if (!deferredIndexes.has(index)) return true;
235634
235722
  removedMessages.add(message);
@@ -240461,10 +240549,18 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240461
240549
  if (VIDEO_MEDIA_TERM_RE.test(text)) selected.add("GenerateVideo");
240462
240550
  return selected;
240463
240551
  }
240552
+ function channelMessagesForTurnText(value) {
240553
+ return [...String(value || "").matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => ({
240554
+ text: match[1],
240555
+ start: match.index,
240556
+ end: match.index + match[0].length,
240557
+ telegram: /^<channel\s+source=["']telegram["'](?:\s|>)/iu.test(match[0].trimStart())
240558
+ }));
240559
+ }
240464
240560
  function mediaToolNamesForTurnText(value) {
240465
240561
  const text = String(value || "");
240466
240562
  const selected = /* @__PURE__ */ new Set();
240467
- const channelBodies = [...text.matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => match[1]);
240563
+ const channelBodies = channelMessagesForTurnText(text).map((message) => message.text);
240468
240564
  const intentTexts = channelBodies.length > 0 ? channelBodies : [text];
240469
240565
  for (const intentText of intentTexts) for (const name of mediaGenerationToolNamesForText(intentText)) selected.add(name);
240470
240566
  if (/\bimage_path\s*=\s*["'][^"']+["']/iu.test(text)) {
@@ -240581,7 +240677,7 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240581
240677
  }
240582
240678
  function rankingIntentTexts(value) {
240583
240679
  const text = String(value || "");
240584
- const channelBodies = [...text.matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => match[1]);
240680
+ const channelBodies = channelMessagesForTurnText(text).map((message) => message.text);
240585
240681
  return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(withoutFencedCode(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " "))));
240586
240682
  }
240587
240683
  function rankingTokens(value) {
@@ -240658,17 +240754,15 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240658
240754
  if (!supportChoice.match(/^(?:tool|skill)\s*:\s*(.+)$/iu)?.[1]) return /* @__PURE__ */ new Set();
240659
240755
  return rankedToolNamesForTurnText(tools, supportChoice, { maxTools: 1 });
240660
240756
  }
240661
- function searchRelatedDeferredTools(tools, query, options = {}) {
240757
+ function searchRelatedDeferredTools(tools, query) {
240662
240758
  const normalized = normalizeDeferredToolQuery(query).toLowerCase();
240663
240759
  if (!normalized || normalized.startsWith("select:")) return [];
240664
240760
  const tokens = normalized.match(/\+?[\p{L}\p{N}_-]+/gu) || [];
240665
- const requestedNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
240666
- const relaxRequiredNameTokens = options.relaxRequiredNameTokens === true && requestedNameTokens.length > 0;
240667
- const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
240668
- const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token) && !TOOL_RANK_STOP_WORDS.has(token));
240761
+ const requiredNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
240762
+ const searchTokens = tokens.filter((token) => !token.startsWith("+")).filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token) && !TOOL_RANK_STOP_WORDS.has(token));
240669
240763
  if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
240670
240764
  const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * .75));
240671
- const ranked = tools.map((tool) => {
240765
+ return tools.map((tool) => {
240672
240766
  const name = String(tool?.name || "").toLowerCase();
240673
240767
  const description = String(tool?.description || "").toLowerCase();
240674
240768
  if (!requiredNameTokens.every((token) => name.includes(token))) return null;
@@ -240699,12 +240793,7 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240699
240793
  score,
240700
240794
  matchedTokens
240701
240795
  } : null;
240702
- }).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name)));
240703
- if (relaxRequiredNameTokens && ranked.length > 0) {
240704
- const best = ranked[0];
240705
- return ranked.filter((entry) => entry.matchedTokens === best.matchedTokens && entry.score === best.score).slice(0, 5).map((entry) => entry.tool);
240706
- }
240707
- return ranked.slice(0, 5).map((entry) => entry.tool);
240796
+ }).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name))).slice(0, 5).map((entry) => entry.tool);
240708
240797
  }
240709
240798
  function rememberLoadedTool(loadedToolNames, name) {
240710
240799
  loadedToolNames.delete(name);
@@ -240729,11 +240818,10 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240729
240818
  const usedNames = new Set([...selectedTools, ...available.values()].map((tool) => String(tool?.name ?? "")));
240730
240819
  let loaderName = DEFERRED_TOOL_LOADER_NAME;
240731
240820
  for (let suffix = 1; usedNames.has(loaderName); suffix += 1) loaderName = `${DEFERRED_TOOL_LOADER_NAME}_${suffix}`;
240732
- const deferredCount = available.size;
240733
240821
  const loader = {
240734
240822
  name: loaderName,
240735
240823
  description: [
240736
- `Search ${deferredCount} deferred ${deferredCount === 1 ? "tool schema" : "tool schemas"} without loading all definitions.`,
240824
+ "Search deferred tool schemas without loading all definitions.",
240737
240825
  "Use select:leaf_name for one known tool, plain keywords to search, +word to require a name word, or catalog:fragment to list matching names.",
240738
240826
  `Loaded tools are available in the next step; up to ${MAX_PERSISTENT_DEFERRED_TOOLS} recently selected schemas remain loaded when the context budget allows.`
240739
240827
  ].join("\n"),
@@ -240764,10 +240852,6 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240764
240852
  matches = searchRelatedDeferredTools([...available.values()], query);
240765
240853
  relatedFallback = matches.length > 0;
240766
240854
  }
240767
- if (matches.length === 0) {
240768
- matches = searchRelatedDeferredTools([...available.values()], query, { relaxRequiredNameTokens: true });
240769
- relatedFallback = matches.length > 0;
240770
- }
240771
240855
  if (matches.length === 0) {
240772
240856
  const alreadyLoaded = query.toLowerCase().startsWith("select:") ? searchDeferredTools(selectedTools.filter((tool) => tool?.name !== loaderName), query) : [];
240773
240857
  if (alreadyLoaded.length === 1) return {
@@ -240806,6 +240890,7 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240806
240890
  return loader;
240807
240891
  }
240808
240892
  module.exports = {
240893
+ channelMessagesForTurnText,
240809
240894
  isDeferredToolLoader: (tool) => deferredToolLoaders.has(tool),
240810
240895
  CORE_TOOL_NAMES,
240811
240896
  DEFERRED_TOOL_LOADER_NAME,
@@ -240828,9 +240913,9 @@ var require_turn_tool_performance_policy = /* @__PURE__ */ __commonJSMin(((expor
240828
240913
  }));
240829
240914
  //#endregion
240830
240915
  //#region ../../packages/agent-core/src/agent/permission/policies/default-tool-approve.ts
240831
- var import_turn_tool_performance_policy$1, DEFAULT_APPROVE_TOOLS, DefaultToolApprovePermissionPolicy;
240916
+ var import_turn_tool_performance_policy$2, DEFAULT_APPROVE_TOOLS, DefaultToolApprovePermissionPolicy;
240832
240917
  var init_default_tool_approve = __esmMin((() => {
240833
- import_turn_tool_performance_policy$1 = require_turn_tool_performance_policy();
240918
+ import_turn_tool_performance_policy$2 = require_turn_tool_performance_policy();
240834
240919
  DEFAULT_APPROVE_TOOLS = new Set([
240835
240920
  "Read",
240836
240921
  "Grep",
@@ -240853,7 +240938,7 @@ var init_default_tool_approve = __esmMin((() => {
240853
240938
  DefaultToolApprovePermissionPolicy = class {
240854
240939
  name = "default-tool-approve";
240855
240940
  evaluate(context) {
240856
- if (!DEFAULT_APPROVE_TOOLS.has(context.toolCall.name) && !(0, import_turn_tool_performance_policy$1.isDeferredToolLoader)(context.tool)) return;
240941
+ if (!DEFAULT_APPROVE_TOOLS.has(context.toolCall.name) && !(0, import_turn_tool_performance_policy$2.isDeferredToolLoader)(context.tool)) return;
240857
240942
  return { kind: "approve" };
240858
240943
  }
240859
240944
  };
@@ -242193,10 +242278,14 @@ var init_replay = __esmMin((() => {
242193
242278
  return this.records;
242194
242279
  }
242195
242280
  removeMessagesFrom(records, removedMessages) {
242196
- for (let i = records.length - 1; i >= 0; i--) {
242197
- const record = records[i];
242198
- if (record.type === "message" && removedMessages.has(record.message)) records.splice(i, 1);
242281
+ let retained = 0;
242282
+ for (let index = 0; index < records.length; index++) {
242283
+ const record = records[index];
242284
+ if (record.type === "message" && removedMessages.has(record.message)) continue;
242285
+ if (retained !== index) records[retained] = record;
242286
+ retained++;
242199
242287
  }
242288
+ records.length = retained;
242200
242289
  }
242201
242290
  };
242202
242291
  }));
@@ -243235,6 +243324,7 @@ function withThinkingOnlyRecovery(llm, onTimeout, observeExecution) {
243235
243324
  systemPrompt: llm.systemPrompt,
243236
243325
  modelName: llm.modelName,
243237
243326
  capability: llm.capability,
243327
+ rebuildsMessagesAtRequestBoundary: llm.rebuildsMessagesAtRequestBoundary,
243238
243328
  prepareRequestBoundary: llm.prepareRequestBoundary?.bind(llm),
243239
243329
  isRetryableError: llm.isRetryableError === void 0 ? void 0 : (error) => !recoveryCallbackFailed && !(error instanceof ThinkingOnlyTimeoutError) && (llm.isRetryableError?.(error) ?? false),
243240
243330
  async chat(params) {
@@ -251492,7 +251582,9 @@ async function executeLoopStep(deps) {
251492
251582
  if (beforeStep?.block === true) throw new Error(beforeStep.reason ?? `Step ${String(currentStep)} was blocked`);
251493
251583
  }
251494
251584
  signal.throwIfAborted();
251495
- const messages = await buildMessages();
251585
+ const prepareRequestBoundary = llm.prepareRequestBoundary?.bind(llm);
251586
+ const deferMessageBuild = prepareRequestBoundary !== void 0 && llm.rebuildsMessagesAtRequestBoundary === true;
251587
+ const messages = deferMessageBuild ? [] : await buildMessages();
251496
251588
  signal.throwIfAborted();
251497
251589
  const stepUuid = randomUUID();
251498
251590
  const stepEvents = createStepEventGate({
@@ -251502,7 +251594,6 @@ async function executeLoopStep(deps) {
251502
251594
  stepUuid,
251503
251595
  onStepStarted
251504
251596
  });
251505
- const prepareRequestBoundary = llm.prepareRequestBoundary?.bind(llm);
251506
251597
  const step = {
251507
251598
  tools,
251508
251599
  hooks,
@@ -251582,7 +251673,7 @@ async function executeLoopStep(deps) {
251582
251673
  turnStep: `${turnId}.${String(currentStep)}`,
251583
251674
  model: llm.modelName
251584
251675
  });
251585
- const strictMessages = await buildMessagesStrict();
251676
+ const strictMessages = deferMessageBuild ? [] : await buildMessagesStrict();
251586
251677
  signal.throwIfAborted();
251587
251678
  let strictParams = {
251588
251679
  ...chatParams,
@@ -259762,7 +259853,7 @@ function Yn(s, t) {
259762
259853
  function Kn(s, t) {
259763
259854
  s.head = new ue$1(t, void 0, s.head, s), s.tail || (s.tail = s.head), s.length++;
259764
259855
  }
259765
- var zr, Ur, Ds, Wr, Gr, Zr, Q$1, J$1, nt$1, De$1, qt, Ne$1, Ns, Ae$1, As, z$1, Mt, g$1, Qt, Bt, b$1, N$1, _$1, bi, Ie$1, L$1, S, _i, Oi, Is, Ti, Z$1, xi, Ce$1, Jt$1, Rt, C, jt, Yr, Kr, Vr, $r, Fe$1, Li, Xr, qr, A$1, Jr, ht, H$1, te, m$1, Ni, tt$1, Ai, ki, vi, ie$1, ke$1, Ut$1, Ht, Ii, Pt, at, U$1, ot, Y$1, zt, Ci, j$1, ee$1, Fi, ve$1, gt$2, Me, bt, _t, Be$1, et$1, Wt$1, jr, Fs, ks, vs, Ms, Bs, tn, se$1, K$1, sn, M$1, rn, zs, nn, Bi, Tt, Gt, Pi, re, Pe$1, ze$1, Ue, He$1, We$1, Ge$1, Ze$1, Ye$1, Ke$1, Us, hn, an, Hs, ln, cn, Ws, Gs, Hi, ne, dn, Ui, oe$1, Ve$1, un, F$1, mn, xt, Wi, pn, lt, En, wn, Sn, ct, yn, Rn, gn, Gi, bn, Lt, ft, On, Tn, xn, f, $e$1, Dt, Nn, Xi, qi, An, B$1, Nt, it, Zi, Zs, V$1, he$1, dt, Ys, p, st$1, ut, Yi, At, w$1, Xe$1, qe$1, Ki, Ks, Vs, ae$1, Vi, Qe$1, Yt$1, $$1, Je$1, It, je$1, ti, $s, In, le$1, $i, Xs, Cn, rt$1, mt, vn, Qi, Mn, Bn, Ct, Ji, zn, qs, ce$1, ei, ji, Un, Hn, ts, Qs, rr, Wn, tr, er, ir, is$2, sr, fe$1, ii, ss, si, rs, ns, os$6, hs, pt, ri, as, es, q$1, de$1, ni, oi, Gn, hi, ue$1, pi, nr, li, me$1, W$1, pe$2, Et, Ft$1, Ee$1, ai, G, ls, ci, or, ds, us, fi, di, hr, cs, ui, lr, fs$11, wt, kt, Vn, $n, fr, dr, Xn, qn, Er, wr, ur, Sr, yr, Rr, jn, to, eo, mr, ms, ps, Ei, io, Es, so, ws, Se$1, St, no, gr, Ss, br, oo, _r, ys, Or, Vt$1, Tr, ao, lo, yi, Lr, Dr, _s, Nr, Os, P$1, Ts, xs, gi, Ar, Ir, Re, Cr, Fr, Rs, yt, O$1, Ri, kr, $t, gs, bs, Ls, ge$1, be, _e$1, Oe$1, Te$1, uo, mo, po, vr, Xt$1, ye$1, xe$1, Eo, wo, So, yo, Ro, go, bo, _o, vt, To;
259856
+ var zr, Ur, Ds, Wr, Gr, Zr, Q$1, J$1, nt$1, De$1, qt, Ne$1, Ns, Ae$1, As, z$1, Mt, g$1, Qt, Bt, b$1, N$1, _$1, bi, Ie$1, L$1, S, _i, Oi, Is, Ti, Z$1, xi, Ce$1, Jt$1, Rt, C, jt, Yr, Kr, Vr, $r, Fe$1, Li, Xr, qr, A$1, Jr, ht, H$1, te, m$1, Ni, tt$1, Ai, ki, vi, ie$1, ke$1, Ut$1, Ht, Ii, Pt, at, U$1, ot, Y$1, zt, Ci, j$1, ee$1, Fi, ve$1, gt$2, Me, bt, _t, Be$1, et$1, Wt$1, jr, Fs, ks, vs, Ms, Bs, tn, se$1, K$1, sn, M$1, rn, zs, nn, Bi, Tt, Gt, Pi, re, Pe$1, ze$1, Ue, He$1, We$1, Ge$1, Ze$1, Ye$1, Ke$1, Us, hn, an, Hs, ln, cn, Ws, Gs, Hi, ne, dn, Ui, oe$1, Ve$1, un, F$1, mn, xt, Wi, pn, lt, En, wn, Sn, ct, yn, Rn, gn, Gi, bn, Lt, ft, On, Tn, xn, f, $e$1, Dt, Nn, Xi, qi, An, B$1, Nt, it, Zi, Zs, V$1, he$1, dt, Ys, p, st$1, ut, Yi, At, w$1, Xe$1, qe$1, Ki, Ks, Vs, ae$1, Vi, Qe$1, Yt$1, $$1, Je$1, It, je$1, ti, $s, In, le$1, $i, Xs, Cn, rt$1, mt, vn, Qi, Mn, Bn, Ct, Ji, zn, qs, ce$1, ei, ji, Un, Hn, ts, Qs, rr, Wn, tr, er, ir, is$2, sr, fe$1, ii, ss, si, rs, ns, os$6, hs, pt, ri, as, es, q$1, de$1, ni, oi, Gn, hi, ue$1, pi, nr, li, me$1, W$1, pe$2, Et, Ft$1, Ee$1, ai, G, ls, ci, or, ds, us, fi, di, hr, cs, ui, lr, fs$12, wt, kt, Vn, $n, fr, dr, Xn, qn, Er, wr, ur, Sr, yr, Rr, jn, to, eo, mr, ms, ps, Ei, io, Es, so, ws, Se$1, St, no, gr, Ss, br, oo, _r, ys, Or, Vt$1, Tr, ao, lo, yi, Lr, Dr, _s, Nr, Os, P$1, Ts, xs, gi, Ar, Ir, Re, Cr, Fr, Rs, yt, O$1, Ri, kr, $t, gs, bs, Ls, ge$1, be, _e$1, Oe$1, Te$1, uo, mo, po, vr, Xt$1, ye$1, xe$1, Eo, wo, So, yo, Ro, go, bo, _o, vt, To;
259766
259857
  var init_index_min = __esmMin((() => {
259767
259858
  zr = Object.defineProperty;
259768
259859
  Ur = (s, t) => {
@@ -261732,7 +261823,7 @@ while (this[Zs](this[st$1].shift()));
261732
261823
  constructor(t, e) {
261733
261824
  this.path = t || "./", this.absolute = e;
261734
261825
  }
261735
- }, nr = Buffer.alloc(1024), li = Symbol("onStat"), me$1 = Symbol("ended"), W$1 = Symbol("queue"), pe$2 = Symbol("pendingLinks"), Et = Symbol("current"), Ft$1 = Symbol("process"), Ee$1 = Symbol("processing"), ai = Symbol("processJob"), G = Symbol("jobs"), ls = Symbol("jobDone"), ci = Symbol("addFSEntry"), or = Symbol("addTarEntry"), ds = Symbol("stat"), us = Symbol("readdir"), fi = Symbol("onreaddir"), di = Symbol("pipe"), hr = Symbol("entry"), cs = Symbol("entryOpt"), ui = Symbol("writeEntryClass"), lr = Symbol("write"), fs$11 = Symbol("ondrain"), wt = class extends A$1 {
261826
+ }, nr = Buffer.alloc(1024), li = Symbol("onStat"), me$1 = Symbol("ended"), W$1 = Symbol("queue"), pe$2 = Symbol("pendingLinks"), Et = Symbol("current"), Ft$1 = Symbol("process"), Ee$1 = Symbol("processing"), ai = Symbol("processJob"), G = Symbol("jobs"), ls = Symbol("jobDone"), ci = Symbol("addFSEntry"), or = Symbol("addTarEntry"), ds = Symbol("stat"), us = Symbol("readdir"), fi = Symbol("onreaddir"), di = Symbol("pipe"), hr = Symbol("entry"), cs = Symbol("entryOpt"), ui = Symbol("writeEntryClass"), lr = Symbol("write"), fs$12 = Symbol("ondrain"), wt = class extends A$1 {
261736
261827
  sync = !1;
261737
261828
  opt;
261738
261829
  cwd;
@@ -261765,8 +261856,8 @@ while (this[Zs](this[st$1].shift()));
261765
261856
  if ((t.gzip ? 1 : 0) + (t.brotli ? 1 : 0) + (t.zstd ? 1 : 0) > 1) throw new TypeError("gzip, brotli, zstd are mutually exclusive");
261766
261857
  if (t.gzip && (typeof t.gzip != "object" && (t.gzip = {}), this.portable && (t.gzip.portable = !0), this.zip = new ze$1(t.gzip)), t.brotli && (typeof t.brotli != "object" && (t.brotli = {}), this.zip = new We$1(t.brotli)), t.zstd && (typeof t.zstd != "object" && (t.zstd = {}), this.zip = new Ye$1(t.zstd)), !this.zip) throw new Error("impossible");
261767
261858
  let e = this.zip;
261768
- e.on("data", (i) => super.write(i)), e.on("end", () => super.end()), e.on("drain", () => this[fs$11]()), this.on("resume", () => e.resume());
261769
- } else this.on("drain", this[fs$11]);
261859
+ e.on("data", (i) => super.write(i)), e.on("end", () => super.end()), e.on("drain", () => this[fs$12]()), this.on("resume", () => e.resume());
261860
+ } else this.on("drain", this[fs$12]);
261770
261861
  this.noDirRecurse = !!t.noDirRecurse, this.follow = !!t.follow, this.noMtime = !!t.noMtime, t.mtime && (this.mtime = t.mtime), this.filter = typeof t.filter == "function" ? t.filter : () => !0, this[W$1] = new hi(), this[G] = 0, this.jobs = Number(t.jobs) || 4, this[Ee$1] = !1, this[me$1] = !1;
261771
261862
  }
261772
261863
  [lr](t) {
@@ -261893,7 +261984,7 @@ while (this[Zs](this[st$1].shift()));
261893
261984
  this.emit("error", e);
261894
261985
  }
261895
261986
  }
261896
- [fs$11]() {
261987
+ [fs$12]() {
261897
261988
  this[Et] && this[Et].entry && this[Et].entry.resume();
261898
261989
  }
261899
261990
  [di](t) {
@@ -262818,7 +262909,7 @@ var require_pend = /* @__PURE__ */ __commonJSMin(((exports, module) => {
262818
262909
  //#endregion
262819
262910
  //#region ../../node_modules/.pnpm/yauzl@3.3.0/node_modules/yauzl/fd-slicer.js
262820
262911
  var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262821
- var fs$10 = __require("fs");
262912
+ var fs$11 = __require("fs");
262822
262913
  var util$6 = __require("util");
262823
262914
  var stream$2 = __require("stream");
262824
262915
  var Readable = stream$2.Readable;
@@ -262843,7 +262934,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262843
262934
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
262844
262935
  var self = this;
262845
262936
  self.pend.go(function(cb) {
262846
- fs$10.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
262937
+ fs$11.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
262847
262938
  cb();
262848
262939
  callback(err, bytesRead, buffer);
262849
262940
  });
@@ -262852,7 +262943,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262852
262943
  FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
262853
262944
  var self = this;
262854
262945
  self.pend.go(function(cb) {
262855
- fs$10.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
262946
+ fs$11.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
262856
262947
  cb();
262857
262948
  callback(err, written, buffer);
262858
262949
  });
@@ -262872,7 +262963,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262872
262963
  self.refCount -= 1;
262873
262964
  if (self.refCount > 0) return;
262874
262965
  if (self.refCount < 0) throw new Error("invalid unref");
262875
- if (self.autoClose) fs$10.close(self.fd, onCloseDone);
262966
+ if (self.autoClose) fs$11.close(self.fd, onCloseDone);
262876
262967
  function onCloseDone(err) {
262877
262968
  if (err) self.emit("error", err);
262878
262969
  else self.emit("close");
@@ -262903,7 +262994,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262903
262994
  self.context.pend.go(function(cb) {
262904
262995
  if (self.destroyed) return cb();
262905
262996
  var buffer = Buffer.allocUnsafe(toRead);
262906
- fs$10.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
262997
+ fs$11.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
262907
262998
  if (err) self.destroy(err);
262908
262999
  else if (bytesRead === 0) {
262909
263000
  self.destroyed = true;
@@ -262949,7 +263040,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
262949
263040
  }
262950
263041
  self.context.pend.go(function(cb) {
262951
263042
  if (self.destroyed) return cb();
262952
- fs$10.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) {
263043
+ fs$11.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) {
262953
263044
  if (err) {
262954
263045
  self.destroy();
262955
263046
  cb();
@@ -266725,7 +266816,9 @@ function renderPersistedToolResult(toolName, toolCallId, text, outputPath, maxCh
266725
266816
  `output_path: ${outputPath}`,
266726
266817
  "next_step: Use Read with output_path to page through the full output."
266727
266818
  ];
266728
- lines.push("", "[preview]", text.slice(0, TOOL_RESULT_PREVIEW_CHARS));
266819
+ let preview = text.slice(0, TOOL_RESULT_PREVIEW_CHARS);
266820
+ if (/[\uD800-\uDBFF]$/.test(preview)) preview = preview.slice(0, -1);
266821
+ lines.push("", "[preview]", preview);
266729
266822
  return lines.join("\n");
266730
266823
  }
266731
266824
  function safeToolResultFileStem(toolName, toolCallId) {
@@ -266869,14 +266962,14 @@ async function readGitExecPath(deps, gitExe) {
266869
266962
  }
266870
266963
  }
266871
266964
  function gitBashCandidatesFromGitExe(gitExe) {
266872
- const normalizedGitExe = path$16.win32.normalize(normalizeWindowsPath(gitExe));
266873
- const gitDir = path$16.win32.dirname(normalizedGitExe);
266874
- const gitDirName = path$16.win32.basename(gitDir).toLowerCase();
266965
+ const normalizedGitExe = path$17.win32.normalize(normalizeWindowsPath(gitExe));
266966
+ const gitDir = path$17.win32.dirname(normalizedGitExe);
266967
+ const gitDirName = path$17.win32.basename(gitDir).toLowerCase();
266875
266968
  if (gitDirName !== "cmd" && gitDirName !== "bin") return;
266876
- return gitBashCandidatesFromGitRoot(path$16.win32.dirname(gitDir));
266969
+ return gitBashCandidatesFromGitRoot(path$17.win32.dirname(gitDir));
266877
266970
  }
266878
266971
  function gitBashCandidatesFromGitExecPath(execPath) {
266879
- const normalized = path$16.win32.normalize(normalizeWindowsPath(execPath));
266972
+ const normalized = path$17.win32.normalize(normalizeWindowsPath(execPath));
266880
266973
  const parts = normalized.split("\\");
266881
266974
  for (let i = parts.length - 1; i >= 0; i -= 1) {
266882
266975
  const segment = parts[i]?.toLowerCase();
@@ -266885,16 +266978,16 @@ function gitBashCandidatesFromGitExecPath(execPath) {
266885
266978
  if (root.length > 0) return gitBashCandidatesFromGitRoot(root);
266886
266979
  }
266887
266980
  }
266888
- return gitBashCandidatesFromGitRoot(path$16.win32.join(normalized, "..", ".."));
266981
+ return gitBashCandidatesFromGitRoot(path$17.win32.join(normalized, "..", ".."));
266889
266982
  }
266890
266983
  function gitBashCandidatesFromGitRoot(root) {
266891
- return [path$16.win32.normalize(path$16.win32.join(root, "bin", "bash.exe")), path$16.win32.normalize(path$16.win32.join(root, "usr", "bin", "bash.exe"))];
266984
+ return [path$17.win32.normalize(path$17.win32.join(root, "bin", "bash.exe")), path$17.win32.normalize(path$17.win32.join(root, "usr", "bin", "bash.exe"))];
266892
266985
  }
266893
266986
  function normalizeWindowsPath(path) {
266894
266987
  return path.replaceAll("/", "\\");
266895
266988
  }
266896
266989
  function isAbsoluteWindowsPath(path) {
266897
- return path$16.win32.isAbsolute(normalizeWindowsPath(path));
266990
+ return path$17.win32.isAbsolute(normalizeWindowsPath(path));
266898
266991
  }
266899
266992
  function dedupeWindowsPaths(paths) {
266900
266993
  const deduped = [];
@@ -268299,6 +268392,52 @@ var init_historical_tool_projection = __esmMin((() => {
268299
268392
  };
268300
268393
  }));
268301
268394
  //#endregion
268395
+ //#region ../../packages/agent-core/src/agent/turn/baseline-skill-projection.ts
268396
+ function shortNonVisualText(text) {
268397
+ return text.length <= 500 && !/[<>]/.test(text) && !/https?:\/\//i.test(text) && NONVISUAL_TASK.test(text) && !VISUAL_TASK.test(text);
268398
+ }
268399
+ function clearlyNonVisual(input, origin) {
268400
+ if (origin.kind !== "user" || input.length !== 1 || input[0]?.type !== "text") return false;
268401
+ const text = input[0].text;
268402
+ if (text.length > 16e3 || /\b(?:image_path|attachment_file_id)\s*=|Telegram-Anhang:/i.test(text)) return false;
268403
+ const messages = (0, import_turn_tool_performance_policy$1.channelMessagesForTurnText)(text);
268404
+ if (messages.length === 0) return shortNonVisualText(text);
268405
+ if (messages.some((message) => !message.telegram || !shortNonVisualText(message.text)) || messages.reduce((size, message) => size + message.text.length, 0) > 500) return false;
268406
+ let cursor = 0;
268407
+ let remainder = "";
268408
+ for (const message of messages) {
268409
+ remainder += text.slice(cursor, message.start);
268410
+ cursor = message.end;
268411
+ }
268412
+ remainder += text.slice(cursor);
268413
+ return !VISUAL_TASK.test(remainder) && remainder.split(/\r?\n/).every((line) => line.trim().length === 0 || /^\[(?:GRUPPENANTWORT|REPLY-PFLICHT|SEMANTISCHE ADRESSIERUNG|NUR MITLESEN)\b[^\r\n]*\]$/.test(line.trim()));
268414
+ }
268415
+ /** Request-only view; the context, records, and resume state keep the full skill. */
268416
+ function projectBaselineSkillForTurn(history, input, origin, turnAnchor) {
268417
+ if (!clearlyNonVisual(input, origin)) return history;
268418
+ const anchorIndex = turnAnchor === void 0 ? -1 : history.indexOf(turnAnchor);
268419
+ if (anchorIndex >= 0 && history.slice(anchorIndex + 1).some((message) => message.role === "tool" && message.content.some((part) => part.type !== "text" || VISUAL_TASK.test(part.text)))) return history;
268420
+ return history.map((message) => message.origin?.kind === "injection" && message.origin.variant === BASELINE_ORIGIN ? {
268421
+ ...message,
268422
+ content: [{
268423
+ type: "text",
268424
+ text: SHORT_REFERENCE
268425
+ }]
268426
+ } : message);
268427
+ }
268428
+ var import_turn_tool_performance_policy$1, BASELINE_ORIGIN, NONVISUAL_TASK, VISUAL_TASK, SHORT_REFERENCE;
268429
+ var init_baseline_skill_projection = __esmMin((() => {
268430
+ import_turn_tool_performance_policy$1 = require_turn_tool_performance_policy();
268431
+ BASELINE_ORIGIN = "baseline_skill:blun-design-dna";
268432
+ NONVISUAL_TASK = /\b(?:backend|back-end|serverseitig|server-side|datenbank|database|sql|api[- ](?:endpoint|route)|memory broker)\b/i;
268433
+ VISUAL_TASK = /\b(?:ui|ux|frontend|front-end|website|webseite|web|page|screen|screenshot|bild|image|design|layout|css|html|react|vue|svelte|komponente|component|button|formular|form|style|visual|visuell|interaction|interaktion|interface|oberfl[aä]che|dashboard|landing|mobile|responsive|accessibility|barrierefreiheit|tui|terminal|konsole|console|browser|diagram|chart|graph)\b/i;
268434
+ SHORT_REFERENCE = [
268435
+ "<system-reminder>",
268436
+ "The BLUN Design DNA baseline is retained in the session. Its visual rules are dormant for this explicitly non-visual backend or data task. Preserve security, privacy, accessibility, permissions, and verification. If the work turns visual or interactive, use the complete baseline before continuing.",
268437
+ "</system-reminder>"
268438
+ ].join("\n");
268439
+ }));
268440
+ //#endregion
268302
268441
  //#region ../../packages/agent-core/src/agent/response-review-decision.ts
268303
268442
  /** Never carry provider/guard prose, signed receipts or arbitrary codes into logs. */
268304
268443
  function rejectionFindings(report) {
@@ -268620,6 +268759,23 @@ var init_response_review = __esmMin((() => {
268620
268759
  }));
268621
268760
  //#endregion
268622
268761
  //#region ../../packages/agent-core/src/agent/turn/index.ts
268762
+ function restoreRecentMcpToolNames(history, loadedNames) {
268763
+ const successfulResults = /* @__PURE__ */ new Set();
268764
+ const recentNames = [];
268765
+ const start = Math.max(0, history.length - 256);
268766
+ for (let index = history.length - 1; index >= start && recentNames.length < import_turn_tool_performance_policy.MAX_PERSISTENT_DEFERRED_TOOLS; index--) {
268767
+ const message = history[index];
268768
+ if (message.role === "tool" && message.isError !== true && message.toolCallId !== void 0) {
268769
+ if (successfulResults.size < 64) successfulResults.add(message.toolCallId);
268770
+ } else if (message.role === "assistant") for (let callIndex = message.toolCalls.length - 1; callIndex >= 0; callIndex--) {
268771
+ const call = message.toolCalls[callIndex];
268772
+ if (!successfulResults.delete(call.id) || !/^mcp__[\w.:-]{1,160}$/.test(call.name) || recentNames.includes(call.name)) continue;
268773
+ recentNames.push(call.name);
268774
+ if (recentNames.length >= import_turn_tool_performance_policy.MAX_PERSISTENT_DEFERRED_TOOLS) break;
268775
+ }
268776
+ }
268777
+ for (const name of recentNames.reverse()) loadedNames.add(name);
268778
+ }
268623
268779
  function blunExtractText(content) {
268624
268780
  if (typeof content === "string") return content;
268625
268781
  if (Array.isArray(content)) return content.map((c) => typeof c === "string" ? c : c && typeof c === "object" && "text" in c && typeof c.text === "string" ? c.text : "").join(" ");
@@ -268639,7 +268795,7 @@ function blunTurnNeedsTools(input, origin) {
268639
268795
  return !/^(?:hi|hallo|hey|hello|hoi|moin|servus|yo|danke|thanks|thx|bye|tschau|ciao)[.!?]*$/.test(text) && !/^(?:wer bist du|who are you|wie geht(?: es dir)?|how are you|na)[.!?]*$/.test(text);
268640
268796
  }
268641
268797
  function blunThinkingIntentInput(input) {
268642
- const channelText = [...blunExtractText(input).matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/gi)].at(-1)?.[1];
268798
+ const channelText = (0, import_turn_tool_performance_policy.channelMessagesForTurnText)(blunExtractText(input)).at(-1)?.text;
268643
268799
  return channelText === void 0 ? input : [{
268644
268800
  type: "text",
268645
268801
  text: channelText
@@ -268676,7 +268832,31 @@ function blunToolsForOrigin(tools, origin) {
268676
268832
  */
268677
268833
  function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames = /* @__PURE__ */ new Set(), requiredToolNames = /* @__PURE__ */ new Set(), selected = []) {
268678
268834
  const schemaBudget = (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens);
268679
- if (estimateTokensForTools(tools, schemaBudget) <= schemaBudget || tools.some(import_turn_tool_performance_policy.isDeferredToolLoader)) {
268835
+ const estimates = /* @__PURE__ */ new Map();
268836
+ const estimateSummary = (tool) => {
268837
+ let estimate = estimates.get(tool);
268838
+ if (estimate === void 0) {
268839
+ estimate = { summary: estimateTokens(tool.name) + estimateTokens(tool.description) };
268840
+ estimates.set(tool, estimate);
268841
+ }
268842
+ return estimate;
268843
+ };
268844
+ const estimateSelection = (candidates) => {
268845
+ let total = 0;
268846
+ for (const candidate of candidates) {
268847
+ const estimate = estimateSummary(candidate);
268848
+ if (estimate.complete === void 0) estimate.complete = estimate.summary + estimateTokens(JSON.stringify(candidate.parameters));
268849
+ total += estimate.complete;
268850
+ if (total > schemaBudget) break;
268851
+ }
268852
+ return total;
268853
+ };
268854
+ let summaryTokens = 0;
268855
+ for (const tool of tools) {
268856
+ summaryTokens += estimateSummary(tool).summary;
268857
+ if (summaryTokens > schemaBudget) break;
268858
+ }
268859
+ if (tools.some(import_turn_tool_performance_policy.isDeferredToolLoader) || summaryTokens <= schemaBudget && estimateSelection(tools) <= schemaBudget) {
268680
268860
  selected.splice(0, selected.length, ...tools);
268681
268861
  return selected;
268682
268862
  }
@@ -268691,7 +268871,7 @@ function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames = /* @__PU
268691
268871
  };
268692
268872
  choose();
268693
268873
  for (const name of loadedToolNames) {
268694
- if (estimateTokensForTools(selected, schemaBudget) <= schemaBudget) break;
268874
+ if (estimateSelection(selected) <= schemaBudget) break;
268695
268875
  if (justLoaded.has(name)) continue;
268696
268876
  if (!remembered.delete(name)) continue;
268697
268877
  choose();
@@ -268957,6 +269137,7 @@ var init_turn = __esmMin((() => {
268957
269137
  init_tool_dedup();
268958
269138
  init_tool_result_budget();
268959
269139
  init_historical_tool_projection();
269140
+ init_baseline_skill_projection();
268960
269141
  init_response_review();
268961
269142
  import_turn_tool_performance_policy = require_turn_tool_performance_policy();
268962
269143
  BLUN_LEAN_TOOL_NAMES = new Set([
@@ -269323,6 +269504,7 @@ var init_turn = __esmMin((() => {
269323
269504
  }
269324
269505
  finishResume() {
269325
269506
  if (this.activeTurn === "resuming") this.activeTurn = null;
269507
+ restoreRecentMcpToolNames(this.agent.context.history, this.loadedToolNames);
269326
269508
  this.steerBuffer.length = 0;
269327
269509
  }
269328
269510
  /**
@@ -269701,11 +269883,13 @@ var init_turn = __esmMin((() => {
269701
269883
  if (current.length !== raw.length || current.some((message, index) => message !== raw[index])) {
269702
269884
  const latest = personalMemoryRecall === void 0 ? current : [...current, personalMemoryRecall];
269703
269885
  const retained = taskToolsNeeded ? latest : greetingHistory(latest, greetingAnchor);
269704
- partialContext = retained.length < latest.length;
269705
- return retained;
269886
+ const request = projectBaselineSkillForTurn(retained, toolInput, origin, turnAnchor);
269887
+ partialContext = retained.length < latest.length || request !== retained;
269888
+ return request;
269706
269889
  }
269707
- partialContext = selected.length < history.length || projected.changed;
269708
- return projected.history;
269890
+ const request = projectBaselineSkillForTurn(projected.history, toolInput, origin, turnAnchor);
269891
+ partialContext = selected.length < history.length || projected.changed || request !== projected.history;
269892
+ return request;
269709
269893
  };
269710
269894
  const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off", turnId);
269711
269895
  const turnTools = this.agent.tools.captureTurnTools();
@@ -273248,15 +273432,17 @@ var init_fallback_llm = __esmMin((() => {
273248
273432
  onModelChanged;
273249
273433
  prepareRequest;
273250
273434
  onContextOverflow;
273435
+ messagePreparation;
273251
273436
  currentIndex = 0;
273252
273437
  attemptedProviders = /* @__PURE__ */ new Set();
273253
273438
  errorsAfterOutput = /* @__PURE__ */ new WeakSet();
273254
273439
  rebuildBoundaryMessages;
273255
- constructor(candidates, onModelChanged = () => {}, prepareRequest, onContextOverflow) {
273440
+ constructor(candidates, onModelChanged = () => {}, prepareRequest, onContextOverflow, messagePreparation = "eager") {
273256
273441
  this.candidates = candidates;
273257
273442
  this.onModelChanged = onModelChanged;
273258
273443
  this.prepareRequest = prepareRequest;
273259
273444
  this.onContextOverflow = onContextOverflow;
273445
+ this.messagePreparation = messagePreparation;
273260
273446
  if (candidates.length === 0) throw new Error("FallbackLLM requires at least one model candidate.");
273261
273447
  }
273262
273448
  get activeAlias() {
@@ -273271,6 +273457,9 @@ var init_fallback_llm = __esmMin((() => {
273271
273457
  get capability() {
273272
273458
  return this.current.llm.capability;
273273
273459
  }
273460
+ get rebuildsMessagesAtRequestBoundary() {
273461
+ return this.messagePreparation === "boundary" && this.prepareRequest !== void 0;
273462
+ }
273274
273463
  async prepareRequestBoundary(params, rebuildMessages) {
273275
273464
  params.signal.throwIfAborted();
273276
273465
  this.rebuildBoundaryMessages = rebuildMessages;
@@ -273984,6 +274173,15 @@ var init_agent = __esmMin((() => {
273984
274173
  };
273985
274174
  if (this.activeProfile !== void 0 && this.rawSystemPromptContext !== void 0 && this.config.systemPrompt === this.profileSystemPromptText) this.updateSystemPromptFromProfile(this.activeProfile, this.fitProfileInstructions(this.activeProfile, this.rawSystemPromptContext, requestTools, true));
273986
274175
  let systemPrompt = this.effectiveSystemPrompt;
274176
+ if (this.config.runtimeModel(_candidate.alias).provider.name === "blun") {
274177
+ const fixedTools = requestTools.filter((tool) => tool.name !== "CompactConversation");
274178
+ const fixedRequestBytes = estimateBlunSerializedBodyBytes(systemPrompt, fixedTools, []) + 4096;
274179
+ if (fixedRequestBytes >= 5e5) throw new BlunError(ErrorCodes.CONTEXT_OVERFLOW, "Fixed instructions or tools exceed the BLUN request limit; compaction cannot reduce them.", { details: {
274180
+ contextBrakeBlocked: true,
274181
+ estimatedRequestBytes: fixedRequestBytes,
274182
+ requestBudgetBytes: 5e5
274183
+ } });
274184
+ }
273987
274185
  const preflightStartedAt = performance.now();
273988
274186
  const compacted = await this.fullCompaction.beforeStep(params.signal, {
273989
274187
  messages: params.messages,
@@ -274028,7 +274226,7 @@ var init_agent = __esmMin((() => {
274028
274226
  };
274029
274227
  }, (candidate, _params, error) => {
274030
274228
  this.fullCompaction.observeContextOverflow(error, candidate.alias);
274031
- });
274229
+ }, "boundary");
274032
274230
  }
274033
274231
  createKosongLLM(modelAlias, thinkingEffort) {
274034
274232
  const runtimeModel = this.config.runtimeModel(modelAlias);
@@ -304107,7 +304305,7 @@ var init_proxy = __esmMin((() => {
304107
304305
  var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304108
304306
  module.exports = isexe;
304109
304307
  isexe.sync = sync;
304110
- var fs$8 = __require("fs");
304308
+ var fs$9 = __require("fs");
304111
304309
  function checkPathExt(path, options) {
304112
304310
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
304113
304311
  if (!pathext) return true;
@@ -304124,12 +304322,12 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304124
304322
  return checkPathExt(path, options);
304125
304323
  }
304126
304324
  function isexe(path, options, cb) {
304127
- fs$8.stat(path, function(er, stat) {
304325
+ fs$9.stat(path, function(er, stat) {
304128
304326
  cb(er, er ? false : checkStat(stat, path, options));
304129
304327
  });
304130
304328
  }
304131
304329
  function sync(path, options) {
304132
- return checkStat(fs$8.statSync(path), path, options);
304330
+ return checkStat(fs$9.statSync(path), path, options);
304133
304331
  }
304134
304332
  }));
304135
304333
  //#endregion
@@ -304137,14 +304335,14 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304137
304335
  var require_mode = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304138
304336
  module.exports = isexe;
304139
304337
  isexe.sync = sync;
304140
- var fs$7 = __require("fs");
304338
+ var fs$8 = __require("fs");
304141
304339
  function isexe(path, options, cb) {
304142
- fs$7.stat(path, function(er, stat) {
304340
+ fs$8.stat(path, function(er, stat) {
304143
304341
  cb(er, er ? false : checkStat(stat, options));
304144
304342
  });
304145
304343
  }
304146
304344
  function sync(path, options) {
304147
- return checkStat(fs$7.statSync(path), options);
304345
+ return checkStat(fs$8.statSync(path), options);
304148
304346
  }
304149
304347
  function checkStat(stat, options) {
304150
304348
  return stat.isFile() && checkMode(stat, options);
@@ -304208,7 +304406,7 @@ var require_isexe = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304208
304406
  //#region ../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js
304209
304407
  var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304210
304408
  const isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
304211
- const path$9 = __require("path");
304409
+ const path$10 = __require("path");
304212
304410
  const COLON = isWindows ? ";" : ":";
304213
304411
  const isexe = require_isexe();
304214
304412
  const getNotFoundError = (cmd) => Object.assign(/* @__PURE__ */ new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -304238,7 +304436,7 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304238
304436
  if (i === pathEnv.length) return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
304239
304437
  const ppRaw = pathEnv[i];
304240
304438
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
304241
- const pCmd = path$9.join(pathPart, cmd);
304439
+ const pCmd = path$10.join(pathPart, cmd);
304242
304440
  resolve(subStep(!pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd, i, 0));
304243
304441
  });
304244
304442
  const subStep = (p, i, ii) => new Promise((resolve, reject) => {
@@ -304259,7 +304457,7 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304259
304457
  for (let i = 0; i < pathEnv.length; i++) {
304260
304458
  const ppRaw = pathEnv[i];
304261
304459
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
304262
- const pCmd = path$9.join(pathPart, cmd);
304460
+ const pCmd = path$10.join(pathPart, cmd);
304263
304461
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
304264
304462
  for (let j = 0; j < pathExt.length; j++) {
304265
304463
  const cur = p + pathExt[j];
@@ -304290,7 +304488,7 @@ var require_path_key = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304290
304488
  //#endregion
304291
304489
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
304292
304490
  var require_resolveCommand = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304293
- const path$8 = __require("path");
304491
+ const path$9 = __require("path");
304294
304492
  const which = require_which();
304295
304493
  const getPathKey = require_path_key();
304296
304494
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -304305,12 +304503,12 @@ var require_resolveCommand = /* @__PURE__ */ __commonJSMin(((exports, module) =>
304305
304503
  try {
304306
304504
  resolved = which.sync(parsed.command, {
304307
304505
  path: env[getPathKey({ env })],
304308
- pathExt: withoutPathExt ? path$8.delimiter : void 0
304506
+ pathExt: withoutPathExt ? path$9.delimiter : void 0
304309
304507
  });
304310
304508
  } catch (e) {} finally {
304311
304509
  if (shouldSwitchCwd) process.chdir(cwd);
304312
304510
  }
304313
- if (resolved) resolved = path$8.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
304511
+ if (resolved) resolved = path$9.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
304314
304512
  return resolved;
304315
304513
  }
304316
304514
  function resolveCommand(parsed) {
@@ -304359,16 +304557,16 @@ var require_shebang_command = /* @__PURE__ */ __commonJSMin(((exports, module) =
304359
304557
  //#endregion
304360
304558
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
304361
304559
  var require_readShebang = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304362
- const fs$6 = __require("fs");
304560
+ const fs$7 = __require("fs");
304363
304561
  const shebangCommand = require_shebang_command();
304364
304562
  function readShebang(command) {
304365
304563
  const size = 150;
304366
304564
  const buffer = Buffer.alloc(size);
304367
304565
  let fd;
304368
304566
  try {
304369
- fd = fs$6.openSync(command, "r");
304370
- fs$6.readSync(fd, buffer, 0, size, 0);
304371
- fs$6.closeSync(fd);
304567
+ fd = fs$7.openSync(command, "r");
304568
+ fs$7.readSync(fd, buffer, 0, size, 0);
304569
+ fs$7.closeSync(fd);
304372
304570
  } catch (e) {}
304373
304571
  return shebangCommand(buffer.toString());
304374
304572
  }
@@ -304377,7 +304575,7 @@ var require_readShebang = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304377
304575
  //#endregion
304378
304576
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
304379
304577
  var require_parse$5 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304380
- const path$7 = __require("path");
304578
+ const path$8 = __require("path");
304381
304579
  const resolveCommand = require_resolveCommand();
304382
304580
  const escape = require_escape();
304383
304581
  const readShebang = require_readShebang();
@@ -304400,7 +304598,7 @@ var require_parse$5 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
304400
304598
  const needsShell = !isExecutableRegExp.test(commandFile);
304401
304599
  if (parsed.options.forceShell || needsShell) {
304402
304600
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
304403
- parsed.command = path$7.normalize(parsed.command);
304601
+ parsed.command = path$8.normalize(parsed.command);
304404
304602
  parsed.command = escape.command(parsed.command);
304405
304603
  parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
304406
304604
  parsed.args = [
@@ -338530,7 +338728,7 @@ var require_dist$5 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
338530
338728
  //#endregion
338531
338729
  //#region ../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js
338532
338730
  var require_yazl = /* @__PURE__ */ __commonJSMin(((exports) => {
338533
- var fs$5 = __require("fs");
338731
+ var fs$6 = __require("fs");
338534
338732
  var Transform$2 = __require("stream").Transform;
338535
338733
  var PassThrough$2 = __require("stream").PassThrough;
338536
338734
  var zlib$1 = __require("zlib");
@@ -338559,14 +338757,14 @@ var require_yazl = /* @__PURE__ */ __commonJSMin(((exports) => {
338559
338757
  if (shouldIgnoreAdding(self)) return;
338560
338758
  var entry = new Entry(metadataPath, false, options);
338561
338759
  self.entries.push(entry);
338562
- fs$5.stat(realPath, function(err, stats) {
338760
+ fs$6.stat(realPath, function(err, stats) {
338563
338761
  if (err) return self.emit("error", err);
338564
338762
  if (!stats.isFile()) return self.emit("error", /* @__PURE__ */ new Error("not a file: " + realPath));
338565
338763
  entry.uncompressedSize = stats.size;
338566
338764
  if (options.mtime == null) entry.setLastModDate(stats.mtime);
338567
338765
  if (options.mode == null) entry.setFileAttributesMode(stats.mode);
338568
338766
  entry.setFileDataPumpFunction(function() {
338569
- var readStream = fs$5.createReadStream(realPath);
338767
+ var readStream = fs$6.createReadStream(realPath);
338570
338768
  entry.state = Entry.FILE_DATA_IN_PROGRESS;
338571
338769
  readStream.on("error", function(err) {
338572
338770
  self.emit("error", err);
@@ -352722,6 +352920,7 @@ var SDKRpcClient = class extends SDKRpcClientBase {
352722
352920
  core;
352723
352921
  ready;
352724
352922
  usesDefaultConfigPath;
352923
+ restoreProfileModel;
352725
352924
  constructor(options = {}) {
352726
352925
  super();
352727
352926
  this.identity = options.identity === void 0 ? void 0 : assertBlunHostIdentity(options.identity);
@@ -352731,9 +352930,11 @@ var SDKRpcClient = class extends SDKRpcClientBase {
352731
352930
  configPath: options.configPath
352732
352931
  });
352733
352932
  this.usesDefaultConfigPath = options.configPath === void 0;
352933
+ const authHomeDir = authHomeForProfile(this.homeDir);
352934
+ this.restoreProfileModel = this.usesDefaultConfigPath && authHomeDir !== this.homeDir;
352734
352935
  this.telemetry = options.telemetry ?? noopTelemetryClient;
352735
352936
  this.auth = new BlunAuthFacade({
352736
- homeDir: authHomeForProfile(this.homeDir),
352937
+ homeDir: authHomeDir,
352737
352938
  configPath: this.configPath,
352738
352939
  identity: this.identity,
352739
352940
  onRefresh: options.onOAuthRefresh
@@ -352753,7 +352954,7 @@ var SDKRpcClient = class extends SDKRpcClientBase {
352753
352954
  }
352754
352955
  async ensureConfigFile() {
352755
352956
  await ensureConfigFile(this.configPath);
352756
- if (this.usesDefaultConfigPath && authHomeForProfile(this.homeDir) !== this.homeDir) await this.auth.restoreMissingProfileModel();
352957
+ if (this.restoreProfileModel) await this.auth.restoreMissingProfileModel();
352757
352958
  }
352758
352959
  async close() {
352759
352960
  try {
@@ -354526,8 +354727,8 @@ var require_suggestSimilar = /* @__PURE__ */ __commonJSMin(((exports) => {
354526
354727
  var require_command = /* @__PURE__ */ __commonJSMin(((exports) => {
354527
354728
  const EventEmitter$12 = __require("node:events").EventEmitter;
354528
354729
  const childProcess = __require("node:child_process");
354529
- const path$6 = __require("node:path");
354530
- const fs$4 = __require("node:fs");
354730
+ const path$7 = __require("node:path");
354731
+ const fs$5 = __require("node:fs");
354531
354732
  const process$2 = __require("node:process");
354532
354733
  const { Argument, humanReadableArgName } = require_argument();
354533
354734
  const { CommanderError } = require_error$2();
@@ -355410,7 +355611,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
355410
355611
  * @param {string} subcommandName
355411
355612
  */
355412
355613
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
355413
- if (fs$4.existsSync(executableFile)) return;
355614
+ if (fs$5.existsSync(executableFile)) return;
355414
355615
  const executableMissing = `'${executableFile}' does not exist
355415
355616
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
355416
355617
  - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
@@ -355433,10 +355634,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
355433
355634
  ".cjs"
355434
355635
  ];
355435
355636
  function findFile(baseDir, baseName) {
355436
- const localBin = path$6.resolve(baseDir, baseName);
355437
- if (fs$4.existsSync(localBin)) return localBin;
355438
- if (sourceExt.includes(path$6.extname(baseName))) return void 0;
355439
- const foundExt = sourceExt.find((ext) => fs$4.existsSync(`${localBin}${ext}`));
355637
+ const localBin = path$7.resolve(baseDir, baseName);
355638
+ if (fs$5.existsSync(localBin)) return localBin;
355639
+ if (sourceExt.includes(path$7.extname(baseName))) return void 0;
355640
+ const foundExt = sourceExt.find((ext) => fs$5.existsSync(`${localBin}${ext}`));
355440
355641
  if (foundExt) return `${localBin}${foundExt}`;
355441
355642
  }
355442
355643
  this._checkForMissingMandatoryOptions();
@@ -355446,21 +355647,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
355446
355647
  if (this._scriptPath) {
355447
355648
  let resolvedScriptPath;
355448
355649
  try {
355449
- resolvedScriptPath = fs$4.realpathSync(this._scriptPath);
355650
+ resolvedScriptPath = fs$5.realpathSync(this._scriptPath);
355450
355651
  } catch {
355451
355652
  resolvedScriptPath = this._scriptPath;
355452
355653
  }
355453
- executableDir = path$6.resolve(path$6.dirname(resolvedScriptPath), executableDir);
355654
+ executableDir = path$7.resolve(path$7.dirname(resolvedScriptPath), executableDir);
355454
355655
  }
355455
355656
  if (executableDir) {
355456
355657
  let localFile = findFile(executableDir, executableFile);
355457
355658
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
355458
- const legacyName = path$6.basename(this._scriptPath, path$6.extname(this._scriptPath));
355659
+ const legacyName = path$7.basename(this._scriptPath, path$7.extname(this._scriptPath));
355459
355660
  if (legacyName !== this._name) localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
355460
355661
  }
355461
355662
  executableFile = localFile || executableFile;
355462
355663
  }
355463
- launchWithNode = sourceExt.includes(path$6.extname(executableFile));
355664
+ launchWithNode = sourceExt.includes(path$7.extname(executableFile));
355464
355665
  let proc;
355465
355666
  if (process$2.platform !== "win32") if (launchWithNode) {
355466
355667
  args.unshift(executableFile);
@@ -356164,7 +356365,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
356164
356365
  * @return {Command}
356165
356366
  */
356166
356367
  nameFromFilename(filename) {
356167
- this._name = path$6.basename(filename, path$6.extname(filename));
356368
+ this._name = path$7.basename(filename, path$7.extname(filename));
356168
356369
  return this;
356169
356370
  }
356170
356371
  /**
@@ -374026,10 +374227,10 @@ var require_atomic_sleep = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374026
374227
  //#endregion
374027
374228
  //#region ../../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js
374028
374229
  var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374029
- const fs$3 = __require("fs");
374230
+ const fs$4 = __require("fs");
374030
374231
  const EventEmitter$10 = __require("events");
374031
374232
  const inherits$6 = __require("util").inherits;
374032
- const path$5 = __require("path");
374233
+ const path$6 = __require("path");
374033
374234
  const sleep = require_atomic_sleep();
374034
374235
  const assert$8 = __require("assert");
374035
374236
  const BUSY_WRITE_TIMEOUT = 100;
@@ -374069,17 +374270,17 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374069
374270
  const flags = sonic.append ? "a" : "w";
374070
374271
  const mode = sonic.mode;
374071
374272
  if (sonic.sync) try {
374072
- if (sonic.mkdir) fs$3.mkdirSync(path$5.dirname(file), { recursive: true });
374073
- fileOpened(null, fs$3.openSync(file, flags, mode));
374273
+ if (sonic.mkdir) fs$4.mkdirSync(path$6.dirname(file), { recursive: true });
374274
+ fileOpened(null, fs$4.openSync(file, flags, mode));
374074
374275
  } catch (err) {
374075
374276
  fileOpened(err);
374076
374277
  throw err;
374077
374278
  }
374078
- else if (sonic.mkdir) fs$3.mkdir(path$5.dirname(file), { recursive: true }, (err) => {
374279
+ else if (sonic.mkdir) fs$4.mkdir(path$6.dirname(file), { recursive: true }, (err) => {
374079
374280
  if (err) return fileOpened(err);
374080
- fs$3.open(file, flags, mode, fileOpened);
374281
+ fs$4.open(file, flags, mode, fileOpened);
374081
374282
  });
374082
- else fs$3.open(file, flags, mode, fileOpened);
374283
+ else fs$4.open(file, flags, mode, fileOpened);
374083
374284
  }
374084
374285
  function SonicBoom(opts) {
374085
374286
  if (!(this instanceof SonicBoom)) return new SonicBoom(opts);
@@ -374117,8 +374318,8 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374117
374318
  this.flush = flushBuffer;
374118
374319
  this.flushSync = flushBufferSync;
374119
374320
  this._actualWrite = actualWriteBuffer;
374120
- fsWriteSync = () => fs$3.writeSync(this.fd, this._writingBuf);
374121
- fsWrite = () => fs$3.write(this.fd, this._writingBuf, this.release);
374321
+ fsWriteSync = () => fs$4.writeSync(this.fd, this._writingBuf);
374322
+ fsWrite = () => fs$4.write(this.fd, this._writingBuf, this.release);
374122
374323
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
374123
374324
  this._writingBuf = "";
374124
374325
  this.write = write;
@@ -374126,12 +374327,12 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374126
374327
  this.flushSync = flushSync;
374127
374328
  this._actualWrite = actualWrite;
374128
374329
  fsWriteSync = () => {
374129
- if (Buffer.isBuffer(this._writingBuf)) return fs$3.writeSync(this.fd, this._writingBuf);
374130
- return fs$3.writeSync(this.fd, this._writingBuf, "utf8");
374330
+ if (Buffer.isBuffer(this._writingBuf)) return fs$4.writeSync(this.fd, this._writingBuf);
374331
+ return fs$4.writeSync(this.fd, this._writingBuf, "utf8");
374131
374332
  };
374132
374333
  fsWrite = () => {
374133
- if (Buffer.isBuffer(this._writingBuf)) return fs$3.write(this.fd, this._writingBuf, this.release);
374134
- return fs$3.write(this.fd, this._writingBuf, "utf8", this.release);
374334
+ if (Buffer.isBuffer(this._writingBuf)) return fs$4.write(this.fd, this._writingBuf, this.release);
374335
+ return fs$4.write(this.fd, this._writingBuf, "utf8", this.release);
374135
374336
  };
374136
374337
  } else throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
374137
374338
  if (typeof fd === "number") {
@@ -374176,7 +374377,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374176
374377
  return;
374177
374378
  }
374178
374379
  }
374179
- if (this._fsync) fs$3.fsyncSync(this.fd);
374380
+ if (this._fsync) fs$4.fsyncSync(this.fd);
374180
374381
  const len = this._len;
374181
374382
  if (this._reopening) {
374182
374383
  this._writing = false;
@@ -374273,7 +374474,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374273
374474
  this._flushPending = true;
374274
374475
  const onDrain = () => {
374275
374476
  if (!this._fsync) try {
374276
- fs$3.fsync(this.fd, (err) => {
374477
+ fs$4.fsync(this.fd, (err) => {
374277
374478
  this._flushPending = false;
374278
374479
  cb(err);
374279
374480
  });
@@ -374350,7 +374551,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374350
374551
  if (this._writing) return;
374351
374552
  const fd = this.fd;
374352
374553
  this.once("ready", () => {
374353
- if (fd !== this.fd) fs$3.close(fd, (err) => {
374554
+ if (fd !== this.fd) fs$4.close(fd, (err) => {
374354
374555
  if (err) return this.emit("error", err);
374355
374556
  });
374356
374557
  });
@@ -374381,7 +374582,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374381
374582
  while (this._bufs.length || buf.length) {
374382
374583
  if (buf.length <= 0) buf = this._bufs[0];
374383
374584
  try {
374384
- const n = Buffer.isBuffer(buf) ? fs$3.writeSync(this.fd, buf) : fs$3.writeSync(this.fd, buf, "utf8");
374585
+ const n = Buffer.isBuffer(buf) ? fs$4.writeSync(this.fd, buf) : fs$4.writeSync(this.fd, buf, "utf8");
374385
374586
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
374386
374587
  buf = releasedBufObj.writingBuf;
374387
374588
  this._len = releasedBufObj.len;
@@ -374392,7 +374593,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374392
374593
  }
374393
374594
  }
374394
374595
  try {
374395
- fs$3.fsyncSync(this.fd);
374596
+ fs$4.fsyncSync(this.fd);
374396
374597
  } catch {}
374397
374598
  }
374398
374599
  function flushBufferSync() {
@@ -374406,7 +374607,7 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374406
374607
  while (this._bufs.length || buf.length) {
374407
374608
  if (buf.length <= 0) buf = mergeBuf(this._bufs[0], this._lens[0]);
374408
374609
  try {
374409
- const n = fs$3.writeSync(this.fd, buf);
374610
+ const n = fs$4.writeSync(this.fd, buf);
374410
374611
  buf = buf.subarray(n);
374411
374612
  this._len = Math.max(this._len - n, 0);
374412
374613
  if (buf.length <= 0) {
@@ -374428,24 +374629,24 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374428
374629
  this._writing = true;
374429
374630
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
374430
374631
  if (this.sync) try {
374431
- release(null, Buffer.isBuffer(this._writingBuf) ? fs$3.writeSync(this.fd, this._writingBuf) : fs$3.writeSync(this.fd, this._writingBuf, "utf8"));
374632
+ release(null, Buffer.isBuffer(this._writingBuf) ? fs$4.writeSync(this.fd, this._writingBuf) : fs$4.writeSync(this.fd, this._writingBuf, "utf8"));
374432
374633
  } catch (err) {
374433
374634
  release(err);
374434
374635
  }
374435
- else fs$3.write(this.fd, this._writingBuf, release);
374636
+ else fs$4.write(this.fd, this._writingBuf, release);
374436
374637
  }
374437
374638
  function actualWriteBuffer() {
374438
374639
  const release = this.release;
374439
374640
  this._writing = true;
374440
374641
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
374441
374642
  if (this.sync) try {
374442
- release(null, fs$3.writeSync(this.fd, this._writingBuf));
374643
+ release(null, fs$4.writeSync(this.fd, this._writingBuf));
374443
374644
  } catch (err) {
374444
374645
  release(err);
374445
374646
  }
374446
374647
  else {
374447
374648
  if (kCopyBuffer) this._writingBuf = Buffer.from(this._writingBuf);
374448
- fs$3.write(this.fd, this._writingBuf, release);
374649
+ fs$4.write(this.fd, this._writingBuf, release);
374449
374650
  }
374450
374651
  }
374451
374652
  function actualClose(sonic) {
@@ -374459,10 +374660,10 @@ var require_sonic_boom = /* @__PURE__ */ __commonJSMin(((exports, module) => {
374459
374660
  sonic._lens = [];
374460
374661
  assert$8(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
374461
374662
  try {
374462
- fs$3.fsync(sonic.fd, closeWrapped);
374663
+ fs$4.fsync(sonic.fd, closeWrapped);
374463
374664
  } catch {}
374464
374665
  function closeWrapped() {
374465
- if (sonic.fd !== 1 && sonic.fd !== 2) fs$3.close(sonic.fd, done);
374666
+ if (sonic.fd !== 1 && sonic.fd !== 2) fs$4.close(sonic.fd, done);
374466
374667
  else done();
374467
374668
  }
374468
374669
  function done(err) {
@@ -404102,7 +404303,7 @@ var import_multipart = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((
404102
404303
  const fp = require_plugin();
404103
404304
  const { createWriteStream: createWriteStream$1 } = __require("node:fs");
404104
404305
  const { unlink: unlink$1 } = __require("node:fs/promises");
404105
- const path$4 = __require("node:path");
404306
+ const path$5 = __require("node:path");
404106
404307
  const { generateId } = require_generateId();
404107
404308
  const createError = require_error$1();
404108
404309
  const streamToNull = require_stream_consumer();
@@ -404397,7 +404598,7 @@ var import_multipart = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((
404397
404598
  for await (const part of parts) {
404398
404599
  values = part.fields;
404399
404600
  if (!part.file) continue;
404400
- const filepath = path$4.join(tmpdir, generateId() + path$4.extname(part.filename || "file" + i++));
404601
+ const filepath = path$5.join(tmpdir, generateId() + path$5.extname(part.filename || "file" + i++));
404401
404602
  const target = createWriteStream$1(filepath);
404402
404603
  try {
404403
404604
  this.tmpUploads.push(filepath);
@@ -417138,8 +417339,8 @@ var require_dist$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
417138
417339
  //#endregion
417139
417340
  //#region ../../node_modules/.pnpm/@fastify+swagger@9.7.0/node_modules/@fastify/swagger/lib/mode/static.js
417140
417341
  var require_static = /* @__PURE__ */ __commonJSMin(((exports, module) => {
417141
- const path$3 = __require("node:path");
417142
- const fs$2 = __require("node:fs");
417342
+ const path$4 = __require("node:path");
417343
+ const fs$3 = __require("node:fs");
417143
417344
  const yaml = require_dist$1();
417144
417345
  module.exports = function(fastify, opts, done) {
417145
417346
  if (!opts.specification) return done(/* @__PURE__ */ new Error("specification is missing in the module options"));
@@ -417148,14 +417349,14 @@ var require_static = /* @__PURE__ */ __commonJSMin(((exports, module) => {
417148
417349
  if (!opts.specification.path && !opts.specification.document) return done(/* @__PURE__ */ new Error("both specification.path and specification.document are missing, should be path to the file or swagger document spec"));
417149
417350
  else if (opts.specification.path) {
417150
417351
  if (typeof opts.specification.path !== "string") return done(/* @__PURE__ */ new Error("specification.path is not a string"));
417151
- if (!fs$2.existsSync(path$3.resolve(opts.specification.path))) return done(/* @__PURE__ */ new Error(`${opts.specification.path} does not exist`));
417152
- const extName = path$3.extname(opts.specification.path).toLowerCase();
417352
+ if (!fs$3.existsSync(path$4.resolve(opts.specification.path))) return done(/* @__PURE__ */ new Error(`${opts.specification.path} does not exist`));
417353
+ const extName = path$4.extname(opts.specification.path).toLowerCase();
417153
417354
  if ([".yaml", ".json"].indexOf(extName) === -1) return done(/* @__PURE__ */ new Error("specification.path extension name is not supported, should be one from ['.yaml', '.json']"));
417154
417355
  if (opts.specification.postProcessor && typeof opts.specification.postProcessor !== "function") return done(/* @__PURE__ */ new Error("specification.postProcessor should be a function"));
417155
417356
  if (opts.specification.baseDir && typeof opts.specification.baseDir !== "string") return done(/* @__PURE__ */ new Error("specification.baseDir should be string"));
417156
- if (!opts.specification.baseDir) opts.specification.baseDir = path$3.resolve(path$3.dirname(opts.specification.path));
417357
+ if (!opts.specification.baseDir) opts.specification.baseDir = path$4.resolve(path$4.dirname(opts.specification.path));
417157
417358
  else while (opts.specification.baseDir.endsWith("/")) opts.specification.baseDir = opts.specification.baseDir.slice(0, -1);
417158
- const source = fs$2.readFileSync(path$3.resolve(opts.specification.path), "utf8");
417359
+ const source = fs$3.readFileSync(path$4.resolve(opts.specification.path), "utf8");
417159
417360
  switch (extName) {
417160
417361
  case ".yaml":
417161
417362
  swaggerObject = yaml.parse(source);
@@ -417422,11 +417623,11 @@ var require_should_route_hide = /* @__PURE__ */ __commonJSMin(((exports, module)
417422
417623
  //#endregion
417423
417624
  //#region ../../node_modules/.pnpm/@fastify+swagger@9.7.0/node_modules/@fastify/swagger/lib/util/read-package-json.js
417424
417625
  var require_read_package_json = /* @__PURE__ */ __commonJSMin(((exports, module) => {
417425
- const fs$1 = __require("node:fs");
417426
- const path$2 = __require("node:path");
417626
+ const fs$2 = __require("node:fs");
417627
+ const path$3 = __require("node:path");
417427
417628
  function readPackageJson() {
417428
417629
  try {
417429
- return JSON.parse(fs$1.readFileSync(path$2.join(__dirname, "..", "..", "package.json")));
417630
+ return JSON.parse(fs$2.readFileSync(path$3.join(__dirname, "..", "..", "package.json")));
417430
417631
  } catch {
417431
417632
  return {};
417432
417633
  }
@@ -434409,9 +434610,9 @@ var TUI = class TUI extends Container {
434409
434610
  const debugRedraw = process.env["PI_DEBUG_REDRAW"] === "1";
434410
434611
  const logRedraw = (reason) => {
434411
434612
  if (!debugRedraw) return;
434412
- const logPath = path$16.join(nodeOs.homedir(), ".pi", "agent", "pi-debug.log");
434613
+ const logPath = path$17.join(nodeOs.homedir(), ".pi", "agent", "pi-debug.log");
434413
434614
  const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\n`;
434414
- fs$16.appendFileSync(logPath, msg);
434615
+ fs$17.appendFileSync(logPath, msg);
434415
434616
  };
434416
434617
  if (this.previousLines.length === 0 && !widthChanged && !heightChanged) {
434417
434618
  logRedraw("first render");
@@ -434558,8 +434759,8 @@ var TUI = class TUI extends Container {
434558
434759
  buffer += "\x1B[?2026l";
434559
434760
  if (process.env["PI_TUI_DEBUG"] === "1") {
434560
434761
  const debugDir = "/tmp/tui";
434561
- fs$16.mkdirSync(debugDir, { recursive: true });
434562
- const debugPath = path$16.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
434762
+ fs$17.mkdirSync(debugDir, { recursive: true });
434763
+ const debugPath = path$17.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
434563
434764
  const debugData = [
434564
434765
  `firstChanged: ${firstChanged}`,
434565
434766
  `viewportTop: ${viewportTop}`,
@@ -434582,7 +434783,7 @@ var TUI = class TUI extends Container {
434582
434783
  "=== buffer ===",
434583
434784
  JSON.stringify(buffer)
434584
434785
  ].join("\n");
434585
- fs$16.writeFileSync(debugPath, debugData);
434786
+ fs$17.writeFileSync(debugPath, debugData);
434586
434787
  }
434587
434788
  this.terminal.write(buffer);
434588
434789
  this.cursorRow = Math.max(0, newLines.length - 1);
@@ -439168,12 +439369,12 @@ function loadNativeModifiersHelper() {
439168
439369
  if (process.platform !== "darwin") return void 0;
439169
439370
  const arch = process.arch;
439170
439371
  if (arch !== "x64" && arch !== "arm64") return void 0;
439171
- const moduleDir = path$16.dirname(fileURLToPath(import.meta.url));
439172
- const nativePath = path$16.join("native", "darwin", "prebuilds", `darwin-${arch}`, "darwin-modifiers.node");
439372
+ const moduleDir = path$17.dirname(fileURLToPath(import.meta.url));
439373
+ const nativePath = path$17.join("native", "darwin", "prebuilds", `darwin-${arch}`, "darwin-modifiers.node");
439173
439374
  const candidates = [
439174
- path$16.join(moduleDir, "..", nativePath),
439175
- path$16.join(moduleDir, nativePath),
439176
- path$16.join(path$16.dirname(process.execPath), nativePath)
439375
+ path$17.join(moduleDir, "..", nativePath),
439376
+ path$17.join(moduleDir, nativePath),
439377
+ path$17.join(path$17.dirname(process.execPath), nativePath)
439177
439378
  ];
439178
439379
  for (const modulePath of candidates) try {
439179
439380
  const helper = cjsRequire$1(modulePath);
@@ -439246,10 +439447,10 @@ var ProcessTerminal = class {
439246
439447
  const env = process.env["PI_TUI_WRITE_LOG"] || "";
439247
439448
  if (!env) return "";
439248
439449
  try {
439249
- if (fs$16.statSync(env).isDirectory()) {
439450
+ if (fs$17.statSync(env).isDirectory()) {
439250
439451
  const now = /* @__PURE__ */ new Date();
439251
439452
  const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}-${String(now.getSeconds()).padStart(2, "0")}`;
439252
- return path$16.join(env, `tui-${ts}-${process.pid}.log`);
439453
+ return path$17.join(env, `tui-${ts}-${process.pid}.log`);
439253
439454
  }
439254
439455
  } catch {}
439255
439456
  return env;
@@ -439452,12 +439653,12 @@ var ProcessTerminal = class {
439452
439653
  try {
439453
439654
  const arch = process.arch;
439454
439655
  if (arch !== "x64" && arch !== "arm64") return;
439455
- const moduleDir = path$16.dirname(fileURLToPath(import.meta.url));
439456
- const nativePath = path$16.join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node");
439656
+ const moduleDir = path$17.dirname(fileURLToPath(import.meta.url));
439657
+ const nativePath = path$17.join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node");
439457
439658
  const candidates = [
439458
- path$16.join(moduleDir, "..", nativePath),
439459
- path$16.join(moduleDir, nativePath),
439460
- path$16.join(path$16.dirname(process.execPath), nativePath)
439659
+ path$17.join(moduleDir, "..", nativePath),
439660
+ path$17.join(moduleDir, nativePath),
439661
+ path$17.join(path$17.dirname(process.execPath), nativePath)
439461
439662
  ];
439462
439663
  for (const modulePath of candidates) try {
439463
439664
  cjsRequire(modulePath).enableVirtualTerminalInput?.();
@@ -439529,7 +439730,7 @@ var ProcessTerminal = class {
439529
439730
  write(data) {
439530
439731
  process.stdout.write(data);
439531
439732
  if (this.writeLogPath) try {
439532
- fs$16.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
439733
+ fs$17.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
439533
439734
  } catch {}
439534
439735
  }
439535
439736
  get columns() {
@@ -515919,7 +516120,8 @@ var TelegramAccessMenuComponent = class extends Container {
515919
516120
  kind: "target",
515920
516121
  editIndex,
515921
516122
  activeField: "id",
515922
- targetType: current?.type ?? "dm"
516123
+ targetType: current?.type ?? "dm",
516124
+ activation: current?.activation ?? "mention"
515923
516125
  };
515924
516126
  }
515925
516127
  handleTargetInput(data) {
@@ -515933,15 +516135,34 @@ var TelegramAccessMenuComponent = class extends Container {
515933
516135
  return;
515934
516136
  }
515935
516137
  if (matchesKey(data, Key.tab) || matchesKey(data, Key.shift("tab"))) {
515936
- this.setTargetField(mode.activeField === "id" ? "type" : "id");
516138
+ const fields = mode.targetType === "group" ? [
516139
+ "id",
516140
+ "type",
516141
+ "activation"
516142
+ ] : ["id", "type"];
516143
+ const direction = matchesKey(data, Key.shift("tab")) ? -1 : 1;
516144
+ const next = (fields.indexOf(mode.activeField) + direction + fields.length) % fields.length;
516145
+ this.setTargetField(fields[next]);
515937
516146
  return;
515938
516147
  }
515939
516148
  if (matchesKey(data, Key.up)) {
515940
- this.setTargetField("id");
516149
+ this.setTargetField(mode.activeField === "activation" ? "type" : "id");
515941
516150
  return;
515942
516151
  }
515943
516152
  if (matchesKey(data, Key.down)) {
515944
- this.setTargetField("type");
516153
+ this.setTargetField(mode.activeField !== "id" && mode.targetType === "group" ? "activation" : "type");
516154
+ return;
516155
+ }
516156
+ if (mode.activeField === "activation") {
516157
+ const ch = printableChar(data);
516158
+ if (matchesKey(data, Key.left) || matchesKey(data, Key.right) || ch === " ") {
516159
+ this.mode = {
516160
+ ...mode,
516161
+ activation: mode.activation === "mention" ? "always" : "mention"
516162
+ };
516163
+ this.notice = void 0;
516164
+ this.invalidate();
516165
+ } else if (matchesKey(data, Key.enter)) this.commitTarget(mode);
515945
516166
  return;
515946
516167
  }
515947
516168
  if (mode.activeField === "type") {
@@ -515971,8 +516192,8 @@ var TelegramAccessMenuComponent = class extends Container {
515971
516192
  this.invalidate();
515972
516193
  }
515973
516194
  commitTarget(mode) {
515974
- const target = normalizeTelegramAccessTarget(mode.targetType, this.targetInput.getValue());
515975
- if (target === void 0) {
516195
+ const normalized = normalizeTelegramAccessTarget(mode.targetType, this.targetInput.getValue());
516196
+ if (normalized === void 0) {
515976
516197
  this.notice = {
515977
516198
  key: mode.targetType === "dm" ? "telegramAccess.target.errorDm" : "telegramAccess.target.errorGroup",
515978
516199
  tone: "warning"
@@ -515984,6 +516205,10 @@ var TelegramAccessMenuComponent = class extends Container {
515984
516205
  this.invalidate();
515985
516206
  return;
515986
516207
  }
516208
+ const target = normalized.type === "group" ? {
516209
+ ...normalized,
516210
+ activation: mode.activation
516211
+ } : normalized;
515987
516212
  if (this.targets.some((candidate, index) => index !== mode.editIndex && candidate.type === target.type && candidate.id === target.id)) {
515988
516213
  this.notice = {
515989
516214
  key: "telegramAccess.target.errorDuplicate",
@@ -516091,7 +516316,10 @@ var TelegramAccessMenuComponent = class extends Container {
516091
516316
  const tone = this.tokenConfigured ? "success" : "warning";
516092
516317
  return ` ${prefix}${labelStyle(uiText("telegramAccess.token"))} ${currentTheme.fg(tone, status)}`;
516093
516318
  }
516094
- case "target": return ` ${prefix}${labelStyle(this.targetTypeLabel(row.target.type))} ${currentTheme.fg("textMuted", row.target.id)}`;
516319
+ case "target": {
516320
+ const activation = row.target.type === "group" ? ` ${currentTheme.fg("textDim", row.target.activation ?? "mention")}` : "";
516321
+ return ` ${prefix}${labelStyle(this.targetTypeLabel(row.target.type))} ${currentTheme.fg("textMuted", row.target.id)}${activation}`;
516322
+ }
516095
516323
  case "add": return ` ${prefix}${labelStyle(uiText("telegramAccess.add"))}`;
516096
516324
  case "save": return ` ${prefix}${labelStyle(uiText("telegramAccess.save"))}`;
516097
516325
  }
@@ -516112,9 +516340,11 @@ var TelegramAccessMenuComponent = class extends Container {
516112
516340
  renderTargetInput(width, mode) {
516113
516341
  const idActive = mode.activeField === "id";
516114
516342
  const idLabel = idActive ? currentTheme.boldFg("accent", uiText("telegramAccess.target.id")) : currentTheme.fg("textDim", uiText("telegramAccess.target.id"));
516115
- const typeLabel = !idActive ? currentTheme.boldFg("accent", uiText("telegramAccess.target.type")) : currentTheme.fg("textDim", uiText("telegramAccess.target.type"));
516116
- const dm = this.renderTypeChoice("dm", mode.targetType, !idActive);
516117
- const group = this.renderTypeChoice("group", mode.targetType, !idActive);
516343
+ const typeActive = mode.activeField === "type";
516344
+ const activationActive = mode.activeField === "activation";
516345
+ const typeLabel = typeActive ? currentTheme.boldFg("accent", uiText("telegramAccess.target.type")) : currentTheme.fg("textDim", uiText("telegramAccess.target.type"));
516346
+ const dm = this.renderChoice(this.targetTypeLabel("dm"), mode.targetType === "dm", typeActive);
516347
+ const group = this.renderChoice(this.targetTypeLabel("group"), mode.targetType === "group", typeActive);
516118
516348
  const title = uiText(mode.editIndex === void 0 ? "telegramAccess.target.addTitle" : "telegramAccess.target.editTitle");
516119
516349
  return this.renderInputBox(width, [
516120
516350
  currentTheme.boldFg("textStrong", title),
@@ -516126,14 +516356,18 @@ var TelegramAccessMenuComponent = class extends Container {
516126
516356
  "",
516127
516357
  typeLabel,
516128
516358
  `${dm} ${group}`,
516359
+ ...mode.targetType === "group" ? [
516360
+ "",
516361
+ activationActive ? currentTheme.boldFg("accent", "requireMention") : currentTheme.fg("textDim", "requireMention"),
516362
+ `${this.renderChoice("mention", mode.activation === "mention", activationActive)} ${this.renderChoice("always", mode.activation === "always", activationActive)}`
516363
+ ] : [],
516129
516364
  ...this.notice === void 0 ? [] : ["", currentTheme.fg(this.notice.tone, this.noticeText())],
516130
516365
  "",
516131
516366
  currentTheme.fg("textDim", uiText(idActive ? "telegramAccess.target.footerId" : "telegramAccess.target.footerType"))
516132
516367
  ]);
516133
516368
  }
516134
- renderTypeChoice(type, selectedType, fieldActive) {
516135
- const label = this.targetTypeLabel(type);
516136
- if (type === selectedType) return fieldActive ? currentTheme.boldFg("primary", `[ ${label} ]`) : currentTheme.fg("text", `[ ${label} ]`);
516369
+ renderChoice(label, selected, fieldActive) {
516370
+ if (selected) return fieldActive ? currentTheme.boldFg("primary", `[ ${label} ]`) : currentTheme.fg("text", `[ ${label} ]`);
516137
516371
  return currentTheme.fg("textMuted", label);
516138
516372
  }
516139
516373
  targetTypeLabel(type) {
@@ -516238,7 +516472,10 @@ function targetsFromDocument(document) {
516238
516472
  if (!isObject$2(policy)) throw new TelegramAccessStorageError("invalid-access");
516239
516473
  const target = normalizeTelegramAccessTarget("group", id);
516240
516474
  if (target === void 0 || target.id !== id) throw new TelegramAccessStorageError("invalid-access");
516241
- groups.push(target);
516475
+ groups.push({
516476
+ ...target,
516477
+ activation: policy["requireMention"] === false ? "always" : "mention"
516478
+ });
516242
516479
  }
516243
516480
  return deduplicateTargets([...dms, ...groups]);
516244
516481
  }
@@ -516259,10 +516496,14 @@ function normalizeDraftTargets(targets) {
516259
516496
  for (const target of targets) {
516260
516497
  const value = normalizeTelegramAccessTarget(target.type, target.id);
516261
516498
  if (value === void 0) throw new TelegramAccessStorageError("invalid-target");
516499
+ if (target.activation !== void 0 && (target.type !== "group" || target.activation !== "mention" && target.activation !== "always")) throw new TelegramAccessStorageError("invalid-target");
516262
516500
  const key = `${value.type}:${value.id}`;
516263
516501
  if (seen.has(key)) throw new TelegramAccessStorageError("invalid-target");
516264
516502
  seen.add(key);
516265
- normalized.push(value);
516503
+ normalized.push(target.activation === void 0 ? value : {
516504
+ ...value,
516505
+ activation: target.activation
516506
+ });
516266
516507
  }
516267
516508
  return normalized;
516268
516509
  }
@@ -516276,10 +516517,14 @@ function nextAccessDocument(current, targets) {
516276
516517
  continue;
516277
516518
  }
516278
516519
  const currentPolicy = currentGroups[target.id];
516279
- groups[target.id] = isObject$2(currentPolicy) ? currentPolicy : {
516520
+ const policy = isObject$2(currentPolicy) ? currentPolicy : {
516280
516521
  requireMention: true,
516281
516522
  allowFrom: []
516282
516523
  };
516524
+ groups[target.id] = target.activation === void 0 ? policy : {
516525
+ ...policy,
516526
+ requireMention: target.activation === "mention"
516527
+ };
516283
516528
  }
516284
516529
  return {
516285
516530
  ...current,
@@ -519269,6 +519514,335 @@ function accumulatedProgressBar(ticks, width, filledColor, colors, emptyColorFor
519269
519514
  return out;
519270
519515
  }
519271
519516
  //#endregion
519517
+ //#region src/tui/constant/goal-channel-replies.ts
519518
+ const GOAL_REPLY_RETRY_DELAY_MS = 1e3;
519519
+ const GOAL_REPLY_REQUEST_TIMEOUT_MS = 15e3;
519520
+ const TELEGRAM_GOAL_REPLY_TOOL_NAME = /^mcp__(?:telegram|plugin-telegram_telegram)__(?:reply|edit_message)$/iu;
519521
+ //#endregion
519522
+ //#region src/tui/utils/telegram-text-chunks.ts
519523
+ /** Split on UTF-16 boundaries without losing whitespace or supplementary characters. */
519524
+ function splitTelegramText(text, limit) {
519525
+ if (!Number.isSafeInteger(limit) || limit < 2) throw new RangeError("Invalid Telegram chunk limit");
519526
+ const chunks = [];
519527
+ for (let start = 0; start < text.length;) {
519528
+ let end = Math.min(text.length, start + limit);
519529
+ if (end < text.length) {
519530
+ const minimum = start + Math.floor((end - start) / 2);
519531
+ for (const boundary of [
519532
+ "\n\n",
519533
+ "\n",
519534
+ " "
519535
+ ]) {
519536
+ const index = text.lastIndexOf(boundary, end - 1);
519537
+ if (index >= minimum) {
519538
+ end = index + boundary.length;
519539
+ break;
519540
+ }
519541
+ }
519542
+ if ((text.codePointAt(end - 1) ?? 0) > 65535) end -= 1;
519543
+ }
519544
+ chunks.push(text.slice(start, end));
519545
+ start = end;
519546
+ }
519547
+ return chunks;
519548
+ }
519549
+ //#endregion
519550
+ //#region src/tui/utils/telegram-reply-fallback.ts
519551
+ /**
519552
+ * Deterministic Telegram reply fallback for channel-origin turns.
519553
+ *
519554
+ * Small models reliably DO the work (Bash/Read/...) but often end a
519555
+ * channel-origin turn without calling the telegram reply tool — the answer
519556
+ * then dies in the console and the sender never sees it. This module makes
519557
+ * delivery a harness guarantee instead of a model courtesy: after a channel
519558
+ * turn finishes, the TUI checks whether the reply tool actually ran (the MCP
519559
+ * server appends to outbox.jsonl on every send) and, if not, sends the turn's
519560
+ * final assistant text itself via the plain Bot API.
519561
+ *
519562
+ * Dependency-free on purpose (fs + global fetch); mirrors the CRLF-tolerant
519563
+ * .env parsing of plugins/telegram/src/state.ts.
519564
+ */
519565
+ init_dist$6();
519566
+ function channelDir() {
519567
+ const base = process.env["BLUN_HOME"]?.trim();
519568
+ return join$4(base !== void 0 && base.length > 0 ? base : join$4(homedir(), ".blun"), "channels", "telegram");
519569
+ }
519570
+ function outboxPath() {
519571
+ return join$4(channelDir(), "outbox.jsonl");
519572
+ }
519573
+ function mediaDir() {
519574
+ const base = process.env["BLUN_HOME"]?.trim();
519575
+ return join$4(base !== void 0 && base.length > 0 ? base : join$4(homedir(), ".blun"), "media");
519576
+ }
519577
+ /** Host-owned channel setting from process env or the channel .env. */
519578
+ function channelSetting(name) {
519579
+ const configured = process.env[name]?.trim();
519580
+ if (configured !== void 0 && configured.length > 0) return configured;
519581
+ try {
519582
+ const raw = readFileSync(join$4(channelDir(), ".env"), "utf8");
519583
+ for (const line of raw.split(/\r?\n/)) {
519584
+ const match = /^(\w+)=(.*)$/.exec(line.trim());
519585
+ if (match?.[1] !== name) continue;
519586
+ const value = match?.[2]?.trim();
519587
+ if (value !== void 0 && value.length > 0) return value;
519588
+ }
519589
+ } catch {}
519590
+ }
519591
+ /** Bot token from the channel .env — CRLF-tolerant, undefined when unset. */
519592
+ function botToken() {
519593
+ return channelSetting("BLUN_TELEGRAM_BOT_TOKEN");
519594
+ }
519595
+ /** Cheap outbox growth marker: byte size (append-only file). */
519596
+ function outboxMarker() {
519597
+ try {
519598
+ return statSync(outboxPath()).size;
519599
+ } catch {
519600
+ return 0;
519601
+ }
519602
+ }
519603
+ /** True when the reply tool (MCP server) appended an outbox entry for this chat since `marker`. */
519604
+ function outboxGrewForChat(marker, chatId, threadId) {
519605
+ if (!Number.isSafeInteger(marker) || marker < 0) return false;
519606
+ let fd;
519607
+ try {
519608
+ fd = openSync(outboxPath(), "r");
519609
+ const end = fstatSync(fd).size;
519610
+ if (end <= marker) return false;
519611
+ const matches = (line) => {
519612
+ if (line.trim().length === 0) return false;
519613
+ try {
519614
+ const entry = JSON.parse(line);
519615
+ return String(entry.chat_id) === String(chatId) && (entry.message_thread_id === void 0 ? void 0 : String(entry.message_thread_id)) === threadId;
519616
+ } catch {
519617
+ return false;
519618
+ }
519619
+ };
519620
+ const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, end - marker));
519621
+ const decoder = new StringDecoder("utf8");
519622
+ let position = marker;
519623
+ let pending = "";
519624
+ while (position < end) {
519625
+ const count = readSync(fd, buffer, 0, Math.min(buffer.length, end - position), position);
519626
+ if (count === 0) break;
519627
+ position += count;
519628
+ pending += decoder.write(buffer.subarray(0, count));
519629
+ let newline = pending.indexOf("\n");
519630
+ while (newline >= 0) {
519631
+ if (matches(pending.slice(0, newline))) return true;
519632
+ pending = pending.slice(newline + 1);
519633
+ newline = pending.indexOf("\n");
519634
+ }
519635
+ }
519636
+ return matches(pending + decoder.end());
519637
+ } catch {} finally {
519638
+ if (fd !== void 0) try {
519639
+ closeSync(fd);
519640
+ } catch {}
519641
+ }
519642
+ return false;
519643
+ }
519644
+ const TELEGRAM_TEXT_LIMIT = 4096;
519645
+ const TELEGRAM_ATTACHMENT_LIMIT = 50 * 1024 * 1024;
519646
+ function mediaTelegramTarget(filePath) {
519647
+ const lower = filePath.toLowerCase();
519648
+ if (/\.(?:png|jpe?g|webp|gif)$/u.test(lower)) return {
519649
+ method: "sendPhoto",
519650
+ field: "photo",
519651
+ mimeType: lower.endsWith(".png") ? "image/png" : lower.endsWith(".webp") ? "image/webp" : lower.endsWith(".gif") ? "image/gif" : "image/jpeg"
519652
+ };
519653
+ if (lower.endsWith(".mp4")) return {
519654
+ method: "sendVideo",
519655
+ field: "video",
519656
+ mimeType: "video/mp4"
519657
+ };
519658
+ if (/\.(?:mp3|wav)$/u.test(lower)) return {
519659
+ method: "sendAudio",
519660
+ field: "audio",
519661
+ mimeType: lower.endsWith(".mp3") ? "audio/mpeg" : "audio/wav"
519662
+ };
519663
+ return {
519664
+ method: "sendDocument",
519665
+ field: "document",
519666
+ mimeType: "application/octet-stream"
519667
+ };
519668
+ }
519669
+ function safeCompletedMediaPath(filePath) {
519670
+ try {
519671
+ const root = realpathSync(mediaDir());
519672
+ const resolved = realpathSync(filePath);
519673
+ const withinRoot = relative(root, resolved);
519674
+ if (withinRoot.length === 0 || withinRoot.startsWith("..") || isAbsolute(withinRoot)) return;
519675
+ const info = statSync(resolved);
519676
+ if (!info.isFile() || info.size <= 0 || info.size > TELEGRAM_ATTACHMENT_LIMIT) return void 0;
519677
+ return resolved;
519678
+ } catch {
519679
+ return;
519680
+ }
519681
+ }
519682
+ /** Extract the host-owned local result path from a successful GetMedia output. */
519683
+ function completedMediaLocalPath(output) {
519684
+ const text = Array.isArray(output) ? output.filter((part) => typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n") : typeof output === "string" ? output : "";
519685
+ const candidate = /Media job [^\r\n]+ is complete\. Local file: (.+?)\. The BLUN host/u.exec(text)?.[1]?.trim();
519686
+ return candidate === void 0 || candidate.length === 0 ? void 0 : safeCompletedMediaPath(candidate);
519687
+ }
519688
+ /** Telegram group/supergroup ids are negative; DMs are the positive user id. */
519689
+ function isGroupChat(chatId) {
519690
+ return chatId.startsWith("-");
519691
+ }
519692
+ function normalizeGroupNoise(text) {
519693
+ return text.toLowerCase().replace(/\u00e4/g, "a").replace(/\u00f6/g, "o").replace(/\u00fc/g, "u").replace(/\u00df/g, "ss").replace(/[\u2010-\u2015]/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
519694
+ }
519695
+ const GROUP_REPLY_EMPTY_CLAUSES = [
519696
+ /^(verstanden|kapiert|ok|okay|alles klar|geht klar|angekommen|seh sie|ich seh sie|gemerkt|passt|erledigt notiert|notiert|understood|got it|noted|acknowledged|roger|received)$/,
519697
+ /^(bin da|bin hier|hier bin ich|ich bin da|was brauchst du|was gibt es|was liegt an|wie kann ich helfen|bereit|ich warte|warte auf|melde mich|freut mich|here|standing by|ready|awaiting|what do you need)$/,
519698
+ /^(keine (gruppen ?)?antwort|gar keine antwort|keine reaktion|kein wort|no ?action|no (response|reply|answer|comment))( (notig|erforderlich|needed|required))?$/,
519699
+ /^(ich )?(halte mich raus|(bin|bleibe) (jetzt )?still|schweige|habe nichts zu melden)$/,
519700
+ /^ich best(?:a|ae|ä)tige nichts und beende still$/u,
519701
+ /^(stille|still|silence|nichts (zu tun|zu melden|fur mich|fuer mich)|nicht meine lane)$/,
519702
+ /^(i (am |will be )?)?(staying (silent|out|quiet)|keeping (quiet|out)|holding back)$/,
519703
+ /^(i have )?nothing (to (add|do|report)|for me)$/,
519704
+ /^no need to (respond|reply)$/,
519705
+ /^(nicht (direkt )?an mich( gerichtet)?|not (for me|my lane|addressed to me|directed at me|to me))$/,
519706
+ /^(die(se)? nachricht ist )?(nicht (direkt )?an mich|an die gruppe)( gerichtet)?$/,
519707
+ /^(this|the) message is (addressed to the group|not (addressed )?to me)$/,
519708
+ /^(es gibt )?kein(en|e)? (auftrag( (an|fur|fuer) mich)?|frage( an mich)?|arbeit( verlangt)?)$/,
519709
+ /^(there is )?no (task|question|work)( for me)?$/,
519710
+ /^(ich beende den )?turn ohne (ausgabe|antwort)( beendet)?$/,
519711
+ /^i (will )?end this turn without (a response|output)$/,
519712
+ /^(nach|gemaess) der leerlauf regel( \d+)? gibt es nichts zu melden$/
519713
+ ];
519714
+ const GROUP_REPLY_NOTIFICATION_CONTEXT = /^die(se)? nachricht ist eine (konfigurations )?information( [\p{L}\p{N} _-]{1,64} wird ab jetzt nur noch bei erwahnung benachrichtigt)?( an die gruppe gerichtet)?$/u;
519715
+ function isGroupNoiseReply(text) {
519716
+ return text.split(/[.!?;,\r\n]+|\s+[-\u2013\u2014]\s+/u).map(normalizeGroupNoise).filter(Boolean).every((clause) => GROUP_REPLY_EMPTY_CLAUSES.some((pattern) => pattern.test(clause)) || GROUP_REPLY_NOTIFICATION_CONTEXT.test(clause));
519717
+ }
519718
+ /** Unknown content is preserved, including short useful context-only warnings. */
519719
+ function isGroupSuppressed(text, _contextOnly) {
519720
+ return isGroupNoiseReply(text);
519721
+ }
519722
+ const SILENT_TURN_MARKER = "[[BLUN_TELEGRAM_SILENT]]";
519723
+ function isSilentTurnMarker(text) {
519724
+ return text.trim() === SILENT_TURN_MARKER;
519725
+ }
519726
+ function stripTrailingSilentTurnMarker(text) {
519727
+ const trimmed = text.trimEnd();
519728
+ if (!trimmed.endsWith("[[BLUN_TELEGRAM_SILENT]]")) return text;
519729
+ const prefix = trimmed.slice(0, -24);
519730
+ if (prefix.length > 0 && !/\s$/u.test(prefix)) return text;
519731
+ return prefix.trimEnd();
519732
+ }
519733
+ async function sendReplyFallback(chatId, rawText, contextOnly = false, requireDelivery = false, progress, threadId) {
519734
+ if (threadId !== void 0 && !validChannelThreadId(threadId)) return false;
519735
+ const text = stripTrailingSilentTurnMarker(rawText);
519736
+ if (text.trim().length === 0) return !requireDelivery;
519737
+ const topic = threadId === void 0 ? {} : { message_thread_id: Number(threadId) };
519738
+ if (isGroupChat(chatId) && isGroupSuppressed(text, contextOnly)) {
519739
+ try {
519740
+ appendFileSync(outboxPath(), `${JSON.stringify({
519741
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
519742
+ direction: "out",
519743
+ kind: "reply-fallback-suppressed",
519744
+ ...topic,
519745
+ chat_id: String(chatId),
519746
+ text
519747
+ })}\n`);
519748
+ } catch {}
519749
+ return !requireDelivery;
519750
+ }
519751
+ const token = botToken();
519752
+ if (token === void 0) return false;
519753
+ if (text.length === 0) return false;
519754
+ const messageIds = [];
519755
+ try {
519756
+ const chunks = splitTelegramText(text, TELEGRAM_TEXT_LIMIT);
519757
+ if (progress?.acceptedChunks !== void 0 && progress.acceptedChunks.length > chunks.length) return false;
519758
+ for (const [index, body] of chunks.entries()) {
519759
+ if (progress?.isCurrent?.() === false || progress?.signal?.aborted) return false;
519760
+ const accepted = progress?.acceptedChunks?.[index];
519761
+ if (accepted !== void 0) {
519762
+ if (accepted.text !== body || !Number.isSafeInteger(accepted.messageId) || accepted.messageId <= 0) return false;
519763
+ messageIds.push(accepted.messageId);
519764
+ continue;
519765
+ }
519766
+ if (progress?.receiptOnly) return false;
519767
+ const timeout = requireDelivery ? AbortSignal.timeout(GOAL_REPLY_REQUEST_TIMEOUT_MS) : void 0;
519768
+ const signal = timeout !== void 0 && progress?.signal !== void 0 ? AbortSignal.any([timeout, progress.signal]) : timeout ?? progress?.signal;
519769
+ const payload = await (await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
519770
+ method: "POST",
519771
+ headers: { "Content-Type": "application/json" },
519772
+ body: JSON.stringify({
519773
+ chat_id: chatId,
519774
+ text: body,
519775
+ ...topic
519776
+ }),
519777
+ signal
519778
+ })).json();
519779
+ const messageId = payload.result?.message_id;
519780
+ if (payload.ok !== true || !Number.isSafeInteger(messageId) || messageId === void 0 || messageId <= 0) return false;
519781
+ if (progress !== void 0) {
519782
+ progress.acceptedChunks ??= [];
519783
+ progress.acceptedChunks[index] = {
519784
+ text: body,
519785
+ messageId
519786
+ };
519787
+ if (await progress.persistAccepted?.() === false) return false;
519788
+ }
519789
+ messageIds.push(messageId);
519790
+ }
519791
+ if (progress?.isCurrent?.() === false || progress?.signal?.aborted) return false;
519792
+ try {
519793
+ appendFileSync(outboxPath(), `${JSON.stringify({
519794
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
519795
+ direction: "out",
519796
+ kind: "reply-fallback",
519797
+ ...topic,
519798
+ chat_id: String(chatId),
519799
+ message_ids: messageIds,
519800
+ text
519801
+ })}\n`);
519802
+ } catch {}
519803
+ return true;
519804
+ } catch {
519805
+ return false;
519806
+ }
519807
+ }
519808
+ /**
519809
+ * Deliver a completed BLUN media file immediately for a channel-origin turn.
519810
+ * The path must resolve to a non-empty file below BLUN_HOME/media. Returns true
519811
+ * only after Telegram accepted the upload and the outbox receipt was appended.
519812
+ */
519813
+ async function sendMediaReplyFallback(chatId, filePath, threadId) {
519814
+ if (threadId !== void 0 && !validChannelThreadId(threadId)) return false;
519815
+ const safePath = safeCompletedMediaPath(filePath);
519816
+ const token = botToken();
519817
+ if (safePath === void 0 || token === void 0) return false;
519818
+ const target = mediaTelegramTarget(safePath);
519819
+ const form = new FormData();
519820
+ form.append("chat_id", chatId);
519821
+ if (threadId !== void 0) form.append("message_thread_id", threadId);
519822
+ form.append(target.field, new Blob([new Uint8Array(readFileSync(safePath))], { type: target.mimeType }), basename(safePath));
519823
+ try {
519824
+ const payload = await (await fetch(`https://api.telegram.org/bot${token}/${target.method}`, {
519825
+ method: "POST",
519826
+ body: form
519827
+ })).json();
519828
+ if (payload.ok !== true) return false;
519829
+ try {
519830
+ appendFileSync(outboxPath(), `${JSON.stringify({
519831
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
519832
+ direction: "out",
519833
+ kind: "media-reply-fallback",
519834
+ ...threadId === void 0 ? {} : { message_thread_id: Number(threadId) },
519835
+ chat_id: String(chatId),
519836
+ message_ids: payload.result?.message_id === void 0 ? [] : [payload.result.message_id],
519837
+ files: [safePath]
519838
+ })}\n`);
519839
+ } catch {}
519840
+ return true;
519841
+ } catch {
519842
+ return false;
519843
+ }
519844
+ }
519845
+ //#endregion
519272
519846
  //#region src/tui/utils/assistant-display.ts
519273
519847
  const SYSTEM_REMINDER_OPEN_RE = /<system-reminder\b[^>]*>/gi;
519274
519848
  const SYSTEM_REMINDER_CLOSE_RE = /<\/system-reminder\b[ \t]*(?:>|(?=\r?\n|$))/gi;
@@ -519288,7 +519862,10 @@ const RUNTIME_INSTRUCTION_CLOSE = "Die einzige Ausnahme: eine Zahl, die der Nutz
519288
519862
  /** Remove model-only envelopes before assistant text reaches a transcript renderer. */
519289
519863
  function sanitizeAssistantDisplayText(text, options = {}) {
519290
519864
  const transient = options.transient === true;
519291
- return stripIncompleteInternalSuffix(stripControlTokens(stripDsmlBlocks(stripSystemReminderBlocks(stripEchoedRuntimeInstructions(text), transient))), transient);
519865
+ const displayText = stripIncompleteInternalSuffix(stripControlTokens(stripDsmlBlocks(stripSystemReminderBlocks(stripEchoedRuntimeInstructions(text), transient))), transient);
519866
+ const trimmed = displayText.trim();
519867
+ if (trimmed === "[[BLUN_TELEGRAM_SILENT]]" || transient && "[[BLUN_TELEGRAM_SILENT]]".startsWith(trimmed)) return "";
519868
+ return displayText;
519292
519869
  }
519293
519870
  function stripEchoedRuntimeInstructions(text) {
519294
519871
  let cursor = 0;
@@ -532785,11 +533362,6 @@ function planQueueCollection(messages, policy, now, activeContext) {
532785
533362
  };
532786
533363
  }
532787
533364
  //#endregion
532788
- //#region src/tui/constant/goal-channel-replies.ts
532789
- const GOAL_REPLY_RETRY_DELAY_MS = 1e3;
532790
- const GOAL_REPLY_REQUEST_TIMEOUT_MS = 15e3;
532791
- const TELEGRAM_GOAL_REPLY_TOOL_NAME = /^mcp__(?:telegram|plugin-telegram_telegram)__(?:reply|edit_message)$/iu;
532792
- //#endregion
532793
533365
  //#region src/tui/controllers/goal-channel-replies.ts
532794
533366
  function object(value) {
532795
533367
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -532809,7 +533381,7 @@ function matchesRoute(record, args) {
532809
533381
  return threadId === record.threadId;
532810
533382
  }
532811
533383
  /** Match the actual Telegram plugin's success output, not a generic successful tool call. */
532812
- function replyReceipt(text, output) {
533384
+ function telegramReplyReceipt(text, output) {
532813
533385
  const single = /^(?:sent|edited) \(id: ([1-9]\d*)\)$/.exec(output.trim());
532814
533386
  if (single) {
532815
533387
  const id = Number(single[1]);
@@ -532865,6 +533437,7 @@ function decodeReply(value, sessionId) {
532865
533437
  turnEndReason: value["turnEndReason"],
532866
533438
  finalText: value["finalText"],
532867
533439
  replyTexts: [...value["replyTexts"]],
533440
+ routePersisted: true,
532868
533441
  replyReceipts: structuredClone(receipts),
532869
533442
  pending: pending === void 0 ? void 0 : structuredClone(pending)
532870
533443
  };
@@ -532903,7 +533476,7 @@ function recoverReply(record, replay) {
532903
533476
  try {
532904
533477
  const args = JSON.parse(call["arguments"]);
532905
533478
  if (!object(args) || !matchesRoute(record, args) || typeof args["text"] !== "string") continue;
532906
- const receipt = replyReceipt(args["text"].trim(), messageText(message["content"]));
533479
+ const receipt = telegramReplyReceipt(args["text"].trim(), messageText(message["content"]));
532907
533480
  if (receipt) receipts.push({
532908
533481
  id,
532909
533482
  receipt
@@ -533001,7 +533574,25 @@ var GoalChannelReplyController = class {
533001
533574
  replyReceipts: []
533002
533575
  });
533003
533576
  scope.activeGoalId = goal.goalId;
533004
- return await this.persist(scope) && this.current(scope);
533577
+ const saved = await this.persist(scope) && this.current(scope);
533578
+ const bound = scope.records.get(goal.goalId);
533579
+ if (!saved || bound === void 0 || bound.status !== "active") return false;
533580
+ bound.routePersisted = true;
533581
+ return true;
533582
+ }
533583
+ ownsActiveRoute(sessionId, goalId, chatId, threadId) {
533584
+ const scope = this.scope;
533585
+ const record = scope?.records.get(goalId);
533586
+ return scope !== void 0 && this.current(scope) && scope.writable && scope.sessionId === sessionId && record?.routePersisted === true && record.status === "active" && record.chatId === chatId && record.threadId === threadId;
533587
+ }
533588
+ completionRouteForTurn(sessionId, turnId) {
533589
+ const scope = this.scope;
533590
+ if (scope === void 0 || !this.current(scope) || scope.sessionId !== sessionId || turnId === void 0) return;
533591
+ for (const record of scope.records.values()) if (record.status === "complete" && record.routePersisted === true && record.turnId === turnId && !record.turnEnded) return {
533592
+ goalId: record.goalId,
533593
+ chatId: record.chatId,
533594
+ threadId: record.threadId
533595
+ };
533005
533596
  }
533006
533597
  beginTurn(sessionId, goalId, turnId) {
533007
533598
  this.completedChats.clear();
@@ -533017,9 +533608,10 @@ var GoalChannelReplyController = class {
533017
533608
  record.finalText = "";
533018
533609
  record.replyTexts = [];
533019
533610
  record.replyReceipts = [];
533611
+ record.completionTranscriptStart = void 0;
533020
533612
  this.persist(scope);
533021
533613
  }
533022
- updateGoal(sessionId, goal) {
533614
+ updateGoal(sessionId, goal, completionTranscriptStart) {
533023
533615
  const scope = this.scope;
533024
533616
  if (!scope || scope.sessionId !== sessionId || !this.current(scope)) return;
533025
533617
  scope.activeGoalId = goal?.goalId;
@@ -533029,6 +533621,7 @@ var GoalChannelReplyController = class {
533029
533621
  }
533030
533622
  const record = scope.records.get(goal.goalId);
533031
533623
  if (!record) return;
533624
+ if (goal.status === "complete" && record.status !== "complete" && !record.turnEnded && record.turnId === scope.activeTurnId) record.completionTranscriptStart = completionTranscriptStart;
533032
533625
  const resumed = record.status !== "active" && goal.status === "active";
533033
533626
  if (goal.status !== record.status) {
533034
533627
  clearTimeout(record.timer);
@@ -533054,7 +533647,7 @@ var GoalChannelReplyController = class {
533054
533647
  if (record.turnId !== String(turnId)) continue;
533055
533648
  record.turnEnded = true;
533056
533649
  record.turnEndReason = reason;
533057
- record.finalText = entries.findLast((entry) => entry.kind === "assistant" && entry.turnId === String(turnId) && !scope.hookEntries.has(entry.id) && entry.content.trim().length > 0)?.content.trim() ?? "";
533650
+ record.finalText = entries.slice(record.completionTranscriptStart ?? 0).findLast((entry) => entry.kind === "assistant" && entry.turnId === String(turnId) && !scope.hookEntries.has(entry.id) && entry.content.trim().length > 0)?.content.trim() ?? "";
533058
533651
  this.prepareReply(scope, record);
533059
533652
  if (record.status === "complete") this.completedChats.add(channelRouteKey(record.chatId, record.threadId));
533060
533653
  }
@@ -533071,7 +533664,7 @@ var GoalChannelReplyController = class {
533071
533664
  recordReply(sessionId, turnId, call, output, isError, synthetic) {
533072
533665
  const scope = this.scope;
533073
533666
  if (!scope || !this.current(scope) || scope.sessionId !== sessionId || isError || synthetic || !TELEGRAM_GOAL_REPLY_TOOL_NAME.test(call.name) || !object(call.args) || typeof call.args["text"] !== "string") return;
533074
- const receipt = replyReceipt(call.args["text"].trim(), output);
533667
+ const receipt = telegramReplyReceipt(call.args["text"].trim(), output);
533075
533668
  if (!receipt) return;
533076
533669
  for (const record of scope.records.values()) {
533077
533670
  if (record.turnId !== String(turnId) || !matchesRoute(record, call.args)) continue;
@@ -537907,11 +538500,11 @@ var SessionEventHandler = class {
537907
538500
  }
537908
538501
  }
537909
538502
  handleStepBegin(event) {
537910
- this.host.commitQueuedSteerAtStepStart(event.turnId);
537911
538503
  this.host.streamingUI.flushNow();
537912
538504
  this.host.streamingUI.setStep(event.step);
537913
538505
  this.host.streamingUI.resetToolUi();
537914
538506
  this.host.streamingUI.finalizeLiveTextBuffers("waiting");
538507
+ this.host.commitQueuedSteerAtStepStart(event.turnId);
537915
538508
  this.host.patchLivePane({
537916
538509
  mode: "waiting",
537917
538510
  pendingApproval: null,
@@ -538150,7 +538743,13 @@ var SessionEventHandler = class {
538150
538743
  this.host.state.ui.requestRender();
538151
538744
  }
538152
538745
  handleGoalUpdated(event) {
538153
- this.host.goalChannelReplies?.updateGoal(event.sessionId, event.snapshot);
538746
+ const completing = event.snapshot?.status === "complete" && event.change?.kind === "completion";
538747
+ if (completing) {
538748
+ this.host.streamingUI.flushNow();
538749
+ this.host.streamingUI.finalizeLiveTextBuffers(this.host.state.appState.streamingPhase === "idle" ? "idle" : "waiting");
538750
+ }
538751
+ this.host.goalChannelReplies?.updateGoal(event.sessionId, event.snapshot, completing ? this.host.state.transcriptEntries.length : void 0);
538752
+ if (completing) this.host.captureChannelReplyAtGoalCompletion?.(event.sessionId, event.snapshot.goalId);
538154
538753
  this.host.setAppState({ goal: event.snapshot });
538155
538754
  if (event.snapshot?.status === "active") this.hideCompactionRetry();
538156
538755
  else this.showPendingCompactionRetry();
@@ -543659,291 +544258,171 @@ function buildChannelImagePart(imagePath) {
543659
544258
  };
543660
544259
  }
543661
544260
  //#endregion
543662
- //#region src/tui/utils/telegram-text-chunks.ts
543663
- /** Split on UTF-16 boundaries without losing whitespace or supplementary characters. */
543664
- function splitTelegramText(text, limit) {
543665
- if (!Number.isSafeInteger(limit) || limit < 2) throw new RangeError("Invalid Telegram chunk limit");
543666
- const chunks = [];
543667
- for (let start = 0; start < text.length;) {
543668
- let end = Math.min(text.length, start + limit);
543669
- if (end < text.length) {
543670
- const minimum = start + Math.floor((end - start) / 2);
543671
- for (const boundary of [
543672
- "\n\n",
543673
- "\n",
543674
- " "
543675
- ]) {
543676
- const index = text.lastIndexOf(boundary, end - 1);
543677
- if (index >= minimum) {
543678
- end = index + boundary.length;
543679
- break;
543680
- }
543681
- }
543682
- if ((text.codePointAt(end - 1) ?? 0) > 65535) end -= 1;
544261
+ //#region src/tui/utils/configured-agent-profiles.ts
544262
+ var import_profile_launch = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
544263
+ const path$2 = __require("node:path");
544264
+ const fs$1 = __require("node:fs");
544265
+ const PROFILE_NAME = /^[a-z0-9][a-z0-9_-]{0,31}$/u;
544266
+ const RESERVED = new Set([
544267
+ "doctor",
544268
+ "export",
544269
+ "help",
544270
+ "login",
544271
+ "mcp",
544272
+ "server",
544273
+ "tools",
544274
+ "update",
544275
+ "upgrade",
544276
+ "version"
544277
+ ]);
544278
+ function profileName(value) {
544279
+ const name = String(value || "").trim().toLowerCase();
544280
+ if (!PROFILE_NAME.test(name)) throw new Error("Profilnamen duerfen nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthalten.");
544281
+ return name;
544282
+ }
544283
+ function parseProfileLaunchArgs(args, mode) {
544284
+ const remaining = [...args];
544285
+ if (mode !== "king") return {
544286
+ args: remaining,
544287
+ name: void 0
544288
+ };
544289
+ const flag = remaining.indexOf("--profile");
544290
+ if (flag >= 0) {
544291
+ if (flag + 1 >= remaining.length) throw new Error("--profile braucht einen Profilnamen.");
544292
+ const name = profileName(remaining[flag + 1]);
544293
+ remaining.splice(flag, 2);
544294
+ return {
544295
+ args: remaining,
544296
+ name
544297
+ };
543683
544298
  }
543684
- chunks.push(text.slice(start, end));
543685
- start = end;
544299
+ if (remaining.length === 1 && !remaining[0].startsWith("-") && !RESERVED.has(remaining[0].toLowerCase())) return {
544300
+ args: [],
544301
+ name: profileName(remaining[0]),
544302
+ implicit: true
544303
+ };
544304
+ if (remaining.length === 2 && remaining.includes("-c")) {
544305
+ const candidate = remaining.find((value) => value !== "-c");
544306
+ if (candidate && !candidate.startsWith("-")) return {
544307
+ args: ["-c"],
544308
+ name: profileName(candidate),
544309
+ implicit: true
544310
+ };
544311
+ }
544312
+ return {
544313
+ args: remaining,
544314
+ name: void 0
544315
+ };
543686
544316
  }
543687
- return chunks;
543688
- }
543689
- //#endregion
543690
- //#region src/tui/utils/telegram-reply-fallback.ts
543691
- /**
543692
- * Deterministic Telegram reply fallback for channel-origin turns.
543693
- *
543694
- * Small models reliably DO the work (Bash/Read/...) but often end a
543695
- * channel-origin turn without calling the telegram reply tool — the answer
543696
- * then dies in the console and the sender never sees it. This module makes
543697
- * delivery a harness guarantee instead of a model courtesy: after a channel
543698
- * turn finishes, the TUI checks whether the reply tool actually ran (the MCP
543699
- * server appends to outbox.jsonl on every send) and, if not, sends the turn's
543700
- * final assistant text itself via the plain Bot API.
543701
- *
543702
- * Dependency-free on purpose (fs + global fetch); mirrors the CRLF-tolerant
543703
- * .env parsing of plugins/telegram/src/state.ts.
543704
- */
543705
- init_dist$6();
543706
- function channelDir() {
543707
- const base = process.env["BLUN_HOME"]?.trim();
543708
- return join$4(base !== void 0 && base.length > 0 ? base : join$4(homedir(), ".blun"), "channels", "telegram");
543709
- }
543710
- function outboxPath() {
543711
- return join$4(channelDir(), "outbox.jsonl");
543712
- }
543713
- function mediaDir() {
543714
- const base = process.env["BLUN_HOME"]?.trim();
543715
- return join$4(base !== void 0 && base.length > 0 ? base : join$4(homedir(), ".blun"), "media");
543716
- }
543717
- /** Host-owned channel setting from process env or the channel .env. */
543718
- function channelSetting(name) {
543719
- const configured = process.env[name]?.trim();
543720
- if (configured !== void 0 && configured.length > 0) return configured;
543721
- try {
543722
- const raw = readFileSync(join$4(channelDir(), ".env"), "utf8");
543723
- for (const line of raw.split(/\r?\n/)) {
543724
- const match = /^(\w+)=(.*)$/.exec(line.trim());
543725
- if (match?.[1] !== name) continue;
543726
- const value = match?.[2]?.trim();
543727
- if (value !== void 0 && value.length > 0) return value;
544317
+ function resolveSelectedProfile(sharedHome, name, pathImpl = path$2) {
544318
+ return pathImpl.join(sharedHome, "profile", profileName(name));
544319
+ }
544320
+ function catalogUnavailable() {
544321
+ return Object.assign(/* @__PURE__ */ new Error("PROFILE_CATALOG_UNAVAILABLE"), { code: "PROFILE_CATALOG_UNAVAILABLE" });
544322
+ }
544323
+ function directoryIdentity(target, fsImpl) {
544324
+ let stat;
544325
+ try {
544326
+ stat = fsImpl.lstatSync(target, { bigint: true });
544327
+ } catch (error) {
544328
+ if (error.code === "ENOENT") return void 0;
544329
+ throw error;
543728
544330
  }
543729
- } catch {}
543730
- }
543731
- /** Bot token from the channel .env — CRLF-tolerant, undefined when unset. */
543732
- function botToken() {
543733
- return channelSetting("BLUN_TELEGRAM_BOT_TOKEN");
543734
- }
543735
- /** Cheap outbox growth marker: byte size (append-only file). */
543736
- function outboxMarker() {
543737
- try {
543738
- return statSync(outboxPath()).size;
543739
- } catch {
543740
- return 0;
544331
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw catalogUnavailable();
544332
+ return stat;
543741
544333
  }
543742
- }
543743
- /** True when the reply tool (MCP server) appended an outbox entry for this chat since `marker`. */
543744
- function outboxGrewForChat(marker, chatId, threadId) {
543745
- try {
543746
- if (statSync(outboxPath()).size <= marker) return false;
543747
- const fresh = readFileSync(outboxPath()).subarray(marker).toString("utf8");
543748
- for (const line of fresh.split(/\r?\n/)) {
543749
- if (line.trim().length === 0) continue;
543750
- try {
543751
- const entry = JSON.parse(line);
543752
- if (String(entry.chat_id) === String(chatId) && (entry.message_thread_id === void 0 ? void 0 : String(entry.message_thread_id)) === threadId) return true;
543753
- } catch {}
544334
+ function homeIdentity(home, fsImpl) {
544335
+ const root = path$2.parse(home).root;
544336
+ let current = root;
544337
+ let stat = directoryIdentity(current, fsImpl);
544338
+ for (const part of home.slice(root.length).split(path$2.sep).filter(Boolean)) {
544339
+ if (stat === void 0) return void 0;
544340
+ current = path$2.join(current, part);
544341
+ stat = directoryIdentity(current, fsImpl);
543754
544342
  }
543755
- } catch {}
543756
- return false;
543757
- }
543758
- const TELEGRAM_TEXT_LIMIT = 4096;
543759
- const TELEGRAM_ATTACHMENT_LIMIT = 50 * 1024 * 1024;
543760
- function mediaTelegramTarget(filePath) {
543761
- const lower = filePath.toLowerCase();
543762
- if (/\.(?:png|jpe?g|webp|gif)$/u.test(lower)) return {
543763
- method: "sendPhoto",
543764
- field: "photo",
543765
- mimeType: lower.endsWith(".png") ? "image/png" : lower.endsWith(".webp") ? "image/webp" : lower.endsWith(".gif") ? "image/gif" : "image/jpeg"
543766
- };
543767
- if (lower.endsWith(".mp4")) return {
543768
- method: "sendVideo",
543769
- field: "video",
543770
- mimeType: "video/mp4"
543771
- };
543772
- if (/\.(?:mp3|wav)$/u.test(lower)) return {
543773
- method: "sendAudio",
543774
- field: "audio",
543775
- mimeType: lower.endsWith(".mp3") ? "audio/mpeg" : "audio/wav"
543776
- };
543777
- return {
543778
- method: "sendDocument",
543779
- field: "document",
543780
- mimeType: "application/octet-stream"
543781
- };
543782
- }
543783
- function safeCompletedMediaPath(filePath) {
543784
- try {
543785
- const root = realpathSync(mediaDir());
543786
- const resolved = realpathSync(filePath);
543787
- const withinRoot = relative(root, resolved);
543788
- if (withinRoot.length === 0 || withinRoot.startsWith("..") || isAbsolute(withinRoot)) return;
543789
- const info = statSync(resolved);
543790
- if (!info.isFile() || info.size <= 0 || info.size > TELEGRAM_ATTACHMENT_LIMIT) return void 0;
543791
- return resolved;
543792
- } catch {
543793
- return;
544343
+ return stat;
543794
544344
  }
543795
- }
543796
- /** Extract the host-owned local result path from a successful GetMedia output. */
543797
- function completedMediaLocalPath(output) {
543798
- const text = Array.isArray(output) ? output.filter((part) => typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n") : typeof output === "string" ? output : "";
543799
- const candidate = /Media job [^\r\n]+ is complete\. Local file: (.+?)\. The BLUN host/u.exec(text)?.[1]?.trim();
543800
- return candidate === void 0 || candidate.length === 0 ? void 0 : safeCompletedMediaPath(candidate);
543801
- }
543802
- /** Telegram group/supergroup ids are negative; DMs are the positive user id. */
543803
- function isGroupChat(chatId) {
543804
- return chatId.startsWith("-");
543805
- }
543806
- function normalizeGroupNoise(text) {
543807
- return text.toLowerCase().replace(/\u00e4/g, "a").replace(/\u00f6/g, "o").replace(/\u00fc/g, "u").replace(/\u00df/g, "ss").replace(/[\u2010-\u2015]/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
543808
- }
543809
- const GROUP_REPLY_EMPTY_CLAUSES = [
543810
- /^(verstanden|kapiert|ok|okay|alles klar|geht klar|angekommen|seh sie|ich seh sie|gemerkt|passt|erledigt notiert|notiert|understood|got it|noted|acknowledged|roger|received)$/,
543811
- /^(bin da|bin hier|hier bin ich|ich bin da|was brauchst du|was gibt es|was liegt an|wie kann ich helfen|bereit|ich warte|warte auf|melde mich|freut mich|here|standing by|ready|awaiting|what do you need)$/,
543812
- /^(keine (gruppen ?)?antwort|gar keine antwort|keine reaktion|kein wort|no ?action|no (response|reply|answer|comment))( (notig|erforderlich|needed|required))?$/,
543813
- /^(ich )?(halte mich raus|(bin|bleibe) (jetzt )?still|schweige|habe nichts zu melden)$/,
543814
- /^(stille|still|silence|nichts (zu tun|zu melden|fur mich|fuer mich)|nicht meine lane)$/,
543815
- /^(i (am |will be )?)?(staying (silent|out|quiet)|keeping (quiet|out)|holding back)$/,
543816
- /^(i have )?nothing (to (add|do|report)|for me)$/,
543817
- /^no need to (respond|reply)$/,
543818
- /^(nicht (direkt )?an mich( gerichtet)?|not (for me|my lane|addressed to me|directed at me|to me))$/,
543819
- /^(die(se)? nachricht ist )?(nicht (direkt )?an mich|an die gruppe)( gerichtet)?$/,
543820
- /^(this|the) message is (addressed to the group|not (addressed )?to me)$/,
543821
- /^(es gibt )?kein(en|e)? (auftrag( (an|fur|fuer) mich)?|frage( an mich)?|arbeit( verlangt)?)$/,
543822
- /^(there is )?no (task|question|work)( for me)?$/,
543823
- /^(ich beende den )?turn ohne (ausgabe|antwort)( beendet)?$/,
543824
- /^i (will )?end this turn without (a response|output)$/,
543825
- /^(nach|gemaess) der leerlauf regel( \d+)? gibt es nichts zu melden$/
543826
- ];
543827
- const GROUP_REPLY_NOTIFICATION_CONTEXT = /^die(se)? nachricht ist eine (konfigurations )?information( [\p{L}\p{N} _-]{1,64} wird ab jetzt nur noch bei erwahnung benachrichtigt)?( an die gruppe gerichtet)?$/u;
543828
- function isGroupNoiseReply(text) {
543829
- return text.split(/[.!?;,\r\n]+|\s+[-\u2013\u2014]\s+/u).map(normalizeGroupNoise).filter(Boolean).every((clause) => GROUP_REPLY_EMPTY_CLAUSES.some((pattern) => pattern.test(clause)) || GROUP_REPLY_NOTIFICATION_CONTEXT.test(clause));
543830
- }
543831
- /** Unknown content is preserved, including short useful context-only warnings. */
543832
- function isGroupSuppressed(text, _contextOnly) {
543833
- return isGroupNoiseReply(text);
543834
- }
543835
- function isSilentTurnMarker(text) {
543836
- return text.trim() === "[[BLUN_TELEGRAM_SILENT]]";
543837
- }
543838
- async function sendReplyFallback(chatId, text, contextOnly = false, requireDelivery = false, progress, threadId) {
543839
- if (threadId !== void 0 && !validChannelThreadId(threadId)) return false;
543840
- if (isSilentTurnMarker(text)) return !requireDelivery;
543841
- const topic = threadId === void 0 ? {} : { message_thread_id: Number(threadId) };
543842
- if (isGroupChat(chatId) && isGroupSuppressed(text, contextOnly)) {
543843
- try {
543844
- appendFileSync(outboxPath(), `${JSON.stringify({
543845
- ts: (/* @__PURE__ */ new Date()).toISOString(),
543846
- direction: "out",
543847
- kind: "reply-fallback-suppressed",
543848
- ...topic,
543849
- chat_id: String(chatId),
543850
- text
543851
- })}\n`);
543852
- } catch {}
543853
- return !requireDelivery;
544345
+ function sameDirectory(before, after) {
544346
+ return before !== void 0 && after !== void 0 && before.dev === after.dev && before.ino === after.ino;
543854
544347
  }
543855
- const token = botToken();
543856
- if (token === void 0) return false;
543857
- if (text.length === 0) return false;
543858
- const messageIds = [];
543859
- try {
543860
- const chunks = splitTelegramText(text, TELEGRAM_TEXT_LIMIT);
543861
- if (progress?.acceptedChunks !== void 0 && progress.acceptedChunks.length > chunks.length) return false;
543862
- for (const [index, body] of chunks.entries()) {
543863
- if (progress?.isCurrent?.() === false || progress?.signal?.aborted) return false;
543864
- const accepted = progress?.acceptedChunks?.[index];
543865
- if (accepted !== void 0) {
543866
- if (accepted.text !== body || !Number.isSafeInteger(accepted.messageId) || accepted.messageId <= 0) return false;
543867
- messageIds.push(accepted.messageId);
543868
- continue;
544348
+ /** Directory names only; selection must revalidate them before changing owner. */
544349
+ function listExistingProfiles(sharedHome, options = {}) {
544350
+ const fsImpl = options.fsImpl || fs$1;
544351
+ try {
544352
+ if (typeof sharedHome !== "string" || !path$2.isAbsolute(sharedHome)) throw catalogUnavailable();
544353
+ const home = path$2.resolve(sharedHome);
544354
+ if (process.platform === "win32" && home.startsWith("\\\\")) throw catalogUnavailable();
544355
+ const beforeHome = homeIdentity(home, fsImpl);
544356
+ if (beforeHome === void 0) return [];
544357
+ const profileRoot = path$2.join(home, "profile");
544358
+ const beforeProfiles = directoryIdentity(profileRoot, fsImpl);
544359
+ if (beforeProfiles === void 0) {
544360
+ if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl))) throw catalogUnavailable();
544361
+ return [];
543869
544362
  }
543870
- if (progress?.receiptOnly) return false;
543871
- const timeout = requireDelivery ? AbortSignal.timeout(GOAL_REPLY_REQUEST_TIMEOUT_MS) : void 0;
543872
- const signal = timeout !== void 0 && progress?.signal !== void 0 ? AbortSignal.any([timeout, progress.signal]) : timeout ?? progress?.signal;
543873
- const payload = await (await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
543874
- method: "POST",
543875
- headers: { "Content-Type": "application/json" },
543876
- body: JSON.stringify({
543877
- chat_id: chatId,
543878
- text: body,
543879
- ...topic
543880
- }),
543881
- signal
543882
- })).json();
543883
- const messageId = payload.result?.message_id;
543884
- if (payload.ok !== true || !Number.isSafeInteger(messageId) || messageId === void 0 || messageId <= 0) return false;
543885
- if (progress !== void 0) {
543886
- progress.acceptedChunks ??= [];
543887
- progress.acceptedChunks[index] = {
543888
- text: body,
543889
- messageId
543890
- };
543891
- if (await progress.persistAccepted?.() === false) return false;
544363
+ const rows = [];
544364
+ const dir = fsImpl.opendirSync(profileRoot);
544365
+ try {
544366
+ let count = 0;
544367
+ for (let entry; (entry = dir.readSync()) !== null;) {
544368
+ if (++count > 4096) throw catalogUnavailable();
544369
+ const name = entry.name;
544370
+ if (!PROFILE_NAME.test(name)) continue;
544371
+ const target = resolveSelectedProfile(home, name);
544372
+ let stat;
544373
+ try {
544374
+ stat = fsImpl.lstatSync(target, { bigint: true });
544375
+ } catch (error) {
544376
+ if (error.code === "ENOENT") continue;
544377
+ throw error;
544378
+ }
544379
+ if (stat.isDirectory() && !stat.isSymbolicLink()) rows.push({
544380
+ name,
544381
+ target,
544382
+ stat
544383
+ });
544384
+ }
544385
+ } finally {
544386
+ dir.closeSync();
543892
544387
  }
543893
- messageIds.push(messageId);
544388
+ if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl)) || !sameDirectory(beforeProfiles, directoryIdentity(profileRoot, fsImpl))) throw catalogUnavailable();
544389
+ for (const row of rows) if (!sameDirectory(row.stat, directoryIdentity(row.target, fsImpl))) throw catalogUnavailable();
544390
+ if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl)) || !sameDirectory(beforeProfiles, directoryIdentity(profileRoot, fsImpl))) throw catalogUnavailable();
544391
+ return rows.map((row) => row.name).sort();
544392
+ } catch {
544393
+ throw catalogUnavailable();
543894
544394
  }
543895
- if (progress?.isCurrent?.() === false || progress?.signal?.aborted) return false;
543896
- try {
543897
- appendFileSync(outboxPath(), `${JSON.stringify({
543898
- ts: (/* @__PURE__ */ new Date()).toISOString(),
543899
- direction: "out",
543900
- kind: "reply-fallback",
543901
- ...topic,
543902
- chat_id: String(chatId),
543903
- message_ids: messageIds,
543904
- text
543905
- })}\n`);
543906
- } catch {}
543907
- return true;
543908
- } catch {
543909
- return false;
543910
544395
  }
543911
- }
543912
- /**
543913
- * Deliver a completed BLUN media file immediately for a channel-origin turn.
543914
- * The path must resolve to a non-empty file below BLUN_HOME/media. Returns true
543915
- * only after Telegram accepted the upload and the outbox receipt was appended.
543916
- */
543917
- async function sendMediaReplyFallback(chatId, filePath, threadId) {
543918
- if (threadId !== void 0 && !validChannelThreadId(threadId)) return false;
543919
- const safePath = safeCompletedMediaPath(filePath);
543920
- const token = botToken();
543921
- if (safePath === void 0 || token === void 0) return false;
543922
- const target = mediaTelegramTarget(safePath);
543923
- const form = new FormData();
543924
- form.append("chat_id", chatId);
543925
- if (threadId !== void 0) form.append("message_thread_id", threadId);
543926
- form.append(target.field, new Blob([new Uint8Array(readFileSync(safePath))], { type: target.mimeType }), basename(safePath));
544396
+ module.exports = {
544397
+ parseProfileLaunchArgs,
544398
+ resolveSelectedProfile,
544399
+ listExistingProfiles
544400
+ };
544401
+ })))();
544402
+ function listConfiguredAgentProfiles(homeDir, env = process.env) {
543927
544403
  try {
543928
- const payload = await (await fetch(`https://api.telegram.org/bot${token}/${target.method}`, {
543929
- method: "POST",
543930
- body: form
543931
- })).json();
543932
- if (payload.ok !== true) return false;
543933
- try {
543934
- appendFileSync(outboxPath(), `${JSON.stringify({
543935
- ts: (/* @__PURE__ */ new Date()).toISOString(),
543936
- direction: "out",
543937
- kind: "media-reply-fallback",
543938
- ...threadId === void 0 ? {} : { message_thread_id: Number(threadId) },
543939
- chat_id: String(chatId),
543940
- message_ids: payload.result?.message_id === void 0 ? [] : [payload.result.message_id],
543941
- files: [safePath]
543942
- })}\n`);
543943
- } catch {}
543944
- return true;
544404
+ if (!isAbsolute(homeDir)) throw new Error();
544405
+ const home = resolve(homeDir);
544406
+ const profile = env["BLUN_PROFILE"] || void 0;
544407
+ const configuredShared = env["BLUN_SHARED_HOME"] || void 0;
544408
+ if (configuredShared !== void 0 && !isAbsolute(configuredShared)) throw new Error();
544409
+ const sharedHome = configuredShared === void 0 ? home : resolve(configuredShared);
544410
+ const samePath = (first, second) => process.platform === "win32" ? first.toLowerCase() === second.toLowerCase() : first === second;
544411
+ if (profile === void 0) {
544412
+ if (!samePath(home, sharedHome)) throw new Error();
544413
+ } else {
544414
+ if (configuredShared === void 0) throw new Error();
544415
+ const selected = (0, import_profile_launch.resolveSelectedProfile)(sharedHome, profile);
544416
+ if (basename(selected) !== profile || !samePath(home, selected)) throw new Error();
544417
+ }
544418
+ const names = (0, import_profile_launch.listExistingProfiles)(sharedHome);
544419
+ if (profile !== void 0 && !names.includes(profile)) throw new Error();
544420
+ return names.map((name) => ({
544421
+ name,
544422
+ current: name === profile
544423
+ }));
543945
544424
  } catch {
543946
- return false;
544425
+ throw Object.assign(/* @__PURE__ */ new Error("CONFIGURED_AGENT_PROFILES_UNAVAILABLE"), { code: "CONFIGURED_AGENT_PROFILES_UNAVAILABLE" });
543947
544426
  }
543948
544427
  }
543949
544428
  //#endregion
@@ -544285,11 +544764,12 @@ function sessionRowsForPicker(sessions, currentSessionId, currentSessionHasConte
544285
544764
  metadata: session.metadata
544286
544765
  }));
544287
544766
  }
544288
- async function enrichSessionRowsForPicker(rows) {
544767
+ async function enrichSessionRowsForPicker(rows, isCurrent = () => true) {
544289
544768
  let next = 0;
544290
544769
  const enriched = rows.slice();
544291
544770
  async function work() {
544292
544771
  while (next < rows.length) {
544772
+ if (!isCurrent()) return;
544293
544773
  const index = next++;
544294
544774
  const row = rows[index];
544295
544775
  if (row?.session_dir === void 0) continue;
@@ -546021,6 +546501,7 @@ var BlunTUI = class {
546021
546501
  canInterruptForQueuedWork() {
546022
546502
  const item = this.state.queuedMessages[0];
546023
546503
  const local = this.queuePolicy.policy?.mode === "interrupt" && this.hasLocalPolicyHead();
546504
+ if (this.session !== void 0 && this.goalChannelReplies.completionRouteForTurn(this.session.id, this.streamingUI.getTurnContext().turnId) !== void 0) return false;
546024
546505
  if (local && this.pendingChannelReplyGuard !== void 0) return false;
546025
546506
  if (/^[1-9]\d*$/u.test(this.pendingChannelReplyGuard?.chatId ?? "") && item?.channelChatId?.startsWith("-") === true) return false;
546026
546507
  return (item?.mode === "channel" || local) && item?.channelContextOnly !== true && this.session !== void 0 && !this.isShuttingDown && !this.queueCommandRunning && !this.editorReplacementActive && this.queueSteerInFlight === void 0 && this.manualPromptInFlight === void 0 && !this.deferUserMessages && !this.state.appState.isCompacting && this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell" && this.shellOutputStreams.size === 0 && !this.streamingUI.hasActiveToolCalls();
@@ -546028,6 +546509,7 @@ var BlunTUI = class {
546028
546509
  canDeliverQueuedChannelHead() {
546029
546510
  const item = this.state.queuedMessages[0];
546030
546511
  if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || this.editorReplacementActive || this.deferUserMessages || this.session === void 0 || this.state.appState.model.trim().length === 0 || item?.mode !== "channel") return false;
546512
+ if (this.goalChannelReplies.completionRouteForTurn(this.session.id, this.streamingUI.getTurnContext().turnId) !== void 0) return false;
546031
546513
  if (this.state.appState.streamingPhase !== "idle" && this.queueFlushBatchRemaining === 0 && this.queuePolicy.policy?.mode !== "steer") return false;
546032
546514
  const guard = this.pendingChannelReplyGuard;
546033
546515
  return guard === void 0 || item.channelChatId !== void 0 && guard.chatId === item.channelChatId && guard.threadId === item.channelThreadId;
@@ -546083,6 +546565,9 @@ var BlunTUI = class {
546083
546565
  accepted: false,
546084
546566
  stepStarted: false,
546085
546567
  turnEnded: false,
546568
+ onStepStart: () => {
546569
+ if (installedGuard !== void 0) installedGuard.transcriptStart = this.state.transcriptEntries.length;
546570
+ },
546086
546571
  onCommit: () => {
546087
546572
  if (expectedTurnId !== void 0) {
546088
546573
  armWorkHistorySearchIntentForChannel(session.id, item.channelChatId, item.displayText ?? "", false);
@@ -546119,7 +546604,10 @@ var BlunTUI = class {
546119
546604
  commitQueuedSteerAtStepStart(turnId) {
546120
546605
  const inFlight = this.queueSteerInFlight;
546121
546606
  if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
546122
- inFlight.stepStarted = true;
546607
+ if (!inFlight.stepStarted) {
546608
+ inFlight.stepStarted = true;
546609
+ inFlight.onStepStart?.();
546610
+ }
546123
546611
  this.commitQueuedSteerIfReady(inFlight);
546124
546612
  }
546125
546613
  restoreQueuedSteerAtTurnEnd(turnId) {
@@ -546152,6 +546640,9 @@ var BlunTUI = class {
546152
546640
  this.channelQueueDeadline?.sync();
546153
546641
  }
546154
546642
  releaseChannelQueueAtSafePoint() {
546643
+ const guard = this.pendingChannelReplyGuard;
546644
+ const head = this.state.queuedMessages[0];
546645
+ if (guard !== void 0 && (guard.goalId === void 0 || this.session !== void 0 && this.goalChannelReplies.ownsActiveRoute(this.session.id, guard.goalId, guard.chatId, guard.threadId)) && head?.mode === "channel" && head.channelContextOnly !== true && head.channelChatId !== void 0 && (head.channelChatId !== guard.chatId || head.channelThreadId !== guard.threadId) && outboxGrewForChat(guard.outboxMarker, guard.chatId, guard.threadId)) this.pendingChannelReplyGuard = void 0;
546155
546646
  if (this.queuePolicy.policy?.mode === "interrupt") this.channelQueueDeadline.requestDeliveryNow();
546156
546647
  else {
546157
546648
  if (this.queuePolicy.policy?.mode === "steer") this.steerQueueFlushPrefix(this.queueFlushBatchRemaining === 0);
@@ -546194,6 +546685,7 @@ var BlunTUI = class {
546194
546685
  this.scheduleQueueDrain();
546195
546686
  }
546196
546687
  steerQueueFlushPrefix(automatic = false) {
546688
+ if (this.session !== void 0 && this.goalChannelReplies.completionRouteForTurn(this.session.id, this.streamingUI.getTurnContext().turnId) !== void 0) return;
546197
546689
  if (automatic && (this.pendingChannelReplyGuard !== void 0 || this.isShuttingDown || this.queueCommandRunning || this.editorReplacementActive || this.shellOutputStreams.size > 0 || this.streamingUI.hasActiveToolCalls())) return;
546198
546690
  if (this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || !automatic && this.queueFlushBatchRemaining === 0 || this.deferUserMessages || this.state.appState.isCompacting || this.state.appState.streamingPhase === "idle" || this.state.appState.streamingPhase === "shell") return;
546199
546691
  const session = this.session;
@@ -546489,6 +546981,13 @@ var BlunTUI = class {
546489
546981
  }
546490
546982
  /** Pending delivery guard for the channel-origin turn currently running. */
546491
546983
  pendingChannelReplyGuard;
546984
+ captureChannelReplyAtGoalCompletion(sessionId, goalId) {
546985
+ const guard = this.pendingChannelReplyGuard;
546986
+ const turnId = this.streamingUI.getTurnContext().turnId;
546987
+ const route = this.goalChannelReplies.completionRouteForTurn(sessionId, turnId);
546988
+ if (guard === void 0 || guard.goalCompletionText !== void 0 || route?.goalId !== goalId || guard.chatId === route.chatId && guard.threadId === route.threadId) return;
546989
+ guard.goalCompletionText = this.state.transcriptEntries.slice(guard.transcriptStart).findLast((entry) => entry.kind === "assistant" && entry.turnId === turnId)?.content.trim() ?? "";
546990
+ }
546492
546991
  /** See SessionEventHost.runChannelReplyFallback — called at turn end. */
546493
546992
  channelMediaDeliveries = /* @__PURE__ */ new Set();
546494
546993
  /** Deliver completed media at tool-result time so later queued work cannot hide it. */
@@ -546517,14 +547016,16 @@ var BlunTUI = class {
546517
547016
  if (reason !== "completed") return;
546518
547017
  if (this.state.transcriptEntries.slice(guard.transcriptStart).some((entry) => {
546519
547018
  const tool = entry.toolCallData;
546520
- if (entry.kind !== "tool_call" || tool === void 0 || !/reply|edit_message/i.test(tool.name)) return false;
547019
+ if (entry.kind !== "tool_call" || tool === void 0 || !TELEGRAM_GOAL_REPLY_TOOL_NAME.test(tool.name)) return false;
547020
+ const result = tool.result;
547021
+ if (result === void 0 || result.tool_call_id !== tool.id || result.is_error === true || result.synthetic === true || telegramReplyReceipt("", result.output) === void 0) return false;
546521
547022
  const chatId = tool.args["chat_id"];
546522
547023
  if (chatId !== void 0 && (typeof chatId !== "string" && typeof chatId !== "number" || String(chatId) !== guard.chatId)) return false;
546523
547024
  const threadId = tool.args["message_thread_id"];
546524
547025
  return threadId === void 0 || (typeof threadId === "string" || typeof threadId === "number") && String(threadId) === guard.threadId;
546525
547026
  })) return;
546526
547027
  if (outboxGrewForChat(guard.outboxMarker, guard.chatId, guard.threadId)) return;
546527
- const finalText = this.state.transcriptEntries.slice(guard.transcriptStart).filter((entry) => entry.kind === "assistant" && entry.content.trim().length > 0).map((entry) => entry.content.trim()).at(-1) ?? "";
547028
+ const finalText = guard.goalCompletionText ?? this.state.transcriptEntries.slice(guard.transcriptStart).filter((entry) => entry.kind === "assistant" && entry.content.trim().length > 0).map((entry) => entry.content.trim()).at(-1) ?? "";
546528
547029
  if (finalText.length === 0 || isSilentTurnMarker(finalText)) return;
546529
547030
  (guard.threadId === void 0 ? sendReplyFallback(guard.chatId, finalText, guard.contextOnly) : sendReplyFallback(guard.chatId, finalText, guard.contextOnly, false, void 0, guard.threadId)).then((sent) => {
546530
547031
  if (sent) this.showStatus(uiText("blunTui.telegram.fallbackDelivered"));
@@ -546840,17 +547341,13 @@ var BlunTUI = class {
546840
547341
  }
546841
547342
  clearQueuedMessages() {
546842
547343
  this.manualPromptInFlight = void 0;
546843
- const discarded = [...this.state.queuedMessages, ...this.queueSteerInFlight?.items ?? []];
547344
+ const pendingChannelSteer = this.queueSteerInFlight?.items.filter((item) => item.mode === "channel") ?? [];
546844
547345
  this.queueSteerInFlight?.onRestore?.();
546845
- this.state.queuedMessages = [];
547346
+ this.state.queuedMessages = [...pendingChannelSteer, ...this.state.queuedMessages.filter((item) => item.mode === "channel")];
546846
547347
  this.queueFlushBatchRemaining = 0;
546847
547348
  this.queueSteerInFlight = void 0;
546848
547349
  this.syncChannelQueueDeadline();
546849
- for (const acknowledge of new Set(discarded.map((item) => item.channelAcknowledge))) try {
546850
- acknowledge?.();
546851
- } catch (error) {
546852
- this.showError(formatErrorMessage$2(error));
546853
- }
547350
+ this.scheduleQueueDrain();
546854
547351
  }
546855
547352
  shiftQueuedMessage() {
546856
547353
  if (this.state.queuedMessages.length === 0) return void 0;
@@ -547013,6 +547510,9 @@ var BlunTUI = class {
547013
547510
  if (this.session === void 0) throw new Error(noActiveSessionMessage());
547014
547511
  return this.session;
547015
547512
  }
547513
+ getConfiguredAgentProfiles(env = process.env) {
547514
+ return listConfiguredAgentProfiles(this.harness.homeDir, env);
547515
+ }
547016
547516
  async createSessionFromCurrentState() {
547017
547517
  const options = {
547018
547518
  workDir: this.state.appState.workDir,
@@ -547240,18 +547740,19 @@ var BlunTUI = class {
547240
547740
  const request = {};
547241
547741
  this.sessionListRequest = request;
547242
547742
  const workDir = this.state.appState.workDir;
547743
+ const isCurrent = () => this.sessionListRequest === request && this.state.appState.workDir === workDir;
547243
547744
  this.state.loadingSessions = true;
547244
547745
  this.state.sessionsScope = scope;
547245
547746
  try {
547246
547747
  const sessions = scope === "all" ? await this.harness.listSessions({}) : await this.harness.listSessions({ workDir });
547247
- if (this.sessionListRequest !== request) return false;
547748
+ if (!isCurrent()) return false;
547248
547749
  let rows = sessionTargetRows(sessionRowsForPicker(sessions, this.state.appState.sessionId, target.length > 0 || this.hasSessionContent()), target);
547249
547750
  if (scope === "cwd" && target.length > 0) {
547250
547751
  const inWorkspace = await Promise.all(rows.map((row) => workspacePathsEqual(row.work_dir, workDir)));
547251
547752
  rows = rows.filter((_, index) => inWorkspace[index]);
547252
547753
  }
547253
- const enriched = await enrichSessionRowsForPicker(rows);
547254
- if (this.sessionListRequest !== request || this.state.appState.workDir !== workDir) return false;
547754
+ const enriched = await enrichSessionRowsForPicker(rows, isCurrent);
547755
+ if (!isCurrent()) return false;
547255
547756
  this.state.sessions = enriched;
547256
547757
  return true;
547257
547758
  } catch (error) {