@agenit/cli 1.1.1 → 1.3.4

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 (3) hide show
  1. package/CHANGELOG.md +369 -0
  2. package/cli.js +1766 -882
  3. package/package.json +4 -4
package/cli.js CHANGED
@@ -1650,7 +1650,7 @@ var init_claude = __esm({
1650
1650
  }
1651
1651
  const reader = resp.body.getReader();
1652
1652
  const decoder = new TextDecoder();
1653
- let buffer = "";
1653
+ let buffer3 = "";
1654
1654
  let full = "";
1655
1655
  let lineBuf = "";
1656
1656
  let usageInput = 0;
@@ -1668,11 +1668,11 @@ var init_claude = __esm({
1668
1668
  const { done, value } = await reader.read();
1669
1669
  if (done)
1670
1670
  break;
1671
- buffer += decoder.decode(value, { stream: true });
1672
- let idx = buffer.indexOf("\n\n");
1671
+ buffer3 += decoder.decode(value, { stream: true });
1672
+ let idx = buffer3.indexOf("\n\n");
1673
1673
  while (idx >= 0) {
1674
- const event = buffer.slice(0, idx + 2);
1675
- buffer = buffer.slice(idx + 2);
1674
+ const event = buffer3.slice(0, idx + 2);
1675
+ buffer3 = buffer3.slice(idx + 2);
1676
1676
  for (const rawLine of event.split("\n")) {
1677
1677
  if (!rawLine.startsWith("data: "))
1678
1678
  continue;
@@ -1695,7 +1695,7 @@ var init_claude = __esm({
1695
1695
  } catch {
1696
1696
  }
1697
1697
  }
1698
- idx = buffer.indexOf("\n\n");
1698
+ idx = buffer3.indexOf("\n\n");
1699
1699
  }
1700
1700
  }
1701
1701
  if (lineBuf.length > 0) {
@@ -1945,7 +1945,7 @@ var init_openai = __esm({
1945
1945
  }
1946
1946
  const reader = resp.body.getReader();
1947
1947
  const decoder = new TextDecoder();
1948
- let buffer = "";
1948
+ let buffer3 = "";
1949
1949
  let full = "";
1950
1950
  let lineBuf = "";
1951
1951
  const emitFromBuffer = () => {
@@ -1961,11 +1961,11 @@ var init_openai = __esm({
1961
1961
  const { done, value } = await reader.read();
1962
1962
  if (done)
1963
1963
  break;
1964
- buffer += decoder.decode(value, { stream: true });
1965
- let idx = buffer.indexOf("\n\n");
1964
+ buffer3 += decoder.decode(value, { stream: true });
1965
+ let idx = buffer3.indexOf("\n\n");
1966
1966
  while (idx >= 0) {
1967
- const event = buffer.slice(0, idx + 2);
1968
- buffer = buffer.slice(idx + 2);
1967
+ const event = buffer3.slice(0, idx + 2);
1968
+ buffer3 = buffer3.slice(idx + 2);
1969
1969
  for (const rawLine of event.split("\n")) {
1970
1970
  if (!rawLine.startsWith("data: "))
1971
1971
  continue;
@@ -1990,7 +1990,7 @@ var init_openai = __esm({
1990
1990
  } catch {
1991
1991
  }
1992
1992
  }
1993
- idx = buffer.indexOf("\n\n");
1993
+ idx = buffer3.indexOf("\n\n");
1994
1994
  }
1995
1995
  }
1996
1996
  if (lineBuf.length > 0) {
@@ -2079,7 +2079,7 @@ var init_ollama = __esm({
2079
2079
  }
2080
2080
  const reader = resp.body.getReader();
2081
2081
  const decoder = new TextDecoder();
2082
- let buffer = "";
2082
+ let buffer3 = "";
2083
2083
  let full = "";
2084
2084
  let lineBuf = "";
2085
2085
  const emitFromBuffer = () => {
@@ -2095,11 +2095,11 @@ var init_ollama = __esm({
2095
2095
  const { done, value } = await reader.read();
2096
2096
  if (done)
2097
2097
  break;
2098
- buffer += decoder.decode(value, { stream: true });
2099
- let nl = buffer.indexOf("\n");
2098
+ buffer3 += decoder.decode(value, { stream: true });
2099
+ let nl = buffer3.indexOf("\n");
2100
2100
  while (nl >= 0) {
2101
- const raw = buffer.slice(0, nl).trim();
2102
- buffer = buffer.slice(nl + 1);
2101
+ const raw = buffer3.slice(0, nl).trim();
2102
+ buffer3 = buffer3.slice(nl + 1);
2103
2103
  if (raw) {
2104
2104
  try {
2105
2105
  const ev = JSON.parse(raw);
@@ -2121,7 +2121,7 @@ var init_ollama = __esm({
2121
2121
  } catch {
2122
2122
  }
2123
2123
  }
2124
- nl = buffer.indexOf("\n");
2124
+ nl = buffer3.indexOf("\n");
2125
2125
  }
2126
2126
  }
2127
2127
  if (lineBuf.length > 0) {
@@ -2561,12 +2561,12 @@ var require_url_state_machine = __commonJS({
2561
2561
  function isASCIIHex(c2) {
2562
2562
  return isASCIIDigit(c2) || c2 >= 65 && c2 <= 70 || c2 >= 97 && c2 <= 102;
2563
2563
  }
2564
- function isSingleDot(buffer) {
2565
- return buffer === "." || buffer.toLowerCase() === "%2e";
2564
+ function isSingleDot(buffer3) {
2565
+ return buffer3 === "." || buffer3.toLowerCase() === "%2e";
2566
2566
  }
2567
- function isDoubleDot(buffer) {
2568
- buffer = buffer.toLowerCase();
2569
- return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e";
2567
+ function isDoubleDot(buffer3) {
2568
+ buffer3 = buffer3.toLowerCase();
2569
+ return buffer3 === ".." || buffer3 === "%2e." || buffer3 === ".%2e" || buffer3 === "%2e%2e";
2570
2570
  }
2571
2571
  function isWindowsDriveLetterCodePoints(cp1, cp2) {
2572
2572
  return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124);
@@ -3460,12 +3460,12 @@ var require_url_state_machine = __commonJS({
3460
3460
  if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") {
3461
3461
  this.encodingOverride = "utf-8";
3462
3462
  }
3463
- const buffer = new Buffer(this.buffer);
3464
- for (let i2 = 0; i2 < buffer.length; ++i2) {
3465
- if (buffer[i2] < 33 || buffer[i2] > 126 || buffer[i2] === 34 || buffer[i2] === 35 || buffer[i2] === 60 || buffer[i2] === 62) {
3466
- this.url.query += percentEncode(buffer[i2]);
3463
+ const buffer3 = new Buffer(this.buffer);
3464
+ for (let i2 = 0; i2 < buffer3.length; ++i2) {
3465
+ if (buffer3[i2] < 33 || buffer3[i2] > 126 || buffer3[i2] === 34 || buffer3[i2] === 35 || buffer3[i2] === 60 || buffer3[i2] === 62) {
3466
+ this.url.query += percentEncode(buffer3[i2]);
3467
3467
  } else {
3468
- this.url.query += String.fromCodePoint(buffer[i2]);
3468
+ this.url.query += String.fromCodePoint(buffer3[i2]);
3469
3469
  }
3470
3470
  }
3471
3471
  this.buffer = "";
@@ -3982,20 +3982,20 @@ var require_lib2 = __commonJS({
3982
3982
  const length = Number(a2.length);
3983
3983
  for (let i2 = 0; i2 < length; i2++) {
3984
3984
  const element = a2[i2];
3985
- let buffer;
3985
+ let buffer3;
3986
3986
  if (element instanceof Buffer) {
3987
- buffer = element;
3987
+ buffer3 = element;
3988
3988
  } else if (ArrayBuffer.isView(element)) {
3989
- buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
3989
+ buffer3 = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
3990
3990
  } else if (element instanceof ArrayBuffer) {
3991
- buffer = Buffer.from(element);
3991
+ buffer3 = Buffer.from(element);
3992
3992
  } else if (element instanceof _Blob) {
3993
- buffer = element[BUFFER2];
3993
+ buffer3 = element[BUFFER2];
3994
3994
  } else {
3995
- buffer = Buffer.from(typeof element === "string" ? element : String(element));
3995
+ buffer3 = Buffer.from(typeof element === "string" ? element : String(element));
3996
3996
  }
3997
- size += buffer.length;
3998
- buffers.push(buffer);
3997
+ size += buffer3.length;
3998
+ buffers.push(buffer3);
3999
3999
  }
4000
4000
  }
4001
4001
  this[BUFFER2] = Buffer.concat(buffers);
@@ -4049,8 +4049,8 @@ var require_lib2 = __commonJS({
4049
4049
  relativeEnd = Math.min(end, size);
4050
4050
  }
4051
4051
  const span = Math.max(relativeEnd - relativeStart, 0);
4052
- const buffer = this[BUFFER2];
4053
- const slicedBuffer = buffer.slice(relativeStart, relativeStart + span);
4052
+ const buffer3 = this[BUFFER2];
4053
+ const slicedBuffer = buffer3.slice(relativeStart, relativeStart + span);
4054
4054
  const blob = new _Blob([], { type: arguments[2] });
4055
4055
  blob[BUFFER2] = slicedBuffer;
4056
4056
  return blob;
@@ -4163,9 +4163,9 @@ var require_lib2 = __commonJS({
4163
4163
  */
4164
4164
  json() {
4165
4165
  var _this2 = this;
4166
- return consumeBody.call(this).then(function(buffer) {
4166
+ return consumeBody.call(this).then(function(buffer3) {
4167
4167
  try {
4168
- return JSON.parse(buffer.toString());
4168
+ return JSON.parse(buffer3.toString());
4169
4169
  } catch (err) {
4170
4170
  return Body.Promise.reject(new FetchError(`invalid json response body at ${_this2.url} reason: ${err.message}`, "invalid-json"));
4171
4171
  }
@@ -4177,8 +4177,8 @@ var require_lib2 = __commonJS({
4177
4177
  * @return Promise
4178
4178
  */
4179
4179
  text() {
4180
- return consumeBody.call(this).then(function(buffer) {
4181
- return buffer.toString();
4180
+ return consumeBody.call(this).then(function(buffer3) {
4181
+ return buffer3.toString();
4182
4182
  });
4183
4183
  },
4184
4184
  /**
@@ -4197,8 +4197,8 @@ var require_lib2 = __commonJS({
4197
4197
  */
4198
4198
  textConverted() {
4199
4199
  var _this3 = this;
4200
- return consumeBody.call(this).then(function(buffer) {
4201
- return convertBody(buffer, _this3.headers);
4200
+ return consumeBody.call(this).then(function(buffer3) {
4201
+ return convertBody(buffer3, _this3.headers);
4202
4202
  });
4203
4203
  }
4204
4204
  };
@@ -4284,7 +4284,7 @@ var require_lib2 = __commonJS({
4284
4284
  });
4285
4285
  });
4286
4286
  }
4287
- function convertBody(buffer, headers) {
4287
+ function convertBody(buffer3, headers) {
4288
4288
  if (typeof convert !== "function") {
4289
4289
  throw new Error("The package `encoding` must be installed to use the textConverted() function");
4290
4290
  }
@@ -4294,7 +4294,7 @@ var require_lib2 = __commonJS({
4294
4294
  if (ct2) {
4295
4295
  res = /charset=([^;]*)/i.exec(ct2);
4296
4296
  }
4297
- str = buffer.slice(0, 1024).toString();
4297
+ str = buffer3.slice(0, 1024).toString();
4298
4298
  if (!res && str) {
4299
4299
  res = /<meta.+?charset=(['"])(.+?)\1/i.exec(str);
4300
4300
  }
@@ -4319,7 +4319,7 @@ var require_lib2 = __commonJS({
4319
4319
  charset = "gb18030";
4320
4320
  }
4321
4321
  }
4322
- return convert(buffer, "UTF-8", charset).toString();
4322
+ return convert(buffer3, "UTF-8", charset).toString();
4323
4323
  }
4324
4324
  function isURLSearchParams(obj) {
4325
4325
  if (typeof obj !== "object" || typeof obj.append !== "function" || typeof obj.delete !== "function" || typeof obj.get !== "function" || typeof obj.getAll !== "function" || typeof obj.has !== "function" || typeof obj.set !== "function") {
@@ -7026,9 +7026,9 @@ async function* consumeNodeBlob(blob) {
7026
7026
  let position = 0;
7027
7027
  while (position !== blob.size) {
7028
7028
  const chunk = blob.slice(position, Math.min(blob.size, position + CHUNK_SIZE));
7029
- const buffer = await chunk.arrayBuffer();
7030
- position += buffer.byteLength;
7031
- yield new Uint8Array(buffer);
7029
+ const buffer3 = await chunk.arrayBuffer();
7030
+ position += buffer3.byteLength;
7031
+ yield new Uint8Array(buffer3);
7032
7032
  }
7033
7033
  }
7034
7034
  async function* consumeBlobParts(parts, clone = false) {
@@ -9186,17 +9186,17 @@ async function* iterSSEChunks(iterator) {
9186
9186
  yield data;
9187
9187
  }
9188
9188
  }
9189
- function findDoubleNewlineIndex(buffer) {
9189
+ function findDoubleNewlineIndex(buffer3) {
9190
9190
  const newline = 10;
9191
9191
  const carriage = 13;
9192
- for (let i2 = 0; i2 < buffer.length - 2; i2++) {
9193
- if (buffer[i2] === newline && buffer[i2 + 1] === newline) {
9192
+ for (let i2 = 0; i2 < buffer3.length - 2; i2++) {
9193
+ if (buffer3[i2] === newline && buffer3[i2 + 1] === newline) {
9194
9194
  return i2 + 2;
9195
9195
  }
9196
- if (buffer[i2] === carriage && buffer[i2 + 1] === carriage) {
9196
+ if (buffer3[i2] === carriage && buffer3[i2 + 1] === carriage) {
9197
9197
  return i2 + 2;
9198
9198
  }
9199
- if (buffer[i2] === carriage && buffer[i2 + 1] === newline && i2 + 3 < buffer.length && buffer[i2 + 2] === carriage && buffer[i2 + 3] === newline) {
9199
+ if (buffer3[i2] === carriage && buffer3[i2 + 1] === newline && i2 + 3 < buffer3.length && buffer3[i2 + 2] === carriage && buffer3[i2 + 3] === newline) {
9200
9200
  return i2 + 4;
9201
9201
  }
9202
9202
  }
@@ -16917,8 +16917,8 @@ var init_esm7 = __esm({
16917
16917
  *
16918
16918
  * @internal
16919
16919
  */
16920
- constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs: fs67 = defaultFS } = {}) {
16921
- this.#fs = fsFromOption(fs67);
16920
+ constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs: fs68 = defaultFS } = {}) {
16921
+ this.#fs = fsFromOption(fs68);
16922
16922
  if (cwd instanceof URL || cwd.startsWith("file://")) {
16923
16923
  cwd = fileURLToPath(cwd);
16924
16924
  }
@@ -17476,8 +17476,8 @@ var init_esm7 = __esm({
17476
17476
  /**
17477
17477
  * @internal
17478
17478
  */
17479
- newRoot(fs67) {
17480
- return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs67 });
17479
+ newRoot(fs68) {
17480
+ return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs68 });
17481
17481
  }
17482
17482
  /**
17483
17483
  * Return true if the provided path string is an absolute path
@@ -17505,8 +17505,8 @@ var init_esm7 = __esm({
17505
17505
  /**
17506
17506
  * @internal
17507
17507
  */
17508
- newRoot(fs67) {
17509
- return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs67 });
17508
+ newRoot(fs68) {
17509
+ return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs68 });
17510
17510
  }
17511
17511
  /**
17512
17512
  * Return true if the provided path string is an absolute path
@@ -21847,9 +21847,9 @@ var require_buffer_util = __commonJS({
21847
21847
  output[offset + i2] = source[i2] ^ mask[i2 & 3];
21848
21848
  }
21849
21849
  }
21850
- function _unmask(buffer, mask) {
21851
- for (let i2 = 0; i2 < buffer.length; i2++) {
21852
- buffer[i2] ^= mask[i2 & 3];
21850
+ function _unmask(buffer3, mask) {
21851
+ for (let i2 = 0; i2 < buffer3.length; i2++) {
21852
+ buffer3[i2] ^= mask[i2 & 3];
21853
21853
  }
21854
21854
  }
21855
21855
  function toArrayBuffer(buf) {
@@ -21886,9 +21886,9 @@ var require_buffer_util = __commonJS({
21886
21886
  if (length < 48) _mask(source, mask, output, offset, length);
21887
21887
  else bufferUtil.mask(source, mask, output, offset, length);
21888
21888
  };
21889
- module.exports.unmask = function(buffer, mask) {
21890
- if (buffer.length < 32) _unmask(buffer, mask);
21891
- else bufferUtil.unmask(buffer, mask);
21889
+ module.exports.unmask = function(buffer3, mask) {
21890
+ if (buffer3.length < 32) _unmask(buffer3, mask);
21891
+ else bufferUtil.unmask(buffer3, mask);
21892
21892
  };
21893
21893
  } catch (e2) {
21894
21894
  }
@@ -25750,8 +25750,8 @@ var require_util = __commonJS({
25750
25750
  }
25751
25751
  return this.putInt(i2, n2);
25752
25752
  };
25753
- util.ByteStringBuffer.prototype.putBuffer = function(buffer) {
25754
- return this.putBytes(buffer.getBytes());
25753
+ util.ByteStringBuffer.prototype.putBuffer = function(buffer3) {
25754
+ return this.putBytes(buffer3.getBytes());
25755
25755
  };
25756
25756
  util.ByteStringBuffer.prototype.getByte = function() {
25757
25757
  return this.data.charCodeAt(this.read++);
@@ -25990,9 +25990,9 @@ var require_util = __commonJS({
25990
25990
  }
25991
25991
  throw Error("Invalid parameter: " + bytes);
25992
25992
  };
25993
- util.DataBuffer.prototype.putBuffer = function(buffer) {
25994
- this.putBytes(buffer);
25995
- buffer.clear();
25993
+ util.DataBuffer.prototype.putBuffer = function(buffer3) {
25994
+ this.putBytes(buffer3);
25995
+ buffer3.clear();
25996
25996
  return this;
25997
25997
  };
25998
25998
  util.DataBuffer.prototype.putString = function(str) {
@@ -33746,11 +33746,11 @@ var require_rsa = __commonJS({
33746
33746
  }
33747
33747
  function _intToUint8Array(x2) {
33748
33748
  var bytes = forge2.util.hexToBytes(x2.toString(16));
33749
- var buffer = new Uint8Array(bytes.length);
33749
+ var buffer3 = new Uint8Array(bytes.length);
33750
33750
  for (var i2 = 0; i2 < bytes.length; ++i2) {
33751
- buffer[i2] = bytes.charCodeAt(i2);
33751
+ buffer3[i2] = bytes.charCodeAt(i2);
33752
33752
  }
33753
- return buffer;
33753
+ return buffer3;
33754
33754
  }
33755
33755
  }
33756
33756
  });
@@ -40921,11 +40921,11 @@ var require_ed25519 = __commonJS({
40921
40921
  '"options.message" must be a node.js Buffer, a Uint8Array, a forge ByteBuffer, or a string with "options.encoding" specifying its encoding.'
40922
40922
  );
40923
40923
  }
40924
- var buffer = new NativeBuffer(message.length());
40925
- for (var i2 = 0; i2 < buffer.length; ++i2) {
40926
- buffer[i2] = message.at(i2);
40924
+ var buffer3 = new NativeBuffer(message.length());
40925
+ for (var i2 = 0; i2 < buffer3.length; ++i2) {
40926
+ buffer3[i2] = message.at(i2);
40927
40927
  }
40928
- return buffer;
40928
+ return buffer3;
40929
40929
  }
40930
40930
  var gf0 = gf();
40931
40931
  var gf1 = gf([1]);
@@ -41055,8 +41055,8 @@ var require_ed25519 = __commonJS({
41055
41055
  ]);
41056
41056
  function sha512(msg, msgLen) {
41057
41057
  var md = forge2.md.sha512.create();
41058
- var buffer = new ByteBuffer(msg);
41059
- md.update(buffer.getBytes(msgLen), "binary");
41058
+ var buffer3 = new ByteBuffer(msg);
41059
+ md.update(buffer3.getBytes(msgLen), "binary");
41060
41060
  var hash = md.digest().getBytes();
41061
41061
  if (typeof Buffer !== "undefined") {
41062
41062
  return Buffer.from(hash, "binary");
@@ -43143,11 +43143,11 @@ var require_ssh = __commonJS({
43143
43143
  ssh.publicKeyToOpenSSH = function(key, comment) {
43144
43144
  var type = "ssh-rsa";
43145
43145
  comment = comment || "";
43146
- var buffer = forge2.util.createBuffer();
43147
- _addStringToBuffer(buffer, type);
43148
- _addBigIntegerToBuffer(buffer, key.e);
43149
- _addBigIntegerToBuffer(buffer, key.n);
43150
- return type + " " + forge2.util.encode64(buffer.bytes()) + " " + comment;
43146
+ var buffer3 = forge2.util.createBuffer();
43147
+ _addStringToBuffer(buffer3, type);
43148
+ _addBigIntegerToBuffer(buffer3, key.e);
43149
+ _addBigIntegerToBuffer(buffer3, key.n);
43150
+ return type + " " + forge2.util.encode64(buffer3.bytes()) + " " + comment;
43151
43151
  };
43152
43152
  ssh.privateKeyToOpenSSH = function(privateKey, passphrase) {
43153
43153
  if (!passphrase) {
@@ -43163,12 +43163,12 @@ var require_ssh = __commonJS({
43163
43163
  options = options || {};
43164
43164
  var md = options.md || forge2.md.md5.create();
43165
43165
  var type = "ssh-rsa";
43166
- var buffer = forge2.util.createBuffer();
43167
- _addStringToBuffer(buffer, type);
43168
- _addBigIntegerToBuffer(buffer, key.e);
43169
- _addBigIntegerToBuffer(buffer, key.n);
43166
+ var buffer3 = forge2.util.createBuffer();
43167
+ _addStringToBuffer(buffer3, type);
43168
+ _addBigIntegerToBuffer(buffer3, key.e);
43169
+ _addBigIntegerToBuffer(buffer3, key.n);
43170
43170
  md.start();
43171
- md.update(buffer.getBytes());
43171
+ md.update(buffer3.getBytes());
43172
43172
  var digest = md.digest();
43173
43173
  if (options.encoding === "hex") {
43174
43174
  var hex = digest.toHex();
@@ -43183,18 +43183,18 @@ var require_ssh = __commonJS({
43183
43183
  }
43184
43184
  return digest;
43185
43185
  };
43186
- function _addBigIntegerToBuffer(buffer, val) {
43186
+ function _addBigIntegerToBuffer(buffer3, val) {
43187
43187
  var hexVal = val.toString(16);
43188
43188
  if (hexVal[0] >= "8") {
43189
43189
  hexVal = "00" + hexVal;
43190
43190
  }
43191
43191
  var bytes = forge2.util.hexToBytes(hexVal);
43192
- buffer.putInt32(bytes.length);
43193
- buffer.putBytes(bytes);
43192
+ buffer3.putInt32(bytes.length);
43193
+ buffer3.putBytes(bytes);
43194
43194
  }
43195
- function _addStringToBuffer(buffer, val) {
43196
- buffer.putInt32(val.length);
43197
- buffer.putString(val);
43195
+ function _addStringToBuffer(buffer3, val) {
43196
+ buffer3.putInt32(val.length);
43197
+ buffer3.putString(val);
43198
43198
  }
43199
43199
  function _sha1() {
43200
43200
  var sha = forge2.md.sha1.create();
@@ -43248,7 +43248,7 @@ __export(model_probe_exports, {
43248
43248
  });
43249
43249
  import { spawn as spawn20 } from "node:child_process";
43250
43250
  import { createHash as createHash4 } from "node:crypto";
43251
- import { promises as fs65 } from "node:fs";
43251
+ import { promises as fs66 } from "node:fs";
43252
43252
  import os6 from "node:os";
43253
43253
  import path67 from "node:path";
43254
43254
  function cacheFilePath() {
@@ -43260,7 +43260,7 @@ function accountKey(flowHome) {
43260
43260
  }
43261
43261
  async function readCache2() {
43262
43262
  try {
43263
- const raw = await fs65.readFile(cacheFilePath(), "utf8");
43263
+ const raw = await fs66.readFile(cacheFilePath(), "utf8");
43264
43264
  const parsed = JSON.parse(raw);
43265
43265
  if (typeof parsed === "object" && parsed && typeof parsed.accountKey === "string" && typeof parsed.at === "number" && parsed.models && typeof parsed.models.fast === "string" && typeof parsed.models.smart === "string" && typeof parsed.models.cheap === "string") {
43266
43266
  return parsed;
@@ -43272,8 +43272,8 @@ async function readCache2() {
43272
43272
  }
43273
43273
  async function writeCache2(entry) {
43274
43274
  const file = cacheFilePath();
43275
- await fs65.mkdir(path67.dirname(file), { recursive: true });
43276
- await fs65.writeFile(file, JSON.stringify(entry, null, 2));
43275
+ await fs66.mkdir(path67.dirname(file), { recursive: true });
43276
+ await fs66.writeFile(file, JSON.stringify(entry, null, 2));
43277
43277
  }
43278
43278
  async function resolveTierModels(cfg, opts = {}) {
43279
43279
  const key = accountKey(cfg.flow.flowHome);
@@ -43305,7 +43305,7 @@ async function resolveTierModels(cfg, opts = {}) {
43305
43305
  }
43306
43306
  async function clearProbeCache() {
43307
43307
  try {
43308
- await fs65.unlink(cacheFilePath());
43308
+ await fs66.unlink(cacheFilePath());
43309
43309
  } catch {
43310
43310
  }
43311
43311
  }
@@ -43354,7 +43354,7 @@ var init_model_probe = __esm({
43354
43354
 
43355
43355
  // src/cli.tsx
43356
43356
  init_dist();
43357
- import { promises as fs66 } from "node:fs";
43357
+ import { promises as fs67 } from "node:fs";
43358
43358
  import path68 from "node:path";
43359
43359
  import { spawn as spawn21 } from "node:child_process";
43360
43360
  import { render as render2 } from "ink";
@@ -43379,8 +43379,8 @@ function flowLog(rec) {
43379
43379
  }
43380
43380
 
43381
43381
  // src/repl/App.tsx
43382
- import { useEffect as useEffect3, useMemo, useRef, useState as useState3 } from "react";
43383
- import { Box as Box8, Static, Text as Text8, useApp, useInput, useStdout } from "ink";
43382
+ import { useEffect as useEffect6, useMemo, useRef, useState as useState6 } from "react";
43383
+ import { Box as Box9, Text as Text9, useApp, useInput, useStdout } from "ink";
43384
43384
  import Spinner from "ink-spinner";
43385
43385
  import TextInput2 from "ink-text-input";
43386
43386
 
@@ -47013,9 +47013,23 @@ import path20 from "node:path";
47013
47013
  async function seedGeminiAssets(projectDir2, flowHome) {
47014
47014
  const sourceSkillsDir = path20.join(flowHome, ".gemini", "skills");
47015
47015
  const sourceSettingsPath = path20.join(flowHome, ".gemini", "settings.json");
47016
+ const sourceToolsDir = path20.join(flowHome, ".flow", "tools");
47017
+ const sourceConstitutionPath = path20.join(
47018
+ flowHome,
47019
+ ".specify",
47020
+ "memory",
47021
+ "constitution.md"
47022
+ );
47016
47023
  const targetGeminiDir = path20.join(projectDir2, ".gemini");
47017
47024
  const targetSkillsDir = path20.join(targetGeminiDir, "skills");
47018
47025
  const targetSettingsPath = path20.join(targetGeminiDir, "settings.json");
47026
+ const targetToolsDir = path20.join(projectDir2, ".flow", "tools");
47027
+ const targetConstitutionPath = path20.join(
47028
+ projectDir2,
47029
+ ".specify",
47030
+ "memory",
47031
+ "constitution.md"
47032
+ );
47019
47033
  await fs24.mkdir(targetGeminiDir, { recursive: true });
47020
47034
  const skillsCopied = await copySkills(sourceSkillsDir, targetSkillsDir);
47021
47035
  const settingsResult = await seedSettings(
@@ -47023,12 +47037,66 @@ async function seedGeminiAssets(projectDir2, flowHome) {
47023
47037
  targetSettingsPath,
47024
47038
  flowHome
47025
47039
  );
47040
+ const toolsCopied = await copyTools(sourceToolsDir, targetToolsDir);
47041
+ const constitutionSeeded = await seedConstitution(
47042
+ sourceConstitutionPath,
47043
+ targetConstitutionPath
47044
+ );
47026
47045
  return {
47027
47046
  skillsCopied,
47028
47047
  settingsWritten: settingsResult.written,
47029
- settingsSkippedReason: settingsResult.skippedReason
47048
+ settingsSkippedReason: settingsResult.skippedReason,
47049
+ toolsCopied,
47050
+ constitutionSeeded
47030
47051
  };
47031
47052
  }
47053
+ async function copyTools(source, target) {
47054
+ let entries;
47055
+ try {
47056
+ entries = await fs24.readdir(source, { withFileTypes: true });
47057
+ } catch {
47058
+ return 0;
47059
+ }
47060
+ await fs24.mkdir(target, { recursive: true });
47061
+ let copied = 0;
47062
+ for (const entry of entries) {
47063
+ const s2 = path20.join(source, entry.name);
47064
+ const d2 = path20.join(target, entry.name);
47065
+ if (entry.isDirectory()) {
47066
+ await copyDirRecursive(s2, d2);
47067
+ copied += await countFiles(d2);
47068
+ } else if (entry.isFile()) {
47069
+ await fs24.copyFile(s2, d2);
47070
+ copied += 1;
47071
+ }
47072
+ }
47073
+ return copied;
47074
+ }
47075
+ async function countFiles(dir) {
47076
+ let n2 = 0;
47077
+ const entries = await fs24.readdir(dir, { withFileTypes: true });
47078
+ for (const entry of entries) {
47079
+ if (entry.isFile()) n2 += 1;
47080
+ else if (entry.isDirectory()) n2 += await countFiles(path20.join(dir, entry.name));
47081
+ }
47082
+ return n2;
47083
+ }
47084
+ async function seedConstitution(sourcePath, targetPath) {
47085
+ try {
47086
+ await fs24.access(targetPath);
47087
+ return false;
47088
+ } catch {
47089
+ }
47090
+ let body;
47091
+ try {
47092
+ body = await fs24.readFile(sourcePath, "utf8");
47093
+ } catch {
47094
+ return false;
47095
+ }
47096
+ await fs24.mkdir(path20.dirname(targetPath), { recursive: true });
47097
+ await fs24.writeFile(targetPath, body);
47098
+ return true;
47099
+ }
47032
47100
  async function copySkills(source, target) {
47033
47101
  let entries;
47034
47102
  try {
@@ -48056,6 +48124,30 @@ ${text || chalk7.dim("(empty)")}
48056
48124
  // src/commands/codedigest.ts
48057
48125
  init_dist3();
48058
48126
  import path24 from "node:path";
48127
+
48128
+ // src/repl/codedigest-history.ts
48129
+ var CAPACITY = 10;
48130
+ var buffer = [];
48131
+ var HEADER_RE = /^### \d+\. /gm;
48132
+ var TOP_LOCATION_RE = /^>\s+([^\s|]+:\d+-\d+)/m;
48133
+ function countSearchHits(searchMarkdown) {
48134
+ if (/No results found\./.test(searchMarkdown)) return 0;
48135
+ const matches = searchMarkdown.match(HEADER_RE);
48136
+ return matches ? matches.length : 0;
48137
+ }
48138
+ function extractTopLocation(searchMarkdown) {
48139
+ const match2 = searchMarkdown.match(TOP_LOCATION_RE);
48140
+ return match2 ? match2[1] : null;
48141
+ }
48142
+ function recordCodeDigestSearch(q2, hits, top = null) {
48143
+ buffer.push({ q: q2, hits, top, at: Date.now() });
48144
+ while (buffer.length > CAPACITY) buffer.shift();
48145
+ }
48146
+ function getRecentSearches() {
48147
+ return buffer.slice().reverse();
48148
+ }
48149
+
48150
+ // src/commands/codedigest.ts
48059
48151
  var codedigestCommand = {
48060
48152
  name: "codedigest",
48061
48153
  description: "AST-walk + keyword search of the codebase (no Docker / native deps)",
@@ -48108,6 +48200,11 @@ ${out}
48108
48200
  topK: 5,
48109
48201
  language: lang
48110
48202
  });
48203
+ recordCodeDigestSearch(
48204
+ query,
48205
+ countSearchHits(md),
48206
+ extractTopLocation(md)
48207
+ );
48111
48208
  return `${section(`CodeDigest \u2014 search '${query}'`)}
48112
48209
 
48113
48210
  ${md}`;
@@ -51478,8 +51575,8 @@ async function advisorCmd(store, pdir, rest) {
51478
51575
  }
51479
51576
  let body;
51480
51577
  try {
51481
- const fs67 = await import("node:fs/promises");
51482
- body = await fs67.readFile(entry.replyPath, "utf8");
51578
+ const fs68 = await import("node:fs/promises");
51579
+ body = await fs68.readFile(entry.replyPath, "utf8");
51483
51580
  } catch (err) {
51484
51581
  return `${chalk15.red("\u2717")} Could not read ${entry.replyPath}: ${err.message}`;
51485
51582
  }
@@ -54508,7 +54605,7 @@ var featureCommand = {
54508
54605
  return false;
54509
54606
  };
54510
54607
  const abort = (reason) => {
54511
- const elapsed2 = ((Date.now() - start) / 1e3).toFixed(1);
54608
+ const elapsed3 = ((Date.now() - start) / 1e3).toFixed(1);
54512
54609
  const total2 = totalCostUsd(completed.map((p2) => p2.result));
54513
54610
  log += `
54514
54611
  ${chalk25.bold.red("\u2717")} Pipeline aborted: ${reason}
@@ -54517,7 +54614,7 @@ ${chalk25.bold.red("\u2717")} Pipeline aborted: ${reason}
54517
54614
  log += summarise2(completed);
54518
54615
  log += `
54519
54616
 
54520
- ${chalk25.dim(`Elapsed: ${elapsed2}s \xB7 Total cost: ${formatCost(total2)}`)}
54617
+ ${chalk25.dim(`Elapsed: ${elapsed3}s \xB7 Total cost: ${formatCost(total2)}`)}
54521
54618
  `;
54522
54619
  return log;
54523
54620
  };
@@ -54720,10 +54817,10 @@ Reference: .specify/specs/${fid}.`;
54720
54817
 
54721
54818
  `;
54722
54819
  }
54723
- const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
54820
+ const elapsed2 = ((Date.now() - start) / 1e3).toFixed(1);
54724
54821
  const total = totalCostUsd(completed.map((p2) => p2.result));
54725
54822
  const allOk = completed.every((p2) => p2.result.ok);
54726
- log += `${allOk ? chalk25.bold.green("\u2713") : chalk25.bold.yellow("\u26A0")} Feature pipeline finished in ${elapsed}s \xB7 Total cost: ${formatCost(total)}.
54823
+ log += `${allOk ? chalk25.bold.green("\u2713") : chalk25.bold.yellow("\u26A0")} Feature pipeline finished in ${elapsed2}s \xB7 Total cost: ${formatCost(total)}.
54727
54824
 
54728
54825
  `;
54729
54826
  log += summarise2(completed) + "\n";
@@ -56319,6 +56416,46 @@ async function expandAtPaths(input) {
56319
56416
  return out;
56320
56417
  }
56321
56418
 
56419
+ // src/repl/at-path-history.ts
56420
+ var CAPACITY2 = 10;
56421
+ var buffer2 = [];
56422
+ var AT_PATH_RE2 = /(?:^|\s)@(?:"([^"]+)"|(\S+))/g;
56423
+ function extractAtPaths(input) {
56424
+ const out = [];
56425
+ for (const m2 of input.matchAll(AT_PATH_RE2)) {
56426
+ const pathStr = m2[1] ?? m2[2] ?? "";
56427
+ if (pathStr) out.push(pathStr);
56428
+ }
56429
+ return out;
56430
+ }
56431
+ function recordAtPath(path69) {
56432
+ if (!path69) return;
56433
+ const existing = buffer2.indexOf(path69);
56434
+ if (existing >= 0) buffer2.splice(existing, 1);
56435
+ buffer2.unshift(path69);
56436
+ while (buffer2.length > CAPACITY2) buffer2.pop();
56437
+ }
56438
+ function recordAtPathsFromInput(input) {
56439
+ for (const p2 of extractAtPaths(input)) recordAtPath(p2);
56440
+ }
56441
+ function getRecentAtPaths() {
56442
+ return buffer2.slice();
56443
+ }
56444
+
56445
+ // src/repl/use-at-path-history.ts
56446
+ import { useEffect, useState } from "react";
56447
+ var REFRESH_MS = 1e3;
56448
+ function useAtPathHistory() {
56449
+ const [paths, setPaths] = useState(
56450
+ () => getRecentAtPaths()
56451
+ );
56452
+ useEffect(() => {
56453
+ const t2 = setInterval(() => setPaths(getRecentAtPaths()), REFRESH_MS);
56454
+ return () => clearInterval(t2);
56455
+ }, []);
56456
+ return paths;
56457
+ }
56458
+
56322
56459
  // src/repl/markdown.ts
56323
56460
  import chalk34 from "chalk";
56324
56461
  var ZERO_WIDTH_RE = /[​-‍]/g;
@@ -56515,12 +56652,9 @@ import { Box, Text } from "ink";
56515
56652
 
56516
56653
  // src/repl/theme.ts
56517
56654
  var ACCENT = "#00d4ff";
56518
- var USER = "blueBright";
56519
- var ASSISTANT = "greenBright";
56520
56655
  var WARNING = "#ffb454";
56521
56656
  var ERROR2 = "#ff5c6c";
56522
56657
  var SUCCESS = "#00ff88";
56523
- var SKILL = "#c792ea";
56524
56658
  var LAYER_NODE = "#3c873a";
56525
56659
  var LAYER_GEMINI = "#4285F4";
56526
56660
  var LAYER_PYTHON = "#ffd43b";
@@ -56545,98 +56679,130 @@ function LayerChip({ layer }) {
56545
56679
  /* @__PURE__ */ jsx(Text, { color: TEXT_DIM, children: layerLabel(layer) })
56546
56680
  ] });
56547
56681
  }
56682
+ var TOOL_COLORS = {
56683
+ write: "#ff5f5a",
56684
+ read: "#a4abb6",
56685
+ shell: "#fbbf24"
56686
+ };
56687
+ var TOOL_DEFAULT_COLOR = "#a4abb6";
56688
+ var SKILL_CHIP = "#ff5f5a";
56689
+ var AGENT_CHIP = "#c4a8ff";
56548
56690
  function ActivityStrip({
56549
56691
  frame
56550
56692
  }) {
56551
- const tools = frame.tools.map(([name, count]) => `${name}\xD7${count}`).join(" ");
56552
56693
  return /* @__PURE__ */ jsxs(Box, { children: [
56553
- /* @__PURE__ */ jsx(LayerChip, { layer: frame.layer }),
56554
- frame.skill && /* @__PURE__ */ jsxs(Text, { children: [
56555
- /* @__PURE__ */ jsx(Text, { color: MUTED, children: " \u25C8 skill " }),
56556
- /* @__PURE__ */ jsx(Text, { color: SKILL, children: frame.skill })
56694
+ /* @__PURE__ */ jsxs(Text, { color: STAT_LABEL, bold: true, children: [
56695
+ "ACTIVITY",
56696
+ " "
56557
56697
  ] }),
56558
- frame.agent && /* @__PURE__ */ jsxs(Text, { children: [
56559
- /* @__PURE__ */ jsx(Text, { color: MUTED, children: " \u25C8 agent " }),
56560
- /* @__PURE__ */ jsx(Text, { color: SKILL, children: frame.agent })
56698
+ /* @__PURE__ */ jsx(LayerChip, { layer: frame.layer }),
56699
+ frame.skill && /* @__PURE__ */ jsxs(Box, { marginLeft: 1, children: [
56700
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: "[ " }),
56701
+ /* @__PURE__ */ jsxs(Text, { color: SKILL_CHIP, children: [
56702
+ "\u2726 skill \xB7 ",
56703
+ frame.skill
56704
+ ] }),
56705
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " ]" })
56561
56706
  ] }),
56562
- tools && /* @__PURE__ */ jsxs(Text, { children: [
56563
- /* @__PURE__ */ jsx(Text, { color: MUTED, children: " \u25C8 tools " }),
56564
- /* @__PURE__ */ jsx(Text, { color: TEXT_DIM, children: tools })
56707
+ frame.agent && /* @__PURE__ */ jsxs(Box, { marginLeft: 1, children: [
56708
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: "[ " }),
56709
+ /* @__PURE__ */ jsx(Text, { color: AGENT_CHIP, children: frame.agent }),
56710
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " ]" })
56565
56711
  ] }),
56566
- /* @__PURE__ */ jsx(Text, { color: MUTED, children: " \u2026 " }),
56567
- /* @__PURE__ */ jsxs(Text, { color: MUTED, children: [
56712
+ frame.tools.map(([name, count]) => {
56713
+ const color = TOOL_COLORS[name] ?? TOOL_DEFAULT_COLOR;
56714
+ return /* @__PURE__ */ jsxs(Box, { marginLeft: 1, children: [
56715
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: "[ " }),
56716
+ /* @__PURE__ */ jsxs(Text, { color, children: [
56717
+ name,
56718
+ "\xD7",
56719
+ count
56720
+ ] }),
56721
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " ]" })
56722
+ ] }, name);
56723
+ }),
56724
+ /* @__PURE__ */ jsxs(Text, { color: STAT_LABEL, children: [
56725
+ " \xB7 ",
56568
56726
  (frame.elapsedMs / 1e3).toFixed(1),
56569
56727
  "s"
56570
56728
  ] })
56571
56729
  ] });
56572
56730
  }
56731
+ var BRAND_ACCENT = "#ff5f5a";
56732
+ var STAT_TEXT = "#a4abb6";
56733
+ var STAT_LABEL = "#4a525e";
56734
+ var STAT_AMBER = "#fbbf24";
56735
+ var STAT_MINT = "#5eead4";
56736
+ function StatPill({ spec }) {
56737
+ const valueColor = spec.tone === "amber" ? STAT_AMBER : spec.tone === "mint" ? STAT_MINT : STAT_TEXT;
56738
+ return /* @__PURE__ */ jsxs(Box, { marginRight: 1, children: [
56739
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: "[ " }),
56740
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, bold: true, children: spec.label.toUpperCase() }),
56741
+ /* @__PURE__ */ jsxs(Text, { color: valueColor, children: [
56742
+ " ",
56743
+ spec.value
56744
+ ] }),
56745
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " ]" })
56746
+ ] });
56747
+ }
56573
56748
  function StatusBar({
56574
56749
  project,
56575
56750
  status: status2,
56576
- mode,
56751
+ mode: _mode,
56577
56752
  approval,
56578
56753
  model,
56579
- backend,
56754
+ backend: _backend,
56580
56755
  width = 100
56581
56756
  }) {
56582
- const approvalColor = approval === "yolo" ? WARNING : approval === "auto_edit" ? ACCENT : TEXT_DIM;
56583
- const left = [];
56584
- left.push(
56585
- /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: "agenIT" }, "brand")
56586
- );
56587
- const sep2 = (k2) => /* @__PURE__ */ jsx(Text, { color: MUTED, children: " \u2502 " }, k2);
56588
- left.push(sep2("s1"));
56589
- left.push(
56590
- /* @__PURE__ */ jsx(Text, { color: TEXT, children: project ?? "no project" }, "proj")
56591
- );
56592
- if (status2.branch) {
56593
- left.push(sep2("s2"));
56594
- left.push(
56595
- /* @__PURE__ */ jsxs(Text, { color: MUTED, children: [
56596
- "\u2387",
56597
- " "
56598
- ] }, "branch")
56599
- );
56600
- left.push(
56601
- /* @__PURE__ */ jsx(Text, { color: TEXT_DIM, children: status2.branch }, "branchN")
56602
- );
56603
- }
56757
+ const stats = [
56758
+ { label: "yolo", value: approval, tone: "amber" },
56759
+ { label: "model", value: model, tone: "text" }
56760
+ ];
56604
56761
  if (status2.stage) {
56605
- left.push(sep2("s3"));
56606
- left.push(
56607
- /* @__PURE__ */ jsx(Text, { color: SKILL, children: status2.stage }, "stage")
56608
- );
56762
+ stats.push({ label: "stage", value: status2.stage, tone: "mint" });
56609
56763
  }
56610
- if (status2.skill) {
56611
- left.push(sep2("s4"));
56612
- left.push(
56613
- /* @__PURE__ */ jsxs(Text, { color: MUTED, children: [
56614
- "skill",
56764
+ const contextSegments = [];
56765
+ if (project) {
56766
+ contextSegments.push(
56767
+ /* @__PURE__ */ jsxs(Text, { color: STAT_MINT, children: [
56768
+ "\u25CF",
56615
56769
  " "
56616
- ] }, "skillL")
56617
- );
56618
- left.push(
56619
- /* @__PURE__ */ jsx(Text, { color: SKILL, children: status2.skill }, "skillN")
56770
+ ] }, "proj-dot"),
56771
+ /* @__PURE__ */ jsx(Text, { color: TEXT, children: project }, "proj-n")
56620
56772
  );
56773
+ if (status2.branch) {
56774
+ contextSegments.push(
56775
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " \u2387 " }, "b-sep"),
56776
+ /* @__PURE__ */ jsx(Text, { color: STAT_TEXT, children: status2.branch }, "b-n")
56777
+ );
56778
+ }
56621
56779
  }
56622
- const rightFragments = [
56623
- { key: "modeL", text: "mode ", color: MUTED },
56624
- { key: "modeN", text: mode, color: ACCENT },
56625
- { key: "sep1", text: " \u2502 ", color: MUTED },
56626
- { key: "appL", text: "approval ", color: MUTED },
56627
- { key: "appN", text: approval, color: approvalColor },
56628
- { key: "sep2", text: " \u2502 ", color: MUTED },
56629
- { key: "backL", text: "backend ", color: MUTED },
56630
- { key: "backN", text: backend, color: TEXT_DIM },
56631
- { key: "sep3", text: " \u2502 ", color: MUTED },
56632
- { key: "modL", text: "model ", color: MUTED },
56633
- { key: "modN", text: model, color: TEXT_DIM }
56634
- ];
56635
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: BORDER_DIM, borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, children: /* @__PURE__ */ jsxs(Box, { width, children: [
56636
- /* @__PURE__ */ jsx(Box, { children: left }),
56637
- /* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
56638
- /* @__PURE__ */ jsx(Box, { children: rightFragments.map((f2) => /* @__PURE__ */ jsx(Text, { color: f2.color, children: f2.text }, f2.key)) })
56639
- ] }) });
56780
+ return /* @__PURE__ */ jsx(
56781
+ Box,
56782
+ {
56783
+ flexDirection: "column",
56784
+ borderStyle: "single",
56785
+ borderColor: BORDER_DIM,
56786
+ borderBottom: true,
56787
+ borderTop: false,
56788
+ borderLeft: false,
56789
+ borderRight: false,
56790
+ children: /* @__PURE__ */ jsxs(Box, { width, children: [
56791
+ /* @__PURE__ */ jsxs(Box, { children: [
56792
+ /* @__PURE__ */ jsx(Text, { color: TEXT, bold: true, children: "agen" }),
56793
+ /* @__PURE__ */ jsx(Text, { color: BRAND_ACCENT, bold: true, children: "IT" }),
56794
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " \xB7 flow" })
56795
+ ] }),
56796
+ contextSegments.length > 0 && /* @__PURE__ */ jsxs(Box, { marginLeft: 2, children: [
56797
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: "[ " }),
56798
+ contextSegments,
56799
+ /* @__PURE__ */ jsx(Text, { color: STAT_LABEL, children: " ]" })
56800
+ ] }),
56801
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
56802
+ /* @__PURE__ */ jsx(Box, { children: stats.map((s2) => /* @__PURE__ */ jsx(StatPill, { spec: s2 }, s2.label)) })
56803
+ ] })
56804
+ }
56805
+ );
56640
56806
  }
56641
56807
  function PhaseRow({
56642
56808
  phase,
@@ -56691,9 +56857,11 @@ function SideRail({
56691
56857
  vmodelDone,
56692
56858
  traceability,
56693
56859
  squad,
56860
+ pinnedFiles,
56694
56861
  width = 26
56695
56862
  }) {
56696
- return /* @__PURE__ */ jsx(
56863
+ const showPinned = !squad && pinnedFiles && pinnedFiles.length > 0;
56864
+ return /* @__PURE__ */ jsxs(
56697
56865
  Box,
56698
56866
  {
56699
56867
  flexDirection: "column",
@@ -56705,17 +56873,50 @@ function SideRail({
56705
56873
  borderLeft: false,
56706
56874
  borderRight: true,
56707
56875
  paddingRight: 1,
56708
- children: squad ? /* @__PURE__ */ jsx(SquadRail, { snap: squad, barWidth: Math.min(20, width - 6) }) : /* @__PURE__ */ jsx(
56709
- VModelRail,
56710
- {
56711
- active: vmodelActive,
56712
- done: vmodelDone,
56713
- traceability
56714
- }
56715
- )
56876
+ children: [
56877
+ squad ? /* @__PURE__ */ jsx(SquadRail, { snap: squad, barWidth: Math.min(20, width - 6) }) : /* @__PURE__ */ jsx(
56878
+ VModelRail,
56879
+ {
56880
+ active: vmodelActive,
56881
+ done: vmodelDone,
56882
+ traceability
56883
+ }
56884
+ ),
56885
+ showPinned && /* @__PURE__ */ jsx(PinnedFiles, { paths: pinnedFiles, width: width - 1 })
56886
+ ]
56716
56887
  }
56717
56888
  );
56718
56889
  }
56890
+ var PINNED_LABEL = "#4a525e";
56891
+ var PINNED_TEXT = "#a4abb6";
56892
+ function PinnedFiles({
56893
+ paths,
56894
+ width
56895
+ }) {
56896
+ const visible = paths.slice(0, 5);
56897
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
56898
+ /* @__PURE__ */ jsx(Text, { color: PINNED_LABEL, bold: true, children: "\u2500 PINNED \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
56899
+ visible.map((p2) => {
56900
+ const room = Math.max(8, width - 3);
56901
+ const display = p2.length <= room ? p2 : truncateFromLeft(p2, room);
56902
+ return /* @__PURE__ */ jsxs(Box, { children: [
56903
+ /* @__PURE__ */ jsx(Text, { color: PINNED_LABEL, children: "@ " }),
56904
+ /* @__PURE__ */ jsx(Text, { color: PINNED_TEXT, wrap: "truncate-end", children: display })
56905
+ ] }, p2);
56906
+ }),
56907
+ paths.length > visible.length && /* @__PURE__ */ jsxs(Text, { color: PINNED_LABEL, children: [
56908
+ " ",
56909
+ "+",
56910
+ paths.length - visible.length,
56911
+ " more"
56912
+ ] })
56913
+ ] });
56914
+ }
56915
+ function truncateFromLeft(s2, max) {
56916
+ if (s2.length <= max) return s2;
56917
+ if (max <= 1) return s2.slice(-max);
56918
+ return "\u2026" + s2.slice(-(max - 1));
56919
+ }
56719
56920
  function VModelRail({
56720
56921
  active,
56721
56922
  done,
@@ -56793,284 +56994,641 @@ function SquadRail({
56793
56994
  }
56794
56995
 
56795
56996
  // src/repl/job-rail.tsx
56796
- import { useEffect, useState } from "react";
56797
- import { Box as Box2, Text as Text2 } from "ink";
56997
+ import { useEffect as useEffect2, useState as useState2 } from "react";
56998
+ import { Box as Box3, Text as Text3 } from "ink";
56798
56999
 
56799
- // src/repl/job-layout.ts
56800
- var INDICATOR_LINES = 1;
56801
- function solveJobLayout(jobs, availableHeight) {
56802
- if (jobs.length === 0 || availableHeight <= 0) {
56803
- return { allocations: [], hiddenCount: 0 };
56804
- }
56805
- let used = 0;
56806
- let visibleCount = 0;
56807
- for (let i2 = 0; i2 < jobs.length; i2++) {
56808
- const job = jobs[i2];
56809
- const min = Math.max(1, job.snapshot.minLines);
56810
- const remainingAfterIndicator = availableHeight - used - (i2 < jobs.length - 1 ? INDICATOR_LINES : 0);
56811
- if (min > remainingAfterIndicator) break;
56812
- used += min;
56813
- visibleCount += 1;
56814
- }
56815
- const hiddenCount = jobs.length - visibleCount;
56816
- if (visibleCount === 0) {
56817
- return { allocations: [], hiddenCount };
56818
- }
56819
- const indicatorLines = hiddenCount > 0 ? INDICATOR_LINES : 0;
56820
- let slack = Math.max(0, availableHeight - used - indicatorLines);
56821
- const visible = jobs.slice(0, visibleCount);
56822
- const allocations = visible.map((j3, i2) => ({
56823
- jobIndex: i2,
56824
- lines: Math.max(1, j3.snapshot.minLines)
56825
- }));
56826
- const wants = visible.map((j3, i2) => ({
56827
- idx: i2,
56828
- want: Math.max(0, j3.snapshot.preferredLines - allocations[i2].lines)
56829
- }));
56830
- wants.sort((a2, b2) => a2.want - b2.want || a2.idx - b2.idx);
56831
- let remaining = wants.length;
56832
- for (const { idx, want } of wants) {
56833
- if (slack <= 0) break;
56834
- if (want <= 0) {
56835
- remaining -= 1;
56836
- continue;
57000
+ // src/repl/rail-sections.tsx
57001
+ import { Box as Box2, Text as Text2 } from "ink";
57002
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
57003
+ var TEXT2 = "#e6e8ec";
57004
+ var TEXT_2 = "#a4abb6";
57005
+ var TEXT_3 = "#6b7280";
57006
+ var TEXT_4 = "#4a525e";
57007
+ var TONE_RUNNING = "#5eead4";
57008
+ var TONE_IDLE = "#7aa7ff";
57009
+ var TONE_STOPPED = "#ff5f5a";
57010
+ var TONE_AMBER = "#fbbf24";
57011
+ var TONE_VIOLET = "#c4a8ff";
57012
+ var STATUS_BORDER = {
57013
+ idle: TONE_IDLE,
57014
+ running: TONE_RUNNING,
57015
+ stopped: TONE_STOPPED
57016
+ };
57017
+ var STATUS_LABEL = {
57018
+ idle: "idle",
57019
+ running: "running",
57020
+ stopped: "stopped"
57021
+ };
57022
+ function truncate(s2, max) {
57023
+ if (s2.length <= max) return s2;
57024
+ if (max <= 1) return s2.slice(0, max);
57025
+ return s2.slice(0, max - 1) + "\u2026";
57026
+ }
57027
+ function relativeTime(iso, now) {
57028
+ if (!iso) return "unknown";
57029
+ const t2 = Date.parse(iso);
57030
+ if (Number.isNaN(t2)) return "unknown";
57031
+ const seconds = Math.max(0, Math.floor((now - t2) / 1e3));
57032
+ if (seconds < 60) return `${seconds}s ago`;
57033
+ const minutes = Math.floor(seconds / 60);
57034
+ if (minutes < 60) return `${minutes}m ago`;
57035
+ const hours = Math.floor(minutes / 60);
57036
+ if (hours < 24) return `${hours}h ago`;
57037
+ return `${Math.floor(hours / 24)}d ago`;
57038
+ }
57039
+ function WidgetFrame({
57040
+ title,
57041
+ subtitle,
57042
+ status: status2,
57043
+ width,
57044
+ compact = false,
57045
+ children
57046
+ }) {
57047
+ const border = STATUS_BORDER[status2];
57048
+ const innerWidth = Math.max(8, width - 4);
57049
+ return /* @__PURE__ */ jsxs2(
57050
+ Box2,
57051
+ {
57052
+ flexDirection: "column",
57053
+ borderStyle: "round",
57054
+ borderColor: border,
57055
+ paddingX: 1,
57056
+ width,
57057
+ marginTop: compact ? 0 : 1,
57058
+ flexShrink: 0,
57059
+ children: [
57060
+ /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsxs2(Text2, { color: TEXT2, bold: true, children: [
57061
+ /* @__PURE__ */ jsx2(Text2, { color: border, children: "\u25CF " }),
57062
+ truncate(title.toUpperCase(), innerWidth - 2)
57063
+ ] }) }),
57064
+ !compact && subtitle && /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, wrap: "truncate-end", children: truncate(subtitle, innerWidth) }) }),
57065
+ children
57066
+ ]
56837
57067
  }
56838
- const share = Math.floor(slack / remaining);
56839
- const give = Math.min(want, share);
56840
- allocations[idx].lines += give;
56841
- slack -= give;
56842
- remaining -= 1;
56843
- }
56844
- return { allocations, hiddenCount };
57068
+ );
56845
57069
  }
56846
-
56847
- // src/repl/job-rail.tsx
56848
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
56849
- var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
56850
- var STALE_THRESHOLD_MS = 6e4;
56851
- function stateBadge(state, stale) {
56852
- if (stale) return { glyph: "?", color: WARNING };
56853
- switch (state) {
56854
- case "starting":
56855
- return { glyph: "\u25CC", color: TEXT_DIM };
56856
- case "active":
56857
- return { glyph: "\u25B6", color: ACCENT };
56858
- case "ticking":
56859
- return { glyph: "\u25D0", color: ACCENT };
56860
- // overridden by spinner frame
56861
- case "blocked":
56862
- return { glyph: "\u26A0", color: WARNING };
56863
- case "paused":
56864
- return { glyph: "\u23F8", color: MUTED };
56865
- case "done":
56866
- return { glyph: "\u2713", color: SUCCESS };
56867
- case "aborted":
56868
- return { glyph: "\u2717", color: ERROR2 };
56869
- case "error":
56870
- return { glyph: "\u2717", color: ERROR2 };
57070
+ function toneForKind(kind2) {
57071
+ switch (kind2) {
57072
+ case "goal":
57073
+ return TONE_RUNNING;
57074
+ case "squad":
57075
+ return TONE_AMBER;
57076
+ case "soul":
57077
+ case "soul-keeper":
57078
+ return TONE_IDLE;
57079
+ case "digest":
57080
+ case "codedigest":
57081
+ case "scanner":
57082
+ return TONE_VIOLET;
57083
+ case "audit":
57084
+ case "auditor":
57085
+ return TONE_STOPPED;
57086
+ default:
57087
+ return TEXT_2;
56871
57088
  }
56872
57089
  }
56873
- function borderColorFor(state) {
57090
+ function stateGlyph(state, stale) {
57091
+ if (stale) return "?";
56874
57092
  switch (state) {
57093
+ case "starting":
57094
+ return "\u25CC";
56875
57095
  case "active":
56876
57096
  case "ticking":
56877
- return ACCENT;
57097
+ return "\u25CF";
56878
57098
  case "blocked":
56879
- return WARNING;
57099
+ return "\u23F8";
56880
57100
  case "done":
56881
- return SUCCESS;
57101
+ return "\u2713";
56882
57102
  case "aborted":
56883
57103
  case "error":
56884
- return ERROR2;
57104
+ return "\u2715";
56885
57105
  default:
56886
- return BORDER_DIM;
57106
+ return "\u25CB";
56887
57107
  }
56888
57108
  }
56889
- function progressBar(current, total, width) {
56890
- if (width <= 0 || total <= 0) return "";
56891
- const pct = Math.max(0, Math.min(1, current / total));
56892
- const filled = Math.round(width * pct);
56893
- return "\u2588".repeat(filled) + "\u2591".repeat(Math.max(0, width - filled));
57109
+ var STALE_THRESHOLD_MS = 6e4;
57110
+ function jobStatus(jobs) {
57111
+ if (jobs.length === 0) return "idle";
57112
+ let anyRunning = false;
57113
+ for (const j3 of jobs) {
57114
+ const s2 = j3.snapshot.state;
57115
+ if (s2 === "error" || s2 === "aborted") return "stopped";
57116
+ if (s2 === "active" || s2 === "ticking" || s2 === "starting") {
57117
+ anyRunning = true;
57118
+ }
57119
+ }
57120
+ return anyRunning ? "running" : "idle";
56894
57121
  }
56895
- function truncate(s2, max) {
56896
- if (s2.length <= max) return s2;
56897
- if (max <= 1) return s2.slice(0, max);
56898
- return s2.slice(0, Math.max(1, max - 1)) + "\u2026";
57122
+ function progressBar(width, pct) {
57123
+ const w2 = Math.max(1, width);
57124
+ const filled = Math.max(0, Math.min(w2, Math.round(pct / 100 * w2)));
57125
+ return "\u25B0".repeat(filled) + "\u25B1".repeat(w2 - filled);
56899
57126
  }
56900
- function formatAge2(ms) {
56901
- const s2 = Math.max(0, Math.floor(ms / 1e3));
57127
+ function elapsed(now, ts) {
57128
+ const s2 = Math.max(0, Math.floor((now - ts) / 1e3));
56902
57129
  if (s2 < 60) return `${s2}s`;
56903
57130
  const m2 = Math.floor(s2 / 60);
56904
- const rem = s2 % 60;
56905
- return rem === 0 ? `${m2}m` : `${m2}m ${rem}s`;
57131
+ const r2 = s2 % 60;
57132
+ return r2 === 0 ? `${m2}m` : `${m2}m ${r2}s`;
56906
57133
  }
56907
- function JobCard({
56908
- job,
56909
- height,
56910
- width,
56911
- spinnerFrame,
56912
- now
56913
- }) {
57134
+ function JobRow({ job, width, verbosity, now }) {
56914
57135
  const snap = job.snapshot;
57136
+ const tone = toneForKind(snap.kind);
56915
57137
  const stale = (snap.state === "active" || snap.state === "blocked") && now - snap.lastEventAt > STALE_THRESHOLD_MS;
56916
- const badge2 = stateBadge(snap.state, stale);
56917
- const glyph = snap.state === "ticking" && !stale ? SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length] : badge2.glyph;
56918
- const borderColor = borderColorFor(snap.state);
56919
- const innerHeight = Math.max(1, height - 2);
56920
- const innerWidth = Math.max(8, width - 4);
56921
- const rows = [];
56922
- const labelRoom = innerWidth - 4;
56923
- rows.push(
57138
+ const glyph = stateGlyph(snap.state, stale);
57139
+ const isGoal = snap.kind === "goal";
57140
+ const innerWidth = Math.max(8, width);
57141
+ const pct = snap.progress && snap.progress.total ? Math.round(snap.progress.current / snap.progress.total * 100) : null;
57142
+ const counter = snap.progress ? snap.progress.total ? `${snap.progress.current}/${snap.progress.total}` : `${snap.progress.current} ${snap.progress.unit}` : null;
57143
+ const kindLabel2 = snap.kind.toUpperCase();
57144
+ const idTrail = snap.id.length > 12 ? snap.id.slice(-8) : snap.id;
57145
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
56924
57146
  /* @__PURE__ */ jsxs2(Box2, { children: [
56925
- /* @__PURE__ */ jsxs2(Text2, { color: badge2.color, children: [
57147
+ /* @__PURE__ */ jsxs2(Text2, { color: tone, children: [
56926
57148
  glyph,
56927
57149
  " "
56928
57150
  ] }),
56929
- /* @__PURE__ */ jsx2(Text2, { color: TEXT, children: truncate(snap.label, labelRoom) })
56930
- ] }, "hdr")
56931
- );
56932
- if (innerHeight >= 2 && snap.progress) {
56933
- const { current, total, unit } = snap.progress;
56934
- if (total !== null && total > 0) {
56935
- const numTxt = `${current}/${total}`;
56936
- const barWidth = Math.max(0, innerWidth - numTxt.length - 1);
56937
- rows.push(
56938
- /* @__PURE__ */ jsxs2(Box2, { children: [
56939
- /* @__PURE__ */ jsx2(Text2, { color: ACCENT, children: progressBar(current, total, barWidth) }),
56940
- /* @__PURE__ */ jsxs2(Text2, { color: TEXT_DIM, children: [
56941
- " ",
56942
- numTxt
56943
- ] })
56944
- ] }, "bar")
56945
- );
56946
- } else {
56947
- rows.push(
56948
- /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: TEXT_DIM, children: [
56949
- current,
56950
- " ",
56951
- unit
56952
- ] }) }, "bar")
56953
- );
56954
- }
56955
- }
56956
- if (innerHeight >= 3 && snap.lastEvent) {
56957
- rows.push(
56958
- /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: TEXT_DIM, children: [
56959
- "\u21B3 ",
56960
- truncate(snap.lastEvent, innerWidth - 2)
56961
- ] }) }, "evt")
57151
+ /* @__PURE__ */ jsx2(Text2, { color: tone, bold: true, children: truncate(kindLabel2, innerWidth - idTrail.length - 4) }),
57152
+ /* @__PURE__ */ jsx2(Box2, { flexGrow: 1 }),
57153
+ /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, children: idTrail })
57154
+ ] }),
57155
+ /* @__PURE__ */ jsx2(Text2, { color: TEXT2, wrap: "truncate-end", children: truncate(snap.label, innerWidth) }),
57156
+ snap.lastEvent && /* @__PURE__ */ jsxs2(Text2, { color: TEXT_3, wrap: "truncate-end", children: [
57157
+ "\u21B3 ",
57158
+ truncate(snap.lastEvent, innerWidth - 2)
57159
+ ] }),
57160
+ isGoal && pct !== null && /* @__PURE__ */ jsxs2(Box2, { children: [
57161
+ /* @__PURE__ */ jsx2(Text2, { color: tone, children: progressBar(innerWidth - 6, pct) }),
57162
+ /* @__PURE__ */ jsxs2(Text2, { color: TEXT_4, children: [
57163
+ " ",
57164
+ pct,
57165
+ "%"
57166
+ ] })
57167
+ ] }),
57168
+ !isGoal && pct !== null && /* @__PURE__ */ jsxs2(Text2, { color: TEXT_3, children: [
57169
+ counter,
57170
+ " \xB7 ",
57171
+ pct,
57172
+ "%"
57173
+ ] }),
57174
+ pct === null && counter && /* @__PURE__ */ jsx2(Text2, { color: TEXT_3, children: truncate(counter, innerWidth) }),
57175
+ (verbosity === "full" || isGoal) && /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, children: snap.state === "ticking" && !stale ? `thinking \xB7 ${elapsed(now, snap.lastEventAt)}` : `${elapsed(now, snap.lastEventAt)} ago` })
57176
+ ] });
57177
+ }
57178
+ function JobsSection({
57179
+ jobs,
57180
+ width,
57181
+ verbosity,
57182
+ now
57183
+ }) {
57184
+ if (jobs.length === 0) return null;
57185
+ const status2 = jobStatus(jobs);
57186
+ const innerWidth = Math.max(8, width - 4);
57187
+ if (verbosity === "compact") {
57188
+ const labels = jobs.map((j3) => `${j3.snapshot.kind}: ${j3.snapshot.label}`).join(" \xB7 ");
57189
+ const summary = truncate(
57190
+ `${jobs.length} ${STATUS_LABEL[status2]} \xB7 ${labels} \xB7 Ctrl-] expand \xB7 Ctrl-G focus`,
57191
+ innerWidth
56962
57192
  );
57193
+ return /* @__PURE__ */ jsx2(WidgetFrame, { title: "Job Tray", status: status2, width, compact: true, children: /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_2, wrap: "truncate-end", children: summary }) }) });
56963
57194
  }
56964
- if (innerHeight >= 4) {
56965
- if (snap.state === "ticking" && !stale) {
56966
- rows.push(
56967
- /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: ACCENT, children: [
56968
- "thinking ",
56969
- formatAge2(now - snap.lastEventAt)
56970
- ] }) }, "age")
56971
- );
56972
- } else {
56973
- const finalState = job.finishedAt ? `\xB7 final ${snap.state}` : "";
56974
- const ageTxt = `${formatAge2(now - snap.lastEventAt)} ago ${finalState}`.trim();
56975
- rows.push(
56976
- /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsx2(Text2, { color: MUTED, children: truncate(ageTxt, innerWidth) }) }, "age")
56977
- );
57195
+ const subtitle = `${jobs.length} ${STATUS_LABEL[status2]}`;
57196
+ return /* @__PURE__ */ jsx2(
57197
+ WidgetFrame,
57198
+ {
57199
+ title: "Job Tray",
57200
+ subtitle,
57201
+ status: status2,
57202
+ width,
57203
+ children: jobs.map((job) => /* @__PURE__ */ jsx2(
57204
+ JobRow,
57205
+ {
57206
+ job,
57207
+ width: innerWidth,
57208
+ verbosity,
57209
+ now
57210
+ },
57211
+ job.snapshot.id
57212
+ ))
56978
57213
  }
57214
+ );
57215
+ }
57216
+ function SoulRow({
57217
+ block,
57218
+ width,
57219
+ bulletLimit
57220
+ }) {
57221
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, width, flexShrink: 0, children: [
57222
+ /* @__PURE__ */ jsx2(Box2, { width, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT2, bold: true, wrap: "truncate-end", children: truncate(block.head, width) }) }),
57223
+ /* @__PURE__ */ jsx2(Box2, { width, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, wrap: "truncate-end", children: truncate(block.badge, width) }) }),
57224
+ block.body.slice(0, bulletLimit).map((line, i2) => /* @__PURE__ */ jsx2(Box2, { width, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_2, wrap: "truncate-end", children: truncate(`\u2014 ${line}`, width) }) }, i2)),
57225
+ block.body.length > bulletLimit && /* @__PURE__ */ jsxs2(Text2, { color: TEXT_4, children: [
57226
+ "+",
57227
+ block.body.length - bulletLimit,
57228
+ " more"
57229
+ ] })
57230
+ ] });
57231
+ }
57232
+ function SoulSection({
57233
+ digest,
57234
+ width,
57235
+ verbosity
57236
+ }) {
57237
+ if (digest.blocks.length === 0) return null;
57238
+ const innerWidth = Math.max(8, width - 4);
57239
+ if (verbosity === "compact") {
57240
+ const heads = digest.blocks.map((b2) => b2.head).join(" \xB7 ");
57241
+ const totalEntries = digest.blocks.reduce(
57242
+ (acc, b2) => acc + b2.body.length,
57243
+ 0
57244
+ );
57245
+ const summary = truncate(
57246
+ `${heads} \xB7 ${totalEntries} entries`,
57247
+ innerWidth
57248
+ );
57249
+ return /* @__PURE__ */ jsx2(WidgetFrame, { title: "Soul", status: "idle", width, compact: true, children: /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_2, wrap: "truncate-end", children: summary }) }) });
56979
57250
  }
56980
- const padded = rows.slice(0, innerHeight);
56981
- while (padded.length < innerHeight) {
56982
- padded.push(/* @__PURE__ */ jsx2(Text2, { children: " " }, `pad-${padded.length}`));
57251
+ return /* @__PURE__ */ jsx2(
57252
+ WidgetFrame,
57253
+ {
57254
+ title: "Soul",
57255
+ subtitle: ".flow/soul.md \xB7 loaded into prompt",
57256
+ status: "idle",
57257
+ width,
57258
+ children: digest.blocks.map((block, i2) => /* @__PURE__ */ jsx2(
57259
+ SoulRow,
57260
+ {
57261
+ block,
57262
+ width: innerWidth,
57263
+ bulletLimit: 8
57264
+ },
57265
+ i2
57266
+ ))
57267
+ }
57268
+ );
57269
+ }
57270
+ function CodeDigestSection({
57271
+ status: status2,
57272
+ width,
57273
+ verbosity,
57274
+ now
57275
+ }) {
57276
+ if (status2.empty && status2.recent.length === 0) return null;
57277
+ const innerWidth = Math.max(8, width - 4);
57278
+ let widgetStatus = "idle";
57279
+ if (status2.empty) widgetStatus = "stopped";
57280
+ else if (status2.recent[0] && now - status2.recent[0].at < 3e4) {
57281
+ widgetStatus = "running";
57282
+ }
57283
+ if (verbosity === "compact") {
57284
+ const summary = status2.empty ? "no index \xB7 /codedigest index ." : `${status2.chunks.toLocaleString()} chunks \xB7 ${relativeTime(status2.builtAt, now)}` + (status2.recent.length > 0 ? ` \xB7 ${status2.recent.length} recent` : "");
57285
+ return /* @__PURE__ */ jsx2(WidgetFrame, { title: "CodeDigest", status: widgetStatus, width, compact: true, children: /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_2, wrap: "truncate-end", children: truncate(summary, innerWidth) }) }) });
57286
+ }
57287
+ const subtitle = status2.empty ? "no index \xB7 /codedigest index . to build" : `${status2.chunks.toLocaleString()} chunks \xB7 built ${relativeTime(status2.builtAt, now)}`;
57288
+ const recent = status2.recent.slice(0, 5);
57289
+ return /* @__PURE__ */ jsxs2(
57290
+ WidgetFrame,
57291
+ {
57292
+ title: "CodeDigest",
57293
+ subtitle,
57294
+ status: widgetStatus,
57295
+ width,
57296
+ children: [
57297
+ !status2.empty && status2.langs.length > 0 && /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: status2.langs.slice(0, 6).map((lang, i2) => /* @__PURE__ */ jsxs2(Text2, { color: TEXT_3, children: [
57298
+ i2 === 0 ? "" : " ",
57299
+ "[",
57300
+ lang,
57301
+ "]"
57302
+ ] }, lang)) }),
57303
+ recent.length > 0 && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
57304
+ /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, children: "recent" }),
57305
+ recent.map((entry) => {
57306
+ const hitColor = entry.hits === 0 ? TONE_AMBER : TONE_RUNNING;
57307
+ const hitText = entry.hits === 0 ? "\u2205" : `${entry.hits} hit`;
57308
+ const queryRoom = Math.max(4, innerWidth - hitText.length - 3);
57309
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
57310
+ /* @__PURE__ */ jsxs2(Box2, { width: innerWidth, children: [
57311
+ /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, children: "\u203A " }),
57312
+ /* @__PURE__ */ jsx2(Text2, { color: TEXT_2, wrap: "truncate-end", children: truncate(entry.q, queryRoom) }),
57313
+ /* @__PURE__ */ jsx2(Box2, { flexGrow: 1 }),
57314
+ /* @__PURE__ */ jsx2(Text2, { color: hitColor, children: hitText })
57315
+ ] }),
57316
+ entry.top && /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_4, wrap: "truncate-end", children: truncate(` ${entry.top}`, innerWidth) }) })
57317
+ ] }, `${entry.at}-${entry.q}`);
57318
+ })
57319
+ ] })
57320
+ ]
57321
+ }
57322
+ );
57323
+ }
57324
+ function ReasoningExcerptSection({
57325
+ lines,
57326
+ width,
57327
+ verbosity,
57328
+ now,
57329
+ lastUpdatedAt
57330
+ }) {
57331
+ const tail = lines.slice(verbosity === "full" ? -6 : -1);
57332
+ if (tail.length === 0) return null;
57333
+ const innerWidth = Math.max(8, width - 4);
57334
+ const stale = now - lastUpdatedAt > 5e3;
57335
+ const status2 = stale ? "idle" : "running";
57336
+ if (verbosity === "compact") {
57337
+ return /* @__PURE__ */ jsx2(WidgetFrame, { title: "Thinking", status: status2, width, compact: true, children: /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_3, wrap: "truncate-end", children: truncate(`\u2192 ${tail[tail.length - 1] ?? ""}`, innerWidth) }) }) });
56983
57338
  }
