fluxflow-cli 1.17.5 → 1.18.1

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 (2) hide show
  1. package/dist/fluxflow.js +622 -364
  2. package/package.json +4 -4
package/dist/fluxflow.js CHANGED
@@ -97,7 +97,7 @@ var init_MultilineInput = __esm({
97
97
  };
98
98
  }
99
99
  return {
100
- preCursor: [{ value: " ", type: "cursor" }],
100
+ preCursor: [{ value: showCursor && focus ? "\u2502" : "", type: "cursor" }],
101
101
  postCursor: []
102
102
  };
103
103
  }
@@ -119,7 +119,7 @@ var init_MultilineInput = __esm({
119
119
  preCursor: [
120
120
  { value: formattedBefore.slice(0, lineStart) },
121
121
  { value: formattedBefore.slice(lineStart), type: "highlight" },
122
- { value: showCursor && focus ? " " : "", type: "cursor" }
122
+ { value: showCursor && focus ? "\u2502" : "", type: "cursor" }
123
123
  ],
124
124
  postCursor: [
125
125
  { value: formattedAfter.slice(0, lineEnd), type: "highlight" },
@@ -135,7 +135,7 @@ var init_MultilineInput = __esm({
135
135
  type: "highlight"
136
136
  },
137
137
  { value: formatText(textBefore.slice(highlight.end)) },
138
- { value: " ", type: "cursor" }
138
+ { value: showCursor && focus ? "\u2502" : "", type: "cursor" }
139
139
  ],
140
140
  postCursor: [
141
141
  {
@@ -188,8 +188,10 @@ var init_MultilineInput = __esm({
188
188
  return highlightStyle ?? textStyle;
189
189
  case "cursor":
190
190
  return {
191
- ...highlightStyle ?? textStyle,
192
- inverse: showCursor && focus
191
+ ...textStyle,
192
+ color: "cyan",
193
+ bold: true,
194
+ inverse: false
193
195
  };
194
196
  default:
195
197
  return textStyle;
@@ -207,6 +209,7 @@ var init_MultilineInput = __esm({
207
209
  showCursor = true,
208
210
  highlightPastedText = false,
209
211
  focus = true,
212
+ columns = 80,
210
213
  useCustomInput = (inputHandler, isActive) => useInput(inputHandler, { isActive }),
211
214
  ...controlledProps
212
215
  }) => {
@@ -217,6 +220,49 @@ var init_MultilineInput = __esm({
217
220
  setCursorIndex(value.length);
218
221
  }
219
222
  }, [value, cursorIndex]);
223
+ const getVisualPosition = useCallback((index) => {
224
+ const text = normalizeLineEndings(value);
225
+ const lines = text.split("\n");
226
+ const wrapWidth = Math.max(20, columns - 10);
227
+ let visualLine = 0;
228
+ let visualCol = 0;
229
+ let currentIdx = 0;
230
+ for (let i = 0; i < lines.length; i++) {
231
+ const line = lines[i];
232
+ const lineLen = line.length;
233
+ if (index >= currentIdx && index <= currentIdx + lineLen) {
234
+ const offsetInLine = index - currentIdx;
235
+ visualLine += Math.floor(offsetInLine / wrapWidth);
236
+ visualCol = offsetInLine % wrapWidth;
237
+ return { visualLine, visualCol };
238
+ }
239
+ const numVisualLines = Math.max(1, Math.ceil(lineLen / wrapWidth));
240
+ visualLine += numVisualLines;
241
+ currentIdx += lineLen + 1;
242
+ }
243
+ return { visualLine, visualCol };
244
+ }, [value, columns]);
245
+ const getIndexFromVisual = useCallback((targetLine, targetCol) => {
246
+ const text = normalizeLineEndings(value);
247
+ const lines = text.split("\n");
248
+ const wrapWidth = Math.max(20, columns - 10);
249
+ let currentVisualLine = 0;
250
+ let currentIdx = 0;
251
+ for (let i = 0; i < lines.length; i++) {
252
+ const line = lines[i];
253
+ const lineLen = line.length;
254
+ const numVisualLines = Math.max(1, Math.ceil(lineLen / wrapWidth));
255
+ if (targetLine >= currentVisualLine && targetLine < currentVisualLine + numVisualLines) {
256
+ const lineOffset = (targetLine - currentVisualLine) * wrapWidth;
257
+ const colInLine = Math.min(targetCol, lineLen - lineOffset);
258
+ const finalCol = Math.max(0, colInLine);
259
+ return Math.min(currentIdx + lineOffset + finalCol, currentIdx + lineLen);
260
+ }
261
+ currentVisualLine += numVisualLines;
262
+ currentIdx += lineLen + 1;
263
+ }
264
+ return value.length;
265
+ }, [value, columns]);
220
266
  useCustomInput((input, key) => {
221
267
  const submitKey = keyBindings?.submit ?? ((key2) => key2.return && key2.ctrl);
222
268
  const newlineKey = keyBindings?.newline ?? ((key2) => key2.return);
@@ -233,83 +279,26 @@ var init_MultilineInput = __esm({
233
279
  if (key.tab || key.shift && key.tab || key.ctrl && input === "c") {
234
280
  return;
235
281
  }
236
- if (keyBindings?.newline?.(key)) {
237
- const newValue = value.slice(0, cursorIndex) + "\n" + value.slice(cursorIndex);
238
- onChange(newValue);
239
- setCursorIndex(cursorIndex + 1);
240
- setPasteLength(0);
241
- return;
242
- }
243
282
  let nextPasteLength = 0;
244
283
  if (input.length > 1) {
245
284
  nextPasteLength = input.length;
246
285
  }
247
286
  if (key.upArrow) {
248
287
  if (showCursor) {
249
- const lines = normalizeLineEndings(value).split("\n");
250
- let currentLineIndex = 0;
251
- let currentPos = 0;
252
- let col = 0;
253
- for (let i = 0; i < lines.length; i++) {
254
- const line = lines[i];
255
- if (line === void 0) continue;
256
- const lineLen = line.length;
257
- const lineEnd = currentPos + lineLen;
258
- if (cursorIndex >= currentPos && cursorIndex <= lineEnd) {
259
- currentLineIndex = i;
260
- col = cursorIndex - currentPos;
261
- break;
262
- }
263
- currentPos = lineEnd + 1;
264
- }
265
- if (currentLineIndex > 0) {
266
- const targetLineIndex = currentLineIndex - 1;
267
- const targetLine = lines[targetLineIndex];
268
- if (targetLine !== void 0) {
269
- const targetLineLen = targetLine.length;
270
- const newCol = Math.min(col, targetLineLen);
271
- let newIndex = 0;
272
- for (let i = 0; i < targetLineIndex; i++) {
273
- newIndex += lines[i].length + 1;
274
- }
275
- newIndex += newCol;
276
- setCursorIndex(newIndex);
277
- setPasteLength(0);
278
- }
288
+ const { visualLine, visualCol } = getVisualPosition(cursorIndex);
289
+ if (visualLine > 0) {
290
+ const newIndex = getIndexFromVisual(visualLine - 1, visualCol);
291
+ setCursorIndex(newIndex);
292
+ setPasteLength(0);
279
293
  }
280
294
  }
281
295
  } else if (key.downArrow) {
282
296
  if (showCursor) {
283
- const lines = normalizeLineEndings(value).split("\n");
284
- let currentLineIndex = 0;
285
- let currentPos = 0;
286
- let col = 0;
287
- for (let i = 0; i < lines.length; i++) {
288
- const line = lines[i];
289
- if (line === void 0) continue;
290
- const lineLen = line.length;
291
- const lineEnd = currentPos + lineLen;
292
- if (cursorIndex >= currentPos && cursorIndex <= lineEnd) {
293
- currentLineIndex = i;
294
- col = cursorIndex - currentPos;
295
- break;
296
- }
297
- currentPos = lineEnd + 1;
298
- }
299
- if (currentLineIndex < lines.length - 1) {
300
- const targetLineIndex = currentLineIndex + 1;
301
- const targetLine = lines[targetLineIndex];
302
- if (targetLine !== void 0) {
303
- const targetLineLen = targetLine.length;
304
- const newCol = Math.min(col, targetLineLen);
305
- let newIndex = 0;
306
- for (let i = 0; i < targetLineIndex; i++) {
307
- newIndex += lines[i].length + 1;
308
- }
309
- newIndex += newCol;
310
- setCursorIndex(newIndex);
311
- setPasteLength(0);
312
- }
297
+ const { visualLine, visualCol } = getVisualPosition(cursorIndex);
298
+ const newIndex = getIndexFromVisual(visualLine + 1, visualCol);
299
+ if (newIndex !== cursorIndex) {
300
+ setCursorIndex(newIndex);
301
+ setPasteLength(0);
313
302
  }
314
303
  }
315
304
  } else if (key.leftArrow) {
@@ -374,66 +363,53 @@ var init_text = __esm({
374
363
  "src/utils/text.js"() {
375
364
  wrapText = (text, width) => {
376
365
  if (!text) return "";
377
- const sourceLines = text.split(/\r?\n/);
366
+ const ansiRegex = /\x1B\[[0-?]*[ -/]*[@-~]/g;
367
+ const sourceLines = text.split("\n");
378
368
  let finalLines = [];
379
369
  if (width <= 5) return text;
370
+ const getVisibleLength = (str) => str.replace(ansiRegex, "").length;
380
371
  sourceLines.forEach((sLine) => {
381
- if (sLine.length <= width) {
372
+ const visibleLength = getVisibleLength(sLine);
373
+ if (visibleLength <= width) {
382
374
  finalLines.push(sLine);
383
375
  return;
384
376
  }
385
377
  const tokens = sLine.split(/(\s+)/);
386
378
  let currentLine = "";
387
- let originalXPos = 0;
388
- let lastSignificantGap = 0;
379
+ let currentVisibleLength = 0;
389
380
  const leadingSpaceMatch = sLine.match(/^(\s*)/);
390
- if (leadingSpaceMatch) {
391
- lastSignificantGap = leadingSpaceMatch[1].length;
392
- }
393
- const listMatch = sLine.match(/^\s*([-*]|\d+\.)\s+/);
394
- if (listMatch) {
395
- lastSignificantGap = listMatch[0].length;
396
- }
381
+ const indent = leadingSpaceMatch ? leadingSpaceMatch[1] : "";
397
382
  tokens.forEach((token, idx) => {
398
383
  if (token.length === 0) return;
399
- const isWhitespace = token.trim().length === 0;
400
- if (isWhitespace) {
401
- if (token.length >= 2) {
402
- lastSignificantGap = originalXPos + token.length;
403
- }
404
- if (currentLine.length > 0) {
405
- currentLine += token;
406
- }
407
- } else {
408
- if (token.includes("|") || token.includes("\u2502")) {
409
- const pipeIdx = token.includes("|") ? token.indexOf("|") : token.indexOf("\u2502");
410
- lastSignificantGap = originalXPos + pipeIdx + 1;
411
- }
412
- if ((currentLine + token).length > width) {
413
- if (currentLine.trim().length > 0) {
414
- finalLines.push(currentLine.replace(/\s+$/, ""));
415
- const safeIndent = Math.min(lastSignificantGap, Math.max(0, width - 12));
416
- const indent = " ".repeat(safeIndent);
417
- currentLine = indent + token;
418
- while (currentLine.length > width && width > 20) {
419
- finalLines.push(currentLine.substring(0, width));
420
- currentLine = indent + currentLine.substring(width);
421
- }
384
+ const tokenVisibleLength = getVisibleLength(token);
385
+ if (currentVisibleLength + tokenVisibleLength > width) {
386
+ if (currentLine.trim().length > 0) {
387
+ finalLines.push(currentLine.trimEnd());
388
+ currentLine = indent + token;
389
+ currentVisibleLength = getVisibleLength(currentLine);
390
+ } else {
391
+ if (ansiRegex.test(token)) {
392
+ finalLines.push(token);
393
+ currentLine = indent;
394
+ currentVisibleLength = getVisibleLength(currentLine);
422
395
  } else {
423
396
  let word = token;
424
- while (word.length > width && width > 5) {
397
+ while (getVisibleLength(word) > width && width > 10) {
425
398
  finalLines.push(word.substring(0, width));
426
399
  word = word.substring(width);
427
400
  }
428
401
  currentLine = word;
402
+ currentVisibleLength = getVisibleLength(currentLine);
429
403
  }
430
- } else {
431
- currentLine += token;
432
404
  }
405
+ } else {
406
+ currentLine += token;
407
+ currentVisibleLength += tokenVisibleLength;
433
408
  }
434
- originalXPos += token.length;
435
409
  });
436
- if (currentLine) finalLines.push(currentLine.replace(/\s+$/, ""));
410
+ if (currentLine.trimEnd().length > 0 || currentLine === indent) {
411
+ finalLines.push(currentLine.trimEnd());
412
+ }
437
413
  });
438
414
  return finalLines.join("\n");
439
415
  };
@@ -463,10 +439,14 @@ var TerminalBox;
463
439
  var init_TerminalBox = __esm({
464
440
  "src/components/TerminalBox.jsx"() {
465
441
  init_text();
466
- TerminalBox = React2.memo(({ command, output, completed = false, isFocused = false, columns = 80 }) => {
467
- const cleanOutput = (output || "").replace(/\r/g, "").trim();
468
- const wrappedOutput = cleanOutput ? wrapText(cleanOutput, columns - 6) : "";
469
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: isFocused ? "double" : "round", borderColor: completed ? "#334155" : isFocused ? "yellow" : "cyan", paddingX: 2, paddingY: completed ? 0 : 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : isFocused ? "yellow" : "cyan", bold: true }, completed ? "\u{1F3C1} FINISHED:" : "\u26A1 EXECUTING:", " "), /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : "white" }, command)), wrappedOutput ? /* @__PURE__ */ React2.createElement(Box2, { marginTop: completed ? 0 : 1, backgroundColor: "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : "green" }, wrappedOutput)) : !completed && /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, backgroundColor: "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "gray", italic: true }, "Waiting for output...")), /* @__PURE__ */ React2.createElement(Box2, { justifyContent: "space-between", marginTop: 1 }, !completed ? /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true, italic: true }, "Double-press ESC to terminate if hanging.") : /* @__PURE__ */ React2.createElement(Box2, null), /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "#475569" : isFocused ? "yellow" : "cyan", bold: true }, completed ? "\u25CF ARCHIVED" : isFocused ? "\u25B6 TERMINAL FOCUSED" : "\u25CF LIVE (Press TAB to focus)")));
442
+ TerminalBox = React2.memo(({ command, output, completed = false, isFocused = false, columns = 80, isPty = false }) => {
443
+ const processOutput = (text) => {
444
+ if (!text) return "";
445
+ return text.split(/\r\n|\r|\n/).map((line) => line.trimEnd()).join("\n").replace(/^\n+|\n+$/g, "");
446
+ };
447
+ const cleanOutput = processOutput(output);
448
+ const displayOutput = isPty ? cleanOutput : cleanOutput ? wrapText(cleanOutput, columns - 6) : "";
449
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: isFocused ? "double" : "round", borderColor: completed ? "#334155" : isFocused ? "yellow" : "cyan", paddingX: 2, paddingY: completed ? 0 : 1, width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React2.createElement(Box2, { flexShrink: 1, paddingRight: 2 }, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : isFocused ? "yellow" : "cyan", bold: true }, completed ? "\u{1F3C1} FINISHED:" : "\u26A1 EXECUTING:", " "), /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : "white" }, command))), isPty && /* @__PURE__ */ React2.createElement(Box2, { flexShrink: 0, paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : "magenta", bold: true }, "ADVANCE"))), displayOutput ? /* @__PURE__ */ React2.createElement(Box2, { marginTop: completed ? 0 : 1, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "gray" : void 0 }, displayOutput)) : !completed && /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "gray", italic: true }, "Waiting for output...")), /* @__PURE__ */ React2.createElement(Box2, { justifyContent: "space-between", marginTop: 1 }, !completed ? /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true, italic: true }, "Double-press ESC to terminate if hanging.") : /* @__PURE__ */ React2.createElement(Box2, null), /* @__PURE__ */ React2.createElement(Text2, { color: completed ? "#475569" : isFocused ? "yellow" : "cyan", bold: true }, completed ? "\u25CF ARCHIVED" : isFocused ? "\u25B6 TERMINAL FOCUSED" : "\u25CF LIVE (Press TAB to focus)")));
470
450
  });
471
451
  }
472
452
  });
