brainfile 0.20.0 → 0.21.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.
Files changed (83) hide show
  1. package/dist/{chunk-UOCQBEEW.mjs → chunk-FOLBAGJS.mjs} +1232 -318
  2. package/dist/cli.mjs +2048 -1318
  3. package/dist/commands/brief.d.ts +1 -0
  4. package/dist/commands/brief.d.ts.map +1 -1
  5. package/dist/commands/brief.js +10 -0
  6. package/dist/commands/brief.js.map +1 -1
  7. package/dist/commands/init.d.ts +14 -0
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +115 -15
  10. package/dist/commands/init.js.map +1 -1
  11. package/dist/commands/mcp.d.ts.map +1 -1
  12. package/dist/commands/mcp.js +44 -0
  13. package/dist/commands/mcp.js.map +1 -1
  14. package/dist/commands/merge-driver.d.ts +26 -0
  15. package/dist/commands/merge-driver.d.ts.map +1 -0
  16. package/dist/commands/merge-driver.js +195 -0
  17. package/dist/commands/merge-driver.js.map +1 -0
  18. package/dist/commands/migrate-tracked.d.ts +8 -0
  19. package/dist/commands/migrate-tracked.d.ts.map +1 -0
  20. package/dist/commands/migrate-tracked.js +428 -0
  21. package/dist/commands/migrate-tracked.js.map +1 -0
  22. package/dist/commands/migrate.d.ts +6 -0
  23. package/dist/commands/migrate.d.ts.map +1 -1
  24. package/dist/commands/migrate.js +9 -0
  25. package/dist/commands/migrate.js.map +1 -1
  26. package/dist/commands/sync.d.ts +16 -0
  27. package/dist/commands/sync.d.ts.map +1 -0
  28. package/dist/commands/sync.js +152 -0
  29. package/dist/commands/sync.js.map +1 -0
  30. package/dist/commands/where.d.ts +21 -0
  31. package/dist/commands/where.d.ts.map +1 -0
  32. package/dist/commands/where.js +135 -0
  33. package/dist/commands/where.js.map +1 -0
  34. package/dist/mcp/helpers.d.ts +8 -0
  35. package/dist/mcp/helpers.d.ts.map +1 -1
  36. package/dist/mcp/helpers.js +44 -0
  37. package/dist/mcp/helpers.js.map +1 -1
  38. package/dist/mcp/tools/brief_tool.d.ts.map +1 -1
  39. package/dist/mcp/tools/brief_tool.js +39 -1
  40. package/dist/mcp/tools/brief_tool.js.map +1 -1
  41. package/dist/mcp/tools/contract_tool.d.ts.map +1 -1
  42. package/dist/mcp/tools/contract_tool.js +6 -5
  43. package/dist/mcp/tools/contract_tool.js.map +1 -1
  44. package/dist/mcp/tools/subtask_tool.d.ts.map +1 -1
  45. package/dist/mcp/tools/subtask_tool.js +5 -4
  46. package/dist/mcp/tools/subtask_tool.js.map +1 -1
  47. package/dist/mcp/tools/task_add_tool.d.ts.map +1 -1
  48. package/dist/mcp/tools/task_add_tool.js +6 -5
  49. package/dist/mcp/tools/task_add_tool.js.map +1 -1
  50. package/dist/mcp/tools/task_complete_tool.d.ts.map +1 -1
  51. package/dist/mcp/tools/task_complete_tool.js +5 -4
  52. package/dist/mcp/tools/task_complete_tool.js.map +1 -1
  53. package/dist/mcp/tools/task_delete_tool.d.ts.map +1 -1
  54. package/dist/mcp/tools/task_delete_tool.js +5 -4
  55. package/dist/mcp/tools/task_delete_tool.js.map +1 -1
  56. package/dist/mcp/tools/task_move_tool.d.ts.map +1 -1
  57. package/dist/mcp/tools/task_move_tool.js +6 -5
  58. package/dist/mcp/tools/task_move_tool.js.map +1 -1
  59. package/dist/mcp/tools/task_patch_tool.d.ts.map +1 -1
  60. package/dist/mcp/tools/task_patch_tool.js +5 -4
  61. package/dist/mcp/tools/task_patch_tool.js.map +1 -1
  62. package/dist/{tui-H3RI22S4.mjs → tui-M2KWIG2E.mjs} +295 -253
  63. package/dist/utils/board-autosync.d.ts +22 -0
  64. package/dist/utils/board-autosync.d.ts.map +1 -0
  65. package/dist/utils/board-autosync.js +166 -0
  66. package/dist/utils/board-autosync.js.map +1 -0
  67. package/dist/utils/board-commit-hooks.d.ts +12 -0
  68. package/dist/utils/board-commit-hooks.d.ts.map +1 -0
  69. package/dist/utils/board-commit-hooks.js +51 -0
  70. package/dist/utils/board-commit-hooks.js.map +1 -0
  71. package/dist/utils/board-repo.d.ts +108 -0
  72. package/dist/utils/board-repo.d.ts.map +1 -0
  73. package/dist/utils/board-repo.js +501 -0
  74. package/dist/utils/board-repo.js.map +1 -0
  75. package/dist/utils/board-sync.d.ts +111 -0
  76. package/dist/utils/board-sync.d.ts.map +1 -0
  77. package/dist/utils/board-sync.js +469 -0
  78. package/dist/utils/board-sync.js.map +1 -0
  79. package/dist/utils/brainfile-path.d.ts +11 -1
  80. package/dist/utils/brainfile-path.d.ts.map +1 -1
  81. package/dist/utils/brainfile-path.js +39 -2
  82. package/dist/utils/brainfile-path.js.map +1 -1
  83. package/package.json +2 -2