56984
57339
  return /* @__PURE__ */ jsx2(
56985
- Box2,
57340
+ WidgetFrame,
56986
57341
  {
56987
- flexDirection: "column",
56988
- borderStyle: "round",
56989
- borderColor,
56990
- paddingX: 1,
57342
+ title: "Thinking",
57343
+ subtitle: "Ctrl-T for full view",
57344
+ status: status2,
56991
57345
  width,
56992
- height,
56993
- children: padded
57346
+ children: tail.map((line, i2) => /* @__PURE__ */ jsx2(Box2, { width: innerWidth, children: /* @__PURE__ */ jsx2(Text2, { color: TEXT_3, wrap: "truncate-end", children: truncate(`\u2192 ${line}`, innerWidth) }) }, i2))
56994
57347
  }
56995
57348
  );
56996
57349
  }
57350
+
57351
+ // src/repl/job-rail.tsx
57352
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
57353
+ var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
57354
+ function stateBadge(state, stale) {
57355
+ if (stale) return { glyph: "?", color: WARNING };
57356
+ switch (state) {
57357
+ case "starting":
57358
+ return { glyph: "\u25CC", color: TEXT_DIM };
57359
+ case "active":
57360
+ return { glyph: "\u25B6", color: ACCENT };
57361
+ case "ticking":
57362
+ return { glyph: "\u25D0", color: ACCENT };
57363
+ case "blocked":
57364
+ return { glyph: "\u26A0", color: WARNING };
57365
+ case "paused":
57366
+ return { glyph: "\u23F8", color: MUTED };
57367
+ case "done":
57368
+ return { glyph: "\u2713", color: SUCCESS };
57369
+ case "aborted":
57370
+ return { glyph: "\u2717", color: ERROR2 };
57371
+ case "error":
57372
+ return { glyph: "\u2717", color: ERROR2 };
57373
+ }
57374
+ }
57375
+ function truncate2(s2, max) {
57376
+ if (s2.length <= max) return s2;
57377
+ if (max <= 1) return s2.slice(0, max);
57378
+ return s2.slice(0, Math.max(1, max - 1)) + "\u2026";
57379
+ }
56997
57380
  function RightRail({
56998
57381
  jobs,
56999
57382
  width,
57000
- height
57383
+ height,
57384
+ verbosity,
57385
+ soul,
57386
+ codeDigest,
57387
+ reasoning,
57388
+ reasoningUpdatedAt
57001
57389
  }) {
57002
- const [spinnerFrame, setSpinnerFrame] = useState(0);
57003
- const [now, setNow] = useState(Date.now());
57004
- const needsSpinner = jobs.some((j3) => j3.snapshot.state === "ticking");
57005
- useEffect(() => {
57006
- if (!needsSpinner) return;
57007
- const t2 = setInterval(() => setSpinnerFrame((f2) => f2 + 1), 120);
57008
- return () => clearInterval(t2);
57009
- }, [needsSpinner]);
57010
- useEffect(() => {
57390
+ const [now, setNow] = useState2(Date.now());
57391
+ useEffect2(() => {
57011
57392
  const t2 = setInterval(() => setNow(Date.now()), 1e3);
57012
57393
  return () => clearInterval(t2);
57013
57394
  }, []);
57014
- if (jobs.length === 0) return null;
57015
- const layout = solveJobLayout(jobs, height);
57016
- if (layout.allocations.length === 0 && layout.hiddenCount === 0) return null;
57017
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width, height, children: [
57018
- /* @__PURE__ */ jsx2(Text2, { color: MUTED, bold: true, children: "BACKGROUND JOBS" }),
57019
- layout.allocations.map((a2) => {
57020
- const job = jobs[a2.jobIndex];
57021
- return /* @__PURE__ */ jsx2(
57022
- JobCard,
57023
- {
57024
- job,
57025
- width,
57026
- height: a2.lines,
57027
- spinnerFrame,
57028
- now
57029
- },
57030
- job.snapshot.id
57031
- );
57032
- }),
57033
- layout.hiddenCount > 0 && /* @__PURE__ */ jsxs2(Text2, { color: TEXT_DIM, children: [
57034
- "+",
57035
- layout.hiddenCount,
57036
- " more \xB7 /jobs to view all"
57037
- ] })
57395
+ const hasContent = jobs.length > 0 || soul.blocks.length > 0 || !codeDigest.empty || codeDigest.recent.length > 0 || reasoning.length > 0;
57396
+ if (!hasContent) return null;
57397
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", width, flexShrink: 0, children: [
57398
+ /* @__PURE__ */ jsx3(
57399
+ JobsSection,
57400
+ {
57401
+ jobs,
57402
+ width,
57403
+ verbosity,
57404
+ now
57405
+ }
57406
+ ),
57407
+ /* @__PURE__ */ jsx3(SoulSection, { digest: soul, width, verbosity }),
57408
+ /* @__PURE__ */ jsx3(
57409
+ CodeDigestSection,
57410
+ {
57411
+ status: codeDigest,
57412
+ width,
57413
+ verbosity,
57414
+ now
57415
+ }
57416
+ ),
57417
+ /* @__PURE__ */ jsx3(
57418
+ ReasoningExcerptSection,
57419
+ {
57420
+ lines: reasoning,
57421
+ width,
57422
+ verbosity,
57423
+ now,
57424
+ lastUpdatedAt: reasoningUpdatedAt
57425
+ }
57426
+ )
57038
57427
  ] });
57039
57428
  }