@@ -510,7 +490,7 @@ var init_ChatLayout = __esm({
510
490
  "exec_command": "ExecuteCommand",
511
491
  "web_search": "WebSearch",
512
492
  "web_scrape": "ReadSite",
513
- "search_keyword": "FindFiles",
493
+ "search_keyword": "SearchKeyword",
514
494
  "write_pdf": "CreatePDF",
515
495
  "write_docx": "CreateDocument",
516
496
  "generate_image": "GenerateImage",
@@ -744,20 +724,26 @@ var init_ChatLayout = __esm({
744
724
  DiffLine = React3.memo(({ line, columns = 80 }) => {
745
725
  const isContext = line.includes("[UI_CONTEXT]");
746
726
  const cleanLine = line.replace("[UI_CONTEXT]", "");
727
+ if (isContext && cleanLine.includes("\u2550")) {
728
+ return /* @__PURE__ */ React3.createElement(Box3, { backgroundColor: "#1a1a1a", paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, "\u2550".repeat(Math.max(10, columns - 4))));
729
+ }
747
730
  const isRemoval = cleanLine.startsWith("-");
748
731
  const isAddition = cleanLine.startsWith("+");
749
- const parts = cleanLine.substring(1).split("|");
750
- const lineNum = parts[0]?.trim() || "";
751
- const content = parts.slice(1).join("|");
732
+ const prefixChar = cleanLine[0];
733
+ const rest = cleanLine.substring(1);
734
+ const splitIdx = rest.indexOf("|");
735
+ const lineNum = splitIdx !== -1 ? rest.substring(0, splitIdx).trim() : "";
736
+ const content = splitIdx !== -1 ? rest.substring(splitIdx + 1) : rest;
752
737
  const bgColor = isRemoval ? "#3a0c0c" : isAddition ? "#0c3a1a" : "#1a1a1a";
753
- const textColor = isRemoval ? "#ff4d4d" : isAddition ? "#4dff88" : "white";
754
- return /* @__PURE__ */ React3.createElement(Box3, { backgroundColor: bgColor, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: isRemoval ? "#cf3a3a" : isAddition ? "#3acf65" : "gray", dimColor: true }, lineNum)), /* @__PURE__ */ React3.createElement(Box3, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: textColor }, wrapText(content, columns - 10))));
738
+ const textColor = isRemoval ? "#ff4d4d" : isAddition ? "#4dff88" : isContext ? "gray" : "white";
739
+ const numColor = isRemoval ? "#cf3a3a" : isAddition ? "#3acf65" : "gray";
740
+ return /* @__PURE__ */ React3.createElement(Box3, { backgroundColor: bgColor, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { width: 5, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: numColor, dimColor: isContext }, lineNum)), /* @__PURE__ */ React3.createElement(Box3, { width: 2, flexShrink: 0, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: textColor, bold: true }, isRemoval ? "-" : isAddition ? "+" : " ")), /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: textColor, dimColor: isContext }, wrapText(content, columns - 14))));
755
741
  });
756
742
  DiffBlock = React3.memo(({ text, columns = 80 }) => {
757
743
  const match = text.match(/\[DIFF_START\]([\s\S]*?)\[DIFF_END\]/);
758
744
  const diffBody = match ? match[1].trim() : "";
759
745
  const diffLines = diffBody.split("\n");
760
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: "100%", marginBottom: 0 }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", backgroundColor: "#1a1a1a", paddingY: 0, width: "100%" }, diffLines.map((line, i) => /* @__PURE__ */ React3.createElement(DiffLine, { key: i, line, columns }))));
746
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: columns - 3, marginBottom: 0 }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", backgroundColor: "#1a1a1a", paddingY: 0, width: "100%" }, diffLines.map((line, i) => /* @__PURE__ */ React3.createElement(DiffLine, { key: i, line, columns: columns - 3 }))));
761
747
  });
762
748
  CodeRenderer = React3.memo(({ text, columns = 80 }) => {
763
749
  if (!text) return null;
@@ -774,11 +760,11 @@ var init_ChatLayout = __esm({
774
760
  const footer = contentAndFooter[1] ? `${footerMarker}${contentAndFooter[1]}` : "";
775
761
  const codeLines = content.split("\n");
776
762
  const gutterWidth = String(codeLines.length).length;
777
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "#444", paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { alignSelf: "flex-end", marginTop: -1, marginRight: 1 }, /* @__PURE__ */ React3.createElement(Text3, { backgroundColor: "#444", color: "white" }, " FILE SNAPSHOT ")), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", paddingY: 1, width: "100%" }, codeLines.map((line, idx) => /* @__PURE__ */ React3.createElement(Box3, { key: idx, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, line)))))));
763
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: columns - 3 }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "#444", paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { alignSelf: "flex-end", marginTop: -1, marginRight: 1 }, /* @__PURE__ */ React3.createElement(Text3, { backgroundColor: "#444", color: "white" }, " FILE SNAPSHOT ")), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", paddingY: 1, width: "100%" }, codeLines.map((line, idx) => /* @__PURE__ */ React3.createElement(Box3, { key: idx, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React3.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, line)))))));
778
764
  }
779
765
  if (text.includes("```")) {
780
766
  const parts = text.split(/(```\w*\n?[\s\S]*?(?:```|$))/g);
781
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: "100%" }, parts.map((part, i) => {
767
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width: columns - 3 }, parts.map((part, i) => {
782
768
  if (part.startsWith("```")) {
783
769
  const match = part.match(/```(\w*)\n?([\s\S]*?)(?:```|$)/);
784
770
  const lang = match ? match[1] : "code";
@@ -795,10 +781,10 @@ var init_ChatLayout = __esm({
795
781
  cleanPart = cleanPart.replace(/[\r\n]+$/, "");
796
782
  }
797
783
  if (!cleanPart) return null;
798
- return /* @__PURE__ */ React3.createElement(MarkdownText, { key: i, text: cleanPart, columns });
784
+ return /* @__PURE__ */ React3.createElement(MarkdownText, { key: i, text: cleanPart, columns: columns - 3 });
799
785
  }));
800
786
  }
801
- return /* @__PURE__ */ React3.createElement(MarkdownText, { text, columns });
787
+ return /* @__PURE__ */ React3.createElement(MarkdownText, { text, columns: columns - 3 });
802
788
  });
