@factiii/runner 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -961,7 +961,7 @@ var require_suggestSimilar = __commonJS({
961
961
  // node_modules/commander/lib/command.js
962
962
  var require_command = __commonJS({
963
963
  "node_modules/commander/lib/command.js"(exports2) {
964
- var EventEmitter = require("node:events").EventEmitter;
964
+ var EventEmitter2 = require("node:events").EventEmitter;
965
965
  var childProcess = require("node:child_process");
966
966
  var path15 = require("node:path");
967
967
  var fs13 = require("node:fs");
@@ -971,7 +971,7 @@ var require_command = __commonJS({
971
971
  var { Help: Help2 } = require_help();
972
972
  var { Option: Option2, DualOptions } = require_option();
973
973
  var { suggestSimilar } = require_suggestSimilar();
974
- var Command2 = class _Command extends EventEmitter {
974
+ var Command2 = class _Command extends EventEmitter2 {
975
975
  /**
976
976
  * Initialize a new `Command`.
977
977
  *
@@ -6503,13 +6503,13 @@ var require_extension = __commonJS({
6503
6503
  var require_websocket = __commonJS({
6504
6504
  "../../node_modules/ws/lib/websocket.js"(exports2, module2) {
6505
6505
  "use strict";
6506
- var EventEmitter = require("events");
6506
+ var EventEmitter2 = require("events");
6507
6507
  var https = require("https");
6508
6508
  var http = require("http");
6509
6509
  var net2 = require("net");
6510
6510
  var tls = require("tls");
6511
6511
  var { randomBytes, createHash: createHash2 } = require("crypto");
6512
- var { Duplex, Readable } = require("stream");
6512
+ var { Duplex, Readable: Readable2 } = require("stream");
6513
6513
  var { URL: URL2 } = require("url");
6514
6514
  var PerMessageDeflate2 = require_permessage_deflate();
6515
6515
  var Receiver2 = require_receiver();
@@ -6535,7 +6535,7 @@ var require_websocket = __commonJS({
6535
6535
  var protocolVersions = [8, 13];
6536
6536
  var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
6537
6537
  var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
6538
- var WebSocket2 = class _WebSocket extends EventEmitter {
6538
+ var WebSocket2 = class _WebSocket extends EventEmitter2 {
6539
6539
  /**
6540
6540
  * Create a new `WebSocket`.
6541
6541
  *
@@ -7457,7 +7457,7 @@ var require_stream = __commonJS({
7457
7457
  };
7458
7458
  duplex._final = function(callback) {
7459
7459
  if (ws.readyState === ws.CONNECTING) {
7460
- ws.once("open", function open() {
7460
+ ws.once("open", function open2() {
7461
7461
  duplex._final(callback);
7462
7462
  });
7463
7463
  return;
@@ -7478,7 +7478,7 @@ var require_stream = __commonJS({
7478
7478
  };
7479
7479
  duplex._write = function(chunk, encoding, callback) {
7480
7480
  if (ws.readyState === ws.CONNECTING) {
7481
- ws.once("open", function open() {
7481
+ ws.once("open", function open2() {
7482
7482
  duplex._write(chunk, encoding, callback);
7483
7483
  });
7484
7484
  return;
@@ -7542,7 +7542,7 @@ var require_subprotocol = __commonJS({
7542
7542
  var require_websocket_server = __commonJS({
7543
7543
  "../../node_modules/ws/lib/websocket-server.js"(exports2, module2) {
7544
7544
  "use strict";
7545
- var EventEmitter = require("events");
7545
+ var EventEmitter2 = require("events");
7546
7546
  var http = require("http");
7547
7547
  var { Duplex } = require("stream");
7548
7548
  var { createHash: createHash2 } = require("crypto");
@@ -7555,7 +7555,7 @@ var require_websocket_server = __commonJS({
7555
7555
  var RUNNING = 0;
7556
7556
  var CLOSING = 1;
7557
7557
  var CLOSED = 2;
7558
- var WebSocketServer2 = class extends EventEmitter {
7558
+ var WebSocketServer2 = class extends EventEmitter2 {
7559
7559
  /**
7560
7560
  * Create a `WebSocketServer` instance.
7561
7561
  *
@@ -7967,10 +7967,10 @@ function prompt(msg) {
7967
7967
  input: process.stdin,
7968
7968
  output: process.stdout
7969
7969
  });
7970
- return new Promise((resolve2) => {
7970
+ return new Promise((resolve4) => {
7971
7971
  rl.question(msg, (answer) => {
7972
7972
  rl.close();
7973
- resolve2(answer.trim());
7973
+ resolve4(answer.trim());
7974
7974
  });
7975
7975
  });
7976
7976
  }
@@ -8779,11 +8779,11 @@ function promptPassword(label) {
8779
8779
  rl._writeToOutput = (text) => {
8780
8780
  if (!muted) write(text);
8781
8781
  };
8782
- return new Promise((resolve2) => {
8782
+ return new Promise((resolve4) => {
8783
8783
  rl.question(label, (answer) => {
8784
8784
  rl.close();
8785
8785
  process.stdout.write("\n");
8786
- resolve2(answer);
8786
+ resolve4(answer);
8787
8787
  });
8788
8788
  muted = true;
8789
8789
  });
@@ -13603,7 +13603,7 @@ async function markOnboardingComplete(target) {
13603
13603
  await target.sh(`node -e "${script}"`);
13604
13604
  }
13605
13605
  function runAgentProc(proc, prompt2, stream, label, errorPrefix) {
13606
- return new Promise((resolve2, reject) => {
13606
+ return new Promise((resolve4, reject) => {
13607
13607
  let errorOutput = "";
13608
13608
  proc.stderr?.on("data", (chunk) => {
13609
13609
  errorOutput += chunk.toString();
@@ -13618,7 +13618,7 @@ function runAgentProc(proc, prompt2, stream, label, errorPrefix) {
13618
13618
  } else if (code !== 0 && !text) {
13619
13619
  reject(new Error(errorOutput || `${label} exited with code ${code}`));
13620
13620
  } else {
13621
- resolve2({ text, sessionId });
13621
+ resolve4({ text, sessionId });
13622
13622
  }
13623
13623
  });
13624
13624
  proc.on("error", (err) => {
@@ -13767,8 +13767,14 @@ function hostSpacePaths(spaceDir) {
13767
13767
  bin: import_path6.default.join(spaceDir, "bin")
13768
13768
  };
13769
13769
  }
13770
- function worktreeFor(paths, taskId) {
13771
- return `${paths.worktrees}/${taskId.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
13770
+ function worktreeFor(paths, workName) {
13771
+ return `${paths.worktrees}/${workName.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
13772
+ }
13773
+
13774
+ // ../../shared/all/helpers/board-agent-core/workName.ts
13775
+ var WORK_NAME_MAX = 48;
13776
+ function slugifyWorkName(name) {
13777
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, WORK_NAME_MAX).replace(/^-+|-+$/g, "");
13772
13778
  }
13773
13779
 
13774
13780
  // ../../shared/all/helpers/board-agent-core/git.ts
@@ -13784,8 +13790,37 @@ function buildCloneUrl(repoUrl, githubToken) {
13784
13790
  async function gitInDir(target, workdir, ...args) {
13785
13791
  return target.run(["git", "-C", workdir, ...args]);
13786
13792
  }
13787
- function cardWorkBranch(taskId) {
13788
- return `factiii/card-${taskId.replace(/[^a-zA-Z0-9._-]/g, "-")}`;
13793
+ var WORK_BRANCH_PREFIX = "factiii/card-";
13794
+ function cardWorkBranch(workName) {
13795
+ return `${WORK_BRANCH_PREFIX}${workName.replace(/[^a-zA-Z0-9._-]/g, "-")}`;
13796
+ }
13797
+ async function listWorkNames(target) {
13798
+ const dirs = await target.sh(`ls -1 ${target.paths.worktrees} 2>/dev/null || true`).catch(() => "");
13799
+ const branches = await gitInDir(
13800
+ target,
13801
+ target.paths.repo,
13802
+ "for-each-ref",
13803
+ "--format=%(refname:short)",
13804
+ "refs/heads/"
13805
+ ).catch(() => "");
13806
+ const names = new Set(dirs.split("\n").map((line) => line.trim()));
13807
+ for (const line of branches.split("\n")) {
13808
+ const name = line.trim();
13809
+ if (name.startsWith(WORK_BRANCH_PREFIX)) {
13810
+ names.add(name.slice(WORK_BRANCH_PREFIX.length));
13811
+ }
13812
+ }
13813
+ names.delete("");
13814
+ return [...names];
13815
+ }
13816
+ async function claimWorkName(target, desired, extraTaken = []) {
13817
+ const name = slugifyWorkName(desired);
13818
+ if (!name) throw new Error("Name this terminal before starting it.");
13819
+ const taken = /* @__PURE__ */ new Set([...await listWorkNames(target), ...extraTaken]);
13820
+ if (taken.has(name)) {
13821
+ throw new Error(`"${name}" is already in use. Pick another name.`);
13822
+ }
13823
+ return name;
13789
13824
  }
13790
13825
  async function ensurePrimaryClone(target, cloneUrl, branch) {
13791
13826
  const repo = target.paths.repo;
@@ -13807,9 +13842,9 @@ async function ensurePrimaryClone(target, cloneUrl, branch) {
13807
13842
  });
13808
13843
  await target.sh(`mkdir -p ${target.paths.worktrees}`);
13809
13844
  }
13810
- async function addWorktree(target, taskId, baseBranch) {
13811
- const path15 = worktreeFor(target.paths, taskId);
13812
- const branch = cardWorkBranch(taskId);
13845
+ async function addWorktree(target, workName, baseBranch) {
13846
+ const path15 = worktreeFor(target.paths, workName);
13847
+ const branch = cardWorkBranch(workName);
13813
13848
  await removeWorktree(target, path15).catch(() => {
13814
13849
  });
13815
13850
  await gitInDir(
@@ -14066,14 +14101,14 @@ function killTree(proc, signal = "SIGKILL") {
14066
14101
  function execLogin(command, opts) {
14067
14102
  const [bin, args] = isWindows ? ["bash", ["-c", command]] : [process.env.SHELL || "/bin/bash", ["-lc", command]];
14068
14103
  const cap = opts.maxBuffer ?? 4 * 1024 * 1024;
14069
- return new Promise((resolve2) => {
14104
+ return new Promise((resolve4) => {
14070
14105
  let output = "";
14071
14106
  let settled = false;
14072
14107
  const done = (code, extra = "") => {
14073
14108
  if (settled) return;
14074
14109
  settled = true;
14075
14110
  clearTimeout(timer);
14076
- resolve2({ code, output: (output + extra).slice(-cap) });
14111
+ resolve4({ code, output: (output + extra).slice(-cap) });
14077
14112
  };
14078
14113
  let proc;
14079
14114
  try {
@@ -14143,7 +14178,7 @@ async function allocateSpacePorts(spaceDir) {
14143
14178
  const ports = [];
14144
14179
  const seen = /* @__PURE__ */ new Set();
14145
14180
  while (ports.length < NUM_PORTS) {
14146
- const port = await new Promise((resolve2, reject) => {
14181
+ const port = await new Promise((resolve4, reject) => {
14147
14182
  const srv = import_net.default.createServer();
14148
14183
  srv.unref();
14149
14184
  srv.on("error", reject);
@@ -14151,7 +14186,7 @@ async function allocateSpacePorts(spaceDir) {
14151
14186
  const addr = srv.address();
14152
14187
  if (typeof addr === "object" && addr) {
14153
14188
  const p = addr.port;
14154
- srv.close(() => resolve2(p));
14189
+ srv.close(() => resolve4(p));
14155
14190
  } else {
14156
14191
  srv.close(() => reject(new Error("Failed to get a free port")));
14157
14192
  }
@@ -14221,7 +14256,7 @@ function hostTarget(spaceDir, extraEnv) {
14221
14256
  async runWithStdin(argv, input, label) {
14222
14257
  const [bin, ...rest] = argv;
14223
14258
  const env = await spawnEnv();
14224
- return new Promise((resolve2, reject) => {
14259
+ return new Promise((resolve4, reject) => {
14225
14260
  const proc = (0, import_child_process4.spawn)(bin, rest, { cwd: usableCwd(paths.root), env });
14226
14261
  let stderr = "";
14227
14262
  proc.stderr?.on("data", (d) => {
@@ -14229,7 +14264,7 @@ function hostTarget(spaceDir, extraEnv) {
14229
14264
  });
14230
14265
  proc.on("error", reject);
14231
14266
  proc.on("close", (code) => {
14232
- if (code === 0) resolve2();
14267
+ if (code === 0) resolve4();
14233
14268
  else reject(new Error(`${label}: ${stderr.trim()}`));
14234
14269
  });
14235
14270
  proc.stdin?.on("error", () => {
@@ -14398,6 +14433,9 @@ function createEventSink(send, spaceSlug, notify) {
14398
14433
  },
14399
14434
  emitDeployEnv(payload) {
14400
14435
  send(channel("deploy-env"), payload);
14436
+ },
14437
+ emitBareFsChange(postId, change) {
14438
+ send(channel(`bare-fs:${postId}`), change);
14401
14439
  }
14402
14440
  };
14403
14441
  }
@@ -14779,8 +14817,8 @@ var ClaudeModeEngine = class _ClaudeModeEngine {
14779
14817
  "system",
14780
14818
  "The agent has a question - waiting for your input."
14781
14819
  );
14782
- const answer = await new Promise((resolve2) => {
14783
- session.answerResolver = resolve2;
14820
+ const answer = await new Promise((resolve4) => {
14821
+ session.answerResolver = resolve4;
14784
14822
  });
14785
14823
  if (this.stopped(session)) return;
14786
14824
  session.phase = "research";
@@ -15239,6 +15277,18 @@ ${buildPrompt(prompts_default.implement)}`;
15239
15277
  }
15240
15278
  };
15241
15279
 
15280
+ // ../../shared/all/helpers/terminal-ai/terminal-mode.ts
15281
+ var import_crypto4 = require("crypto");
15282
+
15283
+ // ../../shared/all/helpers/board-agent-core/boardTerminal.ts
15284
+ function boardTerminalKey(spaceSlug) {
15285
+ return `board-${spaceSlug}`;
15286
+ }
15287
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
15288
+ function isCardPostId(id) {
15289
+ return UUID_RE.test(id);
15290
+ }
15291
+
15242
15292
  // ../../shared/all/helpers/board-agent-core/tmux.ts
15243
15293
  var TMUX_CONF = [
15244
15294
  // Wheel scrolls, drag selects in copy mode.
@@ -15328,6 +15378,1865 @@ async function startTmuxSession(opts) {
15328
15378
  };
15329
15379
  }
15330
15380
 
15381
+ // ../../node_modules/chokidar/esm/index.js
15382
+ var import_fs8 = require("fs");
15383
+ var import_promises5 = require("fs/promises");
15384
+ var import_events = require("events");
15385
+ var sysPath2 = __toESM(require("path"), 1);
15386
+
15387
+ // ../../node_modules/readdirp/esm/index.js
15388
+ var import_promises3 = require("node:fs/promises");
15389
+ var import_node_stream = require("node:stream");
15390
+ var import_node_path = require("node:path");
15391
+ var EntryTypes = {
15392
+ FILE_TYPE: "files",
15393
+ DIR_TYPE: "directories",
15394
+ FILE_DIR_TYPE: "files_directories",
15395
+ EVERYTHING_TYPE: "all"
15396
+ };
15397
+ var defaultOptions = {
15398
+ root: ".",
15399
+ fileFilter: (_entryInfo) => true,
15400
+ directoryFilter: (_entryInfo) => true,
15401
+ type: EntryTypes.FILE_TYPE,
15402
+ lstat: false,
15403
+ depth: 2147483648,
15404
+ alwaysStat: false,
15405
+ highWaterMark: 4096
15406
+ };
15407
+ Object.freeze(defaultOptions);
15408
+ var RECURSIVE_ERROR_CODE = "READDIRP_RECURSIVE_ERROR";
15409
+ var NORMAL_FLOW_ERRORS = /* @__PURE__ */ new Set(["ENOENT", "EPERM", "EACCES", "ELOOP", RECURSIVE_ERROR_CODE]);
15410
+ var ALL_TYPES = [
15411
+ EntryTypes.DIR_TYPE,
15412
+ EntryTypes.EVERYTHING_TYPE,
15413
+ EntryTypes.FILE_DIR_TYPE,
15414
+ EntryTypes.FILE_TYPE
15415
+ ];
15416
+ var DIR_TYPES = /* @__PURE__ */ new Set([
15417
+ EntryTypes.DIR_TYPE,
15418
+ EntryTypes.EVERYTHING_TYPE,
15419
+ EntryTypes.FILE_DIR_TYPE
15420
+ ]);
15421
+ var FILE_TYPES = /* @__PURE__ */ new Set([
15422
+ EntryTypes.EVERYTHING_TYPE,
15423
+ EntryTypes.FILE_DIR_TYPE,
15424
+ EntryTypes.FILE_TYPE
15425
+ ]);
15426
+ var isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);
15427
+ var wantBigintFsStats = process.platform === "win32";
15428
+ var emptyFn = (_entryInfo) => true;
15429
+ var normalizeFilter = (filter) => {
15430
+ if (filter === void 0)
15431
+ return emptyFn;
15432
+ if (typeof filter === "function")
15433
+ return filter;
15434
+ if (typeof filter === "string") {
15435
+ const fl = filter.trim();
15436
+ return (entry) => entry.basename === fl;
15437
+ }
15438
+ if (Array.isArray(filter)) {
15439
+ const trItems = filter.map((item) => item.trim());
15440
+ return (entry) => trItems.some((f) => entry.basename === f);
15441
+ }
15442
+ return emptyFn;
15443
+ };
15444
+ var ReaddirpStream = class extends import_node_stream.Readable {
15445
+ constructor(options = {}) {
15446
+ super({
15447
+ objectMode: true,
15448
+ autoDestroy: true,
15449
+ highWaterMark: options.highWaterMark
15450
+ });
15451
+ const opts = { ...defaultOptions, ...options };
15452
+ const { root, type } = opts;
15453
+ this._fileFilter = normalizeFilter(opts.fileFilter);
15454
+ this._directoryFilter = normalizeFilter(opts.directoryFilter);
15455
+ const statMethod = opts.lstat ? import_promises3.lstat : import_promises3.stat;
15456
+ if (wantBigintFsStats) {
15457
+ this._stat = (path15) => statMethod(path15, { bigint: true });
15458
+ } else {
15459
+ this._stat = statMethod;
15460
+ }
15461
+ this._maxDepth = opts.depth ?? defaultOptions.depth;
15462
+ this._wantsDir = type ? DIR_TYPES.has(type) : false;
15463
+ this._wantsFile = type ? FILE_TYPES.has(type) : false;
15464
+ this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
15465
+ this._root = (0, import_node_path.resolve)(root);
15466
+ this._isDirent = !opts.alwaysStat;
15467
+ this._statsProp = this._isDirent ? "dirent" : "stats";
15468
+ this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
15469
+ this.parents = [this._exploreDir(root, 1)];
15470
+ this.reading = false;
15471
+ this.parent = void 0;
15472
+ }
15473
+ async _read(batch) {
15474
+ if (this.reading)
15475
+ return;
15476
+ this.reading = true;
15477
+ try {
15478
+ while (!this.destroyed && batch > 0) {
15479
+ const par = this.parent;
15480
+ const fil = par && par.files;
15481
+ if (fil && fil.length > 0) {
15482
+ const { path: path15, depth } = par;
15483
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path15));
15484
+ const awaited = await Promise.all(slice);
15485
+ for (const entry of awaited) {
15486
+ if (!entry)
15487
+ continue;
15488
+ if (this.destroyed)
15489
+ return;
15490
+ const entryType = await this._getEntryType(entry);
15491
+ if (entryType === "directory" && this._directoryFilter(entry)) {
15492
+ if (depth <= this._maxDepth) {
15493
+ this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
15494
+ }
15495
+ if (this._wantsDir) {
15496
+ this.push(entry);
15497
+ batch--;
15498
+ }
15499
+ } else if ((entryType === "file" || this._includeAsFile(entry)) && this._fileFilter(entry)) {
15500
+ if (this._wantsFile) {
15501
+ this.push(entry);
15502
+ batch--;
15503
+ }
15504
+ }
15505
+ }
15506
+ } else {
15507
+ const parent = this.parents.pop();
15508
+ if (!parent) {
15509
+ this.push(null);
15510
+ break;
15511
+ }
15512
+ this.parent = await parent;
15513
+ if (this.destroyed)
15514
+ return;
15515
+ }
15516
+ }
15517
+ } catch (error) {
15518
+ this.destroy(error);
15519
+ } finally {
15520
+ this.reading = false;
15521
+ }
15522
+ }
15523
+ async _exploreDir(path15, depth) {
15524
+ let files;
15525
+ try {
15526
+ files = await (0, import_promises3.readdir)(path15, this._rdOptions);
15527
+ } catch (error) {
15528
+ this._onError(error);
15529
+ }
15530
+ return { files, depth, path: path15 };
15531
+ }
15532
+ async _formatEntry(dirent, path15) {
15533
+ let entry;
15534
+ const basename3 = this._isDirent ? dirent.name : dirent;
15535
+ try {
15536
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path15, basename3));
15537
+ entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename3 };
15538
+ entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
15539
+ } catch (err) {
15540
+ this._onError(err);
15541
+ return;
15542
+ }
15543
+ return entry;
15544
+ }
15545
+ _onError(err) {
15546
+ if (isNormalFlowError(err) && !this.destroyed) {
15547
+ this.emit("warn", err);
15548
+ } else {
15549
+ this.destroy(err);
15550
+ }
15551
+ }
15552
+ async _getEntryType(entry) {
15553
+ if (!entry && this._statsProp in entry) {
15554
+ return "";
15555
+ }
15556
+ const stats = entry[this._statsProp];
15557
+ if (stats.isFile())
15558
+ return "file";
15559
+ if (stats.isDirectory())
15560
+ return "directory";
15561
+ if (stats && stats.isSymbolicLink()) {
15562
+ const full = entry.fullPath;
15563
+ try {
15564
+ const entryRealPath = await (0, import_promises3.realpath)(full);
15565
+ const entryRealPathStats = await (0, import_promises3.lstat)(entryRealPath);
15566
+ if (entryRealPathStats.isFile()) {
15567
+ return "file";
15568
+ }
15569
+ if (entryRealPathStats.isDirectory()) {
15570
+ const len = entryRealPath.length;
15571
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path.sep) {
15572
+ const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
15573
+ recursiveError.code = RECURSIVE_ERROR_CODE;
15574
+ return this._onError(recursiveError);
15575
+ }
15576
+ return "directory";
15577
+ }
15578
+ } catch (error) {
15579
+ this._onError(error);
15580
+ return "";
15581
+ }
15582
+ }
15583
+ }
15584
+ _includeAsFile(entry) {
15585
+ const stats = entry && entry[this._statsProp];
15586
+ return stats && this._wantsEverything && !stats.isDirectory();
15587
+ }
15588
+ };
15589
+ function readdirp(root, options = {}) {
15590
+ let type = options.entryType || options.type;
15591
+ if (type === "both")
15592
+ type = EntryTypes.FILE_DIR_TYPE;
15593
+ if (type)
15594
+ options.type = type;
15595
+ if (!root) {
15596
+ throw new Error("readdirp: root argument is required. Usage: readdirp(root, options)");
15597
+ } else if (typeof root !== "string") {
15598
+ throw new TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");
15599
+ } else if (type && !ALL_TYPES.includes(type)) {
15600
+ throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(", ")}`);
15601
+ }
15602
+ options.root = root;
15603
+ return new ReaddirpStream(options);
15604
+ }
15605
+
15606
+ // ../../node_modules/chokidar/esm/handler.js
15607
+ var import_fs7 = require("fs");
15608
+ var import_promises4 = require("fs/promises");
15609
+ var sysPath = __toESM(require("path"), 1);
15610
+ var import_os4 = require("os");
15611
+ var STR_DATA = "data";
15612
+ var STR_END = "end";
15613
+ var STR_CLOSE = "close";
15614
+ var EMPTY_FN = () => {
15615
+ };
15616
+ var pl = process.platform;
15617
+ var isWindows2 = pl === "win32";
15618
+ var isMacos = pl === "darwin";
15619
+ var isLinux = pl === "linux";
15620
+ var isFreeBSD = pl === "freebsd";
15621
+ var isIBMi = (0, import_os4.type)() === "OS400";
15622
+ var EVENTS = {
15623
+ ALL: "all",
15624
+ READY: "ready",
15625
+ ADD: "add",
15626
+ CHANGE: "change",
15627
+ ADD_DIR: "addDir",
15628
+ UNLINK: "unlink",
15629
+ UNLINK_DIR: "unlinkDir",
15630
+ RAW: "raw",
15631
+ ERROR: "error"
15632
+ };
15633
+ var EV = EVENTS;
15634
+ var THROTTLE_MODE_WATCH = "watch";
15635
+ var statMethods = { lstat: import_promises4.lstat, stat: import_promises4.stat };
15636
+ var KEY_LISTENERS = "listeners";
15637
+ var KEY_ERR = "errHandlers";
15638
+ var KEY_RAW = "rawEmitters";
15639
+ var HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
15640
+ var binaryExtensions = /* @__PURE__ */ new Set([
15641
+ "3dm",
15642
+ "3ds",
15643
+ "3g2",
15644
+ "3gp",
15645
+ "7z",
15646
+ "a",
15647
+ "aac",
15648
+ "adp",
15649
+ "afdesign",
15650
+ "afphoto",
15651
+ "afpub",
15652
+ "ai",
15653
+ "aif",
15654
+ "aiff",
15655
+ "alz",
15656
+ "ape",
15657
+ "apk",
15658
+ "appimage",
15659
+ "ar",
15660
+ "arj",
15661
+ "asf",
15662
+ "au",
15663
+ "avi",
15664
+ "bak",
15665
+ "baml",
15666
+ "bh",
15667
+ "bin",
15668
+ "bk",
15669
+ "bmp",
15670
+ "btif",
15671
+ "bz2",
15672
+ "bzip2",
15673
+ "cab",
15674
+ "caf",
15675
+ "cgm",
15676
+ "class",
15677
+ "cmx",
15678
+ "cpio",
15679
+ "cr2",
15680
+ "cur",
15681
+ "dat",
15682
+ "dcm",
15683
+ "deb",
15684
+ "dex",
15685
+ "djvu",
15686
+ "dll",
15687
+ "dmg",
15688
+ "dng",
15689
+ "doc",
15690
+ "docm",
15691
+ "docx",
15692
+ "dot",
15693
+ "dotm",
15694
+ "dra",
15695
+ "DS_Store",
15696
+ "dsk",
15697
+ "dts",
15698
+ "dtshd",
15699
+ "dvb",
15700
+ "dwg",
15701
+ "dxf",
15702
+ "ecelp4800",
15703
+ "ecelp7470",
15704
+ "ecelp9600",
15705
+ "egg",
15706
+ "eol",
15707
+ "eot",
15708
+ "epub",
15709
+ "exe",
15710
+ "f4v",
15711
+ "fbs",
15712
+ "fh",
15713
+ "fla",
15714
+ "flac",
15715
+ "flatpak",
15716
+ "fli",
15717
+ "flv",
15718
+ "fpx",
15719
+ "fst",
15720
+ "fvt",
15721
+ "g3",
15722
+ "gh",
15723
+ "gif",
15724
+ "graffle",
15725
+ "gz",
15726
+ "gzip",
15727
+ "h261",
15728
+ "h263",
15729
+ "h264",
15730
+ "icns",
15731
+ "ico",
15732
+ "ief",
15733
+ "img",
15734
+ "ipa",
15735
+ "iso",
15736
+ "jar",
15737
+ "jpeg",
15738
+ "jpg",
15739
+ "jpgv",
15740
+ "jpm",
15741
+ "jxr",
15742
+ "key",
15743
+ "ktx",
15744
+ "lha",
15745
+ "lib",
15746
+ "lvp",
15747
+ "lz",
15748
+ "lzh",
15749
+ "lzma",
15750
+ "lzo",
15751
+ "m3u",
15752
+ "m4a",
15753
+ "m4v",
15754
+ "mar",
15755
+ "mdi",
15756
+ "mht",
15757
+ "mid",
15758
+ "midi",
15759
+ "mj2",
15760
+ "mka",
15761
+ "mkv",
15762
+ "mmr",
15763
+ "mng",
15764
+ "mobi",
15765
+ "mov",
15766
+ "movie",
15767
+ "mp3",
15768
+ "mp4",
15769
+ "mp4a",
15770
+ "mpeg",
15771
+ "mpg",
15772
+ "mpga",
15773
+ "mxu",
15774
+ "nef",
15775
+ "npx",
15776
+ "numbers",
15777
+ "nupkg",
15778
+ "o",
15779
+ "odp",
15780
+ "ods",
15781
+ "odt",
15782
+ "oga",
15783
+ "ogg",
15784
+ "ogv",
15785
+ "otf",
15786
+ "ott",
15787
+ "pages",
15788
+ "pbm",
15789
+ "pcx",
15790
+ "pdb",
15791
+ "pdf",
15792
+ "pea",
15793
+ "pgm",
15794
+ "pic",
15795
+ "png",
15796
+ "pnm",
15797
+ "pot",
15798
+ "potm",
15799
+ "potx",
15800
+ "ppa",
15801
+ "ppam",
15802
+ "ppm",
15803
+ "pps",
15804
+ "ppsm",
15805
+ "ppsx",
15806
+ "ppt",
15807
+ "pptm",
15808
+ "pptx",
15809
+ "psd",
15810
+ "pya",
15811
+ "pyc",
15812
+ "pyo",
15813
+ "pyv",
15814
+ "qt",
15815
+ "rar",
15816
+ "ras",
15817
+ "raw",
15818
+ "resources",
15819
+ "rgb",
15820
+ "rip",
15821
+ "rlc",
15822
+ "rmf",
15823
+ "rmvb",
15824
+ "rpm",
15825
+ "rtf",
15826
+ "rz",
15827
+ "s3m",
15828
+ "s7z",
15829
+ "scpt",
15830
+ "sgi",
15831
+ "shar",
15832
+ "snap",
15833
+ "sil",
15834
+ "sketch",
15835
+ "slk",
15836
+ "smv",
15837
+ "snk",
15838
+ "so",
15839
+ "stl",
15840
+ "suo",
15841
+ "sub",
15842
+ "swf",
15843
+ "tar",
15844
+ "tbz",
15845
+ "tbz2",
15846
+ "tga",
15847
+ "tgz",
15848
+ "thmx",
15849
+ "tif",
15850
+ "tiff",
15851
+ "tlz",
15852
+ "ttc",
15853
+ "ttf",
15854
+ "txz",
15855
+ "udf",
15856
+ "uvh",
15857
+ "uvi",
15858
+ "uvm",
15859
+ "uvp",
15860
+ "uvs",
15861
+ "uvu",
15862
+ "viv",
15863
+ "vob",
15864
+ "war",
15865
+ "wav",
15866
+ "wax",
15867
+ "wbmp",
15868
+ "wdp",
15869
+ "weba",
15870
+ "webm",
15871
+ "webp",
15872
+ "whl",
15873
+ "wim",
15874
+ "wm",
15875
+ "wma",
15876
+ "wmv",
15877
+ "wmx",
15878
+ "woff",
15879
+ "woff2",
15880
+ "wrm",
15881
+ "wvx",
15882
+ "xbm",
15883
+ "xif",
15884
+ "xla",
15885
+ "xlam",
15886
+ "xls",
15887
+ "xlsb",
15888
+ "xlsm",
15889
+ "xlsx",
15890
+ "xlt",
15891
+ "xltm",
15892
+ "xltx",
15893
+ "xm",
15894
+ "xmind",
15895
+ "xpi",
15896
+ "xpm",
15897
+ "xwd",
15898
+ "xz",
15899
+ "z",
15900
+ "zip",
15901
+ "zipx"
15902
+ ]);
15903
+ var isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
15904
+ var foreach = (val, fn) => {
15905
+ if (val instanceof Set) {
15906
+ val.forEach(fn);
15907
+ } else {
15908
+ fn(val);
15909
+ }
15910
+ };
15911
+ var addAndConvert = (main, prop, item) => {
15912
+ let container = main[prop];
15913
+ if (!(container instanceof Set)) {
15914
+ main[prop] = container = /* @__PURE__ */ new Set([container]);
15915
+ }
15916
+ container.add(item);
15917
+ };
15918
+ var clearItem = (cont) => (key) => {
15919
+ const set = cont[key];
15920
+ if (set instanceof Set) {
15921
+ set.clear();
15922
+ } else {
15923
+ delete cont[key];
15924
+ }
15925
+ };
15926
+ var delFromSet = (main, prop, item) => {
15927
+ const container = main[prop];
15928
+ if (container instanceof Set) {
15929
+ container.delete(item);
15930
+ } else if (container === item) {
15931
+ delete main[prop];
15932
+ }
15933
+ };
15934
+ var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
15935
+ var FsWatchInstances = /* @__PURE__ */ new Map();
15936
+ function createFsWatchInstance(path15, options, listener, errHandler, emitRaw) {
15937
+ const handleEvent = (rawEvent, evPath) => {
15938
+ listener(path15);
15939
+ emitRaw(rawEvent, evPath, { watchedPath: path15 });
15940
+ if (evPath && path15 !== evPath) {
15941
+ fsWatchBroadcast(sysPath.resolve(path15, evPath), KEY_LISTENERS, sysPath.join(path15, evPath));
15942
+ }
15943
+ };
15944
+ try {
15945
+ return (0, import_fs7.watch)(path15, {
15946
+ persistent: options.persistent
15947
+ }, handleEvent);
15948
+ } catch (error) {
15949
+ errHandler(error);
15950
+ return void 0;
15951
+ }
15952
+ }
15953
+ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
15954
+ const cont = FsWatchInstances.get(fullPath);
15955
+ if (!cont)
15956
+ return;
15957
+ foreach(cont[listenerType], (listener) => {
15958
+ listener(val1, val2, val3);
15959
+ });
15960
+ };
15961
+ var setFsWatchListener = (path15, fullPath, options, handlers) => {
15962
+ const { listener, errHandler, rawEmitter } = handlers;
15963
+ let cont = FsWatchInstances.get(fullPath);
15964
+ let watcher;
15965
+ if (!options.persistent) {
15966
+ watcher = createFsWatchInstance(path15, options, listener, errHandler, rawEmitter);
15967
+ if (!watcher)
15968
+ return;
15969
+ return watcher.close.bind(watcher);
15970
+ }
15971
+ if (cont) {
15972
+ addAndConvert(cont, KEY_LISTENERS, listener);
15973
+ addAndConvert(cont, KEY_ERR, errHandler);
15974
+ addAndConvert(cont, KEY_RAW, rawEmitter);
15975
+ } else {
15976
+ watcher = createFsWatchInstance(
15977
+ path15,
15978
+ options,
15979
+ fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
15980
+ errHandler,
15981
+ // no need to use broadcast here
15982
+ fsWatchBroadcast.bind(null, fullPath, KEY_RAW)
15983
+ );
15984
+ if (!watcher)
15985
+ return;
15986
+ watcher.on(EV.ERROR, async (error) => {
15987
+ const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
15988
+ if (cont)
15989
+ cont.watcherUnusable = true;
15990
+ if (isWindows2 && error.code === "EPERM") {
15991
+ try {
15992
+ const fd = await (0, import_promises4.open)(path15, "r");
15993
+ await fd.close();
15994
+ broadcastErr(error);
15995
+ } catch (err) {
15996
+ }
15997
+ } else {
15998
+ broadcastErr(error);
15999
+ }
16000
+ });
16001
+ cont = {
16002
+ listeners: listener,
16003
+ errHandlers: errHandler,
16004
+ rawEmitters: rawEmitter,
16005
+ watcher
16006
+ };
16007
+ FsWatchInstances.set(fullPath, cont);
16008
+ }
16009
+ return () => {
16010
+ delFromSet(cont, KEY_LISTENERS, listener);
16011
+ delFromSet(cont, KEY_ERR, errHandler);
16012
+ delFromSet(cont, KEY_RAW, rawEmitter);
16013
+ if (isEmptySet(cont.listeners)) {
16014
+ cont.watcher.close();
16015
+ FsWatchInstances.delete(fullPath);
16016
+ HANDLER_KEYS.forEach(clearItem(cont));
16017
+ cont.watcher = void 0;
16018
+ Object.freeze(cont);
16019
+ }
16020
+ };
16021
+ };
16022
+ var FsWatchFileInstances = /* @__PURE__ */ new Map();
16023
+ var setFsWatchFileListener = (path15, fullPath, options, handlers) => {
16024
+ const { listener, rawEmitter } = handlers;
16025
+ let cont = FsWatchFileInstances.get(fullPath);
16026
+ const copts = cont && cont.options;
16027
+ if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
16028
+ (0, import_fs7.unwatchFile)(fullPath);
16029
+ cont = void 0;
16030
+ }
16031
+ if (cont) {
16032
+ addAndConvert(cont, KEY_LISTENERS, listener);
16033
+ addAndConvert(cont, KEY_RAW, rawEmitter);
16034
+ } else {
16035
+ cont = {
16036
+ listeners: listener,
16037
+ rawEmitters: rawEmitter,
16038
+ options,
16039
+ watcher: (0, import_fs7.watchFile)(fullPath, options, (curr, prev) => {
16040
+ foreach(cont.rawEmitters, (rawEmitter2) => {
16041
+ rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
16042
+ });
16043
+ const currmtime = curr.mtimeMs;
16044
+ if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
16045
+ foreach(cont.listeners, (listener2) => listener2(path15, curr));
16046
+ }
16047
+ })
16048
+ };
16049
+ FsWatchFileInstances.set(fullPath, cont);
16050
+ }
16051
+ return () => {
16052
+ delFromSet(cont, KEY_LISTENERS, listener);
16053
+ delFromSet(cont, KEY_RAW, rawEmitter);
16054
+ if (isEmptySet(cont.listeners)) {
16055
+ FsWatchFileInstances.delete(fullPath);
16056
+ (0, import_fs7.unwatchFile)(fullPath);
16057
+ cont.options = cont.watcher = void 0;
16058
+ Object.freeze(cont);
16059
+ }
16060
+ };
16061
+ };
16062
+ var NodeFsHandler = class {
16063
+ constructor(fsW) {
16064
+ this.fsw = fsW;
16065
+ this._boundHandleError = (error) => fsW._handleError(error);
16066
+ }
16067
+ /**
16068
+ * Watch file for changes with fs_watchFile or fs_watch.
16069
+ * @param path to file or dir
16070
+ * @param listener on fs change
16071
+ * @returns closer for the watcher instance
16072
+ */
16073
+ _watchWithNodeFs(path15, listener) {
16074
+ const opts = this.fsw.options;
16075
+ const directory = sysPath.dirname(path15);
16076
+ const basename3 = sysPath.basename(path15);
16077
+ const parent = this.fsw._getWatchedDir(directory);
16078
+ parent.add(basename3);
16079
+ const absolutePath = sysPath.resolve(path15);
16080
+ const options = {
16081
+ persistent: opts.persistent
16082
+ };
16083
+ if (!listener)
16084
+ listener = EMPTY_FN;
16085
+ let closer;
16086
+ if (opts.usePolling) {
16087
+ const enableBin = opts.interval !== opts.binaryInterval;
16088
+ options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
16089
+ closer = setFsWatchFileListener(path15, absolutePath, options, {
16090
+ listener,
16091
+ rawEmitter: this.fsw._emitRaw
16092
+ });
16093
+ } else {
16094
+ closer = setFsWatchListener(path15, absolutePath, options, {
16095
+ listener,
16096
+ errHandler: this._boundHandleError,
16097
+ rawEmitter: this.fsw._emitRaw
16098
+ });
16099
+ }
16100
+ return closer;
16101
+ }
16102
+ /**
16103
+ * Watch a file and emit add event if warranted.
16104
+ * @returns closer for the watcher instance
16105
+ */
16106
+ _handleFile(file, stats, initialAdd) {
16107
+ if (this.fsw.closed) {
16108
+ return;
16109
+ }
16110
+ const dirname4 = sysPath.dirname(file);
16111
+ const basename3 = sysPath.basename(file);
16112
+ const parent = this.fsw._getWatchedDir(dirname4);
16113
+ let prevStats = stats;
16114
+ if (parent.has(basename3))
16115
+ return;
16116
+ const listener = async (path15, newStats) => {
16117
+ if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
16118
+ return;
16119
+ if (!newStats || newStats.mtimeMs === 0) {
16120
+ try {
16121
+ const newStats2 = await (0, import_promises4.stat)(file);
16122
+ if (this.fsw.closed)
16123
+ return;
16124
+ const at = newStats2.atimeMs;
16125
+ const mt = newStats2.mtimeMs;
16126
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
16127
+ this.fsw._emit(EV.CHANGE, file, newStats2);
16128
+ }
16129
+ if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
16130
+ this.fsw._closeFile(path15);
16131
+ prevStats = newStats2;
16132
+ const closer2 = this._watchWithNodeFs(file, listener);
16133
+ if (closer2)
16134
+ this.fsw._addPathCloser(path15, closer2);
16135
+ } else {
16136
+ prevStats = newStats2;
16137
+ }
16138
+ } catch (error) {
16139
+ this.fsw._remove(dirname4, basename3);
16140
+ }
16141
+ } else if (parent.has(basename3)) {
16142
+ const at = newStats.atimeMs;
16143
+ const mt = newStats.mtimeMs;
16144
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
16145
+ this.fsw._emit(EV.CHANGE, file, newStats);
16146
+ }
16147
+ prevStats = newStats;
16148
+ }
16149
+ };
16150
+ const closer = this._watchWithNodeFs(file, listener);
16151
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
16152
+ if (!this.fsw._throttle(EV.ADD, file, 0))
16153
+ return;
16154
+ this.fsw._emit(EV.ADD, file, stats);
16155
+ }
16156
+ return closer;
16157
+ }
16158
+ /**
16159
+ * Handle symlinks encountered while reading a dir.
16160
+ * @param entry returned by readdirp
16161
+ * @param directory path of dir being read
16162
+ * @param path of this item
16163
+ * @param item basename of this item
16164
+ * @returns true if no more processing is needed for this entry.
16165
+ */
16166
+ async _handleSymlink(entry, directory, path15, item) {
16167
+ if (this.fsw.closed) {
16168
+ return;
16169
+ }
16170
+ const full = entry.fullPath;
16171
+ const dir = this.fsw._getWatchedDir(directory);
16172
+ if (!this.fsw.options.followSymlinks) {
16173
+ this.fsw._incrReadyCount();
16174
+ let linkPath;
16175
+ try {
16176
+ linkPath = await (0, import_promises4.realpath)(path15);
16177
+ } catch (e) {
16178
+ this.fsw._emitReady();
16179
+ return true;
16180
+ }
16181
+ if (this.fsw.closed)
16182
+ return;
16183
+ if (dir.has(item)) {
16184
+ if (this.fsw._symlinkPaths.get(full) !== linkPath) {
16185
+ this.fsw._symlinkPaths.set(full, linkPath);
16186
+ this.fsw._emit(EV.CHANGE, path15, entry.stats);
16187
+ }
16188
+ } else {
16189
+ dir.add(item);
16190
+ this.fsw._symlinkPaths.set(full, linkPath);
16191
+ this.fsw._emit(EV.ADD, path15, entry.stats);
16192
+ }
16193
+ this.fsw._emitReady();
16194
+ return true;
16195
+ }
16196
+ if (this.fsw._symlinkPaths.has(full)) {
16197
+ return true;
16198
+ }
16199
+ this.fsw._symlinkPaths.set(full, true);
16200
+ }
16201
+ _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
16202
+ directory = sysPath.join(directory, "");
16203
+ throttler = this.fsw._throttle("readdir", directory, 1e3);
16204
+ if (!throttler)
16205
+ return;
16206
+ const previous = this.fsw._getWatchedDir(wh.path);
16207
+ const current = /* @__PURE__ */ new Set();
16208
+ let stream = this.fsw._readdirp(directory, {
16209
+ fileFilter: (entry) => wh.filterPath(entry),
16210
+ directoryFilter: (entry) => wh.filterDir(entry)
16211
+ });
16212
+ if (!stream)
16213
+ return;
16214
+ stream.on(STR_DATA, async (entry) => {
16215
+ if (this.fsw.closed) {
16216
+ stream = void 0;
16217
+ return;
16218
+ }
16219
+ const item = entry.path;
16220
+ let path15 = sysPath.join(directory, item);
16221
+ current.add(item);
16222
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path15, item)) {
16223
+ return;
16224
+ }
16225
+ if (this.fsw.closed) {
16226
+ stream = void 0;
16227
+ return;
16228
+ }
16229
+ if (item === target || !target && !previous.has(item)) {
16230
+ this.fsw._incrReadyCount();
16231
+ path15 = sysPath.join(dir, sysPath.relative(dir, path15));
16232
+ this._addToNodeFs(path15, initialAdd, wh, depth + 1);
16233
+ }
16234
+ }).on(EV.ERROR, this._boundHandleError);
16235
+ return new Promise((resolve4, reject) => {
16236
+ if (!stream)
16237
+ return reject();
16238
+ stream.once(STR_END, () => {
16239
+ if (this.fsw.closed) {
16240
+ stream = void 0;
16241
+ return;
16242
+ }
16243
+ const wasThrottled = throttler ? throttler.clear() : false;
16244
+ resolve4(void 0);
16245
+ previous.getChildren().filter((item) => {
16246
+ return item !== directory && !current.has(item);
16247
+ }).forEach((item) => {
16248
+ this.fsw._remove(directory, item);
16249
+ });
16250
+ stream = void 0;
16251
+ if (wasThrottled)
16252
+ this._handleRead(directory, false, wh, target, dir, depth, throttler);
16253
+ });
16254
+ });
16255
+ }
16256
+ /**
16257
+ * Read directory to add / remove files from `@watched` list and re-read it on change.
16258
+ * @param dir fs path
16259
+ * @param stats
16260
+ * @param initialAdd
16261
+ * @param depth relative to user-supplied path
16262
+ * @param target child path targeted for watch
16263
+ * @param wh Common watch helpers for this path
16264
+ * @param realpath
16265
+ * @returns closer for the watcher instance.
16266
+ */
16267
+ async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath2) {
16268
+ const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
16269
+ const tracked = parentDir.has(sysPath.basename(dir));
16270
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
16271
+ this.fsw._emit(EV.ADD_DIR, dir, stats);
16272
+ }
16273
+ parentDir.add(sysPath.basename(dir));
16274
+ this.fsw._getWatchedDir(dir);
16275
+ let throttler;
16276
+ let closer;
16277
+ const oDepth = this.fsw.options.depth;
16278
+ if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath2)) {
16279
+ if (!target) {
16280
+ await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
16281
+ if (this.fsw.closed)
16282
+ return;
16283
+ }
16284
+ closer = this._watchWithNodeFs(dir, (dirPath, stats2) => {
16285
+ if (stats2 && stats2.mtimeMs === 0)
16286
+ return;
16287
+ this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
16288
+ });
16289
+ }
16290
+ return closer;
16291
+ }
16292
+ /**
16293
+ * Handle added file, directory, or glob pattern.
16294
+ * Delegates call to _handleFile / _handleDir after checks.
16295
+ * @param path to file or ir
16296
+ * @param initialAdd was the file added at watch instantiation?
16297
+ * @param priorWh depth relative to user-supplied path
16298
+ * @param depth Child path actually targeted for watch
16299
+ * @param target Child path actually targeted for watch
16300
+ */
16301
+ async _addToNodeFs(path15, initialAdd, priorWh, depth, target) {
16302
+ const ready = this.fsw._emitReady;
16303
+ if (this.fsw._isIgnored(path15) || this.fsw.closed) {
16304
+ ready();
16305
+ return false;
16306
+ }
16307
+ const wh = this.fsw._getWatchHelpers(path15);
16308
+ if (priorWh) {
16309
+ wh.filterPath = (entry) => priorWh.filterPath(entry);
16310
+ wh.filterDir = (entry) => priorWh.filterDir(entry);
16311
+ }
16312
+ try {
16313
+ const stats = await statMethods[wh.statMethod](wh.watchPath);
16314
+ if (this.fsw.closed)
16315
+ return;
16316
+ if (this.fsw._isIgnored(wh.watchPath, stats)) {
16317
+ ready();
16318
+ return false;
16319
+ }
16320
+ const follow = this.fsw.options.followSymlinks;
16321
+ let closer;
16322
+ if (stats.isDirectory()) {
16323
+ const absPath = sysPath.resolve(path15);
16324
+ const targetPath = follow ? await (0, import_promises4.realpath)(path15) : path15;
16325
+ if (this.fsw.closed)
16326
+ return;
16327
+ closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
16328
+ if (this.fsw.closed)
16329
+ return;
16330
+ if (absPath !== targetPath && targetPath !== void 0) {
16331
+ this.fsw._symlinkPaths.set(absPath, targetPath);
16332
+ }
16333
+ } else if (stats.isSymbolicLink()) {
16334
+ const targetPath = follow ? await (0, import_promises4.realpath)(path15) : path15;
16335
+ if (this.fsw.closed)
16336
+ return;
16337
+ const parent = sysPath.dirname(wh.watchPath);
16338
+ this.fsw._getWatchedDir(parent).add(wh.watchPath);
16339
+ this.fsw._emit(EV.ADD, wh.watchPath, stats);
16340
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path15, wh, targetPath);
16341
+ if (this.fsw.closed)
16342
+ return;
16343
+ if (targetPath !== void 0) {
16344
+ this.fsw._symlinkPaths.set(sysPath.resolve(path15), targetPath);
16345
+ }
16346
+ } else {
16347
+ closer = this._handleFile(wh.watchPath, stats, initialAdd);
16348
+ }
16349
+ ready();
16350
+ if (closer)
16351
+ this.fsw._addPathCloser(path15, closer);
16352
+ return false;
16353
+ } catch (error) {
16354
+ if (this.fsw._handleError(error)) {
16355
+ ready();
16356
+ return path15;
16357
+ }
16358
+ }
16359
+ }
16360
+ };
16361
+
16362
+ // ../../node_modules/chokidar/esm/index.js
16363
+ var SLASH = "/";
16364
+ var SLASH_SLASH = "//";
16365
+ var ONE_DOT = ".";
16366
+ var TWO_DOTS = "..";
16367
+ var STRING_TYPE = "string";
16368
+ var BACK_SLASH_RE = /\\/g;
16369
+ var DOUBLE_SLASH_RE = /\/\//;
16370
+ var DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
16371
+ var REPLACER_RE = /^\.[/\\]/;
16372
+ function arrify(item) {
16373
+ return Array.isArray(item) ? item : [item];
16374
+ }
16375
+ var isMatcherObject = (matcher) => typeof matcher === "object" && matcher !== null && !(matcher instanceof RegExp);
16376
+ function createPattern(matcher) {
16377
+ if (typeof matcher === "function")
16378
+ return matcher;
16379
+ if (typeof matcher === "string")
16380
+ return (string) => matcher === string;
16381
+ if (matcher instanceof RegExp)
16382
+ return (string) => matcher.test(string);
16383
+ if (typeof matcher === "object" && matcher !== null) {
16384
+ return (string) => {
16385
+ if (matcher.path === string)
16386
+ return true;
16387
+ if (matcher.recursive) {
16388
+ const relative3 = sysPath2.relative(matcher.path, string);
16389
+ if (!relative3) {
16390
+ return false;
16391
+ }
16392
+ return !relative3.startsWith("..") && !sysPath2.isAbsolute(relative3);
16393
+ }
16394
+ return false;
16395
+ };
16396
+ }
16397
+ return () => false;
16398
+ }
16399
+ function normalizePath(path15) {
16400
+ if (typeof path15 !== "string")
16401
+ throw new Error("string expected");
16402
+ path15 = sysPath2.normalize(path15);
16403
+ path15 = path15.replace(/\\/g, "/");
16404
+ let prepend = false;
16405
+ if (path15.startsWith("//"))
16406
+ prepend = true;
16407
+ const DOUBLE_SLASH_RE2 = /\/\//;
16408
+ while (path15.match(DOUBLE_SLASH_RE2))
16409
+ path15 = path15.replace(DOUBLE_SLASH_RE2, "/");
16410
+ if (prepend)
16411
+ path15 = "/" + path15;
16412
+ return path15;
16413
+ }
16414
+ function matchPatterns(patterns, testString, stats) {
16415
+ const path15 = normalizePath(testString);
16416
+ for (let index = 0; index < patterns.length; index++) {
16417
+ const pattern = patterns[index];
16418
+ if (pattern(path15, stats)) {
16419
+ return true;
16420
+ }
16421
+ }
16422
+ return false;
16423
+ }
16424
+ function anymatch(matchers, testString) {
16425
+ if (matchers == null) {
16426
+ throw new TypeError("anymatch: specify first argument");
16427
+ }
16428
+ const matchersArray = arrify(matchers);
16429
+ const patterns = matchersArray.map((matcher) => createPattern(matcher));
16430
+ if (testString == null) {
16431
+ return (testString2, stats) => {
16432
+ return matchPatterns(patterns, testString2, stats);
16433
+ };
16434
+ }
16435
+ return matchPatterns(patterns, testString);
16436
+ }
16437
+ var unifyPaths = (paths_) => {
16438
+ const paths = arrify(paths_).flat();
16439
+ if (!paths.every((p) => typeof p === STRING_TYPE)) {
16440
+ throw new TypeError(`Non-string provided as watch path: ${paths}`);
16441
+ }
16442
+ return paths.map(normalizePathToUnix);
16443
+ };
16444
+ var toUnix = (string) => {
16445
+ let str = string.replace(BACK_SLASH_RE, SLASH);
16446
+ let prepend = false;
16447
+ if (str.startsWith(SLASH_SLASH)) {
16448
+ prepend = true;
16449
+ }
16450
+ while (str.match(DOUBLE_SLASH_RE)) {
16451
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
16452
+ }
16453
+ if (prepend) {
16454
+ str = SLASH + str;
16455
+ }
16456
+ return str;
16457
+ };
16458
+ var normalizePathToUnix = (path15) => toUnix(sysPath2.normalize(toUnix(path15)));
16459
+ var normalizeIgnored = (cwd = "") => (path15) => {
16460
+ if (typeof path15 === "string") {
16461
+ return normalizePathToUnix(sysPath2.isAbsolute(path15) ? path15 : sysPath2.join(cwd, path15));
16462
+ } else {
16463
+ return path15;
16464
+ }
16465
+ };
16466
+ var getAbsolutePath = (path15, cwd) => {
16467
+ if (sysPath2.isAbsolute(path15)) {
16468
+ return path15;
16469
+ }
16470
+ return sysPath2.join(cwd, path15);
16471
+ };
16472
+ var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
16473
+ var DirEntry = class {
16474
+ constructor(dir, removeWatcher) {
16475
+ this.path = dir;
16476
+ this._removeWatcher = removeWatcher;
16477
+ this.items = /* @__PURE__ */ new Set();
16478
+ }
16479
+ add(item) {
16480
+ const { items } = this;
16481
+ if (!items)
16482
+ return;
16483
+ if (item !== ONE_DOT && item !== TWO_DOTS)
16484
+ items.add(item);
16485
+ }
16486
+ async remove(item) {
16487
+ const { items } = this;
16488
+ if (!items)
16489
+ return;
16490
+ items.delete(item);
16491
+ if (items.size > 0)
16492
+ return;
16493
+ const dir = this.path;
16494
+ try {
16495
+ await (0, import_promises5.readdir)(dir);
16496
+ } catch (err) {
16497
+ if (this._removeWatcher) {
16498
+ this._removeWatcher(sysPath2.dirname(dir), sysPath2.basename(dir));
16499
+ }
16500
+ }
16501
+ }
16502
+ has(item) {
16503
+ const { items } = this;
16504
+ if (!items)
16505
+ return;
16506
+ return items.has(item);
16507
+ }
16508
+ getChildren() {
16509
+ const { items } = this;
16510
+ if (!items)
16511
+ return [];
16512
+ return [...items.values()];
16513
+ }
16514
+ dispose() {
16515
+ this.items.clear();
16516
+ this.path = "";
16517
+ this._removeWatcher = EMPTY_FN;
16518
+ this.items = EMPTY_SET;
16519
+ Object.freeze(this);
16520
+ }
16521
+ };
16522
+ var STAT_METHOD_F = "stat";
16523
+ var STAT_METHOD_L = "lstat";
16524
+ var WatchHelper = class {
16525
+ constructor(path15, follow, fsw) {
16526
+ this.fsw = fsw;
16527
+ const watchPath = path15;
16528
+ this.path = path15 = path15.replace(REPLACER_RE, "");
16529
+ this.watchPath = watchPath;
16530
+ this.fullWatchPath = sysPath2.resolve(watchPath);
16531
+ this.dirParts = [];
16532
+ this.dirParts.forEach((parts2) => {
16533
+ if (parts2.length > 1)
16534
+ parts2.pop();
16535
+ });
16536
+ this.followSymlinks = follow;
16537
+ this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
16538
+ }
16539
+ entryPath(entry) {
16540
+ return sysPath2.join(this.watchPath, sysPath2.relative(this.watchPath, entry.fullPath));
16541
+ }
16542
+ filterPath(entry) {
16543
+ const { stats } = entry;
16544
+ if (stats && stats.isSymbolicLink())
16545
+ return this.filterDir(entry);
16546
+ const resolvedPath = this.entryPath(entry);
16547
+ return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
16548
+ }
16549
+ filterDir(entry) {
16550
+ return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
16551
+ }
16552
+ };
16553
+ var FSWatcher = class extends import_events.EventEmitter {
16554
+ // Not indenting methods for history sake; for now.
16555
+ constructor(_opts = {}) {
16556
+ super();
16557
+ this.closed = false;
16558
+ this._closers = /* @__PURE__ */ new Map();
16559
+ this._ignoredPaths = /* @__PURE__ */ new Set();
16560
+ this._throttled = /* @__PURE__ */ new Map();
16561
+ this._streams = /* @__PURE__ */ new Set();
16562
+ this._symlinkPaths = /* @__PURE__ */ new Map();
16563
+ this._watched = /* @__PURE__ */ new Map();
16564
+ this._pendingWrites = /* @__PURE__ */ new Map();
16565
+ this._pendingUnlinks = /* @__PURE__ */ new Map();
16566
+ this._readyCount = 0;
16567
+ this._readyEmitted = false;
16568
+ const awf = _opts.awaitWriteFinish;
16569
+ const DEF_AWF = { stabilityThreshold: 2e3, pollInterval: 100 };
16570
+ const opts = {
16571
+ // Defaults
16572
+ persistent: true,
16573
+ ignoreInitial: false,
16574
+ ignorePermissionErrors: false,
16575
+ interval: 100,
16576
+ binaryInterval: 300,
16577
+ followSymlinks: true,
16578
+ usePolling: false,
16579
+ // useAsync: false,
16580
+ atomic: true,
16581
+ // NOTE: overwritten later (depends on usePolling)
16582
+ ..._opts,
16583
+ // Change format
16584
+ ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
16585
+ awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === "object" ? { ...DEF_AWF, ...awf } : false
16586
+ };
16587
+ if (isIBMi)
16588
+ opts.usePolling = true;
16589
+ if (opts.atomic === void 0)
16590
+ opts.atomic = !opts.usePolling;
16591
+ const envPoll = process.env.CHOKIDAR_USEPOLLING;
16592
+ if (envPoll !== void 0) {
16593
+ const envLower = envPoll.toLowerCase();
16594
+ if (envLower === "false" || envLower === "0")
16595
+ opts.usePolling = false;
16596
+ else if (envLower === "true" || envLower === "1")
16597
+ opts.usePolling = true;
16598
+ else
16599
+ opts.usePolling = !!envLower;
16600
+ }
16601
+ const envInterval = process.env.CHOKIDAR_INTERVAL;
16602
+ if (envInterval)
16603
+ opts.interval = Number.parseInt(envInterval, 10);
16604
+ let readyCalls = 0;
16605
+ this._emitReady = () => {
16606
+ readyCalls++;
16607
+ if (readyCalls >= this._readyCount) {
16608
+ this._emitReady = EMPTY_FN;
16609
+ this._readyEmitted = true;
16610
+ process.nextTick(() => this.emit(EVENTS.READY));
16611
+ }
16612
+ };
16613
+ this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args);
16614
+ this._boundRemove = this._remove.bind(this);
16615
+ this.options = opts;
16616
+ this._nodeFsHandler = new NodeFsHandler(this);
16617
+ Object.freeze(opts);
16618
+ }
16619
+ _addIgnoredPath(matcher) {
16620
+ if (isMatcherObject(matcher)) {
16621
+ for (const ignored of this._ignoredPaths) {
16622
+ if (isMatcherObject(ignored) && ignored.path === matcher.path && ignored.recursive === matcher.recursive) {
16623
+ return;
16624
+ }
16625
+ }
16626
+ }
16627
+ this._ignoredPaths.add(matcher);
16628
+ }
16629
+ _removeIgnoredPath(matcher) {
16630
+ this._ignoredPaths.delete(matcher);
16631
+ if (typeof matcher === "string") {
16632
+ for (const ignored of this._ignoredPaths) {
16633
+ if (isMatcherObject(ignored) && ignored.path === matcher) {
16634
+ this._ignoredPaths.delete(ignored);
16635
+ }
16636
+ }
16637
+ }
16638
+ }
16639
+ // Public methods
16640
+ /**
16641
+ * Adds paths to be watched on an existing FSWatcher instance.
16642
+ * @param paths_ file or file list. Other arguments are unused
16643
+ */
16644
+ add(paths_, _origAdd, _internal) {
16645
+ const { cwd } = this.options;
16646
+ this.closed = false;
16647
+ this._closePromise = void 0;
16648
+ let paths = unifyPaths(paths_);
16649
+ if (cwd) {
16650
+ paths = paths.map((path15) => {
16651
+ const absPath = getAbsolutePath(path15, cwd);
16652
+ return absPath;
16653
+ });
16654
+ }
16655
+ paths.forEach((path15) => {
16656
+ this._removeIgnoredPath(path15);
16657
+ });
16658
+ this._userIgnored = void 0;
16659
+ if (!this._readyCount)
16660
+ this._readyCount = 0;
16661
+ this._readyCount += paths.length;
16662
+ Promise.all(paths.map(async (path15) => {
16663
+ const res = await this._nodeFsHandler._addToNodeFs(path15, !_internal, void 0, 0, _origAdd);
16664
+ if (res)
16665
+ this._emitReady();
16666
+ return res;
16667
+ })).then((results) => {
16668
+ if (this.closed)
16669
+ return;
16670
+ results.forEach((item) => {
16671
+ if (item)
16672
+ this.add(sysPath2.dirname(item), sysPath2.basename(_origAdd || item));
16673
+ });
16674
+ });
16675
+ return this;
16676
+ }
16677
+ /**
16678
+ * Close watchers or start ignoring events from specified paths.
16679
+ */
16680
+ unwatch(paths_) {
16681
+ if (this.closed)
16682
+ return this;
16683
+ const paths = unifyPaths(paths_);
16684
+ const { cwd } = this.options;
16685
+ paths.forEach((path15) => {
16686
+ if (!sysPath2.isAbsolute(path15) && !this._closers.has(path15)) {
16687
+ if (cwd)
16688
+ path15 = sysPath2.join(cwd, path15);
16689
+ path15 = sysPath2.resolve(path15);
16690
+ }
16691
+ this._closePath(path15);
16692
+ this._addIgnoredPath(path15);
16693
+ if (this._watched.has(path15)) {
16694
+ this._addIgnoredPath({
16695
+ path: path15,
16696
+ recursive: true
16697
+ });
16698
+ }
16699
+ this._userIgnored = void 0;
16700
+ });
16701
+ return this;
16702
+ }
16703
+ /**
16704
+ * Close watchers and remove all listeners from watched paths.
16705
+ */
16706
+ close() {
16707
+ if (this._closePromise) {
16708
+ return this._closePromise;
16709
+ }
16710
+ this.closed = true;
16711
+ this.removeAllListeners();
16712
+ const closers = [];
16713
+ this._closers.forEach((closerList) => closerList.forEach((closer) => {
16714
+ const promise = closer();
16715
+ if (promise instanceof Promise)
16716
+ closers.push(promise);
16717
+ }));
16718
+ this._streams.forEach((stream) => stream.destroy());
16719
+ this._userIgnored = void 0;
16720
+ this._readyCount = 0;
16721
+ this._readyEmitted = false;
16722
+ this._watched.forEach((dirent) => dirent.dispose());
16723
+ this._closers.clear();
16724
+ this._watched.clear();
16725
+ this._streams.clear();
16726
+ this._symlinkPaths.clear();
16727
+ this._throttled.clear();
16728
+ this._closePromise = closers.length ? Promise.all(closers).then(() => void 0) : Promise.resolve();
16729
+ return this._closePromise;
16730
+ }
16731
+ /**
16732
+ * Expose list of watched paths
16733
+ * @returns for chaining
16734
+ */
16735
+ getWatched() {
16736
+ const watchList = {};
16737
+ this._watched.forEach((entry, dir) => {
16738
+ const key = this.options.cwd ? sysPath2.relative(this.options.cwd, dir) : dir;
16739
+ const index = key || ONE_DOT;
16740
+ watchList[index] = entry.getChildren().sort();
16741
+ });
16742
+ return watchList;
16743
+ }
16744
+ emitWithAll(event, args) {
16745
+ this.emit(event, ...args);
16746
+ if (event !== EVENTS.ERROR)
16747
+ this.emit(EVENTS.ALL, event, ...args);
16748
+ }
16749
+ // Common helpers
16750
+ // --------------
16751
+ /**
16752
+ * Normalize and emit events.
16753
+ * Calling _emit DOES NOT MEAN emit() would be called!
16754
+ * @param event Type of event
16755
+ * @param path File or directory path
16756
+ * @param stats arguments to be passed with event
16757
+ * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
16758
+ */
16759
+ async _emit(event, path15, stats) {
16760
+ if (this.closed)
16761
+ return;
16762
+ const opts = this.options;
16763
+ if (isWindows2)
16764
+ path15 = sysPath2.normalize(path15);
16765
+ if (opts.cwd)
16766
+ path15 = sysPath2.relative(opts.cwd, path15);
16767
+ const args = [path15];
16768
+ if (stats != null)
16769
+ args.push(stats);
16770
+ const awf = opts.awaitWriteFinish;
16771
+ let pw;
16772
+ if (awf && (pw = this._pendingWrites.get(path15))) {
16773
+ pw.lastChange = /* @__PURE__ */ new Date();
16774
+ return this;
16775
+ }
16776
+ if (opts.atomic) {
16777
+ if (event === EVENTS.UNLINK) {
16778
+ this._pendingUnlinks.set(path15, [event, ...args]);
16779
+ setTimeout(() => {
16780
+ this._pendingUnlinks.forEach((entry, path16) => {
16781
+ this.emit(...entry);
16782
+ this.emit(EVENTS.ALL, ...entry);
16783
+ this._pendingUnlinks.delete(path16);
16784
+ });
16785
+ }, typeof opts.atomic === "number" ? opts.atomic : 100);
16786
+ return this;
16787
+ }
16788
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path15)) {
16789
+ event = EVENTS.CHANGE;
16790
+ this._pendingUnlinks.delete(path15);
16791
+ }
16792
+ }
16793
+ if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
16794
+ const awfEmit = (err, stats2) => {
16795
+ if (err) {
16796
+ event = EVENTS.ERROR;
16797
+ args[0] = err;
16798
+ this.emitWithAll(event, args);
16799
+ } else if (stats2) {
16800
+ if (args.length > 1) {
16801
+ args[1] = stats2;
16802
+ } else {
16803
+ args.push(stats2);
16804
+ }
16805
+ this.emitWithAll(event, args);
16806
+ }
16807
+ };
16808
+ this._awaitWriteFinish(path15, awf.stabilityThreshold, event, awfEmit);
16809
+ return this;
16810
+ }
16811
+ if (event === EVENTS.CHANGE) {
16812
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path15, 50);
16813
+ if (isThrottled)
16814
+ return this;
16815
+ }
16816
+ if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
16817
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path15) : path15;
16818
+ let stats2;
16819
+ try {
16820
+ stats2 = await (0, import_promises5.stat)(fullPath);
16821
+ } catch (err) {
16822
+ }
16823
+ if (!stats2 || this.closed)
16824
+ return;
16825
+ args.push(stats2);
16826
+ }
16827
+ this.emitWithAll(event, args);
16828
+ return this;
16829
+ }
16830
+ /**
16831
+ * Common handler for errors
16832
+ * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
16833
+ */
16834
+ _handleError(error) {
16835
+ const code = error && error.code;
16836
+ if (error && code !== "ENOENT" && code !== "ENOTDIR" && (!this.options.ignorePermissionErrors || code !== "EPERM" && code !== "EACCES")) {
16837
+ this.emit(EVENTS.ERROR, error);
16838
+ }
16839
+ return error || this.closed;
16840
+ }
16841
+ /**
16842
+ * Helper utility for throttling
16843
+ * @param actionType type being throttled
16844
+ * @param path being acted upon
16845
+ * @param timeout duration of time to suppress duplicate actions
16846
+ * @returns tracking object or false if action should be suppressed
16847
+ */
16848
+ _throttle(actionType, path15, timeout) {
16849
+ if (!this._throttled.has(actionType)) {
16850
+ this._throttled.set(actionType, /* @__PURE__ */ new Map());
16851
+ }
16852
+ const action = this._throttled.get(actionType);
16853
+ if (!action)
16854
+ throw new Error("invalid throttle");
16855
+ const actionPath = action.get(path15);
16856
+ if (actionPath) {
16857
+ actionPath.count++;
16858
+ return false;
16859
+ }
16860
+ let timeoutObject;
16861
+ const clear = () => {
16862
+ const item = action.get(path15);
16863
+ const count = item ? item.count : 0;
16864
+ action.delete(path15);
16865
+ clearTimeout(timeoutObject);
16866
+ if (item)
16867
+ clearTimeout(item.timeoutObject);
16868
+ return count;
16869
+ };
16870
+ timeoutObject = setTimeout(clear, timeout);
16871
+ const thr = { timeoutObject, clear, count: 0 };
16872
+ action.set(path15, thr);
16873
+ return thr;
16874
+ }
16875
+ _incrReadyCount() {
16876
+ return this._readyCount++;
16877
+ }
16878
+ /**
16879
+ * Awaits write operation to finish.
16880
+ * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
16881
+ * @param path being acted upon
16882
+ * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
16883
+ * @param event
16884
+ * @param awfEmit Callback to be called when ready for event to be emitted.
16885
+ */
16886
+ _awaitWriteFinish(path15, threshold, event, awfEmit) {
16887
+ const awf = this.options.awaitWriteFinish;
16888
+ if (typeof awf !== "object")
16889
+ return;
16890
+ const pollInterval = awf.pollInterval;
16891
+ let timeoutHandler;
16892
+ let fullPath = path15;
16893
+ if (this.options.cwd && !sysPath2.isAbsolute(path15)) {
16894
+ fullPath = sysPath2.join(this.options.cwd, path15);
16895
+ }
16896
+ const now = /* @__PURE__ */ new Date();
16897
+ const writes = this._pendingWrites;
16898
+ function awaitWriteFinishFn(prevStat) {
16899
+ (0, import_fs8.stat)(fullPath, (err, curStat) => {
16900
+ if (err || !writes.has(path15)) {
16901
+ if (err && err.code !== "ENOENT")
16902
+ awfEmit(err);
16903
+ return;
16904
+ }
16905
+ const now2 = Number(/* @__PURE__ */ new Date());
16906
+ if (prevStat && curStat.size !== prevStat.size) {
16907
+ writes.get(path15).lastChange = now2;
16908
+ }
16909
+ const pw = writes.get(path15);
16910
+ const df = now2 - pw.lastChange;
16911
+ if (df >= threshold) {
16912
+ writes.delete(path15);
16913
+ awfEmit(void 0, curStat);
16914
+ } else {
16915
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
16916
+ }
16917
+ });
16918
+ }
16919
+ if (!writes.has(path15)) {
16920
+ writes.set(path15, {
16921
+ lastChange: now,
16922
+ cancelWait: () => {
16923
+ writes.delete(path15);
16924
+ clearTimeout(timeoutHandler);
16925
+ return event;
16926
+ }
16927
+ });
16928
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
16929
+ }
16930
+ }
16931
+ /**
16932
+ * Determines whether user has asked to ignore this path.
16933
+ */
16934
+ _isIgnored(path15, stats) {
16935
+ if (this.options.atomic && DOT_RE.test(path15))
16936
+ return true;
16937
+ if (!this._userIgnored) {
16938
+ const { cwd } = this.options;
16939
+ const ign = this.options.ignored;
16940
+ const ignored = (ign || []).map(normalizeIgnored(cwd));
16941
+ const ignoredPaths = [...this._ignoredPaths];
16942
+ const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
16943
+ this._userIgnored = anymatch(list, void 0);
16944
+ }
16945
+ return this._userIgnored(path15, stats);
16946
+ }
16947
+ _isntIgnored(path15, stat4) {
16948
+ return !this._isIgnored(path15, stat4);
16949
+ }
16950
+ /**
16951
+ * Provides a set of common helpers and properties relating to symlink handling.
16952
+ * @param path file or directory pattern being watched
16953
+ */
16954
+ _getWatchHelpers(path15) {
16955
+ return new WatchHelper(path15, this.options.followSymlinks, this);
16956
+ }
16957
+ // Directory helpers
16958
+ // -----------------
16959
+ /**
16960
+ * Provides directory tracking objects
16961
+ * @param directory path of the directory
16962
+ */
16963
+ _getWatchedDir(directory) {
16964
+ const dir = sysPath2.resolve(directory);
16965
+ if (!this._watched.has(dir))
16966
+ this._watched.set(dir, new DirEntry(dir, this._boundRemove));
16967
+ return this._watched.get(dir);
16968
+ }
16969
+ // File helpers
16970
+ // ------------
16971
+ /**
16972
+ * Check for read permissions: https://stackoverflow.com/a/11781404/1358405
16973
+ */
16974
+ _hasReadPermissions(stats) {
16975
+ if (this.options.ignorePermissionErrors)
16976
+ return true;
16977
+ return Boolean(Number(stats.mode) & 256);
16978
+ }
16979
+ /**
16980
+ * Handles emitting unlink events for
16981
+ * files and directories, and via recursion, for
16982
+ * files and directories within directories that are unlinked
16983
+ * @param directory within which the following item is located
16984
+ * @param item base path of item/directory
16985
+ */
16986
+ _remove(directory, item, isDirectory) {
16987
+ const path15 = sysPath2.join(directory, item);
16988
+ const fullPath = sysPath2.resolve(path15);
16989
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path15) || this._watched.has(fullPath);
16990
+ if (!this._throttle("remove", path15, 100))
16991
+ return;
16992
+ if (!isDirectory && this._watched.size === 1) {
16993
+ this.add(directory, item, true);
16994
+ }
16995
+ const wp = this._getWatchedDir(path15);
16996
+ const nestedDirectoryChildren = wp.getChildren();
16997
+ nestedDirectoryChildren.forEach((nested) => this._remove(path15, nested));
16998
+ const parent = this._getWatchedDir(directory);
16999
+ const wasTracked = parent.has(item);
17000
+ parent.remove(item);
17001
+ if (this._symlinkPaths.has(fullPath)) {
17002
+ this._symlinkPaths.delete(fullPath);
17003
+ }
17004
+ let relPath = path15;
17005
+ if (this.options.cwd)
17006
+ relPath = sysPath2.relative(this.options.cwd, path15);
17007
+ if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
17008
+ const event = this._pendingWrites.get(relPath).cancelWait();
17009
+ if (event === EVENTS.ADD)
17010
+ return;
17011
+ }
17012
+ this._watched.delete(path15);
17013
+ this._watched.delete(fullPath);
17014
+ const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
17015
+ if (wasTracked && !this._isIgnored(path15))
17016
+ this._emit(eventName, path15);
17017
+ this._closePath(path15);
17018
+ }
17019
+ /**
17020
+ * Closes all watchers for a path
17021
+ */
17022
+ _closePath(path15) {
17023
+ this._closeFile(path15);
17024
+ const dir = sysPath2.dirname(path15);
17025
+ this._getWatchedDir(dir).remove(sysPath2.basename(path15));
17026
+ }
17027
+ /**
17028
+ * Closes only file-specific watchers
17029
+ */
17030
+ _closeFile(path15) {
17031
+ const closers = this._closers.get(path15);
17032
+ if (!closers)
17033
+ return;
17034
+ closers.forEach((closer) => closer());
17035
+ this._closers.delete(path15);
17036
+ }
17037
+ _addPathCloser(path15, closer) {
17038
+ if (!closer)
17039
+ return;
17040
+ let list = this._closers.get(path15);
17041
+ if (!list) {
17042
+ list = [];
17043
+ this._closers.set(path15, list);
17044
+ }
17045
+ list.push(closer);
17046
+ }
17047
+ _readdirp(root, opts) {
17048
+ if (this.closed)
17049
+ return;
17050
+ const options = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
17051
+ let stream = readdirp(root, options);
17052
+ this._streams.add(stream);
17053
+ stream.once(STR_CLOSE, () => {
17054
+ stream = void 0;
17055
+ });
17056
+ stream.once(STR_END, () => {
17057
+ if (stream) {
17058
+ this._streams.delete(stream);
17059
+ stream = void 0;
17060
+ }
17061
+ });
17062
+ return stream;
17063
+ }
17064
+ };
17065
+ function watch(paths, options = {}) {
17066
+ const watcher = new FSWatcher(options);
17067
+ watcher.add(paths);
17068
+ return watcher;
17069
+ }
17070
+
17071
+ // ../../shared/all/helpers/terminal-ai/watcher.ts
17072
+ var PRUNED_DIRS = /* @__PURE__ */ new Set([
17073
+ ".git",
17074
+ "node_modules",
17075
+ ".next",
17076
+ ".turbo",
17077
+ ".expo",
17078
+ "dist",
17079
+ "build",
17080
+ "out",
17081
+ "coverage",
17082
+ ".cache",
17083
+ ".venv",
17084
+ "venv",
17085
+ "__pycache__",
17086
+ ".gradle",
17087
+ "Pods",
17088
+ "DerivedData"
17089
+ ]);
17090
+ function isNoiseFile(name) {
17091
+ return name === ".DS_Store" || name === "4913" || name.startsWith(".#") || name.startsWith("#") && name.endsWith("#");
17092
+ }
17093
+ var MAX_BATCH = 200;
17094
+ var FLUSH_MS = 120;
17095
+ var SELF_WRITE_MS = 2e3;
17096
+ var emptyPending = () => ({
17097
+ added: /* @__PURE__ */ new Set(),
17098
+ changed: /* @__PURE__ */ new Set(),
17099
+ removed: /* @__PURE__ */ new Set(),
17100
+ resync: false
17101
+ });
17102
+ var WorkspaceWatcher = class {
17103
+ /**
17104
+ * @param root Absolute path of the working tree. Every emitted path is
17105
+ * repo-relative and `/`-prefixed, matching `bareFsList`.
17106
+ * @param emit Called with a coalesced batch, never with an empty one.
17107
+ * @param exclude Absolute subtrees to skip on top of the name-based pruning.
17108
+ * A no-git card's root is the space dir itself, which also
17109
+ * holds the runner's own bookkeeping.
17110
+ */
17111
+ constructor(root, emit, exclude = []) {
17112
+ this.root = root;
17113
+ this.emit = emit;
17114
+ this.exclude = exclude;
17115
+ this.watcher = null;
17116
+ this.pending = emptyPending();
17117
+ this.flushTimer = null;
17118
+ /** path -> expiry. Events for these paths are ours (the editor just saved)
17119
+ * and must not come back as "changed on disk". */
17120
+ this.selfWrites = /* @__PURE__ */ new Map();
17121
+ this.closed = false;
17122
+ }
17123
+ start() {
17124
+ if (this.watcher || this.closed) return;
17125
+ const watcher = watch(this.root, {
17126
+ // `ignored` prunes: returning true for a directory stops the walk there,
17127
+ // so a pruned tree is never even enumerated.
17128
+ ignored: (absPath) => this.shouldIgnore(absPath),
17129
+ ignoreInitial: true,
17130
+ // A symlink to $HOME (or a sibling checkout) would pull the whole machine
17131
+ // into the watch set.
17132
+ followSymlinks: false,
17133
+ // Report a write only once it stops growing - otherwise a large file
17134
+ // fires while it's still half on disk and the editor reads a torn read.
17135
+ awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 30 },
17136
+ // Recognise the unlink+rename that editors use to save atomically as a
17137
+ // single change rather than a delete followed by a create.
17138
+ atomic: true,
17139
+ ignorePermissionErrors: true,
17140
+ cwd: this.root
17141
+ });
17142
+ this.watcher = watcher;
17143
+ watcher.on("add", (p) => this.record("added", p));
17144
+ watcher.on("addDir", (p) => this.record("added", p));
17145
+ watcher.on("change", (p) => this.record("changed", p));
17146
+ watcher.on("unlink", (p) => this.record("removed", p));
17147
+ watcher.on("unlinkDir", (p) => this.record("removed", p));
17148
+ watcher.on("error", () => {
17149
+ if (this.closed) return;
17150
+ void this.close();
17151
+ this.emit({
17152
+ added: [],
17153
+ changed: [],
17154
+ removed: [],
17155
+ resync: false,
17156
+ stopped: true
17157
+ });
17158
+ });
17159
+ }
17160
+ /**
17161
+ * Mark a path as about to be written by us. The event the write produces is
17162
+ * dropped, so the editor doesn't get told its own save was an outside edit.
17163
+ */
17164
+ expectWrite(repoPath) {
17165
+ this.selfWrites.set(repoPath, Date.now() + SELF_WRITE_MS);
17166
+ }
17167
+ async close() {
17168
+ this.closed = true;
17169
+ if (this.flushTimer) {
17170
+ clearTimeout(this.flushTimer);
17171
+ this.flushTimer = null;
17172
+ }
17173
+ this.pending = emptyPending();
17174
+ this.selfWrites.clear();
17175
+ const watcher = this.watcher;
17176
+ this.watcher = null;
17177
+ if (watcher) await watcher.close().catch(() => void 0);
17178
+ }
17179
+ /** chokidar tests absolute paths, always under the watch root. Matching is
17180
+ * done on the part BELOW the root, so a runner whose space dir happens to
17181
+ * sit under a `build/` or `dist/` of its own doesn't prune everything. */
17182
+ shouldIgnore(absPath) {
17183
+ if (absPath === this.root) return false;
17184
+ for (const excluded of this.exclude) {
17185
+ if (absPath === excluded || absPath.startsWith(excluded + "/")) {
17186
+ return true;
17187
+ }
17188
+ }
17189
+ const segments = absPath.slice(this.root.length + 1).split("/");
17190
+ for (const segment of segments) {
17191
+ if (PRUNED_DIRS.has(segment)) return true;
17192
+ }
17193
+ return isNoiseFile(segments[segments.length - 1] ?? "");
17194
+ }
17195
+ record(kind, relPath) {
17196
+ if (this.closed || !relPath) return;
17197
+ const path15 = "/" + relPath;
17198
+ const expiry = this.selfWrites.get(path15);
17199
+ if (expiry !== void 0) {
17200
+ if (expiry > Date.now()) return;
17201
+ this.selfWrites.delete(path15);
17202
+ }
17203
+ const { added, changed, removed } = this.pending;
17204
+ added.delete(path15);
17205
+ changed.delete(path15);
17206
+ removed.delete(path15);
17207
+ if (kind === "added") added.add(path15);
17208
+ else if (kind === "changed") changed.add(path15);
17209
+ else removed.add(path15);
17210
+ if (added.size + changed.size + removed.size > MAX_BATCH) {
17211
+ this.pending = { ...emptyPending(), resync: true };
17212
+ }
17213
+ this.scheduleFlush();
17214
+ }
17215
+ scheduleFlush() {
17216
+ if (this.flushTimer) return;
17217
+ this.flushTimer = setTimeout(() => {
17218
+ this.flushTimer = null;
17219
+ this.flush();
17220
+ }, FLUSH_MS);
17221
+ }
17222
+ flush() {
17223
+ if (this.closed) return;
17224
+ const { added, changed, removed, resync } = this.pending;
17225
+ this.pending = emptyPending();
17226
+ if (!resync && !added.size && !changed.size && !removed.size) return;
17227
+ const now = Date.now();
17228
+ for (const [path15, expiry] of this.selfWrites) {
17229
+ if (expiry <= now) this.selfWrites.delete(path15);
17230
+ }
17231
+ this.emit({
17232
+ added: resync ? [] : [...added],
17233
+ changed: resync ? [] : [...changed],
17234
+ removed: resync ? [] : [...removed],
17235
+ resync
17236
+ });
17237
+ }
17238
+ };
17239
+
15331
17240
  // ../../shared/all/helpers/terminal-ai/terminal-mode.ts
15332
17241
  function posixNormalize(p) {
15333
17242
  const parts2 = p.split("/").filter(Boolean);
@@ -15355,6 +17264,54 @@ var TerminalModeEngine = class {
15355
17264
  this.core = core;
15356
17265
  this.emitter = emitter;
15357
17266
  this.sessions = /* @__PURE__ */ new Map();
17267
+ /** One working-tree watcher per live bare session, keyed by postId. */
17268
+ this.watchers = /* @__PURE__ */ new Map();
17269
+ /** Worktree name each session claimed, keyed by postId. Covers the window
17270
+ * `claimWorkName`'s disk scan cannot: a name taken but not yet created. */
17271
+ this.reservedNames = /* @__PURE__ */ new Map();
17272
+ }
17273
+ // ── working-tree watching ──
17274
+ /** Start watching a session's tree. Idempotent: re-entering a session (the
17275
+ * modal reopening, a hydrate after restart) must not stack watchers. */
17276
+ startWatching(session) {
17277
+ const postId = session.postId;
17278
+ if (this.watchers.has(postId)) return;
17279
+ const paths = this.core.target().paths;
17280
+ const root = session.workspacePath || paths.root;
17281
+ if (!root) return;
17282
+ const exclude = session.workspacePath ? [] : [
17283
+ paths.state,
17284
+ paths.backups,
17285
+ paths.builds,
17286
+ paths.bin,
17287
+ paths.worktrees,
17288
+ paths.repo,
17289
+ `${paths.root}/drops`
17290
+ ];
17291
+ const watcher = new WorkspaceWatcher(
17292
+ root,
17293
+ (change) => {
17294
+ this.emitter.emitBareFsChange(postId, change);
17295
+ },
17296
+ exclude
17297
+ );
17298
+ this.watchers.set(postId, watcher);
17299
+ watcher.start();
17300
+ }
17301
+ /** Silent by design: a session that ends also emits session-update, and a
17302
+ * re-point stops then starts. The one `stopped` the client cares about is
17303
+ * the watcher failing under a live session, which the watcher emits itself. */
17304
+ stopWatching(postId) {
17305
+ const watcher = this.watchers.get(postId);
17306
+ if (!watcher) return;
17307
+ this.watchers.delete(postId);
17308
+ void watcher.close();
17309
+ }
17310
+ /** Suppress the change event our own write is about to produce, so a save
17311
+ * never comes back to the editor as an outside edit. Normalized to the form
17312
+ * the watcher emits, since callers spell the path either way. */
17313
+ expectWrite(postId, path15) {
17314
+ this.watchers.get(postId)?.expectWrite(posixNormalize(path15));
15358
17315
  }
15359
17316
  // ── Lifecycle / ModeEngine ──
15360
17317
  start(base, args) {
@@ -15398,6 +17355,8 @@ var TerminalModeEngine = class {
15398
17355
  return !!s && (s.phase === "starting" || s.phase === "bare-active");
15399
17356
  }
15400
17357
  remove(postId) {
17358
+ this.stopWatching(postId);
17359
+ this.reservedNames.delete(postId);
15401
17360
  this.sessions.delete(postId);
15402
17361
  }
15403
17362
  async kill(postId) {
@@ -15411,12 +17370,17 @@ var TerminalModeEngine = class {
15411
17370
  }
15412
17371
  }
15413
17372
  if (!session) return;
17373
+ this.stopWatching(session.postId);
15414
17374
  await this.teardown(session);
15415
17375
  const removedPostId = session.postId;
17376
+ this.reservedNames.delete(removedPostId);
15416
17377
  this.sessions.delete(removedPostId);
15417
17378
  this.emitter.emitSessionRemoved(removedPostId);
15418
17379
  }
15419
17380
  destroy() {
17381
+ for (const watcher of this.watchers.values()) void watcher.close();
17382
+ this.watchers.clear();
17383
+ this.reservedNames.clear();
15420
17384
  this.sessions.clear();
15421
17385
  }
15422
17386
  teardown(session) {
@@ -15461,6 +17425,7 @@ var TerminalModeEngine = class {
15461
17425
  exposed: []
15462
17426
  };
15463
17427
  this.sessions.set(r.postId, session);
17428
+ this.startWatching(session);
15464
17429
  this.emitter.emitSessionUpdate(session);
15465
17430
  }
15466
17431
  }
@@ -15503,6 +17468,8 @@ var TerminalModeEngine = class {
15503
17468
  exposed: []
15504
17469
  };
15505
17470
  this.sessions.set(args.postId, session);
17471
+ this.stopWatching(args.postId);
17472
+ this.startWatching(session);
15506
17473
  this.emitter.emitSessionUpdate(session);
15507
17474
  }
15508
17475
  // ── workspace + Claude CLI, user drives ──
@@ -15512,11 +17479,13 @@ var TerminalModeEngine = class {
15512
17479
  await this.core.ensureSpaceWorkspace();
15513
17480
  if (config.repoUrl && config.githubToken) {
15514
17481
  const branch = baseBranch || config.mainBranch || "main";
15515
- const { path: path15 } = await addWorktree(
17482
+ const workName = isCardPostId(session.postId) ? session.taskId : await claimWorkName(
15516
17483
  this.core.target(),
15517
- session.taskId,
15518
- branch
17484
+ session.taskTitle,
17485
+ this.reservedNames.values()
15519
17486
  );
17487
+ this.reservedNames.set(session.postId, workName);
17488
+ const { path: path15 } = await addWorktree(this.core.target(), workName, branch);
15520
17489
  session.workspacePath = path15;
15521
17490
  await setGitIdentity(
15522
17491
  this.core.target(),
@@ -15546,6 +17515,7 @@ var TerminalModeEngine = class {
15546
17515
  }
15547
17516
  }
15548
17517
  session.phase = "bare-active";
17518
+ this.startWatching(session);
15549
17519
  this.emitter.emitSessionUpdate(session);
15550
17520
  this.emitter.addLog(
15551
17521
  session,
@@ -15653,12 +17623,41 @@ var TerminalModeEngine = class {
15653
17623
  if (!/^[A-Za-z0-9+/=\n\r]*$/.test(b64)) {
15654
17624
  throw new Error("Invalid base64 payload.");
15655
17625
  }
17626
+ this.expectWrite(String(postId), path15);
15656
17627
  await target.sh(
15657
17628
  `mkdir -p ${shEscape(posixDirname(abs))} && printf %s ${shEscape(b64)} | base64 -d > ${shEscape(abs)}`
15658
17629
  );
15659
17630
  const session = this.sessions.get(String(postId));
15660
17631
  if (session) delete session.buffers[path15];
15661
17632
  }
17633
+ /** Write a dropped image to the per-space drops dir (`paths.root`, OUTSIDE the
17634
+ * card worktree so it never touches the repo) and return its absolute path. */
17635
+ async terminalDropImage({
17636
+ postId,
17637
+ content,
17638
+ ext
17639
+ }) {
17640
+ const target = this.getBareTarget(postId);
17641
+ if (!/^[A-Za-z0-9+/=\n\r]*$/.test(content)) {
17642
+ throw new Error("Invalid base64 payload.");
17643
+ }
17644
+ if (content.length > 14e6) {
17645
+ throw new Error("Image too large (max ~10MB).");
17646
+ }
17647
+ const safeExt = (ext || "png").toLowerCase().replace(/[^a-z0-9]/g, "") || "png";
17648
+ const dropsDir = `${target.paths.root}/drops`;
17649
+ const abs = `${dropsDir}/${(0, import_crypto4.randomUUID)()}.${safeExt}`;
17650
+ await target.sh(
17651
+ `mkdir -p ${shEscape(dropsDir)} && printf %s ${shEscape(content)} | base64 -d > ${shEscape(abs)}`
17652
+ );
17653
+ try {
17654
+ await target.sh(
17655
+ `find ${shEscape(dropsDir)} -type f -mtime +1 -delete 2>/dev/null || true`
17656
+ );
17657
+ } catch {
17658
+ }
17659
+ return abs;
17660
+ }
15662
17661
  bareEditorState({
15663
17662
  postId: rawPostId
15664
17663
  }) {
@@ -15876,11 +17875,6 @@ var TerminalModeEngine = class {
15876
17875
  }
15877
17876
  };
15878
17877
 
15879
- // ../../shared/all/helpers/board-agent-core/boardTerminal.ts
15880
- function boardTerminalKey(spaceSlug) {
15881
- return `board-${spaceSlug}`;
15882
- }
15883
-
15884
17878
  // ../../shared/all/helpers/board-agent-core/ansi.ts
15885
17879
  var CSI = String.raw`\x1b\[[0-?]*[ -/]*[@-~]`;
15886
17880
  var OSC = String.raw`\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)`;
@@ -15957,8 +17951,8 @@ var ClaudeLoginFlow = class {
15957
17951
  if (this.active) throw new Error("A Claude sign-in is already running.");
15958
17952
  this.reset();
15959
17953
  this.inFlight = true;
15960
- const urlPromise = new Promise((resolve2, reject) => {
15961
- this.urlResolver = resolve2;
17954
+ const urlPromise = new Promise((resolve4, reject) => {
17955
+ this.urlResolver = resolve4;
15962
17956
  this.urlRejecter = reject;
15963
17957
  });
15964
17958
  urlPromise.catch(() => {
@@ -16019,10 +18013,10 @@ var ClaudeLoginFlow = class {
16019
18013
  /https:\/\/[^\s\x00-\x1f]*oauth[^\s\x00-\x1f]*/
16020
18014
  )?.[0];
16021
18015
  if (url2) {
16022
- const resolve2 = this.urlResolver;
18016
+ const resolve4 = this.urlResolver;
16023
18017
  this.urlResolver = null;
16024
18018
  this.urlRejecter = null;
16025
- resolve2(url2.replace(/[.,;)\]]+$/, ""));
18019
+ resolve4(url2.replace(/[.,;)\]]+$/, ""));
16026
18020
  }
16027
18021
  }
16028
18022
  if (this.submitMark < 0 || this.settled) return;
@@ -16118,8 +18112,8 @@ var CodexLoginFlow = class {
16118
18112
  this.reset();
16119
18113
  this.inFlight = true;
16120
18114
  const startPromise = new Promise(
16121
- (resolve2, reject) => {
16122
- this.startResolver = resolve2;
18115
+ (resolve4, reject) => {
18116
+ this.startResolver = resolve4;
16123
18117
  this.startRejecter = reject;
16124
18118
  }
16125
18119
  );
@@ -16165,10 +18159,10 @@ var CodexLoginFlow = class {
16165
18159
  const url2 = this.output.match(/https:\/\/[^\s\x00-\x1f]+/)?.[0];
16166
18160
  const code = this.output.match(CODE_LINE_RE)?.[1] ?? this.output.match(CODE_TOKEN_RE)?.[1];
16167
18161
  if (url2 && code) {
16168
- const resolve2 = this.startResolver;
18162
+ const resolve4 = this.startResolver;
16169
18163
  this.startResolver = null;
16170
18164
  this.startRejecter = null;
16171
- resolve2({ url: url2.replace(/[.,;)\]]+$/, ""), code });
18165
+ resolve4({ url: url2.replace(/[.,;)\]]+$/, ""), code });
16172
18166
  }
16173
18167
  return;
16174
18168
  }
@@ -16347,7 +18341,7 @@ async function listGithubBranches(token, fullName) {
16347
18341
 
16348
18342
  // ../../shared/all/helpers/board-agent-core/host-deploy.ts
16349
18343
  var import_child_process5 = require("child_process");
16350
- var import_promises3 = __toESM(require("fs/promises"));
18344
+ var import_promises6 = __toESM(require("fs/promises"));
16351
18345
  var import_path9 = __toESM(require("path"));
16352
18346
  var import_util5 = require("util");
16353
18347
  var execFileAsync2 = (0, import_util5.promisify)(import_child_process5.execFile);
@@ -16360,12 +18354,12 @@ var CLAUDE_LINK = `${CLAUDE_SKILLS_DIR}/deploy`;
16360
18354
  async function ensureClaudeSkillLink(workspace) {
16361
18355
  const linkPath = import_path9.default.join(workspace, CLAUDE_LINK);
16362
18356
  try {
16363
- await import_promises3.default.lstat(linkPath);
18357
+ await import_promises6.default.lstat(linkPath);
16364
18358
  return;
16365
18359
  } catch {
16366
18360
  }
16367
- await import_promises3.default.mkdir(import_path9.default.join(workspace, CLAUDE_SKILLS_DIR), { recursive: true });
16368
- await import_promises3.default.symlink("../../.agents/skills/deploy", linkPath, "dir");
18361
+ await import_promises6.default.mkdir(import_path9.default.join(workspace, CLAUDE_SKILLS_DIR), { recursive: true });
18362
+ await import_promises6.default.symlink("../../.agents/skills/deploy", linkPath, "dir");
16369
18363
  }
16370
18364
  var GIT_NO_HELPER = ["-c", "credential.helper="];
16371
18365
  var GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
@@ -16474,15 +18468,15 @@ function spaceEnv(spaceDir) {
16474
18468
  };
16475
18469
  }
16476
18470
  async function readContract(workspace) {
16477
- const skill = await import_promises3.default.readFile(import_path9.default.join(workspace, SKILL_PATH), "utf-8").catch(() => {
18471
+ const skill = await import_promises6.default.readFile(import_path9.default.join(workspace, SKILL_PATH), "utf-8").catch(() => {
16478
18472
  throw new Error("The creator wrote no SKILL.md.");
16479
18473
  });
16480
- const checker = await import_promises3.default.readFile(import_path9.default.join(workspace, CHECKER_PATH), "utf-8").catch(() => {
18474
+ const checker = await import_promises6.default.readFile(import_path9.default.join(workspace, CHECKER_PATH), "utf-8").catch(() => {
16481
18475
  throw new Error("The creator wrote no check-environment.sh.");
16482
18476
  });
16483
18477
  try {
16484
18478
  const raw = JSON.parse(
16485
- await import_promises3.default.readFile(import_path9.default.join(workspace, VARIABLES_PATH), "utf-8")
18479
+ await import_promises6.default.readFile(import_path9.default.join(workspace, VARIABLES_PATH), "utf-8")
16486
18480
  );
16487
18481
  return {
16488
18482
  skill,
@@ -16635,7 +18629,7 @@ async function runEnvironmentCheck(opts) {
16635
18629
  `origin/${status.branch}:${CHECKER_PATH}`
16636
18630
  );
16637
18631
  const tmp = import_path9.default.join(opts.spaceDir, `.env-check.${process.pid}.sh`);
16638
- await import_promises3.default.writeFile(tmp, script, { mode: 448 });
18632
+ await import_promises6.default.writeFile(tmp, script, { mode: 448 });
16639
18633
  let ok = true;
16640
18634
  let output = "";
16641
18635
  try {
@@ -16648,7 +18642,7 @@ async function runEnvironmentCheck(opts) {
16648
18642
  output = res.output;
16649
18643
  if (res.code !== 0) ok = false;
16650
18644
  } finally {
16651
- await import_promises3.default.rm(tmp, { force: true });
18645
+ await import_promises6.default.rm(tmp, { force: true });
16652
18646
  }
16653
18647
  const checks = [];
16654
18648
  for (const line of output.split("\n")) {
@@ -16717,8 +18711,8 @@ var import_path11 = __toESM(require("path"));
16717
18711
 
16718
18712
  // ../../shared/all/helpers/board-agent-core/host-secrets.ts
16719
18713
  var import_child_process6 = require("child_process");
16720
- var import_crypto4 = __toESM(require("crypto"));
16721
- var import_promises4 = __toESM(require("fs/promises"));
18714
+ var import_crypto5 = __toESM(require("crypto"));
18715
+ var import_promises7 = __toESM(require("fs/promises"));
16722
18716
  var import_path10 = __toESM(require("path"));
16723
18717
  var import_util6 = require("util");
16724
18718
  var execFileAsync3 = (0, import_util6.promisify)(import_child_process6.execFile);
@@ -16745,14 +18739,14 @@ async function assertBinaries() {
16745
18739
  }
16746
18740
  }
16747
18741
  function deriveKey(password, salt) {
16748
- return import_crypto4.default.scryptSync(password, salt, 32, {
18742
+ return import_crypto5.default.scryptSync(password, salt, 32, {
16749
18743
  N: SCRYPT_N2,
16750
18744
  maxmem: 64 * 1024 * 1024
16751
18745
  });
16752
18746
  }
16753
18747
  async function secretsInitialized(configDir) {
16754
18748
  try {
16755
- await import_promises4.default.access(import_path10.default.join(configDir, IDENTITY_FILE));
18749
+ await import_promises7.default.access(import_path10.default.join(configDir, IDENTITY_FILE));
16756
18750
  return true;
16757
18751
  } catch {
16758
18752
  return false;
@@ -16774,9 +18768,9 @@ async function initSecrets(configDir, password) {
16774
18768
  if (!identity || !recipient) {
16775
18769
  throw new Error("age-keygen returned no usable keypair.");
16776
18770
  }
16777
- const salt = import_crypto4.default.randomBytes(16);
16778
- const iv = import_crypto4.default.randomBytes(12);
16779
- const cipher = import_crypto4.default.createCipheriv(
18771
+ const salt = import_crypto5.default.randomBytes(16);
18772
+ const iv = import_crypto5.default.randomBytes(12);
18773
+ const cipher = import_crypto5.default.createCipheriv(
16780
18774
  "aes-256-gcm",
16781
18775
  deriveKey(password, salt),
16782
18776
  iv
@@ -16791,17 +18785,17 @@ async function initSecrets(configDir, password) {
16791
18785
  tag: cipher.getAuthTag().toString("base64"),
16792
18786
  data: data.toString("base64")
16793
18787
  };
16794
- await import_promises4.default.writeFile(import_path10.default.join(configDir, IDENTITY_FILE), JSON.stringify(box), {
18788
+ await import_promises7.default.writeFile(import_path10.default.join(configDir, IDENTITY_FILE), JSON.stringify(box), {
16795
18789
  mode: 384
16796
18790
  });
16797
- await import_promises4.default.writeFile(import_path10.default.join(configDir, RECIPIENT_FILE), `${recipient}
18791
+ await import_promises7.default.writeFile(import_path10.default.join(configDir, RECIPIENT_FILE), `${recipient}
16798
18792
  `, {
16799
18793
  mode: 384
16800
18794
  });
16801
18795
  return { success: true };
16802
18796
  }
16803
18797
  function decryptIdentity(box, password) {
16804
- const decipher = import_crypto4.default.createDecipheriv(
18798
+ const decipher = import_crypto5.default.createDecipheriv(
16805
18799
  "aes-256-gcm",
16806
18800
  deriveKey(password, Buffer.from(box.salt, "base64")),
16807
18801
  Buffer.from(box.iv, "base64")
@@ -16821,13 +18815,13 @@ function envPath(spaceDir) {
16821
18815
  }
16822
18816
  async function identityFor(configDir, password) {
16823
18817
  const box = JSON.parse(
16824
- await import_promises4.default.readFile(import_path10.default.join(configDir, IDENTITY_FILE), "utf-8")
18818
+ await import_promises7.default.readFile(import_path10.default.join(configDir, IDENTITY_FILE), "utf-8")
16825
18819
  );
16826
18820
  return decryptIdentity(box, password);
16827
18821
  }
16828
18822
  async function readEnv(spaceDir, identity) {
16829
18823
  try {
16830
- await import_promises4.default.access(envPath(spaceDir));
18824
+ await import_promises7.default.access(envPath(spaceDir));
16831
18825
  } catch {
16832
18826
  return {};
16833
18827
  }
@@ -16856,14 +18850,14 @@ async function readEnv(spaceDir, identity) {
16856
18850
  return values;
16857
18851
  }
16858
18852
  async function writeEnv(configDir, spaceDir, identity, values) {
16859
- const recipient = (await import_promises4.default.readFile(import_path10.default.join(configDir, RECIPIENT_FILE), "utf-8")).trim();
18853
+ const recipient = (await import_promises7.default.readFile(import_path10.default.join(configDir, RECIPIENT_FILE), "utf-8")).trim();
16860
18854
  const plain = `${Object.entries(values).map(([k, v]) => `${k}=${v}`).join("\n")}
16861
18855
  `;
16862
18856
  const tmp = envPath(spaceDir).replace(
16863
18857
  /\.enc\.env$/,
16864
18858
  `.${process.pid}.tmp.env`
16865
18859
  );
16866
- await import_promises4.default.writeFile(tmp, plain, { mode: 384 });
18860
+ await import_promises7.default.writeFile(tmp, plain, { mode: 384 });
16867
18861
  try {
16868
18862
  const { stdout } = await execFileAsync3(
16869
18863
  "sops",
@@ -16882,9 +18876,9 @@ async function writeEnv(configDir, spaceDir, identity, values) {
16882
18876
  maxBuffer: 4 * 1024 * 1024
16883
18877
  }
16884
18878
  );
16885
- await import_promises4.default.writeFile(envPath(spaceDir), stdout, { mode: 384 });
18879
+ await import_promises7.default.writeFile(envPath(spaceDir), stdout, { mode: 384 });
16886
18880
  } finally {
16887
- await import_promises4.default.rm(tmp, { force: true });
18881
+ await import_promises7.default.rm(tmp, { force: true });
16888
18882
  }
16889
18883
  }
16890
18884
  async function listSecretKeys(configDir, spaceDir, password) {
@@ -17619,6 +19613,12 @@ var SpaceCore = class {
17619
19613
  await this.ensureSpaceWorkspace();
17620
19614
  return { ready: true };
17621
19615
  }
19616
+ async bareWorkNames() {
19617
+ const config = this.configProvider.readConfig(this.spaceSlug);
19618
+ if (!config.githubToken || !config.repoUrl) return [];
19619
+ await this.ensureSpaceWorkspace();
19620
+ return listWorkNames(this.target());
19621
+ }
17622
19622
  async cardRemoteBranches() {
17623
19623
  const config = this.configProvider.readConfig(this.spaceSlug);
17624
19624
  if (!config.githubToken || !config.repoUrl) return [];
@@ -17737,6 +19737,9 @@ var BoardAgentEngine = class _BoardAgentEngine {
17737
19737
  cardRemoteBranches() {
17738
19738
  return this.core.cardRemoteBranches();
17739
19739
  }
19740
+ bareWorkNames() {
19741
+ return this.core.bareWorkNames();
19742
+ }
17740
19743
  // Deploy button entry: is the repo's deploy contract (SKILL.md +
17741
19744
  // required-variables.json) on the default branch? See .specs/deploy.md.
17742
19745
  async deployStatus() {
@@ -17806,18 +19809,18 @@ var BoardAgentEngine = class _BoardAgentEngine {
17806
19809
  * setup-status channel. A second request cancels the pending one. */
17807
19810
  askSudo(reason) {
17808
19811
  this.sudoResolver?.(null);
17809
- return new Promise((resolve2) => {
17810
- this.sudoResolver = resolve2;
19812
+ return new Promise((resolve4) => {
19813
+ this.sudoResolver = resolve4;
17811
19814
  this.emitter.emitSetupStatus(`${SETUP_AUTH_PREFIX}${reason}`);
17812
19815
  });
17813
19816
  }
17814
19817
  /** Answer a pending sudo request. An empty password denies it, so setup
17815
19818
  * fails with a message rather than hanging. */
17816
19819
  setupAuthorize(p) {
17817
- const resolve2 = this.sudoResolver;
17818
- if (!resolve2) return { success: false };
19820
+ const resolve4 = this.sudoResolver;
19821
+ if (!resolve4) return { success: false };
17819
19822
  this.sudoResolver = null;
17820
- resolve2(p.password || null);
19823
+ resolve4(p.password || null);
17821
19824
  return { success: true };
17822
19825
  }
17823
19826
  deployRunState() {
@@ -17871,12 +19874,12 @@ var BoardAgentEngine = class _BoardAgentEngine {
17871
19874
  hooks: {
17872
19875
  sendLog: bufferLog,
17873
19876
  onTodos: (todos) => this.setRun({ todos }),
17874
- requestHuman: (question) => new Promise((resolve2) => {
17875
- this.runResolvers.human = resolve2;
19877
+ requestHuman: (question) => new Promise((resolve4) => {
19878
+ this.runResolvers.human = resolve4;
17876
19879
  this.setRun({ phase: "awaiting-input", question });
17877
19880
  }),
17878
- requestAuth: (command, errorNote) => new Promise((resolve2) => {
17879
- this.runResolvers.auth = resolve2;
19881
+ requestAuth: (command, errorNote) => new Promise((resolve4) => {
19882
+ this.runResolvers.auth = resolve4;
17880
19883
  this.setRun({
17881
19884
  phase: "awaiting-auth",
17882
19885
  pendingCommand: command,
@@ -17909,35 +19912,35 @@ var BoardAgentEngine = class _BoardAgentEngine {
17909
19912
  return { started: true };
17910
19913
  }
17911
19914
  deployRunAnswer(payload) {
17912
- const resolve2 = this.runResolvers.human;
17913
- if (!resolve2 || this.runState.phase !== "awaiting-input") {
19915
+ const resolve4 = this.runResolvers.human;
19916
+ if (!resolve4 || this.runState.phase !== "awaiting-input") {
17914
19917
  throw new Error("No step is awaiting input.");
17915
19918
  }
17916
19919
  this.runResolvers.human = void 0;
17917
19920
  this.setRun({ phase: "running", question: "", error: "" });
17918
- resolve2(payload.answer);
19921
+ resolve4(payload.answer);
17919
19922
  return { success: true };
17920
19923
  }
17921
19924
  // The password arrives RUNNER-DIRECT here and only feeds decryption; it
17922
19925
  // never enters the agent session (see .specs/deploy.md).
17923
19926
  deployRunAuthorize(payload) {
17924
- const resolve2 = this.runResolvers.auth;
17925
- if (!resolve2 || this.runState.phase !== "awaiting-auth") {
19927
+ const resolve4 = this.runResolvers.auth;
19928
+ if (!resolve4 || this.runState.phase !== "awaiting-auth") {
17926
19929
  throw new Error("No command is awaiting authorization.");
17927
19930
  }
17928
19931
  this.runResolvers.auth = void 0;
17929
19932
  this.setRun({ phase: "running", pendingCommand: "", error: "" });
17930
- resolve2({ password: payload.password });
19933
+ resolve4({ password: payload.password });
17931
19934
  return { success: true };
17932
19935
  }
17933
19936
  deployRunDeny() {
17934
- const resolve2 = this.runResolvers.auth;
17935
- if (!resolve2 || this.runState.phase !== "awaiting-auth") {
19937
+ const resolve4 = this.runResolvers.auth;
19938
+ if (!resolve4 || this.runState.phase !== "awaiting-auth") {
17936
19939
  throw new Error("No command is awaiting authorization.");
17937
19940
  }
17938
19941
  this.runResolvers.auth = void 0;
17939
19942
  this.setRun({ phase: "running", pendingCommand: "" });
17940
- resolve2({ denied: true });
19943
+ resolve4({ denied: true });
17941
19944
  return { success: true };
17942
19945
  }
17943
19946
  deployRunCancel() {
@@ -18392,6 +20395,9 @@ var BoardAgentEngine = class _BoardAgentEngine {
18392
20395
  bareFsWrite(p) {
18393
20396
  return this.terminal.bareFsWrite(p);
18394
20397
  }
20398
+ terminalDropImage(p) {
20399
+ return this.terminal.terminalDropImage(p);
20400
+ }
18395
20401
  bareFsDelete(p) {
18396
20402
  return this.terminal.bareFsDelete(p);
18397
20403
  }
@@ -18822,6 +20828,8 @@ ${c.content.trim() || "(no description)"}`
18822
20828
  return await this.ensureSetup();
18823
20829
  case "cardRemoteBranches":
18824
20830
  return await this.cardRemoteBranches();
20831
+ case "bareWorkNames":
20832
+ return await this.bareWorkNames();
18825
20833
  case "deployStatus":
18826
20834
  return await this.deployStatus();
18827
20835
  case "deployCreateSkill":
@@ -18965,6 +20973,10 @@ ${c.content.trim() || "(no description)"}`
18965
20973
  payload
18966
20974
  );
18967
20975
  return void 0;
20976
+ case "terminalDropImage":
20977
+ return await this.terminalDropImage(
20978
+ payload
20979
+ );
18968
20980
  case "bareFsDelete":
18969
20981
  await this.bareFsDelete(
18970
20982
  payload
@@ -19029,9 +21041,9 @@ ${c.content.trim() || "(no description)"}`
19029
21041
 
19030
21042
  // ../../shared/all/helpers/board-agent-core/index-service.ts
19031
21043
  var import_child_process7 = require("child_process");
19032
- var import_crypto5 = require("crypto");
19033
- var import_fs7 = require("fs");
19034
- var import_promises5 = __toESM(require("fs/promises"));
21044
+ var import_crypto6 = require("crypto");
21045
+ var import_fs9 = require("fs");
21046
+ var import_promises8 = __toESM(require("fs/promises"));
19035
21047
  var import_net2 = require("net");
19036
21048
  var import_path13 = require("path");
19037
21049
  var import_util7 = require("util");
@@ -19047,7 +21059,7 @@ var IndexService = class {
19047
21059
  /** Per-space bearer for MCP + file, derived from the control token (the
19048
21060
  * service computes the same). */
19049
21061
  bearerToken(spaceSlug) {
19050
- return (0, import_crypto5.createHmac)("sha256", this.opts.controlToken).update(`mcp:${spaceSlug}`).digest("hex");
21062
+ return (0, import_crypto6.createHmac)("sha256", this.opts.controlToken).update(`mcp:${spaceSlug}`).digest("hex");
19051
21063
  }
19052
21064
  /** MCP bridge for a space. Null until the service is up (which it kicks
19053
21065
  * off), so a bad :0 URL is never baked in; provisionMcpLane re-runs. */
@@ -19120,8 +21132,8 @@ var IndexService = class {
19120
21132
  * opened (a missing log must never stop the service from starting). */
19121
21133
  async openLog() {
19122
21134
  try {
19123
- await import_promises5.default.mkdir(this.opts.dataDir, { recursive: true });
19124
- return (0, import_fs7.openSync)((0, import_path13.join)(this.opts.dataDir, "index.log"), "a");
21135
+ await import_promises8.default.mkdir(this.opts.dataDir, { recursive: true });
21136
+ return (0, import_fs9.openSync)((0, import_path13.join)(this.opts.dataDir, "index.log"), "a");
19125
21137
  } catch {
19126
21138
  return null;
19127
21139
  }
@@ -19130,8 +21142,8 @@ var IndexService = class {
19130
21142
  * platform needing node-gyp fails here rather than at query time. */
19131
21143
  async installDeps() {
19132
21144
  const dir = this.opts.indexDir;
19133
- if ((0, import_fs7.existsSync)((0, import_path13.join)(dir, "node_modules"))) return;
19134
- await import_promises5.default.copyFile(
21145
+ if ((0, import_fs9.existsSync)((0, import_path13.join)(dir, "node_modules"))) return;
21146
+ await import_promises8.default.copyFile(
19135
21147
  (0, import_path13.join)(dir, "image-package.json"),
19136
21148
  (0, import_path13.join)(dir, "package.json")
19137
21149
  );
@@ -19146,14 +21158,14 @@ var IndexService = class {
19146
21158
  * registration pointing at a dead one. */
19147
21159
  async stablePort() {
19148
21160
  const file = (0, import_path13.join)(this.opts.dataDir, ".port");
19149
- const saved = Number(await import_promises5.default.readFile(file, "utf-8").catch(() => ""));
21161
+ const saved = Number(await import_promises8.default.readFile(file, "utf-8").catch(() => ""));
19150
21162
  if (Number.isInteger(saved) && saved > 0 && await isFree(saved)) {
19151
21163
  return saved;
19152
21164
  }
19153
21165
  const port = await freePort();
19154
- await import_promises5.default.mkdir(this.opts.dataDir, { recursive: true }).catch(() => {
21166
+ await import_promises8.default.mkdir(this.opts.dataDir, { recursive: true }).catch(() => {
19155
21167
  });
19156
- await import_promises5.default.writeFile(file, String(port), "utf-8").catch(() => {
21168
+ await import_promises8.default.writeFile(file, String(port), "utf-8").catch(() => {
19157
21169
  });
19158
21170
  return port;
19159
21171
  }
@@ -19246,20 +21258,20 @@ var IndexService = class {
19246
21258
  }
19247
21259
  };
19248
21260
  function isFree(port) {
19249
- return new Promise((resolve2) => {
21261
+ return new Promise((resolve4) => {
19250
21262
  const srv = (0, import_net2.createServer)();
19251
- srv.once("error", () => resolve2(false));
19252
- srv.listen(port, "127.0.0.1", () => srv.close(() => resolve2(true)));
21263
+ srv.once("error", () => resolve4(false));
21264
+ srv.listen(port, "127.0.0.1", () => srv.close(() => resolve4(true)));
19253
21265
  });
19254
21266
  }
19255
21267
  function freePort() {
19256
- return new Promise((resolve2, reject) => {
21268
+ return new Promise((resolve4, reject) => {
19257
21269
  const srv = (0, import_net2.createServer)();
19258
21270
  srv.on("error", reject);
19259
21271
  srv.listen(0, "127.0.0.1", () => {
19260
21272
  const addr = srv.address();
19261
21273
  const port = typeof addr === "object" && addr ? addr.port : 0;
19262
- srv.close(() => resolve2(port));
21274
+ srv.close(() => resolve4(port));
19263
21275
  });
19264
21276
  });
19265
21277
  }
@@ -19310,7 +21322,7 @@ async function setup(serverUrl) {
19310
21322
  // src/selfUpdate.ts
19311
21323
  var import_node_child_process = require("node:child_process");
19312
21324
  var import_node_fs = __toESM(require("node:fs"));
19313
- var import_node_path = __toESM(require("node:path"));
21325
+ var import_node_path2 = __toESM(require("node:path"));
19314
21326
  var PACKAGE_NAME = "@factiii/runner";
19315
21327
  var RESTART_FOR_UPDATE = 75;
19316
21328
  var WORKER_ENV = "FACTIII_RUNNER_WORKER";
@@ -19323,7 +21335,7 @@ function isWorker() {
19323
21335
  function currentVersion() {
19324
21336
  try {
19325
21337
  const pkg = JSON.parse(
19326
- import_node_fs.default.readFileSync(import_node_path.default.join(__dirname, "..", "package.json"), "utf-8")
21338
+ import_node_fs.default.readFileSync(import_node_path2.default.join(__dirname, "..", "package.json"), "utf-8")
19327
21339
  );
19328
21340
  return pkg.version ?? "0.0.0";
19329
21341
  } catch {
@@ -19398,8 +21410,8 @@ function makeChunkReassembler() {
19398
21410
  }
19399
21411
 
19400
21412
  // src/daemon.ts
19401
- var import_crypto6 = require("crypto");
19402
- var import_fs9 = __toESM(require("fs"));
21413
+ var import_crypto7 = require("crypto");
21414
+ var import_fs11 = __toESM(require("fs"));
19403
21415
  var import_node_datachannel = require("node-datachannel");
19404
21416
  var import_path15 = __toESM(require("path"));
19405
21417
 
@@ -21898,9 +23910,9 @@ var Socket2 = class extends import_component_emitter5.Emitter {
21898
23910
  * @return a Promise that will be fulfilled when the server acknowledges the event
21899
23911
  */
21900
23912
  emitWithAck(ev, ...args) {
21901
- return new Promise((resolve2, reject) => {
23913
+ return new Promise((resolve4, reject) => {
21902
23914
  const fn = (arg1, arg2) => {
21903
- return arg1 ? reject(arg1) : resolve2(arg2);
23915
+ return arg1 ? reject(arg1) : resolve4(arg2);
21904
23916
  };
21905
23917
  fn.withError = true;
21906
23918
  args.push(fn);
@@ -23081,7 +25093,7 @@ var TerminalManager = class {
23081
25093
  };
23082
25094
 
23083
25095
  // src/agent-adapter.ts
23084
- var import_fs8 = __toESM(require("fs"));
25096
+ var import_fs10 = __toESM(require("fs"));
23085
25097
  var import_path14 = __toESM(require("path"));
23086
25098
  var RUNNER_CONFIG_PATH = import_path14.default.join(CONFIG_DIR, "runner-config.json");
23087
25099
  function connectionPath(spaceSlug) {
@@ -23112,7 +25124,7 @@ function migrateLegacyConfigs() {
23112
25124
  const file = { boards: {} };
23113
25125
  let legacy = [];
23114
25126
  try {
23115
- legacy = import_fs8.default.readdirSync(CONFIG_DIR).filter((f) => f.startsWith("space-") && f.endsWith(".json")).filter((f) => !f.endsWith(".onedrive.json"));
25127
+ legacy = import_fs10.default.readdirSync(CONFIG_DIR).filter((f) => f.startsWith("space-") && f.endsWith(".json")).filter((f) => !f.endsWith(".onedrive.json"));
23116
25128
  } catch {
23117
25129
  return file;
23118
25130
  }
@@ -23139,14 +25151,14 @@ function encryptStrayPlaintextConfigs() {
23139
25151
  const OURS = /^(config|runner-config|space-.*)\.json(\.bak-\d+)?$/;
23140
25152
  let names = [];
23141
25153
  try {
23142
- names = import_fs8.default.readdirSync(CONFIG_DIR).filter((f) => OURS.test(f));
25154
+ names = import_fs10.default.readdirSync(CONFIG_DIR).filter((f) => OURS.test(f));
23143
25155
  } catch {
23144
25156
  return;
23145
25157
  }
23146
25158
  for (const name of names) {
23147
25159
  const filePath = import_path14.default.join(CONFIG_DIR, name);
23148
25160
  try {
23149
- const raw = import_fs8.default.readFileSync(filePath, "utf-8");
25161
+ const raw = import_fs10.default.readFileSync(filePath, "utf-8");
23150
25162
  if (!raw.startsWith("{")) continue;
23151
25163
  writeSecureJson(filePath, JSON.parse(raw));
23152
25164
  } catch {
@@ -23177,7 +25189,7 @@ async function getConfiguredConnections() {
23177
25189
  }
23178
25190
  if (await isSignedIn(hostTarget(CONFIG_DIR), "claude")) kinds.add("claude");
23179
25191
  try {
23180
- const hasOneDrive = import_fs8.default.readdirSync(CONFIG_DIR).some((f) => f.endsWith(".onedrive.json"));
25192
+ const hasOneDrive = import_fs10.default.readdirSync(CONFIG_DIR).some((f) => f.endsWith(".onedrive.json"));
23181
25193
  if (hasOneDrive) kinds.add("onedrive");
23182
25194
  } catch {
23183
25195
  }
@@ -23248,7 +25260,7 @@ var localConfigProvider = {
23248
25260
  writeOneDriveConnection(spaceSlug, connection) {
23249
25261
  const filePath = connectionPath(spaceSlug);
23250
25262
  if (!connection) {
23251
- import_fs8.default.rmSync(filePath, { force: true });
25263
+ import_fs10.default.rmSync(filePath, { force: true });
23252
25264
  return;
23253
25265
  }
23254
25266
  writeJson(filePath, connection);
@@ -23273,7 +25285,7 @@ var localConfigProvider = {
23273
25285
  "claude",
23274
25286
  "codex"
23275
25287
  ]) {
23276
- import_fs8.default.mkdirSync(import_path14.default.join(dir, sub), { recursive: true });
25288
+ import_fs10.default.mkdirSync(import_path14.default.join(dir, sub), { recursive: true });
23277
25289
  }
23278
25290
  return dir;
23279
25291
  }
@@ -23397,17 +25409,17 @@ async function startDaemon(config) {
23397
25409
  }
23398
25410
  };
23399
25411
  const mintWebhook = (spaceSlug) => new Promise(
23400
- (resolve2) => {
25412
+ (resolve4) => {
23401
25413
  if (!socket.connected) {
23402
- resolve2(null);
25414
+ resolve4(null);
23403
25415
  return;
23404
25416
  }
23405
25417
  socket.timeout(8e3).emit("onedriveWebhookRegister", { spaceSlug }, (err, res) => {
23406
25418
  if (err || !res || "error" in res) {
23407
- resolve2(null);
25419
+ resolve4(null);
23408
25420
  return;
23409
25421
  }
23410
- resolve2({
25422
+ resolve4({
23411
25423
  notificationUrl: `${config.serverUrl.replace(/\/$/, "")}/onedrive/webhook`,
23412
25424
  clientState: res.clientState
23413
25425
  });
@@ -23418,9 +25430,9 @@ async function startDaemon(config) {
23418
25430
  import_path15.default.join(__dirname, "..", "index"),
23419
25431
  import_path15.default.join(__dirname, "..", "..", "index", "image")
23420
25432
  ];
23421
- const indexDir = indexCandidates.find((p) => import_fs9.default.existsSync(p)) ?? indexCandidates[0];
25433
+ const indexDir = indexCandidates.find((p) => import_fs11.default.existsSync(p)) ?? indexCandidates[0];
23422
25434
  const odIndex = new IndexService({
23423
- controlToken: (0, import_crypto6.createHash)("sha256").update(config.authToken).digest("hex"),
25435
+ controlToken: (0, import_crypto7.createHash)("sha256").update(config.authToken).digest("hex"),
23424
25436
  embedUrl: () => config.serverUrl,
23425
25437
  indexDir,
23426
25438
  dataDir: import_path15.default.join(CONFIG_DIR, "index-data")
@@ -24073,5 +26085,8 @@ xmlhttprequest-ssl/lib/XMLHttpRequest.js:
24073
26085
  * @contributor David Ellis <d.f.ellis@ieee.org>
24074
26086
  * @license MIT
24075
26087
  *)
26088
+
26089
+ chokidar/esm/index.js:
26090
+ (*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) *)
24076
26091
  */
24077
26092
  //# sourceMappingURL=cli.js.map