57429
+ var RIGHT_RAIL_HIDE_BELOW = 100;
57430
+ var RIGHT_RAIL_STRIP_BELOW = 120;
57431
+ function rightRailColumns(cols, expanded) {
57432
+ if (cols < RIGHT_RAIL_STRIP_BELOW) return 0;
57433
+ if (expanded) {
57434
+ return Math.max(48, Math.min(80, Math.floor(cols * 0.42)));
57435
+ }
57436
+ return Math.max(36, Math.min(56, Math.floor(cols * 0.3)));
57437
+ }
57438
+ function pickRightRailMode(cols) {
57439
+ if (cols < RIGHT_RAIL_HIDE_BELOW) return "hidden";
57440
+ if (cols < RIGHT_RAIL_STRIP_BELOW) return "strip";
57441
+ return "rail";
57442
+ }
57040
57443
  function JobStrip({
57041
57444
  jobs
57042
57445
  }) {
57043
- const [spinnerFrame, setSpinnerFrame] = useState(0);
57446
+ const [spinnerFrame, setSpinnerFrame] = useState2(0);
57044
57447
  const needsSpinner = jobs.some((j3) => j3.snapshot.state === "ticking");
57045
- useEffect(() => {
57448
+ useEffect2(() => {
57046
57449
  if (!needsSpinner) return;
57047
57450
  const t2 = setInterval(() => setSpinnerFrame((f2) => f2 + 1), 120);
57048
57451
  return () => clearInterval(t2);
57049
57452
  }, [needsSpinner]);
57050
57453
  if (jobs.length === 0) return null;
57051
- return /* @__PURE__ */ jsx2(Box2, { flexWrap: "wrap", children: jobs.map((j3, i2) => {
57454
+ return /* @__PURE__ */ jsx3(Box3, { flexWrap: "wrap", children: jobs.map((j3, i2) => {
57052
57455
  const snap = j3.snapshot;
57053
57456
  const badge2 = stateBadge(snap.state, false);
57054
57457
  const glyph = snap.state === "ticking" ? SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length] : badge2.glyph;
57055
57458
  const progress = snap.progress && snap.progress.total !== null ? ` ${snap.progress.current}/${snap.progress.total}` : snap.progress ? ` ${snap.progress.current}` : "";
57056
- return /* @__PURE__ */ jsxs2(Box2, { marginRight: 2, children: [
57057
- /* @__PURE__ */ jsxs2(Text2, { color: badge2.color, children: [
57459
+ return /* @__PURE__ */ jsxs3(Box3, { marginRight: 2, children: [
57460
+ /* @__PURE__ */ jsxs3(Text3, { color: badge2.color, children: [
57058
57461
  glyph,
57059
57462
  " "
57060
57463
  ] }),
57061
- /* @__PURE__ */ jsxs2(Text2, { color: TEXT, children: [
57062
- truncate(snap.kind, 8),
57464
+ /* @__PURE__ */ jsxs3(Text3, { color: TEXT, children: [
57465
+ truncate2(snap.kind, 8),
57063
57466
  progress
57064
57467
  ] }),
57065
- i2 < jobs.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: MUTED, children: " " })
57468
+ i2 < jobs.length - 1 && /* @__PURE__ */ jsx3(Text3, { color: MUTED, children: " " })
57066
57469
  ] }, snap.id);
57067
57470
  }) });
57068
57471
  }
57069
57472
 
57473
+ // src/repl/use-soul-digest.ts
57474
+ import { useEffect as useEffect3, useState as useState3 } from "react";
57475
+ import { promises as fs56 } from "node:fs";
57476
+ var POLL_INTERVAL_MS = 2e3;
57477
+ var BLOCK_SPECS = [
57478
+ {
57479
+ begin: "<!-- AGENIT:SECTION:engineering-defaults:BEGIN -->",
57480
+ end: "<!-- AGENIT:SECTION:engineering-defaults:END -->",
57481
+ head: "Engineering Defaults",
57482
+ badge: "immutable \xB7 sha-tracked"
57483
+ },
57484
+ {
57485
+ begin: "<!-- AGENIT:SECTION:user-profile:BEGIN -->",
57486
+ end: "<!-- AGENIT:SECTION:user-profile:END -->",
57487
+ head: "User Profile",
57488
+ badge: "accreted"
57489
+ },
57490
+ {
57491
+ begin: "<!-- AGENIT:SECTION:auto-distilled:BEGIN -->",
57492
+ end: "<!-- AGENIT:SECTION:auto-distilled:END -->",
57493
+ head: "Auto-distilled",
57494
+ badge: "ephemeral"
57495
+ }
57496
+ ];
57497
+ var EMPTY_DIGEST = { blocks: [], full: "" };
57498
+ function extractBetween(content, begin, end) {
57499
+ const startIdx = content.indexOf(begin);
57500
+ if (startIdx < 0) return null;
57501
+ const bodyStart = startIdx + begin.length;
57502
+ const endIdx = content.indexOf(end, bodyStart);
57503
+ if (endIdx < 0) return null;
57504
+ return content.slice(bodyStart, endIdx);
57505
+ }
57506
+ function extractBullets(sectionBody) {
57507
+ const bullets = [];
57508
+ for (const raw of sectionBody.split("\n")) {
57509
+ const line = raw.trim();
57510
+ if (!line.startsWith("- ") && !line.startsWith("* ")) continue;
57511
+ bullets.push(line.slice(2).trim());
57512
+ }
57513
+ return bullets;
57514
+ }
57515
+ function badgeWithCount(base, n2) {
57516
+ if (n2 <= 0) return base;
57517
+ return `${base} \xB7 ${n2} entr${n2 === 1 ? "y" : "ies"}`;
57518
+ }
57519
+ function parseSoulDigest(content) {
57520
+ if (!content.trim()) return EMPTY_DIGEST;
57521
+ const blocks = [];
57522
+ for (const spec of BLOCK_SPECS) {
57523
+ const body = extractBetween(content, spec.begin, spec.end);
57524
+ if (body === null) continue;
57525
+ const bullets = extractBullets(body);
57526
+ if (bullets.length === 0) continue;
57527
+ blocks.push({
57528
+ head: spec.head,
57529
+ badge: spec.head === "User Profile" || spec.head === "Auto-distilled" ? badgeWithCount(spec.badge, bullets.length) : spec.badge,
57530
+ body: bullets
57531
+ });
57532
+ }
57533
+ return { blocks, full: content };
57534
+ }
57535
+ function useSoulDigest(soulPath) {
57536
+ const [digest, setDigest] = useState3(EMPTY_DIGEST);
57537
+ useEffect3(() => {
57538
+ if (!soulPath) {
57539
+ setDigest(EMPTY_DIGEST);
57540
+ return;
57541
+ }
57542
+ let cancelled = false;
57543
+ const tick = async () => {
57544
+ try {
57545
+ const content = await fs56.readFile(soulPath, "utf8");
57546
+ if (!cancelled) setDigest(parseSoulDigest(content));
57547
+ } catch {
57548
+ if (!cancelled) setDigest(EMPTY_DIGEST);
57549
+ }
57550
+ };
57551
+ void tick();
57552
+ const interval = setInterval(tick, POLL_INTERVAL_MS);
57553
+ return () => {
57554
+ cancelled = true;
57555
+ clearInterval(interval);
57556
+ };
57557
+ }, [soulPath]);
57558
+ return digest;
57559
+ }
57560
+
57561
+ // src/repl/use-codedigest-status.ts
57562
+ init_dist3();
57563
+ import { useEffect as useEffect4, useState as useState4 } from "react";
57564
+ var STATUS_POLL_MS = 1e4;
57565
+ var RECENT_REFRESH_MS = 1e3;
57566
+ var EMPTY_PARSED = {
57567
+ empty: true,
57568
+ chunks: 0,
57569
+ builtAt: null,
57570
+ langs: []
57571
+ };
57572
+ function parseStatus(raw) {
57573
+ if (/^No index found/.test(raw)) return EMPTY_PARSED;
57574
+ const chunkMatch = raw.match(/:\s*(\d+)\s+chunks\s+indexed/);
57575
+ const builtMatch = raw.match(/Built:\s*(\S.*?)\s*$/m);
57576
+ const langSection = raw.split(/^By language:\s*$/m)[1];
57577
+ const langs = [];
57578
+ if (langSection) {
57579
+ const pairs = [];
57580
+ for (const line of langSection.split("\n")) {
57581
+ const m2 = line.match(/^\s*(\S+):\s*(\d+)\s*$/);
57582
+ if (!m2) continue;
57583
+ pairs.push({ lang: m2[1], count: Number(m2[2]) });
57584
+ }
57585
+ pairs.sort((a2, b2) => b2.count - a2.count);
57586
+ for (const p2 of pairs) langs.push(p2.lang);
57587
+ }
57588
+ return {
57589
+ empty: false,
57590
+ chunks: chunkMatch ? Number(chunkMatch[1]) : 0,
57591
+ builtAt: builtMatch ? builtMatch[1] : null,
57592
+ langs
57593
+ };
57594
+ }
57595
+ function useCodeDigestStatus(dbDir, project) {
57596
+ const [status2, setStatus] = useState4(EMPTY_PARSED);
57597
+ const [recent, setRecent] = useState4(() => getRecentSearches());
57598
+ useEffect4(() => {
57599
+ if (!dbDir || !project) {
57600
+ setStatus(EMPTY_PARSED);
57601
+ return;
57602
+ }
57603
+ let cancelled = false;
57604
+ const tick = async () => {
57605
+ try {
57606
+ const raw = await status(dbDir, project);
57607
+ if (!cancelled) setStatus(parseStatus(raw));
57608
+ } catch {
57609
+ if (!cancelled) setStatus(EMPTY_PARSED);
57610
+ }
57611
+ };
57612
+ void tick();
57613
+ const interval = setInterval(tick, STATUS_POLL_MS);
57614
+ return () => {
57615
+ cancelled = true;
57616
+ clearInterval(interval);
57617
+ };
57618
+ }, [dbDir, project]);
57619
+ useEffect4(() => {
57620
+ const interval = setInterval(() => {
57621
+ setRecent(getRecentSearches());
57622
+ }, RECENT_REFRESH_MS);
57623
+ return () => clearInterval(interval);
57624
+ }, []);
57625
+ return { ...status2, recent };
57626
+ }
57627
+
57070
57628
  // src/repl/job-detail.tsx
57071
- import { useEffect as useEffect2, useState as useState2 } from "react";
57072
- import { Box as Box3, Text as Text3 } from "ink";
57073
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
57629
+ import { useEffect as useEffect5, useState as useState5 } from "react";
57630
+ import { Box as Box4, Text as Text4 } from "ink";
57631
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
57074
57632
  function colorFor(state) {
57075
57633
  if (state === "active" || state === "ticking") return ACCENT;
57076
57634
  if (state === "blocked") return WARNING;
@@ -57081,14 +57639,15 @@ function colorFor(state) {
57081
57639
  function JobDetailPanel({
57082
57640
  job,
57083
57641
  projectDir: projectDir2,
57642
+ reasoning,
57084
57643
  width,
57085
57644
  height
57086
57645
  }) {
57087
- const [output, setOutput] = useState2(null);
57088
- const [turnList, setTurnList] = useState2([]);
57089
- const [advisorTurns, setAdvisorTurns] = useState2([]);
57090
- const [loading, setLoading] = useState2(true);
57091
- useEffect2(() => {
57646
+ const [output, setOutput] = useState5(null);
57647
+ const [turnList, setTurnList] = useState5([]);
57648
+ const [advisorTurns, setAdvisorTurns] = useState5([]);
57649
+ const [loading, setLoading] = useState5(true);
57650
+ useEffect5(() => {
57092
57651
  let cancelled = false;
57093
57652
  if (!projectDir2) {
57094
57653
  setLoading(false);
@@ -57116,12 +57675,18 @@ function JobDetailPanel({
57116
57675
  };
57117
57676
  }, [projectDir2, job.snapshot.id]);
57118
57677
  const snap = job.snapshot;
57678
+ const isLive = snap.state === "ticking" || snap.state === "active";
57679
+ const showThinking = reasoning.length > 0;
57680
+ const totalBody = Math.max(4, height - 14);
57681
+ const thinkingBudget = showThinking ? isLive ? Math.max(3, Math.floor(totalBody * 0.55)) : Math.min(reasoning.length, Math.max(2, Math.floor(totalBody * 0.35))) : 0;
57682
+ const outputBudget = Math.max(2, totalBody - thinkingBudget - (showThinking ? 2 : 0));
57119
57683
  const outputLines = output ? output.split("\n") : [];
57120
- const maxOutputLines = Math.max(2, height - 14);
57121
- const visibleOutput = outputLines.slice(0, maxOutputLines);
57684
+ const visibleOutput = outputLines.slice(0, outputBudget);
57122
57685
  const hiddenOutputCount = outputLines.length - visibleOutput.length;
57123
- return /* @__PURE__ */ jsxs3(
57124
- Box3,
57686
+ const visibleThinking = reasoning.slice(-thinkingBudget);
57687
+ const hiddenThinkingCount = Math.max(0, reasoning.length - visibleThinking.length);
57688
+ return /* @__PURE__ */ jsxs4(
57689
+ Box4,
57125
57690
  {
57126
57691
  flexDirection: "column",
57127
57692
  borderStyle: "double",
@@ -57130,56 +57695,70 @@ function JobDetailPanel({
57130
57695
  width,
57131
57696
  height,
57132
57697
  children: [
57133
- /* @__PURE__ */ jsxs3(Box3, { children: [
57134
- /* @__PURE__ */ jsxs3(Text3, { bold: true, color: colorFor(snap.state), children: [
57698
+ /* @__PURE__ */ jsxs4(Box4, { children: [
57699
+ /* @__PURE__ */ jsxs4(Text4, { bold: true, color: colorFor(snap.state), children: [
57135
57700
  "\u25C6 ",
57136
57701
  snap.label
57137
57702
  ] }),
57138
- /* @__PURE__ */ jsxs3(Text3, { color: TEXT_DIM, children: [
57703
+ /* @__PURE__ */ jsxs4(Text4, { color: TEXT_DIM, children: [
57139
57704
  " (",
57140
57705
  snap.kind,
57141
57706
  ")"
57142
57707
  ] })
57143
57708
  ] }),
57144
- /* @__PURE__ */ jsx3(Text3, { color: MUTED, children: snap.id }),
57145
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
57146
- /* @__PURE__ */ jsxs3(Box3, { children: [
57147
- /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "state : " }),
57148
- /* @__PURE__ */ jsx3(Text3, { color: colorFor(snap.state), children: snap.state })
57709
+ /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: snap.id }),
57710
+ /* @__PURE__ */ jsx4(Text4, { children: " " }),
57711
+ /* @__PURE__ */ jsxs4(Box4, { children: [
57712
+ /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "state : " }),
57713
+ /* @__PURE__ */ jsx4(Text4, { color: colorFor(snap.state), children: snap.state })
57149
57714
  ] }),
57150
- snap.progress && /* @__PURE__ */ jsxs3(Box3, { children: [
57151
- /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "progress : " }),
57152
- /* @__PURE__ */ jsxs3(Text3, { color: TEXT, children: [
57715
+ snap.progress && /* @__PURE__ */ jsxs4(Box4, { children: [
57716
+ /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "progress : " }),
57717
+ /* @__PURE__ */ jsxs4(Text4, { color: TEXT, children: [
57153
57718
  snap.progress.current,
57154
57719
  snap.progress.total !== null ? `/${snap.progress.total}` : "",
57155
57720
  " ",
57156
57721
  snap.progress.unit
57157
57722
  ] })
57158
57723
  ] }),
57159
- snap.lastEvent && /* @__PURE__ */ jsxs3(Box3, { children: [
57160
- /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "last : " }),
57161
- /* @__PURE__ */ jsx3(Text3, { color: TEXT, children: snap.lastEvent })
57724
+ snap.lastEvent && /* @__PURE__ */ jsxs4(Box4, { children: [
57725
+ /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "last : " }),
57726
+ /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: snap.lastEvent })
57162
57727
  ] }),
57163
- job.finishedAt && /* @__PURE__ */ jsxs3(Box3, { children: [
57164
- /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "finished : " }),
57165
- /* @__PURE__ */ jsx3(Text3, { color: WARNING, children: new Date(job.finishedAt).toLocaleTimeString() })
57728
+ job.finishedAt && /* @__PURE__ */ jsxs4(Box4, { children: [
57729
+ /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "finished : " }),
57730
+ /* @__PURE__ */ jsx4(Text4, { color: WARNING, children: new Date(job.finishedAt).toLocaleTimeString() })
57731
+ ] }),
57732
+ showThinking && /* @__PURE__ */ jsxs4(Fragment2, { children: [
57733
+ /* @__PURE__ */ jsx4(Text4, { children: " " }),
57734
+ /* @__PURE__ */ jsxs4(Box4, { children: [
57735
+ /* @__PURE__ */ jsx4(Text4, { color: BORDER_DIM, children: "\u2500 Model thinking " }),
57736
+ isLive ? /* @__PURE__ */ jsx4(Text4, { color: ACCENT, children: "(live)" }) : /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: "(last trace)" }),
57737
+ /* @__PURE__ */ jsx4(Text4, { color: BORDER_DIM, children: " \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" })
57738
+ ] }),
57739
+ hiddenThinkingCount > 0 && /* @__PURE__ */ jsxs4(Text4, { color: TEXT_DIM, children: [
57740
+ "\u2026 ",
57741
+ hiddenThinkingCount,
57742
+ " earlier lines"
57743
+ ] }),
57744
+ visibleThinking.map((line, i2) => /* @__PURE__ */ jsx4(Text4, { color: isLive ? TEXT : TEXT_DIM, children: line || " " }, `th-${i2}`))
57166
57745
  ] }),
57167
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
57168
- /* @__PURE__ */ jsx3(Text3, { color: BORDER_DIM, children: "\u2500 Latest turn output \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
57169
- loading && /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "loading\u2026" }),
57170
- !loading && turnList.length === 0 && /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: "No stored turns yet (run `/goal tick` or `/goal start`)." }),
57171
- !loading && visibleOutput.map((line, i2) => /* @__PURE__ */ jsx3(Text3, { color: TEXT_DIM, children: line || " " }, i2)),
57172
- hiddenOutputCount > 0 && /* @__PURE__ */ jsxs3(Text3, { color: WARNING, children: [
57746
+ /* @__PURE__ */ jsx4(Text4, { children: " " }),
57747
+ /* @__PURE__ */ jsx4(Text4, { color: BORDER_DIM, children: "\u2500 Latest turn output \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
57748
+ loading && /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "loading\u2026" }),
57749
+ !loading && turnList.length === 0 && /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "No stored turns yet (run `/goal tick` or `/goal start`)." }),
57750
+ !loading && visibleOutput.map((line, i2) => /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: line || " " }, i2)),
57751
+ hiddenOutputCount > 0 && /* @__PURE__ */ jsxs4(Text4, { color: WARNING, children: [
57173
57752
  "+ ",
57174
57753
  hiddenOutputCount,
57175
57754
  " more lines \xB7 `/goal output ",
57176
57755
  turnList[turnList.length - 1],
57177
57756
  "` for full"
57178
57757
  ] }),
57179
- advisorTurns.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
57180
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
57181
- /* @__PURE__ */ jsx3(Text3, { color: BORDER_DIM, children: "\u2500 Advisor consults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
57182
- advisorTurns.map((t2) => /* @__PURE__ */ jsxs3(Text3, { color: TEXT_DIM, children: [
57758
+ advisorTurns.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
57759
+ /* @__PURE__ */ jsx4(Text4, { children: " " }),
57760
+ /* @__PURE__ */ jsx4(Text4, { color: BORDER_DIM, children: "\u2500 Advisor consults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
57761
+ advisorTurns.map((t2) => /* @__PURE__ */ jsxs4(Text4, { color: TEXT_DIM, children: [
57183
57762
  "\xB7 turn ",
57184
57763
  t2,
57185
57764
  " \u2014 `/goal advisor ",
@@ -57187,24 +57766,24 @@ function JobDetailPanel({
57187
57766
  "` for the reply"
57188
57767
  ] }, t2))
57189
57768
  ] }),
57190
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
57191
- /* @__PURE__ */ jsx3(Text3, { color: MUTED, children: "Esc to close \xB7 Tab cycles cards \xB7 Ctrl-J to expand again" })
57769
+ /* @__PURE__ */ jsx4(Text4, { children: " " }),
57770
+ /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: "Esc \xB7 Ctrl-G to minimize \xB7 Tab / Enter to cycle to next job" })
57192
57771
  ]
57193
57772
  }
57194
57773
  );
57195
57774
  }
57196
57775
 
57197
57776
  // src/repl/goal-modals.tsx
57198
- import { Box as Box4, Text as Text4 } from "ink";
57777
+ import { Box as Box5, Text as Text5 } from "ink";
57199
57778
  import TextInput from "ink-text-input";
57200
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
57779
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
57201
57780
  function GoalStartGateModal({
57202
57781
  goalId,
57203
57782
  objective,
57204
57783
  width
57205
57784
  }) {
57206
- return /* @__PURE__ */ jsxs4(
57207
- Box4,
57785
+ return /* @__PURE__ */ jsxs5(
57786
+ Box5,
57208
57787
  {
57209
57788
  flexDirection: "column",
57210
57789
  borderStyle: "double",
@@ -57213,23 +57792,23 @@ function GoalStartGateModal({
57213
57792
  paddingY: 1,
57214
57793
  width,
57215
57794
  children: [
57216
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: ACCENT, children: "\u25C6 /goal start \u2014 plan first?" }),
57217
- /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: goalId }),
57218
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57219
- /* @__PURE__ */ jsxs4(Box4, { children: [
57220
- /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "objective: " }),
57221
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: objective })
57795
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: ACCENT, children: "\u25C6 /goal start \u2014 plan first?" }),
57796
+ /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: goalId }),
57797
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57798
+ /* @__PURE__ */ jsxs5(Box5, { children: [
57799
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: "objective: " }),
57800
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: objective })
57222
57801
  ] }),
57223
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57224
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: "Run speckit planning first? It produces a spec + plan you review before the autonomous runner starts. Helps the agent stay on track, but adds 30-60s of upfront work." }),
57225
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57226
- /* @__PURE__ */ jsxs4(Box4, { children: [
57227
- /* @__PURE__ */ jsx4(Text4, { color: SUCCESS, children: "[Y]" }),
57228
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " plan with speckit, then start " }),
57229
- /* @__PURE__ */ jsx4(Text4, { color: WARNING, children: "[N]" }),
57230
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " skip planning, start now " }),
57231
- /* @__PURE__ */ jsx4(Text4, { color: ERROR2, children: "[Esc]" }),
57232
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " cancel" })
57802
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57803
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: "Run speckit planning first? It produces a spec + plan you review before the autonomous runner starts. Helps the agent stay on track, but adds 30-60s of upfront work." }),
57804
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57805
+ /* @__PURE__ */ jsxs5(Box5, { children: [
57806
+ /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "[Y]" }),
57807
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " plan with speckit, then start " }),
57808
+ /* @__PURE__ */ jsx5(Text5, { color: WARNING, children: "[N]" }),
57809
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " skip planning, start now " }),
57810
+ /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "[Esc]" }),
57811
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel" })
57233
57812
  ] })
57234
57813
  ]
57235
57814
  }
@@ -57242,8 +57821,8 @@ function ModelPickerModal({
57242
57821
  selected,
57243
57822
  width
57244
57823
  }) {
57245
- return /* @__PURE__ */ jsxs4(
57246
- Box4,
57824
+ return /* @__PURE__ */ jsxs5(
57825
+ Box5,
57247
57826
  {
57248
57827
  flexDirection: "column",
57249
57828
  borderStyle: "double",
@@ -57252,17 +57831,17 @@ function ModelPickerModal({
57252
57831
  paddingY: 1,
57253
57832
  width,
57254
57833
  children: [
57255
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: ACCENT, children: [
57834
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, color: ACCENT, children: [
57256
57835
  "\u25C6 Pick a model: ",
57257
57836
  purpose
57258
57837
  ] }),
57259
- hint && /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: hint }),
57260
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57838
+ hint && /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: hint }),
57839
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57261
57840
  choices.map((c2, i2) => {
57262
57841
  const active = i2 === selected;
57263
- return /* @__PURE__ */ jsxs4(Box4, { children: [
57264
- /* @__PURE__ */ jsxs4(
57265
- Text4,
57842
+ return /* @__PURE__ */ jsxs5(Box5, { children: [
57843
+ /* @__PURE__ */ jsxs5(
57844
+ Text5,
57266
57845
  {
57267
57846
  color: active ? SELECTED_FG : TEXT,
57268
57847
  backgroundColor: active ? SELECTED_BG : void 0,
@@ -57272,24 +57851,24 @@ function ModelPickerModal({
57272
57851
  ]
57273
57852
  }
57274
57853
  ),
57275
- /* @__PURE__ */ jsxs4(Text4, { color: TEXT_DIM, children: [
57854
+ /* @__PURE__ */ jsxs5(Text5, { color: TEXT_DIM, children: [
57276
57855
  " ",
57277
57856
  c2.model || "(auto)"
57278
57857
  ] }),
57279
- /* @__PURE__ */ jsxs4(Text4, { color: MUTED, children: [
57858
+ /* @__PURE__ */ jsxs5(Text5, { color: MUTED, children: [
57280
57859
  " ",
57281
57860
  c2.provider
57282
57861
  ] })
57283
57862
  ] }, `${c2.tier}:${c2.model}`);
57284
57863
  }),
57285
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57286
- /* @__PURE__ */ jsxs4(Box4, { children: [
57287
- /* @__PURE__ */ jsx4(Text4, { color: ACCENT, children: "\u2191/\u2193" }),
57288
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " select " }),
57289
- /* @__PURE__ */ jsx4(Text4, { color: SUCCESS, children: "Enter" }),
57290
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " confirm " }),
57291
- /* @__PURE__ */ jsx4(Text4, { color: ERROR2, children: "Esc" }),
57292
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " cancel" })
57864
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57865
+ /* @__PURE__ */ jsxs5(Box5, { children: [
57866
+ /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "\u2191/\u2193" }),
57867
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " select " }),
57868
+ /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "Enter" }),
57869
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " confirm " }),
57870
+ /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "Esc" }),
57871
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel" })
57293
57872
  ] })
57294
57873
  ]
57295
57874
  }