803
789
  formatThinkingDuration = (ms) => {
804
790
  const totalSecs = Math.round(ms / 1e3);
@@ -876,12 +862,14 @@ var init_ChatLayout = __esm({
876
862
  ];
877
863
  return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(Text3, { color: "magenta", bold: true, underline: true }, "\u{1F4DC} COMMAND REFERENCE"), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, commandList.map((c, i) => /* @__PURE__ */ React3.createElement(Box3, { key: i, flexDirection: "row" }, /* @__PURE__ */ React3.createElement(Box3, { width: 15 }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, c.cmd)), /* @__PURE__ */ React3.createElement(Text3, { color: "gray" }, " - ", c.desc))))));
878
864
  }
879
- if (isTerminalRecord) {
880
- const cmdMatch = msg.text.match(/COMMAND: (.*)\n/);
881
- const outputMatch = msg.text.match(/OUTPUT: ([\s\S]*)$/);
865
+ if (msg.isTerminalRecord) {
866
+ const cmdMatch = msg.text.match(/COMMAND: (.*)/);
867
+ const ptyMatch = msg.text.match(/PTY: (true|false)/);
868
+ const outputMatch = msg.text.match(/OUTPUT: ([\s\S]*)/);
882
869
  const cmd = cmdMatch ? cmdMatch[1] : "Unknown";
870
+ const isPty = ptyMatch ? ptyMatch[1] === "true" : false;
883
871
  const outputList = outputMatch ? outputMatch[1] : "";
884
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(TerminalBox, { command: cmd, output: outputList, completed: true, columns }));
872
+ return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1, paddingX: 1, width: "100%" }, /* @__PURE__ */ React3.createElement(TerminalBox, { command: cmd, output: outputList, completed: true, columns, isPty }));
885
873
  }
886
874
  const [animationDone, setAnimationDone] = React3.useState(!msg.isStreaming);
887
875
  const content = React3.useMemo(() => cleanSignals(msg.text), [msg.text]);
@@ -1648,9 +1636,22 @@ var init_secrets = __esm({
1648
1636
  });
1649
1637
 
1650
1638
  // src/data/main_tools.js