@@ -10,20 +10,25 @@ import {
10
10
  RULE,
11
11
  createGitHubIssue,
12
12
  createLinearIssue,
13
+ fetchBeforeRead,
13
14
  getArchiveConfig,
14
15
  getContractStateColor,
15
16
  getEffectiveDestination,
16
17
  getLinearTeams,
17
18
  getTypeGlyph,
18
19
  import_core,
20
+ installAutosync,
19
21
  isGitHubAuthenticated,
20
22
  isLinearAuthenticated,
21
23
  markV2MigrationHintShown,
22
24
  require_dist,
23
25
  require_source,
24
26
  resolveCliBrainfilePath,
25
- shouldSuggestV2Migration
26
- } from "./chunk-UOCQBEEW.mjs";
27
+ scheduleBoardCommit,
28
+ shouldSuggestV2Migration,
29
+ syncMessage,
30
+ syncStatusLabel
31
+ } from "./chunk-FOLBAGJS.mjs";
27
32
  import {
28
33
  __commonJS,
29
34
  __export,
@@ -1994,8 +1999,8 @@ var require_react_reconciler_production = __commonJS({
1994
1999
  currentEntangledActionThenable = {
1995
2000
  status: "pending",
1996
2001
  value: void 0,
1997
- then: function(resolve3) {
1998
- entangledListeners.push(resolve3);
2002
+ then: function(resolve4) {
2003
+ entangledListeners.push(resolve4);
1999
2004
  }
2000
2005
  };
2001
2006
  }
@@ -2018,8 +2023,8 @@ var require_react_reconciler_production = __commonJS({
2018
2023
  status: "pending",
2019
2024
  value: null,
2020
2025
  reason: null,
2021
- then: function(resolve3) {
2022
- listeners.push(resolve3);
2026
+ then: function(resolve4) {
2027
+ listeners.push(resolve4);
2023
2028
  }
2024
2029
  };
2025
2030
  thenable.then(
@@ -9503,7 +9508,7 @@ var require_stack_utils = __commonJS({
9503
9508
  });
9504
9509
 
9505
9510
  // src/commands/tui.tsx
9506
- var import_react44 = __toESM(require_react());
9511
+ var import_react45 = __toESM(require_react());
9507
9512
 
9508
9513
  // node_modules/ink/build/render.js
9509
9514
  import { Stream } from "node:stream";
@@ -17097,8 +17102,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
17097
17102
  }
17098
17103
 
17099
17104
  // node_modules/ink/build/components/ErrorOverview.js
17100
- var cleanupPath = (path4) => {
17101
- return path4?.replace(`file://${cwd()}/`, "");
17105
+ var cleanupPath = (path6) => {
17106
+ return path6?.replace(`file://${cwd()}/`, "");
17102
17107
  };
17103
17108
  var stackUtils = new import_stack_utils.default({
17104
17109
  cwd: cwd(),
@@ -17771,8 +17776,8 @@ var kittyModifiers = {
17771
17776
  var noop = () => {
17772
17777
  };
17773
17778
  var textEncoder = new TextEncoder();
17774
- var yieldImmediate = async () => new Promise((resolve3) => {
17775
- setImmediate(resolve3);
17779
+ var yieldImmediate = async () => new Promise((resolve4) => {
17780
+ setImmediate(resolve4);
17776
17781
  });
17777
17782
  var kittyQueryEscapeByte = 27;
17778
17783
  var kittyQueryOpenBracketByte = 91;
@@ -17989,8 +17994,8 @@ var Ink = class {
17989
17994
  };
17990
17995
  }
17991
17996
  this.initKittyKeyboard();
17992
- this.exitPromise = new Promise((resolve3, reject) => {
17993
- this.resolveExitPromise = resolve3;
17997
+ this.exitPromise = new Promise((resolve4, reject) => {
17998
+ this.resolveExitPromise = resolve4;
17994
17999
  this.rejectExitPromise = reject;
17995
18000
  });
17996
18001
  void this.exitPromise.catch(noop);
@@ -18301,9 +18306,9 @@ var Ink = class {
18301
18306
  settleThrottle(this.throttledOnRender, canWriteToStdout);
18302
18307
  settleThrottle(this.throttledLog, canWriteToStdout);
18303
18308
  if (canWriteToStdout && hasWritableState) {
18304
- await new Promise((resolve3) => {
18309
+ await new Promise((resolve4) => {
18305
18310
  this.options.stdout.write("", () => {
18306
- resolve3();
18311
+ resolve4();
18307
18312
  });
18308
18313
  });
18309
18314
  return;
@@ -18389,8 +18394,8 @@ var Ink = class {
18389
18394
  async awaitNextRender() {
18390
18395
  if (!this.nextRenderCommit) {
18391
18396
  let resolveRender;
18392
- const promise = new Promise((resolve3) => {
18393
- resolveRender = resolve3;
18397
+ const promise = new Promise((resolve4) => {
18398
+ resolveRender = resolve4;
18394
18399
  });
18395
18400
  this.nextRenderCommit = { promise, resolve: resolveRender };
18396
18401
  }
@@ -19192,7 +19197,7 @@ var import_chalk4 = __toESM(require_source());
19192
19197
  import * as fs6 from "fs";
19193
19198
 
19194
19199
  // src/tui/BrainfileTUI.tsx
19195
- var import_react43 = __toESM(require_react());
19200
+ var import_react44 = __toESM(require_react());
19196
19201
  var import_core6 = __toESM(require_dist());
19197
19202
 
19198
19203
  // src/tui/copy.ts
@@ -19488,7 +19493,7 @@ var ReaddirpStream = class extends Readable {
19488
19493
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
19489
19494
  const statMethod = opts.lstat ? lstat : stat;
19490
19495
  if (wantBigintFsStats) {
19491
- this._stat = (path4) => statMethod(path4, { bigint: true });
19496
+ this._stat = (path6) => statMethod(path6, { bigint: true });
19492
19497
  } else {
19493
19498
  this._stat = statMethod;
19494
19499
  }
@@ -19513,8 +19518,8 @@ var ReaddirpStream = class extends Readable {
19513
19518
  const par = this.parent;
19514
19519
  const fil = par && par.files;
19515
19520
  if (fil && fil.length > 0) {
19516
- const { path: path4, depth } = par;
19517
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path4));
19521
+ const { path: path6, depth } = par;
19522
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path6));
19518
19523
  const awaited = await Promise.all(slice);
19519
19524
  for (const entry of awaited) {
19520
19525
  if (!entry)
@@ -19554,20 +19559,20 @@ var ReaddirpStream = class extends Readable {
19554
19559
  this.reading = false;
19555
19560
  }
19556
19561
  }
19557
- async _exploreDir(path4, depth) {
19562
+ async _exploreDir(path6, depth) {
19558
19563
  let files;
19559
19564
  try {
19560
- files = await readdir(path4, this._rdOptions);
19565
+ files = await readdir(path6, this._rdOptions);
19561
19566
  } catch (error) {
19562
19567
  this._onError(error);
19563
19568
  }
19564
- return { files, depth, path: path4 };
19569
+ return { files, depth, path: path6 };
19565
19570
  }
19566
- async _formatEntry(dirent, path4) {
19571
+ async _formatEntry(dirent, path6) {
19567
19572
  let entry;
19568
19573
  const basename4 = this._isDirent ? dirent.name : dirent;
19569
19574
  try {
19570
- const fullPath = presolve(pjoin(path4, basename4));
19575
+ const fullPath = presolve(pjoin(path6, basename4));
19571
19576
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename4 };
19572
19577
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
19573
19578
  } catch (err) {
@@ -19967,16 +19972,16 @@ var delFromSet = (main, prop, item) => {
19967
19972
  };
19968
19973
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
19969
19974
  var FsWatchInstances = /* @__PURE__ */ new Map();
19970
- function createFsWatchInstance(path4, options, listener, errHandler, emitRaw) {
19975
+ function createFsWatchInstance(path6, options, listener, errHandler, emitRaw) {
19971
19976
  const handleEvent = (rawEvent, evPath) => {
19972
- listener(path4);
19973
- emitRaw(rawEvent, evPath, { watchedPath: path4 });
19974
- if (evPath && path4 !== evPath) {
19975
- fsWatchBroadcast(sysPath.resolve(path4, evPath), KEY_LISTENERS, sysPath.join(path4, evPath));
19977
+ listener(path6);
19978
+ emitRaw(rawEvent, evPath, { watchedPath: path6 });
19979
+ if (evPath && path6 !== evPath) {
19980
+ fsWatchBroadcast(sysPath.resolve(path6, evPath), KEY_LISTENERS, sysPath.join(path6, evPath));
19976
19981
  }
19977
19982
  };
19978
19983
  try {
19979
- return fs_watch(path4, {
19984
+ return fs_watch(path6, {
19980
19985
  persistent: options.persistent
19981
19986
  }, handleEvent);
19982
19987
  } catch (error) {
@@ -19992,12 +19997,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
19992
19997
  listener(val1, val2, val3);
19993
19998
  });
19994
19999
  };
19995
- var setFsWatchListener = (path4, fullPath, options, handlers) => {
20000
+ var setFsWatchListener = (path6, fullPath, options, handlers) => {
19996
20001
  const { listener, errHandler, rawEmitter } = handlers;
19997
20002
  let cont = FsWatchInstances.get(fullPath);
19998
20003
  let watcher;
19999
20004
  if (!options.persistent) {
20000
- watcher = createFsWatchInstance(path4, options, listener, errHandler, rawEmitter);
20005
+ watcher = createFsWatchInstance(path6, options, listener, errHandler, rawEmitter);
20001
20006
  if (!watcher)
20002
20007
  return;
20003
20008
  return watcher.close.bind(watcher);
@@ -20008,7 +20013,7 @@ var setFsWatchListener = (path4, fullPath, options, handlers) => {
20008
20013
  addAndConvert(cont, KEY_RAW, rawEmitter);
20009
20014
  } else {
20010
20015
  watcher = createFsWatchInstance(
20011
- path4,
20016
+ path6,
20012
20017
  options,
20013
20018
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
20014
20019
  errHandler,
@@ -20023,7 +20028,7 @@ var setFsWatchListener = (path4, fullPath, options, handlers) => {
20023
20028
  cont.watcherUnusable = true;
20024
20029
  if (isWindows3 && error.code === "EPERM") {
20025
20030
  try {
20026
- const fd = await open(path4, "r");
20031
+ const fd = await open(path6, "r");
20027
20032
  await fd.close();
20028
20033
  broadcastErr(error);
20029
20034
  } catch (err) {
@@ -20054,7 +20059,7 @@ var setFsWatchListener = (path4, fullPath, options, handlers) => {
20054
20059
  };
20055
20060
  };
20056
20061
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
20057
- var setFsWatchFileListener = (path4, fullPath, options, handlers) => {
20062
+ var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
20058
20063
  const { listener, rawEmitter } = handlers;
20059
20064
  let cont = FsWatchFileInstances.get(fullPath);
20060
20065
  const copts = cont && cont.options;
@@ -20076,7 +20081,7 @@ var setFsWatchFileListener = (path4, fullPath, options, handlers) => {
20076
20081
  });
20077
20082
  const currmtime = curr.mtimeMs;
20078
20083
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
20079
- foreach(cont.listeners, (listener2) => listener2(path4, curr));
20084
+ foreach(cont.listeners, (listener2) => listener2(path6, curr));
20080
20085
  }
20081
20086
  })
20082
20087
  };
@@ -20104,13 +20109,13 @@ var NodeFsHandler = class {
20104
20109
  * @param listener on fs change
20105
20110
  * @returns closer for the watcher instance
20106
20111
  */
20107
- _watchWithNodeFs(path4, listener) {
20112
+ _watchWithNodeFs(path6, listener) {
20108
20113
  const opts = this.fsw.options;
20109
- const directory = sysPath.dirname(path4);
20110
- const basename4 = sysPath.basename(path4);
20114
+ const directory = sysPath.dirname(path6);
20115
+ const basename4 = sysPath.basename(path6);
20111
20116
  const parent = this.fsw._getWatchedDir(directory);
20112
20117
  parent.add(basename4);
20113
- const absolutePath = sysPath.resolve(path4);
20118
+ const absolutePath = sysPath.resolve(path6);
20114
20119
  const options = {
20115
20120
  persistent: opts.persistent
20116
20121
  };
@@ -20120,12 +20125,12 @@ var NodeFsHandler = class {
20120
20125
  if (opts.usePolling) {
20121
20126
  const enableBin = opts.interval !== opts.binaryInterval;
20122
20127
  options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
20123
- closer = setFsWatchFileListener(path4, absolutePath, options, {
20128
+ closer = setFsWatchFileListener(path6, absolutePath, options, {
20124
20129
  listener,
20125
20130
  rawEmitter: this.fsw._emitRaw
20126
20131
  });
20127
20132
  } else {
20128
- closer = setFsWatchListener(path4, absolutePath, options, {
20133
+ closer = setFsWatchListener(path6, absolutePath, options, {
20129
20134
  listener,
20130
20135
  errHandler: this._boundHandleError,
20131
20136
  rawEmitter: this.fsw._emitRaw
@@ -20141,13 +20146,13 @@ var NodeFsHandler = class {
20141
20146
  if (this.fsw.closed) {
20142
20147
  return;
20143
20148
  }
20144
- const dirname4 = sysPath.dirname(file);
20149
+ const dirname6 = sysPath.dirname(file);
20145
20150
  const basename4 = sysPath.basename(file);
20146
- const parent = this.fsw._getWatchedDir(dirname4);
20151
+ const parent = this.fsw._getWatchedDir(dirname6);
20147
20152
  let prevStats = stats;
20148
20153
  if (parent.has(basename4))
20149
20154
  return;
20150
- const listener = async (path4, newStats) => {
20155
+ const listener = async (path6, newStats) => {
20151
20156
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
20152
20157
  return;
20153
20158
  if (!newStats || newStats.mtimeMs === 0) {
@@ -20161,16 +20166,16 @@ var NodeFsHandler = class {
20161
20166
  this.fsw._emit(EV.CHANGE, file, newStats2);
20162
20167
  }
20163
20168
  if ((isMacos || isLinux2 || isFreeBSD) && prevStats.ino !== newStats2.ino) {
20164
- this.fsw._closeFile(path4);
20169
+ this.fsw._closeFile(path6);
20165
20170
  prevStats = newStats2;
20166
20171
  const closer2 = this._watchWithNodeFs(file, listener);
20167
20172
  if (closer2)
20168
- this.fsw._addPathCloser(path4, closer2);
20173
+ this.fsw._addPathCloser(path6, closer2);
20169
20174
  } else {
20170
20175
  prevStats = newStats2;
20171
20176
  }
20172
20177
  } catch (error) {
20173
- this.fsw._remove(dirname4, basename4);
20178
+ this.fsw._remove(dirname6, basename4);
20174
20179
  }
20175
20180
  } else if (parent.has(basename4)) {
20176
20181
  const at = newStats.atimeMs;
@@ -20197,7 +20202,7 @@ var NodeFsHandler = class {
20197
20202
  * @param item basename of this item
20198
20203
  * @returns true if no more processing is needed for this entry.
20199
20204
  */
20200
- async _handleSymlink(entry, directory, path4, item) {
20205
+ async _handleSymlink(entry, directory, path6, item) {
20201
20206
  if (this.fsw.closed) {
20202
20207
  return;
20203
20208
  }
@@ -20207,7 +20212,7 @@ var NodeFsHandler = class {
20207
20212
  this.fsw._incrReadyCount();
20208
20213
  let linkPath;
20209
20214
  try {
20210
- linkPath = await fsrealpath(path4);
20215
+ linkPath = await fsrealpath(path6);
20211
20216
  } catch (e) {
20212
20217
  this.fsw._emitReady();
20213
20218
  return true;
@@ -20217,12 +20222,12 @@ var NodeFsHandler = class {
20217
20222
  if (dir.has(item)) {
20218
20223
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
20219
20224
  this.fsw._symlinkPaths.set(full, linkPath);
20220
- this.fsw._emit(EV.CHANGE, path4, entry.stats);
20225
+ this.fsw._emit(EV.CHANGE, path6, entry.stats);
20221
20226
  }
20222
20227
  } else {
20223
20228
  dir.add(item);
20224
20229
  this.fsw._symlinkPaths.set(full, linkPath);
20225
- this.fsw._emit(EV.ADD, path4, entry.stats);
20230
+ this.fsw._emit(EV.ADD, path6, entry.stats);
20226
20231
  }
20227
20232
  this.fsw._emitReady();
20228
20233
  return true;
@@ -20251,9 +20256,9 @@ var NodeFsHandler = class {
20251
20256
  return;
20252
20257
  }
20253
20258
  const item = entry.path;
20254
- let path4 = sysPath.join(directory, item);
20259
+ let path6 = sysPath.join(directory, item);
20255
20260
  current.add(item);
20256
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path4, item)) {
20261
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path6, item)) {
20257
20262
  return;
20258
20263
  }
20259
20264
  if (this.fsw.closed) {
@@ -20262,11 +20267,11 @@ var NodeFsHandler = class {
20262
20267
  }
20263
20268
  if (item === target || !target && !previous.has(item)) {
20264
20269
  this.fsw._incrReadyCount();
20265
- path4 = sysPath.join(dir, sysPath.relative(dir, path4));
20266
- this._addToNodeFs(path4, initialAdd, wh, depth + 1);
20270
+ path6 = sysPath.join(dir, sysPath.relative(dir, path6));
20271
+ this._addToNodeFs(path6, initialAdd, wh, depth + 1);
20267
20272
  }
20268
20273
  }).on(EV.ERROR, this._boundHandleError);
20269
- return new Promise((resolve3, reject) => {
20274
+ return new Promise((resolve4, reject) => {
20270
20275
  if (!stream)
20271
20276
  return reject();
20272
20277
  stream.once(STR_END, () => {
@@ -20275,7 +20280,7 @@ var NodeFsHandler = class {
20275
20280
  return;
20276
20281
  }
20277
20282
  const wasThrottled = throttler ? throttler.clear() : false;
20278
- resolve3(void 0);
20283
+ resolve4(void 0);
20279
20284
  previous.getChildren().filter((item) => {
20280
20285
  return item !== directory && !current.has(item);
20281
20286
  }).forEach((item) => {
@@ -20332,13 +20337,13 @@ var NodeFsHandler = class {
20332
20337
  * @param depth Child path actually targeted for watch
20333
20338
  * @param target Child path actually targeted for watch
20334
20339
  */
20335
- async _addToNodeFs(path4, initialAdd, priorWh, depth, target) {
20340
+ async _addToNodeFs(path6, initialAdd, priorWh, depth, target) {
20336
20341
  const ready = this.fsw._emitReady;
20337
- if (this.fsw._isIgnored(path4) || this.fsw.closed) {
20342
+ if (this.fsw._isIgnored(path6) || this.fsw.closed) {
20338
20343
  ready();
20339
20344
  return false;
20340
20345
  }
20341
- const wh = this.fsw._getWatchHelpers(path4);
20346
+ const wh = this.fsw._getWatchHelpers(path6);
20342
20347
  if (priorWh) {
20343
20348
  wh.filterPath = (entry) => priorWh.filterPath(entry);
20344
20349
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -20354,8 +20359,8 @@ var NodeFsHandler = class {
20354
20359
  const follow = this.fsw.options.followSymlinks;
20355
20360
  let closer;
20356
20361
  if (stats.isDirectory()) {
20357
- const absPath = sysPath.resolve(path4);
20358
- const targetPath = follow ? await fsrealpath(path4) : path4;
20362
+ const absPath = sysPath.resolve(path6);
20363
+ const targetPath = follow ? await fsrealpath(path6) : path6;
20359
20364
  if (this.fsw.closed)
20360
20365
  return;
20361
20366
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -20365,29 +20370,29 @@ var NodeFsHandler = class {
20365
20370
  this.fsw._symlinkPaths.set(absPath, targetPath);
20366
20371
  }
20367
20372
  } else if (stats.isSymbolicLink()) {
20368
- const targetPath = follow ? await fsrealpath(path4) : path4;
20373
+ const targetPath = follow ? await fsrealpath(path6) : path6;
20369
20374
  if (this.fsw.closed)
20370
20375
  return;
20371
20376
  const parent = sysPath.dirname(wh.watchPath);
20372
20377
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
20373
20378
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
20374
- closer = await this._handleDir(parent, stats, initialAdd, depth, path4, wh, targetPath);
20379
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path6, wh, targetPath);
20375
20380
  if (this.fsw.closed)
20376
20381
  return;
20377
20382
  if (targetPath !== void 0) {
20378
- this.fsw._symlinkPaths.set(sysPath.resolve(path4), targetPath);
20383
+ this.fsw._symlinkPaths.set(sysPath.resolve(path6), targetPath);
20379
20384
  }
20380
20385
  } else {
20381
20386
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
20382
20387
  }
20383
20388
  ready();
20384
20389
  if (closer)
20385
- this.fsw._addPathCloser(path4, closer);
20390
+ this.fsw._addPathCloser(path6, closer);
20386
20391
  return false;
20387
20392
  } catch (error) {
20388
20393
  if (this.fsw._handleError(error)) {
20389
20394
  ready();
20390
- return path4;
20395
+ return path6;
20391
20396
  }
20392
20397
  }
20393
20398
  }
@@ -20430,26 +20435,26 @@ function createPattern(matcher) {
20430
20435
  }
20431
20436
  return () => false;
20432
20437
  }
20433
- function normalizePath(path4) {
20434
- if (typeof path4 !== "string")
20438
+ function normalizePath(path6) {
20439
+ if (typeof path6 !== "string")
20435
20440
  throw new Error("string expected");
20436
- path4 = sysPath2.normalize(path4);
20437
- path4 = path4.replace(/\\/g, "/");
20441
+ path6 = sysPath2.normalize(path6);
20442
+ path6 = path6.replace(/\\/g, "/");
20438
20443
  let prepend = false;
20439
- if (path4.startsWith("//"))
20444
+ if (path6.startsWith("//"))
20440
20445
  prepend = true;
20441
20446
  const DOUBLE_SLASH_RE2 = /\/\//;
20442
- while (path4.match(DOUBLE_SLASH_RE2))
20443
- path4 = path4.replace(DOUBLE_SLASH_RE2, "/");
20447
+ while (path6.match(DOUBLE_SLASH_RE2))
20448
+ path6 = path6.replace(DOUBLE_SLASH_RE2, "/");
20444
20449
  if (prepend)
20445
- path4 = "/" + path4;
20446
- return path4;
20450
+ path6 = "/" + path6;
20451
+ return path6;
20447
20452
  }
20448
20453
  function matchPatterns(patterns, testString, stats) {
20449
- const path4 = normalizePath(testString);
20454
+ const path6 = normalizePath(testString);
20450
20455
  for (let index = 0; index < patterns.length; index++) {
20451
20456
  const pattern = patterns[index];
20452
- if (pattern(path4, stats)) {
20457
+ if (pattern(path6, stats)) {
20453
20458
  return true;
20454
20459
  }
20455
20460
  }
@@ -20489,19 +20494,19 @@ var toUnix = (string) => {
20489
20494
  }
20490
20495
  return str;
20491
20496
  };
20492
- var normalizePathToUnix = (path4) => toUnix(sysPath2.normalize(toUnix(path4)));
20493
- var normalizeIgnored = (cwd2 = "") => (path4) => {
20494
- if (typeof path4 === "string") {
20495
- return normalizePathToUnix(sysPath2.isAbsolute(path4) ? path4 : sysPath2.join(cwd2, path4));
20497
+ var normalizePathToUnix = (path6) => toUnix(sysPath2.normalize(toUnix(path6)));
20498
+ var normalizeIgnored = (cwd2 = "") => (path6) => {
20499
+ if (typeof path6 === "string") {
20500
+ return normalizePathToUnix(sysPath2.isAbsolute(path6) ? path6 : sysPath2.join(cwd2, path6));
20496
20501
  } else {
20497
- return path4;
20502
+ return path6;
20498
20503
  }
20499
20504
  };
20500
- var getAbsolutePath = (path4, cwd2) => {
20501
- if (sysPath2.isAbsolute(path4)) {
20502
- return path4;
20505
+ var getAbsolutePath = (path6, cwd2) => {
20506
+ if (sysPath2.isAbsolute(path6)) {
20507
+ return path6;
20503
20508
  }
20504
- return sysPath2.join(cwd2, path4);
20509
+ return sysPath2.join(cwd2, path6);
20505
20510
  };
20506
20511
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
20507
20512
  var DirEntry = class {
@@ -20556,10 +20561,10 @@ var DirEntry = class {
20556
20561
  var STAT_METHOD_F = "stat";
20557
20562
  var STAT_METHOD_L = "lstat";
20558
20563
  var WatchHelper = class {
20559
- constructor(path4, follow, fsw) {
20564
+ constructor(path6, follow, fsw) {
20560
20565
  this.fsw = fsw;
20561
- const watchPath = path4;
20562
- this.path = path4 = path4.replace(REPLACER_RE, "");
20566
+ const watchPath = path6;
20567
+ this.path = path6 = path6.replace(REPLACER_RE, "");
20563
20568
  this.watchPath = watchPath;
20564
20569
  this.fullWatchPath = sysPath2.resolve(watchPath);
20565
20570
  this.dirParts = [];
@@ -20681,20 +20686,20 @@ var FSWatcher = class extends EventEmitter3 {
20681
20686
  this._closePromise = void 0;
20682
20687
  let paths = unifyPaths(paths_);
20683
20688
  if (cwd2) {
20684
- paths = paths.map((path4) => {
20685
- const absPath = getAbsolutePath(path4, cwd2);
20689
+ paths = paths.map((path6) => {
20690
+ const absPath = getAbsolutePath(path6, cwd2);
20686
20691
  return absPath;
20687
20692
  });
20688
20693
  }
20689
- paths.forEach((path4) => {
20690
- this._removeIgnoredPath(path4);
20694
+ paths.forEach((path6) => {
20695
+ this._removeIgnoredPath(path6);
20691
20696
  });
20692
20697
  this._userIgnored = void 0;
20693
20698
  if (!this._readyCount)
20694
20699
  this._readyCount = 0;
20695
20700
  this._readyCount += paths.length;
20696
- Promise.all(paths.map(async (path4) => {
20697
- const res = await this._nodeFsHandler._addToNodeFs(path4, !_internal, void 0, 0, _origAdd);
20701
+ Promise.all(paths.map(async (path6) => {
20702
+ const res = await this._nodeFsHandler._addToNodeFs(path6, !_internal, void 0, 0, _origAdd);
20698
20703
  if (res)
20699
20704
  this._emitReady();
20700
20705
  return res;
@@ -20716,17 +20721,17 @@ var FSWatcher = class extends EventEmitter3 {
20716
20721
  return this;
20717
20722
  const paths = unifyPaths(paths_);
20718
20723
  const { cwd: cwd2 } = this.options;
20719
- paths.forEach((path4) => {
20720
- if (!sysPath2.isAbsolute(path4) && !this._closers.has(path4)) {
20724
+ paths.forEach((path6) => {
20725
+ if (!sysPath2.isAbsolute(path6) && !this._closers.has(path6)) {
20721
20726
  if (cwd2)
20722
- path4 = sysPath2.join(cwd2, path4);
20723
- path4 = sysPath2.resolve(path4);
20727
+ path6 = sysPath2.join(cwd2, path6);
20728
+ path6 = sysPath2.resolve(path6);
20724
20729
  }
20725
- this._closePath(path4);
20726
- this._addIgnoredPath(path4);
20727
- if (this._watched.has(path4)) {
20730
+ this._closePath(path6);
20731
+ this._addIgnoredPath(path6);
20732
+ if (this._watched.has(path6)) {
20728
20733
  this._addIgnoredPath({
20729
- path: path4,
20734
+ path: path6,
20730
20735
  recursive: true
20731
20736
  });
20732
20737
  }
@@ -20790,38 +20795,38 @@ var FSWatcher = class extends EventEmitter3 {
20790
20795
  * @param stats arguments to be passed with event
20791
20796
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
20792
20797
  */
20793
- async _emit(event, path4, stats) {
20798
+ async _emit(event, path6, stats) {
20794
20799
  if (this.closed)
20795
20800
  return;
20796
20801
  const opts = this.options;
20797
20802
  if (isWindows3)
20798
- path4 = sysPath2.normalize(path4);
20803
+ path6 = sysPath2.normalize(path6);
20799
20804
  if (opts.cwd)
20800
- path4 = sysPath2.relative(opts.cwd, path4);
20801
- const args = [path4];
20805
+ path6 = sysPath2.relative(opts.cwd, path6);
20806
+ const args = [path6];
20802
20807
  if (stats != null)
20803
20808
  args.push(stats);
20804
20809
  const awf = opts.awaitWriteFinish;
20805
20810
  let pw;
20806
- if (awf && (pw = this._pendingWrites.get(path4))) {
20811
+ if (awf && (pw = this._pendingWrites.get(path6))) {
20807
20812
  pw.lastChange = /* @__PURE__ */ new Date();
20808
20813
  return this;
20809
20814
  }
20810
20815
  if (opts.atomic) {
20811
20816
  if (event === EVENTS.UNLINK) {
20812
- this._pendingUnlinks.set(path4, [event, ...args]);
20817
+ this._pendingUnlinks.set(path6, [event, ...args]);
20813
20818
  setTimeout(() => {
20814
- this._pendingUnlinks.forEach((entry, path5) => {
20819
+ this._pendingUnlinks.forEach((entry, path7) => {
20815
20820
  this.emit(...entry);
20816
20821
  this.emit(EVENTS.ALL, ...entry);
20817
- this._pendingUnlinks.delete(path5);
20822
+ this._pendingUnlinks.delete(path7);
20818
20823
  });
20819
20824
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
20820
20825
  return this;
20821
20826
  }
20822
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path4)) {
20827
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path6)) {
20823
20828
  event = EVENTS.CHANGE;
20824
- this._pendingUnlinks.delete(path4);
20829
+ this._pendingUnlinks.delete(path6);
20825
20830
  }
20826
20831
  }
20827
20832
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -20839,16 +20844,16 @@ var FSWatcher = class extends EventEmitter3 {
20839
20844
  this.emitWithAll(event, args);
20840
20845
  }
20841
20846
  };
20842
- this._awaitWriteFinish(path4, awf.stabilityThreshold, event, awfEmit);
20847
+ this._awaitWriteFinish(path6, awf.stabilityThreshold, event, awfEmit);
20843
20848
  return this;
20844
20849
  }
20845
20850
  if (event === EVENTS.CHANGE) {
20846
- const isThrottled = !this._throttle(EVENTS.CHANGE, path4, 50);
20851
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path6, 50);
20847
20852
  if (isThrottled)
20848
20853
  return this;
20849
20854
  }
20850
20855
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
20851
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path4) : path4;
20856
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path6) : path6;
20852
20857
  let stats2;
20853
20858
  try {
20854
20859
  stats2 = await stat3(fullPath);
@@ -20879,23 +20884,23 @@ var FSWatcher = class extends EventEmitter3 {
20879
20884
  * @param timeout duration of time to suppress duplicate actions
20880
20885
  * @returns tracking object or false if action should be suppressed
20881
20886
  */
20882
- _throttle(actionType, path4, timeout) {
20887
+ _throttle(actionType, path6, timeout) {
20883
20888
  if (!this._throttled.has(actionType)) {
20884
20889
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
20885
20890
  }
20886
20891
  const action = this._throttled.get(actionType);
20887
20892
  if (!action)
20888
20893
  throw new Error("invalid throttle");
20889
- const actionPath = action.get(path4);
20894
+ const actionPath = action.get(path6);
20890
20895
  if (actionPath) {
20891
20896
  actionPath.count++;
20892
20897
  return false;
20893
20898
  }
20894
20899
  let timeoutObject;
20895
20900
  const clear = () => {
20896
- const item = action.get(path4);
20901
+ const item = action.get(path6);
20897
20902
  const count = item ? item.count : 0;
20898
- action.delete(path4);
20903
+ action.delete(path6);
20899
20904
  clearTimeout(timeoutObject);
20900
20905
  if (item)
20901
20906
  clearTimeout(item.timeoutObject);
@@ -20903,7 +20908,7 @@ var FSWatcher = class extends EventEmitter3 {
20903
20908
  };
20904
20909
  timeoutObject = setTimeout(clear, timeout);
20905
20910
  const thr = { timeoutObject, clear, count: 0 };
20906
- action.set(path4, thr);
20911
+ action.set(path6, thr);
20907
20912
  return thr;
20908
20913
  }
20909
20914
  _incrReadyCount() {
@@ -20917,44 +20922,44 @@ var FSWatcher = class extends EventEmitter3 {
20917
20922
  * @param event
20918
20923
  * @param awfEmit Callback to be called when ready for event to be emitted.
20919
20924
  */
20920
- _awaitWriteFinish(path4, threshold, event, awfEmit) {
20925
+ _awaitWriteFinish(path6, threshold, event, awfEmit) {
20921
20926
  const awf = this.options.awaitWriteFinish;
20922
20927
  if (typeof awf !== "object")
20923
20928
  return;
20924
20929
  const pollInterval = awf.pollInterval;
20925
20930
  let timeoutHandler;
20926
- let fullPath = path4;
20927
- if (this.options.cwd && !sysPath2.isAbsolute(path4)) {
20928
- fullPath = sysPath2.join(this.options.cwd, path4);
20931
+ let fullPath = path6;
20932
+ if (this.options.cwd && !sysPath2.isAbsolute(path6)) {
20933
+ fullPath = sysPath2.join(this.options.cwd, path6);
20929
20934
  }
20930
20935
  const now = /* @__PURE__ */ new Date();
20931
20936
  const writes = this._pendingWrites;
20932
20937
  function awaitWriteFinishFn(prevStat) {
20933
20938
  statcb(fullPath, (err, curStat) => {
20934
- if (err || !writes.has(path4)) {
20939
+ if (err || !writes.has(path6)) {
20935
20940
  if (err && err.code !== "ENOENT")
20936
20941
  awfEmit(err);
20937
20942
  return;
20938
20943
  }
20939
20944
  const now2 = Number(/* @__PURE__ */ new Date());
20940
20945
  if (prevStat && curStat.size !== prevStat.size) {
20941
- writes.get(path4).lastChange = now2;
20946
+ writes.get(path6).lastChange = now2;
20942
20947
  }
20943
- const pw = writes.get(path4);
20948
+ const pw = writes.get(path6);
20944
20949
  const df = now2 - pw.lastChange;
20945
20950
  if (df >= threshold) {
20946
- writes.delete(path4);
20951
+ writes.delete(path6);
20947
20952
  awfEmit(void 0, curStat);
20948
20953
  } else {
20949
20954
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
20950
20955
  }
20951
20956
  });
20952
20957
  }
20953
- if (!writes.has(path4)) {
20954
- writes.set(path4, {
20958
+ if (!writes.has(path6)) {
20959
+ writes.set(path6, {
20955
20960
  lastChange: now,
20956
20961
  cancelWait: () => {
20957
- writes.delete(path4);
20962
+ writes.delete(path6);
20958
20963
  clearTimeout(timeoutHandler);
20959
20964
  return event;
20960
20965
  }
@@ -20965,8 +20970,8 @@ var FSWatcher = class extends EventEmitter3 {
20965
20970
  /**
20966
20971
  * Determines whether user has asked to ignore this path.
20967
20972
  */
20968
- _isIgnored(path4, stats) {
20969
- if (this.options.atomic && DOT_RE.test(path4))
20973
+ _isIgnored(path6, stats) {
20974
+ if (this.options.atomic && DOT_RE.test(path6))
20970
20975
  return true;
20971
20976
  if (!this._userIgnored) {
20972
20977
  const { cwd: cwd2 } = this.options;
@@ -20976,17 +20981,17 @@ var FSWatcher = class extends EventEmitter3 {
20976
20981
  const list = [...ignoredPaths.map(normalizeIgnored(cwd2)), ...ignored];
20977
20982
  this._userIgnored = anymatch(list, void 0);
20978
20983
  }
20979
- return this._userIgnored(path4, stats);
20984
+ return this._userIgnored(path6, stats);
20980
20985
  }
20981
- _isntIgnored(path4, stat4) {
20982
- return !this._isIgnored(path4, stat4);
20986
+ _isntIgnored(path6, stat4) {
20987
+ return !this._isIgnored(path6, stat4);
20983
20988
  }
20984
20989
  /**
20985
20990
  * Provides a set of common helpers and properties relating to symlink handling.
20986
20991
  * @param path file or directory pattern being watched
20987
20992
  */
20988
- _getWatchHelpers(path4) {
20989
- return new WatchHelper(path4, this.options.followSymlinks, this);
20993
+ _getWatchHelpers(path6) {
20994
+ return new WatchHelper(path6, this.options.followSymlinks, this);
20990
20995
  }
20991
20996
  // Directory helpers
20992
20997
  // -----------------
@@ -21018,63 +21023,63 @@ var FSWatcher = class extends EventEmitter3 {
21018
21023
  * @param item base path of item/directory
21019
21024
  */
21020
21025
  _remove(directory, item, isDirectory) {
21021
- const path4 = sysPath2.join(directory, item);
21022
- const fullPath = sysPath2.resolve(path4);
21023
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path4) || this._watched.has(fullPath);
21024
- if (!this._throttle("remove", path4, 100))
21026
+ const path6 = sysPath2.join(directory, item);
21027
+ const fullPath = sysPath2.resolve(path6);
21028
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path6) || this._watched.has(fullPath);
21029
+ if (!this._throttle("remove", path6, 100))
21025
21030
  return;
21026
21031
  if (!isDirectory && this._watched.size === 1) {
21027
21032
  this.add(directory, item, true);
21028
21033
  }
21029
- const wp = this._getWatchedDir(path4);
21034
+ const wp = this._getWatchedDir(path6);
21030
21035
  const nestedDirectoryChildren = wp.getChildren();
21031
- nestedDirectoryChildren.forEach((nested) => this._remove(path4, nested));
21036
+ nestedDirectoryChildren.forEach((nested) => this._remove(path6, nested));
21032
21037
  const parent = this._getWatchedDir(directory);
21033
21038
  const wasTracked = parent.has(item);
21034
21039
  parent.remove(item);
21035
21040
  if (this._symlinkPaths.has(fullPath)) {
21036
21041
  this._symlinkPaths.delete(fullPath);
21037
21042
  }
21038
- let relPath = path4;
21043
+ let relPath = path6;
21039
21044
  if (this.options.cwd)
21040
- relPath = sysPath2.relative(this.options.cwd, path4);
21045
+ relPath = sysPath2.relative(this.options.cwd, path6);
21041
21046
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
21042
21047
  const event = this._pendingWrites.get(relPath).cancelWait();
21043
21048
  if (event === EVENTS.ADD)
21044
21049
  return;
21045
21050
  }
21046
- this._watched.delete(path4);
21051
+ this._watched.delete(path6);
21047
21052
  this._watched.delete(fullPath);
21048
21053
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
21049
- if (wasTracked && !this._isIgnored(path4))
21050
- this._emit(eventName, path4);
21051
- this._closePath(path4);
21054
+ if (wasTracked && !this._isIgnored(path6))
21055
+ this._emit(eventName, path6);
21056
+ this._closePath(path6);
21052
21057
  }
21053
21058
  /**
21054
21059
  * Closes all watchers for a path
21055
21060
  */
21056
- _closePath(path4) {
21057
- this._closeFile(path4);
21058
- const dir = sysPath2.dirname(path4);
21059
- this._getWatchedDir(dir).remove(sysPath2.basename(path4));
21061
+ _closePath(path6) {
21062
+ this._closeFile(path6);
21063
+ const dir = sysPath2.dirname(path6);
21064
+ this._getWatchedDir(dir).remove(sysPath2.basename(path6));
21060
21065
  }
21061
21066
  /**
21062
21067
  * Closes only file-specific watchers
21063
21068
  */
21064
- _closeFile(path4) {
21065
- const closers = this._closers.get(path4);
21069
+ _closeFile(path6) {
21070
+ const closers = this._closers.get(path6);
21066
21071
  if (!closers)
21067
21072
  return;
21068
21073
  closers.forEach((closer) => closer());
21069
- this._closers.delete(path4);
21074
+ this._closers.delete(path6);
21070
21075
  }
21071
- _addPathCloser(path4, closer) {
21076
+ _addPathCloser(path6, closer) {
21072
21077
  if (!closer)
21073
21078
  return;
21074
- let list = this._closers.get(path4);
21079
+ let list = this._closers.get(path6);
21075
21080
  if (!list) {
21076
21081
  list = [];
21077
- this._closers.set(path4, list);
21082
+ this._closers.set(path6, list);
21078
21083
  }
21079
21084
  list.push(closer);
21080
21085
  }
@@ -21106,10 +21111,10 @@ function watch(paths, options = {}) {
21106
21111
  var import_core4 = __toESM(require_dist());
21107
21112
 
21108
21113
  // src/tui/actions.ts
21109
- var import_core3 = __toESM(require_dist());
21110
21114
  import * as fs3 from "fs";
21111
21115
  import * as path from "path";
21112
21116
  import { spawnSync } from "child_process";
21117
+ var import_core3 = __toESM(require_dist());
21113
21118
  function readBrainfile(filePath) {
21114
21119
  try {
21115
21120
  const content = fs3.readFileSync(filePath, "utf-8");
@@ -21169,6 +21174,7 @@ function moveTaskAction(filePath, taskId, targetColumnId) {
21169
21174
  targetColumn.id
21170
21175
  );
21171
21176
  if (!moveResult.success) return { success: false, error: moveResult.error };
21177
+ scheduleBoardCommit(filePath, `move ${taskId}: ${targetColumn.id}`);
21172
21178
  return {
21173
21179
  success: true,
21174
21180
  message: moveResult.autoCompleted ? `Completed via ${targetColumn.title}` : `Moved to ${targetColumn.title}`
@@ -21178,6 +21184,7 @@ function moveTaskAction(filePath, taskId, targetColumnId) {
21178
21184
  if (!result.success) return { success: false, error: result.error };
21179
21185
  const writeResult = writeBrainfile(filePath, result.board);
21180
21186
  if (!writeResult.success) return writeResult;
21187
+ scheduleBoardCommit(filePath, `move ${taskId}: ${targetColumn.id}`);
21181
21188
  return { success: true, message: `Moved to ${targetColumn.title}` };
21182
21189
  }
21183
21190
  function deleteTaskAction(filePath, taskId) {
@@ -21190,12 +21197,14 @@ function deleteTaskAction(filePath, taskId) {
21190
21197
  if (!located) return { success: false, error: `Task ${taskId} not found` };
21191
21198
  const result2 = (0, import_core3.deleteTaskFile)(located.taskPath);
21192
21199
  if (!result2.success) return { success: false, error: result2.error };
21200
+ scheduleBoardCommit(filePath, `delete ${taskId}`);
21193
21201
  return { success: true, message: `Deleted ${taskId}` };
21194
21202
  }
21195
21203
  const result = (0, import_core3.deleteTask)(board, taskInfo.column.id, taskId);
21196
21204
  if (!result.success) return { success: false, error: result.error };
21197
21205
  const writeResult = writeBrainfile(filePath, result.board);
21198
21206
  if (!writeResult.success) return writeResult;
21207
+ scheduleBoardCommit(filePath, `delete ${taskId}`);
21199
21208
  return { success: true, message: `Deleted ${taskId}` };
21200
21209
  }
21201
21210
  function getArchivePath(filePath) {
@@ -21224,6 +21233,7 @@ function archiveTaskAction(filePath, taskId, options) {
21224
21233
  incompleteChildren: result2.incompleteChildren
21225
21234
  };
21226
21235
  }
21236
+ scheduleBoardCommit(filePath, `complete ${taskId}`);
21227
21237
  return { success: true, message: `Moved ${taskId} to logs` };
21228
21238
  }
21229
21239
  const { board, error } = readBrainfile(filePath);
@@ -21266,6 +21276,7 @@ function archiveTaskAction(filePath, taskId, options) {
21266
21276
  error: `Task removed from board but failed to write logs: ${err instanceof Error ? err.message : String(err)}`
21267
21277
  };
21268
21278
  }
21279
+ scheduleBoardCommit(filePath, `complete ${taskId}`);
21269
21280
  return { success: true, message: `Moved ${taskId} to logs` };
21270
21281
  }
21271
21282
  async function archiveTaskActionAsync(filePath, taskId, options) {
@@ -21397,6 +21408,7 @@ function cyclePriorityAction(filePath, taskId) {
21397
21408
  const nextPriority2 = priorities[nextIndex2];
21398
21409
  const result2 = (0, import_core3.patchTaskFile)(located.taskPath, { priority: nextPriority2 ?? null });
21399
21410
  if (!result2.success) return { success: false, error: result2.error };
21411
+ scheduleBoardCommit(filePath, `patch ${taskId}: priority ${nextPriority2 || "none"}`);
21400
21412
  return { success: true, message: `Priority: ${nextPriority2 || "none"}` };
21401
21413
  }
21402
21414
  const { board, error } = readBrainfile(filePath);
@@ -21411,6 +21423,7 @@ function cyclePriorityAction(filePath, taskId) {
21411
21423
  if (!result.success) return { success: false, error: result.error };
21412
21424
  const writeResult = writeBrainfile(filePath, result.board);
21413
21425
  if (!writeResult.success) return writeResult;
21426
+ scheduleBoardCommit(filePath, `patch ${taskId}: priority ${nextPriority || "none"}`);
21414
21427
  return { success: true, message: `Priority: ${nextPriority || "none"}` };
21415
21428
  }
21416
21429
  function toggleSubtaskAction(filePath, taskId, subtaskId) {
@@ -21424,6 +21437,7 @@ function toggleSubtaskAction(filePath, taskId, subtaskId) {
21424
21437
  error: result2.missing?.length ? `Subtask ${subtaskId} not found` : result2.error
21425
21438
  };
21426
21439
  }
21440
+ scheduleBoardCommit(filePath, `subtask toggle ${subtaskId}`);
21427
21441
  return { success: true, message: `Toggled ${subtaskId}` };
21428
21442
  }
21429
21443
  const { board, error } = readBrainfile(filePath);
@@ -21432,6 +21446,7 @@ function toggleSubtaskAction(filePath, taskId, subtaskId) {
21432
21446
  if (!result.success) return { success: false, error: result.error };
21433
21447
  const writeResult = writeBrainfile(filePath, result.board);
21434
21448
  if (!writeResult.success) return writeResult;
21449
+ scheduleBoardCommit(filePath, `subtask toggle ${subtaskId}`);
21435
21450
  return { success: true, message: `Toggled ${subtaskId}` };
21436
21451
  }
21437
21452
  function addTaskAction(filePath, columnId, taskInput) {
@@ -21459,6 +21474,7 @@ ${taskInput.description.trim()}
21459
21474
  dirs.logsDir
21460
21475
  );
21461
21476
  if (!result2.success) return { success: false, error: result2.error };
21477
+ scheduleBoardCommit(filePath, `add ${result2.task?.id || "task"}`);
21462
21478
  return { success: true, message: `Added ${result2.task?.id || "task"}` };
21463
21479
  }
21464
21480
  const result = (0, import_core3.addTask)(board, column.id, taskInput);
@@ -21467,6 +21483,7 @@ ${taskInput.description.trim()}
21467
21483
  if (!writeResult.success) return writeResult;
21468
21484
  const newColumn = result.board.columns.find((c) => c.id === column.id);
21469
21485
  const newTask = newColumn?.tasks[newColumn.tasks.length - 1];
21486
+ scheduleBoardCommit(filePath, `add ${newTask?.id || "task"}`);
21470
21487
  return { success: true, message: `Added ${newTask?.id || "task"}` };
21471
21488
  }
21472
21489
  function resolveTaskFilePath(filePath, taskId) {
@@ -21747,8 +21764,25 @@ ${getV2ChangeSignature(filePath)}`) : (0, import_core4.hashBoardContent)(content
21747
21764
  return { loadBrainfile };
21748
21765
  }
21749
21766
 
21767
+ // src/tui/hooks/useSyncStatus.ts
21768
+ var import_react35 = __toESM(require_react());
21769
+ import * as path3 from "path";
21770
+ var POLL_MS = 5e3;
21771
+ function useSyncStatus(filePath, lastUpdated) {
21772
+ const dotDir = path3.dirname(path3.resolve(filePath));
21773
+ const [label, setLabel] = (0, import_react35.useState)(() => syncStatusLabel(dotDir) ?? void 0);
21774
+ (0, import_react35.useEffect)(() => {
21775
+ const refresh = () => setLabel(syncStatusLabel(dotDir) ?? void 0);
21776
+ refresh();
21777
+ const timer = setInterval(refresh, POLL_MS);
21778
+ timer.unref?.();
21779
+ return () => clearInterval(timer);
21780
+ }, [dotDir, lastUpdated]);
21781
+ return label;
21782
+ }
21783
+
21750
21784
  // src/tui/hooks/useKeyboardNavigation.ts
21751
- var import_react36 = __toESM(require_react());
21785
+ var import_react37 = __toESM(require_react());
21752
21786
  import { spawnSync as spawnSync2 } from "child_process";
21753
21787
 
21754
21788
  // src/tui/detailStops.ts
@@ -21765,7 +21799,7 @@ function clampDetailCursor(cursor, stopCount) {
21765
21799
  }
21766
21800
 
21767
21801
  // src/tui/components/DetailView.tsx
21768
- var import_react35 = __toESM(require_react());
21802
+ var import_react36 = __toESM(require_react());
21769
21803
  var MAX_DELIVERABLES = 3;
21770
21804
  var MAX_VALIDATION_COMMANDS = 2;
21771
21805
  function computeDetailLayout(task, width, height, children, activity) {
@@ -21827,7 +21861,7 @@ function DetailView({
21827
21861
  const breadcrumbStr = truncateStart(breadcrumb.join(" \u25B8 ") || task.id, breadcrumbBudget);
21828
21862
  const headWidth = Math.max(1, contentWidth - stateText.length - 2);
21829
21863
  const head = truncate(`${breadcrumbStr} ${task.title}`, headWidth);
21830
- return /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", width, flexShrink: 0 }, /* @__PURE__ */ import_react35.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.text, bold: true }, head), /* @__PURE__ */ import_react35.default.createElement(Text, null, pad(Math.max(1, contentWidth - head.length - stateText.length))), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textSecondary }, columnLabel), priority ? /* @__PURE__ */ import_react35.default.createElement(Text, null, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textDim }, " \xB7 "), /* @__PURE__ */ import_react35.default.createElement(Text, { color: getPriorityColor(priority) }, priority)) : null)), /* @__PURE__ */ import_react35.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(contentWidth))), /* @__PURE__ */ import_react35.default.createElement(MetadataBlock, { task, parent, stacked, width }), bodyLines.length > 0 ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react35.default.createElement(
21864
+ return /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", width, flexShrink: 0 }, /* @__PURE__ */ import_react36.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.text, bold: true }, head), /* @__PURE__ */ import_react36.default.createElement(Text, null, pad(Math.max(1, contentWidth - head.length - stateText.length))), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textSecondary }, columnLabel), priority ? /* @__PURE__ */ import_react36.default.createElement(Text, null, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textDim }, " \xB7 "), /* @__PURE__ */ import_react36.default.createElement(Text, { color: getPriorityColor(priority) }, priority)) : null)), /* @__PURE__ */ import_react36.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(contentWidth))), /* @__PURE__ */ import_react36.default.createElement(MetadataBlock, { task, parent, stacked, width }), bodyLines.length > 0 ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react36.default.createElement(
21831
21865
  DescriptionHeading,
21832
21866
  {
21833
21867
  bodyOverflows,
@@ -21835,7 +21869,7 @@ function DetailView({
21835
21869
  total: bodyLines.length,
21836
21870
  contentWidth
21837
21871
  }
21838
- ), visibleBody.map((line, index) => /* @__PURE__ */ import_react35.default.createElement(
21872
+ ), visibleBody.map((line, index) => /* @__PURE__ */ import_react36.default.createElement(
21839
21873
  Text,
21840
21874
  {
21841
21875
  key: `body-${index}`,
@@ -21844,7 +21878,7 @@ function DetailView({
21844
21878
  color: line.kind === "code" ? PALETTE.textMuted : line.kind === "heading" ? PALETTE.text : PALETTE.textSecondary
21845
21879
  },
21846
21880
  line.text || " "
21847
- ))) : null, children.length > 0 ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, `children (${children.length})`), children.map((child, index) => /* @__PURE__ */ import_react35.default.createElement(
21881
+ ))) : null, children.length > 0 ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, `children (${children.length})`), children.map((child, index) => /* @__PURE__ */ import_react36.default.createElement(
21848
21882
  StopRow,
21849
21883
  {
21850
21884
  key: child.id,
@@ -21854,10 +21888,10 @@ function DetailView({
21854
21888
  rightColor: PALETTE.textSecondary,
21855
21889
  contentWidth
21856
21890
  }
21857
- ))) : null, subtasks.length > 0 ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, `subtasks (${subtasks.filter((s) => s.completed).length}/${subtasks.length})`), subtasks.map((subtask, index) => {
21891
+ ))) : null, subtasks.length > 0 ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, `subtasks (${subtasks.filter((s) => s.completed).length}/${subtasks.length})`), subtasks.map((subtask, index) => {
21858
21892
  const stopIndex = children.length + index;
21859
21893
  const glyph = subtask.completed ? GLYPHS.subtaskDone : GLYPHS.subtaskOpen;
21860
- return /* @__PURE__ */ import_react35.default.createElement(
21894
+ return /* @__PURE__ */ import_react36.default.createElement(
21861
21895
  StopRow,
21862
21896
  {
21863
21897
  key: subtask.id,
@@ -21867,7 +21901,7 @@ function DetailView({
21867
21901
  contentWidth
21868
21902
  }
21869
21903
  );
21870
- })) : null, contract ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, null, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, "contract "), /* @__PURE__ */ import_react35.default.createElement(Text, { color: getContractStateColor(contract.status) }, contract.status)), contract.deliverables?.length ? /* @__PURE__ */ import_react35.default.createElement(
21904
+ })) : null, contract ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react36.default.createElement(Text, null, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, "contract "), /* @__PURE__ */ import_react36.default.createElement(Text, { color: getContractStateColor(contract.status) }, contract.status)), contract.deliverables?.length ? /* @__PURE__ */ import_react36.default.createElement(
21871
21905
  LabeledList,
21872
21906
  {
21873
21907
  label: "deliverables",
@@ -21875,7 +21909,7 @@ function DetailView({
21875
21909
  contentWidth,
21876
21910
  color: PALETTE.textSecondary
21877
21911
  }
21878
- ) : null, contract.validation?.commands?.length ? /* @__PURE__ */ import_react35.default.createElement(
21912
+ ) : null, contract.validation?.commands?.length ? /* @__PURE__ */ import_react36.default.createElement(
21879
21913
  LabeledList,
21880
21914
  {
21881
21915
  label: "validation",
@@ -21883,11 +21917,11 @@ function DetailView({
21883
21917
  contentWidth,
21884
21918
  color: PALETTE.textMuted
21885
21919
  }
21886
- ) : null, contract.feedback ? /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, " feedback "), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.error }, truncate(contract.feedback, Math.max(1, contentWidth - 12)))) : null) : null, activity.length > 0 ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, "activity"), activity.map((entry, index) => {
21920
+ ) : null, contract.feedback ? /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, " feedback "), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.error }, truncate(contract.feedback, Math.max(1, contentWidth - 12)))) : null) : null, activity.length > 0 ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, "activity"), activity.map((entry, index) => {
21887
21921
  const stamp = entry.at ? entry.at.slice(5, 10) : " ";
21888
21922
  const prefix = ` ${stamp} `;
21889
- return /* @__PURE__ */ import_react35.default.createElement(Text, { key: `activity-${index}`, wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textDim }, prefix), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(entry.text, Math.max(1, contentWidth - prefix.length))));
21890
- })) : null, files.length > 0 ? /* @__PURE__ */ import_react35.default.createElement(Box_default, { paddingLeft: 1, marginTop: 1, width }, /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, "files "), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(files.join(" \xB7 "), Math.max(1, contentWidth - 7))))) : null);
21923
+ return /* @__PURE__ */ import_react36.default.createElement(Text, { key: `activity-${index}`, wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textDim }, prefix), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(entry.text, Math.max(1, contentWidth - prefix.length))));
21924
+ })) : null, files.length > 0 ? /* @__PURE__ */ import_react36.default.createElement(Box_default, { paddingLeft: 1, marginTop: 1, width }, /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, "files "), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(files.join(" \xB7 "), Math.max(1, contentWidth - 7))))) : null);
21891
21925
  }
21892
21926
  function DescriptionHeading({
21893
21927
  bodyOverflows,
@@ -21897,7 +21931,7 @@ function DescriptionHeading({
21897
21931
  }) {
21898
21932
  const indicator = bodyOverflows ? `${GLYPHS.scroll} ${scrollStart}/${total}` : "";
21899
21933
  const gap = Math.max(1, contentWidth - "description".length - indicator.length);
21900
- return /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, "description"), indicator ? /* @__PURE__ */ import_react35.default.createElement(Text, null, pad(gap)) : null, indicator ? /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textDim }, indicator) : null);
21934
+ return /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, "description"), indicator ? /* @__PURE__ */ import_react36.default.createElement(Text, null, pad(gap)) : null, indicator ? /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textDim }, indicator) : null);
21901
21935
  }
21902
21936
  function StopRow({
21903
21937
  selected,
@@ -21910,7 +21944,7 @@ function StopRow({
21910
21944
  const rightText = right ?? "";
21911
21945
  const leftTruncated = truncate(left, Math.max(1, contentWidth - rightText.length - 2));
21912
21946
  const gap = Math.max(1, contentWidth - leftTruncated.length - rightText.length);
21913
- return /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: selected ? void 0 : leftColor, inverse: selected }, leftTruncated), /* @__PURE__ */ import_react35.default.createElement(Text, null, pad(gap)), rightText ? /* @__PURE__ */ import_react35.default.createElement(Text, { color: rightColor }, rightText) : null);
21947
+ return /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: selected ? void 0 : leftColor, inverse: selected }, leftTruncated), /* @__PURE__ */ import_react36.default.createElement(Text, null, pad(gap)), rightText ? /* @__PURE__ */ import_react36.default.createElement(Text, { color: rightColor }, rightText) : null);
21914
21948
  }
21915
21949
  function LabeledList({
21916
21950
  label,
@@ -21919,7 +21953,7 @@ function LabeledList({
21919
21953
  color
21920
21954
  }) {
21921
21955
  const labelWidth = 16;
21922
- return /* @__PURE__ */ import_react35.default.createElement(import_react35.default.Fragment, null, items.map((item, index) => /* @__PURE__ */ import_react35.default.createElement(Text, { key: `${label}-${index}`, wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, ` ${index === 0 ? label.padEnd(labelWidth - 2) : " ".repeat(labelWidth - 2)}`), /* @__PURE__ */ import_react35.default.createElement(Text, { color }, truncate(item, Math.max(1, contentWidth - labelWidth))))));
21956
+ return /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, items.map((item, index) => /* @__PURE__ */ import_react36.default.createElement(Text, { key: `${label}-${index}`, wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, ` ${index === 0 ? label.padEnd(labelWidth - 2) : " ".repeat(labelWidth - 2)}`), /* @__PURE__ */ import_react36.default.createElement(Text, { color }, truncate(item, Math.max(1, contentWidth - labelWidth))))));
21923
21957
  }
21924
21958
  function MetadataBlock({
21925
21959
  task,
@@ -21938,9 +21972,9 @@ function MetadataBlock({
21938
21972
  ["parent", parentLabel]
21939
21973
  ];
21940
21974
  if (stacked) {
21941
- return /* @__PURE__ */ import_react35.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, width }, fields.map(([label, value]) => /* @__PURE__ */ import_react35.default.createElement(Text, { key: label, wrap: "truncate" }, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, `${label} `), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textSecondary }, value))));
21975
+ return /* @__PURE__ */ import_react36.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1, width }, fields.map(([label, value]) => /* @__PURE__ */ import_react36.default.createElement(Text, { key: label, wrap: "truncate" }, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, `${label} `), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textSecondary }, value))));
21942
21976
  }
21943
- return /* @__PURE__ */ import_react35.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react35.default.createElement(Text, { wrap: "truncate" }, fields.map(([label, value], index) => /* @__PURE__ */ import_react35.default.createElement(Text, { key: label }, index > 0 ? /* @__PURE__ */ import_react35.default.createElement(Text, null, pad(4)) : null, /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textMuted }, `${label} `), /* @__PURE__ */ import_react35.default.createElement(Text, { color: PALETTE.textSecondary }, value)))));
21977
+ return /* @__PURE__ */ import_react36.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "truncate" }, fields.map(([label, value], index) => /* @__PURE__ */ import_react36.default.createElement(Text, { key: label }, index > 0 ? /* @__PURE__ */ import_react36.default.createElement(Text, null, pad(4)) : null, /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textMuted }, `${label} `), /* @__PURE__ */ import_react36.default.createElement(Text, { color: PALETTE.textSecondary }, value)))));
21944
21978
  }
21945
21979
  function parentLabelFor(task, parent) {
21946
21980
  if (!task.parentId) return "\u2014";
@@ -21987,9 +22021,9 @@ function buildBodyLines(description, width) {
21987
22021
  // src/tui/tuiState.ts
21988
22022
  var import_core5 = __toESM(require_dist());
21989
22023
  import * as fs5 from "fs";
21990
- import * as path3 from "path";
22024
+ import * as path4 from "path";
21991
22025
  function getTuiStatePath(brainfilePath) {
21992
- return path3.join((0, import_core5.getBrainfileStateDir)(brainfilePath), import_core5.DOT_BRAINFILE_STATE_DIRNAME, "tui.json");
22026
+ return path4.join((0, import_core5.getBrainfileStateDir)(brainfilePath), import_core5.DOT_BRAINFILE_STATE_DIRNAME, "tui.json");
21993
22027
  }
21994
22028
  function readTuiState(brainfilePath) {
21995
22029
  const statePath = getTuiStatePath(brainfilePath);
@@ -22039,15 +22073,15 @@ function useKeyboardNavigation({
22039
22073
  }) {
22040
22074
  const { exit, suspendTerminal } = use_app_default();
22041
22075
  const { isRawModeSupported } = use_stdin_default();
22042
- const statusTimers = (0, import_react36.useRef)(/* @__PURE__ */ new Set());
22043
- (0, import_react36.useEffect)(
22076
+ const statusTimers = (0, import_react37.useRef)(/* @__PURE__ */ new Set());
22077
+ (0, import_react37.useEffect)(
22044
22078
  () => () => {
22045
22079
  for (const timer of statusTimers.current) clearTimeout(timer);
22046
22080
  statusTimers.current.clear();
22047
22081
  },
22048
22082
  []
22049
22083
  );
22050
- const showStatus = (0, import_react36.useCallback)(
22084
+ const showStatus = (0, import_react37.useCallback)(
22051
22085
  (text, type) => {
22052
22086
  const timestamp = Date.now();
22053
22087
  setState((prev) => ({ ...prev, statusMessage: { text, type, timestamp } }));
@@ -22061,7 +22095,7 @@ function useKeyboardNavigation({
22061
22095
  },
22062
22096
  [setState]
22063
22097
  );
22064
- const openInEditor = (0, import_react36.useCallback)(
22098
+ const openInEditor = (0, import_react37.useCallback)(
22065
22099
  (taskId) => {
22066
22100
  const located = resolveTaskFilePath(filePath, taskId);
22067
22101
  if (!located.success) {
@@ -22086,7 +22120,7 @@ function useKeyboardNavigation({
22086
22120
  },
22087
22121
  [filePath, showStatus, suspendTerminal, loadBrainfile, isRawModeSupported]
22088
22122
  );
22089
- const rememberColumn = (0, import_react36.useCallback)(
22123
+ const rememberColumn = (0, import_react37.useCallback)(
22090
22124
  (columnIndex) => {
22091
22125
  const id = allColumns[columnIndex]?.id;
22092
22126
  if (id) patchTuiState(filePath, { lastColumn: id });
@@ -22646,7 +22680,7 @@ function getTypeCycleOptions(board) {
22646
22680
  }
22647
22681
 
22648
22682
  // src/tui/components/HeaderBar.tsx
22649
- var import_react37 = __toESM(require_react());
22683
+ var import_react38 = __toESM(require_react());
22650
22684
  function HeaderBar({
22651
22685
  title,
22652
22686
  columns,
@@ -22657,7 +22691,8 @@ function HeaderBar({
22657
22691
  matchCount,
22658
22692
  totalCount,
22659
22693
  panelLabel,
22660
- activeType
22694
+ activeType,
22695
+ statusLabel
22661
22696
  }) {
22662
22697
  const affordances = CHROME.filterAffordance;
22663
22698
  const boardTitle = truncate(title, 24);
@@ -22667,18 +22702,19 @@ function HeaderBar({
22667
22702
  const active = index === activeColumnIndex;
22668
22703
  return sum + (index > 0 ? 3 : 0) + `${column.title} ${column.tasks?.length ?? 0}`.length + (active ? 1 : 0);
22669
22704
  }, 0)) + typeLabel.length;
22705
+ const status = statusLabel ? `${statusLabel} ` : "";
22670
22706
  const used = boardTitle.length + separator.length + tabsWidth;
22671
- const gap = Math.max(1, width - 1 - used - affordances.length - 1);
22707
+ const gap = Math.max(1, width - 1 - used - status.length - affordances.length - 1);
22672
22708
  return (
22673
22709
  // flexShrink={0}: a detail v2 pane can legitimately render taller than the
22674
22710
  // nominal viewport (§B1's many optional sections). Without this, yoga
22675
22711
  // shrinks *this* sibling instead of letting the column overflow, and the
22676
22712
  // header silently loses rows rather than the frame simply growing.
22677
- /* @__PURE__ */ import_react37.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react37.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react37.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.text, bold: true }, boardTitle), /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textDim }, separator), panelLabel ? /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.text }, panelLabel) : columns.map((column, index) => {
22713
+ /* @__PURE__ */ import_react38.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react38.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react38.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.text, bold: true }, boardTitle), /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textDim }, separator), panelLabel ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.text }, panelLabel) : columns.map((column, index) => {
22678
22714
  const active = index === activeColumnIndex;
22679
22715
  const count = column.tasks?.length ?? 0;
22680
- return /* @__PURE__ */ import_react37.default.createElement(Text, { key: column.id }, index > 0 ? /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textDim }, " \u2502 ") : null, /* @__PURE__ */ import_react37.default.createElement(Text, { color: active ? PALETTE.text : PALETTE.textMuted, bold: active }, `${column.title} ${count}`), active ? /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.text, bold: true }, "*") : null);
22681
- }), typeLabel ? /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textDim }, typeLabel) : null, /* @__PURE__ */ import_react37.default.createElement(Text, null, pad(gap)), /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textMuted }, affordances))), filterActive ? /* @__PURE__ */ import_react37.default.createElement(
22716
+ return /* @__PURE__ */ import_react38.default.createElement(Text, { key: column.id }, index > 0 ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textDim }, " \u2502 ") : null, /* @__PURE__ */ import_react38.default.createElement(Text, { color: active ? PALETTE.text : PALETTE.textMuted, bold: active }, `${column.title} ${count}`), active ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.text, bold: true }, "*") : null);
22717
+ }), typeLabel ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textDim }, typeLabel) : null, /* @__PURE__ */ import_react38.default.createElement(Text, null, pad(gap)), status ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: statusLabel?.startsWith("not synced \xB7") ? PALETTE.warning : PALETTE.textDim }, status) : null, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textMuted }, affordances))), filterActive ? /* @__PURE__ */ import_react38.default.createElement(
22682
22718
  FilterLine,
22683
22719
  {
22684
22720
  query: filterQuery,
@@ -22686,7 +22722,7 @@ function HeaderBar({
22686
22722
  matchCount,
22687
22723
  totalCount
22688
22724
  }
22689
- ) : /* @__PURE__ */ import_react37.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, width - 2)))))
22725
+ ) : /* @__PURE__ */ import_react38.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, width - 2)))))
22690
22726
  );
22691
22727
  }
22692
22728
  function FilterLine({
@@ -22698,11 +22734,11 @@ function FilterLine({
22698
22734
  const count = matchCount === void 0 || totalCount === void 0 ? "" : matchCountLabel(matchCount, totalCount, query);
22699
22735
  const input = `/${query}`;
22700
22736
  const gap = Math.max(1, width - 2 - input.length - 1 - count.length);
22701
- return /* @__PURE__ */ import_react37.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react37.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.accent }, input), /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.accent }, GLYPHS.cursor), /* @__PURE__ */ import_react37.default.createElement(Text, null, pad(gap)), /* @__PURE__ */ import_react37.default.createElement(Text, { color: PALETTE.textMuted }, count || " ")));
22737
+ return /* @__PURE__ */ import_react38.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react38.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.accent }, input), /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.accent }, GLYPHS.cursor), /* @__PURE__ */ import_react38.default.createElement(Text, null, pad(gap)), /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textMuted }, count || " ")));
22702
22738
  }
22703
22739
 
22704
22740
  // src/tui/components/FooterBar.tsx
22705
- var import_react38 = __toESM(require_react());
22741
+ var import_react39 = __toESM(require_react());
22706
22742
  function browseActions(selected, archived = false) {
22707
22743
  if (archived) return ["\u21B5 detail", "e edit", "t type", "L board", "q quit"];
22708
22744
  const actions = ["\u21B5 detail", "m move"];
@@ -22742,12 +22778,12 @@ function FooterBar({
22742
22778
  return (
22743
22779
  // flexShrink={0}: see HeaderBar's matching comment — the footer must not
22744
22780
  // be the thing that silently loses rows when detail v2 overflows.
22745
- /* @__PURE__ */ import_react38.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, showRule ? /* @__PURE__ */ import_react38.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, width - 2)))) : null, /* @__PURE__ */ import_react38.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react38.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textMuted }, text), /* @__PURE__ */ import_react38.default.createElement(Text, null, pad(gap)), quit ? /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textMuted }, quit) : null, quit && chip ? /* @__PURE__ */ import_react38.default.createElement(Text, null, pad(2)) : null, /* @__PURE__ */ import_react38.default.createElement(Text, { color: PALETTE.textSecondary }, chip || " "))))
22781
+ /* @__PURE__ */ import_react39.default.createElement(Box_default, { flexDirection: "column", flexShrink: 0 }, showRule ? /* @__PURE__ */ import_react39.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react39.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, width - 2)))) : null, /* @__PURE__ */ import_react39.default.createElement(Box_default, { paddingLeft: 1, width }, /* @__PURE__ */ import_react39.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react39.default.createElement(Text, { color: PALETTE.textMuted }, text), /* @__PURE__ */ import_react39.default.createElement(Text, null, pad(gap)), quit ? /* @__PURE__ */ import_react39.default.createElement(Text, { color: PALETTE.textMuted }, quit) : null, quit && chip ? /* @__PURE__ */ import_react39.default.createElement(Text, null, pad(2)) : null, /* @__PURE__ */ import_react39.default.createElement(Text, { color: PALETTE.textSecondary }, chip || " "))))
22746
22782
  );
22747
22783
  }
22748
22784
 
22749
22785
  // src/tui/components/DocumentRow.tsx
22750
- var import_react39 = __toESM(require_react());
22786
+ var import_react40 = __toESM(require_react());
22751
22787
  var MAX_CHIPS = 3;
22752
22788
  function buildChips(row) {
22753
22789
  const chips = [];
@@ -22794,11 +22830,11 @@ function DocumentRow({ row, selected, width, idWidth, archived = false }) {
22794
22830
  const title = truncate(task.title, titleWidth);
22795
22831
  const gap = Math.max(1, width - leftWidth - title.length - rightWidth - 1);
22796
22832
  const dim = selected ? void 0 : PALETTE.textMuted;
22797
- return /* @__PURE__ */ import_react39.default.createElement(Text, { wrap: "truncate", inverse: selected }, /* @__PURE__ */ import_react39.default.createElement(Text, null, indent), /* @__PURE__ */ import_react39.default.createElement(Text, { color: selected ? void 0 : PALETTE.textSecondary }, glyphCell), /* @__PURE__ */ import_react39.default.createElement(Text, { color: dim }, idCell), /* @__PURE__ */ import_react39.default.createElement(Text, { color: selected ? void 0 : archived ? PALETTE.textMuted : PALETTE.text }, title), /* @__PURE__ */ import_react39.default.createElement(Text, null, pad(gap)), rightSegments.map((seg, index) => /* @__PURE__ */ import_react39.default.createElement(Text, { key: `${seg.text}-${index}` }, index > 0 ? /* @__PURE__ */ import_react39.default.createElement(Text, null, pad(2)) : null, /* @__PURE__ */ import_react39.default.createElement(Text, { color: selected ? void 0 : seg.color }, seg.text))), /* @__PURE__ */ import_react39.default.createElement(Text, null, pad(1)));
22833
+ return /* @__PURE__ */ import_react40.default.createElement(Text, { wrap: "truncate", inverse: selected }, /* @__PURE__ */ import_react40.default.createElement(Text, null, indent), /* @__PURE__ */ import_react40.default.createElement(Text, { color: selected ? void 0 : PALETTE.textSecondary }, glyphCell), /* @__PURE__ */ import_react40.default.createElement(Text, { color: dim }, idCell), /* @__PURE__ */ import_react40.default.createElement(Text, { color: selected ? void 0 : archived ? PALETTE.textMuted : PALETTE.text }, title), /* @__PURE__ */ import_react40.default.createElement(Text, null, pad(gap)), rightSegments.map((seg, index) => /* @__PURE__ */ import_react40.default.createElement(Text, { key: `${seg.text}-${index}` }, index > 0 ? /* @__PURE__ */ import_react40.default.createElement(Text, null, pad(2)) : null, /* @__PURE__ */ import_react40.default.createElement(Text, { color: selected ? void 0 : seg.color }, seg.text))), /* @__PURE__ */ import_react40.default.createElement(Text, null, pad(1)));
22798
22834
  }
22799
22835
 
22800
22836
  // src/tui/components/DocumentList.tsx
22801
- var import_react40 = __toESM(require_react());
22837
+ var import_react41 = __toESM(require_react());
22802
22838
  function DocumentList({
22803
22839
  rows,
22804
22840
  selectedIndex,
@@ -22808,11 +22844,11 @@ function DocumentList({
22808
22844
  emptyMessage = EMPTY.noDocuments
22809
22845
  }) {
22810
22846
  if (rows.length === 0) {
22811
- return /* @__PURE__ */ import_react40.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react40.default.createElement(Text, { color: PALETTE.textMuted }, emptyMessage));
22847
+ return /* @__PURE__ */ import_react41.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.textMuted }, emptyMessage));
22812
22848
  }
22813
22849
  const { visible, start } = windowRows(rows, selectedIndex, viewportHeight);
22814
22850
  const idWidth = Math.max(6, ...visible.map((row) => row.task.id.length));
22815
- return /* @__PURE__ */ import_react40.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1 }, visible.map((row, index) => /* @__PURE__ */ import_react40.default.createElement(
22851
+ return /* @__PURE__ */ import_react41.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1 }, visible.map((row, index) => /* @__PURE__ */ import_react41.default.createElement(
22816
22852
  DocumentRow,
22817
22853
  {
22818
22854
  key: row.task.id,
@@ -22826,7 +22862,7 @@ function DocumentList({
22826
22862
  }
22827
22863
 
22828
22864
  // src/tui/components/HelpOverlay.tsx
22829
- var import_react41 = __toESM(require_react());
22865
+ var import_react42 = __toESM(require_react());
22830
22866
  var LIST = {
22831
22867
  heading: "list",
22832
22868
  rows: [
@@ -22885,25 +22921,25 @@ var KEYS_WIDTH = 14;
22885
22921
  function HelpOverlay({ termWidth, termHeight }) {
22886
22922
  const columnWidth = Math.max(24, Math.floor((termWidth - 4) / COLUMNS.length));
22887
22923
  const descriptionWidth = Math.max(6, columnWidth - KEYS_WIDTH - 2);
22888
- return /* @__PURE__ */ import_react41.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight, paddingLeft: 1 }, /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.text, bold: true }, CHROME.helpTitle), /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, termWidth - 2))), /* @__PURE__ */ import_react41.default.createElement(Box_default, { marginTop: 1 }, COLUMNS.map((column, columnIndex) => /* @__PURE__ */ import_react41.default.createElement(Box_default, { key: columnIndex, flexDirection: "column", width: columnWidth }, column.map((group, groupIndex) => /* @__PURE__ */ import_react41.default.createElement(
22924
+ return /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight, paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.text, bold: true }, CHROME.helpTitle), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textDim }, RULE.repeat(Math.max(1, termWidth - 2))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1 }, COLUMNS.map((column, columnIndex) => /* @__PURE__ */ import_react42.default.createElement(Box_default, { key: columnIndex, flexDirection: "column", width: columnWidth }, column.map((group, groupIndex) => /* @__PURE__ */ import_react42.default.createElement(
22889
22925
  Box_default,
22890
22926
  {
22891
22927
  key: group.heading,
22892
22928
  flexDirection: "column",
22893
22929
  marginTop: groupIndex === 0 ? 0 : 1
22894
22930
  },
22895
- /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.textSecondary, bold: true }, group.heading),
22896
- group.rows.map(([keys, description]) => /* @__PURE__ */ import_react41.default.createElement(Text, { key: keys, wrap: "truncate" }, /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.text }, keys.padEnd(KEYS_WIDTH)), /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.textMuted }, truncate(description, descriptionWidth))))
22897
- ))))), /* @__PURE__ */ import_react41.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react41.default.createElement(Text, { color: PALETTE.textDim }, CHROME.helpDismiss)));
22931
+ /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textSecondary, bold: true }, group.heading),
22932
+ group.rows.map(([keys, description]) => /* @__PURE__ */ import_react42.default.createElement(Text, { key: keys, wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.text }, keys.padEnd(KEYS_WIDTH)), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, truncate(description, descriptionWidth))))
22933
+ ))))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textDim }, CHROME.helpDismiss)));
22898
22934
  }
22899
22935
 
22900
22936
  // src/tui/components/Overlays.tsx
22901
- var import_react42 = __toESM(require_react());
22937
+ var import_react43 = __toESM(require_react());
22902
22938
  function StatusMessageDisplay({ message }) {
22903
22939
  if (!message) return null;
22904
22940
  const color = message.type === "success" ? PALETTE.success : message.type === "error" ? PALETTE.error : PALETTE.textSecondary;
22905
22941
  const glyph = message.type === "success" ? GLYPHS.success : message.type === "error" ? GLYPHS.error : GLYPHS.live;
22906
- return /* @__PURE__ */ import_react42.default.createElement(Box_default, { paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color, wrap: "truncate" }, `${glyph} ${message.text}`));
22942
+ return /* @__PURE__ */ import_react43.default.createElement(Box_default, { paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color, wrap: "truncate" }, `${glyph} ${message.text}`));
22907
22943
  }
22908
22944
  function MoveOverlay({
22909
22945
  columns,
@@ -22912,16 +22948,16 @@ function MoveOverlay({
22912
22948
  taskTitle,
22913
22949
  width
22914
22950
  }) {
22915
- return /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, "move"), /* @__PURE__ */ import_react42.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, ` ${taskId} `), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.text }, truncate(taskTitle, Math.max(1, width - taskId.length - 6)))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", marginTop: 1, paddingLeft: 2 }, columns.map((column, index) => /* @__PURE__ */ import_react42.default.createElement(Text, { key: column.id, inverse: index === selectedIndex, wrap: "truncate" }, `${index + 1} ${column.title}`))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, "\u2191\u2193 select \xB7 1-", columns.length, " jump \xB7 \u21B5 confirm \xB7 esc cancel")));
22951
+ return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "move"), /* @__PURE__ */ import_react43.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, ` ${taskId} `), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.text }, truncate(taskTitle, Math.max(1, width - taskId.length - 6)))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", marginTop: 1, paddingLeft: 2 }, columns.map((column, index) => /* @__PURE__ */ import_react43.default.createElement(Text, { key: column.id, inverse: index === selectedIndex, wrap: "truncate" }, `${index + 1} ${column.title}`))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "\u2191\u2193 select \xB7 1-", columns.length, " jump \xB7 \u21B5 confirm \xB7 esc cancel")));
22916
22952
  }
22917
22953
  function DeleteConfirmOverlay({ taskId, taskTitle, width }) {
22918
- return /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.error }, "delete"), /* @__PURE__ */ import_react42.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, ` ${taskId} `), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.text }, truncate(taskTitle, Math.max(1, width - taskId.length - 6)))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, "Deletes the file. This cannot be undone.")), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, "y delete \xB7 n cancel")));
22954
+ return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.error }, "delete"), /* @__PURE__ */ import_react43.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, ` ${taskId} `), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.text }, truncate(taskTitle, Math.max(1, width - taskId.length - 6)))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "Deletes the file. This cannot be undone.")), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "y delete \xB7 n cancel")));
22919
22955
  }
22920
22956
  function CompleteConfirmOverlay({ target, width }) {
22921
- return /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.warning }, "complete"), /* @__PURE__ */ import_react42.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, ` ${target.id} `), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.text }, truncate(target.title, Math.max(1, width - target.id.length - 6)))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, incompleteChildrenLabel(target.incompleteChildren.length))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 4 }, target.incompleteChildren.map((child) => /* @__PURE__ */ import_react42.default.createElement(Text, { key: child.id, wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, `${child.id} `), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(child.title, Math.max(1, width - child.id.length - 8)))))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, "y complete anyway \xB7 n cancel")));
22957
+ return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.warning }, "complete"), /* @__PURE__ */ import_react43.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, ` ${target.id} `), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.text }, truncate(target.title, Math.max(1, width - target.id.length - 6)))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, incompleteChildrenLabel(target.incompleteChildren.length))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 4 }, target.incompleteChildren.map((child) => /* @__PURE__ */ import_react43.default.createElement(Text, { key: child.id, wrap: "truncate" }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, `${child.id} `), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textSecondary }, truncate(child.title, Math.max(1, width - child.id.length - 8)))))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "y complete anyway \xB7 n cancel")));
22922
22958
  }
22923
22959
  function AddOverlay({ title, columnName, thenEdit = false }) {
22924
- return /* @__PURE__ */ import_react42.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, thenEdit ? `add to ${columnName}, then edit` : `add to ${columnName}`), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: title ? PALETTE.text : PALETTE.textMuted }, title || "title\u2026"), /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.accent }, GLYPHS.cursor))), /* @__PURE__ */ import_react42.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react42.default.createElement(Text, { color: PALETTE.textMuted }, thenEdit ? "\u21B5 create and edit \xB7 esc cancel" : "\u21B5 create \xB7 esc cancel")));
22960
+ return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", flexGrow: 1, paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, thenEdit ? `add to ${columnName}, then edit` : `add to ${columnName}`), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { wrap: "truncate" }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: title ? PALETTE.text : PALETTE.textMuted }, title || "title\u2026"), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.accent }, GLYPHS.cursor))), /* @__PURE__ */ import_react43.default.createElement(Box_default, { marginTop: 1, paddingLeft: 2 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, thenEdit ? "\u21B5 create and edit \xB7 esc cancel" : "\u21B5 create \xB7 esc cancel")));
22925
22961
  }
22926
22962
 
22927
22963
  // src/tui/BrainfileTUI.tsx
@@ -22950,11 +22986,11 @@ var baseInitialState = {
22950
22986
  };
22951
22987
  function BrainfileTUI({ filePath, width, height }) {
22952
22988
  const { stdout } = use_stdout_default();
22953
- const [dimensions, setDimensions] = (0, import_react43.useState)({
22989
+ const [dimensions, setDimensions] = (0, import_react44.useState)({
22954
22990
  width: width ?? stdout?.columns ?? process.stdout.columns ?? 80,
22955
22991
  height: height ?? stdout?.rows ?? process.stdout.rows ?? 24
22956
22992
  });
22957
- (0, import_react43.useEffect)(() => {
22993
+ (0, import_react44.useEffect)(() => {
22958
22994
  if (width !== void 0 && height !== void 0) return void 0;
22959
22995
  const handleResize = () => {
22960
22996
  setDimensions({
@@ -22971,8 +23007,8 @@ function BrainfileTUI({ filePath, width, height }) {
22971
23007
  const termHeight = height ?? dimensions.height;
22972
23008
  const isTooSmall = termWidth < LAYOUT.MIN_WIDTH || termHeight < LAYOUT.MIN_HEIGHT;
22973
23009
  const layoutMode = termWidth >= LAYOUT.DETAIL_PANE_MIN_WIDTH ? "wide" : "narrow";
22974
- const resumeColumn = (0, import_react43.useRef)(void 0);
22975
- const [state, setState] = (0, import_react43.useState)(() => {
23010
+ const resumeColumn = (0, import_react44.useRef)(void 0);
23011
+ const [state, setState] = (0, import_react44.useState)(() => {
22976
23012
  const persisted = readTuiState(filePath);
22977
23013
  resumeColumn.current = persisted.lastColumn;
22978
23014
  return {
@@ -22984,7 +23020,8 @@ function BrainfileTUI({ filePath, width, height }) {
22984
23020
  });
22985
23021
  const viewportHeight = Math.max(termHeight - HEADER_ROWS - FOOTER_ROWS, 3);
22986
23022
  const { loadBrainfile } = useBrainfileLoader(filePath, state, setState);
22987
- const orderedColumns = (0, import_react43.useMemo)(() => {
23023
+ const syncStatus = useSyncStatus(filePath, state.lastUpdated);
23024
+ const orderedColumns = (0, import_react44.useMemo)(() => {
22988
23025
  if (!state.board) return [];
22989
23026
  return [...state.board.columns].sort((a, b) => {
22990
23027
  const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
@@ -22992,24 +23029,24 @@ function BrainfileTUI({ filePath, width, height }) {
22992
23029
  return orderA - orderB;
22993
23030
  });
22994
23031
  }, [state.board]);
22995
- const typeCycleOptions = (0, import_react43.useMemo)(() => getTypeCycleOptions(state.board), [state.board]);
23032
+ const typeCycleOptions = (0, import_react44.useMemo)(() => getTypeCycleOptions(state.board), [state.board]);
22996
23033
  const activeTypeFilter = typeCycleOptions.includes(state.activeTypeFilter) ? state.activeTypeFilter : "all";
22997
23034
  const typeFilterActive = activeTypeFilter !== "all";
22998
23035
  const doneView = state.doneView;
22999
- const typeFilteredColumns = (0, import_react43.useMemo)(() => {
23036
+ const typeFilteredColumns = (0, import_react44.useMemo)(() => {
23000
23037
  if (!typeFilterActive) return orderedColumns;
23001
23038
  return orderedColumns.map((column) => ({
23002
23039
  ...column,
23003
23040
  tasks: (column.tasks ?? []).filter((task) => getDocType(task) === activeTypeFilter)
23004
23041
  }));
23005
23042
  }, [orderedColumns, typeFilterActive, doneView, activeTypeFilter]);
23006
- const totalCount = (0, import_react43.useMemo)(
23043
+ const totalCount = (0, import_react44.useMemo)(
23007
23044
  () => doneView ? typeFilterActive ? state.logs.filter((task) => getDocType(task) === activeTypeFilter).length : state.logs.length : typeFilteredColumns.reduce((sum, column) => sum + (column.tasks?.length ?? 0), 0),
23008
23045
  [typeFilteredColumns, doneView, state.logs]
23009
23046
  );
23010
23047
  const filterQuery = state.filterQuery.trim();
23011
23048
  const hasFilter = filterQuery.length > 0;
23012
- const filteredColumns = (0, import_react43.useMemo)(() => {
23049
+ const filteredColumns = (0, import_react44.useMemo)(() => {
23013
23050
  if (!hasFilter) return typeFilteredColumns;
23014
23051
  return typeFilteredColumns.map((column) => {
23015
23052
  const docs = (column.tasks ?? []).map((task) => ({ task, body: task.description ?? "" }));
@@ -23017,14 +23054,14 @@ function BrainfileTUI({ filePath, width, height }) {
23017
23054
  return { ...column, tasks: matches.map((match) => match.doc.task) };
23018
23055
  });
23019
23056
  }, [typeFilteredColumns, hasFilter, filterQuery]);
23020
- const filteredLogs = (0, import_react43.useMemo)(() => {
23057
+ const filteredLogs = (0, import_react44.useMemo)(() => {
23021
23058
  if (!doneView) return [];
23022
23059
  const typed = typeFilterActive ? state.logs.filter((task) => getDocType(task) === activeTypeFilter) : state.logs;
23023
23060
  if (!hasFilter) return typed;
23024
23061
  const docs = typed.map((task) => ({ task, body: task.description ?? "" }));
23025
23062
  return (0, import_core6.searchTasksRanked)(docs, filterQuery).map((match) => match.doc.task);
23026
23063
  }, [doneView, state.logs, typeFilterActive, activeTypeFilter, hasFilter, filterQuery]);
23027
- const matchCount = (0, import_react43.useMemo)(
23064
+ const matchCount = (0, import_react44.useMemo)(
23028
23065
  () => doneView ? filteredLogs.length : filteredColumns.reduce((sum, column) => sum + (column.tasks?.length ?? 0), 0),
23029
23066
  [filteredColumns, doneView, filteredLogs]
23030
23067
  );
@@ -23033,30 +23070,30 @@ function BrainfileTUI({ filePath, width, height }) {
23033
23070
  Math.max(0, filteredColumns.length - 1)
23034
23071
  );
23035
23072
  const currentColumn = filteredColumns[activeColumnIndex];
23036
- const rows = (0, import_react43.useMemo)(
23073
+ const rows = (0, import_react44.useMemo)(
23037
23074
  () => doneView ? buildFlatRows(filteredLogs) : typeFilterActive ? buildFlatRows(currentColumn?.tasks ?? []) : buildRows(currentColumn?.tasks ?? [], state.collapsedIds),
23038
23075
  [currentColumn, doneView, filteredLogs, typeFilterActive, state.collapsedIds]
23039
23076
  );
23040
23077
  const maxRowIndex = Math.max(0, rows.length - 1);
23041
23078
  const selectedIndex = Math.min(state.selectedTaskIndex, maxRowIndex);
23042
23079
  const selectedTask = rows[selectedIndex]?.task;
23043
- const allBoardTasks = (0, import_react43.useMemo)(
23080
+ const allBoardTasks = (0, import_react44.useMemo)(
23044
23081
  () => orderedColumns.flatMap((column) => column.tasks ?? []),
23045
23082
  [orderedColumns]
23046
23083
  );
23047
- const allDocs = (0, import_react43.useMemo)(
23084
+ const allDocs = (0, import_react44.useMemo)(
23048
23085
  () => [...allBoardTasks, ...state.logs],
23049
23086
  [allBoardTasks, state.logs]
23050
23087
  );
23051
- const archivedIds = (0, import_react43.useMemo)(() => new Set(state.logs.map((t) => t.id)), [state.logs]);
23088
+ const archivedIds = (0, import_react44.useMemo)(() => new Set(state.logs.map((t) => t.id)), [state.logs]);
23052
23089
  const detailTaskId = state.detailPath[state.detailPath.length - 1];
23053
23090
  const detailTask = state.detailPath.length > 0 ? allDocs.find((t) => t.id === detailTaskId) : void 0;
23054
- const detailChildren = (0, import_react43.useMemo)(
23091
+ const detailChildren = (0, import_react44.useMemo)(
23055
23092
  () => detailTask ? allDocs.filter((t) => t.parentId === detailTask.id) : [],
23056
23093
  [allDocs, detailTask]
23057
23094
  );
23058
23095
  const detailParent = detailTask?.parentId ? allDocs.find((t) => t.id === detailTask.parentId) : void 0;
23059
- const detailColumnLabel = (0, import_react43.useMemo)(() => {
23096
+ const detailColumnLabel = (0, import_react44.useMemo)(() => {
23060
23097
  if (!detailTask) return "";
23061
23098
  if (archivedIds.has(detailTask.id)) {
23062
23099
  const at = detailTask.completedAt;
@@ -23064,7 +23101,7 @@ function BrainfileTUI({ filePath, width, height }) {
23064
23101
  }
23065
23102
  return orderedColumns.find((c) => c.tasks?.some((t) => t.id === detailTask.id))?.id ?? "";
23066
23103
  }, [orderedColumns, detailTask, archivedIds]);
23067
- const detailActivity = (0, import_react43.useMemo)(
23104
+ const detailActivity = (0, import_react44.useMemo)(
23068
23105
  () => detailTask ? getTaskActivity(filePath, detailTask.id) : [],
23069
23106
  [detailTask, filePath, state.lastUpdated]
23070
23107
  );
@@ -23074,14 +23111,14 @@ function BrainfileTUI({ filePath, width, height }) {
23074
23111
  const detailViewWidth = fullscreenDetailMode ? termWidth : detailPaneWidth;
23075
23112
  const detailViewHeight = fullscreenDetailMode ? termHeight - FOOTER_ROWS : viewportHeight;
23076
23113
  const detailLayout = detailTask ? computeDetailLayout(detailTask, detailViewWidth, detailViewHeight, detailChildren, detailActivity) : null;
23077
- (0, import_react43.useEffect)(() => {
23114
+ (0, import_react44.useEffect)(() => {
23078
23115
  const wanted = resumeColumn.current;
23079
23116
  if (!wanted || orderedColumns.length === 0) return;
23080
23117
  resumeColumn.current = void 0;
23081
23118
  const idx = orderedColumns.findIndex((c) => c.id === wanted);
23082
23119
  if (idx > 0) setState((prev) => ({ ...prev, activeColumnIndex: idx }));
23083
23120
  }, [orderedColumns]);
23084
- (0, import_react43.useEffect)(() => {
23121
+ (0, import_react44.useEffect)(() => {
23085
23122
  setState((prev) => ({
23086
23123
  ...prev,
23087
23124
  activeColumnIndex: Math.min(prev.activeColumnIndex, Math.max(0, filteredColumns.length - 1)),
@@ -23108,16 +23145,16 @@ function BrainfileTUI({ filePath, width, height }) {
23108
23145
  detailArchived: Boolean(detailTask && archivedIds.has(detailTask.id))
23109
23146
  });
23110
23147
  if (isTooSmall) {
23111
- return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight, paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.error }, CHROME.tooSmall), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, "Minimum ", LAYOUT.MIN_WIDTH, "\xD7", LAYOUT.MIN_HEIGHT, " \xB7 current ", termWidth, "\xD7", termHeight));
23148
+ return /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight, paddingLeft: 1 }, /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.error }, CHROME.tooSmall), /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.textMuted }, "Minimum ", LAYOUT.MIN_WIDTH, "\xD7", LAYOUT.MIN_HEIGHT, " \xB7 current ", termWidth, "\xD7", termHeight));
23112
23149
  }
23113
23150
  if (state.error) {
23114
- return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.error }, CHROME.errorTitle), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textSecondary }, state.error), /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, CHROME.errorHint));
23151
+ return /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexDirection: "column", paddingLeft: 1 }, /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.error }, CHROME.errorTitle), /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.textSecondary }, state.error), /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.textMuted }, CHROME.errorHint));
23115
23152
  }
23116
23153
  if (!state.board) {
23117
- return /* @__PURE__ */ import_react43.default.createElement(Box_default, { paddingLeft: 1 }, /* @__PURE__ */ import_react43.default.createElement(Text, { color: PALETTE.textMuted }, CHROME.loading));
23154
+ return /* @__PURE__ */ import_react44.default.createElement(Box_default, { paddingLeft: 1 }, /* @__PURE__ */ import_react44.default.createElement(Text, { color: PALETTE.textMuted }, CHROME.loading));
23118
23155
  }
23119
23156
  if (state.mode === "help") {
23120
- return /* @__PURE__ */ import_react43.default.createElement(HelpOverlay, { termWidth, termHeight });
23157
+ return /* @__PURE__ */ import_react44.default.createElement(HelpOverlay, { termWidth, termHeight });
23121
23158
  }
23122
23159
  const boardTitle = state.board.title || "brainfile";
23123
23160
  const columnLabel = doneView ? "done" : currentColumn?.id ?? "";
@@ -23133,7 +23170,7 @@ function BrainfileTUI({ filePath, width, height }) {
23133
23170
  archived: detailArchived
23134
23171
  };
23135
23172
  if (fullscreenDetail && detailTask) {
23136
- return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight }, /* @__PURE__ */ import_react43.default.createElement(
23173
+ return /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight }, /* @__PURE__ */ import_react44.default.createElement(
23137
23174
  DetailView,
23138
23175
  {
23139
23176
  task: detailTask,
@@ -23147,7 +23184,7 @@ function BrainfileTUI({ filePath, width, height }) {
23147
23184
  cursor: state.detailCursor,
23148
23185
  scrollOffset: state.detailScroll
23149
23186
  }
23150
- ), /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexGrow: 1 }), /* @__PURE__ */ import_react43.default.createElement(Box_default, { height: 1, flexShrink: 0 }, /* @__PURE__ */ import_react43.default.createElement(StatusMessageDisplay, { message: state.statusMessage })), /* @__PURE__ */ import_react43.default.createElement(
23187
+ ), /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexGrow: 1 }), /* @__PURE__ */ import_react44.default.createElement(Box_default, { height: 1, flexShrink: 0 }, /* @__PURE__ */ import_react44.default.createElement(StatusMessageDisplay, { message: state.statusMessage })), /* @__PURE__ */ import_react44.default.createElement(
23151
23188
  FooterBar,
23152
23189
  {
23153
23190
  width: termWidth,
@@ -23158,7 +23195,7 @@ function BrainfileTUI({ filePath, width, height }) {
23158
23195
  }
23159
23196
  const listWidth = detailOpen ? termWidth - detailPaneWidth : termWidth;
23160
23197
  const footerActions = detailOpen ? detailActions(detailFooterCtx) : browseActions(selectedTask, doneView);
23161
- return /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight }, /* @__PURE__ */ import_react43.default.createElement(
23198
+ return /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexDirection: "column", width: termWidth, height: termHeight }, /* @__PURE__ */ import_react44.default.createElement(
23162
23199
  HeaderBar,
23163
23200
  {
23164
23201
  title: boardTitle,
@@ -23170,9 +23207,10 @@ function BrainfileTUI({ filePath, width, height }) {
23170
23207
  matchCount,
23171
23208
  totalCount,
23172
23209
  panelLabel: doneView ? "done" : void 0,
23173
- activeType: typeFilterActive ? activeTypeFilter : "all"
23210
+ activeType: typeFilterActive ? activeTypeFilter : "all",
23211
+ statusLabel: syncStatus
23174
23212
  }
23175
- ), /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexGrow: 1, flexShrink: 0, flexDirection: "column" }, /* @__PURE__ */ import_react43.default.createElement(
23213
+ ), /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexGrow: 1, flexShrink: 0, flexDirection: "column" }, /* @__PURE__ */ import_react44.default.createElement(
23176
23214
  BoardContent,
23177
23215
  {
23178
23216
  state,
@@ -23196,7 +23234,7 @@ function BrainfileTUI({ filePath, width, height }) {
23196
23234
  typeFilter: typeFilterActive ? activeTypeFilter : void 0,
23197
23235
  thenEdit: state.addThenEdit
23198
23236
  }
23199
- )), /* @__PURE__ */ import_react43.default.createElement(Box_default, { height: 1, flexShrink: 0 }, /* @__PURE__ */ import_react43.default.createElement(StatusMessageDisplay, { message: state.statusMessage })), /* @__PURE__ */ import_react43.default.createElement(
23237
+ )), /* @__PURE__ */ import_react44.default.createElement(Box_default, { height: 1, flexShrink: 0 }, /* @__PURE__ */ import_react44.default.createElement(StatusMessageDisplay, { message: state.statusMessage })), /* @__PURE__ */ import_react44.default.createElement(
23200
23238
  FooterBar,
23201
23239
  {
23202
23240
  width: termWidth,
@@ -23230,7 +23268,7 @@ function BoardContent({
23230
23268
  }) {
23231
23269
  const overlayTarget = state.detailPath.length > 0 ? detailTask : selectedTask;
23232
23270
  if (state.mode === "move" && overlayTarget) {
23233
- return /* @__PURE__ */ import_react43.default.createElement(
23271
+ return /* @__PURE__ */ import_react44.default.createElement(
23234
23272
  MoveOverlay,
23235
23273
  {
23236
23274
  columns,
@@ -23242,7 +23280,7 @@ function BoardContent({
23242
23280
  );
23243
23281
  }
23244
23282
  if (state.mode === "delete-confirm" && overlayTarget) {
23245
- return /* @__PURE__ */ import_react43.default.createElement(
23283
+ return /* @__PURE__ */ import_react44.default.createElement(
23246
23284
  DeleteConfirmOverlay,
23247
23285
  {
23248
23286
  taskId: overlayTarget.id,
@@ -23252,12 +23290,12 @@ function BoardContent({
23252
23290
  );
23253
23291
  }
23254
23292
  if (state.mode === "complete-confirm" && state.completeConfirm) {
23255
- return /* @__PURE__ */ import_react43.default.createElement(CompleteConfirmOverlay, { target: state.completeConfirm, width: termWidth });
23293
+ return /* @__PURE__ */ import_react44.default.createElement(CompleteConfirmOverlay, { target: state.completeConfirm, width: termWidth });
23256
23294
  }
23257
23295
  if (state.mode === "add") {
23258
- return /* @__PURE__ */ import_react43.default.createElement(AddOverlay, { title: state.newTaskTitle, columnName, thenEdit });
23296
+ return /* @__PURE__ */ import_react44.default.createElement(AddOverlay, { title: state.newTaskTitle, columnName, thenEdit });
23259
23297
  }
23260
- const list = /* @__PURE__ */ import_react43.default.createElement(
23298
+ const list = /* @__PURE__ */ import_react44.default.createElement(
23261
23299
  DocumentList,
23262
23300
  {
23263
23301
  rows,
@@ -23276,7 +23314,7 @@ function BoardContent({
23276
23314
  // shrink to fit corrupts the layout — rows silently lose height and their
23277
23315
  // text vanishes — rather than the frame simply growing taller, which ink
23278
23316
  // and real terminals handle fine.
23279
- /* @__PURE__ */ import_react43.default.createElement(Box_default, { flexDirection: "row", flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ import_react43.default.createElement(Box_default, { width: listWidth, flexDirection: "column", flexShrink: 0 }, list), /* @__PURE__ */ import_react43.default.createElement(Box_default, { width: detailPaneWidth, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react43.default.createElement(
23317
+ /* @__PURE__ */ import_react44.default.createElement(Box_default, { flexDirection: "row", flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ import_react44.default.createElement(Box_default, { width: listWidth, flexDirection: "column", flexShrink: 0 }, list), /* @__PURE__ */ import_react44.default.createElement(Box_default, { width: detailPaneWidth, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ import_react44.default.createElement(
23280
23318
  DetailView,
23281
23319
  {
23282
23320
  task: detailTask,
@@ -23295,6 +23333,7 @@ function BoardContent({
23295
23333
  }
23296
23334
 
23297
23335
  // src/commands/tui.tsx
23336
+ import * as path5 from "path";
23298
23337
  async function tuiCommand(options) {
23299
23338
  const filePath = resolveCliBrainfilePath(options.file);
23300
23339
  if (!fs6.existsSync(filePath)) {
@@ -23314,7 +23353,10 @@ async function tuiCommand(options) {
23314
23353
  console.log("");
23315
23354
  markV2MigrationHintShown(filePath);
23316
23355
  }
23317
- const { waitUntilExit } = render_default(/* @__PURE__ */ import_react44.default.createElement(BrainfileTUI, { filePath }));
23356
+ installAutosync();
23357
+ const fetched = fetchBeforeRead(path5.dirname(filePath));
23358
+ if (fetched && !fetched.ok) console.error(import_chalk4.default.yellow(syncMessage(fetched).text));
23359
+ const { waitUntilExit } = render_default(/* @__PURE__ */ import_react45.default.createElement(BrainfileTUI, { filePath }));
23318
23360
  await waitUntilExit();
23319
23361
  process.stdout.write("\x1B[2J");
23320
23362
  process.stdout.write("\x1B[H");