@@ -57297,17 +57876,17 @@ function ModelPickerModal({
57297
57876
  }
57298
57877
  function StreamingPlanLoaderModal({
57299
57878
  goalId,
57300
- buffer,
57879
+ buffer: buffer3,
57301
57880
  model,
57302
57881
  phase = "plan",
57303
57882
  width,
57304
57883
  height
57305
57884
  }) {
57306
57885
  const visibleLines = Math.max(5, height - 7);
57307
- const lines = buffer.split("\n");
57886
+ const lines = buffer3.split("\n");
57308
57887
  const tail = lines.slice(Math.max(0, lines.length - visibleLines));
57309
- return /* @__PURE__ */ jsxs4(
57310
- Box4,
57888
+ return /* @__PURE__ */ jsxs5(
57889
+ Box5,
57311
57890
  {
57312
57891
  flexDirection: "column",
57313
57892
  borderStyle: "double",
@@ -57317,20 +57896,20 @@ function StreamingPlanLoaderModal({
57317
57896
  width,
57318
57897
  height,
57319
57898
  children: [
57320
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: ACCENT, children: [
57899
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, color: ACCENT, children: [
57321
57900
  "\u25C6 Running ",
57322
57901
  phase,
57323
57902
  "\u2026 (live)"
57324
57903
  ] }),
57325
- /* @__PURE__ */ jsxs4(Text4, { color: MUTED, children: [
57904
+ /* @__PURE__ */ jsxs5(Text5, { color: MUTED, children: [
57326
57905
  goalId,
57327
57906
  " \xB7 model: ",
57328
57907
  model || "(auto)"
57329
57908
  ] }),
57330
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57331
- tail.length === 0 || tail.length === 1 && tail[0] === "" ? /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: "(waiting for first token\u2026)" }) : tail.map((line, i2) => /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: line || " " }, i2)),
57332
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57333
- /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: "Streaming directly from the model. Esc cancels." })
57909
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57910
+ tail.length === 0 || tail.length === 1 && tail[0] === "" ? /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: "(waiting for first token\u2026)" }) : tail.map((line, i2) => /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: line || " " }, i2)),
57911
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57912
+ /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: "Streaming directly from the model. Esc cancels." })
57334
57913
  ]