1651
- var TOOL_PROTOCOL;
1639
+ import { execSync } from "child_process";
1640
+ var _isPsAvailable, isPsAvailable, TOOL_PROTOCOL;
1652
1641
  var init_main_tools = __esm({
1653
1642
  "src/data/main_tools.js"() {
1643
+ _isPsAvailable = null;
1644
+ isPsAvailable = () => {
1645
+ if (process.platform !== "win32") return false;
1646
+ if (_isPsAvailable !== null) return _isPsAvailable;
1647
+ try {
1648
+ execSync('powershell.exe -NoProfile -Command "exit"', { stdio: "ignore" });
1649
+ _isPsAvailable = true;
1650
+ } catch (e) {
1651
+ _isPsAvailable = false;
1652
+ }
1653
+ return _isPsAvailable;
1654
+ };
1654
1655
  TOOL_PROTOCOL = (mode, osDetected) => `
1655
1656
  -- TOOL DEFINITIONS --
1656
1657
  Access to internal tools. To call a tool, MUST use the exact syntax on a new line: [tool:functions.ToolName(args)]
@@ -1668,10 +1669,10 @@ Suggest best options; don't ask for preferences
1668
1669
  ${mode === "Flux" ? `- PROJECT TOOLS (path = relative to CWD) -
1669
1670
  1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. Supports images/docs. User gives image/doc: VIEW FIRST
1670
1671
  2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
1671
- 3. [tool:functions.PatchFile(path="...", replaceContent="exact old content", newContent="new content")]. Surgical patching. Unsure replaceContent? ReadFile > guessing
1672
+ 3. [tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 8)]. Surgical Patch. Unsure? ReadFile > guessing. Multiple blocks same file? Use replaceContent2, newContent2 etc.
1672
1673
  4. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile >> WriteFile. Verify Imports
1673
- 5. [tool:functions.SearchKeyword(keyword="...")]. Global project search. Finds definitions/logic without reading every file
1674
- 6. [tool:functions.Run(command="...")]. Runs a ${osDetected === "Windows" ? "Windows CMD" : "Bash"} command. Destructive/Irreversible ops -> Ask user
1674
+ 5. [tool:functions.SearchKeyword(keyword="...", file="path/to/file")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file
1675
+ 6. [tool:functions.Run(command="...")]. Runs a ${osDetected === "Windows" ? isPsAvailable() ? "Windows Powershell" : "Windows CMD" : "Bash"} command. Destructive/Irreversible ops -> Ask user
1675
1676
  7. [tool:functions.GenerateImage(path="... png", prompt="detailed", ratio="16:9, 9:16, 1:1")]. Usage: Mockups, PDF thumbnails, any visual content
1676
1677
  8. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout (100vh/vw)
1677
1678
  9. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document
@@ -3223,14 +3224,24 @@ var init_update_file = __esm({
3223
3224
  update_file = async (args) => {
3224
3225
  const parsed = parseArgs(args);
3225
3226
  const targetPath = parsed.path;
3226
- let content_to_replace = parsed.content_to_replace !== void 0 ? parsed.content_to_replace : parsed.replaceContent;
3227
- let content_to_add = parsed.content_to_add !== void 0 ? parsed.content_to_add : parsed.newContent;
3228
3227
  if (!targetPath) return 'ERROR: Missing "path" argument for update_file.';
3229
- if (content_to_replace === void 0) return 'ERROR: Missing "replaceContent" argument.';
3230
- if (content_to_add === void 0) return 'ERROR: Missing "newContent" argument.';
3228
+ const patchPairs = [];
3229
+ const legacyReplace = parsed.content_to_replace !== void 0 ? parsed.content_to_replace : parsed.replaceContent;
3230
+ const legacyNew = parsed.content_to_add !== void 0 ? parsed.content_to_add : parsed.newContent;
3231
+ if (legacyReplace !== void 0 && legacyNew !== void 0) {
3232
+ patchPairs.push({ replace: legacyReplace, new: legacyNew });
3233
+ }
3234
+ for (let i = 1; i <= 10; i++) {
3235
+ const r = parsed[`replaceContent${i}`];
3236
+ const n = parsed[`newContent${i}`];
3237
+ if (r !== void 0 && n !== void 0 && r !== legacyReplace) {
3238
+ patchPairs.push({ replace: r, new: n });
3239
+ }
3240
+ }
3241
+ if (patchPairs.length === 0) {
3242
+ return "ERROR: No valid replacement pairs found. Use replaceContent1, newContent1, etc.";
3243
+ }
3231
3244
  const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3232
- content_to_replace = strip(content_to_replace);
3233
- content_to_add = strip(content_to_add);
3234
3245
  const absolutePath = path9.resolve(process.cwd(), targetPath);
3235
3246
  try {
3236
3247
  if (!fs10.existsSync(absolutePath)) {
@@ -3238,122 +3249,164 @@ var init_update_file = __esm({
3238
3249
  }
3239
3250
  await RevertManager.recordFileChange(absolutePath);
3240
3251
  let diskContent = fs10.readFileSync(absolutePath, "utf8");
3241
- if (diskContent.startsWith("\uFEFF")) {
3242
- diskContent = diskContent.slice(1);
3243
- }
3244
- const normalizedDisk = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3245
- if (diskContent !== normalizedDisk) {
3246
- fs10.writeFileSync(absolutePath, normalizedDisk, "utf8");
3247
- diskContent = normalizedDisk;
3248
- }
3249
- const currentContent = diskContent;
3250
- const adjustIndentation = (newText, originalMatch, leadingContext = "") => {
3251
- if (!newText || originalMatch === void 0) return newText;
3252
- const getIndent = (line) => line.match(/^\s*/)[0];
3253
- const getMinIndent = (text) => {
3254
- const lines = text.split("\n").filter((l) => l.trim() !== "");
3255
- if (lines.length === 0) return "";
3256
- let min = getIndent(lines[0]);
3257
- for (const line of lines) {
3258
- const indent = getIndent(line);
3259
- if (indent.length < min.length) min = indent;
3260
- }
3261
- return min;
3252
+ if (diskContent.startsWith("\uFEFF")) diskContent = diskContent.slice(1);
3253
+ let currentFileContent = diskContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3254
+ const results = [];
3255
+ let totalInstances = 0;
3256
+ for (let i = 0; i < patchPairs.length; i++) {
3257
+ const pair = patchPairs[i];
3258
+ const content_to_replace = strip(pair.replace);
3259
+ const content_to_add = strip(pair.new);
3260
+ const adjustIndentation = (newText, originalMatch, leadingContext2 = "") => {
3261
+ if (!newText || originalMatch === void 0) return newText;
3262
+ const getIndent = (line) => line.match(/^\s*/)[0];
3263
+ const getMinIndent = (text) => {
3264
+ const lines = text.split("\n").filter((l) => l.trim() !== "");
3265
+ if (lines.length === 0) return "";
3266
+ let min = getIndent(lines[0]);
3267
+ for (const line of lines) {
3268
+ const indent = getIndent(line);
3269
+ if (indent.length < min.length) min = indent;
3270
+ }
3271
+ return min;
3272
+ };
3273
+ const matchBaseIndent = getMinIndent(originalMatch);
3274
+ const targetBaseIndent = leadingContext2.match(/^\s*/)[0] + matchBaseIndent;
3275
+ const newBaseIndent = getMinIndent(newText);
3276
+ const delta = targetBaseIndent.length - newBaseIndent.length;
3277
+ const indentChar = (targetBaseIndent.match(/\s/) || originalMatch.match(/\s/) || [" "])[0];
3278
+ const newLines = newText.split("\n");
3279
+ return newLines.map((line, i2) => {
3280
+ if (line.trim() === "" && i2 !== 0) return "";
3281
+ const currentLineIndent = getIndent(line).length;
3282
+ const shiftedIndentLength = Math.max(0, currentLineIndent + delta);
3283
+ const prependedIndentLength = i2 === 0 ? Math.max(0, shiftedIndentLength - leadingContext2.length) : shiftedIndentLength;
3284
+ return indentChar.repeat(prependedIndentLength) + line.trimStart();
3285
+ }).join("\n");
3262
3286
  };
3263
- const matchBaseIndent = getMinIndent(originalMatch);
3264
- const targetBaseIndent = leadingContext.match(/^\s*/)[0] + matchBaseIndent;
3265
- const newBaseIndent = getMinIndent(newText);
3266
- const delta = targetBaseIndent.length - newBaseIndent.length;
3267
- const indentChar = (targetBaseIndent.match(/\s/) || originalMatch.match(/\s/) || [" "])[0];
3268
- const newLines = newText.split("\n");
3269
- return newLines.map((line, i) => {
3270
- if (line.trim() === "" && i !== 0) return "";
3271
- const currentLineIndent = getIndent(line).length;
3272
- const shiftedIndentLength = Math.max(0, currentLineIndent + delta);
3273
- const prependedIndentLength = i === 0 ? Math.max(0, shiftedIndentLength - leadingContext.length) : shiftedIndentLength;
3274
- return indentChar.repeat(prependedIndentLength) + line.trimStart();
3275
- }).join("\n");
3276
- };
3277
- let instances = 0;
3278
- let startPos = -1;
3279
- let matchRegex = null;
3280
- const exactPattern = content_to_replace.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3281
- if (content_to_replace !== "" && currentContent.includes(content_to_replace)) {
3282
- matchRegex = new RegExp(exactPattern, "g");
3283
- } else {
3284
- const fuzzyLines = content_to_replace.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => line.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\s+/g, "\\s*"));
3285
- if (fuzzyLines.length > 0) {
3286
- const fuzzyPattern = fuzzyLines.join("\\s*");
3287
- try {
3288
- matchRegex = new RegExp(fuzzyPattern, "g");
3289
- } catch (e) {
3287
+ const exactPattern = content_to_replace.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3288
+ let matchRegex = null;
3289
+ if (content_to_replace !== "" && currentFileContent.includes(content_to_replace)) {
3290
+ matchRegex = new RegExp(exactPattern, "g");
3291
+ } else {
3292
+ const fuzzyLines = content_to_replace.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => line.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\s+/g, "\\s*"));
3293
+ if (fuzzyLines.length > 0) {
3294
+ const fuzzyPattern = fuzzyLines.join("\\s*");
3295
+ try {
3296
+ matchRegex = new RegExp(fuzzyPattern, "g");
3297
+ } catch (e) {
3298
+ matchRegex = new RegExp(exactPattern, "g");
3299
+ }
3300
+ } else {
3290
3301
  matchRegex = new RegExp(exactPattern, "g");
3291
3302
  }
3292
- } else {
3293
- matchRegex = new RegExp(exactPattern, "g");
3294
3303
  }
3304
+ const matches = [...currentFileContent.matchAll(matchRegex)];
3305
+ if (matches.length === 0) {
3306
+ results.push({ success: false, error: `Block ${i + 1}: Could not find match.` });
3307
+ continue;
3308
+ }
3309
+ if (matches.length > 1) {
3310
+ results.push({ success: false, error: `Block ${i + 1}: Found ${matches.length} matches (must be unique).` });
3311
+ continue;
3312
+ }
3313
+ const startPos = matches[0].index;
3314
+ const firstMatchContent = matches[0][0];
3315
+ const lineStart = currentFileContent.lastIndexOf("\n", startPos) + 1;
3316
+ const leadingContext = currentFileContent.substring(lineStart, startPos);
3317
+ const finalReplacement = adjustIndentation(content_to_add, firstMatchContent, leadingContext);
3318
+ const allOriginalLines = currentFileContent.split("\n");
3319
+ const patchStartLine = currentFileContent.substring(0, startPos).split("\n").length;
3320
+ const patchOldLines = firstMatchContent.split("\n");
3321
+ const contextBefore = [];
3322
+ for (let j = Math.max(0, patchStartLine - 4); j < patchStartLine - 1; j++) {
3323
+ contextBefore.push({ num: j + 1, text: allOriginalLines[j] });
3324
+ }
3325
+ const contextAfter = [];
3326
+ const patchEndLineIdx = patchStartLine + patchOldLines.length - 1;
3327
+ for (let j = patchEndLineIdx; j < Math.min(allOriginalLines.length, patchEndLineIdx + 3); j++) {
3328
+ contextAfter.push({ num: j + 1, text: allOriginalLines[j] });
3329
+ }
3330
+ results.push({
3331
+ success: true,
3332
+ startPos,
3333
+ oldContent: firstMatchContent,
3334
+ newContent: finalReplacement,
3335
+ originalStartLine: patchStartLine,
3336
+ contextBefore,
3337
+ contextAfter
3338
+ });
3339
+ currentFileContent = currentFileContent.substring(0, startPos) + finalReplacement + currentFileContent.substring(startPos + firstMatchContent.length);
3340
+ totalInstances++;
3295
3341
  }
3296
- const matches = matchRegex ? [...currentContent.matchAll(matchRegex)] : [];
3297
- instances = matches.length;
3298
- if (instances === 0) {
3299
- return `ERROR: Could not find match for "content_to_replace" in [${targetPath}]. Check for whitespace discrepancies or ReadFile to get exact content.`;
3300
- }
3301
- if (instances > 1) {
3302
- return `ERROR: Unable to find unique match. [${instances}] instances of the specified "content_to_replace" were found in [${targetPath}]. Try providing more context (surrounding lines) to make the match unique.`;
3342
+ if (totalInstances === 0) {
3343
+ return `ERROR: Failed to apply any patches to [${targetPath}].
3344
+ ${results.map((r) => r.error).join("\n")}`;
3303
3345
  }
3304
- startPos = matches[0].index;
3305
- const firstMatchContent = matches[0][0];
3306
- const newFileContent = currentContent.replace(matchRegex, (match, offset) => {
3307
- const lineStart = currentContent.lastIndexOf("\n", offset) + 1;
3308
- const leadingContext = currentContent.substring(lineStart, offset);
3309
- return adjustIndentation(content_to_add, match, leadingContext);
3310
- });
3311
- const firstLineStart = currentContent.lastIndexOf("\n", startPos) + 1;
3312
- const firstLeadingContext = currentContent.substring(firstLineStart, startPos);
3313
- const finalContentToAdd = adjustIndentation(content_to_add, firstMatchContent, firstLeadingContext);
3314
- const finalContentToReplace = firstMatchContent;
3315
- fs10.writeFileSync(absolutePath, newFileContent, "utf8");
3316
- const allOriginalLines = currentContent.split(/\r?\n/);
3317
- const startLine = currentContent.substring(0, startPos).split(/\r?\n/).length;
3318
- const oldLines = content_to_replace.split(/\r?\n/);
3319
- const endLine = startLine + oldLines.length - 1;
3320
- let diffText = `SUCCESS: File [${targetPath}] updated. [${instances}] instances replaced.
3346
+ fs10.writeFileSync(absolutePath, currentFileContent, "utf8");
3347
+ let diffText = `SUCCESS: File [${targetPath}] updated. [${totalInstances}/${patchPairs.length}] blocks applied.
3321
3348
 
3322
3349
  `;
3323
3350
  diffText += `[DIFF_START]
3324
3351
  `;
3325
- const contextStart = Math.max(0, startLine - 16);
3326
- for (let i = contextStart; i < startLine - 1; i++) {
3327
- diffText += `[UI_CONTEXT] ${i + 1}|${allOriginalLines[i]}
3352
+ const terminalWidth = process.stdout.columns || 100;
3353
+ const separatorLine = "\u2550".repeat(Math.max(20, terminalWidth - 12));
3354
+ const allLinesFinal = currentFileContent.split("\n");
3355
+ const successfulPatches = results.filter((r) => r.success);
3356
+ successfulPatches.forEach((res, idx) => {
3357
+ if (idx === 0) {
3358
+ res.contextBefore.forEach((ctx) => {
3359
+ diffText += `[UI_CONTEXT] ${ctx.num} |${ctx.text}
3328
3360
  `;
3329
- }
3330
- const lineStartPos = currentContent.lastIndexOf("\n", startPos) + 1;
3331
- const affectedEndPos = startPos + content_to_replace.length;
3332
- const lineEndPos = currentContent.indexOf("\n", affectedEndPos);
3333
- const actualEndPos = lineEndPos === -1 ? currentContent.length : lineEndPos;
3334
- const fullOldLines = currentContent.substring(lineStartPos, actualEndPos).split("\n");
3335
- const newAffectedEndPos = startPos + finalContentToAdd.length;
3336
- const newLineEndPos = newFileContent.indexOf("\n", newAffectedEndPos);
3337
- const actualNewEndPos = newLineEndPos === -1 ? newFileContent.length : newLineEndPos;
3338
- const fullNewLines = newFileContent.substring(lineStartPos, actualNewEndPos).split("\n");
3339
- fullOldLines.forEach((line, i) => {
3340
- diffText += `-${startLine + i}|${line}
3361
+ });
3362
+ } else {
3363
+ const prev = successfulPatches[idx - 1];
3364
+ const prevLinesCount = prev.newContent.split("\n").length;
3365
+ const prevEndLine = prev.originalStartLine + prevLinesCount - 1;
3366
+ const gap = res.originalStartLine - prevEndLine - 1;
3367
+ if (gap >= 1 && gap < 12) {
3368
+ for (let j = prevEndLine; j < res.originalStartLine - 1; j++) {
3369
+ diffText += `[UI_CONTEXT] ${j + 1} |${allLinesFinal[j]}
3341
3370
  `;
3342
- });
3343
- let currentNewLine = startLine;
3344
- fullNewLines.forEach((line) => {
3345
- diffText += `+${currentNewLine}|${line}
3371
+ }
3372
+ } else if (gap >= 12) {
3373
+ prev.contextAfter.forEach((ctx) => {
3374
+ diffText += `[UI_CONTEXT] ${ctx.num} |${ctx.text}
3346
3375
  `;
3347
- currentNewLine++;
3348
- });
3349
- const linesAffected = fullOldLines.length;
3350
- const originalContextIdx = startLine + linesAffected - 1;
3351
- for (let i = originalContextIdx; i < Math.min(allOriginalLines.length, originalContextIdx + 15); i++) {
3352
- diffText += `[UI_CONTEXT] ${currentNewLine}|${allOriginalLines[i]}
3376
+ });
3377
+ diffText += `[UI_CONTEXT] ${separatorLine}
3353
3378
  `;
3354
- currentNewLine++;
3355
- }
3379
+ res.contextBefore.forEach((ctx) => {
3380
+ diffText += `[UI_CONTEXT] ${ctx.num} |${ctx.text}
3381
+ `;
3382
+ });
3383
+ }
3384
+ }
3385
+ const oldLines = res.oldContent.split("\n");
3386
+ const newLines = res.newContent.split("\n");
3387
+ oldLines.forEach((line, i) => {
3388
+ diffText += `-${res.originalStartLine + i}|${line}
3389
+ `;
3390
+ });
3391
+ newLines.forEach((line, i) => {
3392
+ diffText += `+${res.originalStartLine + i}|${line}
3393
+ `;
3394
+ });
3395
+ if (idx === successfulPatches.length - 1) {
3396
+ res.contextAfter.forEach((ctx) => {
3397
+ diffText += `[UI_CONTEXT] ${ctx.num} |${ctx.text}
3398
+ `;
3399
+ });
3400
+ }
3401
+ });
3356
3402
  diffText += `[DIFF_END]`;
3403
+ const errors = results.filter((r) => !r.success);
3404
+ if (errors.length > 0) {
3405
+ diffText += `
3406
+
3407
+ \u26A0\uFE0F WARNING: Some blocks failed:
3408
+ ${errors.map((e) => ` \u2022 ${e.error}`).join("\n")}`;
3409
+ }
3357
3410
  return diffText;
3358
3411
  } catch (err) {
3359
3412
  return `ERROR: Failed to update file [${targetPath}]: ${err.message}`;
@@ -3364,15 +3417,26 @@ var init_update_file = __esm({
3364
3417
 
3365
3418
  // src/tools/exec_command.js
3366
3419
  import { spawn } from "child_process";
3367
- var activeChildProcess, writeToActiveCommand, terminateActiveCommand, adjustWindowsCommand, exec_command;
3420
+ var pty, activeChildProcess, isActiveCommandPty, writeToActiveCommand, terminateActiveCommand, adjustWindowsCommand, exec_command, runStandardSpawn;
3368
3421
  var init_exec_command = __esm({
3369
- "src/tools/exec_command.js"() {
3422
+ async "src/tools/exec_command.js"() {
3370
3423
  init_arg_parser();
3424
+ pty = null;
3425
+ try {
3426
+ const ptyModule = await import("node-pty");
3427
+ pty = ptyModule.default || ptyModule;
3428
+ } catch (err) {
3429
+ }
3371
3430
  activeChildProcess = null;
3431
+ isActiveCommandPty = false;
3372
3432
  writeToActiveCommand = (data) => {
3373
3433
  try {
3374
- if (activeChildProcess && activeChildProcess.stdin && activeChildProcess.stdin.writable) {
3375
- activeChildProcess.stdin.write(data);
3434
+ if (activeChildProcess) {
3435
+ if (isActiveCommandPty && typeof activeChildProcess.write === "function") {
3436
+ activeChildProcess.write(data);
3437
+ } else if (activeChildProcess.stdin && activeChildProcess.stdin.writable) {
3438
+ activeChildProcess.stdin.write(data);
3439
+ }
3376
3440
  }
3377
3441
  } catch (err) {
3378
3442
  }
@@ -3380,13 +3444,18 @@ var init_exec_command = __esm({
3380
3444
  terminateActiveCommand = () => {
3381
3445
  if (activeChildProcess) {
3382
3446
  try {
3383
- activeChildProcess.kill("SIGKILL");
3447
+ if (isActiveCommandPty && typeof activeChildProcess.destroy === "function") {
3448
+ activeChildProcess.destroy();
3449
+ } else if (typeof activeChildProcess.kill === "function") {
3450
+ activeChildProcess.kill("SIGKILL");
3451
+ }
3384
3452
  } catch (err) {
3385
3453
  }
3386
3454
  activeChildProcess = null;
3455
+ isActiveCommandPty = false;
3387
3456
  }
3388
3457
  };
3389
- adjustWindowsCommand = (command) => {
3458
+ adjustWindowsCommand = (command, usePowerShell = false) => {
3390
3459
  if (process.platform !== "win32") return command;
3391
3460
  const tokens = [];
3392
3461
  let current = "";
@@ -3423,7 +3492,7 @@ var init_exec_command = __esm({
3423
3492
  tokens.push(current);
3424
3493
  current = "";
3425
3494
  }
3426
- tokens.push("&");
3495
+ tokens.push(usePowerShell ? ";" : "&");
3427
3496
  } else if (char === "|" && !current.includes("://")) {
3428
3497
  if (current.length > 0) {
3429
3498
  tokens.push(current);
@@ -3516,7 +3585,7 @@ var init_exec_command = __esm({
3516
3585
  const { command: rawCommand } = parseArgs(args);
3517
3586
  const { onChunk } = options;
3518
3587
  if (!rawCommand) return 'ERROR: Missing "command" argument for exec_command.';
3519
- const command = adjustWindowsCommand(rawCommand);
3588
+ const isWin = process.platform === "win32";
3520
3589
  const systemSettings = options.systemSettings || {};
3521
3590
  const netEnv = {};
3522
3591
  if (systemSettings.networkAccess === false) {
@@ -3529,58 +3598,127 @@ var init_exec_command = __esm({
3529
3598
  netEnv.NO_PROXY = "localhost,127.0.0.1";
3530
3599
  }
3531
3600
  return new Promise((resolve) => {
3532
- const child = spawn(command, {
3533
- shell: true,
3534
- cwd: process.cwd(),
3535
- env: {
3536
- ...process.env,
3537
- CI: "false",
3538
- TERM: "xterm-256color",
3539
- FORCE_COLOR: "1",
3540
- ...netEnv
3601
+ const attempt = (usePowerShell) => {
3602
+ const command = adjustWindowsCommand(rawCommand, usePowerShell);
3603
+ const shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
3604
+ const shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
3605
+ if (pty) {
3606
+ try {
3607
+ const ptyProcess = pty.spawn(shell, shellArgs, {
3608
+ name: "xterm-256color",
3609
+ cols: options.cols || 120,
3610
+ rows: options.rows || 30,
3611
+ cwd: process.cwd(),
3612
+ env: {
3613
+ ...process.env,
3614
+ CI: "false",
3615
+ TERM: "xterm-256color",
3616
+ FORCE_COLOR: "1",
3617
+ ...netEnv
3618
+ }
3619
+ });
3620
+ activeChildProcess = ptyProcess;
3621
+ isActiveCommandPty = true;
3622
+ let output = "";
3623
+ ptyProcess.onData((data) => {
3624
+ output += data;
3625
+ if (onChunk) onChunk(data);
3626
+ });
3627
+ ptyProcess.onExit(({ exitCode }) => {
3628
+ activeChildProcess = null;
3629
+ const finalOutput = output || "Command executed with no output.";
3630
+ if (exitCode !== 0) {
3631
+ resolve(`ERROR: Command [${rawCommand}] failed with exit code [${exitCode}].
3632
+
3633
+ ${finalOutput}`);
3634
+ } else {
3635
+ resolve(`SUCCESS: Command [${rawCommand}] completed.
3636
+
3637
+ ${finalOutput}`);
3638
+ }
3639
+ });
3640
+ return true;
3641
+ } catch (err) {
3642
+ if (isWin && usePowerShell && err.code === "ENOENT") {
3643
+ return false;
3644
+ }
3645
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell);
3646
+ return true;
3647
+ }
3648
+ } else {
3649
+ runStandardSpawn(resolve, command, rawCommand, netEnv, onChunk, usePowerShell);
3650
+ return true;
3541
3651
  }
3542
- });
3543
- activeChildProcess = child;
3544
- if (child.stdin) {
3545
- child.stdin.on("error", () => {
3546
- activeChildProcess = null;
3547
- });
3652
+ };
3653
+ if (isWin) {
3654
+ if (!attempt(true)) {
3655
+ attempt(false);
3656
+ }
3657
+ } else {
3658
+ attempt(false);
3548
3659
  }
3549
- let stdout = "";
3550
- let stderr = "";
3551
- child.stdout.on("data", (data) => {
3552
- const chunk = data.toString();
3553
- stdout += chunk;
3554
- if (onChunk) onChunk(chunk);
3555
- });
3556
- child.stderr.on("data", (data) => {
3557
- const chunk = data.toString();
3558
- stderr += chunk;
3559
- if (onChunk) onChunk(chunk);
3560
- });
3561
- child.on("close", (code) => {
3660
+ });
3661
+ };
3662
+ runStandardSpawn = (resolve, command, rawCommand, netEnv, onChunk, usePowerShell = true) => {
3663
+ const isWin = process.platform === "win32";
3664
+ const shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
3665
+ const shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
3666
+ const child = isWin ? spawn(shell, shellArgs, { cwd: process.cwd(), env: { ...process.env, ...netEnv } }) : spawn(command, {
3667
+ shell: true,
3668
+ cwd: process.cwd(),
3669
+ env: {
3670
+ ...process.env,
3671
+ CI: "false",
3672
+ TERM: "xterm-256color",
3673
+ FORCE_COLOR: "1",
3674
+ ...netEnv
3675
+ }
3676
+ });
3677
+ activeChildProcess = child;
3678
+ isActiveCommandPty = false;
3679
+ if (child.stdin) {
3680
+ child.stdin.on("error", () => {
3562
3681
  activeChildProcess = null;
3563
- const result = [];
3564
- if (stdout) result.push(`STDOUT:
3682
+ });
3683
+ }
3684
+ let stdout = "";
3685
+ let stderr = "";
3686
+ child.stdout.on("data", (data) => {
3687
+ const chunk = data.toString();
3688
+ stdout += chunk;
3689
+ if (onChunk) onChunk(chunk);
3690
+ });
3691
+ child.stderr.on("data", (data) => {
3692
+ const chunk = data.toString();
3693
+ stderr += chunk;
3694
+ if (onChunk) onChunk(chunk);
3695
+ });
3696
+ child.on("close", (code) => {
3697
+ activeChildProcess = null;
3698
+ const result = [];
3699
+ if (stdout) result.push(`STDOUT:
3565
3700
  ${stdout}`);
3566
- if (stderr) result.push(`STDERR:
3701
+ if (stderr) result.push(`STDERR:
3567
3702
  ${stderr}`);
3568
- if (code !== 0) result.push(`EXIT CODE: ${code}`);
3569
- const finalOutput = result.join("\n\n") || "Command executed with no output.";
3570
- if (code !== 0) {
3571
- resolve(`ERROR: Command [${rawCommand}] failed with exit code [${code}].
3703
+ if (code !== 0) result.push(`EXIT CODE: ${code}`);
3704
+ const finalOutput = result.join("\n\n") || "Command executed with no output.";
3705
+ if (code !== 0) {
3706
+ resolve(`ERROR: Command [${rawCommand}] failed with exit code [${code}].
3572
3707
 
3573
3708
  ${finalOutput}`);
3574
- } else {
3575
- resolve(`SUCCESS: Command [${rawCommand}] completed.
3709
+ } else {
3710
+ resolve(`SUCCESS: Command [${rawCommand}] completed.
3576
3711
 
3577
3712
  ${finalOutput}`);
3578
- }
3579
- });
3580
- child.on("error", (err) => {
3581
- activeChildProcess = null;
3582
- resolve(`ERROR: Failed to start command [${rawCommand}]: ${err.message}`);
3583
- });
3713
+ }
3714
+ });
3715
+ child.on("error", (err) => {
3716
+ if (isWin && usePowerShell && err.code === "ENOENT") {
3717
+ const cmdCommand = adjustWindowsCommand(rawCommand, false);
3718
+ return runStandardSpawn(resolve, cmdCommand, rawCommand, netEnv, onChunk, false);
3719
+ }
3720
+ activeChildProcess = null;
3721
+ resolve(`ERROR: Failed to start command [${rawCommand}]: ${err.message}`);
3584
3722
  });
3585
3723
  };
3586
3724
  }
@@ -3916,33 +4054,44 @@ var init_search_keyword = __esm({
3916
4054
  "src/tools/search_keyword.js"() {
3917
4055
  init_arg_parser();
3918
4056
  search_keyword = async (args) => {
3919
- const { keyword } = parseArgs(args);
4057
+ const { keyword, file } = parseArgs(args);
3920
4058
  if (!keyword) return 'ERROR: Missing "keyword" argument.';
3921
4059
  const isWindows = process.platform === "win32";
3922
4060
  const excludes = ["node_modules", ".git", "dist", ".next", ".gemini"];
3923
4061
  let command = "";
3924
- if (isWindows) {
3925
- const excludePattern = excludes.join("|").replace(/\./g, "\\.");
3926
- command = `powershell -Command "Get-ChildItem -Path . -Recurse -File | Where-Object { $_.FullName -notmatch '${excludePattern}' } | Select-String -Pattern '${keyword}' | Select-Object -First 150 | ForEach-Object { $rel = Resolve-Path $_.Path -Relative; '{0}:{1}:' -f $rel, $_.LineNumber }"`;
4062
+ if (file) {
4063
+ if (isWindows) {
4064
+ command = `powershell -Command "if (Test-Path '${file}') { Select-String -Path '${file}' -Pattern '${keyword}' | Select-Object -First 150 | ForEach-Object { $rel = Resolve-Path $_.Path -Relative; '{0}:{1}:' -f $rel, $_.LineNumber } } else { Write-Error 'File not found: ${file}' }"`;
4065
+ } else {
4066
+ command = `grep -HnI "${keyword}" "${file}" | head -n 150`;
4067
+ }
3927
4068
  } else {
3928
- const excludeDirArgs = excludes.map((d) => `--exclude-dir="${d}"`).join(" ");
3929
- command = `grep -rnI ${excludeDirArgs} "${keyword}" . | head -n 150`;
4069
+ if (isWindows) {
4070
+ const excludePattern = excludes.join("|").replace(/\./g, "\\.");
4071
+ command = `powershell -Command "Get-ChildItem -Path . -Recurse -File | Where-Object { $_.FullName -notmatch '${excludePattern}' } | Select-String -Pattern '${keyword}' | Select-Object -First 150 | ForEach-Object { $rel = Resolve-Path $_.Path -Relative; '{0}:{1}:' -f $rel, $_.LineNumber }"`;
4072
+ } else {
4073
+ const excludeDirArgs = excludes.map((d) => `--exclude-dir="${d}"`).join(" ");
4074
+ command = `grep -rnI ${excludeDirArgs} "${keyword}" . | head -n 150`;
4075
+ }
3930
4076
  }
3931
4077
  return new Promise((resolve) => {
3932
4078
  exec(command, { cwd: process.cwd(), maxBuffer: 15 * 1024 * 1024 }, (error, stdout, stderr) => {
4079
+ if (error && stderr && stderr.includes("File not found")) {
4080
+ return resolve(`ERROR: File not found: ${file}`);
4081
+ }
3933
4082
  if (error && error.code === 1 && !stdout) {
3934
- return resolve(`Found 0 matches for keyword: "${keyword}"`);
4083
+ return resolve(`Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ""}`);
3935
4084
  }
3936
4085
  if (error && !stdout) {
3937
4086
  return resolve(`ERROR: ${stderr || error.message}`);
3938
4087
  }
3939
4088
  const rawLines = stdout.trim().split("\n").filter((l) => l.trim() !== "");
3940
- if (rawLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"`);
4089
+ if (rawLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ""}`);
3941
4090
  const filteredLines = rawLines.filter((line) => {
3942
4091
  const lower = line.toLowerCase();
3943
4092
  return !lower.includes("node_modules") && !lower.includes(".git") && !lower.includes("dist") && !lower.includes(".next") && !lower.includes(".gemini");
3944
4093
  });
3945
- if (filteredLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"`);
4094
+ if (filteredLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"${file ? ` in file: ${file}` : ""}`);
3946
4095
  const matches = filteredLines.slice(0, 150).map((line) => {
3947
4096
  const firstColon = line.indexOf(":");
3948
4097
  const secondColon = line.indexOf(":", firstColon + 1);
@@ -4385,7 +4534,7 @@ var init_addMemScore = __esm({
4385
4534
  // src/utils/tools.js
4386
4535
  var TOOL_MAP, dispatchTool;
4387
4536
  var init_tools = __esm({
4388
- "src/utils/tools.js"() {
4537
+ async "src/utils/tools.js"() {
4389
4538
  init_web_search();
4390
4539
  init_web_scrape();
4391
4540
  init_memory();
@@ -4393,7 +4542,7 @@ var init_tools = __esm({
4393
4542
  init_view_file();
4394
4543
  init_write_file();
4395
4544
  init_update_file();
4396
- init_exec_command();
4545
+ await init_exec_command();
4397
4546
  init_read_folder();
4398
4547
  init_ask_user();
4399
4548
  init_write_pdf();
@@ -4462,11 +4611,11 @@ import path15 from "path";
4462
4611
  import fs16 from "fs";
4463
4612
  var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, consolidatePastMemories, getAIStream;
4464
4613
  var init_ai = __esm({
4465
- "src/utils/ai.js"() {
4614
+ async "src/utils/ai.js"() {
4466
4615
  init_prompts();
4467
4616
  init_history();
4468
4617
  init_usage();
4469
- init_tools();
4618
+ await init_tools();
4470
4619
  init_crypto();
4471
4620
  init_arg_parser();
4472
4621
  init_terminal();
@@ -5015,7 +5164,7 @@ ${newMemoryListStr}
5015
5164
  const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
5016
5165
  const memoryPrompt = getMemoryPrompt(otherMemories, mainUserMemories, isMemoryEnabled, isContext32k);
5017
5166
  const dateTimeStr = (/* @__PURE__ */ new Date()).toLocaleString([], { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", hour12: true });
5018
- const getDirTree = (dir, prefix = "") => {
5167
+ const getDirTree = (dir, prefix = "", depth = 1) => {
5019
5168
  try {
5020
5169
  const files = fs16.readdirSync(dir);
5021
5170
  const sep = path15.sep;
@@ -5052,13 +5201,13 @@ ${newMemoryListStr}
5052
5201
  const stat = fs16.statSync(filePath);
5053
5202
  if (stat.isDirectory()) {
5054
5203
  const subFiles = fs16.readdirSync(filePath);
5055
- if (subFiles.length > 80) {
5204
+ if (subFiles.length > 80 || depth >= 7) {
5056
5205
  result += `${prefix}${connector}${file}${sep}...
5057
5206
  `;
5058
5207
  } else {
5059
5208
  result += `${prefix}${connector}${file}${sep}
5060
5209
  `;
5061
- result += getDirTree(filePath, childPrefix);
5210
+ result += getDirTree(filePath, childPrefix, depth + 1);
5062
5211
  }
5063
5212
  } else {
5064
5213
  result += `${prefix}${connector}${file}
@@ -5076,7 +5225,7 @@ ${newMemoryListStr}
5076
5225
  };
5077
5226
  yield { type: "status", content: "Gathering Context..." };
5078
5227
  let dirStructure = process.cwd() + "\n" + getDirTree(process.cwd());
5079
- const firstUserMsg = `[METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v${versionFluxflow2}
5228
+ const firstUserMsg = `[SYSTEM METADATA (PRIORITY: DYNAMIC)] Time: ${dateTimeStr} | v${versionFluxflow2}
5080
5229
  CWD: ${process.cwd()}
5081
5230
  **DIRECTORY STRUCTURE**
5082
5231
  ${dirStructure}
@@ -5178,8 +5327,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITI
5178
5327
  }
5179
5328
  const currentSystemInstruction = getSystemInstruction(profile, thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
5180
5329
  const jitInstruction = `
5181
-
5182
- [SYSTEM] Tool result received. Analyze output and proceed with your turn.${thinkingLevel != "Fast" ? "**STRICTLY MAINTAIN THINKING POLICY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**" : ""}`;
5330
+ [SYSTEM] Tool result received. Analyze output and proceed with your turn${thinkingLevel != "Fast" ? ". **STRICTLY MAINTAIN THINKING POLICY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**" : ""}`;
5183
5331
  const lastUserMsg = contents[contents.length - 1];
5184
5332
  let addedMarker = false;
5185
5333
  if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL RESULT]")) {
@@ -5800,7 +5948,7 @@ ${boxBottom}` };
5800
5948
  const waitTime = Math.min(1e3 * Math.pow(2, inStreamRetryCount - 1), 24e3);
5801
5949
  if (turnText.trim().length > 0) {
5802
5950
  modifiedHistory.push({ role: "agent", text: turnText });
5803
- const recoveryText = "[SYSTEM: STREAM RECOVERY]\n- SEAMLESS CONTINUATION: Resume immediately. Pick up from last words with zero gap/disruption.\n- NO REPETITION: Do not repeat any text already written.\n- NO RE-THINK: Do not restart or open <think> if reasoning already started.\n- MID-TOOL SAFETY: If cutoff was mid-tool call, restart that tool call from start.\n- STEALTH: Do not mention/apologize for cutoff.\n- KEEP LENGTH: Maintain standard depth/length.";
5951
+ const recoveryText = "[SYSTEM]\n- SEAMLESS CONTINUATION: Resume immediately. Pick up from last words with zero gap/disruption\n- NO REPETITION: Do not repeat any text already written\n- NO RE-THINK: Do not restart or open <think> if reasoning already started. Continue the thinking and close thinking block with </think> if opened\n- MID-TOOL SAFETY: If cutoff was mid-tool call, restart that tool call from start\n- STEALTH: Do not mention/apologize for cutoff";
5804
5952
  if (toolResults.length > 0) {
5805
5953
  toolResults.forEach((tr, idx) => {
5806
5954
  if (idx === toolResults.length - 1) {
@@ -5820,7 +5968,7 @@ ${recoveryText}`
5820
5968
  accumulatedContext += turnText;
5821
5969
  }
5822
5970
  for (let i = waitTime / 1e3; i > 0; i--) {
5823
- yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [${i}s]...` };
5971
+ yield { type: "status", content: `Error Occured. Recovering Stream (${inStreamRetryCount}/${MAX_RETRIES}) [Retrying in ${i}s]...` };
5824
5972
  await new Promise((resolve) => setTimeout(resolve, 1e3));
5825
5973
  }
5826
5974
  yield { type: "status", content: `Error Occured. Recovering Stream...` };
@@ -5835,14 +5983,14 @@ Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
5835
5983
  accumulatedContext = "";
5836
5984
  const waitTime = Math.min(1e3 * Math.pow(2, retryCount - 1), 32e3);
5837
5985
  isInitialAttempt = true;
5838
- yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${(waitTime / 1e3).toFixed(0)}s]...` };
5986
+ yield { type: "status", content: `Trying to reach ${modelName} (${retryCount}/${MAX_RETRIES}) [Retrying in ${(waitTime / 1e3).toFixed(0)}s]...` };
5839
5987
  for (let i = waitTime / 1e3; i > 0; i--) {
5840
- yield { type: "status", content: `Retrying Connection (${retryCount}/${MAX_RETRIES}) [${i}s]...` };
5988
+ yield { type: "status", content: `Trying to reach ${modelName} (${retryCount}/${MAX_RETRIES}) [Retrying in ${i}s]...` };
5841
5989
  await new Promise((resolve) => setTimeout(resolve, 1e3));
5842
5990
  }
5843
- yield { type: "status", content: `Retrying Connection...` };
5991
+ yield { type: "status", content: `Trying to reach ${modelName}...` };
5844
5992
  } else {
5845
- throw new Error(`Model cannot be reached. (Failed ${MAX_RETRIES} times)
5993
+ throw new Error(`Model ${modelName} cannot be reached. (Failed ${MAX_RETRIES} times)
5846
5994
  Error Log can be found in ${path15.join(LOGS_DIR, "agent", "error.log")}`);
5847
5995
  }
5848
5996
  }
@@ -6092,15 +6240,28 @@ var init_MemoryModal = __esm({
6092
6240
  // src/components/UpdateProcessor.jsx
6093
6241
  import React11, { useState as useState8, useEffect as useEffect6 } from "react";
6094
6242
  import { Box as Box11, Text as Text11 } from "ink";
6095
- import Spinner from "ink-spinner";
6096
- import { exec as exec2 } from "child_process";
6097
- var UpdateProcessor, UpdateProcessor_default;
6243
+ import { spawn as spawn2 } from "child_process";
6244
+ var pty2, SPINNER_FRAMES, UpdateProcessor, UpdateProcessor_default;
6098
6245
  var init_UpdateProcessor = __esm({
6099
- "src/components/UpdateProcessor.jsx"() {
6246
+ async "src/components/UpdateProcessor.jsx"() {
6247
+ pty2 = null;
6248
+ try {
6249
+ const ptyModule = await import("node-pty");
6250
+ pty2 = ptyModule.default || ptyModule;
6251
+ } catch (err) {
6252
+ }
6253
+ SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6100
6254
  UpdateProcessor = ({ latest, current, settings, onClose, onUpdateSettings, onSuccess }) => {
6101
6255
  const [status, setStatus] = useState8("initializing");
6102
6256
  const [log, setLog] = useState8("");
6103
6257
  const [error, setError] = useState8(null);
6258
+ const [tick, setTick] = useState8(0);
6259
+ useEffect6(() => {
6260
+ const interval = setInterval(() => {
6261
+ setTick((t) => (t + 1) % 1e3);
6262
+ }, 33);
6263
+ return () => clearInterval(interval);
6264
+ }, []);
6104
6265
  useEffect6(() => {
6105
6266
  let child;
6106
6267
  const runUpdate = async () => {
@@ -6117,31 +6278,101 @@ var init_UpdateProcessor = __esm({
6117
6278
  else command = `npm install -g fluxflow-cli@${latest}`;
6118
6279
  setStatus("downloading");
6119
6280
  setLog(`Running: ${command}...`);
6120
- child = exec2(command, (err, stdout, stderr) => {
6121
- if (err) {
6122
- setError(stderr || err.message);
6123
- setStatus("error");
6124
- return;
6281
+ const isWin = process.platform === "win32";
6282
+ const executeCommand = (usePowerShell) => {
6283
+ return new Promise((resolve) => {
6284
+ const shell = isWin ? usePowerShell ? "powershell.exe" : "cmd.exe" : process.env.SHELL || "bash";
6285
+ const shellArgs = isWin ? usePowerShell ? ["-NoProfile", "-Command", command] : ["/c", command] : ["-c", command];
6286
+ const handleOutput = (data) => {
6287
+ const str = data.toString();
6288
+ const cleanStr = str.replace(/\x1B\[[0-?]*[ -/]*[@-~]|\x1B\][^\x07\x1B]*[\x07\x1B]|\b|\x07/g, "").replace(/\r/g, "").trim();
6289
+ if (cleanStr) {
6290
+ setLog((prev) => (prev + "\n" + cleanStr).split("\n").slice(-5).join("\n"));
6291
+ }
6292
+ };
6293
+ if (pty2) {
6294
+ try {
6295
+ const ptyProcess = pty2.spawn(shell, shellArgs, {
6296
+ name: "xterm-256color",
6297
+ cols: 80,
6298
+ rows: 30,
6299
+ cwd: process.cwd(),
6300
+ env: process.env
6301
+ });
6302
+ child = ptyProcess;
6303
+ ptyProcess.onData(handleOutput);
6304
+ ptyProcess.onExit(({ exitCode }) => {
6305
+ child = null;
6306
+ if (exitCode !== 0) {
6307
+ resolve({ error: `Process exited with code ${exitCode}` });
6308
+ } else {
6309
+ resolve({ success: true });
6310
+ }
6311
+ });
6312
+ return;
6313
+ } catch (err) {
6314
+ if (isWin && usePowerShell && err.code === "ENOENT") {
6315
+ resolve({ retryCmd: true });
6316
+ return;
6317
+ }
6318
+ }
6319
+ }
6320
+ const cp = isWin ? spawn2(shell, shellArgs, { cwd: process.cwd(), env: process.env }) : spawn2(command, { shell: true, cwd: process.cwd(), env: process.env });
6321
+ child = cp;
6322
+ cp.stdout.on("data", handleOutput);
6323
+ cp.stderr.on("data", handleOutput);
6324
+ cp.on("close", (code) => {
6325
+ child = null;
6326
+ if (code !== 0) {
6327
+ resolve({ error: `Process exited with code ${code}` });
6328
+ } else {
6329
+ resolve({ success: true });
6330
+ }
6331
+ });
6332
+ cp.on("error", (err) => {
6333
+ if (isWin && usePowerShell && err.code === "ENOENT") {
6334
+ resolve({ retryCmd: true });
6335
+ } else {
6336
+ child = null;
6337
+ resolve({ error: err.message });
6338
+ }
6339
+ });
6340
+ });
6341
+ };
6342
+ let result = {};
6343
+ if (isWin) {
6344
+ result = await executeCommand(true);
6345
+ if (result.retryCmd) {
6346
+ result = await executeCommand(false);
6125
6347
  }
6348
+ } else {
6349
+ result = await executeCommand(false);
6350
+ }
6351
+ if (result.error) {
6352
+ setError(result.error);
6353
+ setStatus("error");
6354
+ } else if (result.success) {
6126
6355
  setStatus("success");
6127
6356
  if (onSuccess) onSuccess();
6128
- });
6129
- child.stdout.on("data", (data) => {
6130
- setLog((prev) => (prev + "\n" + data).split("\n").slice(-5).join("\n"));
6131
- });
6357
+ }
6132
6358
  };
6133
6359
  runUpdate();
6134
6360
  return () => {
6135
6361
  if (child) {
6136
6362
  try {
6137
- child.kill();
6363
+ if (typeof child.destroy === "function") {
6364
+ child.destroy();
6365
+ } else if (typeof child.kill === "function") {
6366
+ child.kill();
6367
+ }
6138
6368
  } catch (e) {
6139
6369
  }
6140
6370
  }
6141
6371
  };
6142
6372
  }, []);
6143
6373
  if (status === "initializing" || status === "downloading") {
6144
- return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, /* @__PURE__ */ React11.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React11.createElement(Text11, { marginLeft: 1, bold: true }, " Updating Flux Flow to v", latest, "...")), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "#333" }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, log || "Preparing environment...")), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, dimColor: true }, "(Please do not close the terminal)"));
6374
+ const frame = SPINNER_FRAMES[Math.floor(tick / 3) % SPINNER_FRAMES.length];
6375
+ return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color: "magenta" }, frame), /* @__PURE__ */ React11.createElement(Text11, { marginLeft: 1, bold: true }, " Updating Flux Flow to v", latest, "...")), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "#333" }, /* @__PURE__ */ React11.createElement(Text11, { color: "gray", dimColor: true, italic: true }, log || "Preparing environment...")), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, dimColor: true }, "(Please do not close the terminal)"));
6145
6376
  }
6146
6377
  if (status === "success") {
6147
6378
  return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "green", bold: true }, "\u2705 UPDATE SUCCESSFUL!"), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1 }, "Flux Flow has been updated to ", /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, "v", latest), "."), /* @__PURE__ */ React11.createElement(Text11, { marginTop: 1, color: "yellow", bold: true }, "CRITICAL: Please restart your terminal session to apply changes."), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "(Press ESC to return to chat)")));
@@ -6241,13 +6472,13 @@ var init_RevertModal = __esm({
6241
6472
 
6242
6473
  // src/utils/setup.js
6243
6474
  import puppeteer4 from "puppeteer";
6244
- import { exec as exec3 } from "child_process";
6475
+ import { exec as exec2 } from "child_process";
6245
6476
  import { promisify } from "util";
6246
6477
  import fs17 from "fs";
6247
6478
  var execAsync, checkPuppeteerReady, installPuppeteerBrowser;
6248
6479
  var init_setup = __esm({
6249
6480
  "src/utils/setup.js"() {
6250
- execAsync = promisify(exec3);
6481
+ execAsync = promisify(exec2);
6251
6482
  checkPuppeteerReady = () => {
6252
6483
  try {
6253
6484
  const exePath = puppeteer4.executablePath();
@@ -6284,10 +6515,9 @@ __export(app_exports, {
6284
6515
  import os4 from "os";
6285
6516
  import React13, { useState as useState10, useEffect as useEffect7, useRef as useRef3, useMemo as useMemo2 } from "react";
6286
6517
  import { Box as Box13, Text as Text13, useInput as useInput7, useStdout } from "ink";
6287
- import Spinner2 from "ink-spinner";
6288
6518
  import fs18 from "fs-extra";
6289
6519
  import path16 from "path";
6290
- import { exec as exec4 } from "child_process";
6520
+ import { exec as exec3 } from "child_process";
6291
6521
  import { fileURLToPath } from "url";
6292
6522
  import TextInput4 from "ink-text-input";
6293
6523
  import gradient from "gradient-string";
@@ -6439,6 +6669,7 @@ function App({ args = [] }) {
6439
6669
  const [activeCommand, setActiveCommand] = useState10(null);
6440
6670
  const [execOutput, setExecOutput] = useState10("");
6441
6671
  const [isTerminalFocused, setIsTerminalFocused] = useState10(false);
6672
+ const [tick, setTick] = useState10(0);
6442
6673
  useEffect7(() => {
6443
6674
  if (apiTier !== "Free" && activeModel === "gemma-4-31b-it") {
6444
6675
  setActiveModel("gemini-3-flash-preview");
@@ -6579,13 +6810,17 @@ function App({ args = [] }) {
6579
6810
  if (key.return) {
6580
6811
  const isWin = process.platform === "win32";
6581
6812
  writeToActiveCommand(isWin ? "\r\n" : "\n");
6582
- setExecOutput((prev) => prev + "\n");
6813
+ if (!isActiveCommandPty) setExecOutput((prev) => prev + "\n");
6583
6814
  } else if (key.backspace || key.delete) {
6584
- writeToActiveCommand("\b \b");
6585
- setExecOutput((prev) => prev.slice(0, -1));
6815
+ if (isActiveCommandPty) {
6816
+ writeToActiveCommand("\x7F");
6817
+ } else {
6818
+ writeToActiveCommand("\b \b");
6819
+ setExecOutput((prev) => prev.slice(0, -1));
6820
+ }
6586
6821
  } else if (inputText) {
6587
6822
  writeToActiveCommand(inputText);
6588
- setExecOutput((prev) => prev + inputText);
6823
+ if (!isActiveCommandPty) setExecOutput((prev) => prev + inputText);
6589
6824
  }
6590
6825
  return;
6591
6826
  }
@@ -6634,17 +6869,21 @@ function App({ args = [] }) {
6634
6869
  } else if (nextCount === 2) {
6635
6870
  if (escDoubleTimerRef.current) clearTimeout(escDoubleTimerRef.current);
6636
6871
  setEscPressCount(0);
6637
- RevertManager.getChatHistory(chatId).then((prompts) => {
6638
- if (prompts.length > 0) {
6639
- setRecentPrompts(prompts.reverse());
6640
- setActiveView("revert");
6641
- } else {
6642
- setMessages((prev2) => {
6643
- setCompletedIndex(prev2.length + 1);
6644
- return [...prev2, { id: "revert-empty-" + Date.now(), role: "system", text: "\u{1F6C8} No revert checkpoints found for this session.", isMeta: true }];
6645
- });
6646
- }
6647
- });
6872
+ if (input.length > 0) {
6873
+ setInput("");
6874
+ } else {
6875
+ RevertManager.getChatHistory(chatId).then((prompts) => {
6876
+ if (prompts.length > 0) {
6877
+ setRecentPrompts(prompts.reverse());
6878
+ setActiveView("revert");
6879
+ } else {
6880
+ setMessages((prev2) => {
6881
+ setCompletedIndex(prev2.length + 1);
6882
+ return [...prev2, { id: "revert-empty-" + Date.now(), role: "system", text: "\u{1F6C8} No revert checkpoints found for this session.", isMeta: true }];
6883
+ });
6884
+ }
6885
+ });
6886
+ }
6648
6887
  }
6649
6888
  return nextCount;
6650
6889
  });
@@ -6667,6 +6906,10 @@ function App({ args = [] }) {
6667
6906
  if (key.tab && activeView === "chat") {
6668
6907
  }
6669
6908
  if (key.ctrl && inputText === "c" && activeView !== "exit") {
6909
+ if (input.length > 0) {
6910
+ setInput("");
6911
+ return;
6912
+ }
6670
6913
  if (key.shift) {
6671
6914
  setActiveView("exit");
6672
6915
  setConfirmExit(false);
@@ -7100,7 +7343,7 @@ ${hintText}`, color: "magenta" }];
7100
7343
  isMeta: true
7101
7344
  }];
7102
7345
  });
7103
- exec4("start https://enter.pollinations.ai/#pollen");
7346
+ exec3("start https://enter.pollinations.ai/#pollen");
7104
7347
  } else {
7105
7348
  try {
7106
7349
  const stats = await getImageQuotaStats();
@@ -7426,7 +7669,7 @@ ${list || "No saved chats found."}`, isMeta: true }];
7426
7669
  case "/changelog": {
7427
7670
  const platform = process.platform;
7428
7671
  const command = platform === "win32" ? "start" : platform === "darwin" ? "open" : "xdg-open";
7429
- exec4(`${command} ${CHANGELOG_URL}`);
7672
+ exec3(`${command} ${CHANGELOG_URL}`);
7430
7673
  setMessages((prev) => {
7431
7674
  setCompletedIndex(prev.length + 1);
7432
7675
  return [...prev, { id: Date.now(), role: "system", text: `\u{1F310} [BROWSER] Opening changelog: ${CHANGELOG_URL}`, isMeta: true }];
@@ -7530,6 +7773,8 @@ ${timestamp}` };
7530
7773
  janitorModel,
7531
7774
  sessionStats,
7532
7775
  chatId,
7776
+ cols: terminalSize.columns - 6,
7777
+ rows: 30,
7533
7778
  onExecStart: (cmd) => {
7534
7779
  setActiveCommand(cmd);
7535
7780
  setExecOutput("");
@@ -7542,6 +7787,7 @@ ${timestamp}` };
7542
7787
  if (!activeCommandRef.current) return prev;
7543
7788
  const finalStatus = `[TERMINAL_RECORD]
7544
7789
  COMMAND: ${activeCommandRef.current}
7790
+ PTY: ${isActiveCommandPty}
7545
7791
  OUTPUT: ${execOutputRef.current}`;
7546
7792
  return [...prev, { id: "term-" + Date.now(), role: "system", text: finalStatus, isTerminalRecord: true }];
7547
7793
  });
@@ -8431,7 +8677,7 @@ Selection: ${val}`,
8431
8677
  }
8432
8678
  )));
8433
8679
  default:
8434
- return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, null, statusText ? /* @__PURE__ */ React13.createElement(Box13, null, isSpinnerActive && /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, /* @__PURE__ */ React13.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React13.createElement(Text13, { color: "magenta", bold: true, italic: true }, isSpinnerActive ? " " : "", statusText.toUpperCase())) : /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", dimColor: true, italic: true }, "READY FOR COMMAND...")), /* @__PURE__ */ React13.createElement(Box13, null, /* @__PURE__ */ React13.createElement(Text13, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React13.createElement(Text13, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React13.createElement(
8680
+ return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, null, statusText ? /* @__PURE__ */ React13.createElement(Box13, null, isSpinnerActive && /* @__PURE__ */ React13.createElement(StatusSpinner, null), /* @__PURE__ */ React13.createElement(Text13, { color: "magenta", bold: true, italic: true }, isSpinnerActive ? " " : "", statusText.toUpperCase())) : /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", dimColor: true, italic: true }, "READY FOR COMMAND...")), /* @__PURE__ */ React13.createElement(Box13, null, /* @__PURE__ */ React13.createElement(Text13, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React13.createElement(Text13, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React13.createElement(
8435
8681
  Box13,
8436
8682
  {
8437
8683
  borderStyle: "round",
@@ -8457,12 +8703,13 @@ Selection: ${val}`,
8457
8703
  newline: (key) => key.return && key.shift || key.return && key.ctrl || key.return && key.leftAlt || key.return && key.rightAlt
8458
8704
  }
8459
8705
  }
8460
- )))) : /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React13.createElement(Box13, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React13.createElement(Text13, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u2726 " : "\u{1F4A0} ")), /* @__PURE__ */ React13.createElement(Box13, { flexGrow: 1 }, /* @__PURE__ */ React13.createElement(Box13, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React13.createElement(Box13, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React13.createElement(Text13, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : escPressCount === 1 ? /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, " Press ESC again to revert codebase to checkpoint...") : /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React13.createElement(
8706
+ )))) : /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "row", width: "100%", paddingY: 0 }, /* @__PURE__ */ React13.createElement(Box13, { flexShrink: 0, width: 4 }, /* @__PURE__ */ React13.createElement(Text13, { color: isProcessing ? "magenta" : "cyan", bold: true }, isProcessing ? "\u2726 " : "\u{1F4A0} ")), /* @__PURE__ */ React13.createElement(Box13, { flexGrow: 1 }, /* @__PURE__ */ React13.createElement(Box13, { flexGrow: 1, position: "relative" }, input === "" && /* @__PURE__ */ React13.createElement(Box13, { position: "absolute", paddingLeft: 0 }, activeCommand && !isTerminalFocused ? /* @__PURE__ */ React13.createElement(Text13, { color: "yellow" }, " Press TAB to interact with terminal...") : activeCommand && isTerminalFocused ? /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, " [ TERMINAL FOCUSED ] Type to interact, press TAB to exit...") : escPressCount === 1 ? /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, " Press ESC again to ", input.length > 0 ? "clear input" : "revert codebase to checkpoint", "...") : /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, escPressed ? " Press ESC again to cancel the request." : !isProcessing ? ` Send message or /cmd... (${terminalEnv.shortcut} for newline)` : " Enter a prompt to steer the agent.")), /* @__PURE__ */ React13.createElement(
8461
8707
  MultilineInput,
8462
8708
  {
8463
8709
  key: `input-${inputKey}`,
8464
8710
  focus: !isTerminalFocused,
8465
8711
  value: input,
8712
+ columns: terminalSize.columns,
8466
8713
  onChange: (val) => {
8467
8714
  const cleanVal = val.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\\\s*\n/g, "\n");
8468
8715
  setInput(cleanVal);
@@ -8486,7 +8733,7 @@ Selection: ${val}`,
8486
8733
  showFullThinking,
8487
8734
  columns: Math.max(20, (stdout?.columns || 80) - 1)
8488
8735
  }
8489
- ), activeCommand && /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused }))), isInitializing ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "gray", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, null, "Please enter your Gemini API Key to initialize the agent."), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React13.createElement(
8736
+ ), activeCommand && /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "gray", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, null, "Please enter your Gemini API Key to initialize the agent."), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React13.createElement(
8490
8737
  TextInput4,
8491
8738
  {
8492
8739
  value: tempKey,
@@ -8561,9 +8808,9 @@ Selection: ${val}`,
8561
8808
  );
8562
8809
  })()));
8563
8810
  }
8564
- var SESSION_START_TIME, CHANGELOG_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, FLUX_LOGO, parseAgentText, getProjectFiles;
8811
+ var SESSION_START_TIME, CHANGELOG_URL, linesAdded, linesRemoved, packageJsonPath, packageJson, versionFluxflow, updatedOn, SPINNER_FRAMES2, StatusSpinner, ResolutionModal, FLUX_LOGO, parseAgentText, getProjectFiles;
8565
8812
  var init_app = __esm({
8566
- "src/app.jsx"() {
8813
+ async "src/app.jsx"() {
8567
8814
  init_MultilineInput();
8568
8815
  init_ChatLayout();
8569
8816
  init_StatusBar();
@@ -8572,12 +8819,12 @@ var init_app = __esm({
8572
8819
  init_ProfileForm();
8573
8820
  init_AskUserModal();
8574
8821
  init_secrets();
8575
- init_ai();
8822
+ await init_ai();
8576
8823
  init_settings();
8577
8824
  init_history();
8578
8825
  init_ResumeModal();
8579
8826
  init_MemoryModal();
8580
- init_UpdateProcessor();
8827
+ await init_UpdateProcessor();
8581
8828
  init_revert();
8582
8829
  init_RevertModal();
8583
8830
  init_usage();
@@ -8585,7 +8832,7 @@ var init_app = __esm({
8585
8832
  init_arg_parser();
8586
8833
  init_paths();
8587
8834
  init_terminal();
8588
- init_exec_command();
8835
+ await init_exec_command();
8589
8836
  init_setup();
8590
8837
  init_text();
8591
8838
  SESSION_START_TIME = Date.now();
@@ -8596,6 +8843,17 @@ var init_app = __esm({
8596
8843
  packageJson = JSON.parse(fs18.readFileSync(packageJsonPath, "utf8"));
8597
8844
  versionFluxflow = packageJson.version;
8598
8845
  updatedOn = packageJson.date || "2026-05-20";
8846
+ SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8847
+ StatusSpinner = () => {
8848
+ const [tick, setTick] = useState10(0);
8849
+ useEffect7(() => {
8850
+ const interval = setInterval(() => {
8851
+ setTick((t) => (t + 1) % 1e3);
8852
+ }, 33);
8853
+ return () => clearInterval(interval);
8854
+ }, []);
8855
+ return /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, SPINNER_FRAMES2[Math.floor(tick / 3) % SPINNER_FRAMES2.length]);
8856
+ };
8599
8857
  ResolutionModal = ({ data, onResolve, onEdit }) => /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "magenta", bold: true, underline: true }, "\u{1F7E3} STEERING HINT RESOLUTION")), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "The agent already finished the task before your hint was consumed.")), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1, backgroundColor: "#222", paddingX: 2, width: "100%" }, /* @__PURE__ */ React13.createElement(Text13, { italic: true, color: "gray" }, '"', data, '"')), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, "How would you like to proceed?")), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 0 }, /* @__PURE__ */ React13.createElement(
8600
8858
  CommandMenu,
8601
8859
  {
@@ -8723,12 +8981,12 @@ var init_app = __esm({
8723
8981
  });
8724
8982
 
8725
8983
  // src/cli.jsx
8726
- import { spawn as spawn2 } from "child_process";
8984
+ import { spawn as spawn3 } from "child_process";
8727
8985
  import { fileURLToPath as fileURLToPath2 } from "url";
8728
8986
  var HEAP_LIMIT = 4096;
8729
8987
  var isBundled = fileURLToPath2(import.meta.url).endsWith(".js");
8730
8988
  if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-size"))) {
8731
- const cp = spawn2(process.execPath, [
8989
+ const cp = spawn3(process.execPath, [
8732
8990
  `--max-old-space-size=${HEAP_LIMIT}`,
8733
8991
  fileURLToPath2(import.meta.url),
8734
8992
  ...process.argv.slice(2)
@@ -8737,7 +8995,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
8737
8995
  } else {
8738
8996
  const { default: React14 } = await import("react");
8739
8997
  const { render } = await import("ink");
8740
- const { default: App2 } = await Promise.resolve().then(() => (init_app(), app_exports));
8998
+ const { default: App2 } = await init_app().then(() => app_exports);
8741
8999
  process.env.NODE_NO_WARNINGS = "1";
8742
9000
  const silentPatterns = [
8743
9001
  "cuimp",