@runfusion/fusion 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -134,9 +134,11 @@ var init_settings_schema = __esm({
134
134
  defaultPresetBySize: {},
135
135
  autoResolveConflicts: true,
136
136
  smartConflictResolution: true,
137
+ worktreeRebaseBeforeMerge: true,
138
+ worktreeRebaseRemote: "",
137
139
  strictScopeEnforcement: false,
138
140
  buildRetryCount: 0,
139
- verificationFixRetries: 1,
141
+ verificationFixRetries: 3,
140
142
  buildTimeoutMs: 3e5,
141
143
  requirePlanApproval: false,
142
144
  specStalenessEnabled: false,
@@ -30549,6 +30551,7 @@ ${newTask.description}
30549
30551
  }
30550
30552
  }
30551
30553
  if (updates.steps !== void 0) task.steps = updates.steps;
30554
+ if (updates.currentStep !== void 0) task.currentStep = updates.currentStep;
30552
30555
  if (updates.status === null) {
30553
30556
  task.status = void 0;
30554
30557
  } else if (updates.status !== void 0) {
@@ -37138,9 +37141,9 @@ var require_pump = __commonJS({
37138
37141
  "use strict";
37139
37142
  var once3 = require_once();
37140
37143
  var eos = require_end_of_stream();
37141
- var fs;
37144
+ var fs2;
37142
37145
  try {
37143
- fs = __require("fs");
37146
+ fs2 = __require("fs");
37144
37147
  } catch (e) {
37145
37148
  }
37146
37149
  var noop = function() {
@@ -37151,8 +37154,8 @@ var require_pump = __commonJS({
37151
37154
  };
37152
37155
  var isFS = function(stream) {
37153
37156
  if (!ancient) return false;
37154
- if (!fs) return false;
37155
- return (stream instanceof (fs.ReadStream || noop) || stream instanceof (fs.WriteStream || noop)) && isFn(stream.close);
37157
+ if (!fs2) return false;
37158
+ return (stream instanceof (fs2.ReadStream || noop) || stream instanceof (fs2.WriteStream || noop)) && isFn(stream.close);
37156
37159
  };
37157
37160
  var isRequest = function(stream) {
37158
37161
  return stream.setHeader && isFn(stream.abort);
@@ -37366,7 +37369,7 @@ var require_pend = __commonJS({
37366
37369
  var require_fd_slicer = __commonJS({
37367
37370
  "../../node_modules/.pnpm/fd-slicer@1.1.0/node_modules/fd-slicer/index.js"(exports) {
37368
37371
  "use strict";
37369
- var fs = __require("fs");
37372
+ var fs2 = __require("fs");
37370
37373
  var util = __require("util");
37371
37374
  var stream = __require("stream");
37372
37375
  var Readable2 = stream.Readable;
@@ -37391,7 +37394,7 @@ var require_fd_slicer = __commonJS({
37391
37394
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
37392
37395
  var self2 = this;
37393
37396
  self2.pend.go(function(cb) {
37394
- fs.read(self2.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
37397
+ fs2.read(self2.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
37395
37398
  cb();
37396
37399
  callback(err, bytesRead, buffer2);
37397
37400
  });
@@ -37400,7 +37403,7 @@ var require_fd_slicer = __commonJS({
37400
37403
  FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
37401
37404
  var self2 = this;
37402
37405
  self2.pend.go(function(cb) {
37403
- fs.write(self2.fd, buffer, offset, length, position, function(err, written, buffer2) {
37406
+ fs2.write(self2.fd, buffer, offset, length, position, function(err, written, buffer2) {
37404
37407
  cb();
37405
37408
  callback(err, written, buffer2);
37406
37409
  });
@@ -37421,7 +37424,7 @@ var require_fd_slicer = __commonJS({
37421
37424
  if (self2.refCount > 0) return;
37422
37425
  if (self2.refCount < 0) throw new Error("invalid unref");
37423
37426
  if (self2.autoClose) {
37424
- fs.close(self2.fd, onCloseDone);
37427
+ fs2.close(self2.fd, onCloseDone);
37425
37428
  }
37426
37429
  function onCloseDone(err) {
37427
37430
  if (err) {
@@ -37458,7 +37461,7 @@ var require_fd_slicer = __commonJS({
37458
37461
  self2.context.pend.go(function(cb) {
37459
37462
  if (self2.destroyed) return cb();
37460
37463
  var buffer = new Buffer(toRead);
37461
- fs.read(self2.context.fd, buffer, 0, toRead, self2.pos, function(err, bytesRead) {
37464
+ fs2.read(self2.context.fd, buffer, 0, toRead, self2.pos, function(err, bytesRead) {
37462
37465
  if (err) {
37463
37466
  self2.destroy(err);
37464
37467
  } else if (bytesRead === 0) {
@@ -37505,7 +37508,7 @@ var require_fd_slicer = __commonJS({
37505
37508
  }
37506
37509
  self2.context.pend.go(function(cb) {
37507
37510
  if (self2.destroyed) return cb();
37508
- fs.write(self2.context.fd, buffer, 0, buffer.length, self2.pos, function(err2, bytes) {
37511
+ fs2.write(self2.context.fd, buffer, 0, buffer.length, self2.pos, function(err2, bytes) {
37509
37512
  if (err2) {
37510
37513
  self2.destroy();
37511
37514
  cb();
@@ -37934,7 +37937,7 @@ var require_buffer_crc32 = __commonJS({
37934
37937
  var require_yauzl = __commonJS({
37935
37938
  "../../node_modules/.pnpm/yauzl@2.10.0/node_modules/yauzl/index.js"(exports) {
37936
37939
  "use strict";
37937
- var fs = __require("fs");
37940
+ var fs2 = __require("fs");
37938
37941
  var zlib = __require("zlib");
37939
37942
  var fd_slicer = require_fd_slicer();
37940
37943
  var crc32 = require_buffer_crc32();
@@ -37964,10 +37967,10 @@ var require_yauzl = __commonJS({
37964
37967
  if (options.validateEntrySizes == null) options.validateEntrySizes = true;
37965
37968
  if (options.strictFileNames == null) options.strictFileNames = false;
37966
37969
  if (callback == null) callback = defaultCallback;
37967
- fs.open(path4, "r", function(err, fd) {
37970
+ fs2.open(path4, "r", function(err, fd) {
37968
37971
  if (err) return callback(err);
37969
37972
  fromFd(fd, options, function(err2, zipfile) {
37970
- if (err2) fs.close(fd, defaultCallback);
37973
+ if (err2) fs2.close(fd, defaultCallback);
37971
37974
  callback(err2, zipfile);
37972
37975
  });
37973
37976
  });
@@ -37984,7 +37987,7 @@ var require_yauzl = __commonJS({
37984
37987
  if (options.validateEntrySizes == null) options.validateEntrySizes = true;
37985
37988
  if (options.strictFileNames == null) options.strictFileNames = false;
37986
37989
  if (callback == null) callback = defaultCallback;
37987
- fs.fstat(fd, function(err, stats) {
37990
+ fs2.fstat(fd, function(err, stats) {
37988
37991
  if (err) return callback(err);
37989
37992
  var reader = fd_slicer.createFromFd(fd, { autoClose: true });
37990
37993
  fromRandomAccessReader(reader, stats.size, options, callback);
@@ -38565,7 +38568,7 @@ var require_extract_zip = __commonJS({
38565
38568
  "../../node_modules/.pnpm/extract-zip@2.0.1/node_modules/extract-zip/index.js"(exports, module) {
38566
38569
  "use strict";
38567
38570
  var debug = require_src()("extract-zip");
38568
- var { createWriteStream: createWriteStream2, promises: fs } = __require("fs");
38571
+ var { createWriteStream: createWriteStream2, promises: fs2 } = __require("fs");
38569
38572
  var getStream = require_get_stream();
38570
38573
  var path4 = __require("path");
38571
38574
  var { promisify: promisify14 } = __require("util");
@@ -38606,8 +38609,8 @@ var require_extract_zip = __commonJS({
38606
38609
  }
38607
38610
  const destDir = path4.dirname(path4.join(this.opts.dir, entry.fileName));
38608
38611
  try {
38609
- await fs.mkdir(destDir, { recursive: true });
38610
- const canonicalDestDir = await fs.realpath(destDir);
38612
+ await fs2.mkdir(destDir, { recursive: true });
38613
+ const canonicalDestDir = await fs2.realpath(destDir);
38611
38614
  const relativeDestDir = path4.relative(this.opts.dir, canonicalDestDir);
38612
38615
  if (relativeDestDir.split(path4.sep).includes("..")) {
38613
38616
  throw new Error(`Out of bound path "${canonicalDestDir}" found while processing file ${entry.fileName}`);
@@ -38651,14 +38654,14 @@ var require_extract_zip = __commonJS({
38651
38654
  mkdirOptions.mode = procMode;
38652
38655
  }
38653
38656
  debug("mkdir", { dir: destDir, ...mkdirOptions });
38654
- await fs.mkdir(destDir, mkdirOptions);
38657
+ await fs2.mkdir(destDir, mkdirOptions);
38655
38658
  if (isDir) return;
38656
38659
  debug("opening read stream", dest);
38657
38660
  const readStream = await promisify14(this.zipfile.openReadStream.bind(this.zipfile))(entry);
38658
38661
  if (symlink) {
38659
38662
  const link = await getStream(readStream);
38660
38663
  debug("creating symlink", link, dest);
38661
- await fs.symlink(link, dest);
38664
+ await fs2.symlink(link, dest);
38662
38665
  } else {
38663
38666
  await pipeline(readStream, createWriteStream2(dest, { mode: procMode }));
38664
38667
  }
@@ -38690,8 +38693,8 @@ var require_extract_zip = __commonJS({
38690
38693
  if (!path4.isAbsolute(opts.dir)) {
38691
38694
  throw new Error("Target directory is expected to be absolute");
38692
38695
  }
38693
- await fs.mkdir(opts.dir, { recursive: true });
38694
- opts.dir = await fs.realpath(opts.dir);
38696
+ await fs2.mkdir(opts.dir, { recursive: true });
38697
+ opts.dir = await fs2.realpath(opts.dir);
38695
38698
  return new Extractor(zipPath, opts).extract();
38696
38699
  };
38697
38700
  }
@@ -45550,14 +45553,14 @@ var require_parser = __commonJS({
45550
45553
  case "scalar":
45551
45554
  case "single-quoted-scalar":
45552
45555
  case "double-quoted-scalar": {
45553
- const fs = this.flowScalar(this.type);
45556
+ const fs2 = this.flowScalar(this.type);
45554
45557
  if (atNextItem || it.value) {
45555
- map2.items.push({ start, key: fs, sep: [] });
45558
+ map2.items.push({ start, key: fs2, sep: [] });
45556
45559
  this.onKeyLine = true;
45557
45560
  } else if (it.sep) {
45558
- this.stack.push(fs);
45561
+ this.stack.push(fs2);
45559
45562
  } else {
45560
- Object.assign(it, { key: fs, sep: [] });
45563
+ Object.assign(it, { key: fs2, sep: [] });
45561
45564
  this.onKeyLine = true;
45562
45565
  }
45563
45566
  return;
@@ -45685,13 +45688,13 @@ var require_parser = __commonJS({
45685
45688
  case "scalar":
45686
45689
  case "single-quoted-scalar":
45687
45690
  case "double-quoted-scalar": {
45688
- const fs = this.flowScalar(this.type);
45691
+ const fs2 = this.flowScalar(this.type);
45689
45692
  if (!it || it.value)
45690
- fc.items.push({ start: [], key: fs, sep: [] });
45693
+ fc.items.push({ start: [], key: fs2, sep: [] });
45691
45694
  else if (it.sep)
45692
- this.stack.push(fs);
45695
+ this.stack.push(fs2);
45693
45696
  else
45694
- Object.assign(it, { key: fs, sep: [] });
45697
+ Object.assign(it, { key: fs2, sep: [] });
45695
45698
  return;
45696
45699
  }
45697
45700
  case "flow-map-end":
@@ -49972,7 +49975,7 @@ var require_windowsPtyAgent = __commonJS({
49972
49975
  "use strict";
49973
49976
  Object.defineProperty(exports, "__esModule", { value: true });
49974
49977
  exports.argsToCommandLine = exports.WindowsPtyAgent = void 0;
49975
- var fs = __require("fs");
49978
+ var fs2 = __require("fs");
49976
49979
  var os3 = __require("os");
49977
49980
  var path4 = __require("path");
49978
49981
  var child_process_1 = __require("child_process");
@@ -50031,7 +50034,7 @@ var require_windowsPtyAgent = __commonJS({
50031
50034
  this._outSocket.on("connect", function() {
50032
50035
  _this._outSocket.emit("ready_datapipe");
50033
50036
  });
50034
- var inSocketFD = fs.openSync(term.conin, "w");
50037
+ var inSocketFD = fs2.openSync(term.conin, "w");
50035
50038
  this._inSocket = new net_1.Socket({
50036
50039
  fd: inSocketFD,
50037
50040
  readable: false,
@@ -50465,7 +50468,7 @@ var require_unixTerminal = __commonJS({
50465
50468
  })();
50466
50469
  Object.defineProperty(exports, "__esModule", { value: true });
50467
50470
  exports.UnixTerminal = void 0;
50468
- var fs = __require("fs");
50471
+ var fs2 = __require("fs");
50469
50472
  var path4 = __require("path");
50470
50473
  var tty = __require("tty");
50471
50474
  var terminal_1 = require_terminal();
@@ -50728,7 +50731,7 @@ var require_unixTerminal = __commonJS({
50728
50731
  return;
50729
50732
  }
50730
50733
  var task = this._writeQueue[0];
50731
- fs.write(this._fd, task.buffer, task.offset, function(err, written) {
50734
+ fs2.write(this._fd, task.buffer, task.offset, function(err, written) {
50732
50735
  if (err) {
50733
50736
  if ("code" in err && err.code === "EAGAIN") {
50734
50737
  _this._writeImmediate = setImmediate(function() {
@@ -50790,26 +50793,74 @@ var require_lib = __commonJS({
50790
50793
  import { EventEmitter as EventEmitter17 } from "events";
50791
50794
  import * as os2 from "os";
50792
50795
  import * as path from "path";
50793
- import { existsSync as existsSync17 } from "node:fs";
50796
+ import * as fs from "node:fs";
50797
+ import { createRequire } from "node:module";
50794
50798
  import { join as join22, dirname as dirname7 } from "node:path";
50795
- function findStagedNativeDir() {
50799
+ function getNativePrebuildName() {
50796
50800
  const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
50797
50801
  const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
50798
- const prebuildName = `${platform3}-${arch}`;
50802
+ return `${platform3}-${arch}`;
50803
+ }
50804
+ function findInstalledNodePtyNativeDir() {
50805
+ try {
50806
+ const packageJsonPath = require2.resolve("node-pty/package.json");
50807
+ const nativeDir = join22(dirname7(packageJsonPath), "prebuilds", getNativePrebuildName());
50808
+ return fs.existsSync(join22(nativeDir, "pty.node")) ? nativeDir : null;
50809
+ } catch {
50810
+ return null;
50811
+ }
50812
+ }
50813
+ function ensureNodePtyNativePermissions() {
50814
+ if (process.platform === "win32") {
50815
+ return;
50816
+ }
50817
+ const candidateDirs = /* @__PURE__ */ new Set();
50818
+ const envNativeDir = process.env.NODE_PTY_SPAWN_HELPER_DIR || process.env.FUSION_NATIVE_ASSETS_PATH;
50819
+ if (envNativeDir) {
50820
+ candidateDirs.add(envNativeDir);
50821
+ }
50822
+ const stagedNativeDir = findStagedNativeDir();
50823
+ if (stagedNativeDir) {
50824
+ candidateDirs.add(stagedNativeDir);
50825
+ }
50826
+ const installedNativeDir = findInstalledNodePtyNativeDir();
50827
+ if (installedNativeDir) {
50828
+ candidateDirs.add(installedNativeDir);
50829
+ }
50830
+ for (const nativeDir of candidateDirs) {
50831
+ const helperPath = join22(nativeDir, "spawn-helper");
50832
+ const nativeModulePath = join22(nativeDir, "pty.node");
50833
+ try {
50834
+ fs.chmodSync(helperPath, 493);
50835
+ } catch {
50836
+ }
50837
+ try {
50838
+ fs.chmodSync(nativeModulePath, 493);
50839
+ } catch (err) {
50840
+ console.warn("[terminal] Failed to repair node-pty native permissions:", {
50841
+ nativeDir,
50842
+ error: err instanceof Error ? err.message : String(err)
50843
+ });
50844
+ }
50845
+ }
50846
+ }
50847
+ function findStagedNativeDir() {
50848
+ const prebuildName = getNativePrebuildName();
50799
50849
  if (process.env.FUSION_RUNTIME_DIR) {
50800
50850
  const envPath = join22(process.env.FUSION_RUNTIME_DIR, prebuildName);
50801
- if (existsSync17(join22(envPath, "pty.node"))) {
50851
+ if (fs.existsSync(join22(envPath, "pty.node"))) {
50802
50852
  return envPath;
50803
50853
  }
50804
50854
  }
50805
50855
  const execDir = dirname7(process.execPath);
50806
50856
  const nextToBinary = join22(execDir, "runtime", prebuildName);
50807
- if (existsSync17(join22(nextToBinary, "pty.node"))) {
50857
+ if (fs.existsSync(join22(nextToBinary, "pty.node"))) {
50808
50858
  return nextToBinary;
50809
50859
  }
50810
50860
  return null;
50811
50861
  }
50812
50862
  async function loadPtyModule() {
50863
+ ensureNodePtyNativePermissions();
50813
50864
  if (ptyModule) {
50814
50865
  return ptyModule;
50815
50866
  }
@@ -50824,7 +50875,7 @@ async function loadPtyModule() {
50824
50875
  }
50825
50876
  process.env.FUSION_NATIVE_ASSETS_PATH = nativeDir;
50826
50877
  const nativePath = join22(nativeDir, "pty.node");
50827
- if (existsSync17(nativePath)) {
50878
+ if (fs.existsSync(nativePath)) {
50828
50879
  try {
50829
50880
  const nativeModule = { exports: {} };
50830
50881
  process.dlopen(nativeModule, nativePath);
@@ -50861,13 +50912,14 @@ function getTerminalService(projectRoot, maxSessions) {
50861
50912
  terminalServices.set(resolvedRoot, service);
50862
50913
  return service;
50863
50914
  }
50864
- var isBunBinary, ptyModule, ptyLoadError, MAX_SCROLLBACK_SIZE, MIN_MAX_SESSIONS, MAX_MAX_SESSIONS, DEFAULT_MAX_SESSIONS, OUTPUT_THROTTLE_MS, OUTPUT_BATCH_SIZE, STALE_SESSION_THRESHOLD_MS, SESSION_ID_PATTERN, ALLOWED_SHELL_PATHS, STRIP_ENV_VARS, TerminalService, terminalServices;
50915
+ var isBunBinary, ptyModule, ptyLoadError, require2, MAX_SCROLLBACK_SIZE, MIN_MAX_SESSIONS, MAX_MAX_SESSIONS, DEFAULT_MAX_SESSIONS, OUTPUT_THROTTLE_MS, OUTPUT_BATCH_SIZE, STALE_SESSION_THRESHOLD_MS, SESSION_ID_PATTERN, ALLOWED_SHELL_PATHS, STRIP_ENV_VARS, TerminalService, terminalServices;
50865
50916
  var init_terminal_service = __esm({
50866
50917
  "../dashboard/src/terminal-service.ts"() {
50867
50918
  "use strict";
50868
50919
  isBunBinary = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
50869
50920
  ptyModule = null;
50870
50921
  ptyLoadError = null;
50922
+ require2 = createRequire(import.meta.url);
50871
50923
  MAX_SCROLLBACK_SIZE = 5e4;
50872
50924
  MIN_MAX_SESSIONS = 1;
50873
50925
  MAX_MAX_SESSIONS = 100;
@@ -50957,13 +51009,13 @@ var init_terminal_service = __esm({
50957
51009
  const normalizedUserShell = this.isWindows ? userShell.toLowerCase() : userShell;
50958
51010
  for (const allowed of allowedShells) {
50959
51011
  const normalizedAllowed = this.isWindows ? allowed.toLowerCase() : allowed;
50960
- if (normalizedAllowed === normalizedUserShell && existsSync17(allowed)) {
51012
+ if (normalizedAllowed === normalizedUserShell && fs.existsSync(allowed)) {
50961
51013
  return { shell: allowed, args: getShellArgs(allowed) };
50962
51014
  }
50963
51015
  }
50964
51016
  }
50965
51017
  for (const shell of allowedShells) {
50966
- if (existsSync17(shell)) {
51018
+ if (fs.existsSync(shell)) {
50967
51019
  return { shell, args: getShellArgs(shell) };
50968
51020
  }
50969
51021
  }
@@ -50984,7 +51036,7 @@ var init_terminal_service = __esm({
50984
51036
  detectedShell,
50985
51037
  detectedArgs,
50986
51038
  envShell: process.env.SHELL ?? null,
50987
- allowedShells: this.getAllowedShells().filter((shellPath) => existsSync17(shellPath))
51039
+ allowedShells: this.getAllowedShells().filter((shellPath) => fs.existsSync(shellPath))
50988
51040
  };
50989
51041
  }
50990
51042
  /**
@@ -51005,7 +51057,7 @@ var init_terminal_service = __esm({
51005
51057
  return this.projectRoot;
51006
51058
  }
51007
51059
  try {
51008
- const stat11 = await import("node:fs/promises").then((fs) => fs.stat(cwd));
51060
+ const stat11 = await import("node:fs/promises").then((fs2) => fs2.stat(cwd));
51009
51061
  if (stat11.isDirectory()) {
51010
51062
  return cwd;
51011
51063
  }
@@ -51168,7 +51220,7 @@ var init_terminal_service = __esm({
51168
51220
  addSpawnAttempt(shell, [], "retry-without-login");
51169
51221
  }
51170
51222
  for (const allowedShell of this.getAllowedShells()) {
51171
- if (allowedShell === shell || !existsSync17(allowedShell)) continue;
51223
+ if (allowedShell === shell || !fs.existsSync(allowedShell)) continue;
51172
51224
  const shellName = path.basename(allowedShell).toLowerCase().replace(".exe", "");
51173
51225
  const fallbackArgs = shellName === "bash" || shellName === "zsh" ? [] : [];
51174
51226
  addSpawnAttempt(allowedShell, fallbackArgs, "allowed-fallback");
@@ -65072,6 +65124,71 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
65072
65124
  mergerLog.warn(`${taskId}: unable to verify/checkout main branch \u2014 proceeding on current HEAD`);
65073
65125
  }
65074
65126
  }
65127
+ if (settings.worktreeRebaseBeforeMerge !== false) {
65128
+ try {
65129
+ let remote = settings.worktreeRebaseRemote?.trim();
65130
+ if (!remote) {
65131
+ try {
65132
+ const { stdout: mainBranchOut } = await execAsync2(
65133
+ "git rev-parse --abbrev-ref HEAD",
65134
+ { cwd: rootDir, encoding: "utf-8" }
65135
+ );
65136
+ const mainBranch = mainBranchOut.trim();
65137
+ const { stdout: configuredRemote } = await execAsync2(
65138
+ `git config --get branch.${mainBranch}.remote`,
65139
+ { cwd: rootDir, encoding: "utf-8" }
65140
+ ).catch(() => ({ stdout: "" }));
65141
+ remote = configuredRemote.trim();
65142
+ } catch {
65143
+ }
65144
+ }
65145
+ if (!remote) {
65146
+ try {
65147
+ const { stdout: remotesOut } = await execAsync2("git remote", {
65148
+ cwd: rootDir,
65149
+ encoding: "utf-8"
65150
+ });
65151
+ const remotes = remotesOut.trim().split(/\s+/).filter(Boolean);
65152
+ if (remotes.length === 1) {
65153
+ remote = remotes[0];
65154
+ } else if (remotes.includes("origin")) {
65155
+ remote = "origin";
65156
+ }
65157
+ } catch {
65158
+ }
65159
+ }
65160
+ if (!remote) {
65161
+ mergerLog.log(`${taskId}: no remote resolvable \u2014 skipping pre-merge rebase`);
65162
+ } else {
65163
+ mergerLog.log(`${taskId}: fetching ${remote} before merge`);
65164
+ await execAsync2(`git fetch "${remote}"`, { cwd: rootDir });
65165
+ try {
65166
+ const { stdout: mainBranchOut } = await execAsync2(
65167
+ "git rev-parse --abbrev-ref HEAD",
65168
+ { cwd: rootDir, encoding: "utf-8" }
65169
+ );
65170
+ const mainBranch = mainBranchOut.trim();
65171
+ const remoteRef = `${remote}/${mainBranch}`;
65172
+ if (worktreePath) {
65173
+ await execAsync2(`git rebase "${remoteRef}"`, { cwd: worktreePath });
65174
+ mergerLog.log(`${taskId}: rebased ${branch} onto ${remoteRef}`);
65175
+ } else {
65176
+ mergerLog.warn(`${taskId}: no worktreePath \u2014 skipping task branch rebase`);
65177
+ }
65178
+ } catch (rebaseErr) {
65179
+ const msg = rebaseErr instanceof Error ? rebaseErr.message : String(rebaseErr);
65180
+ mergerLog.warn(`${taskId}: pre-merge rebase failed (${msg}) \u2014 aborting rebase and falling through to smart/AI merge`);
65181
+ if (worktreePath) {
65182
+ await execAsync2("git rebase --abort", { cwd: worktreePath }).catch(() => {
65183
+ });
65184
+ }
65185
+ }
65186
+ }
65187
+ } catch (err) {
65188
+ const msg = err instanceof Error ? err.message : String(err);
65189
+ mergerLog.warn(`${taskId}: pre-merge rebase pipeline failed (${msg}) \u2014 proceeding without rebase`);
65190
+ }
65191
+ }
65075
65192
  let commitLog = "";
65076
65193
  let diffStat = "";
65077
65194
  try {
@@ -65170,7 +65287,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
65170
65287
  } catch (error) {
65171
65288
  if (error.name === "VerificationError") {
65172
65289
  const verificationErr = error;
65173
- const maxFixRetries = Math.min(settings.verificationFixRetries ?? 1, 3);
65290
+ const maxFixRetries = Math.min(settings.verificationFixRetries ?? 3, 3);
65174
65291
  if (maxFixRetries > 0 && (verificationErr.verificationResult.testResult || verificationErr.verificationResult.buildResult)) {
65175
65292
  mergerLog.log(`${taskId}: deterministic verification failed \u2014 attempting in-merge fix (up to ${maxFixRetries} attempts)`);
65176
65293
  await store.logEntry(taskId, `Verification failed during merge \u2014 attempting in-merge fix (up to ${maxFixRetries} attempts)`);
@@ -65215,7 +65332,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
65215
65332
  throw error;
65216
65333
  }
65217
65334
  if (error.message?.includes("Build verification failed")) {
65218
- const maxFixRetries = Math.min(settings.verificationFixRetries ?? 1, 3);
65335
+ const maxFixRetries = Math.min(settings.verificationFixRetries ?? 3, 3);
65219
65336
  if (maxFixRetries > 0 && (effectiveTestCommand || effectiveBuildCommand)) {
65220
65337
  mergerLog.log(`${taskId}: build verification failed \u2014 attempting in-merge fix`);
65221
65338
  await store.logEntry(taskId, `Build verification failed during merge \u2014 attempting in-merge fix`);
@@ -67588,19 +67705,6 @@ import { existsSync as existsSync26 } from "node:fs";
67588
67705
  import { readFile as readFile16, writeFile as writeFile12 } from "node:fs/promises";
67589
67706
  import { Type as Type4 } from "@mariozechner/pi-ai";
67590
67707
  import { ModelRegistry as ModelRegistry2, SessionManager as SessionManager2 } from "@mariozechner/pi-coding-agent";
67591
- function determineRevisionResetStart(steps, feedback) {
67592
- const total = steps.length;
67593
- if (total === 0) return 0;
67594
- const skipPreflight = /preflight/i.test(steps[0].name);
67595
- const firstCandidate = skipPreflight ? 1 : 0;
67596
- if (firstCandidate >= total) return total;
67597
- const fb = feedback.toLowerCase();
67598
- for (let i = firstCandidate; i < total; i++) {
67599
- const tokens = steps[i].name.toLowerCase().match(/[a-z][a-z]{4,}/g) ?? [];
67600
- if (tokens.some((t) => fb.includes(t))) return i;
67601
- }
67602
- return firstCandidate;
67603
- }
67604
67708
  function truncateWorkflowScriptOutput2(output) {
67605
67709
  if (output.length <= WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS2) return output;
67606
67710
  return `... output truncated to last ${WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS2} characters ...
@@ -69917,35 +70021,23 @@ Take a different approach. Do NOT repeat the rejected strategy. Re-read the step
69917
70021
  }
69918
70022
  /**
69919
70023
  * Handle a workflow step revision request.
69920
- *
69921
- * This method:
69922
- * 1. Updates PROMPT.md with "Workflow Revision Instructions" section
69923
- * 2. Resets task execution state (all steps reset to pending)
69924
- * 3. Schedules fresh execution to run after current guard unwinds
69925
- *
69926
- * The task stays in "in-progress" and is scheduled for a fresh executor pass.
70024
+ *
70025
+ * Re-opens ONLY the last step so the executor has exactly one pending slot
70026
+ * to re-enter through. All earlier done steps stay done — the agent reads
70027
+ * the injected feedback from PROMPT.md and applies an in-place fix rather
70028
+ * than redoing any completed step.
69927
70029
  */
69928
70030
  async handleWorkflowRevisionRequest(task, worktreePath, feedback, stepName) {
69929
70031
  executorLog.log(`${task.id}: workflow revision requested by step "${stepName}"`);
69930
70032
  const updatedTask = await this.store.getTask(task.id);
69931
- const resetStart = determineRevisionResetStart(updatedTask.steps, feedback);
69932
- const targetStepName = resetStart < updatedTask.steps.length ? updatedTask.steps[resetStart].name : null;
69933
- const resetSummary = resetStart >= updatedTask.steps.length ? "no steps to reset" : `resetting steps ${resetStart + 1}\u2013${updatedTask.steps.length} (starting at "${targetStepName}")`;
70033
+ const reopen = await this.reopenLastStepForRevision(task.id, updatedTask);
70034
+ const reopenSummary = reopen ? `re-opening Step ${reopen.index + 1} ("${reopen.name}") for in-place fix` : "no step to re-open (none were completed)";
69934
70035
  await this.store.logEntry(
69935
70036
  task.id,
69936
- `Workflow step "${stepName}" requested revision \u2014 ${resetSummary}`,
70037
+ `Workflow step "${stepName}" requested revision \u2014 ${reopenSummary}`,
69937
70038
  feedback
69938
70039
  );
69939
- await this.injectWorkflowRevisionInstructions(task, feedback, {
69940
- resetStart,
69941
- targetStepName,
69942
- totalSteps: updatedTask.steps.length
69943
- });
69944
- for (let i = resetStart; i < updatedTask.steps.length; i++) {
69945
- if (updatedTask.steps[i].status !== "pending") {
69946
- await this.store.updateStep(task.id, i, "pending");
69947
- }
69948
- }
70040
+ await this.injectWorkflowRevisionInstructions(task, feedback);
69949
70041
  await this.store.updateTask(task.id, {
69950
70042
  status: null,
69951
70043
  sessionFile: null
@@ -69967,12 +70059,36 @@ Take a different approach. Do NOT repeat the rejected strategy. Re-read the step
69967
70059
  }
69968
70060
  }, 0);
69969
70061
  }
70062
+ /**
70063
+ * Re-open the last non-pending step so a revision/failure handler gives the
70064
+ * executor exactly one pending slot to re-enter through. Returns the index
70065
+ * and name of the step that was flipped to `pending`, or null when there
70066
+ * was nothing to re-open.
70067
+ */
70068
+ async reopenLastStepForRevision(taskId, task) {
70069
+ const steps = task.steps;
70070
+ if (steps.length === 0) return null;
70071
+ let targetIndex = -1;
70072
+ for (let i = steps.length - 1; i >= 0; i--) {
70073
+ if (steps[i].status !== "pending") {
70074
+ targetIndex = i;
70075
+ break;
70076
+ }
70077
+ }
70078
+ if (targetIndex === -1) {
70079
+ await this.store.updateTask(taskId, { currentStep: 0 });
70080
+ return null;
70081
+ }
70082
+ await this.store.updateStep(taskId, targetIndex, "pending");
70083
+ await this.store.updateTask(taskId, { currentStep: targetIndex });
70084
+ return { index: targetIndex, name: steps[targetIndex].name };
70085
+ }
69970
70086
  /**
69971
70087
  * Inject or update the "Workflow Revision Instructions" section in PROMPT.md.
69972
70088
  * This section contains feedback from workflow steps that requested revisions.
69973
70089
  * The section is replaced entirely to avoid accumulation of old feedback.
69974
70090
  */
69975
- async injectWorkflowRevisionInstructions(task, feedback, scope) {
70091
+ async injectWorkflowRevisionInstructions(task, feedback) {
69976
70092
  const promptPath = join35(this.store.getFusionDir(), "tasks", task.id, "PROMPT.md");
69977
70093
  let content;
69978
70094
  try {
@@ -69981,14 +70097,7 @@ Take a different approach. Do NOT repeat the rejected strategy. Re-read the step
69981
70097
  executorLog.warn(`${task.id}: PROMPT.md not found at ${promptPath}, skipping revision injection`);
69982
70098
  return;
69983
70099
  }
69984
- let scopeLine;
69985
- if (scope && scope.targetStepName && scope.resetStart < scope.totalSteps) {
69986
- scopeLine = `Re-execution starts at **Step ${scope.resetStart + 1} ("${scope.targetStepName}")**. Earlier steps remain done \u2014 do not re-run them unless the feedback explicitly calls them out.`;
69987
- } else if (scope && scope.resetStart >= scope.totalSteps) {
69988
- scopeLine = "No steps were reset; apply the feedback as an in-place fix and call task_done() when complete.";
69989
- } else {
69990
- scopeLine = "Address the feedback above by making the necessary code changes, then mark all affected steps as done and call task_done() when complete.";
69991
- }
70100
+ const scopeLine = "All prior steps remain **done**. Apply the feedback above as an in-place fix (make the necessary code changes, commit, and call `task_done()` when complete). Do **not** re-run or re-plan any earlier step unless the feedback explicitly calls it out.";
69992
70101
  const revisionSectionHeader = "## Workflow Revision Instructions";
69993
70102
  const revisionSectionContent = `${revisionSectionHeader}
69994
70103
 
@@ -70047,11 +70156,7 @@ ${feedback}
70047
70156
  });
70048
70157
  await this.injectWorkflowStepFailureInstructions(task, failureFeedback, stepName, retryCount);
70049
70158
  const updatedTask = await this.store.getTask(task.id);
70050
- for (let i = 0; i < updatedTask.steps.length; i++) {
70051
- if (updatedTask.steps[i].status !== "pending") {
70052
- await this.store.updateStep(task.id, i, "pending");
70053
- }
70054
- }
70159
+ await this.reopenLastStepForRevision(task.id, updatedTask);
70055
70160
  await this.store.updateTask(task.id, {
70056
70161
  status: null,
70057
70162
  sessionFile: null
@@ -70095,11 +70200,7 @@ Please fix the issues so the verification can pass on the next attempt.`,
70095
70200
  );
70096
70201
  await this.injectWorkflowStepFailureInstructions(task, failureFeedback, stepName, MAX_WORKFLOW_STEP_RETRIES);
70097
70202
  const updatedTask = await this.store.getTask(taskId);
70098
- for (let i = 0; i < updatedTask.steps.length; i++) {
70099
- if (updatedTask.steps[i].status !== "pending") {
70100
- await this.store.updateStep(taskId, i, "pending");
70101
- }
70102
- }
70203
+ await this.reopenLastStepForRevision(taskId, updatedTask);
70103
70204
  await this.store.updateTask(taskId, {
70104
70205
  status: null,
70105
70206
  error: null,
@@ -75898,6 +75999,12 @@ async function getHeartbeatMemorySettings(taskStore) {
75898
75999
  }
75899
76000
  return maybeGetSettings.call(taskStore);
75900
76001
  }
76002
+ function isTickableState(state) {
76003
+ return state === "active" || state === "running";
76004
+ }
76005
+ function isHeartbeatManaged(agent) {
76006
+ return !isEphemeralAgent(agent);
76007
+ }
75901
76008
  var HEARTBEAT_SYSTEM_PROMPT, HEARTBEAT_NO_TASK_SYSTEM_PROMPT, heartbeatDoneParams, HeartbeatMonitor, HeartbeatTriggerScheduler;
75902
76009
  var init_agent_heartbeat = __esm({
75903
76010
  "../engine/src/agent-heartbeat.ts"() {
@@ -77134,10 +77241,6 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
77134
77241
  * @param config - Per-agent heartbeat config
77135
77242
  */
77136
77243
  registerAgent(agentId, config) {
77137
- if (config.enabled === false) {
77138
- heartbeatLog.log(`Skipping timer registration for ${agentId} (disabled)`);
77139
- return;
77140
- }
77141
77244
  let rawIntervalMs = config.heartbeatIntervalMs;
77142
77245
  let usingDefaultInterval = false;
77143
77246
  if (!rawIntervalMs || typeof rawIntervalMs !== "number" || !Number.isFinite(rawIntervalMs) || rawIntervalMs <= 0) {
@@ -77227,8 +77330,13 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
77227
77330
  this.assignedListener = async (agent, taskId) => {
77228
77331
  if (!this.running) return;
77229
77332
  try {
77230
- if (agent.runtimeConfig?.enabled === false) {
77231
- heartbeatLog.log(`Assignment trigger skipped for ${agent.id} (heartbeat disabled)`);
77333
+ if (!isHeartbeatManaged(agent)) {
77334
+ heartbeatLog.log(`Assignment trigger skipped for ${agent.id} (ephemeral/internal)`);
77335
+ return;
77336
+ }
77337
+ const runtimeConfig = agent.runtimeConfig ?? {};
77338
+ if (runtimeConfig.enabled === false) {
77339
+ heartbeatLog.log(`Assignment trigger skipped for ${agent.id} (disabled)`);
77232
77340
  return;
77233
77341
  }
77234
77342
  const activeRun = await this.store.getActiveHeartbeatRun(agent.id);
@@ -77297,9 +77405,21 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
77297
77405
  watchAgentLifecycle() {
77298
77406
  if (this.updatedListener || this.deletedListener) return;
77299
77407
  this.updatedListener = (agent) => {
77300
- if (agent.state === "terminated" || agent.runtimeConfig?.enabled === false) {
77408
+ if (!isHeartbeatManaged(agent) || !isTickableState(agent.state)) {
77301
77409
  this.unregisterAgent(agent.id);
77410
+ return;
77302
77411
  }
77412
+ if (this.timers.has(agent.id)) {
77413
+ return;
77414
+ }
77415
+ const rc = agent.runtimeConfig ?? {};
77416
+ this.registerAgent(agent.id, {
77417
+ heartbeatIntervalMs: rc.heartbeatIntervalMs,
77418
+ maxConcurrentRuns: rc.maxConcurrentRuns
77419
+ });
77420
+ heartbeatLog.log(
77421
+ `State-driven registration: ${agent.id} is ${agent.state} \u2014 timer armed`
77422
+ );
77303
77423
  };
77304
77424
  this.deletedListener = (agentId) => {
77305
77425
  this.unregisterAgent(agentId);
@@ -77330,8 +77450,8 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
77330
77450
  this.unregisterAgent(agentId);
77331
77451
  return;
77332
77452
  }
77333
- if (agent.state === "terminated" || agent.runtimeConfig?.enabled === false) {
77334
- heartbeatLog.log(`Timer tick skipped for ${agentId} (disabled or terminated)`);
77453
+ if (!isHeartbeatManaged(agent) || !isTickableState(agent.state)) {
77454
+ heartbeatLog.log(`Timer tick skipped for ${agentId} (state=${agent.state})`);
77335
77455
  this.unregisterAgent(agentId);
77336
77456
  return;
77337
77457
  }
@@ -77675,6 +77795,10 @@ var init_self_healing = __esm({
77675
77795
  const result = await readLog("HEAD");
77676
77796
  stdout = result.stdout;
77677
77797
  }
77798
+ if (!stdout.trim() && task.baseCommitSha) {
77799
+ const result = await readLog("HEAD");
77800
+ stdout = result.stdout;
77801
+ }
77678
77802
  const firstLine = stdout.trim().split("\n").find(Boolean);
77679
77803
  if (!firstLine) return null;
77680
77804
  const [sha, subject] = firstLine.split("");
@@ -79536,13 +79660,13 @@ var init_in_process_runtime = __esm({
79536
79660
  this.taskStore
79537
79661
  );
79538
79662
  this.triggerScheduler.start();
79663
+ const isHeartbeatEnabledAgent = (agent) => !isEphemeralAgent(agent) && agent.runtimeConfig?.enabled !== false;
79539
79664
  this.agentCreatedListener = (agent) => {
79540
79665
  if (!this.triggerScheduler) return;
79666
+ if (!isHeartbeatEnabledAgent(agent)) return;
79541
79667
  const rc = agent.runtimeConfig;
79542
- if (rc?.enabled === false) return;
79543
79668
  this.triggerScheduler.registerAgent(agent.id, {
79544
79669
  heartbeatIntervalMs: rc?.heartbeatIntervalMs,
79545
- enabled: rc?.enabled,
79546
79670
  maxConcurrentRuns: rc?.maxConcurrentRuns
79547
79671
  });
79548
79672
  runtimeLog.log(`Registered new agent ${agent.id} for heartbeat triggers`);
@@ -79550,18 +79674,17 @@ var init_in_process_runtime = __esm({
79550
79674
  this.agentStore.on("agent:created", this.agentCreatedListener);
79551
79675
  this.agentUpdatedListener = (agent) => {
79552
79676
  if (!this.triggerScheduler) return;
79553
- const rc = agent.runtimeConfig;
79554
- if (rc?.enabled === false) {
79677
+ if (!isHeartbeatEnabledAgent(agent)) {
79555
79678
  this.triggerScheduler.unregisterAgent(agent.id);
79556
- runtimeLog.log(`Unregistered agent ${agent.id} from heartbeat triggers (disabled)`);
79557
- } else {
79558
- this.triggerScheduler.registerAgent(agent.id, {
79559
- heartbeatIntervalMs: rc?.heartbeatIntervalMs,
79560
- enabled: rc?.enabled,
79561
- maxConcurrentRuns: rc?.maxConcurrentRuns
79562
- });
79563
- runtimeLog.log(`Re-registered agent ${agent.id} for heartbeat triggers`);
79679
+ runtimeLog.log(`Unregistered agent ${agent.id} from heartbeat triggers`);
79680
+ return;
79564
79681
  }
79682
+ const rc = agent.runtimeConfig;
79683
+ this.triggerScheduler.registerAgent(agent.id, {
79684
+ heartbeatIntervalMs: rc?.heartbeatIntervalMs,
79685
+ maxConcurrentRuns: rc?.maxConcurrentRuns
79686
+ });
79687
+ runtimeLog.log(`Re-registered agent ${agent.id} for heartbeat triggers`);
79565
79688
  };
79566
79689
  this.agentStore.on("agent:updated", this.agentUpdatedListener);
79567
79690
  this.ephemeralTerminationListener = (agentId, from, to) => {
@@ -79596,15 +79719,13 @@ var init_in_process_runtime = __esm({
79596
79719
  const agents = await this.agentStore.listAgents();
79597
79720
  let registeredCount = 0;
79598
79721
  for (const agent of agents) {
79722
+ if (!isHeartbeatEnabledAgent(agent)) continue;
79599
79723
  const rc = agent.runtimeConfig;
79600
- if (rc?.enabled !== false) {
79601
- this.triggerScheduler.registerAgent(agent.id, {
79602
- heartbeatIntervalMs: rc?.heartbeatIntervalMs,
79603
- enabled: rc?.enabled,
79604
- maxConcurrentRuns: rc?.maxConcurrentRuns
79605
- });
79606
- registeredCount++;
79607
- }
79724
+ this.triggerScheduler.registerAgent(agent.id, {
79725
+ heartbeatIntervalMs: rc?.heartbeatIntervalMs,
79726
+ maxConcurrentRuns: rc?.maxConcurrentRuns
79727
+ });
79728
+ registeredCount++;
79608
79729
  }
79609
79730
  if (agents.length > 0) {
79610
79731
  runtimeLog.log(`Registered ${registeredCount} of ${agents.length} agents for heartbeat triggers`);
@@ -88081,13 +88202,13 @@ var require_readdir_glob = __commonJS({
88081
88202
  "../../node_modules/.pnpm/readdir-glob@1.1.3/node_modules/readdir-glob/index.js"(exports, module) {
88082
88203
  "use strict";
88083
88204
  module.exports = readdirGlob;
88084
- var fs = __require("fs");
88205
+ var fs2 = __require("fs");
88085
88206
  var { EventEmitter: EventEmitter33 } = __require("events");
88086
88207
  var { Minimatch } = require_minimatch();
88087
88208
  var { resolve: resolve29 } = __require("path");
88088
88209
  function readdir11(dir2, strict) {
88089
88210
  return new Promise((resolve30, reject2) => {
88090
- fs.readdir(dir2, { withFileTypes: true }, (err, files) => {
88211
+ fs2.readdir(dir2, { withFileTypes: true }, (err, files) => {
88091
88212
  if (err) {
88092
88213
  switch (err.code) {
88093
88214
  case "ENOTDIR":
@@ -88120,7 +88241,7 @@ var require_readdir_glob = __commonJS({
88120
88241
  }
88121
88242
  function stat11(file, followSymlinks) {
88122
88243
  return new Promise((resolve30, reject2) => {
88123
- const statFunc = followSymlinks ? fs.stat : fs.lstat;
88244
+ const statFunc = followSymlinks ? fs2.stat : fs2.lstat;
88124
88245
  statFunc(file, (err, stats) => {
88125
88246
  if (err) {
88126
88247
  switch (err.code) {
@@ -90183,54 +90304,54 @@ var require_polyfills = __commonJS({
90183
90304
  }
90184
90305
  var chdir;
90185
90306
  module.exports = patch;
90186
- function patch(fs) {
90307
+ function patch(fs2) {
90187
90308
  if (constants2.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
90188
- patchLchmod(fs);
90189
- }
90190
- if (!fs.lutimes) {
90191
- patchLutimes(fs);
90192
- }
90193
- fs.chown = chownFix(fs.chown);
90194
- fs.fchown = chownFix(fs.fchown);
90195
- fs.lchown = chownFix(fs.lchown);
90196
- fs.chmod = chmodFix(fs.chmod);
90197
- fs.fchmod = chmodFix(fs.fchmod);
90198
- fs.lchmod = chmodFix(fs.lchmod);
90199
- fs.chownSync = chownFixSync(fs.chownSync);
90200
- fs.fchownSync = chownFixSync(fs.fchownSync);
90201
- fs.lchownSync = chownFixSync(fs.lchownSync);
90202
- fs.chmodSync = chmodFixSync(fs.chmodSync);
90203
- fs.fchmodSync = chmodFixSync(fs.fchmodSync);
90204
- fs.lchmodSync = chmodFixSync(fs.lchmodSync);
90205
- fs.stat = statFix(fs.stat);
90206
- fs.fstat = statFix(fs.fstat);
90207
- fs.lstat = statFix(fs.lstat);
90208
- fs.statSync = statFixSync(fs.statSync);
90209
- fs.fstatSync = statFixSync(fs.fstatSync);
90210
- fs.lstatSync = statFixSync(fs.lstatSync);
90211
- if (fs.chmod && !fs.lchmod) {
90212
- fs.lchmod = function(path4, mode, cb) {
90309
+ patchLchmod(fs2);
90310
+ }
90311
+ if (!fs2.lutimes) {
90312
+ patchLutimes(fs2);
90313
+ }
90314
+ fs2.chown = chownFix(fs2.chown);
90315
+ fs2.fchown = chownFix(fs2.fchown);
90316
+ fs2.lchown = chownFix(fs2.lchown);
90317
+ fs2.chmod = chmodFix(fs2.chmod);
90318
+ fs2.fchmod = chmodFix(fs2.fchmod);
90319
+ fs2.lchmod = chmodFix(fs2.lchmod);
90320
+ fs2.chownSync = chownFixSync(fs2.chownSync);
90321
+ fs2.fchownSync = chownFixSync(fs2.fchownSync);
90322
+ fs2.lchownSync = chownFixSync(fs2.lchownSync);
90323
+ fs2.chmodSync = chmodFixSync(fs2.chmodSync);
90324
+ fs2.fchmodSync = chmodFixSync(fs2.fchmodSync);
90325
+ fs2.lchmodSync = chmodFixSync(fs2.lchmodSync);
90326
+ fs2.stat = statFix(fs2.stat);
90327
+ fs2.fstat = statFix(fs2.fstat);
90328
+ fs2.lstat = statFix(fs2.lstat);
90329
+ fs2.statSync = statFixSync(fs2.statSync);
90330
+ fs2.fstatSync = statFixSync(fs2.fstatSync);
90331
+ fs2.lstatSync = statFixSync(fs2.lstatSync);
90332
+ if (fs2.chmod && !fs2.lchmod) {
90333
+ fs2.lchmod = function(path4, mode, cb) {
90213
90334
  if (cb) process.nextTick(cb);
90214
90335
  };
90215
- fs.lchmodSync = function() {
90336
+ fs2.lchmodSync = function() {
90216
90337
  };
90217
90338
  }
90218
- if (fs.chown && !fs.lchown) {
90219
- fs.lchown = function(path4, uid, gid, cb) {
90339
+ if (fs2.chown && !fs2.lchown) {
90340
+ fs2.lchown = function(path4, uid, gid, cb) {
90220
90341
  if (cb) process.nextTick(cb);
90221
90342
  };
90222
- fs.lchownSync = function() {
90343
+ fs2.lchownSync = function() {
90223
90344
  };
90224
90345
  }
90225
90346
  if (platform3 === "win32") {
90226
- fs.rename = typeof fs.rename !== "function" ? fs.rename : (function(fs$rename) {
90347
+ fs2.rename = typeof fs2.rename !== "function" ? fs2.rename : (function(fs$rename) {
90227
90348
  function rename6(from, to, cb) {
90228
90349
  var start = Date.now();
90229
90350
  var backoff = 0;
90230
90351
  fs$rename(from, to, function CB(er) {
90231
90352
  if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
90232
90353
  setTimeout(function() {
90233
- fs.stat(to, function(stater, st) {
90354
+ fs2.stat(to, function(stater, st) {
90234
90355
  if (stater && stater.code === "ENOENT")
90235
90356
  fs$rename(from, to, CB);
90236
90357
  else
@@ -90246,9 +90367,9 @@ var require_polyfills = __commonJS({
90246
90367
  }
90247
90368
  if (Object.setPrototypeOf) Object.setPrototypeOf(rename6, fs$rename);
90248
90369
  return rename6;
90249
- })(fs.rename);
90370
+ })(fs2.rename);
90250
90371
  }
90251
- fs.read = typeof fs.read !== "function" ? fs.read : (function(fs$read) {
90372
+ fs2.read = typeof fs2.read !== "function" ? fs2.read : (function(fs$read) {
90252
90373
  function read(fd, buffer, offset, length, position, callback_) {
90253
90374
  var callback;
90254
90375
  if (callback_ && typeof callback_ === "function") {
@@ -90256,22 +90377,22 @@ var require_polyfills = __commonJS({
90256
90377
  callback = function(er, _2, __) {
90257
90378
  if (er && er.code === "EAGAIN" && eagCounter < 10) {
90258
90379
  eagCounter++;
90259
- return fs$read.call(fs, fd, buffer, offset, length, position, callback);
90380
+ return fs$read.call(fs2, fd, buffer, offset, length, position, callback);
90260
90381
  }
90261
90382
  callback_.apply(this, arguments);
90262
90383
  };
90263
90384
  }
90264
- return fs$read.call(fs, fd, buffer, offset, length, position, callback);
90385
+ return fs$read.call(fs2, fd, buffer, offset, length, position, callback);
90265
90386
  }
90266
90387
  if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
90267
90388
  return read;
90268
- })(fs.read);
90269
- fs.readSync = typeof fs.readSync !== "function" ? fs.readSync : /* @__PURE__ */ (function(fs$readSync) {
90389
+ })(fs2.read);
90390
+ fs2.readSync = typeof fs2.readSync !== "function" ? fs2.readSync : /* @__PURE__ */ (function(fs$readSync) {
90270
90391
  return function(fd, buffer, offset, length, position) {
90271
90392
  var eagCounter = 0;
90272
90393
  while (true) {
90273
90394
  try {
90274
- return fs$readSync.call(fs, fd, buffer, offset, length, position);
90395
+ return fs$readSync.call(fs2, fd, buffer, offset, length, position);
90275
90396
  } catch (er) {
90276
90397
  if (er.code === "EAGAIN" && eagCounter < 10) {
90277
90398
  eagCounter++;
@@ -90281,10 +90402,10 @@ var require_polyfills = __commonJS({
90281
90402
  }
90282
90403
  }
90283
90404
  };
90284
- })(fs.readSync);
90285
- function patchLchmod(fs2) {
90286
- fs2.lchmod = function(path4, mode, callback) {
90287
- fs2.open(
90405
+ })(fs2.readSync);
90406
+ function patchLchmod(fs3) {
90407
+ fs3.lchmod = function(path4, mode, callback) {
90408
+ fs3.open(
90288
90409
  path4,
90289
90410
  constants2.O_WRONLY | constants2.O_SYMLINK,
90290
90411
  mode,
@@ -90293,80 +90414,80 @@ var require_polyfills = __commonJS({
90293
90414
  if (callback) callback(err);
90294
90415
  return;
90295
90416
  }
90296
- fs2.fchmod(fd, mode, function(err2) {
90297
- fs2.close(fd, function(err22) {
90417
+ fs3.fchmod(fd, mode, function(err2) {
90418
+ fs3.close(fd, function(err22) {
90298
90419
  if (callback) callback(err2 || err22);
90299
90420
  });
90300
90421
  });
90301
90422
  }
90302
90423
  );
90303
90424
  };
90304
- fs2.lchmodSync = function(path4, mode) {
90305
- var fd = fs2.openSync(path4, constants2.O_WRONLY | constants2.O_SYMLINK, mode);
90425
+ fs3.lchmodSync = function(path4, mode) {
90426
+ var fd = fs3.openSync(path4, constants2.O_WRONLY | constants2.O_SYMLINK, mode);
90306
90427
  var threw = true;
90307
90428
  var ret;
90308
90429
  try {
90309
- ret = fs2.fchmodSync(fd, mode);
90430
+ ret = fs3.fchmodSync(fd, mode);
90310
90431
  threw = false;
90311
90432
  } finally {
90312
90433
  if (threw) {
90313
90434
  try {
90314
- fs2.closeSync(fd);
90435
+ fs3.closeSync(fd);
90315
90436
  } catch (er) {
90316
90437
  }
90317
90438
  } else {
90318
- fs2.closeSync(fd);
90439
+ fs3.closeSync(fd);
90319
90440
  }
90320
90441
  }
90321
90442
  return ret;
90322
90443
  };
90323
90444
  }
90324
- function patchLutimes(fs2) {
90325
- if (constants2.hasOwnProperty("O_SYMLINK") && fs2.futimes) {
90326
- fs2.lutimes = function(path4, at, mt, cb) {
90327
- fs2.open(path4, constants2.O_SYMLINK, function(er, fd) {
90445
+ function patchLutimes(fs3) {
90446
+ if (constants2.hasOwnProperty("O_SYMLINK") && fs3.futimes) {
90447
+ fs3.lutimes = function(path4, at, mt, cb) {
90448
+ fs3.open(path4, constants2.O_SYMLINK, function(er, fd) {
90328
90449
  if (er) {
90329
90450
  if (cb) cb(er);
90330
90451
  return;
90331
90452
  }
90332
- fs2.futimes(fd, at, mt, function(er2) {
90333
- fs2.close(fd, function(er22) {
90453
+ fs3.futimes(fd, at, mt, function(er2) {
90454
+ fs3.close(fd, function(er22) {
90334
90455
  if (cb) cb(er2 || er22);
90335
90456
  });
90336
90457
  });
90337
90458
  });
90338
90459
  };
90339
- fs2.lutimesSync = function(path4, at, mt) {
90340
- var fd = fs2.openSync(path4, constants2.O_SYMLINK);
90460
+ fs3.lutimesSync = function(path4, at, mt) {
90461
+ var fd = fs3.openSync(path4, constants2.O_SYMLINK);
90341
90462
  var ret;
90342
90463
  var threw = true;
90343
90464
  try {
90344
- ret = fs2.futimesSync(fd, at, mt);
90465
+ ret = fs3.futimesSync(fd, at, mt);
90345
90466
  threw = false;
90346
90467
  } finally {
90347
90468
  if (threw) {
90348
90469
  try {
90349
- fs2.closeSync(fd);
90470
+ fs3.closeSync(fd);
90350
90471
  } catch (er) {
90351
90472
  }
90352
90473
  } else {
90353
- fs2.closeSync(fd);
90474
+ fs3.closeSync(fd);
90354
90475
  }
90355
90476
  }
90356
90477
  return ret;
90357
90478
  };
90358
- } else if (fs2.futimes) {
90359
- fs2.lutimes = function(_a, _b, _c, cb) {
90479
+ } else if (fs3.futimes) {
90480
+ fs3.lutimes = function(_a, _b, _c, cb) {
90360
90481
  if (cb) process.nextTick(cb);
90361
90482
  };
90362
- fs2.lutimesSync = function() {
90483
+ fs3.lutimesSync = function() {
90363
90484
  };
90364
90485
  }
90365
90486
  }
90366
90487
  function chmodFix(orig) {
90367
90488
  if (!orig) return orig;
90368
90489
  return function(target, mode, cb) {
90369
- return orig.call(fs, target, mode, function(er) {
90490
+ return orig.call(fs2, target, mode, function(er) {
90370
90491
  if (chownErOk(er)) er = null;
90371
90492
  if (cb) cb.apply(this, arguments);
90372
90493
  });
@@ -90376,7 +90497,7 @@ var require_polyfills = __commonJS({
90376
90497
  if (!orig) return orig;
90377
90498
  return function(target, mode) {
90378
90499
  try {
90379
- return orig.call(fs, target, mode);
90500
+ return orig.call(fs2, target, mode);
90380
90501
  } catch (er) {
90381
90502
  if (!chownErOk(er)) throw er;
90382
90503
  }
@@ -90385,7 +90506,7 @@ var require_polyfills = __commonJS({
90385
90506
  function chownFix(orig) {
90386
90507
  if (!orig) return orig;
90387
90508
  return function(target, uid, gid, cb) {
90388
- return orig.call(fs, target, uid, gid, function(er) {
90509
+ return orig.call(fs2, target, uid, gid, function(er) {
90389
90510
  if (chownErOk(er)) er = null;
90390
90511
  if (cb) cb.apply(this, arguments);
90391
90512
  });
@@ -90395,7 +90516,7 @@ var require_polyfills = __commonJS({
90395
90516
  if (!orig) return orig;
90396
90517
  return function(target, uid, gid) {
90397
90518
  try {
90398
- return orig.call(fs, target, uid, gid);
90519
+ return orig.call(fs2, target, uid, gid);
90399
90520
  } catch (er) {
90400
90521
  if (!chownErOk(er)) throw er;
90401
90522
  }
@@ -90415,13 +90536,13 @@ var require_polyfills = __commonJS({
90415
90536
  }
90416
90537
  if (cb) cb.apply(this, arguments);
90417
90538
  }
90418
- return options ? orig.call(fs, target, options, callback) : orig.call(fs, target, callback);
90539
+ return options ? orig.call(fs2, target, options, callback) : orig.call(fs2, target, callback);
90419
90540
  };
90420
90541
  }
90421
90542
  function statFixSync(orig) {
90422
90543
  if (!orig) return orig;
90423
90544
  return function(target, options) {
90424
- var stats = options ? orig.call(fs, target, options) : orig.call(fs, target);
90545
+ var stats = options ? orig.call(fs2, target, options) : orig.call(fs2, target);
90425
90546
  if (stats) {
90426
90547
  if (stats.uid < 0) stats.uid += 4294967296;
90427
90548
  if (stats.gid < 0) stats.gid += 4294967296;
@@ -90451,7 +90572,7 @@ var require_legacy_streams = __commonJS({
90451
90572
  "use strict";
90452
90573
  var Stream = __require("stream").Stream;
90453
90574
  module.exports = legacy;
90454
- function legacy(fs) {
90575
+ function legacy(fs2) {
90455
90576
  return {
90456
90577
  ReadStream,
90457
90578
  WriteStream
@@ -90494,7 +90615,7 @@ var require_legacy_streams = __commonJS({
90494
90615
  });
90495
90616
  return;
90496
90617
  }
90497
- fs.open(this.path, this.flags, this.mode, function(err, fd) {
90618
+ fs2.open(this.path, this.flags, this.mode, function(err, fd) {
90498
90619
  if (err) {
90499
90620
  self2.emit("error", err);
90500
90621
  self2.readable = false;
@@ -90533,7 +90654,7 @@ var require_legacy_streams = __commonJS({
90533
90654
  this.busy = false;
90534
90655
  this._queue = [];
90535
90656
  if (this.fd === null) {
90536
- this._open = fs.open;
90657
+ this._open = fs2.open;
90537
90658
  this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
90538
90659
  this.flush();
90539
90660
  }
@@ -90569,7 +90690,7 @@ var require_clone = __commonJS({
90569
90690
  var require_graceful_fs = __commonJS({
90570
90691
  "../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js"(exports, module) {
90571
90692
  "use strict";
90572
- var fs = __require("fs");
90693
+ var fs2 = __require("fs");
90573
90694
  var polyfills = require_polyfills();
90574
90695
  var legacy = require_legacy_streams();
90575
90696
  var clone = require_clone();
@@ -90601,12 +90722,12 @@ var require_graceful_fs = __commonJS({
90601
90722
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
90602
90723
  console.error(m);
90603
90724
  };
90604
- if (!fs[gracefulQueue]) {
90725
+ if (!fs2[gracefulQueue]) {
90605
90726
  queue2 = global[gracefulQueue] || [];
90606
- publishQueue(fs, queue2);
90607
- fs.close = (function(fs$close) {
90727
+ publishQueue(fs2, queue2);
90728
+ fs2.close = (function(fs$close) {
90608
90729
  function close(fd, cb) {
90609
- return fs$close.call(fs, fd, function(err) {
90730
+ return fs$close.call(fs2, fd, function(err) {
90610
90731
  if (!err) {
90611
90732
  resetQueue();
90612
90733
  }
@@ -90618,40 +90739,40 @@ var require_graceful_fs = __commonJS({
90618
90739
  value: fs$close
90619
90740
  });
90620
90741
  return close;
90621
- })(fs.close);
90622
- fs.closeSync = (function(fs$closeSync) {
90742
+ })(fs2.close);
90743
+ fs2.closeSync = (function(fs$closeSync) {
90623
90744
  function closeSync(fd) {
90624
- fs$closeSync.apply(fs, arguments);
90745
+ fs$closeSync.apply(fs2, arguments);
90625
90746
  resetQueue();
90626
90747
  }
90627
90748
  Object.defineProperty(closeSync, previousSymbol, {
90628
90749
  value: fs$closeSync
90629
90750
  });
90630
90751
  return closeSync;
90631
- })(fs.closeSync);
90752
+ })(fs2.closeSync);
90632
90753
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
90633
90754
  process.on("exit", function() {
90634
- debug(fs[gracefulQueue]);
90635
- __require("assert").equal(fs[gracefulQueue].length, 0);
90755
+ debug(fs2[gracefulQueue]);
90756
+ __require("assert").equal(fs2[gracefulQueue].length, 0);
90636
90757
  });
90637
90758
  }
90638
90759
  }
90639
90760
  var queue2;
90640
90761
  if (!global[gracefulQueue]) {
90641
- publishQueue(global, fs[gracefulQueue]);
90642
- }
90643
- module.exports = patch(clone(fs));
90644
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
90645
- module.exports = patch(fs);
90646
- fs.__patched = true;
90647
- }
90648
- function patch(fs2) {
90649
- polyfills(fs2);
90650
- fs2.gracefulify = patch;
90651
- fs2.createReadStream = createReadStream2;
90652
- fs2.createWriteStream = createWriteStream2;
90653
- var fs$readFile = fs2.readFile;
90654
- fs2.readFile = readFile24;
90762
+ publishQueue(global, fs2[gracefulQueue]);
90763
+ }
90764
+ module.exports = patch(clone(fs2));
90765
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs2.__patched) {
90766
+ module.exports = patch(fs2);
90767
+ fs2.__patched = true;
90768
+ }
90769
+ function patch(fs3) {
90770
+ polyfills(fs3);
90771
+ fs3.gracefulify = patch;
90772
+ fs3.createReadStream = createReadStream2;
90773
+ fs3.createWriteStream = createWriteStream2;
90774
+ var fs$readFile = fs3.readFile;
90775
+ fs3.readFile = readFile24;
90655
90776
  function readFile24(path4, options, cb) {
90656
90777
  if (typeof options === "function")
90657
90778
  cb = options, options = null;
@@ -90667,8 +90788,8 @@ var require_graceful_fs = __commonJS({
90667
90788
  });
90668
90789
  }
90669
90790
  }
90670
- var fs$writeFile = fs2.writeFile;
90671
- fs2.writeFile = writeFile16;
90791
+ var fs$writeFile = fs3.writeFile;
90792
+ fs3.writeFile = writeFile16;
90672
90793
  function writeFile16(path4, data, options, cb) {
90673
90794
  if (typeof options === "function")
90674
90795
  cb = options, options = null;
@@ -90684,9 +90805,9 @@ var require_graceful_fs = __commonJS({
90684
90805
  });
90685
90806
  }
90686
90807
  }
90687
- var fs$appendFile = fs2.appendFile;
90808
+ var fs$appendFile = fs3.appendFile;
90688
90809
  if (fs$appendFile)
90689
- fs2.appendFile = appendFile3;
90810
+ fs3.appendFile = appendFile3;
90690
90811
  function appendFile3(path4, data, options, cb) {
90691
90812
  if (typeof options === "function")
90692
90813
  cb = options, options = null;
@@ -90702,9 +90823,9 @@ var require_graceful_fs = __commonJS({
90702
90823
  });
90703
90824
  }
90704
90825
  }
90705
- var fs$copyFile = fs2.copyFile;
90826
+ var fs$copyFile = fs3.copyFile;
90706
90827
  if (fs$copyFile)
90707
- fs2.copyFile = copyFile;
90828
+ fs3.copyFile = copyFile;
90708
90829
  function copyFile(src, dest, flags, cb) {
90709
90830
  if (typeof flags === "function") {
90710
90831
  cb = flags;
@@ -90722,8 +90843,8 @@ var require_graceful_fs = __commonJS({
90722
90843
  });
90723
90844
  }
90724
90845
  }
90725
- var fs$readdir = fs2.readdir;
90726
- fs2.readdir = readdir11;
90846
+ var fs$readdir = fs3.readdir;
90847
+ fs3.readdir = readdir11;
90727
90848
  var noReaddirOptionVersions = /^v[0-5]\./;
90728
90849
  function readdir11(path4, options, cb) {
90729
90850
  if (typeof options === "function")
@@ -90764,21 +90885,21 @@ var require_graceful_fs = __commonJS({
90764
90885
  }
90765
90886
  }
90766
90887
  if (process.version.substr(0, 4) === "v0.8") {
90767
- var legStreams = legacy(fs2);
90888
+ var legStreams = legacy(fs3);
90768
90889
  ReadStream = legStreams.ReadStream;
90769
90890
  WriteStream = legStreams.WriteStream;
90770
90891
  }
90771
- var fs$ReadStream = fs2.ReadStream;
90892
+ var fs$ReadStream = fs3.ReadStream;
90772
90893
  if (fs$ReadStream) {
90773
90894
  ReadStream.prototype = Object.create(fs$ReadStream.prototype);
90774
90895
  ReadStream.prototype.open = ReadStream$open;
90775
90896
  }
90776
- var fs$WriteStream = fs2.WriteStream;
90897
+ var fs$WriteStream = fs3.WriteStream;
90777
90898
  if (fs$WriteStream) {
90778
90899
  WriteStream.prototype = Object.create(fs$WriteStream.prototype);
90779
90900
  WriteStream.prototype.open = WriteStream$open;
90780
90901
  }
90781
- Object.defineProperty(fs2, "ReadStream", {
90902
+ Object.defineProperty(fs3, "ReadStream", {
90782
90903
  get: function() {
90783
90904
  return ReadStream;
90784
90905
  },
@@ -90788,7 +90909,7 @@ var require_graceful_fs = __commonJS({
90788
90909
  enumerable: true,
90789
90910
  configurable: true
90790
90911
  });
90791
- Object.defineProperty(fs2, "WriteStream", {
90912
+ Object.defineProperty(fs3, "WriteStream", {
90792
90913
  get: function() {
90793
90914
  return WriteStream;
90794
90915
  },
@@ -90799,7 +90920,7 @@ var require_graceful_fs = __commonJS({
90799
90920
  configurable: true
90800
90921
  });
90801
90922
  var FileReadStream = ReadStream;
90802
- Object.defineProperty(fs2, "FileReadStream", {
90923
+ Object.defineProperty(fs3, "FileReadStream", {
90803
90924
  get: function() {
90804
90925
  return FileReadStream;
90805
90926
  },
@@ -90810,7 +90931,7 @@ var require_graceful_fs = __commonJS({
90810
90931
  configurable: true
90811
90932
  });
90812
90933
  var FileWriteStream = WriteStream;
90813
- Object.defineProperty(fs2, "FileWriteStream", {
90934
+ Object.defineProperty(fs3, "FileWriteStream", {
90814
90935
  get: function() {
90815
90936
  return FileWriteStream;
90816
90937
  },
@@ -90859,13 +90980,13 @@ var require_graceful_fs = __commonJS({
90859
90980
  });
90860
90981
  }
90861
90982
  function createReadStream2(path4, options) {
90862
- return new fs2.ReadStream(path4, options);
90983
+ return new fs3.ReadStream(path4, options);
90863
90984
  }
90864
90985
  function createWriteStream2(path4, options) {
90865
- return new fs2.WriteStream(path4, options);
90986
+ return new fs3.WriteStream(path4, options);
90866
90987
  }
90867
- var fs$open = fs2.open;
90868
- fs2.open = open;
90988
+ var fs$open = fs3.open;
90989
+ fs3.open = open;
90869
90990
  function open(path4, flags, mode, cb) {
90870
90991
  if (typeof mode === "function")
90871
90992
  cb = mode, mode = null;
@@ -90881,20 +91002,20 @@ var require_graceful_fs = __commonJS({
90881
91002
  });
90882
91003
  }
90883
91004
  }
90884
- return fs2;
91005
+ return fs3;
90885
91006
  }
90886
91007
  function enqueue(elem) {
90887
91008
  debug("ENQUEUE", elem[0].name, elem[1]);
90888
- fs[gracefulQueue].push(elem);
91009
+ fs2[gracefulQueue].push(elem);
90889
91010
  retry2();
90890
91011
  }
90891
91012
  var retryTimer;
90892
91013
  function resetQueue() {
90893
91014
  var now = Date.now();
90894
- for (var i = 0; i < fs[gracefulQueue].length; ++i) {
90895
- if (fs[gracefulQueue][i].length > 2) {
90896
- fs[gracefulQueue][i][3] = now;
90897
- fs[gracefulQueue][i][4] = now;
91015
+ for (var i = 0; i < fs2[gracefulQueue].length; ++i) {
91016
+ if (fs2[gracefulQueue][i].length > 2) {
91017
+ fs2[gracefulQueue][i][3] = now;
91018
+ fs2[gracefulQueue][i][4] = now;
90898
91019
  }
90899
91020
  }
90900
91021
  retry2();
@@ -90902,9 +91023,9 @@ var require_graceful_fs = __commonJS({
90902
91023
  function retry2() {
90903
91024
  clearTimeout(retryTimer);
90904
91025
  retryTimer = void 0;
90905
- if (fs[gracefulQueue].length === 0)
91026
+ if (fs2[gracefulQueue].length === 0)
90906
91027
  return;
90907
- var elem = fs[gracefulQueue].shift();
91028
+ var elem = fs2[gracefulQueue].shift();
90908
91029
  var fn = elem[0];
90909
91030
  var args = elem[1];
90910
91031
  var err = elem[2];
@@ -90926,7 +91047,7 @@ var require_graceful_fs = __commonJS({
90926
91047
  debug("RETRY", fn.name, args);
90927
91048
  fn.apply(null, args.concat([startTime]));
90928
91049
  } else {
90929
- fs[gracefulQueue].push(elem);
91050
+ fs2[gracefulQueue].push(elem);
90930
91051
  }
90931
91052
  }
90932
91053
  if (retryTimer === void 0) {
@@ -106119,8 +106240,8 @@ var require_commonjs4 = __commonJS({
106119
106240
  *
106120
106241
  * @internal
106121
106242
  */
106122
- constructor(cwd = process.cwd(), pathImpl, sep6, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
106123
- this.#fs = fsFromOption(fs);
106243
+ constructor(cwd = process.cwd(), pathImpl, sep6, { nocase, childrenCacheSize = 16 * 1024, fs: fs2 = defaultFS } = {}) {
106244
+ this.#fs = fsFromOption(fs2);
106124
106245
  if (cwd instanceof URL || cwd.startsWith("file://")) {
106125
106246
  cwd = (0, node_url_1.fileURLToPath)(cwd);
106126
106247
  }
@@ -106679,8 +106800,8 @@ var require_commonjs4 = __commonJS({
106679
106800
  /**
106680
106801
  * @internal
106681
106802
  */
106682
- newRoot(fs) {
106683
- return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs });
106803
+ newRoot(fs2) {
106804
+ return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs2 });
106684
106805
  }
106685
106806
  /**
106686
106807
  * Return true if the provided path string is an absolute path
@@ -106709,8 +106830,8 @@ var require_commonjs4 = __commonJS({
106709
106830
  /**
106710
106831
  * @internal
106711
106832
  */
106712
- newRoot(fs) {
106713
- return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs });
106833
+ newRoot(fs2) {
106834
+ return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs2 });
106714
106835
  }
106715
106836
  /**
106716
106837
  * Return true if the provided path string is an absolute path
@@ -107896,7 +108017,7 @@ var require_commonjs5 = __commonJS({
107896
108017
  var require_file = __commonJS({
107897
108018
  "../../node_modules/.pnpm/archiver-utils@5.0.2/node_modules/archiver-utils/file.js"(exports, module) {
107898
108019
  "use strict";
107899
- var fs = require_graceful_fs();
108020
+ var fs2 = require_graceful_fs();
107900
108021
  var path4 = __require("path");
107901
108022
  var flatten = require_flatten();
107902
108023
  var difference = require_difference();
@@ -107923,7 +108044,7 @@ var require_file = __commonJS({
107923
108044
  };
107924
108045
  file.exists = function() {
107925
108046
  var filepath = path4.join.apply(path4, arguments);
107926
- return fs.existsSync(filepath);
108047
+ return fs2.existsSync(filepath);
107927
108048
  };
107928
108049
  file.expand = function(...args) {
107929
108050
  var options = isPlainObject(args[0]) ? args.shift() : {};
@@ -107941,7 +108062,7 @@ var require_file = __commonJS({
107941
108062
  if (typeof options.filter === "function") {
107942
108063
  return options.filter(filepath);
107943
108064
  } else {
107944
- return fs.statSync(filepath)[options.filter]();
108065
+ return fs2.statSync(filepath)[options.filter]();
107945
108066
  }
107946
108067
  } catch (e) {
107947
108068
  return false;
@@ -108050,7 +108171,7 @@ var require_file = __commonJS({
108050
108171
  var require_archiver_utils = __commonJS({
108051
108172
  "../../node_modules/.pnpm/archiver-utils@5.0.2/node_modules/archiver-utils/index.js"(exports, module) {
108052
108173
  "use strict";
108053
- var fs = require_graceful_fs();
108174
+ var fs2 = require_graceful_fs();
108054
108175
  var path4 = __require("path");
108055
108176
  var isStream = require_is_stream();
108056
108177
  var lazystream = require_lazystream();
@@ -108099,7 +108220,7 @@ var require_archiver_utils = __commonJS({
108099
108220
  };
108100
108221
  utils.lazyReadStream = function(filepath) {
108101
108222
  return new lazystream.Readable(function() {
108102
- return fs.createReadStream(filepath);
108223
+ return fs2.createReadStream(filepath);
108103
108224
  });
108104
108225
  };
108105
108226
  utils.normalizeInputSource = function(source) {
@@ -108127,7 +108248,7 @@ var require_archiver_utils = __commonJS({
108127
108248
  callback = base;
108128
108249
  base = dirpath;
108129
108250
  }
108130
- fs.readdir(dirpath, function(err, list) {
108251
+ fs2.readdir(dirpath, function(err, list) {
108131
108252
  var i = 0;
108132
108253
  var file;
108133
108254
  var filepath;
@@ -108140,7 +108261,7 @@ var require_archiver_utils = __commonJS({
108140
108261
  return callback(null, results);
108141
108262
  }
108142
108263
  filepath = path4.join(dirpath, file);
108143
- fs.stat(filepath, function(err2, stats) {
108264
+ fs2.stat(filepath, function(err2, stats) {
108144
108265
  results.push({
108145
108266
  path: filepath,
108146
108267
  relative: path4.relative(base, filepath).replace(/\\/g, "/"),
@@ -108204,7 +108325,7 @@ var require_error = __commonJS({
108204
108325
  var require_core = __commonJS({
108205
108326
  "../../node_modules/.pnpm/archiver@7.0.1/node_modules/archiver/lib/core.js"(exports, module) {
108206
108327
  "use strict";
108207
- var fs = __require("fs");
108328
+ var fs2 = __require("fs");
108208
108329
  var glob2 = require_readdir_glob();
108209
108330
  var async = (init_async(), __toCommonJS(async_exports));
108210
108331
  var path4 = __require("path");
@@ -108268,7 +108389,7 @@ var require_core = __commonJS({
108268
108389
  data.sourcePath = filepath;
108269
108390
  task.data = data;
108270
108391
  this._entriesCount++;
108271
- if (data.stats && data.stats instanceof fs.Stats) {
108392
+ if (data.stats && data.stats instanceof fs2.Stats) {
108272
108393
  task = this._updateQueueTaskWithStats(task, data.stats);
108273
108394
  if (task) {
108274
108395
  if (data.stats.size) {
@@ -108439,7 +108560,7 @@ var require_core = __commonJS({
108439
108560
  callback();
108440
108561
  return;
108441
108562
  }
108442
- fs.lstat(task.filepath, function(err, stats) {
108563
+ fs2.lstat(task.filepath, function(err, stats) {
108443
108564
  if (this._state.aborted) {
108444
108565
  setImmediate(callback);
108445
108566
  return;
@@ -108482,7 +108603,7 @@ var require_core = __commonJS({
108482
108603
  task.data.sourceType = "buffer";
108483
108604
  task.source = Buffer.concat([]);
108484
108605
  } else if (stats.isSymbolicLink() && this._moduleSupports("symlink")) {
108485
- var linkPath = fs.readlinkSync(task.filepath);
108606
+ var linkPath = fs2.readlinkSync(task.filepath);
108486
108607
  var dirName = path4.dirname(task.filepath);
108487
108608
  task.data.type = "symlink";
108488
108609
  task.data.linkname = path4.relative(dirName, path4.resolve(dirName, linkPath));
@@ -121468,6 +121589,34 @@ Description: ${step.description}`
121468
121589
  rethrowAsApiError3(err);
121469
121590
  }
121470
121591
  });
121592
+ const TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "archived"]);
121593
+ function isTerminalTaskStatus(status) {
121594
+ return status !== void 0 && TERMINAL_TASK_STATUSES.has(status);
121595
+ }
121596
+ async function sanitizeAgentTaskLinks(agents, scopedStore) {
121597
+ const taskIds = [...new Set(agents.map((a) => a.taskId).filter((id) => id !== void 0))];
121598
+ const taskStatusMap = /* @__PURE__ */ new Map();
121599
+ await Promise.all(
121600
+ taskIds.map(async (taskId) => {
121601
+ try {
121602
+ const task = await scopedStore.getTask(taskId);
121603
+ if (task) {
121604
+ taskStatusMap.set(taskId, task.column);
121605
+ }
121606
+ } catch {
121607
+ }
121608
+ })
121609
+ );
121610
+ return agents.map((agent) => {
121611
+ if (!agent.taskId) return agent;
121612
+ const taskStatus = taskStatusMap.get(agent.taskId);
121613
+ if (isTerminalTaskStatus(taskStatus)) {
121614
+ const { taskId: _omitted, ...sanitized } = agent;
121615
+ return sanitized;
121616
+ }
121617
+ return agent;
121618
+ });
121619
+ }
121471
121620
  router.get("/agents", async (req, res) => {
121472
121621
  try {
121473
121622
  const filter2 = {};
@@ -121485,7 +121634,8 @@ Description: ${step.description}`
121485
121634
  const agentStore = new AgentStore2({ rootDir: scopedStore.getFusionDir() });
121486
121635
  await agentStore.init();
121487
121636
  const agents = await agentStore.listAgents(filter2);
121488
- res.json(agents);
121637
+ const sanitizedAgents = await sanitizeAgentTaskLinks(agents, scopedStore);
121638
+ res.json(sanitizedAgents);
121489
121639
  } catch (err) {
121490
121640
  if (err instanceof ApiError) {
121491
121641
  throw err;
@@ -122180,7 +122330,8 @@ ${body}`;
122180
122330
  await agentStore.init();
122181
122331
  const agents = await agentStore.listAgents();
122182
122332
  const activeCount = agents.filter((a) => a.state === "active" || a.state === "running").length;
122183
- const assignedTaskCount = agents.filter((a) => a.taskId).length;
122333
+ const sanitizedAgents = await sanitizeAgentTaskLinks(agents, scopedStore);
122334
+ const assignedTaskCount = sanitizedAgents.filter((a) => a.taskId).length;
122184
122335
  let completedRuns = 0;
122185
122336
  let failedRuns = 0;
122186
122337
  for (const agent of agents) {
@@ -122242,7 +122393,8 @@ ${body}`;
122242
122393
  if (!agent) {
122243
122394
  throw notFound("Agent not found");
122244
122395
  }
122245
- res.json(agent);
122396
+ const [sanitizedAgent] = await sanitizeAgentTaskLinks([agent], scopedStore);
122397
+ res.json(sanitizedAgent);
122246
122398
  } catch (err) {
122247
122399
  if (err instanceof ApiError) {
122248
122400
  throw err;
@@ -131577,6 +131729,9 @@ function isApiPath(path4) {
131577
131729
  return path4 === "/api" || path4.startsWith("/api/");
131578
131730
  }
131579
131731
  function getDaemonToken(options) {
131732
+ if (options?.noAuth) {
131733
+ return void 0;
131734
+ }
131580
131735
  if (options?.daemon?.token) {
131581
131736
  return options.daemon.token;
131582
131737
  }
@@ -131800,7 +131955,7 @@ function createServer(store, options) {
131800
131955
  }
131801
131956
  }
131802
131957
  }));
131803
- const daemonToken = options?.daemon?.token ?? process.env.FUSION_DAEMON_TOKEN;
131958
+ const daemonToken = options?.noAuth ? void 0 : options?.daemon?.token ?? process.env.FUSION_DAEMON_TOKEN;
131804
131959
  if (daemonToken) {
131805
131960
  app.use(createAuthMiddleware(daemonToken));
131806
131961
  }
@@ -132143,7 +132298,7 @@ function setupTerminalWebSocket(app, server, store, options) {
132143
132298
  if (pathname !== "/api/terminal/ws") {
132144
132299
  return;
132145
132300
  }
132146
- if (wsDaemonToken && !authenticateUpgradeRequest(wsDaemonToken, req)) {
132301
+ if (wsDaemonToken && !options?.noAuth && !authenticateUpgradeRequest(wsDaemonToken, req)) {
132147
132302
  socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
132148
132303
  socket.destroy();
132149
132304
  return;
@@ -132334,7 +132489,7 @@ function setupBadgeWebSocket(app, server, store, options) {
132334
132489
  if (pathname !== "/api/ws") {
132335
132490
  return;
132336
132491
  }
132337
- if (badgeWsDaemonToken && !authenticateUpgradeRequest(badgeWsDaemonToken, req)) {
132492
+ if (badgeWsDaemonToken && !options?.noAuth && !authenticateUpgradeRequest(badgeWsDaemonToken, req)) {
132338
132493
  socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
132339
132494
  socket.destroy();
132340
132495
  return;
@@ -133593,6 +133748,696 @@ var init_project_context = __esm({
133593
133748
  }
133594
133749
  });
133595
133750
 
133751
+ // src/commands/dashboard-tui.ts
133752
+ import * as readline from "node:readline";
133753
+ function moveCursorTo(x, y) {
133754
+ process.stdout.write(`\x1B[${y};${x}H`);
133755
+ }
133756
+ function clearLine() {
133757
+ process.stdout.write("\x1B[2K");
133758
+ }
133759
+ function clearScreen() {
133760
+ process.stdout.write("\x1B[2J");
133761
+ }
133762
+ function hideCursor() {
133763
+ process.stdout.write("\x1B[?25l");
133764
+ }
133765
+ function showCursor() {
133766
+ process.stdout.write("\x1B[?25h");
133767
+ }
133768
+ function enableAlternateScreen() {
133769
+ process.stdout.write("\x1B[?47h");
133770
+ }
133771
+ function disableAlternateScreen() {
133772
+ process.stdout.write("\x1B[?47l");
133773
+ }
133774
+ function colorize(text, color) {
133775
+ const colors = {
133776
+ reset: "\x1B[0m",
133777
+ bold: "\x1B[1m",
133778
+ dim: "\x1B[2m",
133779
+ red: "\x1B[31m",
133780
+ green: "\x1B[32m",
133781
+ yellow: "\x1B[33m",
133782
+ blue: "\x1B[34m",
133783
+ magenta: "\x1B[35m",
133784
+ cyan: "\x1B[36m",
133785
+ white: "\x1B[37m",
133786
+ gray: "\x1B[90m",
133787
+ brightRed: "\x1B[91m",
133788
+ brightGreen: "\x1B[92m",
133789
+ brightYellow: "\x1B[93m",
133790
+ brightBlue: "\x1B[94m",
133791
+ brightMagenta: "\x1B[95m",
133792
+ brightCyan: "\x1B[96m"
133793
+ };
133794
+ return `${colors[color] || ""}${text}${colors.reset}`;
133795
+ }
133796
+ function formatTimestamp3(date) {
133797
+ const h = date.getHours().toString().padStart(2, "0");
133798
+ const m = date.getMinutes().toString().padStart(2, "0");
133799
+ const s = date.getSeconds().toString().padStart(2, "0");
133800
+ const ms = date.getMilliseconds().toString().padStart(3, "0");
133801
+ return `${h}:${m}:${s}.${ms}`;
133802
+ }
133803
+ function formatUptime(ms) {
133804
+ const seconds = Math.floor(ms / 1e3);
133805
+ const minutes = Math.floor(seconds / 60);
133806
+ const hours = Math.floor(minutes / 60);
133807
+ const days = Math.floor(hours / 24);
133808
+ if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`;
133809
+ if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
133810
+ if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
133811
+ return `${seconds}s`;
133812
+ }
133813
+ function visibleLength(str) {
133814
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").length;
133815
+ }
133816
+ function visibleTruncate(text, maxWidth) {
133817
+ if (maxWidth <= 0) return "";
133818
+ const currentLength = visibleLength(text);
133819
+ if (currentLength <= maxWidth) return text;
133820
+ const ansiRegex = /\x1b\[[0-9;]*[a-zA-Z]/g;
133821
+ let result = "";
133822
+ let visibleCount = 0;
133823
+ let match;
133824
+ const ansiMatches = [];
133825
+ while ((match = ansiRegex.exec(text)) !== null) {
133826
+ ansiMatches.push({
133827
+ start: match.index,
133828
+ end: match.index + match[0].length,
133829
+ seq: match[0]
133830
+ });
133831
+ }
133832
+ for (let i = 0; i < text.length; i++) {
133833
+ const char = text[i];
133834
+ const ansiMatch = ansiMatches.find((m) => m.start === i);
133835
+ if (ansiMatch) {
133836
+ result += ansiMatch.seq;
133837
+ continue;
133838
+ }
133839
+ visibleCount++;
133840
+ result += char;
133841
+ if (visibleCount >= maxWidth - 3) {
133842
+ break;
133843
+ }
133844
+ }
133845
+ if (visibleCount >= maxWidth - 3 && visibleCount < currentLength) {
133846
+ result += "...";
133847
+ }
133848
+ return result;
133849
+ }
133850
+ function centerText(text, width, padChar = " ") {
133851
+ const visibleLen = visibleLength(text);
133852
+ const padding = Math.max(0, width - visibleLen);
133853
+ const leftPad = Math.floor(padding / 2);
133854
+ const rightPad = padding - leftPad;
133855
+ return padChar.repeat(leftPad) + text + padChar.repeat(rightPad);
133856
+ }
133857
+ function padRight(text, width) {
133858
+ if (width <= 0) return "";
133859
+ const visibleLen = visibleLength(text);
133860
+ return text + " ".repeat(Math.max(0, width - visibleLen));
133861
+ }
133862
+ function isTTYAvailable() {
133863
+ return Boolean(process.stdout.isTTY && process.stdin.isTTY);
133864
+ }
133865
+ var MAX_LOG_ENTRIES, LogRingBuffer, SECTION_ORDER, DashboardTUI, DashboardLogSink;
133866
+ var init_dashboard_tui = __esm({
133867
+ "src/commands/dashboard-tui.ts"() {
133868
+ "use strict";
133869
+ MAX_LOG_ENTRIES = 1e3;
133870
+ LogRingBuffer = class {
133871
+ entries = [];
133872
+ count = 0;
133873
+ push(entry) {
133874
+ if (this.entries.length < MAX_LOG_ENTRIES) {
133875
+ this.entries.push(entry);
133876
+ } else {
133877
+ this.entries[this.count % MAX_LOG_ENTRIES] = entry;
133878
+ }
133879
+ this.count++;
133880
+ }
133881
+ getAll() {
133882
+ if (this.count <= MAX_LOG_ENTRIES) {
133883
+ return this.entries.slice();
133884
+ }
133885
+ const start = this.count % MAX_LOG_ENTRIES;
133886
+ return [
133887
+ ...this.entries.slice(start),
133888
+ ...this.entries.slice(0, start)
133889
+ ];
133890
+ }
133891
+ clear() {
133892
+ this.entries = [];
133893
+ this.count = 0;
133894
+ }
133895
+ get total() {
133896
+ return this.count;
133897
+ }
133898
+ };
133899
+ SECTION_ORDER = ["logs", "system", "utilities", "stats", "settings"];
133900
+ DashboardTUI = class {
133901
+ activeSection = "logs";
133902
+ logBuffer;
133903
+ systemInfo = null;
133904
+ taskStats = null;
133905
+ settings = null;
133906
+ callbacks = null;
133907
+ isRunning = false;
133908
+ rl = null;
133909
+ originalHandlers = /* @__PURE__ */ new Map();
133910
+ lastRenderHeight = 0;
133911
+ showHelp = false;
133912
+ uptimeTimer = null;
133913
+ resizeHandler = null;
133914
+ constructor() {
133915
+ this.logBuffer = new LogRingBuffer();
133916
+ }
133917
+ // ── Public API ─────────────────────────────────────────────────────────────
133918
+ /** Returns whether the TUI is currently running */
133919
+ get running() {
133920
+ return this.isRunning;
133921
+ }
133922
+ setCallbacks(callbacks) {
133923
+ this.callbacks = callbacks;
133924
+ }
133925
+ setSystemInfo(info) {
133926
+ this.systemInfo = info;
133927
+ this.render();
133928
+ }
133929
+ setTaskStats(stats) {
133930
+ this.taskStats = stats;
133931
+ this.render();
133932
+ }
133933
+ setSettings(settings) {
133934
+ this.settings = settings;
133935
+ this.render();
133936
+ }
133937
+ addLog(entry) {
133938
+ this.logBuffer.push({
133939
+ ...entry,
133940
+ timestamp: /* @__PURE__ */ new Date()
133941
+ });
133942
+ this.render();
133943
+ }
133944
+ log(message, prefix) {
133945
+ this.addLog({ level: "info", message, prefix });
133946
+ }
133947
+ warn(message, prefix) {
133948
+ this.addLog({ level: "warn", message, prefix });
133949
+ }
133950
+ error(message, prefix) {
133951
+ this.addLog({ level: "error", message, prefix });
133952
+ }
133953
+ async start() {
133954
+ if (this.isRunning) return;
133955
+ this.isRunning = true;
133956
+ enableAlternateScreen();
133957
+ hideCursor();
133958
+ this.saveSignalHandlers();
133959
+ this.rl = readline.createInterface({
133960
+ input: process.stdin,
133961
+ output: process.stdout,
133962
+ terminal: true
133963
+ });
133964
+ process.stdin.setRawMode?.(true);
133965
+ process.stdin.resume();
133966
+ process.stdin.setEncoding("utf8");
133967
+ readline.emitKeypressEvents(process.stdin);
133968
+ process.stdin.on("keypress", (str, key) => {
133969
+ if (str) {
133970
+ this.handleKeypress(str);
133971
+ } else if (key.ctrl && key.name === "c") {
133972
+ this.handleKeypress("");
133973
+ } else if (key.name === "right") {
133974
+ this.handleKeypress("\x1B[C");
133975
+ } else if (key.name === "left") {
133976
+ this.handleKeypress("\x1B[D");
133977
+ } else if (key.name === "up") {
133978
+ this.handleKeypress("\x1B[A");
133979
+ } else if (key.name === "down") {
133980
+ this.handleKeypress("\x1B[B");
133981
+ } else if (key.name === "escape") {
133982
+ this.handleKeypress("\x1B");
133983
+ }
133984
+ });
133985
+ this.uptimeTimer = setInterval(() => {
133986
+ if (this.isRunning) {
133987
+ this.renderFooter();
133988
+ }
133989
+ }, 5e3);
133990
+ this.resizeHandler = () => {
133991
+ if (this.isRunning) {
133992
+ this.render();
133993
+ }
133994
+ };
133995
+ process.stdout.on("resize", this.resizeHandler);
133996
+ this.render();
133997
+ }
133998
+ async stop() {
133999
+ if (!this.isRunning) return;
134000
+ this.isRunning = false;
134001
+ if (this.uptimeTimer) {
134002
+ clearInterval(this.uptimeTimer);
134003
+ this.uptimeTimer = null;
134004
+ }
134005
+ if (this.resizeHandler) {
134006
+ process.stdout.off("resize", this.resizeHandler);
134007
+ this.resizeHandler = null;
134008
+ }
134009
+ this.restoreTerminal();
134010
+ this.restoreSignalHandlers();
134011
+ if (this.rl) {
134012
+ this.rl.close();
134013
+ this.rl = null;
134014
+ }
134015
+ }
134016
+ // ── Private: Signal Handling ───────────────────────────────────────────────
134017
+ saveSignalHandlers() {
134018
+ const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
134019
+ for (const sig of signals) {
134020
+ const listeners = process.listeners(sig);
134021
+ if (listeners.length > 0) {
134022
+ this.originalHandlers.set(sig, listeners[listeners.length - 1]);
134023
+ }
134024
+ }
134025
+ }
134026
+ restoreSignalHandlers() {
134027
+ for (const [sig, handler] of this.originalHandlers) {
134028
+ process.on(sig, handler);
134029
+ }
134030
+ this.originalHandlers.clear();
134031
+ }
134032
+ // ── Private: Terminal Restoration ────────────────────────────────────────
134033
+ restoreTerminal() {
134034
+ showCursor();
134035
+ disableAlternateScreen();
134036
+ process.stdout.write("\n");
134037
+ process.stdin.pause?.();
134038
+ process.stdin.setRawMode?.(false);
134039
+ }
134040
+ // ── Private: Key Handling ────────────────────────────────────────────────
134041
+ handleKeypress(key) {
134042
+ if (key === "") {
134043
+ void this.stop();
134044
+ process.exit(0);
134045
+ return;
134046
+ }
134047
+ if (key === "q" || key === "Q") {
134048
+ void this.stop();
134049
+ process.exit(0);
134050
+ return;
134051
+ }
134052
+ if (key === "?" || key === "h" || key === "H") {
134053
+ this.showHelp = !this.showHelp;
134054
+ this.render();
134055
+ return;
134056
+ }
134057
+ if (key >= "1" && key <= "5") {
134058
+ const index2 = parseInt(key, 10) - 1;
134059
+ if (index2 >= 0 && index2 < SECTION_ORDER.length) {
134060
+ this.activeSection = SECTION_ORDER[index2];
134061
+ this.showHelp = false;
134062
+ this.render();
134063
+ }
134064
+ return;
134065
+ }
134066
+ if (key === "\x1B[C" || key === "n" || key === "N") {
134067
+ const currentIndex = SECTION_ORDER.indexOf(this.activeSection);
134068
+ this.activeSection = SECTION_ORDER[(currentIndex + 1) % SECTION_ORDER.length];
134069
+ this.showHelp = false;
134070
+ this.render();
134071
+ return;
134072
+ }
134073
+ if (key === "\x1B[D" || key === "p" || key === "P") {
134074
+ const currentIndex = SECTION_ORDER.indexOf(this.activeSection);
134075
+ this.activeSection = SECTION_ORDER[(currentIndex - 1 + SECTION_ORDER.length) % SECTION_ORDER.length];
134076
+ this.showHelp = false;
134077
+ this.render();
134078
+ return;
134079
+ }
134080
+ if (this.activeSection === "utilities") {
134081
+ this.handleUtilityKeypress(key);
134082
+ }
134083
+ }
134084
+ async handleUtilityKeypress(key) {
134085
+ if (!this.callbacks) return;
134086
+ switch (key.toLowerCase()) {
134087
+ case "r":
134088
+ await this.callbacks.onRefreshStats();
134089
+ break;
134090
+ case "c":
134091
+ this.callbacks.onClearLogs();
134092
+ this.logBuffer.clear();
134093
+ this.render();
134094
+ break;
134095
+ case "t":
134096
+ if (this.systemInfo) {
134097
+ const newPaused = this.systemInfo.engineMode !== "paused";
134098
+ const newSettings = await this.callbacks.onTogglePause(newPaused);
134099
+ const newEngineMode = newSettings.enginePaused ? "paused" : "active";
134100
+ this.setSystemInfo({ ...this.systemInfo, engineMode: newEngineMode });
134101
+ this.setSettings(newSettings);
134102
+ }
134103
+ break;
134104
+ }
134105
+ }
134106
+ // ── Private: Rendering ───────────────────────────────────────────────────
134107
+ render() {
134108
+ if (!this.isRunning) return;
134109
+ clearScreen();
134110
+ moveCursorTo(1, 1);
134111
+ this.renderHeader();
134112
+ this.renderSection();
134113
+ this.renderFooter();
134114
+ if (this.showHelp) {
134115
+ this.renderHelpOverlay();
134116
+ }
134117
+ }
134118
+ renderHeader() {
134119
+ const cols = process.stdout.columns || 80;
134120
+ const title = colorize(" fn board ", "cyan");
134121
+ const titleLen = visibleLength(title);
134122
+ process.stdout.write(title);
134123
+ if (cols >= 70) {
134124
+ for (let i = 0; i < SECTION_ORDER.length; i++) {
134125
+ const section = SECTION_ORDER[i];
134126
+ const isActive = section === this.activeSection;
134127
+ const num = (i + 1).toString();
134128
+ const label = section.charAt(0).toUpperCase() + section.slice(1);
134129
+ const tabText = `[${num}] ${label}`;
134130
+ const style = isActive ? "brightBlue" : "dim";
134131
+ process.stdout.write(colorize(` ${tabText} `, style));
134132
+ }
134133
+ } else if (cols >= 40) {
134134
+ const shortLabels = {
134135
+ logs: "L",
134136
+ system: "S",
134137
+ utilities: "U",
134138
+ stats: "St",
134139
+ settings: "Se"
134140
+ };
134141
+ for (let i = 0; i < SECTION_ORDER.length; i++) {
134142
+ const section = SECTION_ORDER[i];
134143
+ const isActive = section === this.activeSection;
134144
+ const num = (i + 1).toString();
134145
+ const shortLabel = shortLabels[section];
134146
+ const tabText = `[${num}]${shortLabel}`;
134147
+ const style = isActive ? "brightBlue" : "dim";
134148
+ process.stdout.write(colorize(` ${tabText} `, style));
134149
+ }
134150
+ } else {
134151
+ const activeIndex = SECTION_ORDER.indexOf(this.activeSection);
134152
+ const activeLabel = this.activeSection.charAt(0).toUpperCase() + this.activeSection.slice(1);
134153
+ process.stdout.write(colorize(` [${activeIndex + 1}]${activeLabel} `, "brightBlue"));
134154
+ process.stdout.write(colorize(" [n/p]nav ", "dim"));
134155
+ }
134156
+ const tabsLength = SECTION_ORDER.reduce((acc, s, i) => {
134157
+ let label;
134158
+ if (cols >= 70) {
134159
+ label = s.charAt(0).toUpperCase() + s.slice(1);
134160
+ } else if (cols >= 40) {
134161
+ const shortLabels = {
134162
+ logs: "L",
134163
+ system: "S",
134164
+ utilities: "U",
134165
+ stats: "St",
134166
+ settings: "Se"
134167
+ };
134168
+ label = shortLabels[s];
134169
+ } else {
134170
+ label = s.charAt(0).toUpperCase() + s.slice(1);
134171
+ }
134172
+ const tabText = `[${i + 1}]${label} `;
134173
+ return acc + tabText.length;
134174
+ }, 0);
134175
+ const headerLen = titleLen + tabsLength;
134176
+ const remaining = cols - headerLen;
134177
+ if (remaining > 0) {
134178
+ process.stdout.write(" ".repeat(remaining));
134179
+ }
134180
+ process.stdout.write("\n");
134181
+ process.stdout.write(colorize("\u2500".repeat(Math.max(20, cols)), "dim") + "\n");
134182
+ }
134183
+ renderSection() {
134184
+ switch (this.activeSection) {
134185
+ case "logs":
134186
+ this.renderLogsSection();
134187
+ break;
134188
+ case "system":
134189
+ this.renderSystemSection();
134190
+ break;
134191
+ case "utilities":
134192
+ this.renderUtilitiesSection();
134193
+ break;
134194
+ case "stats":
134195
+ this.renderStatsSection();
134196
+ break;
134197
+ case "settings":
134198
+ this.renderSettingsSection();
134199
+ break;
134200
+ }
134201
+ }
134202
+ renderLogsSection() {
134203
+ const cols = process.stdout.columns || 80;
134204
+ const entries = this.logBuffer.getAll();
134205
+ const maxRows = Math.max(1, (process.stdout.rows ?? 38) - 8);
134206
+ process.stdout.write(colorize("\n LOGS\n", "bold"));
134207
+ process.stdout.write(colorize(` Ring buffer: ${this.logBuffer.total}/${MAX_LOG_ENTRIES} entries
134208
+
134209
+ `, "dim"));
134210
+ if (entries.length === 0) {
134211
+ process.stdout.write(colorize(" No log entries yet.\n", "dim"));
134212
+ return;
134213
+ }
134214
+ const displayEntries = entries.slice(-maxRows).reverse();
134215
+ for (const entry of displayEntries) {
134216
+ const ts = colorize(formatTimestamp3(entry.timestamp), "dim");
134217
+ const prefix = entry.prefix ? colorize(`[${entry.prefix}]`, "gray") : "";
134218
+ const levelChar = entry.level === "error" ? colorize("\u2717", "brightRed") : entry.level === "warn" ? colorize("\u26A0", "brightYellow") : colorize("\u2713", "brightGreen");
134219
+ const messageWidth = Math.max(8, cols - 40);
134220
+ const message = visibleTruncate(entry.message, messageWidth);
134221
+ const line = ` ${ts} ${levelChar} ${prefix ? prefix + " " : ""}${message}`;
134222
+ process.stdout.write(visibleTruncate(line, cols - 1) + "\n");
134223
+ }
134224
+ }
134225
+ renderSystemSection() {
134226
+ if (!this.systemInfo) {
134227
+ process.stdout.write(colorize("\n System information not available.\n", "dim"));
134228
+ return;
134229
+ }
134230
+ const cols = process.stdout.columns || 80;
134231
+ const info = this.systemInfo;
134232
+ const rows = [];
134233
+ rows.push(colorize("\n SYSTEM INFORMATION\n", "bold"));
134234
+ rows.push("");
134235
+ const labelWidth = 12;
134236
+ const availableValueWidth = Math.max(8, cols - labelWidth - 1);
134237
+ rows.push(` ${colorize("Host:", "white")} ${info.host}`);
134238
+ rows.push(` ${colorize("Port:", "white")} ${info.port}`);
134239
+ rows.push(` ${colorize("URL:", "white")} ${colorize(visibleTruncate(info.baseUrl, availableValueWidth), "brightCyan")}`);
134240
+ rows.push("");
134241
+ if (info.authEnabled) {
134242
+ rows.push(` ${colorize("Auth:", "white")} ${colorize("bearer token required", "yellow")}`);
134243
+ if (info.authToken) {
134244
+ rows.push(` ${colorize("Token:", "white")} ${visibleTruncate(info.authToken, availableValueWidth)}`);
134245
+ }
134246
+ if (info.tokenizedUrl) {
134247
+ rows.push(` ${colorize("Open:", "white")} ${visibleTruncate(info.tokenizedUrl, availableValueWidth)}`);
134248
+ rows.push(colorize(" (browser stores token, click once)", "dim"));
134249
+ }
134250
+ } else {
134251
+ rows.push(` ${colorize("Auth:", "white")} ${colorize("disabled (--no-auth)", "dim")}`);
134252
+ }
134253
+ rows.push("");
134254
+ rows.push(` ${colorize("AI Engine:", "white")} ${info.engineMode === "dev" ? colorize("\u2717 disabled (dev mode)", "yellow") : info.engineMode === "paused" ? colorize("\u23F8 paused", "brightYellow") : colorize("\u2713 active", "brightGreen")}`);
134255
+ rows.push(` ${colorize("File Watcher:", "white")} ${info.fileWatcher ? colorize("\u2713 active", "brightGreen") : colorize("\u2717 inactive", "brightRed")}`);
134256
+ rows.push(` ${colorize("Uptime:", "white")} ${formatUptime(Date.now() - info.startTimeMs)}`);
134257
+ for (const row of rows) {
134258
+ process.stdout.write(visibleTruncate(row, cols) + "\n");
134259
+ }
134260
+ }
134261
+ renderUtilitiesSection() {
134262
+ const cols = process.stdout.columns || 80;
134263
+ const actions = [
134264
+ { id: "refresh", label: "Refresh Stats", key: "r", description: "Re-fetch task and agent counts" },
134265
+ { id: "clear", label: "Clear Logs", key: "c", description: "Clear the log ring buffer" },
134266
+ { id: "pause", label: "Toggle Engine Pause", key: "t", description: "Pause/resume AI engine automation" },
134267
+ { id: "help", label: "Help", key: "?", description: "Show keyboard shortcuts" }
134268
+ ];
134269
+ process.stdout.write(colorize("\n UTILITIES\n", "bold"));
134270
+ process.stdout.write(colorize(" Press key to execute action\n\n", "dim"));
134271
+ const prefixWidth = 2 + 3 + 1 + 20 + 3;
134272
+ const descriptionWidth = Math.max(8, cols - prefixWidth - 1);
134273
+ for (const action of actions) {
134274
+ const keyDisplay = colorize(`[${action.key}]`, "brightYellow");
134275
+ const label = colorize(action.label.padEnd(20), "white");
134276
+ const description = visibleTruncate(action.description, descriptionWidth);
134277
+ const line = ` ${keyDisplay} ${label} - ${description}`;
134278
+ process.stdout.write(visibleTruncate(line, cols - 1) + "\n");
134279
+ }
134280
+ }
134281
+ renderStatsSection() {
134282
+ const cols = process.stdout.columns || 80;
134283
+ if (!this.taskStats) {
134284
+ process.stdout.write(colorize("\n Statistics not available.\n", "dim"));
134285
+ return;
134286
+ }
134287
+ const stats = this.taskStats;
134288
+ const rows = [];
134289
+ rows.push(colorize("\n STATISTICS\n", "bold"));
134290
+ rows.push("");
134291
+ rows.push(` ${colorize("Total Tasks:", "white")} ${stats.total}`);
134292
+ rows.push("");
134293
+ rows.push(` ${colorize("By Column:", "dim")}`);
134294
+ for (const [column, count] of Object.entries(stats.byColumn)) {
134295
+ const colName = column.replace("-", " ").replace(/\b\w/g, (l) => l.toUpperCase());
134296
+ const activeMark = (column === "in-progress" || column === "in-review") && count > 0 ? colorize(" \u25CF", "brightGreen") : "";
134297
+ rows.push(` ${colName}: ${count}${activeMark}`);
134298
+ }
134299
+ rows.push("");
134300
+ rows.push(` ${colorize("Active Tasks:", "white")} ${stats.active} (in-progress + in-review)`);
134301
+ rows.push("");
134302
+ rows.push(` ${colorize("Agents:", "dim")}`);
134303
+ rows.push(` Idle: ${stats.agents.idle}`);
134304
+ rows.push(` Active: ${stats.agents.active}`);
134305
+ rows.push(` Running: ${stats.agents.running}`);
134306
+ rows.push(` Error: ${stats.agents.error}`);
134307
+ for (const row of rows) {
134308
+ process.stdout.write(visibleTruncate(row, cols) + "\n");
134309
+ }
134310
+ }
134311
+ renderSettingsSection() {
134312
+ const cols = process.stdout.columns || 80;
134313
+ if (!this.settings) {
134314
+ process.stdout.write(colorize("\n Settings not available.\n", "dim"));
134315
+ return;
134316
+ }
134317
+ const s = this.settings;
134318
+ const rows = [];
134319
+ rows.push(colorize("\n SETTINGS\n", "bold"));
134320
+ rows.push("");
134321
+ const settingsList = [
134322
+ ["maxConcurrent", s.maxConcurrent.toString()],
134323
+ ["maxWorktrees", s.maxWorktrees.toString()],
134324
+ ["autoMerge", s.autoMerge ? "enabled" : "disabled"],
134325
+ ["mergeStrategy", s.mergeStrategy],
134326
+ ["pollIntervalMs", `${s.pollIntervalMs}ms`],
134327
+ ["enginePaused", s.enginePaused ? "yes" : "no"],
134328
+ ["globalPause", s.globalPause ? "yes" : "no"]
134329
+ ];
134330
+ const keyWidth = Math.max(...settingsList.map(([k]) => k.length));
134331
+ for (const [key, value] of settingsList) {
134332
+ const keyPad = key.padEnd(keyWidth);
134333
+ const isEnabled = value === "enabled" || value === "yes";
134334
+ const isDisabled = value === "disabled" || value === "no";
134335
+ const valueColor = isEnabled ? "brightGreen" : isDisabled ? "brightYellow" : "white";
134336
+ rows.push(` ${colorize(keyPad, "gray")} ${colorize(value, valueColor)}`);
134337
+ }
134338
+ for (const row of rows) {
134339
+ process.stdout.write(visibleTruncate(row, cols) + "\n");
134340
+ }
134341
+ }
134342
+ renderFooter() {
134343
+ const cols = process.stdout.columns || 80;
134344
+ const footerY = Math.max(1, (process.stdout.rows ?? 22) - 2);
134345
+ moveCursorTo(1, footerY);
134346
+ clearLine();
134347
+ const status = this.systemInfo ? `${this.systemInfo.baseUrl} | ${formatUptime(Date.now() - this.systemInfo.startTimeMs)}` : "";
134348
+ const left = colorize("Press ? for help", "dim");
134349
+ const right = colorize(visibleTruncate(status, Math.max(20, cols - 20)), "dim");
134350
+ const leftLen = visibleLength(left);
134351
+ const rightLen = visibleLength(right);
134352
+ process.stdout.write(left);
134353
+ const padding = Math.max(1, cols - leftLen - rightLen - 2);
134354
+ process.stdout.write(" ".repeat(padding));
134355
+ process.stdout.write(right);
134356
+ process.stdout.write("\n");
134357
+ }
134358
+ renderHelpOverlay() {
134359
+ const cols = process.stdout.columns || 80;
134360
+ const rows = process.stdout.rows || 24;
134361
+ const boxWidth = Math.min(62, Math.max(cols - 4, 20));
134362
+ const useBoxDrawing = cols >= boxWidth + 4;
134363
+ let helpLines;
134364
+ if (useBoxDrawing) {
134365
+ helpLines = [
134366
+ colorize("\u250C" + "\u2500".repeat(boxWidth) + "\u2510", "brightBlue"),
134367
+ colorize("\u2502" + centerText("KEYBOARD SHORTCUTS", boxWidth, " ") + "\u2502", "brightBlue"),
134368
+ colorize("\u251C" + "\u2500".repeat(boxWidth) + "\u2524", "brightBlue"),
134369
+ colorize("\u2502 [1-5] Switch to tab by number" + padRight("", boxWidth - 39) + "\u2502", "white"),
134370
+ colorize("\u2502 [n] / \u2192 Next tab" + padRight("", boxWidth - 25) + "\u2502", "white"),
134371
+ colorize("\u2502 [p] / \u2190 Previous tab" + padRight("", boxWidth - 27) + "\u2502", "white"),
134372
+ colorize("\u2502 [r] Refresh stats (Utilities)" + padRight("", boxWidth - 36) + "\u2502", "white"),
134373
+ colorize("\u2502 [c] Clear logs (Utilities)" + padRight("", boxWidth - 33) + "\u2502", "white"),
134374
+ colorize("\u2502 [t] Toggle engine pause (Utilities)" + padRight("", boxWidth - 42) + "\u2502", "white"),
134375
+ colorize("\u2502 [?] / [h] Toggle help" + padRight("", boxWidth - 24) + "\u2502", "white"),
134376
+ colorize("\u2502 [q] Quit" + padRight("", boxWidth - 15) + "\u2502", "white"),
134377
+ colorize("\u2502 [Ctrl+C] Force quit" + padRight("", boxWidth - 22) + "\u2502", "white"),
134378
+ colorize("\u2514" + "\u2500".repeat(boxWidth) + "\u2518", "brightBlue")
134379
+ ];
134380
+ } else {
134381
+ const maxLineWidth = cols - 2;
134382
+ helpLines = [
134383
+ visibleTruncate(colorize("KEYBOARD SHORTCUTS", "brightBlue"), maxLineWidth),
134384
+ visibleTruncate(colorize(" [1-5] Switch tab | [n/p] Next/Prev | [q] Quit", "white"), maxLineWidth),
134385
+ visibleTruncate(colorize(" [r] Refresh | [c] Clear logs | [t] Toggle engine", "white"), maxLineWidth),
134386
+ visibleTruncate(colorize(" [?/h] Help | [Ctrl+C] Force quit", "white"), maxLineWidth)
134387
+ ];
134388
+ }
134389
+ const compactBoxWidth = useBoxDrawing ? boxWidth : Math.max(...helpLines.map(visibleLength));
134390
+ const boxHeight = helpLines.length;
134391
+ const safeStartX = Math.max(1, Math.floor((cols - compactBoxWidth) / 2));
134392
+ const safeStartY = Math.max(1, Math.floor((rows - boxHeight) / 2));
134393
+ const clearTop = Math.max(1, safeStartY - 1);
134394
+ const clearBottom = Math.min(rows, safeStartY + boxHeight);
134395
+ for (let y = clearTop; y <= clearBottom; y++) {
134396
+ moveCursorTo(1, y);
134397
+ clearLine();
134398
+ }
134399
+ for (let i = 0; i < helpLines.length; i++) {
134400
+ moveCursorTo(safeStartX, safeStartY + i);
134401
+ process.stdout.write(helpLines[i]);
134402
+ }
134403
+ }
134404
+ };
134405
+ DashboardLogSink = class {
134406
+ tui = null;
134407
+ isTTY;
134408
+ constructor(tui) {
134409
+ this.tui = tui ?? null;
134410
+ this.isTTY = tui?.running ?? false;
134411
+ }
134412
+ setTUI(tui) {
134413
+ this.tui = tui;
134414
+ this.isTTY = true;
134415
+ }
134416
+ log(message, prefix) {
134417
+ if (this.tui && this.isTTY) {
134418
+ this.tui.log(message, prefix);
134419
+ } else {
134420
+ console.log(prefix ? `[${prefix}] ${message}` : message);
134421
+ }
134422
+ }
134423
+ warn(message, prefix) {
134424
+ if (this.tui && this.isTTY) {
134425
+ this.tui.warn(message, prefix);
134426
+ } else {
134427
+ console.warn(prefix ? `[${prefix}] ${message}` : message);
134428
+ }
134429
+ }
134430
+ error(message, prefix) {
134431
+ if (this.tui && this.isTTY) {
134432
+ this.tui.error(message, prefix);
134433
+ } else {
134434
+ console.error(prefix ? `[${prefix}] ${message}` : message);
134435
+ }
134436
+ }
134437
+ };
134438
+ }
134439
+ });
134440
+
133596
134441
  // src/commands/dashboard.ts
133597
134442
  var dashboard_exports = {};
133598
134443
  __export(dashboard_exports, {
@@ -133608,7 +134453,7 @@ function formatBytes2(bytes) {
133608
134453
  if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
133609
134454
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
133610
134455
  }
133611
- function formatUptime(ms) {
134456
+ function formatUptime2(ms) {
133612
134457
  const seconds = Math.floor(ms / 1e3);
133613
134458
  const minutes = Math.floor(seconds / 60);
133614
134459
  const hours = Math.floor(minutes / 60);
@@ -133645,7 +134490,7 @@ function logDiagnostics(prefix, startTime, dbHealthCheck) {
133645
134490
  } catch {
133646
134491
  }
133647
134492
  }
133648
- const logLine = `[${prefix}] diagnostics: uptime=${formatUptime(uptime)} rss=${formatBytes2(mem.rss)} heap=${formatBytes2(mem.heapUsed)}/${formatBytes2(mem.heapTotal)} external=${formatBytes2(mem.external)} arrayBuffers=${formatBytes2(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
134493
+ const logLine = `[${prefix}] diagnostics: uptime=${formatUptime2(uptime)} rss=${formatBytes2(mem.rss)} heap=${formatBytes2(mem.heapUsed)}/${formatBytes2(mem.heapTotal)} external=${formatBytes2(mem.external)} arrayBuffers=${formatBytes2(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
133649
134494
  console.log(logLine);
133650
134495
  }
133651
134496
  function ensureProcessDiagnostics() {
@@ -133668,11 +134513,11 @@ function ensureProcessDiagnostics() {
133668
134513
  requestCount = process._getActiveRequests?.()?.length ?? -1;
133669
134514
  } catch {
133670
134515
  }
133671
- console.log(`[dashboard] beforeExit code=${code} uptime=${formatUptime(uptime)} handles=${handleCount} requests=${requestCount}`);
134516
+ console.log(`[dashboard] beforeExit code=${code} uptime=${formatUptime2(uptime)} handles=${handleCount} requests=${requestCount}`);
133672
134517
  });
133673
134518
  process.on("exit", (code) => {
133674
134519
  const uptime = Date.now() - diagnosticStartTime;
133675
- console.log(`[dashboard] exit code=${code} uptime=${formatUptime(uptime)}`);
134520
+ console.log(`[dashboard] exit code=${code} uptime=${formatUptime2(uptime)}`);
133676
134521
  });
133677
134522
  process.on("uncaughtExceptionMonitor", (error) => {
133678
134523
  console.error(`[dashboard] uncaught exception pid=${process.pid}: ${error.stack || error.message}`);
@@ -133718,7 +134563,73 @@ async function runDashboard(port, opts = {}) {
133718
134563
  }
133719
134564
  }
133720
134565
  const cwd = await resolveRuntimeProjectPath();
133721
- const store = new TaskStore(cwd);
134566
+ const isTTY = isTTYAvailable();
134567
+ let tui;
134568
+ const dashboardStartedAt = Date.now();
134569
+ let store;
134570
+ let agentStore;
134571
+ const logSink = new DashboardLogSink();
134572
+ if (isTTY) {
134573
+ tui = new DashboardTUI();
134574
+ tui.setCallbacks({
134575
+ onRefreshStats: async () => {
134576
+ if (store && agentStore) {
134577
+ const tasks = await store.listTasks({ slim: true, includeArchived: false });
134578
+ const counts = /* @__PURE__ */ new Map();
134579
+ for (const task of tasks) {
134580
+ counts.set(task.column, (counts.get(task.column) ?? 0) + 1);
134581
+ }
134582
+ const active = tasks.filter(
134583
+ (task) => task.column === "in-progress" || task.column === "in-review"
134584
+ ).length;
134585
+ const agents = await agentStore.listAgents();
134586
+ const agentStats = { idle: 0, active: 0, running: 0, error: 0 };
134587
+ for (const agent of agents) {
134588
+ const state = agent.state;
134589
+ if (state in agentStats) {
134590
+ agentStats[state]++;
134591
+ }
134592
+ }
134593
+ tui.setTaskStats({
134594
+ total: tasks.length,
134595
+ byColumn: Object.fromEntries(counts),
134596
+ active,
134597
+ agents: agentStats
134598
+ });
134599
+ }
134600
+ },
134601
+ onClearLogs: () => {
134602
+ },
134603
+ onTogglePause: async (paused) => {
134604
+ if (store) {
134605
+ await store.updateSettings({ enginePaused: paused });
134606
+ tui.log(`Engine ${paused ? "paused" : "resumed"}`);
134607
+ const fullSettings = await store.getSettings();
134608
+ return {
134609
+ maxConcurrent: fullSettings.maxConcurrent ?? 1,
134610
+ maxWorktrees: fullSettings.maxWorktrees ?? 2,
134611
+ autoMerge: fullSettings.autoMerge ?? false,
134612
+ mergeStrategy: fullSettings.mergeStrategy ?? "direct",
134613
+ pollIntervalMs: fullSettings.pollIntervalMs ?? 6e4,
134614
+ enginePaused: fullSettings.enginePaused ?? false,
134615
+ globalPause: fullSettings.globalPause ?? false
134616
+ };
134617
+ }
134618
+ return {
134619
+ maxConcurrent: 1,
134620
+ maxWorktrees: 2,
134621
+ autoMerge: false,
134622
+ mergeStrategy: "direct",
134623
+ pollIntervalMs: 6e4,
134624
+ enginePaused: paused,
134625
+ globalPause: false
134626
+ };
134627
+ }
134628
+ });
134629
+ await tui.start();
134630
+ logSink.setTUI(tui);
134631
+ }
134632
+ store = new TaskStore(cwd);
133722
134633
  await store.init();
133723
134634
  await store.watch();
133724
134635
  setDiagnosticDbHealthCheck(() => store.healthCheck());
@@ -133730,15 +134641,78 @@ async function runDashboard(port, opts = {}) {
133730
134641
  "settings:updated": store.listenerCount("settings:updated"),
133731
134642
  "agent:log": store.listenerCount("agent:log")
133732
134643
  }));
134644
+ let tuiRefreshPending = false;
134645
+ let tuiRefreshDebounceTimer = null;
134646
+ async function refreshTUIStats() {
134647
+ if (!tui || !isTTY) return;
134648
+ if (!store || !agentStore) return;
134649
+ if (tuiRefreshPending) return;
134650
+ tuiRefreshPending = true;
134651
+ try {
134652
+ const tasks = await store.listTasks({ slim: true, includeArchived: false });
134653
+ const counts = /* @__PURE__ */ new Map();
134654
+ for (const task of tasks) {
134655
+ counts.set(task.column, (counts.get(task.column) ?? 0) + 1);
134656
+ }
134657
+ const active = tasks.filter(
134658
+ (task) => task.column === "in-progress" || task.column === "in-review"
134659
+ ).length;
134660
+ const agents = await agentStore.listAgents();
134661
+ const agentStats = { idle: 0, active: 0, running: 0, error: 0 };
134662
+ for (const agent of agents) {
134663
+ const state = agent.state;
134664
+ if (state in agentStats) {
134665
+ agentStats[state]++;
134666
+ }
134667
+ }
134668
+ tui.setTaskStats({
134669
+ total: tasks.length,
134670
+ byColumn: Object.fromEntries(counts),
134671
+ active,
134672
+ agents: agentStats
134673
+ });
134674
+ } finally {
134675
+ tuiRefreshPending = false;
134676
+ }
134677
+ }
134678
+ async function refreshTUISettings() {
134679
+ if (!tui || !isTTY) return;
134680
+ if (!store) return;
134681
+ try {
134682
+ const settings = await store.getSettings();
134683
+ tui.setSettings({
134684
+ maxConcurrent: settings.maxConcurrent ?? 1,
134685
+ maxWorktrees: settings.maxWorktrees ?? 2,
134686
+ autoMerge: settings.autoMerge ?? false,
134687
+ mergeStrategy: settings.mergeStrategy ?? "direct",
134688
+ pollIntervalMs: settings.pollIntervalMs ?? 6e4,
134689
+ enginePaused: settings.enginePaused ?? false,
134690
+ globalPause: settings.globalPause ?? false
134691
+ });
134692
+ } catch {
134693
+ }
134694
+ }
134695
+ function scheduleStatsRefresh() {
134696
+ if (tuiRefreshDebounceTimer) {
134697
+ clearTimeout(tuiRefreshDebounceTimer);
134698
+ }
134699
+ tuiRefreshDebounceTimer = setTimeout(() => {
134700
+ void refreshTUIStats();
134701
+ }, 500);
134702
+ }
133733
134703
  const handlers = [];
133734
134704
  const disposeCallbacks = [];
133735
134705
  let disposed = false;
133736
134706
  let shutdownInProgress = false;
133737
- const dashboardStartedAt = Date.now();
133738
134707
  async function logShutdownDiagnostics(reason) {
133739
134708
  const uptimeSeconds = Math.round((Date.now() - dashboardStartedAt) / 1e3);
133740
134709
  let taskSummary = "tasks=unknown";
133741
134710
  try {
134711
+ if (!store) {
134712
+ taskSummary = "tasks=unavailable (store not initialized)";
134713
+ console.log(`[dashboard] shutdown requested reason=${reason} pid=${process.pid} ppid=${process.ppid} uptime=${uptimeSeconds}s ${taskSummary}`);
134714
+ return;
134715
+ }
133742
134716
  const tasks = await store.listTasks({ slim: true, includeArchived: false });
133743
134717
  const counts = /* @__PURE__ */ new Map();
133744
134718
  for (const task of tasks) {
@@ -133762,8 +134736,20 @@ async function runDashboard(port, opts = {}) {
133762
134736
  }
133763
134737
  const automationStore = new AutomationStore(cwd);
133764
134738
  await automationStore.init();
133765
- const agentStore = new AgentStore({ rootDir: store.getFusionDir() });
134739
+ agentStore = new AgentStore({ rootDir: store.getFusionDir() });
133766
134740
  await agentStore.init();
134741
+ if (tui && isTTY) {
134742
+ registerHandler(store, "task:created", scheduleStatsRefresh);
134743
+ registerHandler(store, "task:moved", scheduleStatsRefresh);
134744
+ registerHandler(store, "task:updated", scheduleStatsRefresh);
134745
+ registerHandler(store, "task:deleted", scheduleStatsRefresh);
134746
+ registerHandler(store, "settings:updated", () => {
134747
+ void refreshTUISettings();
134748
+ });
134749
+ registerHandler(agentStore, "agent:created", scheduleStatsRefresh);
134750
+ registerHandler(agentStore, "agent:updated", scheduleStatsRefresh);
134751
+ registerHandler(agentStore, "agent:deleted", scheduleStatsRefresh);
134752
+ }
133767
134753
  const pluginStore = new PluginStore(store.getFusionDir());
133768
134754
  await pluginStore.init();
133769
134755
  const pluginLoader = new PluginLoader({
@@ -133774,7 +134760,7 @@ async function runDashboard(port, opts = {}) {
133774
134760
  let triggerScheduler;
133775
134761
  if (opts.paused) {
133776
134762
  await store.updateSettings({ enginePaused: true });
133777
- console.log("[engine] Starting in paused mode \u2014 automation disabled");
134763
+ logSink.log("Starting in paused mode \u2014 automation disabled", "engine");
133778
134764
  }
133779
134765
  const onMergeImpl = (taskId) => aiMergeTask(store, cwd, taskId, {
133780
134766
  agentStore,
@@ -133819,14 +134805,14 @@ async function runDashboard(port, opts = {}) {
133819
134805
  join48(cwd, ".fusion", "disabled-auto-extension-discovery")
133820
134806
  );
133821
134807
  for (const { path: path4, error } of extensionsResult.errors) {
133822
- console.log(`[extensions] Failed to load ${path4}: ${error}`);
134808
+ logSink.log(`Failed to load ${path4}: ${error}`, "extensions");
133823
134809
  }
133824
134810
  for (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {
133825
134811
  try {
133826
134812
  modelRegistry.registerProvider(name, config);
133827
134813
  } catch (error) {
133828
134814
  const message = error instanceof Error ? error.message : String(error);
133829
- console.log(`[extensions] Failed to register provider from ${extensionPath}: ${message}`);
134815
+ logSink.log(`Failed to register provider from ${extensionPath}: ${message}`, "extensions");
133830
134816
  }
133831
134817
  }
133832
134818
  extensionsResult.runtime.pendingProviderRegistrations = [];
@@ -133866,15 +134852,15 @@ async function runDashboard(port, opts = {}) {
133866
134852
  api: "openai-completions",
133867
134853
  models: orModels
133868
134854
  });
133869
- console.log(`[openrouter] Synced ${orModels.length} models from OpenRouter API`);
134855
+ logSink.log(`Synced ${orModels.length} models from OpenRouter API`, "openrouter");
133870
134856
  } catch (err) {
133871
134857
  const message = err instanceof Error ? err.message : String(err);
133872
- console.log(`[openrouter] Failed to sync models: ${message}`);
134858
+ logSink.log(`Failed to sync models: ${message}`, "openrouter");
133873
134859
  }
133874
134860
  })();
133875
134861
  } catch (error) {
133876
134862
  const message = error instanceof Error ? error.message : String(error);
133877
- console.log(`[extensions] Failed to discover extensions: ${message}`);
134863
+ logSink.log(`Failed to discover extensions: ${message}`, "extensions");
133878
134864
  createExtensionRuntime2();
133879
134865
  modelRegistry.refresh();
133880
134866
  }
@@ -133886,6 +134872,13 @@ async function runDashboard(port, opts = {}) {
133886
134872
  function dispose() {
133887
134873
  if (disposed) return;
133888
134874
  disposed = true;
134875
+ if (tuiRefreshDebounceTimer) {
134876
+ clearTimeout(tuiRefreshDebounceTimer);
134877
+ tuiRefreshDebounceTimer = null;
134878
+ }
134879
+ if (tui) {
134880
+ void tui.stop();
134881
+ }
133889
134882
  for (const { target, event, handler } of handlers) {
133890
134883
  target.off(event, handler);
133891
134884
  }
@@ -133953,7 +134946,8 @@ async function runDashboard(port, opts = {}) {
133953
134946
  onProjectFirstAccessed: (projectId) => engineManager.onProjectAccessed(projectId),
133954
134947
  skillsAdapter,
133955
134948
  https: loadTlsCredentialsFromEnv(),
133956
- daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0
134949
+ daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0,
134950
+ noAuth: opts.noAuth
133957
134951
  });
133958
134952
  const shutdown = async (signal) => {
133959
134953
  if (shutdownInProgress) return;
@@ -134022,10 +135016,10 @@ async function runDashboard(port, opts = {}) {
134022
135016
  taskStore: store,
134023
135017
  rootDir: cwd,
134024
135018
  onMissed: (agentId) => {
134025
- console.log(`[engine] Agent ${agentId} missed heartbeat`);
135019
+ logSink.log(`Agent ${agentId} missed heartbeat`, "engine");
134026
135020
  },
134027
135021
  onTerminated: (agentId) => {
134028
- console.log(`[engine] Agent ${agentId} terminated (unresponsive)`);
135022
+ logSink.log(`Agent ${agentId} terminated (unresponsive)`, "engine");
134029
135023
  }
134030
135024
  });
134031
135025
  heartbeatMonitorImpl.start();
@@ -134048,20 +135042,20 @@ async function runDashboard(port, opts = {}) {
134048
135042
  triggerScheduler.start();
134049
135043
  const agents = await agentStore.listAgents();
134050
135044
  for (const agent of agents) {
135045
+ if (isEphemeralAgent(agent)) continue;
135046
+ if (agent.state !== "active" && agent.state !== "running") continue;
134051
135047
  const rc = agent.runtimeConfig;
134052
- if (rc && (rc.heartbeatIntervalMs || rc.enabled !== void 0 || rc.maxConcurrentRuns)) {
134053
- triggerScheduler.registerAgent(agent.id, {
134054
- heartbeatIntervalMs: rc.heartbeatIntervalMs,
134055
- enabled: rc.enabled,
134056
- maxConcurrentRuns: rc.maxConcurrentRuns
134057
- });
134058
- }
135048
+ triggerScheduler.registerAgent(agent.id, {
135049
+ heartbeatIntervalMs: rc?.heartbeatIntervalMs,
135050
+ maxConcurrentRuns: rc?.maxConcurrentRuns
135051
+ });
134059
135052
  }
134060
135053
  if (agents.length > 0) {
134061
- console.log(`[engine] Registered ${triggerScheduler.getRegisteredAgents().length} agents for heartbeat triggers`);
135054
+ logSink.log(`Registered ${triggerScheduler.getRegisteredAgents().length} agents for heartbeat triggers`, "engine");
134062
135055
  }
134063
135056
  } catch (err) {
134064
- console.log(`[engine] HeartbeatMonitor initialization failed (continuing without agent monitoring):`, err);
135057
+ const message = err instanceof Error ? err.message : String(err);
135058
+ logSink.log(`HeartbeatMonitor initialization failed (continuing without agent monitoring): ${message}`, "engine");
134065
135059
  }
134066
135060
  app = createServer(store, {
134067
135061
  onMerge,
@@ -134094,7 +135088,8 @@ async function runDashboard(port, opts = {}) {
134094
135088
  pluginRunner: pluginLoader,
134095
135089
  skillsAdapter,
134096
135090
  https: loadTlsCredentialsFromEnv(),
134097
- daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0
135091
+ daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0,
135092
+ noAuth: opts.noAuth
134098
135093
  });
134099
135094
  }
134100
135095
  if (opts.dev) {
@@ -134196,32 +135191,89 @@ async function runDashboard(port, opts = {}) {
134196
135191
  const displayHost = selectedHost === "0.0.0.0" || selectedHost === "::" ? selectedHost : "localhost";
134197
135192
  const baseUrl = `http://${displayHost}:${actualPort}`;
134198
135193
  const tokenizedUrl = dashboardAuthToken ? `${baseUrl}/?token=${encodeURIComponent(dashboardAuthToken)}` : baseUrl;
134199
- console.log();
134200
- console.log(` fn board`);
134201
- console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
134202
- console.log(` \u2192 ${baseUrl}`);
134203
- if (dashboardAuthToken) {
134204
- console.log(` Auth: bearer token required`);
134205
- console.log(` Token: ${dashboardAuthToken}`);
134206
- console.log(` Open: ${tokenizedUrl}`);
134207
- console.log(` (the browser stores the token so you only need to click once)`);
134208
- } else {
134209
- console.log(` Auth: disabled (--no-auth)`);
134210
- }
134211
- console.log();
134212
- console.log(` Tasks stored in .fusion/tasks/`);
134213
- console.log(` Merge: AI-assisted (conflict resolution + commit messages)`);
134214
- if (opts.dev) {
134215
- console.log(` AI engine: \u2717 disabled (dev mode)`);
135194
+ if (isTTY && tui) {
135195
+ const settings = await store.getSettings();
135196
+ const engineMode = opts.dev ? "dev" : settings.enginePaused ? "paused" : "active";
135197
+ const systemInfo = {
135198
+ host: displayHost,
135199
+ port: actualPort,
135200
+ baseUrl,
135201
+ authEnabled: Boolean(dashboardAuthToken),
135202
+ authToken: dashboardAuthToken,
135203
+ tokenizedUrl: dashboardAuthToken ? tokenizedUrl : void 0,
135204
+ engineMode,
135205
+ fileWatcher: true,
135206
+ startTimeMs: dashboardStartedAt
135207
+ };
135208
+ tui.setSystemInfo(systemInfo);
135209
+ tui.setSettings({
135210
+ maxConcurrent: settings.maxConcurrent ?? 1,
135211
+ maxWorktrees: settings.maxWorktrees ?? 2,
135212
+ autoMerge: settings.autoMerge ?? false,
135213
+ mergeStrategy: settings.mergeStrategy ?? "direct",
135214
+ pollIntervalMs: settings.pollIntervalMs ?? 6e4,
135215
+ enginePaused: settings.enginePaused ?? false,
135216
+ globalPause: settings.globalPause ?? false
135217
+ });
135218
+ const tasks = await store.listTasks({ slim: true, includeArchived: false });
135219
+ const counts = /* @__PURE__ */ new Map();
135220
+ for (const task of tasks) {
135221
+ counts.set(task.column, (counts.get(task.column) ?? 0) + 1);
135222
+ }
135223
+ const active = tasks.filter(
135224
+ (task) => task.column === "in-progress" || task.column === "in-review"
135225
+ ).length;
135226
+ const agents = await agentStore.listAgents();
135227
+ const agentStats = { idle: 0, active: 0, running: 0, error: 0 };
135228
+ for (const agent of agents) {
135229
+ const state = agent.state;
135230
+ if (state in agentStats) {
135231
+ agentStats[state]++;
135232
+ }
135233
+ }
135234
+ tui.setTaskStats({
135235
+ total: tasks.length,
135236
+ byColumn: Object.fromEntries(counts),
135237
+ active,
135238
+ agents: agentStats
135239
+ });
135240
+ tui.log(`Dashboard started at ${baseUrl}`);
135241
+ if (engineMode === "active") {
135242
+ tui.log("AI engine active");
135243
+ } else if (engineMode === "dev") {
135244
+ tui.log("AI engine disabled (dev mode)");
135245
+ } else {
135246
+ tui.log("AI engine paused");
135247
+ }
135248
+ tui.log("File watcher active");
134216
135249
  } else {
134217
- console.log(` AI engine: \u2713 active`);
134218
- console.log(` \u2022 triage: auto-specifying tasks`);
134219
- console.log(` \u2022 scheduler: dependency-aware execution`);
134220
- console.log(` \u2022 cron: scheduled task execution`);
135250
+ console.log();
135251
+ console.log(` fn board`);
135252
+ console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
135253
+ console.log(` \u2192 ${baseUrl}`);
135254
+ if (dashboardAuthToken) {
135255
+ console.log(` Auth: bearer token required`);
135256
+ console.log(` Token: ${dashboardAuthToken}`);
135257
+ console.log(` Open: ${tokenizedUrl}`);
135258
+ console.log(` (the browser stores the token so you only need to click once)`);
135259
+ } else {
135260
+ console.log(` Auth: disabled (--no-auth)`);
135261
+ }
135262
+ console.log();
135263
+ console.log(` Tasks stored in .fusion/tasks/`);
135264
+ console.log(` Merge: AI-assisted (conflict resolution + commit messages)`);
135265
+ if (opts.dev) {
135266
+ console.log(` AI engine: \u2717 disabled (dev mode)`);
135267
+ } else {
135268
+ console.log(` AI engine: \u2713 active`);
135269
+ console.log(` \u2022 triage: auto-specifying tasks`);
135270
+ console.log(` \u2022 scheduler: dependency-aware execution`);
135271
+ console.log(` \u2022 cron: scheduled task execution`);
135272
+ }
135273
+ console.log(` File watcher: \u2713 active`);
135274
+ console.log(` Press Ctrl+C to stop`);
135275
+ console.log();
134221
135276
  }
134222
- console.log(` File watcher: \u2713 active`);
134223
- console.log(` Press Ctrl+C to stop`);
134224
- console.log();
134225
135277
  });
134226
135278
  return { dispose };
134227
135279
  }
@@ -134238,6 +135290,7 @@ var init_dashboard = __esm({
134238
135290
  init_provider_auth();
134239
135291
  init_auth_paths2();
134240
135292
  init_project_context();
135293
+ init_dashboard_tui();
134241
135294
  processDiagnosticsRegistered = false;
134242
135295
  diagnosticIntervalHandle = null;
134243
135296
  DIAGNOSTIC_INTERVAL_MS = 30 * 60 * 1e3;
@@ -134254,7 +135307,7 @@ __export(node_exports, {
134254
135307
  formatBytes: () => formatBytes3,
134255
135308
  formatLastActivity: () => formatLastActivity,
134256
135309
  formatStatusBar: () => formatStatusBar,
134257
- formatUptime: () => formatUptime2,
135310
+ formatUptime: () => formatUptime3,
134258
135311
  isValidNodeName: () => isValidNodeName,
134259
135312
  maskApiKey: () => maskApiKey,
134260
135313
  runMeshStatus: () => runMeshStatus,
@@ -134267,7 +135320,7 @@ __export(node_exports, {
134267
135320
  runNodeRemove: () => runNodeRemove,
134268
135321
  runNodeShow: () => runNodeShow
134269
135322
  });
134270
- import { createInterface as createInterface2 } from "node:readline/promises";
135323
+ import { createInterface as createInterface3 } from "node:readline/promises";
134271
135324
  function maskApiKey(key) {
134272
135325
  if (!key) return "none";
134273
135326
  if (key.length < 4) return "****";
@@ -134284,7 +135337,7 @@ function formatBytes3(bytes) {
134284
135337
  if (value >= 10) return `${value.toFixed(1)} ${units[i]}`;
134285
135338
  return `${value.toFixed(2)} ${units[i]}`;
134286
135339
  }
134287
- function formatUptime2(ms) {
135340
+ function formatUptime3(ms) {
134288
135341
  if (ms < 0) return "0s";
134289
135342
  const seconds = Math.floor(ms / 1e3);
134290
135343
  const minutes = Math.floor(seconds / 60);
@@ -134462,7 +135515,7 @@ async function runNodeDisconnect(name, options = {}) {
134462
135515
  process.exit(1);
134463
135516
  }
134464
135517
  if (!options.force) {
134465
- const rl = createInterface2({ input: process.stdin, output: process.stdout });
135518
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
134466
135519
  const answer = await rl.question(`Disconnect node '${node.name}'? [y/N] `);
134467
135520
  rl.close();
134468
135521
  if (answer.trim().toLowerCase() !== "y") {
@@ -134532,7 +135585,7 @@ async function runNodeShow(name, options = {}) {
134532
135585
  console.log(` CPU Usage: ${formatStatusBar(metrics.cpuUsage)}`);
134533
135586
  console.log(` Memory: ${formatBytes3(metrics.memoryUsed)} / ${formatBytes3(metrics.memoryTotal)}`);
134534
135587
  console.log(` Storage: ${formatBytes3(metrics.storageUsed)} / ${formatBytes3(metrics.storageTotal)}`);
134535
- console.log(` Uptime: ${formatUptime2(metrics.uptime)}`);
135588
+ console.log(` Uptime: ${formatUptime3(metrics.uptime)}`);
134536
135589
  console.log(` Reported: ${formatLastActivity(metrics.reportedAt)}`);
134537
135590
  } else {
134538
135591
  console.log();
@@ -134688,7 +135741,7 @@ function formatBytes4(bytes) {
134688
135741
  if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
134689
135742
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
134690
135743
  }
134691
- function formatUptime3(ms) {
135744
+ function formatUptime4(ms) {
134692
135745
  const seconds = Math.floor(ms / 1e3);
134693
135746
  const minutes = Math.floor(seconds / 60);
134694
135747
  const hours = Math.floor(minutes / 60);
@@ -134723,7 +135776,7 @@ function logDiagnostics2(prefix, dbHealthCheck) {
134723
135776
  } catch {
134724
135777
  }
134725
135778
  }
134726
- const logLine = `[${prefix}] diagnostics: uptime=${formatUptime3(uptime)} rss=${formatBytes4(mem.rss)} heap=${formatBytes4(mem.heapUsed)}/${formatBytes4(mem.heapTotal)} external=${formatBytes4(mem.external)} arrayBuffers=${formatBytes4(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
135779
+ const logLine = `[${prefix}] diagnostics: uptime=${formatUptime4(uptime)} rss=${formatBytes4(mem.rss)} heap=${formatBytes4(mem.heapUsed)}/${formatBytes4(mem.heapTotal)} external=${formatBytes4(mem.external)} arrayBuffers=${formatBytes4(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}${listenerInfo}`;
134727
135780
  console.log(logLine);
134728
135781
  }
134729
135782
  function stopDiagnosticInterval2() {
@@ -134750,11 +135803,11 @@ function ensureProcessDiagnostics2() {
134750
135803
  requestCount = process._getActiveRequests?.()?.length ?? -1;
134751
135804
  } catch {
134752
135805
  }
134753
- console.log(`[serve] beforeExit code=${code} uptime=${formatUptime3(uptime)} handles=${handleCount} requests=${requestCount}`);
135806
+ console.log(`[serve] beforeExit code=${code} uptime=${formatUptime4(uptime)} handles=${handleCount} requests=${requestCount}`);
134754
135807
  });
134755
135808
  process.on("exit", (code) => {
134756
135809
  const uptime = Date.now() - serveStartTime;
134757
- console.log(`[serve] exit code=${code} uptime=${formatUptime3(uptime)}`);
135810
+ console.log(`[serve] exit code=${code} uptime=${formatUptime4(uptime)}`);
134758
135811
  });
134759
135812
  process.on("uncaughtExceptionMonitor", (error) => {
134760
135813
  console.error(`[serve] uncaught exception pid=${process.pid}: ${error.stack || error.message}`);
@@ -135189,7 +136242,7 @@ function formatBytes5(bytes) {
135189
136242
  if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}MB`;
135190
136243
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
135191
136244
  }
135192
- function formatUptime4(ms) {
136245
+ function formatUptime5(ms) {
135193
136246
  const seconds = Math.floor(ms / 1e3);
135194
136247
  const minutes = Math.floor(seconds / 60);
135195
136248
  const hours = Math.floor(minutes / 60);
@@ -135217,7 +136270,7 @@ function logDiagnostics3(dbHealthCheck) {
135217
136270
  dbHealth = "error";
135218
136271
  }
135219
136272
  }
135220
- const logLine = `[daemon] diagnostics: uptime=${formatUptime4(uptime)} rss=${formatBytes5(mem.rss)} heap=${formatBytes5(mem.heapUsed)}/${formatBytes5(mem.heapTotal)} external=${formatBytes5(mem.external)} arrayBuffers=${formatBytes5(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}`;
136273
+ const logLine = `[daemon] diagnostics: uptime=${formatUptime5(uptime)} rss=${formatBytes5(mem.rss)} heap=${formatBytes5(mem.heapUsed)}/${formatBytes5(mem.heapTotal)} external=${formatBytes5(mem.external)} arrayBuffers=${formatBytes5(mem.arrayBuffers)} handles=${handleCount} requests=${requestCount} db=${dbHealth}`;
135221
136274
  console.log(logLine);
135222
136275
  }
135223
136276
  function maskToken(token) {
@@ -135560,7 +136613,7 @@ __export(desktop_exports, {
135560
136613
  import { spawn as spawn4 } from "node:child_process";
135561
136614
  import { once as once2 } from "node:events";
135562
136615
  import { join as join51 } from "node:path";
135563
- import { createRequire } from "node:module";
136616
+ import { createRequire as createRequire2 } from "node:module";
135564
136617
  function runCommand(command, args, cwd) {
135565
136618
  return new Promise((resolve29, reject2) => {
135566
136619
  const child = spawn4(command, args, {
@@ -135623,7 +136676,7 @@ function resolveElectronBinary() {
135623
136676
  if (process.env.FUSION_ELECTRON_BINARY) {
135624
136677
  return process.env.FUSION_ELECTRON_BINARY;
135625
136678
  }
135626
- return require2("electron");
136679
+ return require3("electron");
135627
136680
  }
135628
136681
  function terminateProcess(child, signal = "SIGTERM") {
135629
136682
  if (!child || child.killed) {
@@ -135681,13 +136734,13 @@ async function runDesktop(options = {}) {
135681
136734
  void shutdown(code ?? 0);
135682
136735
  });
135683
136736
  }
135684
- var require2;
136737
+ var require3;
135685
136738
  var init_desktop = __esm({
135686
136739
  "src/commands/desktop.ts"() {
135687
136740
  "use strict";
135688
136741
  init_src();
135689
136742
  init_src3();
135690
- require2 = createRequire(import.meta.url);
136743
+ require3 = createRequire2(import.meta.url);
135691
136744
  }
135692
136745
  });
135693
136746
 
@@ -135720,7 +136773,7 @@ __export(task_exports, {
135720
136773
  runTaskUnpause: () => runTaskUnpause,
135721
136774
  runTaskUpdate: () => runTaskUpdate
135722
136775
  });
135723
- import { createInterface as createInterface3 } from "node:readline/promises";
136776
+ import { createInterface as createInterface4 } from "node:readline/promises";
135724
136777
  import { watchFile, unwatchFile, statSync as statSync7, existsSync as existsSync35, readFileSync as readFileSync14 } from "node:fs";
135725
136778
  import { join as join52 } from "node:path";
135726
136779
  function asLocalProjectContext(store) {
@@ -135789,7 +136842,7 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName)
135789
136842
  let description = descriptionArg;
135790
136843
  const projectContext = await getProjectContext(projectName);
135791
136844
  if (!description) {
135792
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
136845
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
135793
136846
  description = await rl.question("Task description: ");
135794
136847
  rl.close();
135795
136848
  }
@@ -135890,11 +136943,11 @@ async function runTaskLog(id, message, outcome, projectName) {
135890
136943
  console.log(` \u2713 ${id}: logged "${message}"`);
135891
136944
  console.log();
135892
136945
  }
135893
- function formatTimestamp3(timestamp) {
136946
+ function formatTimestamp4(timestamp) {
135894
136947
  return new Date(timestamp).toLocaleTimeString();
135895
136948
  }
135896
136949
  function formatLogEntry(entry) {
135897
- const ts = formatTimestamp3(entry.timestamp);
136950
+ const ts = formatTimestamp4(entry.timestamp);
135898
136951
  const agent = entry.agent ? `[${entry.agent.toUpperCase()}] ` : "";
135899
136952
  switch (entry.type) {
135900
136953
  case "text":
@@ -136126,7 +137179,7 @@ async function runTaskRefine(id, feedbackArg, projectName) {
136126
137179
  const store = await getStore(projectName);
136127
137180
  let feedback = feedbackArg;
136128
137181
  if (feedback === void 0) {
136129
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137182
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136130
137183
  feedback = await rl.question("What needs to be refined? ");
136131
137184
  rl.close();
136132
137185
  }
@@ -136198,7 +137251,7 @@ async function runTaskDelete(id, force, projectName) {
136198
137251
  return;
136199
137252
  }
136200
137253
  if (!force) {
136201
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137254
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136202
137255
  const answer = await rl.question(`Are you sure you want to delete ${id}? [y/N] `);
136203
137256
  rl.close();
136204
137257
  const trimmed = answer.trim().toLowerCase();
@@ -136262,7 +137315,7 @@ async function runTaskImportGitHubInteractive(ownerRepo, options = {}, projectNa
136262
137315
  console.log(` ${i + 1}. #${issue.number} ${issue.title.slice(0, 80)}${issue.title.length > 80 ? "\u2026" : ""}${status}`);
136263
137316
  }
136264
137317
  console.log();
136265
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137318
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136266
137319
  let selectedIndices = [];
136267
137320
  let validInput = false;
136268
137321
  while (!validInput) {
@@ -136405,7 +137458,7 @@ async function runTaskComment(id, message, author = "user", projectName) {
136405
137458
  const store = await getStore(projectName);
136406
137459
  let text = message;
136407
137460
  if (text === void 0) {
136408
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137461
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136409
137462
  text = await rl.question("Comment: ");
136410
137463
  rl.close();
136411
137464
  }
@@ -136448,7 +137501,7 @@ async function runTaskSteer(id, message, projectName) {
136448
137501
  const store = await getStore(projectName);
136449
137502
  let text = message;
136450
137503
  if (text === void 0) {
136451
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137504
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136452
137505
  text = await rl.question("Message: ");
136453
137506
  rl.close();
136454
137507
  }
@@ -136578,7 +137631,7 @@ async function promptText(question) {
136578
137631
  console.log(` ${question.description}`);
136579
137632
  }
136580
137633
  console.log(" (Enter your response. Type DONE on its own line when finished):\n");
136581
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137634
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136582
137635
  const lines = [];
136583
137636
  return new Promise((resolve29) => {
136584
137637
  const askLine = () => {
@@ -136612,7 +137665,7 @@ async function promptSingleSelect(question) {
136612
137665
  console.log(` ${opt.description}`);
136613
137666
  }
136614
137667
  }
136615
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137668
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136616
137669
  while (true) {
136617
137670
  const answer = await rl.question("\n Select (1-" + question.options.length + "): ");
136618
137671
  const num = parseInt(answer.trim(), 10);
@@ -136640,7 +137693,7 @@ async function promptMultiSelect(question) {
136640
137693
  console.log(` ${opt.description}`);
136641
137694
  }
136642
137695
  }
136643
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137696
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136644
137697
  while (true) {
136645
137698
  const answer = await rl.question("\n Select (comma-separated): ");
136646
137699
  const nums = answer.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n));
@@ -136663,7 +137716,7 @@ async function promptConfirm(question) {
136663
137716
  if (question.description) {
136664
137717
  console.log(` ${question.description}`);
136665
137718
  }
136666
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137719
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136667
137720
  const answer = await rl.question("\n [Y/n]: ");
136668
137721
  rl.close();
136669
137722
  const trimmed = answer.trim().toLowerCase();
@@ -136728,7 +137781,7 @@ function wrapText(text, width) {
136728
137781
  async function runTaskPlan(initialPlanArg, yesFlag = false, projectName) {
136729
137782
  let initialPlan = initialPlanArg;
136730
137783
  if (!initialPlan) {
136731
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137784
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136732
137785
  console.log("\n Let's plan your task. What would you like to accomplish?\n");
136733
137786
  initialPlan = await rl.question(" Describe your idea: ");
136734
137787
  rl.close();
@@ -136829,7 +137882,7 @@ async function runTaskPlan(initialPlanArg, yesFlag = false, projectName) {
136829
137882
  displaySummary(result.data);
136830
137883
  let confirmed = yesFlag;
136831
137884
  if (!yesFlag) {
136832
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
137885
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
136833
137886
  const answer = await rl.question(" Create this task? [Y/n]: ");
136834
137887
  rl.close();
136835
137888
  const trimmed = answer.trim().toLowerCase();
@@ -137313,7 +138366,7 @@ __export(git_exports, {
137313
138366
  });
137314
138367
  import { exec as exec10 } from "node:child_process";
137315
138368
  import { promisify as promisify12 } from "node:util";
137316
- import { createInterface as createInterface4 } from "node:readline/promises";
138369
+ import { createInterface as createInterface5 } from "node:readline/promises";
137317
138370
  async function resolveGitCwd(projectName) {
137318
138371
  if (projectName) {
137319
138372
  return (await resolveProject(projectName)).projectPath;
@@ -137501,7 +138554,7 @@ async function runGitPull(options = {}) {
137501
138554
  console.log();
137502
138555
  console.log(" \u26A0 Warning: You have uncommitted changes.");
137503
138556
  console.log(` Branch: ${status.branch}`);
137504
- const rl = createInterface4({ input: process.stdin, output: process.stdout });
138557
+ const rl = createInterface5({ input: process.stdin, output: process.stdout });
137505
138558
  const answer = await rl.question(" Continue with pull? [y/N] ");
137506
138559
  rl.close();
137507
138560
  const trimmed = answer.trim().toLowerCase();
@@ -137552,7 +138605,7 @@ async function runGitPush(options = {}) {
137552
138605
  }
137553
138606
  if (!options.skipConfirm) {
137554
138607
  console.log();
137555
- const rl = createInterface4({ input: process.stdin, output: process.stdout });
138608
+ const rl = createInterface5({ input: process.stdin, output: process.stdout });
137556
138609
  const answer = await rl.question(` Push branch ${status.branch} to remote? [Y/n] `);
137557
138610
  rl.close();
137558
138611
  const trimmed = answer.trim().toLowerCase();
@@ -137689,7 +138742,7 @@ var init_backup2 = __esm({
137689
138742
  // src/project-resolver.ts
137690
138743
  import { existsSync as existsSync37, statSync as statSync8 } from "node:fs";
137691
138744
  import { dirname as dirname18, resolve as resolve24, normalize as normalize4 } from "node:path";
137692
- import { createInterface as createInterface5 } from "node:readline/promises";
138745
+ import { createInterface as createInterface6 } from "node:readline/promises";
137693
138746
  async function getCentralCore() {
137694
138747
  if (!centralCoreInstance) {
137695
138748
  centralCoreInstance = new CentralCore();
@@ -137720,7 +138773,7 @@ function findKbDir(startPath) {
137720
138773
  return null;
137721
138774
  }
137722
138775
  async function promptProjectSelection(projects, message = "Select a project:") {
137723
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
138776
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
137724
138777
  console.log(`
137725
138778
  ${message}`);
137726
138779
  for (let i = 0; i < projects.length; i++) {
@@ -137737,7 +138790,7 @@ async function promptProjectSelection(projects, message = "Select a project:") {
137737
138790
  }
137738
138791
  }
137739
138792
  async function promptConfirm2(message, defaultYes = false) {
137740
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
138793
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
137741
138794
  const prompt = defaultYes ? "[Y/n]" : "[y/N]";
137742
138795
  const answer = await rl.question(` ${message} ${prompt}: `);
137743
138796
  rl.close();
@@ -137797,7 +138850,7 @@ Run \`fn project remove ` + match.name + "` to clean up the registry entry.",
137797
138850
  Found fn project at ${kbDir} but it's not registered.`);
137798
138851
  const shouldRegister = await promptConfirm2("Register this project now?", true);
137799
138852
  if (shouldRegister) {
137800
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
138853
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
137801
138854
  const defaultName = kbDir.split("/").pop() || "unnamed";
137802
138855
  const name = await rl.question(` Project name [${defaultName}]: `);
137803
138856
  rl.close();
@@ -137958,12 +139011,12 @@ __export(mission_exports, {
137958
139011
  runMissionShow: () => runMissionShow,
137959
139012
  runSliceAdd: () => runSliceAdd
137960
139013
  });
137961
- import { createInterface as createInterface6 } from "node:readline/promises";
139014
+ import { createInterface as createInterface7 } from "node:readline/promises";
137962
139015
  async function promptForTitleAndDescription(titleArg, titlePrompt, descriptionPrompt) {
137963
139016
  let title = titleArg;
137964
139017
  let description;
137965
139018
  if (!title) {
137966
- const rl = createInterface6({ input: process.stdin, output: process.stdout });
139019
+ const rl = createInterface7({ input: process.stdin, output: process.stdout });
137967
139020
  title = await rl.question(titlePrompt);
137968
139021
  if (!title?.trim()) {
137969
139022
  rl.close();
@@ -138092,7 +139145,7 @@ async function runMissionDelete(id, force, projectName) {
138092
139145
  process.exit(1);
138093
139146
  }
138094
139147
  if (!force) {
138095
- const rl = createInterface6({ input: process.stdin, output: process.stdout });
139148
+ const rl = createInterface7({ input: process.stdin, output: process.stdout });
138096
139149
  const answer = await rl.question(`Are you sure you want to delete ${id}: "${mission.title}"? [y/N] `);
138097
139150
  rl.close();
138098
139151
  const trimmed = answer.trim().toLowerCase();
@@ -138193,7 +139246,7 @@ async function runFeatureAdd(sliceId, titleArg, descriptionArg, acceptanceCriter
138193
139246
  let description = descriptionArg?.trim() || void 0;
138194
139247
  let acceptanceCriteria = acceptanceCriteriaArg?.trim() || void 0;
138195
139248
  if (!title) {
138196
- const rl = createInterface6({ input: process.stdin, output: process.stdout });
139249
+ const rl = createInterface7({ input: process.stdin, output: process.stdout });
138197
139250
  title = await rl.question("Feature title: ");
138198
139251
  if (!title?.trim()) {
138199
139252
  rl.close();
@@ -138287,7 +139340,7 @@ __export(project_exports, {
138287
139340
  });
138288
139341
  import { resolve as resolve25, isAbsolute as isAbsolute13, relative as relative11, basename as basename11 } from "node:path";
138289
139342
  import { existsSync as existsSync38, statSync as statSync9 } from "node:fs";
138290
- import { createInterface as createInterface7 } from "node:readline/promises";
139343
+ import { createInterface as createInterface8 } from "node:readline/promises";
138291
139344
  function formatDisplayPath(projectPath) {
138292
139345
  const rel = relative11(process.cwd(), projectPath);
138293
139346
  if (rel && !rel.startsWith("..") && rel !== "") {
@@ -138408,7 +139461,7 @@ async function runProjectAdd(name, path4, options = {}) {
138408
139461
  let projectName = name;
138409
139462
  let projectPath = path4;
138410
139463
  if (!projectName || !projectPath || options.interactive) {
138411
- const rl = createInterface7({ input: process.stdin, output: process.stdout });
139464
+ const rl = createInterface8({ input: process.stdin, output: process.stdout });
138412
139465
  if (!projectPath) {
138413
139466
  const defaultPath = process.cwd();
138414
139467
  const pathInput = await rl.question(` Project path [${defaultPath}]: `);
@@ -138533,7 +139586,7 @@ async function runProjectRemove(name, options = {}) {
138533
139586
  process.exit(1);
138534
139587
  }
138535
139588
  if (!options.force) {
138536
- const rl = createInterface7({ input: process.stdin, output: process.stdout });
139589
+ const rl = createInterface8({ input: process.stdin, output: process.stdout });
138537
139590
  const answer = await rl.question(`Unregister project '${project.name}'? [y/N] `);
138538
139591
  rl.close();
138539
139592
  if (answer.trim().toLowerCase() !== "y") {
@@ -139505,7 +140558,7 @@ __export(plugin_exports, {
139505
140558
  import { existsSync as existsSync41 } from "node:fs";
139506
140559
  import { join as join55 } from "node:path";
139507
140560
  import { readFile as readFile23 } from "node:fs/promises";
139508
- import * as readline from "node:readline";
140561
+ import * as readline2 from "node:readline";
139509
140562
  async function getProjectPath6(projectName) {
139510
140563
  if (projectName) {
139511
140564
  const context = await resolveProject(projectName);
@@ -139645,7 +140698,7 @@ async function runPluginUninstall(id, options) {
139645
140698
  console.log(` This will stop and remove the plugin.`);
139646
140699
  console.log();
139647
140700
  const response = await new Promise((resolve29) => {
139648
- const rl = readline.createInterface({
140701
+ const rl = readline2.createInterface({
139649
140702
  input: process.stdin,
139650
140703
  output: process.stdout
139651
140704
  });
@@ -140163,7 +141216,7 @@ var init_native_patch = __esm({
140163
141216
 
140164
141217
  // src/bin.ts
140165
141218
  import { existsSync as existsSync44, mkdtempSync as mkdtempSync2, readFileSync as readFileSync17, symlinkSync as symlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
140166
- import { createRequire as createRequire2 } from "node:module";
141219
+ import { createRequire as createRequire3 } from "node:module";
140167
141220
  import { join as join58, dirname as dirname20 } from "node:path";
140168
141221
  import { tmpdir as tmpdir4 } from "node:os";
140169
141222
  var isBunBinary3 = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
@@ -140178,8 +141231,8 @@ function configurePiPackage() {
140178
141231
  type: "module"
140179
141232
  };
140180
141233
  try {
140181
- const require3 = createRequire2(import.meta.url);
140182
- const piPackagePath = require3.resolve("@mariozechner/pi-coding-agent/package.json");
141234
+ const require4 = createRequire3(import.meta.url);
141235
+ const piPackagePath = require4.resolve("@mariozechner/pi-coding-agent/package.json");
140183
141236
  const piPackageDir = dirname20(piPackagePath);
140184
141237
  packageJson = JSON.parse(readFileSync17(piPackagePath, "utf-8"));
140185
141238
  for (const entry of ["dist", "docs", "examples", "README.md", "CHANGELOG.md"]) {