57335
57914
  }
57336
57915
  );
@@ -57341,8 +57920,8 @@ function YesNoStepModal({
57341
57920
  detail,
57342
57921
  width
57343
57922
  }) {
57344
- return /* @__PURE__ */ jsxs4(
57345
- Box4,
57923
+ return /* @__PURE__ */ jsxs5(
57924
+ Box5,
57346
57925
  {
57347
57926
  flexDirection: "column",
57348
57927
  borderStyle: "double",
@@ -57351,24 +57930,24 @@ function YesNoStepModal({
57351
57930
  paddingY: 1,
57352
57931
  width,
57353
57932
  children: [
57354
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: ACCENT, children: [
57933
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, color: ACCENT, children: [
57355
57934
  "\u25C6 ",
57356
57935
  title
57357
57936
  ] }),
57358
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57359
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: description }),
57360
- detail && /* @__PURE__ */ jsxs4(Fragment3, { children: [
57361
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57362
- /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: detail })
57937
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57938
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: description }),
57939
+ detail && /* @__PURE__ */ jsxs5(Fragment3, { children: [
57940
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57941
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: detail })
57363
57942
  ] }),
57364
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57365
- /* @__PURE__ */ jsxs4(Box4, { children: [
57366
- /* @__PURE__ */ jsx4(Text4, { color: SUCCESS, children: "[Y]" }),
57367
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " run it " }),
57368
- /* @__PURE__ */ jsx4(Text4, { color: WARNING, children: "[N]" }),
57369
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " skip " }),
57370
- /* @__PURE__ */ jsx4(Text4, { color: ERROR2, children: "[Esc]" }),
57371
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " cancel goal start" })
57943
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57944
+ /* @__PURE__ */ jsxs5(Box5, { children: [
57945
+ /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "[Y]" }),
57946
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " run it " }),
57947
+ /* @__PURE__ */ jsx5(Text5, { color: WARNING, children: "[N]" }),
57948
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " skip " }),
57949
+ /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "[Esc]" }),
57950
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel goal start" })
57372
57951
  ] })
57373
57952
  ]
57374
57953
  }
@@ -57382,8 +57961,8 @@ function ClarifyQAModal({
57382
57961
  onChange,
57383
57962
  width
57384
57963
  }) {
57385
- return /* @__PURE__ */ jsxs4(
57386
- Box4,
57964
+ return /* @__PURE__ */ jsxs5(
57965
+ Box5,
57387
57966
  {
57388
57967
  flexDirection: "column",
57389
57968
  borderStyle: "double",
@@ -57392,20 +57971,20 @@ function ClarifyQAModal({
57392
57971
  paddingY: 1,
57393
57972
  width,
57394
57973
  children: [
57395
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: ACCENT, children: [
57974
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, color: ACCENT, children: [
57396
57975
  "\u25C6 Clarify (",
57397
57976
  index2,
57398
57977
  " / ",
57399
57978
  total,
57400
57979
  ")"
57401
57980
  ] }),
57402
- /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: "Your answers feed pass-2 which rewrites spec.md." }),
57403
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57404
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: question }),
57405
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57406
- /* @__PURE__ */ jsxs4(Box4, { children: [
57407
- /* @__PURE__ */ jsx4(Text4, { color: ACCENT, children: "\u203A " }),
57408
- /* @__PURE__ */ jsx4(
57981
+ /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: "Your answers feed pass-2 which rewrites spec.md." }),
57982
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57983
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: question }),
57984
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57985
+ /* @__PURE__ */ jsxs5(Box5, { children: [
57986
+ /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "\u203A " }),
57987
+ /* @__PURE__ */ jsx5(
57409
57988
  TextInput,
57410
57989
  {
57411
57990
  value: draft,
@@ -57416,32 +57995,42 @@ function ClarifyQAModal({
57416
57995
  }
57417
57996
  )
57418
57997
  ] }),
57419
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57420
- /* @__PURE__ */ jsxs4(Box4, { children: [
57421
- /* @__PURE__ */ jsx4(Text4, { color: SUCCESS, children: "Enter" }),
57422
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " next question " }),
57423
- /* @__PURE__ */ jsx4(Text4, { color: WARNING, children: "Esc" }),
57424
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " skip this one " }),
57425
- /* @__PURE__ */ jsx4(Text4, { color: ERROR2, children: "Ctrl-C" }),
57426
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " cancel clarify" })
57998
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
57999
+ /* @__PURE__ */ jsxs5(Box5, { children: [
58000
+ /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "Enter" }),
58001
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " next question " }),
58002
+ /* @__PURE__ */ jsx5(Text5, { color: WARNING, children: "Esc" }),
58003
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " skip this one " }),
58004
+ /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "Ctrl-C" }),
58005
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel clarify" })
57427
58006
  ] })
57428
58007
  ]
57429
58008
  }
57430
58009
  );
57431
58010
  }
58011
+ var CHROME_LINES = 9;
58012
+ function renderPlanLines(summary) {
58013
+ return renderMarkdown(summary).split("\n");
58014
+ }
58015
+ function planViewportLines(height) {
58016
+ return Math.max(4, height - CHROME_LINES);
58017
+ }
57432
58018
  function PlanApprovalModal({
57433
58019
  goalId,
57434
58020
  summary,
57435
58021
  planPath,
58022
+ scrollOffset,
57436
58023
  width,
57437
58024
  height
57438
58025
  }) {
57439
- const lines = summary.split("\n");
57440
- const maxLines = Math.max(4, height - 9);
57441
- const visible = lines.slice(0, maxLines);
57442
- const hidden = lines.length - visible.length;
57443
- return /* @__PURE__ */ jsxs4(
57444
- Box4,
58026
+ const lines = renderPlanLines(summary);
58027
+ const maxLines = planViewportLines(height);
58028
+ const offset = Math.max(0, Math.min(scrollOffset, Math.max(0, lines.length - maxLines)));
58029
+ const visible = lines.slice(offset, offset + maxLines);
58030
+ const above = offset;
58031
+ const below = Math.max(0, lines.length - offset - visible.length);
58032
+ return /* @__PURE__ */ jsxs5(
58033
+ Box5,
57445
58034
  {
57446
58035
  flexDirection: "column",
57447
58036
  borderStyle: "double",
@@ -57451,25 +58040,32 @@ function PlanApprovalModal({
57451
58040
  width,
57452
58041
  height,
57453
58042
  children: [
57454
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: ACCENT, children: "\u25C6 Plan ready \u2014 approve?" }),
57455
- /* @__PURE__ */ jsx4(Text4, { color: MUTED, children: goalId }),
57456
- /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: planPath }),
57457
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57458
- /* @__PURE__ */ jsx4(Text4, { color: BORDER_DIM, children: "\u2500 Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
57459
- visible.map((l2, i2) => /* @__PURE__ */ jsx4(Text4, { color: TEXT_DIM, children: l2 || " " }, i2)),
57460
- hidden > 0 && /* @__PURE__ */ jsxs4(Text4, { color: WARNING, children: [
57461
- "+ ",
57462
- hidden,
57463
- " more lines (open the file to read)"
58043
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: ACCENT, children: "\u25C6 Plan ready \u2014 approve?" }),
58044
+ /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: goalId }),
58045
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: planPath }),
58046
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
58047
+ /* @__PURE__ */ jsxs5(Box5, { children: [
58048
+ /* @__PURE__ */ jsx5(Text5, { color: BORDER_DIM, children: "\u2500 Summary " }),
58049
+ /* @__PURE__ */ jsx5(Text5, { color: above > 0 ? ACCENT : BORDER_DIM, children: above > 0 ? "\u25B2" : "\u2500" }),
58050
+ /* @__PURE__ */ jsx5(Text5, { color: BORDER_DIM, children: " " }),
58051
+ /* @__PURE__ */ jsx5(Text5, { color: below > 0 ? ACCENT : BORDER_DIM, children: below > 0 ? "\u25BC" : "\u2500" }),
58052
+ /* @__PURE__ */ jsxs5(Text5, { color: BORDER_DIM, children: [
58053
+ " ",
58054
+ lines.length > 0 ? `${offset + 1}-${offset + visible.length} / ${lines.length} ` : "",
58055
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
58056
+ ] })
57464
58057
  ] }),
57465
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
57466
- /* @__PURE__ */ jsxs4(Box4, { children: [
57467
- /* @__PURE__ */ jsx4(Text4, { color: SUCCESS, children: "[Y]" }),
57468
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " approve & start runner " }),
57469
- /* @__PURE__ */ jsx4(Text4, { color: ACCENT, children: "[E]" }),
57470
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " edit in $EDITOR " }),
57471
- /* @__PURE__ */ jsx4(Text4, { color: ERROR2, children: "[N/Esc]" }),
57472
- /* @__PURE__ */ jsx4(Text4, { color: TEXT, children: " cancel" })
58058
+ visible.map((l2, i2) => /* @__PURE__ */ jsx5(Text5, { children: l2.length > 0 ? l2 : " " }, i2)),
58059
+ /* @__PURE__ */ jsx5(Text5, { children: " " }),
58060
+ /* @__PURE__ */ jsxs5(Box5, { children: [
58061
+ /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "[Y]" }),
58062
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " approve & start " }),
58063
+ /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "[E]" }),
58064
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " edit in $EDITOR " }),
58065
+ /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "[\u2191/\u2193]" }),
58066
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " scroll " }),
58067
+ /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "[N/Esc]" }),
58068
+ /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel" })
57473
58069
  ] })
57474
58070
  ]
57475
58071
  }
@@ -57478,7 +58074,7 @@ function PlanApprovalModal({
57478
58074
 
57479
58075
  // src/repl/plan-generation.ts
57480
58076
  import { spawn as spawn19 } from "node:child_process";
57481
- import { promises as fs56 } from "node:fs";
58077
+ import { promises as fs57 } from "node:fs";
57482
58078
  init_dist2();
57483
58079
  async function editPlanFile(planPath) {
57484
58080
  const editor = process.env.VISUAL || process.env.EDITOR || "vi";
@@ -57490,12 +58086,12 @@ async function editPlanFile(planPath) {
57490
58086
  else reject(new Error(`${editor} exited with status ${code}`));
57491
58087
  });
57492
58088
  });
57493
- return fs56.readFile(planPath, "utf8");
58089
+ return fs57.readFile(planPath, "utf8");
57494
58090
  }
57495
58091
 
57496
58092
  // src/repl/plan-via-speckit.ts
57497
58093
  init_dist2();
57498
- import { promises as fs57 } from "node:fs";
58094
+ import { promises as fs58 } from "node:fs";
57499
58095
  import path58 from "node:path";
57500
58096
  async function generatePlanViaSpeckit(cfg, state, objective, opts = {}) {
57501
58097
  const fid = slugify(objective);
@@ -57519,7 +58115,7 @@ async function generatePlanViaSpeckit(cfg, state, objective, opts = {}) {
57519
58115
  });
57520
58116
  let resolvedFid = fid;
57521
58117
  try {
57522
- await fs57.access(featureDir);
58118
+ await fs58.access(featureDir);
57523
58119
  } catch {
57524
58120
  const latest = await findLatestSpecDir();
57525
58121
  if (latest) resolvedFid = latest;
@@ -57535,7 +58131,7 @@ async function generatePlanViaSpeckit(cfg, state, objective, opts = {}) {
57535
58131
  const planPath = path58.join(resolvedDir, "plan.md");
57536
58132
  let body;
57537
58133
  try {
57538
- body = await fs57.readFile(planPath, "utf8");
58134
+ body = await fs58.readFile(planPath, "utf8");
57539
58135
  } catch (err) {
57540
58136
  throw new Error(
57541
58137
  `speckit-plan finished but plan.md was not produced at ${planPath}: ${err.message}. The skill may have written elsewhere or failed silently.`
@@ -57549,7 +58145,7 @@ async function runSpeckitPhase(cfg, state, phase, fid, opts = {}) {
57549
58145
  const specPath = path58.join(featureDir, "spec.md");
57550
58146
  let specMtimeBefore = 0;
57551
58147
  try {
57552
- const stat4 = await fs57.stat(specPath);
58148
+ const stat4 = await fs58.stat(specPath);
57553
58149
  specMtimeBefore = stat4.mtimeMs;
57554
58150
  } catch {
57555
58151
  }
@@ -57564,7 +58160,7 @@ async function runSpeckitPhase(cfg, state, phase, fid, opts = {}) {
57564
58160
  let body2 = "";
57565
58161
  let produced2 = false;
57566
58162
  try {
57567
- body2 = await fs57.readFile(savedAt, "utf8");
58163
+ body2 = await fs58.readFile(savedAt, "utf8");
57568
58164
  produced2 = body2.trim().length > 0;
57569
58165
  } catch {
57570
58166
  }
@@ -57573,8 +58169,8 @@ async function runSpeckitPhase(cfg, state, phase, fid, opts = {}) {
57573
58169
  let body = "";
57574
58170
  let produced = false;
57575
58171
  try {
57576
- body = await fs57.readFile(specPath, "utf8");
57577
- const stat4 = await fs57.stat(specPath);
58172
+ body = await fs58.readFile(specPath, "utf8");
58173
+ const stat4 = await fs58.stat(specPath);
57578
58174
  const hasClarifications = /^## Clarifications/m.test(body);
57579
58175
  const mtimeMoved = stat4.mtimeMs > specMtimeBefore;
57580
58176
  produced = hasClarifications || mtimeMoved;
@@ -57603,7 +58199,7 @@ async function extractClarifyQuestions(cfg, fid, opts = {}) {
57603
58199
  const specPath = path58.join(baseDir, SPECS_DIR, fid, "spec.md");
57604
58200
  let spec;
57605
58201
  try {
57606
- spec = await fs57.readFile(specPath, "utf8");
58202
+ spec = await fs58.readFile(specPath, "utf8");
57607
58203
  } catch (err) {
57608
58204
  throw new Error(
57609
58205
  `Cannot extract questions: spec.md missing at ${specPath}: ${err.message}`
@@ -57655,7 +58251,7 @@ async function applyClarifications(cfg, fid, pairs, opts = {}) {
57655
58251
  }
57656
58252
  let spec;
57657
58253
  try {
57658
- spec = await fs57.readFile(specPath, "utf8");
58254
+ spec = await fs58.readFile(specPath, "utf8");
57659
58255
  } catch (err) {
57660
58256
  throw new Error(
57661
58257
  `Cannot apply clarifications: spec.md missing at ${specPath}: ${err.message}`
@@ -57694,7 +58290,7 @@ Output the updated spec.md body now.`;
57694
58290
  { tier: opts.tier, model: opts.model, signal: opts.signal }
57695
58291
  );
57696
58292
  const cleaned = stripWrappingFences(updated.trim());
57697
- await fs57.writeFile(specPath, cleaned + "\n");
58293
+ await fs58.writeFile(specPath, cleaned + "\n");
57698
58294
  return { specPath, updated: true };
57699
58295
  }
57700
58296
  function stripWrappingFences(s2) {
@@ -57704,7 +58300,7 @@ function stripWrappingFences(s2) {
57704
58300
 
57705
58301
  // src/session-summary.ts
57706
58302
  init_dist2();
57707
- import { promises as fs58 } from "node:fs";
58303
+ import { promises as fs59 } from "node:fs";
57708
58304
  import path59 from "node:path";
57709
58305
  var SYSTEM_PROMPT2 = `You are a session summarizer for an interactive AI coding REPL. Read the chat session below and extract DURABLE signal \u2014 facts and decisions that should persist across sessions, not transient details.
57710
58306
 
@@ -57814,7 +58410,7 @@ async function applySessionSummary(cfg, projectName, summary) {
57814
58410
  const updated = [];
57815
58411
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
57816
58412
  const projectDir2 = path59.join(cfg.flow.memoryDir, projectName);
57817
- await fs58.mkdir(projectDir2, { recursive: true });
58413
+ await fs59.mkdir(projectDir2, { recursive: true });
57818
58414
  if (summary.context.trim() !== "") {
57819
58415
  const file = path59.join(projectDir2, "context.md");
57820
58416
  await appendBlock(file, `## Session ${date}`, summary.context.trim());
@@ -57839,7 +58435,7 @@ async function applySessionSummary(cfg, projectName, summary) {
57839
58435
  updated.push(file);
57840
58436
  }
57841
58437
  if (summary.soulUpdates.length > 0 && cfg.flow.soulPath) {
57842
- await fs58.mkdir(path59.dirname(cfg.flow.soulPath), { recursive: true });
58438
+ await fs59.mkdir(path59.dirname(cfg.flow.soulPath), { recursive: true });
57843
58439
  await appendBlock(
57844
58440
  cfg.flow.soulPath,
57845
58441
  `## ${projectName} \u2014 ${date}`,
@@ -57852,7 +58448,7 @@ async function applySessionSummary(cfg, projectName, summary) {
57852
58448
  async function appendBlock(file, header, body) {
57853
58449
  let existing = "";
57854
58450
  try {
57855
- existing = await fs58.readFile(file, "utf8");
58451
+ existing = await fs59.readFile(file, "utf8");
57856
58452
  } catch {
57857
58453
  }
57858
58454
  const sep2 = existing.endsWith("\n\n") || existing === "" ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
@@ -57860,27 +58456,27 @@ async function appendBlock(file, header, body) {
57860
58456
 
57861
58457
  ${body}
57862
58458
  `;
57863
- await fs58.writeFile(file, existing + block);
58459
+ await fs59.writeFile(file, existing + block);
57864
58460
  }
57865
58461
  async function readSafe(file) {
57866
58462
  try {
57867
- return await fs58.readFile(file, "utf8");
58463
+ return await fs59.readFile(file, "utf8");
57868
58464
  } catch {
57869
58465
  return "";
57870
58466
  }
57871
58467
  }
57872
58468
 
57873
58469
  // src/repl/init-modals.tsx
57874
- import { Box as Box5, Text as Text5 } from "ink";
57875
- import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
58470
+ import { Box as Box6, Text as Text6 } from "ink";
58471
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
57876
58472
  function ProfilePickerModal({
57877
58473
  choices,
57878
58474
  selected,
57879
58475
  status: status2,
57880
58476
  width
57881
58477
  }) {
57882
- return /* @__PURE__ */ jsxs5(
57883
- Box5,
58478
+ return /* @__PURE__ */ jsxs6(
58479
+ Box6,
57884
58480
  {
57885
58481
  flexDirection: "column",
57886
58482
  borderStyle: "double",
@@ -57889,17 +58485,17 @@ function ProfilePickerModal({
57889
58485
  paddingY: 1,
57890
58486
  width,
57891
58487
  children: [
57892
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: ACCENT, children: "\u25C6 Pick a profile for this project" }),
57893
- /* @__PURE__ */ jsx5(Text5, { color: MUTED, children: "Each profile shapes the standards, naming, and skills the agent applies \u2014 pick the closest match to your domain." }),
57894
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
58488
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: ACCENT, children: "\u25C6 Pick a profile for this project" }),
58489
+ /* @__PURE__ */ jsx6(Text6, { color: MUTED, children: "Each profile shapes the standards, naming, and skills the agent applies \u2014 pick the closest match to your domain." }),
58490
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
57895
58491
  choices.map((c2, i2) => {
57896
58492
  const active = i2 === selected;
57897
58493
  const tags = [];
57898
58494
  if (c2.detected) tags.push("detected");
57899
58495
  if (c2.recommended) tags.push("Gemini recommends");
57900
- return /* @__PURE__ */ jsxs5(Box5, { children: [
57901
- /* @__PURE__ */ jsxs5(
57902
- Text5,
58496
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
58497
+ /* @__PURE__ */ jsxs6(
58498
+ Text6,
57903
58499
  {
57904
58500
  color: active ? SELECTED_FG : TEXT,
57905
58501
  backgroundColor: active ? SELECTED_BG : void 0,
@@ -57909,30 +58505,30 @@ function ProfilePickerModal({
57909
58505
  ]
57910
58506
  }
57911
58507
  ),
57912
- /* @__PURE__ */ jsxs5(Text5, { color: TEXT_DIM, children: [
58508
+ /* @__PURE__ */ jsxs6(Text6, { color: TEXT_DIM, children: [
57913
58509
  " ",
57914
58510
  c2.description
57915
58511
  ] }),
57916
- tags.length > 0 && /* @__PURE__ */ jsxs5(Text5, { color: SUCCESS, children: [
58512
+ tags.length > 0 && /* @__PURE__ */ jsxs6(Text6, { color: SUCCESS, children: [
57917
58513
  " \u2190 ",
57918
58514
  tags.join(", ")
57919
58515
  ] })
57920
58516
  ] }, c2.name);
57921
58517
  }),
57922
- status2 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
57923
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
57924
- /* @__PURE__ */ jsx5(Text5, { color: WARNING, children: status2 })
58518
+ status2 && /* @__PURE__ */ jsxs6(Fragment4, { children: [
58519
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
58520
+ /* @__PURE__ */ jsx6(Text6, { color: WARNING, children: status2 })
57925
58521
  ] }),
57926
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
57927
- /* @__PURE__ */ jsxs5(Box5, { children: [
57928
- /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "\u2191/\u2193" }),
57929
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " select " }),
57930
- /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "Enter" }),
57931
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " confirm " }),
57932
- /* @__PURE__ */ jsx5(Text5, { color: ACCENT, children: "r" }),
57933
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " ask Gemini " }),
57934
- /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "Esc" }),
57935
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel" })
58522
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
58523
+ /* @__PURE__ */ jsxs6(Box6, { children: [
58524
+ /* @__PURE__ */ jsx6(Text6, { color: ACCENT, children: "\u2191/\u2193" }),
58525
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " select " }),
58526
+ /* @__PURE__ */ jsx6(Text6, { color: SUCCESS, children: "Enter" }),
58527
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " confirm " }),
58528
+ /* @__PURE__ */ jsx6(Text6, { color: ACCENT, children: "r" }),
58529
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " ask Gemini " }),
58530
+ /* @__PURE__ */ jsx6(Text6, { color: ERROR2, children: "Esc" }),
58531
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " cancel" })
57936
58532
  ] })
57937
58533
  ]
57938
58534
  }
@@ -57942,8 +58538,8 @@ function CustomAgentModal({
57942
58538
  profileName,
57943
58539
  width
57944
58540
  }) {
57945
- return /* @__PURE__ */ jsxs5(
57946
- Box5,
58541
+ return /* @__PURE__ */ jsxs6(
58542
+ Box6,
57947
58543
  {
57948
58544
  flexDirection: "column",
57949
58545
  borderStyle: "double",
@@ -57952,23 +58548,23 @@ function CustomAgentModal({
57952
58548
  paddingY: 1,
57953
58549
  width,
57954
58550
  children: [
57955
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: ACCENT, children: "\u25C6 Generate a custom agent for this project?" }),
57956
- /* @__PURE__ */ jsxs5(Text5, { color: MUTED, children: [
58551
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: ACCENT, children: "\u25C6 Generate a custom agent for this project?" }),
58552
+ /* @__PURE__ */ jsxs6(Text6, { color: MUTED, children: [
57957
58553
  "profile: ",
57958
58554
  profileName
57959
58555
  ] }),
57960
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
57961
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: "Gemini will scan the project and draft a SKILL.md tailored to the code you have here \u2014 naming conventions in use, top-level modules, suspected test framework. The skill lands at" }),
57962
- /* @__PURE__ */ jsx5(Text5, { color: TEXT_DIM, children: ".gemini/skills/<project>-agent/SKILL.md" }),
57963
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: "and auto-loads on the next Gemini-CLI invocation. Adds 30-60s to the init." }),
57964
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
57965
- /* @__PURE__ */ jsxs5(Box5, { children: [
57966
- /* @__PURE__ */ jsx5(Text5, { color: SUCCESS, children: "[Y]" }),
57967
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " yes, draft an agent " }),
57968
- /* @__PURE__ */ jsx5(Text5, { color: WARNING, children: "[N]" }),
57969
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " skip " }),
57970
- /* @__PURE__ */ jsx5(Text5, { color: ERROR2, children: "[Esc]" }),
57971
- /* @__PURE__ */ jsx5(Text5, { color: TEXT, children: " cancel init" })
58556
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
58557
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: "Gemini will scan the project and draft a SKILL.md tailored to the code you have here \u2014 naming conventions in use, top-level modules, suspected test framework. The skill lands at" }),
58558
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT_DIM, children: ".gemini/skills/<project>-agent/SKILL.md" }),
58559
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: "and auto-loads on the next Gemini-CLI invocation. Adds 30-60s to the init." }),
58560
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
58561
+ /* @__PURE__ */ jsxs6(Box6, { children: [
58562
+ /* @__PURE__ */ jsx6(Text6, { color: SUCCESS, children: "[Y]" }),
58563
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " yes, draft an agent " }),
58564
+ /* @__PURE__ */ jsx6(Text6, { color: WARNING, children: "[N]" }),
58565
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " skip " }),
58566
+ /* @__PURE__ */ jsx6(Text6, { color: ERROR2, children: "[Esc]" }),
58567
+ /* @__PURE__ */ jsx6(Text6, { color: TEXT, children: " cancel init" })
57972
58568
  ] })
57973
58569
  ]
57974
58570
  }
@@ -57977,7 +58573,7 @@ function CustomAgentModal({
57977
58573
 
57978
58574
  // src/repl/profile-recommend.ts
57979
58575
  init_dist2();
57980
- import { promises as fs59 } from "node:fs";
58576
+ import { promises as fs60 } from "node:fs";
57981
58577
  import path60 from "node:path";
57982
58578
  var VALID_PROFILES = ["automotive", "embedded", "web", "generic"];
57983
58579
  var HIGH_SIGNAL_FILES2 = [
@@ -58020,7 +58616,7 @@ async function buildDigest(cwd) {
58020
58616
  const out = [];
58021
58617
  let entries = [];
58022
58618
  try {
58023
- entries = await fs59.readdir(cwd, { withFileTypes: true });
58619
+ entries = await fs60.readdir(cwd, { withFileTypes: true });
58024
58620
  } catch {
58025
58621
  }
58026
58622
  const visible = entries.filter((e2) => !e2.name.startsWith(".") || e2.name === ".gitignore").slice(0, ENTRY_CAP);
@@ -58032,9 +58628,9 @@ async function buildDigest(cwd) {
58032
58628
  for (const file of HIGH_SIGNAL_FILES2) {
58033
58629
  const p2 = path60.join(cwd, file);
58034
58630
  try {
58035
- const stat4 = await fs59.stat(p2);
58631
+ const stat4 = await fs60.stat(p2);
58036
58632
  if (!stat4.isFile()) continue;
58037
- const buf = await fs59.readFile(p2, "utf8");
58633
+ const buf = await fs60.readFile(p2, "utf8");
58038
58634
  const trimmed = buf.slice(0, FILE_BYTE_CAP2);
58039
58635
  out.push(`## ${file}`);
58040
58636
  out.push("```");
@@ -58104,15 +58700,15 @@ function connectPoolToBus(pool) {
58104
58700
  import path62 from "node:path";
58105
58701
 
58106
58702
  // src/repl/reasoning.tsx
58107
- import { Box as Box6, Text as Text6 } from "ink";
58108
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
58703
+ import { Box as Box7, Text as Text7 } from "ink";
58704
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
58109
58705
  function ReasoningCard({
58110
58706
  lines,
58111
58707
  expanded
58112
58708
  }) {
58113
58709
  if (lines.length === 0) return null;
58114
- return /* @__PURE__ */ jsxs6(
58115
- Box6,
58710
+ return /* @__PURE__ */ jsxs7(
58711
+ Box7,
58116
58712
  {
58117
58713
  flexDirection: "column",
58118
58714
  borderStyle: "round",
@@ -58120,12 +58716,12 @@ function ReasoningCard({
58120
58716
  paddingX: 1,
58121
58717
  marginTop: 1,
58122
58718
  children: [
58123
- /* @__PURE__ */ jsxs6(Box6, { children: [
58124
- /* @__PURE__ */ jsxs6(Text6, { color: ACCENT, bold: true, children: [
58719
+ /* @__PURE__ */ jsxs7(Box7, { children: [
58720
+ /* @__PURE__ */ jsxs7(Text7, { color: ACCENT, bold: true, children: [
58125
58721
  expanded ? "\u25BC" : "\u25B6",
58126
58722
  " Thinking"
58127
58723
  ] }),
58128
- /* @__PURE__ */ jsxs6(Text6, { color: MUTED, children: [
58724
+ /* @__PURE__ */ jsxs7(Text7, { color: MUTED, children: [
58129
58725
  " ",
58130
58726
  "(",
58131
58727
  lines.length,
@@ -58137,18 +58733,18 @@ function ReasoningCard({
58137
58733
  ")"
58138
58734
  ] })
58139
58735
  ] }),
58140
- expanded && lines.slice(-12).map((ln, i2) => /* @__PURE__ */ jsx6(Text6, { color: TEXT_DIM, wrap: "truncate-end", children: ln }, i2)),
58141
- !expanded && lines.length > 0 && /* @__PURE__ */ jsx6(Text6, { color: TEXT_DIM, wrap: "truncate-end", children: lines[lines.length - 1] ?? "" })
58736
+ expanded && lines.slice(-12).map((ln, i2) => /* @__PURE__ */ jsx7(Text7, { color: TEXT_DIM, wrap: "truncate-end", children: ln }, i2)),
58737
+ !expanded && lines.length > 0 && /* @__PURE__ */ jsx7(Text7, { color: TEXT_DIM, wrap: "truncate-end", children: lines[lines.length - 1] ?? "" })
58142
58738
  ]
58143
58739
  }
58144
58740
  );
58145
58741
  }
58146
58742
 
58147
58743
  // src/repl/picker.tsx
58148
- import { Box as Box7, Text as Text7 } from "ink";
58149
- import { promises as fs60 } from "node:fs";
58744
+ import { Box as Box8, Text as Text8 } from "ink";
58745
+ import { promises as fs61 } from "node:fs";
58150
58746
  import path61 from "node:path";
58151
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
58747
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
58152
58748
  var MAX_VISIBLE = 12;
58153
58749
  function Picker({
58154
58750
  kind: kind2,
@@ -58162,35 +58758,35 @@ function Picker({
58162
58758
  const slice = items.slice(start, start + MAX_VISIBLE);
58163
58759
  const labelW = Math.max(...items.map((i2) => i2.label.length));
58164
58760
  const descW = Math.max(20, width - labelW - 6);
58165
- return /* @__PURE__ */ jsxs7(
58166
- Box7,
58761
+ return /* @__PURE__ */ jsxs8(
58762
+ Box8,
58167
58763
  {
58168
58764
  flexDirection: "column",
58169
58765
  borderStyle: "round",
58170
58766
  borderColor: BORDER_DIM,
58171
58767
  paddingX: 1,
58172
58768
  children: [
58173
- /* @__PURE__ */ jsxs7(Box7, { children: [
58174
- /* @__PURE__ */ jsxs7(Text7, { color: MUTED, children: [
58769
+ /* @__PURE__ */ jsxs8(Box8, { children: [
58770
+ /* @__PURE__ */ jsxs8(Text8, { color: MUTED, children: [
58175
58771
  kindLabel(kind2),
58176
- fragment && /* @__PURE__ */ jsxs7(Text7, { color: ACCENT, children: [
58772
+ fragment && /* @__PURE__ */ jsxs8(Text8, { color: ACCENT, children: [
58177
58773
  " ",
58178
58774
  fragment
58179
58775
  ] }),
58180
58776
  " "
58181
58777
  ] }),
58182
- /* @__PURE__ */ jsx7(Text7, { color: MUTED, children: "\u2191/\u2193 select \xB7 Tab complete \xB7 Esc cancel" })
58778
+ /* @__PURE__ */ jsx8(Text8, { color: MUTED, children: "\u2191/\u2193 select \xB7 Tab complete \xB7 Esc cancel" })
58183
58779
  ] }),
58184
58780
  slice.map((item, i2) => {
58185
58781
  const idx = start + i2;
58186
58782
  const isSel = idx === selected;
58187
58783
  const lbl = item.label.padEnd(labelW + 2);
58188
- return /* @__PURE__ */ jsxs7(Box7, { children: [
58189
- isSel ? /* @__PURE__ */ jsx7(Text7, { color: SELECTED_FG, backgroundColor: SELECTED_BG, children: " \u203A " + lbl }) : /* @__PURE__ */ jsx7(Text7, { color: TEXT, children: " " + lbl }),
58190
- item.description && /* @__PURE__ */ jsx7(Text7, { color: isSel ? SELECTED_FG : TEXT_DIM, children: truncate2(item.description, descW) })
58784
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
58785
+ isSel ? /* @__PURE__ */ jsx8(Text8, { color: SELECTED_FG, backgroundColor: SELECTED_BG, children: " \u203A " + lbl }) : /* @__PURE__ */ jsx8(Text8, { color: TEXT, children: " " + lbl }),
58786
+ item.description && /* @__PURE__ */ jsx8(Text8, { color: isSel ? SELECTED_FG : TEXT_DIM, children: truncate3(item.description, descW) })
58191
58787
  ] }, idx);
58192
58788
  }),
58193
- items.length > MAX_VISIBLE && /* @__PURE__ */ jsxs7(Text7, { color: MUTED, children: [
58789
+ items.length > MAX_VISIBLE && /* @__PURE__ */ jsxs8(Text8, { color: MUTED, children: [
58194
58790
  " ",
58195
58791
  selected + 1,
58196
58792
  "/",
@@ -58212,7 +58808,7 @@ function kindLabel(k2) {
58212
58808
  return "History";
58213
58809
  }
58214
58810
  }
58215
- function truncate2(s2, w2) {
58811
+ function truncate3(s2, w2) {
58216
58812
  if (s2.length <= w2) return s2;
58217
58813
  return s2.slice(0, Math.max(0, w2 - 1)) + "\u2026";
58218
58814
  }
@@ -58237,7 +58833,7 @@ async function listAtPath(prefix) {
58237
58833
  const target = path61.resolve(cwd, dir || ".");
58238
58834
  let entries;
58239
58835
  try {
58240
- entries = await fs60.readdir(target, { withFileTypes: true });
58836
+ entries = await fs61.readdir(target, { withFileTypes: true });
58241
58837
  } catch {
58242
58838
  return [];
58243
58839
  }
@@ -58352,20 +58948,72 @@ var SUBCOMMAND_HINTS = {
58352
58948
  };
58353
58949
 
58354
58950
  // src/repl/App.tsx
58355
- import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
58356
- var RAIL_MIN_WIDTH = 100;
58357
- var RIGHT_RAIL_WIDE_MIN = 140;
58358
- var RIGHT_RAIL_NARROW_MIN = 120;
58359
- var STRIP_HIDE_BELOW = 80;
58360
- function pickRightRailMode(cols) {
58361
- if (cols >= RIGHT_RAIL_WIDE_MIN) return "wide";
58362
- if (cols >= RIGHT_RAIL_NARROW_MIN) return "narrow";
58363
- if (cols >= STRIP_HIDE_BELOW) return "strip";
58364
- return "hidden";
58951
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
58952
+ var ANSI_RE = /\x1b\[[0-9;]*m/g;
58953
+ function visibleLength(s2) {
58954
+ return s2.replace(ANSI_RE, "").length;
58365
58955
  }
58366
- function rightRailWidth(mode) {
58367
- return mode === "wide" ? 32 : mode === "narrow" ? 28 : 0;
58956
+ function wordWrap(text, width) {
58957
+ if (width <= 0) return text.split("\n");
58958
+ const out = [];
58959
+ for (const rawLine of text.split("\n")) {
58960
+ if (visibleLength(rawLine) <= width) {
58961
+ out.push(rawLine);
58962
+ continue;
58963
+ }
58964
+ const tokens = Array.from(
58965
+ rawLine.matchAll(/\x1b\[[0-9;]*m|\s+|\S+/g)
58966
+ ).map((m2) => m2[0]);
58967
+ let cur = "";
58968
+ let curW = 0;
58969
+ for (const tok of tokens) {
58970
+ if (tok.startsWith("\x1B[")) {
58971
+ cur += tok;
58972
+ continue;
58973
+ }
58974
+ const isSpace = /^\s+$/.test(tok);
58975
+ const tokW = tok.length;
58976
+ if (curW === 0 && isSpace) continue;
58977
+ if (curW + tokW <= width) {
58978
+ cur += tok;
58979
+ curW += tokW;
58980
+ continue;
58981
+ }
58982
+ if (isSpace) {
58983
+ out.push(cur);
58984
+ cur = "";
58985
+ curW = 0;
58986
+ continue;
58987
+ }
58988
+ if (tokW > width) {
58989
+ if (cur) {
58990
+ out.push(cur);
58991
+ cur = "";
58992
+ curW = 0;
58993
+ }
58994
+ let chunk = tok;
58995
+ while (chunk.length > width) {
58996
+ out.push(chunk.slice(0, width));
58997
+ chunk = chunk.slice(width);
58998
+ }
58999
+ cur = chunk;
59000
+ curW = chunk.length;
59001
+ continue;
59002
+ }
59003
+ out.push(cur);
59004
+ cur = tok;
59005
+ curW = tokW;
59006
+ }
59007
+ if (cur) out.push(cur);
59008
+ }
59009
+ return out;
59010
+ }
59011
+ function measureEntryRows(entry, width) {
59012
+ const text = entry.kind === "assistant" ? renderMarkdown(entry.text) : entry.kind === "error" ? `\u26A0 ${entry.text}` : entry.text;
59013
+ const lines = wordWrap(text, width).length;
59014
+ return lines + 3;
58368
59015
  }
59016
+ var RAIL_MIN_WIDTH = 100;
58369
59017
  function App({
58370
59018
  cfg,
58371
59019
  initialProject,
@@ -58374,8 +59022,8 @@ function App({
58374
59022
  }) {
58375
59023
  const app = useApp();
58376
59024
  const { stdout } = useStdout();
58377
- const [registry] = useState3(() => new CommandRegistry());
58378
- const [replState] = useState3(() => {
59025
+ const [registry] = useState6(() => new CommandRegistry());
59026
+ const [replState] = useState6(() => {
58379
59027
  const s2 = newReplState();
58380
59028
  s2.activeProject = initialProject;
58381
59029
  if (resumeFrom) {
@@ -58384,40 +59032,52 @@ function App({
58384
59032
  return s2;
58385
59033
  });
58386
59034
  const sessionRef = useRef(null);
58387
- const [input, setInput] = useState3("");
58388
- const [busy, setBusy] = useState3(false);
58389
- const [busyLabel, setBusyLabel] = useState3("Thinking");
58390
- const [busyStart, setBusyStart] = useState3(null);
58391
- const [now, setNow] = useState3(Date.now());
59035
+ const [input, setInput] = useState6("");
59036
+ const [busy, setBusy] = useState6(false);
59037
+ const [busyLabel, setBusyLabel] = useState6("Thinking");
59038
+ const [busyStart, setBusyStart] = useState6(null);
59039
+ const [now, setNow] = useState6(Date.now());
58392
59040
  const inflight = useRef(null);
58393
59041
  const armedExit = useRef(false);
58394
- const [entries, setEntries] = useState3(() => [
59042
+ const [entries, setEntries] = useState6(() => [
58395
59043
  {
58396
59044
  id: 0,
58397
59045
  kind: "system",
58398
- text: "agenIT \u2014 profile-driven AI dev co-pilot.\nType a question, or use /help to list commands. /exit to quit.\n\u2191/\u2193 recall \xB7 Tab complete \xB7 Ctrl-R search history \xB7 Ctrl-T fold thinking \xB7 Ctrl-B toggle rail \xB7 Ctrl-J expand job"
59046
+ text: "agenIT \u2014 profile-driven AI dev co-pilot.\nType a question, or use /help to list commands. /exit to quit.\n\u2191/\u2193 recall \xB7 Tab complete \xB7 Ctrl-R search history \xB7 Ctrl-T fold thinking \xB7 Ctrl-B toggle rail \xB7 Ctrl-] widen rail \xB7 Ctrl-U/Ctrl-D (or PgUp/PgDn) scroll backlog \xB7 Ctrl-G expand/minimize job \xB7 Ctrl-J cycle jobs"
58399
59047
  }
58400
59048
  ]);
58401
- const [reasoning, setReasoning] = useState3([]);
58402
- const [reasoningOpen, setReasoningOpen] = useState3(false);
58403
- const [railVisible, setRailVisible] = useState3(true);
58404
- const [expandedJobIndex, setExpandedJobIndex] = useState3(null);
58405
- const [goalGate, setGoalGate] = useState3(null);
58406
- const [planLoading, setPlanLoading] = useState3(null);
58407
- const [planApprove, setPlanApprove] = useState3(null);
58408
- const [yesNoStep, setYesNoStep] = useState3(null);
58409
- const [clarifyQA, setClarifyQA] = useState3(null);
58410
- const [modelPicker, setModelPicker] = useState3(null);
58411
- const [profilePicker, setProfilePicker] = useState3(null);
58412
- const [customAgent, setCustomAgent] = useState3(null);
58413
- const [tuiState, setTuiState] = useState3(tuiBus.get());
58414
- const [picker, setPicker] = useState3(null);
59049
+ const [reasoning, setReasoning] = useState6([]);
59050
+ const [reasoningUpdatedAt, setReasoningUpdatedAt] = useState6(0);
59051
+ const [reasoningOpen, setReasoningOpen] = useState6(false);
59052
+ const [railVisible, setRailVisible] = useState6(true);
59053
+ const [railExpanded, setRailExpanded] = useState6(false);
59054
+ const [chatScrollback, setChatScrollback] = useState6(0);
59055
+ const [expandedJobIndex, setExpandedJobIndex] = useState6(null);
59056
+ const [goalGate, setGoalGate] = useState6(null);
59057
+ const [planLoading, setPlanLoading] = useState6(null);
59058
+ const [planApprove, setPlanApprove] = useState6(null);
59059
+ const [planApproveScroll, setPlanApproveScroll] = useState6(0);
59060
+ const planApproveLines = useMemo(
59061
+ () => planApprove ? renderPlanLines(planApprove.plan) : [],
59062
+ [planApprove?.plan]
59063
+ );
59064
+ useEffect6(() => {
59065
+ setPlanApproveScroll(0);
59066
+ }, [planApprove?.goalId]);
59067
+ const [yesNoStep, setYesNoStep] = useState6(null);
59068
+ const [clarifyQA, setClarifyQA] = useState6(null);
59069
+ const [modelPicker, setModelPicker] = useState6(null);
59070
+ const [profilePicker, setProfilePicker] = useState6(null);
59071
+ const [customAgent, setCustomAgent] = useState6(null);
59072
+ const [tuiState, setTuiState] = useState6(tuiBus.get());
59073
+ const [picker, setPicker] = useState6(null);
58415
59074
  const nextId = useRef(1);
58416
- const [cols, setCols] = useState3(stdout?.columns ?? 100);
58417
- const [rows, setRows] = useState3(stdout?.rows ?? 30);
58418
- useEffect3(() => {
59075
+ const [cols, setCols] = useState6(stdout?.columns ?? 100);
59076
+ const [rows, setRows] = useState6(stdout?.rows ?? 30);
59077
+ useEffect6(() => {
58419
59078
  if (!stdout) return;
58420
59079
  const onResize = () => {
59080
+ if (stdout.isTTY) stdout.write("\x1B[2J\x1B[H");
58421
59081
  setCols(stdout.columns ?? 100);
58422
59082
  setRows(stdout.rows ?? 30);
58423
59083
  };
@@ -58426,14 +59086,29 @@ function App({
58426
59086
  stdout.off("resize", onResize);
58427
59087
  };
58428
59088
  }, [stdout]);
59089
+ useEffect6(() => {
59090
+ setChatScrollback(0);
59091
+ }, [entries.length]);
58429
59092
  const railEnabled = railVisible && cols >= RAIL_MIN_WIDTH;
58430
59093
  const rightRailMode = pickRightRailMode(cols);
58431
- const rightRailW = rightRailWidth(rightRailMode);
59094
+ const rightRailW = rightRailColumns(cols, railExpanded);
59095
+ const railVerbosity = railExpanded ? "full" : "compact";
59096
+ const chatInnerWidth = Math.max(
59097
+ 20,
59098
+ cols - (railEnabled ? 28 : 2) - (rightRailMode === "rail" ? rightRailW : 0) - 4
59099
+ );
59100
+ const soulDigest = useSoulDigest(cfg.flow.soulPath);
59101
+ const codeDigestStatus = useCodeDigestStatus(
59102
+ cfg.flow.codedigestDir,
59103
+ replState.activeProject ?? null
59104
+ );
59105
+ const pinnedAtPaths = useAtPathHistory();
58432
59106
  const rightRailH = Math.max(8, Math.min(Math.floor(rows * 0.7), rows - 6));
58433
- useEffect3(() => {
59107
+ useEffect6(() => {
58434
59108
  process.env.FLOW_TUI_ACTIVE = "1";
58435
59109
  setReasoningSink((line) => {
58436
59110
  setReasoning((r2) => [...r2.slice(-29), line]);
59111
+ setReasoningUpdatedAt(Date.now());
58437
59112
  });
58438
59113
  const unsub = tuiBus.subscribe((s2) => setTuiState({ ...s2 }));
58439
59114
  const unsubPool = connectPoolToBus(getLoopWorkerPool());
@@ -58852,12 +59527,12 @@ function App({
58852
59527
  app.exit();
58853
59528
  })();
58854
59529
  };
58855
- useEffect3(() => {
59530
+ useEffect6(() => {
58856
59531
  if (expandedJobIndex !== null && expandedJobIndex >= tuiState.backgroundJobs.length) {
58857
59532
  setExpandedJobIndex(null);
58858
59533
  }
58859
59534
  }, [tuiState.backgroundJobs.length, expandedJobIndex]);
58860
- useEffect3(() => {
59535
+ useEffect6(() => {
58861
59536
  if (!busy) return;
58862
59537
  const t2 = setInterval(() => setNow(Date.now()), 250);
58863
59538
  return () => clearInterval(t2);
@@ -58868,7 +59543,7 @@ function App({
58868
59543
  description: c2.description
58869
59544
  }));
58870
59545
  }, [registry]);
58871
- useEffect3(() => {
59546
+ useEffect6(() => {
58872
59547
  if (input.startsWith("/") && !input.includes(" ")) {
58873
59548
  const fragment = input.slice(1);
58874
59549
  const items = fuzzyFilter(slashSuggestions, fragment);
@@ -59124,6 +59799,24 @@ function App({
59124
59799
  setPlanApprove(null);
59125
59800
  return;
59126
59801
  }
59802
+ const viewport = planViewportLines(Math.max(12, rows - 4));
59803
+ const maxOffset = Math.max(0, planApproveLines.length - viewport);
59804
+ if (key.upArrow) {
59805
+ setPlanApproveScroll((o2) => Math.max(0, o2 - 1));
59806
+ return;
59807
+ }
59808
+ if (key.downArrow) {
59809
+ setPlanApproveScroll((o2) => Math.min(maxOffset, o2 + 1));
59810
+ return;
59811
+ }
59812
+ if (key.pageUp) {
59813
+ setPlanApproveScroll((o2) => Math.max(0, o2 - viewport));
59814
+ return;
59815
+ }
59816
+ if (key.pageDown) {
59817
+ setPlanApproveScroll((o2) => Math.min(maxOffset, o2 + viewport));
59818
+ return;
59819
+ }
59127
59820
  return;
59128
59821
  }
59129
59822
  if (key.ctrl && ch === "c") {
@@ -59155,7 +59848,21 @@ function App({
59155
59848
  setRailVisible((v2) => !v2);
59156
59849
  return;
59157
59850
  }
59158
- if (key.ctrl && ch === "j") {
59851
+ if (key.pageUp || key.ctrl && ch === "u") {
59852
+ const maxOffset = Math.max(0, entries.length - 1);
59853
+ setChatScrollback((s2) => Math.min(maxOffset, s2 + 1));
59854
+ return;
59855
+ }
59856
+ if (key.pageDown || key.ctrl && ch === "d") {
59857
+ setChatScrollback((s2) => Math.max(0, s2 - 1));
59858
+ return;
59859
+ }
59860
+ if (key.ctrl && ch === "]") {
59861
+ if (rightRailMode === "rail") setRailExpanded((x2) => !x2);
59862
+ return;
59863
+ }
59864
+ const cycleJobKey = key.ctrl && ch === "j" || expandedJobIndex !== null && (key.tab || key.return);
59865
+ if (cycleJobKey) {
59159
59866
  const jobs = tuiState.backgroundJobs;
59160
59867
  if (jobs.length === 0) {
59161
59868
  addEntry("system", "(no background jobs to expand \u2014 start a /goal)");
@@ -59166,6 +59873,15 @@ function App({
59166
59873
  );
59167
59874
  return;
59168
59875
  }
59876
+ if (key.ctrl && ch === "g") {
59877
+ const jobs = tuiState.backgroundJobs;
59878
+ if (jobs.length === 0) {
59879
+ addEntry("system", "(no background jobs to expand \u2014 start a /goal)");
59880
+ return;
59881
+ }
59882
+ setExpandedJobIndex((i2) => i2 === null ? 0 : null);
59883
+ return;
59884
+ }
59169
59885
  if (key.ctrl && ch === "r") {
59170
59886
  setPicker({
59171
59887
  kind: "history",
@@ -59306,6 +60022,7 @@ function App({
59306
60022
  { role: "user", content: t2.user },
59307
60023
  { role: "assistant", content: t2.assistant }
59308
60024
  ]);
60025
+ recordAtPathsFromInput(line);
59309
60026
  const expanded = await expandAtPaths(line);
59310
60027
  const { text: textOnly, parts: imageParts } = await extractImageParts(expanded);
59311
60028
  const finalMessage = withModePrefix(textOnly, replState.mode);
@@ -59333,179 +60050,309 @@ function App({
59333
60050
  const showJobStrip = rightRailMode === "strip" && tuiState.backgroundJobs.length > 0;
59334
60051
  const expandedJob = expandedJobIndex !== null && expandedJobIndex < tuiState.backgroundJobs.length ? tuiState.backgroundJobs[expandedJobIndex] : null;
59335
60052
  const expandedProjectDir = replState.activeProject ? path62.join(cfg.flow.memoryDir, replState.activeProject) : null;
59336
- const main2 = /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", flexGrow: 1, children: [
59337
- tuiState.activity && /* @__PURE__ */ jsx8(ActivityStrip, { frame: tuiState.activity }),
59338
- /* @__PURE__ */ jsx8(ReasoningCard, { lines: reasoning, expanded: reasoningOpen }),
59339
- showJobStrip && /* @__PURE__ */ jsx8(JobStrip, { jobs: tuiState.backgroundJobs }),
59340
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: busy ? /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
59341
- /* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
59342
- " ",
59343
- busyLabel,
59344
- "\u2026",
59345
- busyStart && /* @__PURE__ */ jsxs8(Text8, { color: MUTED, children: [
59346
- " ",
59347
- ((now - busyStart) / 1e3).toFixed(1),
59348
- "s"
59349
- ] })
59350
- ] }) : /* @__PURE__ */ jsxs8(Box8, { children: [
59351
- /* @__PURE__ */ jsx8(Text8, { color: ACCENT, children: "\u203A " }),
59352
- /* @__PURE__ */ jsx8(
59353
- TextInput2,
59354
- {
59355
- value: input,
59356
- onChange: setInput,
59357
- onSubmit: (value) => {
59358
- void handleSubmit(value);
59359
- },
59360
- placeholder: "Ask anything, or /help for commands"
59361
- }
59362
- )
59363
- ] }) }),
59364
- picker && /* @__PURE__ */ jsx8(
59365
- Picker,
60053
+ const totalEntries = entries.length;
60054
+ const footerReserve = 10 + (tuiState.activity ? 2 : 0) + (showJobStrip ? 3 : 0) + (busy ? 1 : 0) + (reasoningOpen && reasoning.length > 0 ? Math.min(8, reasoning.length) : 0) + (picker ? 6 : 0);
60055
+ const chatRowBudget = Math.max(8, rows - footerReserve);
60056
+ const anchorIndex = Math.max(
60057
+ 0,
60058
+ entries.length - 1 - Math.min(chatScrollback, Math.max(0, entries.length - 1))
60059
+ );
60060
+ const visibleEntries = [];
60061
+ let usedRows = 0;
60062
+ for (let i2 = anchorIndex; i2 >= 0; i2--) {
60063
+ const entry = entries[i2];
60064
+ if (!entry) continue;
60065
+ const entryRows = measureEntryRows(entry, chatInnerWidth) + 1;
60066
+ if (usedRows + entryRows > chatRowBudget && visibleEntries.length > 0) {
60067
+ break;
60068
+ }
60069
+ visibleEntries.unshift(entry);
60070
+ usedRows += entryRows;
60071
+ if (usedRows >= chatRowBudget) break;
60072
+ }
60073
+ const hiddenAbove = visibleEntries.length > 0 ? entries.findIndex((e2) => e2 === visibleEntries[0]) : 0;
60074
+ const hiddenBelow = totalEntries - anchorIndex - 1;
60075
+ const hiddenCount = hiddenAbove;
60076
+ const main2 = /* @__PURE__ */ jsxs9(
60077
+ Box9,
60078
+ {
60079
+ flexDirection: "column",
60080
+ flexGrow: 1,
60081
+ minHeight: 0,
60082
+ justifyContent: "space-between",
60083
+ children: [
60084
+ /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", flexGrow: 1, minHeight: 0, overflow: "hidden", children: [
60085
+ hiddenCount > 0 && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { color: MUTED, children: [
60086
+ "\u2191 ",
60087
+ hiddenCount,
60088
+ " earlier message",
60089
+ hiddenCount === 1 ? "" : "s",
60090
+ " above",
60091
+ chatScrollback > 0 ? " \xB7 Ctrl-U older \xB7 Ctrl-D newer" : " \xB7 Ctrl-U to scroll"
60092
+ ] }) }),
60093
+ visibleEntries.map((entry) => /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx9(EntryView, { entry, width: chatInnerWidth }) }, entry.id)),
60094
+ hiddenBelow > 0 && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { color: MUTED, children: [
60095
+ "\u2193 ",
60096
+ hiddenBelow,
60097
+ " newer message",
60098
+ hiddenBelow === 1 ? "" : "s",
60099
+ " below \xB7 Ctrl-D to catch up"
60100
+ ] }) })
60101
+ ] }),
60102
+ /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", flexShrink: 0, children: [
60103
+ tuiState.activity && /* @__PURE__ */ jsx9(ActivityStrip, { frame: tuiState.activity }),
60104
+ /* @__PURE__ */ jsx9(ReasoningCard, { lines: reasoning, expanded: reasoningOpen }),
60105
+ showJobStrip && /* @__PURE__ */ jsx9(JobStrip, { jobs: tuiState.backgroundJobs }),
60106
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: busy ? /* @__PURE__ */ jsxs9(Text9, { color: "yellow", children: [
60107
+ /* @__PURE__ */ jsx9(Spinner, { type: "dots" }),
60108
+ " ",
60109
+ busyLabel,
60110
+ "\u2026",
60111
+ busyStart && /* @__PURE__ */ jsxs9(Text9, { color: MUTED, children: [
60112
+ " ",
60113
+ ((now - busyStart) / 1e3).toFixed(1),
60114
+ "s"
60115
+ ] })
60116
+ ] }) : /* @__PURE__ */ jsxs9(Box9, { children: [
60117
+ /* @__PURE__ */ jsx9(Text9, { color: ACCENT, children: "\u203A " }),
60118
+ /* @__PURE__ */ jsx9(
60119
+ TextInput2,
60120
+ {
60121
+ value: input,
60122
+ onChange: setInput,
60123
+ onSubmit: (value) => {
60124
+ void handleSubmit(value);
60125
+ },
60126
+ placeholder: "Ask anything, or /help for commands"
60127
+ }
60128
+ )
60129
+ ] }) }),
60130
+ picker && /* @__PURE__ */ jsx9(
60131
+ Picker,
60132
+ {
60133
+ ...picker,
60134
+ width: cols - (railEnabled ? 28 : 2) - rightRailW
60135
+ }
60136
+ )
60137
+ ] })
60138
+ ]
60139
+ }
60140
+ );
60141
+ return /* @__PURE__ */ jsx9(Fragment5, { children: /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", height: rows, children: [
60142
+ /* @__PURE__ */ jsx9(
60143
+ StatusBar,
59366
60144
  {
59367
- ...picker,
59368
- width: cols - (railEnabled ? 28 : 2) - rightRailW
60145
+ project: replState.activeProject,
60146
+ status: tuiState.status,
60147
+ mode: replState.mode ?? "build",
60148
+ approval: replState.approvalModeOverride ?? cfg.gemini.approvalMode,
60149
+ model: cfg.gemini.model ?? "auto",
60150
+ backend: cfg.backend.provider,
60151
+ width: cols
60152
+ }
60153
+ ),
60154
+ /* @__PURE__ */ jsxs9(
60155
+ Box9,
60156
+ {
60157
+ flexDirection: "row",
60158
+ flexGrow: 1,
60159
+ minHeight: 0,
60160
+ overflow: "hidden",
60161
+ children: [
60162
+ railEnabled && !expandedJob && !goalGate && !planLoading && !planApprove && !profilePicker && !customAgent && !modelPicker && !yesNoStep && !clarifyQA && /* @__PURE__ */ jsx9(
60163
+ SideRail,
60164
+ {
60165
+ vmodelActive: tuiState.vmodelActive,
60166
+ vmodelDone: tuiState.vmodelDone,
60167
+ traceability: tuiState.traceability,
60168
+ squad: tuiState.squad,
60169
+ pinnedFiles: pinnedAtPaths
60170
+ }
60171
+ ),
60172
+ profilePicker ? /* @__PURE__ */ jsx9(
60173
+ ProfilePickerModal,
60174
+ {
60175
+ choices: profilePicker.choices,
60176
+ selected: profilePicker.selected,
60177
+ status: profilePicker.status,
60178
+ width: cols - 2
60179
+ }
60180
+ ) : customAgent ? /* @__PURE__ */ jsx9(
60181
+ CustomAgentModal,
60182
+ {
60183
+ profileName: customAgent.profile,
60184
+ width: cols - 2
60185
+ }
60186
+ ) : modelPicker ? /* @__PURE__ */ jsx9(
60187
+ ModelPickerModal,
60188
+ {
60189
+ purpose: modelPicker.purpose,
60190
+ hint: modelPicker.hint,
60191
+ choices: modelPicker.choices,
60192
+ selected: modelPicker.selected,
60193
+ width: cols - 2
60194
+ }
60195
+ ) : goalGate ? /* @__PURE__ */ jsx9(
60196
+ GoalStartGateModal,
60197
+ {
60198
+ goalId: goalGate.goalId,
60199
+ objective: goalGate.objective,
60200
+ width: cols - 2
60201
+ }
60202
+ ) : yesNoStep ? /* @__PURE__ */ jsx9(
60203
+ YesNoStepModal,
60204
+ {
60205
+ title: yesNoStep.title,
60206
+ description: yesNoStep.description,
60207
+ detail: yesNoStep.detail,
60208
+ width: cols - 2
60209
+ }
60210
+ ) : clarifyQA ? /* @__PURE__ */ jsx9(
60211
+ ClarifyQAModal,
60212
+ {
60213
+ index: clarifyQA.index,
60214
+ total: clarifyQA.total,
60215
+ question: clarifyQA.question.text,
60216
+ draft: clarifyQA.draft,
60217
+ onChange: (next) => setClarifyQA((prev) => prev ? { ...prev, draft: next } : prev),
60218
+ width: cols - 2
60219
+ }
60220
+ ) : planLoading ? /* @__PURE__ */ jsx9(
60221
+ StreamingPlanLoaderModal,
60222
+ {
60223
+ goalId: planLoading.goalId,
60224
+ buffer: planLoading.buffer,
60225
+ model: planLoading.model,
60226
+ phase: planLoading.phase,
60227
+ width: cols - 2,
60228
+ height: Math.max(14, rows - 4)
60229
+ }
60230
+ ) : planApprove ? /* @__PURE__ */ jsx9(
60231
+ PlanApprovalModal,
60232
+ {
60233
+ goalId: planApprove.goalId,
60234
+ summary: planApprove.plan,
60235
+ planPath: planApprove.planPath,
60236
+ scrollOffset: planApproveScroll,
60237
+ width: cols - 2,
60238
+ height: Math.max(12, rows - 4)
60239
+ }
60240
+ ) : expandedJob ? /* @__PURE__ */ jsx9(
60241
+ JobDetailPanel,
60242
+ {
60243
+ job: expandedJob,
60244
+ projectDir: expandedProjectDir,
60245
+ reasoning,
60246
+ width: cols - 2,
60247
+ height: Math.max(10, rows - 4)
60248
+ }
60249
+ ) : main2,
60250
+ !expandedJob && !goalGate && !planLoading && !planApprove && !profilePicker && !customAgent && !modelPicker && !yesNoStep && !clarifyQA && rightRailMode === "rail" && /* @__PURE__ */ jsx9(
60251
+ RightRail,
60252
+ {
60253
+ jobs: tuiState.backgroundJobs,
60254
+ width: rightRailW,
60255
+ height: rightRailH,
60256
+ verbosity: railVerbosity,
60257
+ soul: soulDigest,
60258
+ codeDigest: codeDigestStatus,
60259
+ reasoning,
60260
+ reasoningUpdatedAt
60261
+ }
60262
+ )
60263
+ ]
59369
60264
  }
59370
60265
  )
59371
- ] });
59372
- return /* @__PURE__ */ jsxs8(Fragment5, { children: [
59373
- /* @__PURE__ */ jsx8(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx8(EntryView, { entry }) }, entry.id) }),
59374
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
59375
- /* @__PURE__ */ jsx8(
59376
- StatusBar,
59377
- {
59378
- project: replState.activeProject,
59379
- status: tuiState.status,
59380
- mode: replState.mode ?? "build",
59381
- approval: replState.approvalModeOverride ?? cfg.gemini.approvalMode,
59382
- model: cfg.gemini.model ?? "auto",
59383
- backend: cfg.backend.provider,
59384
- width: cols
59385
- }
59386
- ),
59387
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
59388
- railEnabled && !expandedJob && !goalGate && !planLoading && !planApprove && !profilePicker && !customAgent && !modelPicker && !yesNoStep && !clarifyQA && /* @__PURE__ */ jsx8(
59389
- SideRail,
59390
- {
59391
- vmodelActive: tuiState.vmodelActive,
59392
- vmodelDone: tuiState.vmodelDone,
59393
- traceability: tuiState.traceability,
59394
- squad: tuiState.squad
59395
- }
59396
- ),
59397
- profilePicker ? /* @__PURE__ */ jsx8(
59398
- ProfilePickerModal,
59399
- {
59400
- choices: profilePicker.choices,
59401
- selected: profilePicker.selected,
59402
- status: profilePicker.status,
59403
- width: cols - 2
59404
- }
59405
- ) : customAgent ? /* @__PURE__ */ jsx8(
59406
- CustomAgentModal,
59407
- {
59408
- profileName: customAgent.profile,
59409
- width: cols - 2
59410
- }
59411
- ) : modelPicker ? /* @__PURE__ */ jsx8(
59412
- ModelPickerModal,
59413
- {
59414
- purpose: modelPicker.purpose,
59415
- hint: modelPicker.hint,
59416
- choices: modelPicker.choices,
59417
- selected: modelPicker.selected,
59418
- width: cols - 2
59419
- }
59420
- ) : goalGate ? /* @__PURE__ */ jsx8(
59421
- GoalStartGateModal,
59422
- {
59423
- goalId: goalGate.goalId,
59424
- objective: goalGate.objective,
59425
- width: cols - 2
59426
- }
59427
- ) : yesNoStep ? /* @__PURE__ */ jsx8(
59428
- YesNoStepModal,
59429
- {
59430
- title: yesNoStep.title,
59431
- description: yesNoStep.description,
59432
- detail: yesNoStep.detail,
59433
- width: cols - 2
59434
- }
59435
- ) : clarifyQA ? /* @__PURE__ */ jsx8(
59436
- ClarifyQAModal,
59437
- {
59438
- index: clarifyQA.index,
59439
- total: clarifyQA.total,
59440
- question: clarifyQA.question.text,
59441
- draft: clarifyQA.draft,
59442
- onChange: (next) => setClarifyQA((prev) => prev ? { ...prev, draft: next } : prev),
59443
- width: cols - 2
59444
- }
59445
- ) : planLoading ? /* @__PURE__ */ jsx8(
59446
- StreamingPlanLoaderModal,
59447
- {
59448
- goalId: planLoading.goalId,
59449
- buffer: planLoading.buffer,
59450
- model: planLoading.model,
59451
- phase: planLoading.phase,
59452
- width: cols - 2,
59453
- height: Math.max(14, rows - 4)
59454
- }
59455
- ) : planApprove ? /* @__PURE__ */ jsx8(
59456
- PlanApprovalModal,
59457
- {
59458
- goalId: planApprove.goalId,
59459
- summary: planApprove.plan,
59460
- planPath: planApprove.planPath,
59461
- width: cols - 2,
59462
- height: Math.max(12, rows - 4)
59463
- }
59464
- ) : expandedJob ? /* @__PURE__ */ jsx8(
59465
- JobDetailPanel,
59466
- {
59467
- job: expandedJob,
59468
- projectDir: expandedProjectDir,
59469
- width: cols - 2,
59470
- height: Math.max(10, rows - 4)
59471
- }
59472
- ) : main2,
59473
- !expandedJob && !goalGate && !planLoading && !planApprove && !profilePicker && !customAgent && !modelPicker && !yesNoStep && !clarifyQA && (rightRailMode === "wide" || rightRailMode === "narrow") && tuiState.backgroundJobs.length > 0 && /* @__PURE__ */ jsx8(
59474
- RightRail,
59475
- {
59476
- jobs: tuiState.backgroundJobs,
59477
- width: rightRailW,
59478
- height: rightRailH
59479
- }
59480
- )
59481
- ] })
59482
- ] })
59483
- ] });
60266
+ ] }) });
60267
+ }
60268
+ var CHAT_USER = "#7aa7ff";
60269
+ var CHAT_ASSISTANT = "#5eead4";
60270
+ var CHAT_SYSTEM = "#fbbf24";
60271
+ var CHAT_ERROR = "#ff5f5a";
60272
+ var CHAT_LABEL_DIM = "#4a525e";
60273
+ function ChatBubble({
60274
+ role,
60275
+ roleColor,
60276
+ body
60277
+ }) {
60278
+ return /* @__PURE__ */ jsxs9(
60279
+ Box9,
60280
+ {
60281
+ flexDirection: "column",
60282
+ borderStyle: "round",
60283
+ borderColor: roleColor,
60284
+ paddingX: 1,
60285
+ children: [
60286
+ /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text9, { color: roleColor, bold: true, children: [
60287
+ "\u25CF ",
60288
+ role.toUpperCase()
60289
+ ] }) }),
60290
+ body
60291
+ ]
60292
+ }
60293
+ );
60294
+ }
60295
+ function MultilineText({
60296
+ text,
60297
+ color,
60298
+ width
60299
+ }) {
60300
+ const lines = width && width > 0 ? wordWrap(text, width) : text.split("\n");
60301
+ return /* @__PURE__ */ jsx9(Fragment5, { children: lines.map((line, i2) => /* @__PURE__ */ jsx9(Text9, { color, children: line.length === 0 ? " " : line }, i2)) });
59484
60302
  }
59485
- function EntryView({ entry }) {
60303
+ function EntryView({
60304
+ entry,
60305
+ width
60306
+ }) {
59486
60307
  switch (entry.kind) {
59487
60308
  case "user":
59488
- return /* @__PURE__ */ jsxs8(Box8, { children: [
59489
- /* @__PURE__ */ jsxs8(Text8, { color: USER, bold: true, children: [
59490
- "\u203A",
59491
- " "
59492
- ] }),
59493
- /* @__PURE__ */ jsx8(Text8, { children: entry.text })
59494
- ] });
60309
+ return /* @__PURE__ */ jsx9(
60310
+ ChatBubble,
60311
+ {
60312
+ role: "you",
60313
+ roleColor: CHAT_USER,
60314
+ body: /* @__PURE__ */ jsx9(MultilineText, { text: entry.text, width })
60315
+ }
60316
+ );
59495
60317
  case "assistant":
59496
- return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: ASSISTANT, children: renderMarkdown(entry.text) }) });
60318
+ return /* @__PURE__ */ jsx9(
60319
+ ChatBubble,
60320
+ {
60321
+ role: "agent",
60322
+ roleColor: CHAT_ASSISTANT,
60323
+ body: /* @__PURE__ */ jsx9(MultilineText, { text: renderMarkdown(entry.text), width })
60324
+ }
60325
+ );
59497
60326
  case "system":
59498
- return /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: entry.text });
60327
+ return /* @__PURE__ */ jsx9(
60328
+ ChatBubble,
60329
+ {
60330
+ role: "system",
60331
+ roleColor: CHAT_SYSTEM,
60332
+ body: /* @__PURE__ */ jsx9(MultilineText, { text: entry.text, color: CHAT_LABEL_DIM, width })
60333
+ }
60334
+ );
59499
60335
  case "error":
59500
- return /* @__PURE__ */ jsxs8(Text8, { color: ERROR2, children: [
59501
- "\u26A0 ",
59502
- entry.text
59503
- ] });
60336
+ return /* @__PURE__ */ jsx9(
60337
+ ChatBubble,
60338
+ {
60339
+ role: "error",
60340
+ roleColor: CHAT_ERROR,
60341
+ body: /* @__PURE__ */ jsx9(
60342
+ MultilineText,
60343
+ {
60344
+ text: `\u26A0 ${entry.text}`,
60345
+ color: CHAT_ERROR,
60346
+ width
60347
+ }
60348
+ )
60349
+ }
60350
+ );
59504
60351
  }
59505
60352
  }
59506
60353
 
59507
60354
  // src/repl/history.ts
59508
- import { promises as fs61 } from "node:fs";
60355
+ import { promises as fs62 } from "node:fs";
59509
60356
  import path63 from "node:path";
59510
60357
  var HISTORY_FILE = ".the_flow_history";
59511
60358
  var MAX_LINES = 1e3;
@@ -59515,7 +60362,7 @@ var History = class _History {
59515
60362
  static async load(cwd = process.cwd()) {
59516
60363
  const h2 = new _History();
59517
60364
  try {
59518
- const text = await fs61.readFile(path63.join(cwd, HISTORY_FILE), "utf8");
60365
+ const text = await fs62.readFile(path63.join(cwd, HISTORY_FILE), "utf8");
59519
60366
  h2.entries = text.split("\n").map((l2) => l2.trim()).filter(Boolean).slice(-MAX_LINES);
59520
60367
  } catch {
59521
60368
  }
@@ -59529,7 +60376,7 @@ var History = class _History {
59529
60376
  this.entries.push(trimmed);
59530
60377
  if (this.entries.length > MAX_LINES) this.entries.shift();
59531
60378
  this.cursor = this.entries.length;
59532
- await fs61.writeFile(path63.join(cwd, HISTORY_FILE), this.entries.join("\n") + "\n").catch(() => {
60379
+ await fs62.writeFile(path63.join(cwd, HISTORY_FILE), this.entries.join("\n") + "\n").catch(() => {
59533
60380
  });
59534
60381
  }
59535
60382
  /** Navigate one step backward (older). Returns null at the start. */
@@ -59562,7 +60409,7 @@ var History = class _History {
59562
60409
  };
59563
60410
 
59564
60411
  // src/binary-resolver.ts
59565
- import { promises as fs62 } from "node:fs";
60412
+ import { promises as fs63 } from "node:fs";
59566
60413
  import path64 from "node:path";
59567
60414
  import os3 from "node:os";
59568
60415
  import { fileURLToPath as fileURLToPath4 } from "node:url";
@@ -59574,7 +60421,7 @@ async function resolveBinary(nameOrPath) {
59574
60421
  for (const ext2 of exts) {
59575
60422
  const probe = ext2 && !full.toLowerCase().endsWith(ext2) ? full + ext2 : full;
59576
60423
  try {
59577
- await fs62.access(probe, fs62.constants.F_OK);
60424
+ await fs63.access(probe, fs63.constants.F_OK);
59578
60425
  return probe;
59579
60426
  } catch {
59580
60427
  }
@@ -59605,7 +60452,7 @@ async function bundledNodeModulesBin(name) {
59605
60452
  for (let i2 = 0; i2 < 10; i2 += 1) {
59606
60453
  const candidatePath = path64.join(dir, "node_modules", ".bin", baseName + ext2);
59607
60454
  try {
59608
- const stat4 = await fs62.stat(candidatePath);
60455
+ const stat4 = await fs63.stat(candidatePath);
59609
60456
  if (stat4.isFile()) return candidatePath;
59610
60457
  } catch {
59611
60458
  }
@@ -59641,7 +60488,7 @@ function wellKnownBinDirs() {
59641
60488
  }
59642
60489
 
59643
60490
  // src/config.ts
59644
- import { promises as fs63 } from "node:fs";
60491
+ import { promises as fs64 } from "node:fs";
59645
60492
  import os4 from "node:os";
59646
60493
  import path65 from "node:path";
59647
60494
  import { fileURLToPath as fileURLToPath5 } from "node:url";
@@ -59686,7 +60533,7 @@ var DEFAULT_WEB_ALLOWLIST = [
59686
60533
  "developer.arm.com"
59687
60534
  ];
59688
60535
  async function loadConfig(configPath, projectDir2 = process.cwd()) {
59689
- const raw = await fs63.readFile(configPath, "utf8");
60536
+ const raw = await fs64.readFile(configPath, "utf8");
59690
60537
  const parsed = toml2.parse(raw);
59691
60538
  const baseDir = path65.dirname(path65.resolve(configPath));
59692
60539
  const gemini = parsed.gemini ?? {};
@@ -59976,7 +60823,7 @@ async function findBundledConfig() {
59976
60823
  ]) {
59977
60824
  const candidate = path65.join(dir, name);
59978
60825
  try {
59979
- await fs63.access(candidate);
60826
+ await fs64.access(candidate);
59980
60827
  return candidate;
59981
60828
  } catch {
59982
60829
  }
@@ -59991,8 +60838,8 @@ async function bootstrapUserConfig() {
59991
60838
  const userCfgDir = path65.join(userDir, "config");
59992
60839
  const target = path65.join(userCfgDir, "agenit.toml");
59993
60840
  try {
59994
- await fs63.mkdir(userCfgDir, { recursive: true });
59995
- await fs63.copyFile(bundled, target);
60841
+ await fs64.mkdir(userCfgDir, { recursive: true });
60842
+ await fs64.copyFile(bundled, target);
59996
60843
  process.stderr.write(
59997
60844
  `agenit: bootstrapped default config at ${target}
59998
60845
  edit it to customise; agenit will pick it up on next run.
@@ -60026,7 +60873,7 @@ async function resolveDefaultConfig() {
60026
60873
  }
60027
60874
  for (const c2 of candidates) {
60028
60875
  try {
60029
- await fs63.access(c2);
60876
+ await fs64.access(c2);
60030
60877
  return c2;
60031
60878
  } catch {
60032
60879
  }
@@ -60232,7 +61079,7 @@ async function readStdin() {
60232
61079
  }
60233
61080
 
60234
61081
  // src/update-check.ts
60235
- import { promises as fs64 } from "node:fs";
61082
+ import { promises as fs65 } from "node:fs";
60236
61083
  import os5 from "node:os";
60237
61084
  import path66 from "node:path";
60238
61085
  var DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -60243,7 +61090,7 @@ function defaultCachePath() {
60243
61090
  }
60244
61091
  async function readCache(p2) {
60245
61092
  try {
60246
- const raw = await fs64.readFile(p2, "utf8");
61093
+ const raw = await fs65.readFile(p2, "utf8");
60247
61094
  const parsed = JSON.parse(raw);
60248
61095
  if (typeof parsed.checked_at === "number" && typeof parsed.installed === "string") {
60249
61096
  return {
@@ -60259,8 +61106,8 @@ async function readCache(p2) {
60259
61106
  }
60260
61107
  async function writeCache(p2, entry) {
60261
61108
  try {
60262
- await fs64.mkdir(path66.dirname(p2), { recursive: true });
60263
- await fs64.writeFile(p2, JSON.stringify(entry, null, 2));
61109
+ await fs65.mkdir(path66.dirname(p2), { recursive: true });
61110
+ await fs65.writeFile(p2, JSON.stringify(entry, null, 2));
60264
61111
  } catch {
60265
61112
  }
60266
61113
  }
@@ -60408,8 +61255,8 @@ var SoulKeeperWorker = class {
60408
61255
  };
60409
61256
 
60410
61257
  // src/cli.tsx
60411
- import { jsx as jsx9 } from "react/jsx-runtime";
60412
- var FLOW_VERSION = "1.1.1";
61258
+ import { jsx as jsx10 } from "react/jsx-runtime";
61259
+ var FLOW_VERSION = "1.3.4";
60413
61260
  var MIN_GEMINI_MAJOR = 0;
60414
61261
  var MIN_GEMINI_MINOR = 37;
60415
61262
  async function checkGeminiCli(cfg) {
@@ -60472,7 +61319,7 @@ Upgrade: npm install -g @google/gemini-cli@latest`
60472
61319
  }
60473
61320
  async function readActiveProject() {
60474
61321
  try {
60475
- const txt = await fs66.readFile(".agenit_project", "utf8");
61322
+ const txt = await fs67.readFile(".agenit_project", "utf8");
60476
61323
  const trimmed = txt.trim();
60477
61324
  if (!trimmed) return null;
60478
61325
  if (trimmed.includes("=")) {
@@ -60484,7 +61331,7 @@ async function readActiveProject() {
60484
61331
  } catch {
60485
61332
  }
60486
61333
  try {
60487
- const txt = await fs66.readFile(".flow_project", "utf8");
61334
+ const txt = await fs67.readFile(".flow_project", "utf8");
60488
61335
  const trimmed = txt.trim();
60489
61336
  return trimmed || null;
60490
61337
  } catch {
@@ -60499,6 +61346,31 @@ async function loadFlowConfig(configFlag) {
60499
61346
  initMetrics(cfg.telemetry);
60500
61347
  return cfg;
60501
61348
  }
61349
+ async function withAltScreen(run) {
61350
+ const isTty = process.stdout.isTTY;
61351
+ const enter = () => {
61352
+ if (isTty) process.stdout.write("\x1B[?1049h\x1B[H");
61353
+ };
61354
+ const exit = () => {
61355
+ if (isTty) process.stdout.write("\x1B[?1049l\r\n");
61356
+ };
61357
+ enter();
61358
+ const onSignal = (sig) => {
61359
+ exit();
61360
+ process.kill(process.pid, sig);
61361
+ };
61362
+ process.once("SIGINT", onSignal);
61363
+ process.once("SIGTERM", onSignal);
61364
+ process.once("SIGHUP", onSignal);
61365
+ try {
61366
+ await run();
61367
+ } finally {
61368
+ exit();
61369
+ process.off("SIGINT", onSignal);
61370
+ process.off("SIGTERM", onSignal);
61371
+ process.off("SIGHUP", onSignal);
61372
+ }
61373
+ }
60502
61374
  async function cmdResume(cfg, idHint) {
60503
61375
  const id = await resolveSessionId(idHint);
60504
61376
  if (!id) {
@@ -60518,22 +61390,24 @@ async function cmdResume(cfg, idHint) {
60518
61390
  const history = await History.load();
60519
61391
  await writeGuard(cfg, null);
60520
61392
  await ensureGuardHookRegistered();
60521
- const { waitUntilExit } = render2(
60522
- /* @__PURE__ */ jsx9(
60523
- App,
60524
- {
60525
- cfg,
60526
- initialProject,
60527
- history,
60528
- resumeFrom: { id: session.meta.id, turns: session.turns }
60529
- }
60530
- )
60531
- );
60532
61393
  process.stderr.write(
60533
61394
  `\u25B6 resuming session ${session.meta.id} (${session.meta.turns} turn${session.meta.turns === 1 ? "" : "s"})
60534
61395
  `
60535
61396
  );
60536
- await waitUntilExit();
61397
+ await withAltScreen(async () => {
61398
+ const { waitUntilExit } = render2(
61399
+ /* @__PURE__ */ jsx10(
61400
+ App,
61401
+ {
61402
+ cfg,
61403
+ initialProject,
61404
+ history,
61405
+ resumeFrom: { id: session.meta.id, turns: session.turns }
61406
+ }
61407
+ )
61408
+ );
61409
+ await waitUntilExit();
61410
+ });
60537
61411
  }
60538
61412
  async function cmdSessionsList() {
60539
61413
  const list = await listSessions();
@@ -60634,15 +61508,17 @@ agenIT ${info.latest} is available (you have ${info.installed}). Update with: np
60634
61508
  }
60635
61509
  }).catch(() => {
60636
61510
  });
60637
- const { waitUntilExit } = render2(
60638
- /* @__PURE__ */ jsx9(App, { cfg, initialProject, history })
60639
- );
60640
- try {
60641
- await waitUntilExit();
60642
- } finally {
60643
- if (watcher) await watcher.stop().catch(() => {
60644
- });
60645
- }
61511
+ await withAltScreen(async () => {
61512
+ const { waitUntilExit } = render2(
61513
+ /* @__PURE__ */ jsx10(App, { cfg, initialProject, history })
61514
+ );
61515
+ try {
61516
+ await waitUntilExit();
61517
+ } finally {
61518
+ if (watcher) await watcher.stop().catch(() => {
61519
+ });
61520
+ }
61521
+ });
60646
61522
  }
60647
61523
  async function cmdPrint(cfg, task) {
60648
61524
  let resolved = task;
@@ -60679,7 +61555,7 @@ async function cmdProjects(cfg) {
60679
61555
  const dir = cfg.flow.memoryDir;
60680
61556
  let entries = [];
60681
61557
  try {
60682
- entries = await fs66.readdir(dir, { withFileTypes: true });
61558
+ entries = await fs67.readdir(dir, { withFileTypes: true });
60683
61559
  } catch {
60684
61560
  return;
60685
61561
  }
@@ -60692,16 +61568,16 @@ async function cmdInit(cfg, projectDir2, name) {
60692
61568
  const target = path68.resolve(projectDir2);
60693
61569
  const projectName = name ?? path68.basename(target);
60694
61570
  const memDir = path68.join(cfg.flow.memoryDir, projectName);
60695
- await fs66.mkdir(memDir, { recursive: true });
61571
+ await fs67.mkdir(memDir, { recursive: true });
60696
61572
  for (const file of ["context.md", "decisions.md", "requirements.md"]) {
60697
61573
  const p2 = path68.join(memDir, file);
60698
61574
  try {
60699
- await fs66.access(p2);
61575
+ await fs67.access(p2);
60700
61576
  } catch {
60701
- await fs66.writeFile(p2, "");
61577
+ await fs67.writeFile(p2, "");
60702
61578
  }
60703
61579
  }
60704
- await fs66.writeFile(
61580
+ await fs67.writeFile(
60705
61581
  path68.join(target, ".agenit_project"),
60706
61582
  `project = "${projectName}"
60707
61583
  profile = "automotive"
@@ -60724,6 +61600,14 @@ profile = "automotive"
60724
61600
  `
60725
61601
  );
60726
61602
  }
61603
+ process.stdout.write(
61604
+ ` Tools: ${seed.toolsCopied} python script${seed.toolsCopied === 1 ? "" : "s"} copied to ${path68.join(target, ".flow/tools")}
61605
+ `
61606
+ );
61607
+ process.stdout.write(
61608
+ ` Constitution: ${seed.constitutionSeeded ? "seeded default" : "preserved existing"} at ${path68.join(target, ".specify/memory/constitution.md")}
61609
+ `
61610
+ );
60727
61611
  } catch (err) {
60728
61612
  process.stderr.write(
60729
61613
  ` warning: failed to seed .gemini/ assets: ${err.message}
@@ -60739,7 +61623,7 @@ async function cmdUnflow(projectDir2) {
60739
61623
  for (const fname of [".agenit_project", ".flow_project"]) {
60740
61624
  const marker = path68.join(target, fname);
60741
61625
  try {
60742
- await fs66.unlink(marker);
61626
+ await fs67.unlink(marker);
60743
61627
  process.stdout.write(`\u2713 Removed ${marker}
60744
61628
  `);
60745
61629
  removed = true;