fluxflow-cli 2.13.3 → 2.13.5

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 +1534 -1083
  2. package/package.json +1 -1
package/dist/fluxflow.js CHANGED
@@ -2087,984 +2087,1299 @@ var init_build = __esm({
2087
2087
  }
2088
2088
  });
2089
2089
 
2090
- // src/components/MultilineInput.jsx
2091
- import React2, { useState as useState2, useEffect as useEffect2, useMemo, useCallback, useRef } from "react";
2092
- import { Box, Text as Text2, useInput } from "ink";
2093
- function expandTabs(text, tabSize) {
2094
- return text.replace(/\t/g, " ".repeat(tabSize));
2095
- }
2096
- function normalizeLineEndings(text) {
2097
- if (text == null) return "";
2098
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2099
- }
2100
- function computeVisualMatrix(value, cursorIndex, wrapWidth, formatText) {
2101
- const textBefore = (value || "").slice(0, cursorIndex);
2102
- const visualCursorIdx = formatText(textBefore).length;
2103
- const fullFormatted = formatText(value || "");
2104
- const literalLines = fullFormatted.split("\n");
2105
- const visualLines = [];
2106
- let currentIdx = 0;
2107
- let cursorLine = 0;
2108
- let cursorCol = 0;
2109
- let foundCursor = false;
2110
- for (let i = 0; i < literalLines.length; i++) {
2111
- const line = literalLines[i];
2112
- if (line.length === 0) {
2113
- if (!foundCursor && visualCursorIdx === currentIdx) {
2114
- cursorLine = visualLines.length;
2115
- cursorCol = 0;
2116
- foundCursor = true;
2090
+ // src/utils/text.js
2091
+ import os2 from "os";
2092
+ var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseMessageToBlocks, TOOL_LABELS, cleanSignals;
2093
+ var init_text = __esm({
2094
+ "src/utils/text.js"() {
2095
+ init_paths();
2096
+ wrapText = (text, width) => {
2097
+ if (!text) return "";
2098
+ const ansiRegex2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
2099
+ const sourceLines = text.split("\n");
2100
+ let finalLines = [];
2101
+ if (width <= 5) return text;
2102
+ const getVisibleLength = (str) => str.replace(ansiRegex2, "").length;
2103
+ sourceLines.forEach((sLine) => {
2104
+ const visibleLength = getVisibleLength(sLine);
2105
+ if (visibleLength <= width) {
2106
+ finalLines.push(sLine);
2107
+ return;
2108
+ }
2109
+ const tokens = sLine.split(/(\s+)/);
2110
+ let currentLine = "";
2111
+ let currentVisibleLength = 0;
2112
+ const leadingSpaceMatch = sLine.match(/^(\s*)/);
2113
+ const indent = leadingSpaceMatch ? leadingSpaceMatch[1] : "";
2114
+ tokens.forEach((token, idx) => {
2115
+ if (token.length === 0) return;
2116
+ const tokenVisibleLength = getVisibleLength(token);
2117
+ if (currentVisibleLength + tokenVisibleLength > width) {
2118
+ if (currentLine.trim().length > 0) {
2119
+ finalLines.push(currentLine.trimEnd());
2120
+ currentLine = indent + token;
2121
+ currentVisibleLength = getVisibleLength(currentLine);
2122
+ } else {
2123
+ if (ansiRegex2.test(token)) {
2124
+ finalLines.push(token);
2125
+ currentLine = indent;
2126
+ currentVisibleLength = getVisibleLength(currentLine);
2127
+ } else {
2128
+ let word = token;
2129
+ while (getVisibleLength(word) > width && width > 10) {
2130
+ finalLines.push(word.substring(0, width));
2131
+ word = word.substring(width);
2132
+ }
2133
+ currentLine = word;
2134
+ currentVisibleLength = getVisibleLength(currentLine);
2135
+ }
2136
+ }
2137
+ } else {
2138
+ currentLine += token;
2139
+ currentVisibleLength += tokenVisibleLength;
2140
+ }
2141
+ });
2142
+ if (currentLine.trimEnd().length > 0 || currentLine === indent) {
2143
+ finalLines.push(currentLine.trimEnd());
2144
+ }
2145
+ });
2146
+ return finalLines.join("\n");
2147
+ };
2148
+ formatTokens = (tokens) => {
2149
+ if (!tokens && tokens !== 0) return "0.0k";
2150
+ const num = typeof tokens === "string" ? parseFloat(tokens) : tokens;
2151
+ if (num >= 1e6) {
2152
+ return `${(num / 1e6).toFixed(1)}m`;
2153
+ } else if (num >= 1e3) {
2154
+ return `${(num / 1e3).toFixed(1)}k`;
2155
+ }
2156
+ return num.toString();
2157
+ };
2158
+ truncatePath = (p, maxLength = 40) => {
2159
+ let data_dir = DATA_DIR.replaceAll("\\\\", "\\");
2160
+ p = p.replace(os2.homedir(), "~").replace(data_dir, "FluxFlow").replaceAll("\\", "/");
2161
+ if (!p || p.length <= maxLength) return p;
2162
+ const half = Math.floor((maxLength - 3) / 2);
2163
+ return p.substring(0, half) + "..." + p.substring(p.length - half).replaceAll("\\", "/");
2164
+ };
2165
+ parsePatchPairs = (args) => {
2166
+ const patchPairs = [];
2167
+ const indices = /* @__PURE__ */ new Set();
2168
+ Object.keys(args).forEach((key) => {
2169
+ const m = key.match(/^(replaceContent|newContent|content_to_replace|content_to_add)(\d+)?$/);
2170
+ if (m) {
2171
+ const index = m[2] ? parseInt(m[2]) : 1;
2172
+ indices.add(index);
2173
+ }
2174
+ });
2175
+ const sortedIndices = Array.from(indices).sort((a, b) => a - b);
2176
+ for (const i of sortedIndices) {
2177
+ let r, n;
2178
+ if (i === 1) {
2179
+ r = args.replaceContent1 ?? (args.content_to_replace ?? args.replaceContent);
2180
+ n = args.newContent1 ?? (args.content_to_add ?? args.newContent);
2181
+ } else {
2182
+ r = args[`replaceContent${i}`] ?? args[`content_to_replace${i}`];
2183
+ n = args[`newContent${i}`] ?? args[`content_to_add${i}`];
2184
+ }
2185
+ if (r !== void 0 && n !== void 0) {
2186
+ patchPairs.push({ replace: r, new: n });
2187
+ } else if (r !== void 0 || n !== void 0) {
2188
+ return { error: `Mismatched replacement pair for index ${i}. Both replacement and new content must be provided.` };
2189
+ }
2190
+ }
2191
+ return { patchPairs };
2192
+ };
2193
+ applyPatches = (content, patches) => {
2194
+ let currentFileContent = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2195
+ const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2196
+ const getIndent = (line) => line.match(/^\s*/)[0];
2197
+ const getMinIndent = (text) => {
2198
+ const lines = text.split("\n").filter((l) => l.trim() !== "");
2199
+ if (lines.length === 0) return "";
2200
+ let min = getIndent(lines[0]);
2201
+ for (const line of lines) {
2202
+ const indent = getIndent(line);
2203
+ if (indent.length < min.length) min = indent;
2204
+ }
2205
+ return min;
2206
+ };
2207
+ const adjustIndentation = (newText, originalMatch, leadingContext = "") => {
2208
+ if (!newText || originalMatch === void 0) return newText;
2209
+ const getIndentStyle = (text) => {
2210
+ const lines = text.split("\n").filter((l) => l.trim() !== "");
2211
+ if (lines.length === 0) return { char: " ", size: 4 };
2212
+ const firstIndent = lines[0].match(/^\s*/)[0];
2213
+ if (firstIndent.includes(" ")) return { char: " ", size: 1 };
2214
+ const indents = lines.map((l) => l.match(/^\s*/)[0].length).filter((l) => l > 0);
2215
+ if (indents.length === 0) return { char: " ", size: firstIndent.length || 4 };
2216
+ const gcd = (a, b) => b ? gcd(b, a % b) : a;
2217
+ const step = indents.reduce((a, b) => gcd(a, b));
2218
+ return { char: " ", size: step || 4 };
2219
+ };
2220
+ const fileStyle = getIndentStyle(originalMatch);
2221
+ const modelStyle = getIndentStyle(newText);
2222
+ const matchMinIndent = getMinIndent(originalMatch).length;
2223
+ const leadingIndent = (leadingContext.match(/^\s*/) || [""])[0].length;
2224
+ const targetBaseIndentRaw = leadingIndent + matchMinIndent;
2225
+ const targetUnits = targetBaseIndentRaw / fileStyle.size;
2226
+ const modelBaseUnits = getMinIndent(newText).length / modelStyle.size;
2227
+ const deltaUnits = targetUnits - modelBaseUnits;
2228
+ const newLines = newText.split("\n");
2229
+ return newLines.map((line, i) => {
2230
+ if (line.trim() === "" && i !== 0) return "";
2231
+ const currentLineUnits = line.match(/^\s*/)[0].length / modelStyle.size;
2232
+ const finalUnits = Math.max(0, currentLineUnits + deltaUnits);
2233
+ let unitCount = finalUnits;
2234
+ if (i === 0) {
2235
+ const leadingUnits = leadingIndent / fileStyle.size;
2236
+ unitCount = Math.max(0, finalUnits - leadingUnits);
2237
+ }
2238
+ return fileStyle.char.repeat(unitCount * fileStyle.size) + line.trimStart();
2239
+ }).join("\n");
2240
+ };
2241
+ const patchMatches = [];
2242
+ for (let i = 0; i < patches.length; i++) {
2243
+ const pair = patches[i];
2244
+ const content_to_replace = strip(pair.replace || "");
2245
+ const content_to_add = strip(pair.new || "");
2246
+ if (content_to_replace === "" && content_to_add === "") {
2247
+ patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Empty replace and add content.` });
2248
+ continue;
2249
+ }
2250
+ const exactPattern = content_to_replace.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2251
+ let matchRegex = null;
2252
+ if (content_to_replace !== "" && currentFileContent.includes(content_to_replace)) {
2253
+ matchRegex = new RegExp(exactPattern, "g");
2254
+ } else {
2255
+ 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*"));
2256
+ if (fuzzyLines.length > 0) {
2257
+ const fuzzyPattern = fuzzyLines.join("\\s*");
2258
+ try {
2259
+ matchRegex = new RegExp(fuzzyPattern, "g");
2260
+ } catch (e) {
2261
+ matchRegex = new RegExp(exactPattern, "g");
2262
+ }
2263
+ } else {
2264
+ matchRegex = new RegExp(exactPattern, "g");
2265
+ }
2266
+ }
2267
+ const matches = [...currentFileContent.matchAll(matchRegex)];
2268
+ if (matches.length === 0) {
2269
+ patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Could not find match.` });
2270
+ continue;
2271
+ }
2272
+ if (matches.length > 1) {
2273
+ patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Found ${matches.length} matches (must be unique).` });
2274
+ continue;
2275
+ }
2276
+ patchMatches.push({
2277
+ index: i,
2278
+ success: true,
2279
+ startPos: matches[0].index,
2280
+ firstMatchContent: matches[0][0],
2281
+ content_to_add
2282
+ });
2283
+ }
2284
+ const successful = patchMatches.filter((m) => m.success).sort((a, b) => a.startPos - b.startPos);
2285
+ for (let j = 0; j < successful.length - 1; j++) {
2286
+ const curr = successful[j];
2287
+ const next = successful[j + 1];
2288
+ if (curr.startPos + curr.firstMatchContent.length > next.startPos) {
2289
+ curr.success = false;
2290
+ curr.error = `Block ${curr.index + 1}: Overlaps with another block.`;
2291
+ next.success = false;
2292
+ next.error = `Block ${next.index + 1}: Overlaps with another block.`;
2293
+ }
2294
+ }
2295
+ const resultsMap = /* @__PURE__ */ new Map();
2296
+ let finalContent = currentFileContent;
2297
+ let charOffset = 0;
2298
+ let lineOffset = 0;
2299
+ const toApply = patchMatches.filter((m) => m.success).sort((a, b) => a.startPos - b.startPos);
2300
+ for (const match of toApply) {
2301
+ const originalStartPos = match.startPos;
2302
+ const originalStartLine = currentFileContent.substring(0, originalStartPos).split("\n").length;
2303
+ const finalStartPos = originalStartPos + charOffset;
2304
+ const finalStartLine = originalStartLine + lineOffset;
2305
+ const lineStart = finalContent.lastIndexOf("\n", finalStartPos) + 1;
2306
+ const leadingContext = finalContent.substring(lineStart, finalStartPos);
2307
+ const finalReplacement = adjustIndentation(match.content_to_add, match.firstMatchContent, leadingContext);
2308
+ const allLines = finalContent.split("\n");
2309
+ const contextBefore = [];
2310
+ for (let j = Math.max(0, finalStartLine - 4); j < finalStartLine - 1; j++) {
2311
+ contextBefore.push({ num: j + 1, text: allLines[j] });
2312
+ }
2313
+ const patchOldLines = match.firstMatchContent.split("\n");
2314
+ const contextAfter = [];
2315
+ const patchEndLineIdx = finalStartLine + patchOldLines.length - 1;
2316
+ for (let j = patchEndLineIdx; j < Math.min(allLines.length, patchEndLineIdx + 3); j++) {
2317
+ contextAfter.push({ num: j + 1, text: allLines[j] });
2318
+ }
2319
+ resultsMap.set(match.index, {
2320
+ success: true,
2321
+ oldContent: match.firstMatchContent,
2322
+ newContent: finalReplacement,
2323
+ originalStartLine,
2324
+ finalStartLine,
2325
+ contextBefore,
2326
+ contextAfter
2327
+ });
2328
+ finalContent = finalContent.substring(0, finalStartPos) + finalReplacement + finalContent.substring(finalStartPos + match.firstMatchContent.length);
2329
+ charOffset += finalReplacement.length - match.firstMatchContent.length;
2330
+ lineOffset += finalReplacement.split("\n").length - match.firstMatchContent.split("\n").length;
2331
+ }
2332
+ const results = [];
2333
+ for (let i = 0; i < patches.length; i++) {
2334
+ if (resultsMap.has(i)) {
2335
+ results.push(resultsMap.get(i));
2336
+ } else {
2337
+ const match = patchMatches.find((m) => m.index === i);
2338
+ results.push({
2339
+ success: false,
2340
+ error: match ? match.error : `Block ${i + 1}: Unknown error.`
2341
+ });
2342
+ }
2343
+ }
2344
+ return { content: finalContent, results };
2345
+ };
2346
+ generateHighFidelityDiff = (originalContent, finalContent, patchResults, threshold = 8) => {
2347
+ if (!patchResults || patchResults.length === 0) return "";
2348
+ const allLinesOriginal = originalContent.split(/\r?\n/);
2349
+ const allLinesFinal = finalContent.split(/\r?\n/);
2350
+ let diffText = `[DIFF_START]
2351
+ `;
2352
+ const separatorLine = "\u2550".repeat(88);
2353
+ let currentFinalLineIdx = 0;
2354
+ let lastSuccessfulHunk = null;
2355
+ const sortedResults = patchResults.filter((res) => res.success).sort((a, b) => a.originalStartLine - b.originalStartLine);
2356
+ sortedResults.forEach((res, idx) => {
2357
+ const startLineFinal = res.finalStartLine !== void 0 ? res.finalStartLine : res.originalStartLine;
2358
+ if (lastSuccessfulHunk === null) {
2359
+ const contextStart = Math.max(0, startLineFinal - 4);
2360
+ currentFinalLineIdx = contextStart;
2361
+ while (currentFinalLineIdx < startLineFinal - 1) {
2362
+ diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2363
+ `;
2364
+ currentFinalLineIdx++;
2365
+ }
2366
+ } else {
2367
+ const prev = lastSuccessfulHunk;
2368
+ const prevOriginalEnd = prev.originalStartLine + prev.oldContent.split("\n").length - 1;
2369
+ const gap = res.originalStartLine - prevOriginalEnd - 1;
2370
+ if (gap >= threshold) {
2371
+ let afterLimit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
2372
+ while (currentFinalLineIdx < afterLimit) {
2373
+ diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2374
+ `;
2375
+ currentFinalLineIdx++;
2376
+ }
2377
+ diffText += `[UI_CONTEXT] ${separatorLine}
2378
+ `;
2379
+ const beforeStart = Math.max(currentFinalLineIdx, startLineFinal - 4);
2380
+ currentFinalLineIdx = beforeStart;
2381
+ while (currentFinalLineIdx < startLineFinal - 1) {
2382
+ diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2383
+ `;
2384
+ currentFinalLineIdx++;
2385
+ }
2386
+ } else {
2387
+ while (currentFinalLineIdx < startLineFinal - 1) {
2388
+ diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2389
+ `;
2390
+ currentFinalLineIdx++;
2391
+ }
2392
+ }
2393
+ }
2394
+ const oldLines = res.oldContent.split("\n");
2395
+ oldLines.forEach((line, i) => {
2396
+ diffText += `-${res.originalStartLine + i}|${line}
2397
+ `;
2398
+ });
2399
+ let hunkEndInFinal = currentFinalLineIdx;
2400
+ if (res.finalStartLine !== void 0) {
2401
+ hunkEndInFinal = res.finalStartLine - 1 + (res.newContent ? res.newContent.split("\n").length : 0);
2402
+ } else {
2403
+ const originalResyncLineIdx = res.originalStartLine + oldLines.length - 1;
2404
+ const resyncAnchorText = allLinesOriginal[originalResyncLineIdx] || null;
2405
+ if (resyncAnchorText !== null) {
2406
+ const lookAheadLimit = idx < sortedResults.length - 1 ? (sortedResults[idx + 1].originalStartLine || allLinesFinal.length) + 10 : allLinesFinal.length;
2407
+ for (let s = currentFinalLineIdx; s < lookAheadLimit; s++) {
2408
+ if (allLinesFinal[s] === resyncAnchorText) {
2409
+ hunkEndInFinal = s;
2410
+ break;
2411
+ }
2412
+ if (s === allLinesFinal.length - 1) hunkEndInFinal = allLinesFinal.length;
2413
+ }
2414
+ } else {
2415
+ hunkEndInFinal = allLinesFinal.length;
2416
+ }
2417
+ }
2418
+ while (currentFinalLineIdx < hunkEndInFinal) {
2419
+ diffText += `+${currentFinalLineIdx + 1}|${allLinesFinal[currentFinalLineIdx] || ""}
2420
+ `;
2421
+ currentFinalLineIdx++;
2422
+ }
2423
+ lastSuccessfulHunk = res;
2424
+ });
2425
+ if (lastSuccessfulHunk !== null) {
2426
+ let limit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
2427
+ while (currentFinalLineIdx < limit) {
2428
+ diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2429
+ `;
2430
+ currentFinalLineIdx++;
2431
+ }
2117
2432
  }
2118
- visualLines.push({ text: "", globalStart: currentIdx });
2119
- currentIdx += 1;
2120
- continue;
2121
- }
2122
- for (let j = 0; j < line.length; j += wrapWidth) {
2123
- const chunk = line.slice(j, j + wrapWidth);
2124
- const chunkStart = currentIdx + j;
2125
- const chunkEnd = chunkStart + chunk.length;
2126
- if (!foundCursor && visualCursorIdx >= chunkStart && (visualCursorIdx < chunkEnd || visualCursorIdx === chunkEnd && j + wrapWidth >= line.length && i === literalLines.length - 1)) {
2127
- cursorLine = visualLines.length;
2128
- cursorCol = visualCursorIdx - chunkStart;
2129
- foundCursor = true;
2433
+ diffText += `[DIFF_END]`;
2434
+ return diffText;
2435
+ };
2436
+ parseMessageToBlocks = (msg, columns) => {
2437
+ const text = cleanSignals(msg.text || "");
2438
+ if (text.includes("- Content Preview:")) {
2439
+ const mainParts = text.split("- Content Preview:");
2440
+ const headerText = mainParts[0] || "";
2441
+ const contentPart = mainParts[1] || "";
2442
+ const footerMarker = "[SYSTEM] Check the content preview for verification [/SYSTEM]";
2443
+ const contentAndFooter = contentPart.split(footerMarker);
2444
+ const content = contentAndFooter[0]?.trim() || "";
2445
+ const footer = contentAndFooter[1] ? `${footerMarker}${contentAndFooter[1]}` : "";
2446
+ const codeLines = content.split("\n").map((l) => l.replace(/\r$/, ""));
2447
+ const gutterWidth = String(codeLines.length).length;
2448
+ const completedBlocks2 = [];
2449
+ let activeBlock2 = null;
2450
+ codeLines.forEach((line, idx) => {
2451
+ const isLast = idx === codeLines.length - 1;
2452
+ const block = {
2453
+ key: `${msg.id || Date.now()}-write-line-${idx}`,
2454
+ msg,
2455
+ type: "write-line",
2456
+ text: line,
2457
+ gutterWidth,
2458
+ lineNum: idx + 1,
2459
+ isFirstLine: idx === 0,
2460
+ isLastLine: isLast
2461
+ };
2462
+ if (isLast && msg.isStreaming) {
2463
+ activeBlock2 = block;
2464
+ } else {
2465
+ completedBlocks2.push(block);
2466
+ }
2467
+ });
2468
+ return {
2469
+ completed: completedBlocks2,
2470
+ active: activeBlock2 ? [activeBlock2] : []
2471
+ };
2130
2472
  }
2131
- visualLines.push({ text: chunk, globalStart: chunkStart });
2132
- }
2133
- currentIdx += line.length + 1;
2134
- }
2135
- if (!foundCursor) {
2136
- if (visualLines.length === 0) {
2137
- visualLines.push({ text: "", globalStart: 0 });
2138
- } else {
2139
- if (fullFormatted.endsWith("\n")) {
2140
- visualLines.push({ text: "", globalStart: currentIdx });
2141
- cursorLine = visualLines.length - 1;
2142
- cursorCol = 0;
2143
- } else {
2144
- cursorLine = visualLines.length - 1;
2145
- cursorCol = visualLines[cursorLine].text.length;
2473
+ if (text.includes("[DIFF_START]")) {
2474
+ const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
2475
+ const diffBody = match ? match[1].trim() : "";
2476
+ const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
2477
+ const completedBlocks2 = [];
2478
+ let activeBlock2 = null;
2479
+ diffLines.forEach((line, i) => {
2480
+ const isLast = i === diffLines.length - 1;
2481
+ const block = {
2482
+ key: `${msg.id || Date.now()}-diff-${i}`,
2483
+ msg,
2484
+ type: "diff-line",
2485
+ text: line,
2486
+ isFirstLine: i === 0,
2487
+ isLastLine: isLast
2488
+ };
2489
+ if (isLast && msg.isStreaming) {
2490
+ activeBlock2 = block;
2491
+ } else {
2492
+ completedBlocks2.push(block);
2493
+ }
2494
+ });
2495
+ return {
2496
+ completed: completedBlocks2,
2497
+ active: activeBlock2 ? [activeBlock2] : []
2498
+ };
2146
2499
  }
2147
- }
2148
- }
2149
- return { visualLines, cursorLine, cursorCol };
2150
- }
2151
- var ControlledMultilineInput, MultilineInput;
2152
- var init_MultilineInput = __esm({
2153
- "src/components/MultilineInput.jsx"() {
2154
- ControlledMultilineInput = ({
2155
- value,
2156
- rows,
2157
- maxRows,
2158
- highlightStyle,
2159
- textStyle,
2160
- placeholder = "",
2161
- mask,
2162
- showCursor = true,
2163
- focus = true,
2164
- tabSize = 4,
2165
- cursorIndex = 0,
2166
- highlight,
2167
- columns = 80
2168
- }) => {
2169
- const scrollOffsetRef = useRef(0);
2170
- const wrapWidth = useMemo(() => Math.max(20, columns - 10), [columns]);
2171
- const formatText = useCallback(
2172
- (text, isPlaceholder = false) => {
2173
- const normalized = normalizeLineEndings(text);
2174
- if (!isPlaceholder && mask) {
2175
- return normalized.replace(/[^\n]/g, mask);
2500
+ if (msg.role === "system" || msg.isLogo || msg.isHelpRecord || msg.isTerminalRecord || msg.isHomeWarning || msg.isImageStats || msg.isAskRecord || msg.isAboutRecord || msg.isUpdateNotification || msg.role === "user") {
2501
+ return {
2502
+ completed: [{
2503
+ key: `${msg.id || Date.now()}-full`,
2504
+ msg,
2505
+ type: "full-message",
2506
+ text
2507
+ }],
2508
+ active: []
2509
+ };
2510
+ }
2511
+ const completedBlocks = [];
2512
+ let activeBlock = null;
2513
+ if (msg.role === "think") {
2514
+ completedBlocks.push({
2515
+ key: `${msg.id}-header`,
2516
+ msg,
2517
+ type: "think-header",
2518
+ text: ""
2519
+ });
2520
+ const lines = text.split("\n");
2521
+ lines.forEach((line, idx) => {
2522
+ const isLast = idx === lines.length - 1;
2523
+ const block = {
2524
+ key: `${msg.id}-${idx}`,
2525
+ msg,
2526
+ type: "think-line",
2527
+ text: line
2528
+ };
2529
+ if (isLast && msg.isStreaming) {
2530
+ block.isActiveBlock = true;
2531
+ activeBlock = block;
2532
+ } else {
2533
+ completedBlocks.push(block);
2176
2534
  }
2177
- const expanded = expandTabs(normalized, tabSize);
2178
- if (isPlaceholder) return expanded;
2179
- return expanded.replace(/@\[(.*?)\]/g, (match, p1) => {
2180
- const hashIdx = p1.indexOf("#");
2181
- const colonIdx = p1.indexOf(":L");
2182
- let pathOnly = p1;
2183
- let suffix = "";
2184
- if (hashIdx !== -1) {
2185
- pathOnly = p1.slice(0, hashIdx);
2186
- suffix = p1.slice(hashIdx);
2187
- } else if (colonIdx !== -1) {
2188
- pathOnly = p1.slice(0, colonIdx);
2189
- suffix = p1.slice(colonIdx);
2535
+ });
2536
+ if (!msg.isStreaming) {
2537
+ completedBlocks.push({
2538
+ key: `${msg.id}-footer-padding`,
2539
+ msg,
2540
+ type: "think-footer-padding",
2541
+ text: ""
2542
+ });
2543
+ }
2544
+ } else {
2545
+ const lines = text.split("\n");
2546
+ let inTable = false;
2547
+ let tableLines = [];
2548
+ let inCodeBlock = false;
2549
+ let codeLines = [];
2550
+ lines.forEach((line, idx) => {
2551
+ const isLast = idx === lines.length - 1;
2552
+ const isTableRow = line.trim().startsWith("|");
2553
+ const isCodeBlockMarker = line.trim().startsWith("```");
2554
+ if (inCodeBlock) {
2555
+ codeLines.push(line);
2556
+ if (isCodeBlockMarker || isLast) {
2557
+ inCodeBlock = !isCodeBlockMarker;
2558
+ if (!inCodeBlock || isLast) {
2559
+ const block = {
2560
+ key: `${msg.id}-code-${idx}`,
2561
+ msg,
2562
+ type: "agent-line",
2563
+ text: codeLines.join("\n")
2564
+ };
2565
+ if (isLast && msg.isStreaming && inCodeBlock) {
2566
+ block.isActiveBlock = true;
2567
+ activeBlock = block;
2568
+ } else {
2569
+ completedBlocks.push(block);
2570
+ }
2571
+ codeLines = [];
2572
+ }
2573
+ }
2574
+ } else if (isCodeBlockMarker) {
2575
+ inCodeBlock = true;
2576
+ codeLines.push(line);
2577
+ if (isLast) {
2578
+ const block = {
2579
+ key: `${msg.id}-code-${idx}`,
2580
+ msg,
2581
+ type: "agent-line",
2582
+ text: codeLines.join("\n")
2583
+ };
2584
+ if (msg.isStreaming) {
2585
+ block.isActiveBlock = true;
2586
+ activeBlock = block;
2587
+ } else {
2588
+ completedBlocks.push(block);
2589
+ }
2190
2590
  }
2191
- let rel = pathOnly.replace(/\\/g, "/");
2192
- const cwd = (process.cwd() || "").replace(/\\/g, "/");
2193
- if (cwd && rel.toLowerCase().startsWith(cwd.toLowerCase() + "/")) {
2194
- rel = rel.slice(cwd.length + 1);
2195
- } else if (rel.startsWith("./")) {
2196
- rel = rel.slice(2);
2591
+ } else if (isTableRow) {
2592
+ inTable = true;
2593
+ tableLines.push(line);
2594
+ if (isLast) {
2595
+ if (msg.isStreaming) {
2596
+ activeBlock = {
2597
+ key: `${msg.id}-table-${idx}`,
2598
+ msg,
2599
+ type: "table",
2600
+ text: tableLines.join("\n"),
2601
+ isStreaming: true,
2602
+ isActiveBlock: true
2603
+ };
2604
+ } else {
2605
+ completedBlocks.push({
2606
+ key: `${msg.id}-table-${idx}`,
2607
+ msg,
2608
+ type: "table",
2609
+ text: tableLines.join("\n"),
2610
+ isStreaming: false
2611
+ });
2612
+ }
2197
2613
  }
2198
- const parts = rel.split("/");
2199
- const basename = parts[parts.length - 1];
2200
- return `[${basename}${suffix}]`;
2614
+ } else {
2615
+ if (inTable) {
2616
+ completedBlocks.push({
2617
+ key: `${msg.id}-table-${idx}`,
2618
+ msg,
2619
+ type: "table",
2620
+ text: tableLines.join("\n"),
2621
+ isStreaming: false
2622
+ });
2623
+ inTable = false;
2624
+ tableLines = [];
2625
+ }
2626
+ const block = {
2627
+ key: `${msg.id}-${idx}`,
2628
+ msg,
2629
+ type: "agent-line",
2630
+ text: line
2631
+ };
2632
+ if (isLast && msg.isStreaming) {
2633
+ block.isActiveBlock = true;
2634
+ activeBlock = block;
2635
+ } else {
2636
+ completedBlocks.push(block);
2637
+ }
2638
+ }
2639
+ });
2640
+ if (!msg.isStreaming && msg.workedDuration) {
2641
+ completedBlocks.push({
2642
+ key: `${msg.id}-worked-duration`,
2643
+ msg,
2644
+ type: "worked-duration",
2645
+ text: ""
2201
2646
  });
2202
- },
2203
- [tabSize, mask]
2204
- );
2205
- const { visualLines, cursorLine, cursorCol } = useMemo(() => {
2206
- return computeVisualMatrix(value, cursorIndex, wrapWidth, formatText);
2207
- }, [value, cursorIndex, wrapWidth, formatText]);
2208
- const contentHeight = visualLines.length;
2209
- const visibleRows = useMemo(() => {
2210
- return Math.max(rows ?? maxRows ?? 1, Math.min(maxRows ?? rows ?? 1, contentHeight));
2211
- }, [rows, maxRows, contentHeight]);
2212
- const cursorLineEnd = cursorLine + 1;
2213
- const viewportEnd = scrollOffsetRef.current + visibleRows;
2214
- let newScrollOffset = scrollOffsetRef.current;
2215
- if (cursorLineEnd <= scrollOffsetRef.current) {
2216
- newScrollOffset = Math.max(0, cursorLineEnd - 1);
2217
- } else if (cursorLineEnd > viewportEnd) {
2218
- newScrollOffset = cursorLineEnd - visibleRows;
2219
- } else if (contentHeight) {
2220
- if (contentHeight < visibleRows) {
2221
- newScrollOffset = 0;
2222
- } else if (contentHeight < viewportEnd) {
2223
- newScrollOffset = contentHeight - visibleRows;
2224
2647
  }
2225
2648
  }
2226
- scrollOffsetRef.current = newScrollOffset;
2227
- const visibleLines = useMemo(() => {
2228
- return visualLines.slice(newScrollOffset, newScrollOffset + visibleRows);
2229
- }, [visualLines, newScrollOffset, visibleRows]);
2230
- const [blink, setBlink] = useState2(true);
2231
- useEffect2(() => {
2232
- setBlink(true);
2233
- if (!focus || !showCursor) return;
2234
- const timer = setInterval(() => {
2235
- setBlink((prev) => !prev);
2236
- }, 530);
2237
- return () => clearInterval(timer);
2238
- }, [focus, showCursor, value, cursorIndex]);
2239
- const cursorStyle = useMemo(() => ({
2240
- ...textStyle,
2241
- color: showCursor && focus && blink ? "white" : void 0,
2242
- bold: showCursor && focus && blink,
2243
- inverse: showCursor && focus && blink
2244
- }), [textStyle, showCursor, focus, blink]);
2245
- return /* @__PURE__ */ React2.createElement(Box, { height: visibleRows, width: wrapWidth, overflow: "hidden", flexDirection: "column", flexGrow: 0, flexShrink: 0 }, visibleLines.map((lineObj, idx) => {
2246
- const globalLineIdx = newScrollOffset + idx;
2247
- const isCursorLine = globalLineIdx === cursorLine && focus && showCursor;
2248
- if (!isCursorLine) {
2249
- return /* @__PURE__ */ React2.createElement(Text2, { key: globalLineIdx, ...textStyle, wrap: "truncate" }, lineObj.text || (placeholder && value.length === 0 ? formatText(placeholder, true) : " "));
2250
- }
2251
- const text = lineObj.text;
2252
- const left = text.slice(0, cursorCol);
2253
- const charAtCursor = text[cursorCol] || " ";
2254
- const right = text.slice(cursorCol + 1);
2255
- return /* @__PURE__ */ React2.createElement(Text2, { key: globalLineIdx, ...textStyle, wrap: "truncate" }, /* @__PURE__ */ React2.createElement(Text2, null, left), /* @__PURE__ */ React2.createElement(Text2, { ...cursorStyle }, charAtCursor), /* @__PURE__ */ React2.createElement(Text2, null, right));
2256
- }));
2649
+ return {
2650
+ completed: completedBlocks,
2651
+ active: activeBlock ? [activeBlock] : []
2652
+ };
2257
2653
  };
2258
- MultilineInput = ({
2259
- value,
2260
- onChange,
2261
- onSubmit,
2262
- keyBindings,
2263
- showCursor = true,
2264
- highlightPastedText = false,
2265
- focus = true,
2266
- columns = 80,
2267
- useCustomInput = (inputHandler, isActive) => useInput(inputHandler, { isActive }),
2268
- ...controlledProps
2269
- }) => {
2270
- const [cursorIndex, setCursorIndex] = useState2(value.length);
2271
- const [pasteLength, setPasteLength] = useState2(0);
2272
- const cursorIndexRef = useRef(value.length);
2273
- const valueRef = useRef(value);
2274
- const pasteLengthRef = useRef(0);
2275
- const lastArrowTimeRef = useRef(0);
2276
- cursorIndexRef.current = cursorIndex;
2277
- valueRef.current = value;
2278
- pasteLengthRef.current = pasteLength;
2279
- useEffect2(() => {
2280
- if (cursorIndexRef.current > value.length) {
2281
- cursorIndexRef.current = value.length;
2282
- setCursorIndex(value.length);
2283
- }
2284
- }, [value]);
2285
- useCustomInput((input, key) => {
2286
- if (input === "\x1B[I" || input === "\x1B[O" || input === "[I" || input === "[O") {
2287
- return;
2288
- }
2289
- const isArrowKey = key.upArrow || key.downArrow || key.leftArrow || key.rightArrow;
2290
- if (isArrowKey) {
2291
- const now = Date.now();
2292
- if (now - lastArrowTimeRef.current < 33) {
2293
- return;
2294
- }
2295
- lastArrowTimeRef.current = now;
2296
- }
2297
- const curIdx = cursorIndexRef.current;
2298
- const val = valueRef.current;
2299
- const wrapWidth = Math.max(20, columns - 10);
2300
- const submitKey = keyBindings?.submit ?? ((k) => k.return && k.ctrl);
2301
- const newlineKey = keyBindings?.newline ?? ((k) => k.return);
2302
- if (submitKey(key)) {
2303
- onSubmit?.(val);
2304
- return;
2305
- } else if (newlineKey(key)) {
2306
- const newValue = val.slice(0, curIdx) + "\n" + val.slice(curIdx);
2307
- onChange(newValue);
2308
- cursorIndexRef.current = curIdx + 1;
2309
- setCursorIndex(curIdx + 1);
2310
- setPasteLength(0);
2311
- return;
2312
- }
2313
- if (key.tab || key.shift && key.tab || key.ctrl && input === "c") {
2314
- return;
2654
+ TOOL_LABELS = {
2655
+ "write_file": "WriteFile",
2656
+ "update_file": "UpdateFile",
2657
+ "read_folder": "ReadFolder",
2658
+ "view_file": "ViewFile",
2659
+ "exec_command": "ExecuteCommand",
2660
+ "web_search": "WebSearch",
2661
+ "web_scrape": "ReadSite",
2662
+ "search_keyword": "SearchKeyword",
2663
+ "write_pdf": "CreatePDF",
2664
+ "write_docx": "CreateDocument",
2665
+ "generate_image": "GenerateImage",
2666
+ // PascalCase Support
2667
+ "WriteFile": "WriteFile",
2668
+ "PatchFile": "PatchFile",
2669
+ "ReadFolder": "ReadFolder",
2670
+ "ReadFile": "ReadFile",
2671
+ "Run": "RunCommand",
2672
+ "WebSearch": "WebSearch",
2673
+ "WebScrape": "WebScrape",
2674
+ "SearchKeyword": "SearchKeyword",
2675
+ "WritePDF": "WritePDF",
2676
+ "WriteDoc": "WriteDoc",
2677
+ "Memory": "Memory",
2678
+ "Chat": "Chat",
2679
+ "GenerateImage": "GenerateImage"
2680
+ };
2681
+ cleanSignals = (text) => {
2682
+ if (!text) return text;
2683
+ let result = text.replace(/<\/think>(\r?\n){2}/gi, "</think>").replace(/(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi, "");
2684
+ const trigger = "tool:functions.";
2685
+ while (true) {
2686
+ const lowerResult = result.toLowerCase();
2687
+ let triggerIdx = lowerResult.indexOf(trigger);
2688
+ if (triggerIdx === -1) break;
2689
+ let startIdx = triggerIdx;
2690
+ let hasOuterBracket = false;
2691
+ let k = triggerIdx - 1;
2692
+ while (k >= 0 && /\s/.test(result[k])) k--;
2693
+ if (k >= 0 && result[k] === "[") {
2694
+ startIdx = k;
2695
+ hasOuterBracket = true;
2315
2696
  }
2316
- const identity = (t) => t;
2317
- if (key.upArrow || key.downArrow) {
2318
- if (showCursor) {
2319
- const { visualLines, cursorLine, cursorCol } = computeVisualMatrix(val, curIdx, wrapWidth, identity);
2320
- const targetLine = key.upArrow ? cursorLine - 1 : cursorLine + 1;
2321
- if (targetLine >= 0 && targetLine < visualLines.length) {
2322
- const targetLineObj = visualLines[targetLine];
2323
- const targetCol = Math.min(cursorCol, targetLineObj.text.length);
2324
- const newIndex = targetLineObj.globalStart + targetCol;
2325
- cursorIndexRef.current = newIndex;
2326
- setCursorIndex(newIndex);
2327
- setPasteLength(0);
2328
- } else if (key.upArrow && cursorLine === 0) {
2329
- cursorIndexRef.current = 0;
2330
- setCursorIndex(0);
2331
- setPasteLength(0);
2332
- } else if (key.downArrow && cursorLine === visualLines.length - 1) {
2333
- const lastLineObj = visualLines[visualLines.length - 1];
2334
- const newIndex = lastLineObj.globalStart + lastLineObj.text.length;
2335
- cursorIndexRef.current = newIndex;
2336
- setCursorIndex(newIndex);
2337
- setPasteLength(0);
2338
- }
2339
- }
2340
- } else if (key.leftArrow) {
2341
- if (showCursor) {
2342
- const newIndex = Math.max(0, curIdx - 1);
2343
- cursorIndexRef.current = newIndex;
2344
- setCursorIndex(newIndex);
2345
- setPasteLength(0);
2346
- }
2347
- } else if (key.rightArrow) {
2348
- if (showCursor) {
2349
- const newIndex = Math.min(val.length, curIdx + 1);
2350
- cursorIndexRef.current = newIndex;
2351
- setCursorIndex(newIndex);
2352
- setPasteLength(0);
2353
- }
2354
- } else if (key.backspace) {
2355
- if (curIdx > 0) {
2356
- const newValue = val.slice(0, curIdx - 1) + val.slice(curIdx);
2357
- onChange(newValue);
2358
- cursorIndexRef.current = curIdx - 1;
2359
- setCursorIndex(curIdx - 1);
2360
- setPasteLength(0);
2697
+ let balance = 0;
2698
+ let foundStart = false;
2699
+ let inString = null;
2700
+ let j = triggerIdx;
2701
+ while (j < result.length) {
2702
+ const char = result[j];
2703
+ if (!inString && (char === "'" || char === '"' || char === "`")) {
2704
+ inString = char;
2705
+ } else if (inString && char === inString && result[j - 1] !== "\\") {
2706
+ inString = null;
2361
2707
  }
2362
- } else if (key.delete) {
2363
- if (curIdx < val.length) {
2364
- const newValue = val.slice(0, curIdx) + val.slice(curIdx + 1);
2365
- onChange(newValue);
2366
- setPasteLength(0);
2708
+ if (!inString) {
2709
+ if (char === "(") {
2710
+ balance++;
2711
+ foundStart = true;
2712
+ } else if (char === ")") {
2713
+ balance--;
2714
+ }
2367
2715
  }
2368
- } else if (key.home || key.end) {
2369
- if (showCursor) {
2370
- const { visualLines, cursorLine } = computeVisualMatrix(val, curIdx, wrapWidth, identity);
2371
- const currentLineObj = visualLines[cursorLine];
2372
- if (currentLineObj) {
2373
- let newIndex;
2374
- if (key.home) {
2375
- newIndex = currentLineObj.globalStart;
2376
- } else if (key.end) {
2377
- newIndex = currentLineObj.globalStart + currentLineObj.text.length;
2716
+ if (foundStart && balance === 0 && !inString) {
2717
+ let endIdx = j;
2718
+ if (hasOuterBracket) {
2719
+ let m = j + 1;
2720
+ while (m < result.length && /\s/.test(result[m])) m++;
2721
+ if (m < result.length && result[m] === "]") {
2722
+ endIdx = m;
2378
2723
  }
2379
- cursorIndexRef.current = newIndex;
2380
- setCursorIndex(newIndex);
2381
- setPasteLength(0);
2382
2724
  }
2725
+ result = result.substring(0, startIdx) + result.substring(endIdx + 1);
2726
+ break;
2383
2727
  }
2384
- } else {
2385
- if (input) {
2386
- const newValue = val.slice(0, curIdx) + input + val.slice(curIdx);
2387
- onChange(newValue);
2388
- const newIndex = curIdx + input.length;
2389
- cursorIndexRef.current = newIndex;
2390
- setCursorIndex(newIndex);
2391
- setPasteLength(input.length > 1 ? input.length : 0);
2728
+ j++;
2729
+ if (j === result.length) {
2730
+ result = result.substring(0, startIdx);
2731
+ return result;
2392
2732
  }
2393
2733
  }
2394
- }, focus);
2395
- return /* @__PURE__ */ React2.createElement(
2396
- ControlledMultilineInput,
2397
- {
2398
- ...controlledProps,
2399
- value,
2400
- cursorIndex,
2401
- showCursor,
2402
- focus,
2403
- columns
2404
- }
2405
- );
2734
+ }
2735
+ return result.replaceAll(/\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi, "").replaceAll(/<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi, "").replace(/\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi, "").replaceAll(/\[TOOL RESULT\]:?\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replaceAll(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replaceAll(/\[\[END\]\]/gi, "").replaceAll(/\[\s*turn\s*:?.*?$/gi, "").replaceAll(/\n\s*turn\s*:?.*?$/gi, "").replaceAll(/\[\s*$/gi, "").replaceAll(/\n\nResponded on .*/g, "").replaceAll(/\n\n\[Prompted on: .*\]/g, "").replaceAll(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replaceAll(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replaceAll(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replaceAll(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replaceAll(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replaceAll(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replaceAll(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx|generate_image)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
2406
2736
  };
2407
2737
  }
2408
2738
  });
2409
2739
 
2410
- // src/utils/text.js
2411
- import os2 from "os";
2412
- var wrapText, formatTokens, truncatePath, parsePatchPairs, applyPatches, generateHighFidelityDiff, parseMessageToBlocks, TOOL_LABELS, cleanSignals;
2413
- var init_text = __esm({
2414
- "src/utils/text.js"() {
2415
- init_paths();
2416
- wrapText = (text, width) => {
2417
- if (!text) return "";
2418
- const ansiRegex2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
2419
- const sourceLines = text.split("\n");
2420
- let finalLines = [];
2421
- if (width <= 5) return text;
2422
- const getVisibleLength = (str) => str.replace(ansiRegex2, "").length;
2423
- sourceLines.forEach((sLine) => {
2424
- const visibleLength = getVisibleLength(sLine);
2425
- if (visibleLength <= width) {
2426
- finalLines.push(sLine);
2427
- return;
2428
- }
2429
- const tokens = sLine.split(/(\s+)/);
2430
- let currentLine = "";
2431
- let currentVisibleLength = 0;
2432
- const leadingSpaceMatch = sLine.match(/^(\s*)/);
2433
- const indent = leadingSpaceMatch ? leadingSpaceMatch[1] : "";
2434
- tokens.forEach((token, idx) => {
2435
- if (token.length === 0) return;
2436
- const tokenVisibleLength = getVisibleLength(token);
2437
- if (currentVisibleLength + tokenVisibleLength > width) {
2438
- if (currentLine.trim().length > 0) {
2439
- finalLines.push(currentLine.trimEnd());
2440
- currentLine = indent + token;
2441
- currentVisibleLength = getVisibleLength(currentLine);
2442
- } else {
2443
- if (ansiRegex2.test(token)) {
2444
- finalLines.push(token);
2445
- currentLine = indent;
2446
- currentVisibleLength = getVisibleLength(currentLine);
2447
- } else {
2448
- let word = token;
2449
- while (getVisibleLength(word) > width && width > 10) {
2450
- finalLines.push(word.substring(0, width));
2451
- word = word.substring(width);
2452
- }
2453
- currentLine = word;
2454
- currentVisibleLength = getVisibleLength(currentLine);
2455
- }
2456
- }
2457
- } else {
2458
- currentLine += token;
2459
- currentVisibleLength += tokenVisibleLength;
2460
- }
2461
- });
2462
- if (currentLine.trimEnd().length > 0 || currentLine === indent) {
2463
- finalLines.push(currentLine.trimEnd());
2464
- }
2465
- });
2466
- return finalLines.join("\n");
2467
- };
2468
- formatTokens = (tokens) => {
2469
- if (!tokens && tokens !== 0) return "0.0k";
2470
- const num = typeof tokens === "string" ? parseFloat(tokens) : tokens;
2471
- if (num >= 1e6) {
2472
- return `${(num / 1e6).toFixed(1)}m`;
2473
- } else if (num >= 1e3) {
2474
- return `${(num / 1e3).toFixed(1)}k`;
2475
- }
2476
- return num.toString();
2477
- };
2478
- truncatePath = (p, maxLength = 40) => {
2479
- let data_dir = DATA_DIR.replaceAll("\\\\", "\\");
2480
- p = p.replace(os2.homedir(), "~").replace(data_dir, "FluxFlow").replaceAll("\\", "/");
2481
- if (!p || p.length <= maxLength) return p;
2482
- const half = Math.floor((maxLength - 3) / 2);
2483
- return p.substring(0, half) + "..." + p.substring(p.length - half).replaceAll("\\", "/");
2484
- };
2485
- parsePatchPairs = (args) => {
2486
- const patchPairs = [];
2487
- const indices = /* @__PURE__ */ new Set();
2488
- Object.keys(args).forEach((key) => {
2489
- const m = key.match(/^(replaceContent|newContent|content_to_replace|content_to_add)(\d+)?$/);
2490
- if (m) {
2491
- const index = m[2] ? parseInt(m[2]) : 1;
2492
- indices.add(index);
2493
- }
2494
- });
2495
- const sortedIndices = Array.from(indices).sort((a, b) => a - b);
2496
- for (const i of sortedIndices) {
2497
- let r, n;
2498
- if (i === 1) {
2499
- r = args.replaceContent1 ?? (args.content_to_replace ?? args.replaceContent);
2500
- n = args.newContent1 ?? (args.content_to_add ?? args.newContent);
2501
- } else {
2502
- r = args[`replaceContent${i}`] ?? args[`content_to_replace${i}`];
2503
- n = args[`newContent${i}`] ?? args[`content_to_add${i}`];
2504
- }
2505
- if (r !== void 0 && n !== void 0) {
2506
- patchPairs.push({ replace: r, new: n });
2507
- } else if (r !== void 0 || n !== void 0) {
2508
- return { error: `Mismatched replacement pair for index ${i}. Both replacement and new content must be provided.` };
2509
- }
2740
+ // src/components/MultilineInput.jsx
2741
+ import React2, { useState as useState2, useEffect as useEffect2, useMemo, useCallback, useRef } from "react";
2742
+ import { Box, Text as Text2, useInput } from "ink";
2743
+ function expandTabs(text, tabSize) {
2744
+ return text.replace(/\t/g, " ".repeat(tabSize));
2745
+ }
2746
+ function normalizeLineEndings(text) {
2747
+ if (text == null) return "";
2748
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2749
+ }
2750
+ function formattedToRaw(formattedIdx, pasteBlocks, value) {
2751
+ let rawIdx = formattedIdx;
2752
+ const sortedBlocks = [...pasteBlocks].sort((a, b) => a.start - b.start);
2753
+ let currentFormattedOffset = 0;
2754
+ for (const block of sortedBlocks) {
2755
+ const formattedStart = block.start - currentFormattedOffset;
2756
+ const lines = normalizeLineEndings(block.text).split("\n").length;
2757
+ const chars = block.text.length;
2758
+ const placeholderLength = (lines > 3 ? `[Pasted ${lines} lines]` : `[Pasted ${chars} chars]`).length;
2759
+ const formattedEnd = formattedStart + placeholderLength;
2760
+ if (formattedIdx <= formattedStart) {
2761
+ break;
2762
+ } else if (formattedIdx < formattedEnd) {
2763
+ rawIdx = block.end;
2764
+ break;
2765
+ } else {
2766
+ const delta = block.text.length - placeholderLength;
2767
+ rawIdx += delta;
2768
+ currentFormattedOffset += delta;
2769
+ }
2770
+ }
2771
+ return Math.min(rawIdx, value.length);
2772
+ }
2773
+ function computeVisualMatrix(value, cursorIndex, wrapWidth, formatText, pasteBlocks = []) {
2774
+ const textBefore = (value || "").slice(0, cursorIndex);
2775
+ let visualCursorIdx = formatText(textBefore).length;
2776
+ let fullFormatted = formatText(value || "");
2777
+ const sortedBlocks = [...pasteBlocks].sort((a, b) => b.start - a.start);
2778
+ for (const block of sortedBlocks) {
2779
+ const formattedStart = formatText(value.slice(0, block.start)).length;
2780
+ const formattedPasted = formatText(block.text);
2781
+ const formattedEnd = formattedStart + formattedPasted.length;
2782
+ const lines = normalizeLineEndings(block.text).split("\n").length;
2783
+ const chars = block.text.length;
2784
+ const placeholderText = lines > 3 ? `[Pasted ${lines} lines]` : `[Pasted ${chars} chars]`;
2785
+ fullFormatted = fullFormatted.slice(0, formattedStart) + placeholderText + fullFormatted.slice(formattedEnd);
2786
+ if (visualCursorIdx > formattedStart && visualCursorIdx < formattedEnd) {
2787
+ visualCursorIdx = formattedStart + placeholderText.length;
2788
+ } else if (visualCursorIdx >= formattedEnd) {
2789
+ visualCursorIdx = visualCursorIdx - (formattedEnd - formattedStart) + placeholderText.length;
2790
+ }
2791
+ }
2792
+ const literalLines = fullFormatted.split("\n");
2793
+ const visualLines = [];
2794
+ let currentIdx = 0;
2795
+ let cursorLine = 0;
2796
+ let cursorCol = 0;
2797
+ let foundCursor = false;
2798
+ for (let i = 0; i < literalLines.length; i++) {
2799
+ const line = literalLines[i];
2800
+ if (line.length === 0) {
2801
+ if (!foundCursor && visualCursorIdx === currentIdx) {
2802
+ cursorLine = visualLines.length;
2803
+ cursorCol = 0;
2804
+ foundCursor = true;
2510
2805
  }
2511
- return { patchPairs };
2512
- };
2513
- applyPatches = (content, patches) => {
2514
- let currentFileContent = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2515
- const strip = (t) => t.replace(/^```[\w]*\n?/, "").replace(/```\s*$/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2516
- const getIndent = (line) => line.match(/^\s*/)[0];
2517
- const getMinIndent = (text) => {
2518
- const lines = text.split("\n").filter((l) => l.trim() !== "");
2519
- if (lines.length === 0) return "";
2520
- let min = getIndent(lines[0]);
2521
- for (const line of lines) {
2522
- const indent = getIndent(line);
2523
- if (indent.length < min.length) min = indent;
2524
- }
2525
- return min;
2526
- };
2527
- const adjustIndentation = (newText, originalMatch, leadingContext = "") => {
2528
- if (!newText || originalMatch === void 0) return newText;
2529
- const getIndentStyle = (text) => {
2530
- const lines = text.split("\n").filter((l) => l.trim() !== "");
2531
- if (lines.length === 0) return { char: " ", size: 4 };
2532
- const firstIndent = lines[0].match(/^\s*/)[0];
2533
- if (firstIndent.includes(" ")) return { char: " ", size: 1 };
2534
- const indents = lines.map((l) => l.match(/^\s*/)[0].length).filter((l) => l > 0);
2535
- if (indents.length === 0) return { char: " ", size: firstIndent.length || 4 };
2536
- const gcd = (a, b) => b ? gcd(b, a % b) : a;
2537
- const step = indents.reduce((a, b) => gcd(a, b));
2538
- return { char: " ", size: step || 4 };
2539
- };
2540
- const fileStyle = getIndentStyle(originalMatch);
2541
- const modelStyle = getIndentStyle(newText);
2542
- const matchMinIndent = getMinIndent(originalMatch).length;
2543
- const leadingIndent = (leadingContext.match(/^\s*/) || [""])[0].length;
2544
- const targetBaseIndentRaw = leadingIndent + matchMinIndent;
2545
- const targetUnits = targetBaseIndentRaw / fileStyle.size;
2546
- const modelBaseUnits = getMinIndent(newText).length / modelStyle.size;
2547
- const deltaUnits = targetUnits - modelBaseUnits;
2548
- const newLines = newText.split("\n");
2549
- return newLines.map((line, i) => {
2550
- if (line.trim() === "" && i !== 0) return "";
2551
- const currentLineUnits = line.match(/^\s*/)[0].length / modelStyle.size;
2552
- const finalUnits = Math.max(0, currentLineUnits + deltaUnits);
2553
- let unitCount = finalUnits;
2554
- if (i === 0) {
2555
- const leadingUnits = leadingIndent / fileStyle.size;
2556
- unitCount = Math.max(0, finalUnits - leadingUnits);
2557
- }
2558
- return fileStyle.char.repeat(unitCount * fileStyle.size) + line.trimStart();
2559
- }).join("\n");
2560
- };
2561
- const patchMatches = [];
2562
- for (let i = 0; i < patches.length; i++) {
2563
- const pair = patches[i];
2564
- const content_to_replace = strip(pair.replace || "");
2565
- const content_to_add = strip(pair.new || "");
2566
- if (content_to_replace === "" && content_to_add === "") {
2567
- patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Empty replace and add content.` });
2568
- continue;
2569
- }
2570
- const exactPattern = content_to_replace.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2571
- let matchRegex = null;
2572
- if (content_to_replace !== "" && currentFileContent.includes(content_to_replace)) {
2573
- matchRegex = new RegExp(exactPattern, "g");
2574
- } else {
2575
- 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*"));
2576
- if (fuzzyLines.length > 0) {
2577
- const fuzzyPattern = fuzzyLines.join("\\s*");
2578
- try {
2579
- matchRegex = new RegExp(fuzzyPattern, "g");
2580
- } catch (e) {
2581
- matchRegex = new RegExp(exactPattern, "g");
2806
+ visualLines.push({ text: "", globalStart: formattedToRaw(currentIdx, pasteBlocks, value), formattedStart: currentIdx });
2807
+ currentIdx += 1;
2808
+ continue;
2809
+ }
2810
+ const wrapped = wrapText(line, wrapWidth);
2811
+ const wrappedLines = wrapped.split("\n");
2812
+ let lastMatchEnd = 0;
2813
+ const chunks = [];
2814
+ for (let j = 0; j < wrappedLines.length; j++) {
2815
+ const wLine = wrappedLines[j];
2816
+ const trimmed = wLine.trim();
2817
+ if (trimmed.length === 0) {
2818
+ const spaceLength = wLine.length || 1;
2819
+ chunks.push({
2820
+ text: wLine,
2821
+ start: lastMatchEnd,
2822
+ length: spaceLength
2823
+ });
2824
+ lastMatchEnd += spaceLength;
2825
+ } else {
2826
+ const idx = line.indexOf(trimmed, lastMatchEnd);
2827
+ if (idx !== -1) {
2828
+ const start = lastMatchEnd;
2829
+ const nextTrimmed = j < wrappedLines.length - 1 ? wrappedLines[j + 1].trim() : "";
2830
+ let end = line.length;
2831
+ if (nextTrimmed.length > 0) {
2832
+ const nextIdx = line.indexOf(nextTrimmed, idx + trimmed.length);
2833
+ if (nextIdx !== -1) {
2834
+ end = nextIdx;
2582
2835
  }
2583
- } else {
2584
- matchRegex = new RegExp(exactPattern, "g");
2585
2836
  }
2837
+ chunks.push({
2838
+ text: line.slice(start, end),
2839
+ start,
2840
+ length: end - start
2841
+ });
2842
+ lastMatchEnd = end;
2843
+ } else {
2844
+ chunks.push({
2845
+ text: wLine,
2846
+ start: lastMatchEnd,
2847
+ length: wLine.length
2848
+ });
2849
+ lastMatchEnd += wLine.length;
2586
2850
  }
2587
- const matches = [...currentFileContent.matchAll(matchRegex)];
2588
- if (matches.length === 0) {
2589
- patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Could not find match.` });
2590
- continue;
2591
- }
2592
- if (matches.length > 1) {
2593
- patchMatches.push({ index: i, success: false, error: `Block ${i + 1}: Found ${matches.length} matches (must be unique).` });
2594
- continue;
2595
- }
2596
- patchMatches.push({
2597
- index: i,
2598
- success: true,
2599
- startPos: matches[0].index,
2600
- firstMatchContent: matches[0][0],
2601
- content_to_add
2602
- });
2603
2851
  }
2604
- const successful = patchMatches.filter((m) => m.success).sort((a, b) => a.startPos - b.startPos);
2605
- for (let j = 0; j < successful.length - 1; j++) {
2606
- const curr = successful[j];
2607
- const next = successful[j + 1];
2608
- if (curr.startPos + curr.firstMatchContent.length > next.startPos) {
2609
- curr.success = false;
2610
- curr.error = `Block ${curr.index + 1}: Overlaps with another block.`;
2611
- next.success = false;
2612
- next.error = `Block ${next.index + 1}: Overlaps with another block.`;
2613
- }
2852
+ }
2853
+ for (let idx = 0; idx < chunks.length; idx++) {
2854
+ const chunkObj = chunks[idx];
2855
+ const chunk = chunkObj.text;
2856
+ const chunkStart = currentIdx + chunkObj.start;
2857
+ const chunkEnd = chunkStart + chunkObj.length;
2858
+ if (!foundCursor && visualCursorIdx >= chunkStart && (visualCursorIdx < chunkEnd || visualCursorIdx === chunkEnd && idx === chunks.length - 1)) {
2859
+ cursorLine = visualLines.length;
2860
+ cursorCol = visualCursorIdx - chunkStart;
2861
+ foundCursor = true;
2614
2862
  }
2615
- const resultsMap = /* @__PURE__ */ new Map();
2616
- let finalContent = currentFileContent;
2617
- let charOffset = 0;
2618
- let lineOffset = 0;
2619
- const toApply = patchMatches.filter((m) => m.success).sort((a, b) => a.startPos - b.startPos);
2620
- for (const match of toApply) {
2621
- const originalStartPos = match.startPos;
2622
- const originalStartLine = currentFileContent.substring(0, originalStartPos).split("\n").length;
2623
- const finalStartPos = originalStartPos + charOffset;
2624
- const finalStartLine = originalStartLine + lineOffset;
2625
- const lineStart = finalContent.lastIndexOf("\n", finalStartPos) + 1;
2626
- const leadingContext = finalContent.substring(lineStart, finalStartPos);
2627
- const finalReplacement = adjustIndentation(match.content_to_add, match.firstMatchContent, leadingContext);
2628
- const allLines = finalContent.split("\n");
2629
- const contextBefore = [];
2630
- for (let j = Math.max(0, finalStartLine - 4); j < finalStartLine - 1; j++) {
2631
- contextBefore.push({ num: j + 1, text: allLines[j] });
2632
- }
2633
- const patchOldLines = match.firstMatchContent.split("\n");
2634
- const contextAfter = [];
2635
- const patchEndLineIdx = finalStartLine + patchOldLines.length - 1;
2636
- for (let j = patchEndLineIdx; j < Math.min(allLines.length, patchEndLineIdx + 3); j++) {
2637
- contextAfter.push({ num: j + 1, text: allLines[j] });
2638
- }
2639
- resultsMap.set(match.index, {
2640
- success: true,
2641
- oldContent: match.firstMatchContent,
2642
- newContent: finalReplacement,
2643
- originalStartLine,
2644
- finalStartLine,
2645
- contextBefore,
2646
- contextAfter
2863
+ visualLines.push({
2864
+ text: chunk,
2865
+ globalStart: formattedToRaw(chunkStart, pasteBlocks, value),
2866
+ formattedStart: chunkStart
2867
+ });
2868
+ }
2869
+ currentIdx += line.length + 1;
2870
+ }
2871
+ if (!foundCursor) {
2872
+ if (visualLines.length === 0) {
2873
+ visualLines.push({ text: "", globalStart: 0, formattedStart: 0 });
2874
+ } else {
2875
+ if (fullFormatted.endsWith("\n")) {
2876
+ visualLines.push({
2877
+ text: "",
2878
+ globalStart: formattedToRaw(currentIdx, pasteBlocks, value),
2879
+ formattedStart: currentIdx
2647
2880
  });
2648
- finalContent = finalContent.substring(0, finalStartPos) + finalReplacement + finalContent.substring(finalStartPos + match.firstMatchContent.length);
2649
- charOffset += finalReplacement.length - match.firstMatchContent.length;
2650
- lineOffset += finalReplacement.split("\n").length - match.firstMatchContent.split("\n").length;
2651
- }
2652
- const results = [];
2653
- for (let i = 0; i < patches.length; i++) {
2654
- if (resultsMap.has(i)) {
2655
- results.push(resultsMap.get(i));
2656
- } else {
2657
- const match = patchMatches.find((m) => m.index === i);
2658
- results.push({
2659
- success: false,
2660
- error: match ? match.error : `Block ${i + 1}: Unknown error.`
2661
- });
2662
- }
2881
+ cursorLine = visualLines.length - 1;
2882
+ cursorCol = 0;
2883
+ } else {
2884
+ cursorLine = visualLines.length - 1;
2885
+ cursorCol = visualLines[cursorLine].text.length;
2663
2886
  }
2664
- return { content: finalContent, results };
2665
- };
2666
- generateHighFidelityDiff = (originalContent, finalContent, patchResults, threshold = 8) => {
2667
- if (!patchResults || patchResults.length === 0) return "";
2668
- const allLinesOriginal = originalContent.split(/\r?\n/);
2669
- const allLinesFinal = finalContent.split(/\r?\n/);
2670
- let diffText = `[DIFF_START]
2671
- `;
2672
- const separatorLine = "\u2550".repeat(88);
2673
- let currentFinalLineIdx = 0;
2674
- let lastSuccessfulHunk = null;
2675
- const sortedResults = patchResults.filter((res) => res.success).sort((a, b) => a.originalStartLine - b.originalStartLine);
2676
- sortedResults.forEach((res, idx) => {
2677
- const startLineFinal = res.finalStartLine !== void 0 ? res.finalStartLine : res.originalStartLine;
2678
- if (lastSuccessfulHunk === null) {
2679
- const contextStart = Math.max(0, startLineFinal - 4);
2680
- currentFinalLineIdx = contextStart;
2681
- while (currentFinalLineIdx < startLineFinal - 1) {
2682
- diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2683
- `;
2684
- currentFinalLineIdx++;
2887
+ }
2888
+ }
2889
+ return { visualLines, cursorLine, cursorCol };
2890
+ }
2891
+ var ControlledMultilineInput, MultilineInput;
2892
+ var init_MultilineInput = __esm({
2893
+ "src/components/MultilineInput.jsx"() {
2894
+ init_text();
2895
+ ControlledMultilineInput = ({
2896
+ value,
2897
+ rows,
2898
+ maxRows,
2899
+ highlightStyle,
2900
+ textStyle,
2901
+ placeholder = "",
2902
+ mask,
2903
+ showCursor = true,
2904
+ focus = true,
2905
+ tabSize = 4,
2906
+ cursorIndex = 0,
2907
+ highlight,
2908
+ columns = 80,
2909
+ pasteBlocks = []
2910
+ }) => {
2911
+ const scrollOffsetRef = useRef(0);
2912
+ const wrapWidth = useMemo(() => Math.max(20, columns - 10), [columns]);
2913
+ const formatText = useCallback(
2914
+ (text, isPlaceholder = false) => {
2915
+ const normalized = normalizeLineEndings(text);
2916
+ if (!isPlaceholder && mask) {
2917
+ return normalized.replace(/[^\n]/g, mask);
2685
2918
  }
2686
- } else {
2687
- const prev = lastSuccessfulHunk;
2688
- const prevOriginalEnd = prev.originalStartLine + prev.oldContent.split("\n").length - 1;
2689
- const gap = res.originalStartLine - prevOriginalEnd - 1;
2690
- if (gap >= threshold) {
2691
- let afterLimit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
2692
- while (currentFinalLineIdx < afterLimit) {
2693
- diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2694
- `;
2695
- currentFinalLineIdx++;
2919
+ const expanded = expandTabs(normalized, tabSize);
2920
+ if (isPlaceholder) return expanded;
2921
+ return expanded.replace(/@\[(.*?)\]/g, (match, p1) => {
2922
+ const hashIdx = p1.indexOf("#");
2923
+ const colonIdx = p1.indexOf(":L");
2924
+ let pathOnly = p1;
2925
+ let suffix = "";
2926
+ if (hashIdx !== -1) {
2927
+ pathOnly = p1.slice(0, hashIdx);
2928
+ suffix = p1.slice(hashIdx);
2929
+ } else if (colonIdx !== -1) {
2930
+ pathOnly = p1.slice(0, colonIdx);
2931
+ suffix = p1.slice(colonIdx);
2696
2932
  }
2697
- diffText += `[UI_CONTEXT] ${separatorLine}
2698
- `;
2699
- const beforeStart = Math.max(currentFinalLineIdx, startLineFinal - 4);
2700
- currentFinalLineIdx = beforeStart;
2701
- while (currentFinalLineIdx < startLineFinal - 1) {
2702
- diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2703
- `;
2704
- currentFinalLineIdx++;
2933
+ let rel = pathOnly.replace(/\\/g, "/");
2934
+ const cwd = (process.cwd() || "").replace(/\\/g, "/");
2935
+ if (cwd && rel.toLowerCase().startsWith(cwd.toLowerCase() + "/")) {
2936
+ rel = rel.slice(cwd.length + 1);
2937
+ } else if (rel.startsWith("./")) {
2938
+ rel = rel.slice(2);
2705
2939
  }
2940
+ const parts = rel.split("/");
2941
+ const basename = parts[parts.length - 1];
2942
+ return `[${basename}${suffix}]`;
2943
+ });
2944
+ },
2945
+ [tabSize, mask]
2946
+ );
2947
+ const { visualLines, cursorLine, cursorCol } = useMemo(() => {
2948
+ return computeVisualMatrix(value, cursorIndex, wrapWidth, formatText, pasteBlocks);
2949
+ }, [value, cursorIndex, wrapWidth, formatText, pasteBlocks]);
2950
+ const contentHeight = visualLines.length;
2951
+ const visibleRows = useMemo(() => {
2952
+ return Math.max(rows ?? maxRows ?? 1, Math.min(maxRows ?? rows ?? 1, contentHeight));
2953
+ }, [rows, maxRows, contentHeight]);
2954
+ const cursorLineEnd = cursorLine + 1;
2955
+ const viewportEnd = scrollOffsetRef.current + visibleRows;
2956
+ let newScrollOffset = scrollOffsetRef.current;
2957
+ if (cursorLineEnd <= scrollOffsetRef.current) {
2958
+ newScrollOffset = Math.max(0, cursorLineEnd - 1);
2959
+ } else if (cursorLineEnd > viewportEnd) {
2960
+ newScrollOffset = cursorLineEnd - visibleRows;
2961
+ } else if (contentHeight) {
2962
+ if (contentHeight < visibleRows) {
2963
+ newScrollOffset = 0;
2964
+ } else if (contentHeight < viewportEnd) {
2965
+ newScrollOffset = contentHeight - visibleRows;
2966
+ }
2967
+ }
2968
+ scrollOffsetRef.current = newScrollOffset;
2969
+ const visibleLines = useMemo(() => {
2970
+ return visualLines.slice(newScrollOffset, newScrollOffset + visibleRows);
2971
+ }, [visualLines, newScrollOffset, visibleRows]);
2972
+ const [blink, setBlink] = useState2(true);
2973
+ useEffect2(() => {
2974
+ setBlink(true);
2975
+ if (!focus || !showCursor) return;
2976
+ const timer = setInterval(() => {
2977
+ setBlink((prev) => !prev);
2978
+ }, 530);
2979
+ return () => clearInterval(timer);
2980
+ }, [focus, showCursor, value, cursorIndex]);
2981
+ const cursorStyle = useMemo(() => ({
2982
+ ...textStyle,
2983
+ color: showCursor && focus && blink ? "white" : void 0,
2984
+ bold: showCursor && focus && blink,
2985
+ inverse: showCursor && focus && blink
2986
+ }), [textStyle, showCursor, focus, blink]);
2987
+ const renderLineText = (text, isCursor, col, cStyle) => {
2988
+ if (!text) {
2989
+ const emptyText = placeholder && value.length === 0 ? formatText(placeholder, true) : "";
2990
+ if (isCursor) {
2991
+ const charAtCursor = emptyText[0] || " ";
2992
+ const right = emptyText.slice(1);
2993
+ return /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { ...cStyle }, charAtCursor), /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true }, right));
2994
+ }
2995
+ return /* @__PURE__ */ React2.createElement(Text2, { color: "gray", dimColor: true }, emptyText || " ");
2996
+ }
2997
+ const regex2 = /(\[Pasted \d+ (?:lines|chars)\])/g;
2998
+ const parts = text.split(regex2);
2999
+ let currentOffset = 0;
3000
+ const rendered = [];
3001
+ for (let i = 0; i < parts.length; i++) {
3002
+ const part = parts[i];
3003
+ if (part === "") continue;
3004
+ const isPlaceholder = part.match(/^\[Pasted \d+ (?:lines|chars)\]$/);
3005
+ const partLength = part.length;
3006
+ const partEnd = currentOffset + partLength;
3007
+ if (isCursor && col >= currentOffset && col < partEnd) {
3008
+ const localCol = col - currentOffset;
3009
+ const left = part.slice(0, localCol);
3010
+ const charAtCursor = part[localCol] || " ";
3011
+ const right = part.slice(localCol + 1);
3012
+ rendered.push(
3013
+ /* @__PURE__ */ React2.createElement(Text2, { key: i }, /* @__PURE__ */ React2.createElement(Text2, { color: isPlaceholder ? "magenta" : void 0 }, left), /* @__PURE__ */ React2.createElement(Text2, { ...cStyle }, charAtCursor), /* @__PURE__ */ React2.createElement(Text2, { color: isPlaceholder ? "magenta" : void 0 }, right))
3014
+ );
2706
3015
  } else {
2707
- while (currentFinalLineIdx < startLineFinal - 1) {
2708
- diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2709
- `;
2710
- currentFinalLineIdx++;
2711
- }
3016
+ rendered.push(
3017
+ /* @__PURE__ */ React2.createElement(Text2, { key: i, color: isPlaceholder ? "magenta" : void 0 }, part)
3018
+ );
2712
3019
  }
3020
+ currentOffset = partEnd;
3021
+ }
3022
+ if (isCursor && col >= text.length) {
3023
+ rendered.push(
3024
+ /* @__PURE__ */ React2.createElement(Text2, { key: "cursor-end", ...cStyle }, " ")
3025
+ );
3026
+ }
3027
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, rendered);
3028
+ };
3029
+ return /* @__PURE__ */ React2.createElement(Box, { height: visibleRows, width: wrapWidth + 1, overflow: "hidden", flexDirection: "column", flexGrow: 0, flexShrink: 0 }, visibleLines.map((lineObj, idx) => {
3030
+ const globalLineIdx = newScrollOffset + idx;
3031
+ const isCursorLine = globalLineIdx === cursorLine && focus && showCursor;
3032
+ return /* @__PURE__ */ React2.createElement(Text2, { key: globalLineIdx, ...textStyle, wrap: "truncate" }, renderLineText(lineObj.text, isCursorLine, cursorCol, cursorStyle));
3033
+ }));
3034
+ };
3035
+ MultilineInput = ({
3036
+ value,
3037
+ onChange,
3038
+ onSubmit,
3039
+ keyBindings,
3040
+ showCursor = true,
3041
+ highlightPastedText = false,
3042
+ focus = true,
3043
+ columns = 80,
3044
+ useCustomInput = (inputHandler, isActive) => useInput(inputHandler, { isActive }),
3045
+ onPasteStateChange,
3046
+ ...controlledProps
3047
+ }) => {
3048
+ const [cursorIndex, setCursorIndex] = useState2(value.length);
3049
+ const [pasteLength, setPasteLength] = useState2(0);
3050
+ const [pasteBlocks, setPasteBlocks] = useState2([]);
3051
+ const cursorIndexRef = useRef(value.length);
3052
+ const valueRef = useRef(value);
3053
+ const pasteLengthRef = useRef(0);
3054
+ const pasteBlocksRef = useRef([]);
3055
+ const pasteBufferRef = useRef("");
3056
+ const pasteBufferStartRef = useRef(-1);
3057
+ const pasteTimerRef = useRef(null);
3058
+ const lastArrowTimeRef = useRef(0);
3059
+ cursorIndexRef.current = cursorIndex;
3060
+ valueRef.current = value;
3061
+ pasteLengthRef.current = pasteLength;
3062
+ pasteBlocksRef.current = pasteBlocks;
3063
+ useEffect2(() => {
3064
+ if (cursorIndexRef.current > value.length) {
3065
+ cursorIndexRef.current = value.length;
3066
+ setCursorIndex(value.length);
2713
3067
  }
2714
- const oldLines = res.oldContent.split("\n");
2715
- oldLines.forEach((line, i) => {
2716
- diffText += `-${res.originalStartLine + i}|${line}
2717
- `;
2718
- });
2719
- let hunkEndInFinal = currentFinalLineIdx;
2720
- if (res.finalStartLine !== void 0) {
2721
- hunkEndInFinal = res.finalStartLine - 1 + (res.newContent ? res.newContent.split("\n").length : 0);
3068
+ if (!value) {
3069
+ setPasteBlocks([]);
3070
+ setPasteLength(0);
2722
3071
  } else {
2723
- const originalResyncLineIdx = res.originalStartLine + oldLines.length - 1;
2724
- const resyncAnchorText = allLinesOriginal[originalResyncLineIdx] || null;
2725
- if (resyncAnchorText !== null) {
2726
- const lookAheadLimit = idx < sortedResults.length - 1 ? (sortedResults[idx + 1].originalStartLine || allLinesFinal.length) + 10 : allLinesFinal.length;
2727
- for (let s = currentFinalLineIdx; s < lookAheadLimit; s++) {
2728
- if (allLinesFinal[s] === resyncAnchorText) {
2729
- hunkEndInFinal = s;
2730
- break;
3072
+ setPasteBlocks((prev) => prev.filter((b) => b.end <= value.length && b.start <= value.length));
3073
+ }
3074
+ }, [value]);
3075
+ useEffect2(() => {
3076
+ onPasteStateChange?.(pasteBlocks.length > 0);
3077
+ }, [pasteBlocks, onPasteStateChange]);
3078
+ const finalizePasteTransaction = () => {
3079
+ const accumulated = pasteBufferRef.current;
3080
+ const start = pasteBufferStartRef.current;
3081
+ const end = start + accumulated.length;
3082
+ const val = valueRef.current;
3083
+ const newValue = val.slice(0, start) + accumulated + val.slice(start);
3084
+ onChange(newValue);
3085
+ cursorIndexRef.current = end;
3086
+ setCursorIndex(end);
3087
+ setPasteLength(accumulated.length > 1 ? accumulated.length : 0);
3088
+ const lines = normalizeLineEndings(accumulated).split("\n").length;
3089
+ const chars = accumulated.length;
3090
+ if (chars > 50 && (lines > 3 || lines <= 3 && chars > 200)) {
3091
+ const newBlock = {
3092
+ start,
3093
+ end,
3094
+ text: accumulated
3095
+ };
3096
+ setPasteBlocks((prev) => {
3097
+ const delta = accumulated.length;
3098
+ const adjusted = prev.map((block) => {
3099
+ if (start <= block.start) {
3100
+ return {
3101
+ ...block,
3102
+ start: block.start + delta,
3103
+ end: block.end + delta
3104
+ };
2731
3105
  }
2732
- if (s === allLinesFinal.length - 1) hunkEndInFinal = allLinesFinal.length;
2733
- }
2734
- } else {
2735
- hunkEndInFinal = allLinesFinal.length;
2736
- }
3106
+ return block;
3107
+ });
3108
+ return [...adjusted, newBlock];
3109
+ });
2737
3110
  }
2738
- while (currentFinalLineIdx < hunkEndInFinal) {
2739
- diffText += `+${currentFinalLineIdx + 1}|${allLinesFinal[currentFinalLineIdx] || ""}
2740
- `;
2741
- currentFinalLineIdx++;
3111
+ pasteBufferRef.current = "";
3112
+ pasteBufferStartRef.current = -1;
3113
+ pasteTimerRef.current = null;
3114
+ };
3115
+ const flushPasteTransaction = () => {
3116
+ if (pasteTimerRef.current) {
3117
+ clearTimeout(pasteTimerRef.current);
3118
+ finalizePasteTransaction();
2742
3119
  }
2743
- lastSuccessfulHunk = res;
2744
- });
2745
- if (lastSuccessfulHunk !== null) {
2746
- let limit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
2747
- while (currentFinalLineIdx < limit) {
2748
- diffText += `[UI_CONTEXT] ${currentFinalLineIdx + 1} |${allLinesFinal[currentFinalLineIdx] || ""}
2749
- `;
2750
- currentFinalLineIdx++;
3120
+ };
3121
+ useCustomInput((input, key) => {
3122
+ if (input === "\x1B[I" || input === "\x1B[O" || input === "[I" || input === "[O") {
3123
+ return;
2751
3124
  }
2752
- }
2753
- diffText += `[DIFF_END]`;
2754
- return diffText;
2755
- };
2756
- parseMessageToBlocks = (msg, columns) => {
2757
- const text = cleanSignals(msg.text || "");
2758
- if (text.includes("- Content Preview:")) {
2759
- const mainParts = text.split("- Content Preview:");
2760
- const headerText = mainParts[0] || "";
2761
- const contentPart = mainParts[1] || "";
2762
- const footerMarker = "[SYSTEM] Check the content preview for verification [/SYSTEM]";
2763
- const contentAndFooter = contentPart.split(footerMarker);
2764
- const content = contentAndFooter[0]?.trim() || "";
2765
- const footer = contentAndFooter[1] ? `${footerMarker}${contentAndFooter[1]}` : "";
2766
- const codeLines = content.split("\n").map((l) => l.replace(/\r$/, ""));
2767
- const gutterWidth = String(codeLines.length).length;
2768
- const completedBlocks2 = [];
2769
- let activeBlock2 = null;
2770
- codeLines.forEach((line, idx) => {
2771
- const isLast = idx === codeLines.length - 1;
2772
- const block = {
2773
- key: `${msg.id || Date.now()}-write-line-${idx}`,
2774
- msg,
2775
- type: "write-line",
2776
- text: line,
2777
- gutterWidth,
2778
- lineNum: idx + 1,
2779
- isFirstLine: idx === 0,
2780
- isLastLine: isLast
2781
- };
2782
- if (isLast && msg.isStreaming) {
2783
- activeBlock2 = block;
2784
- } else {
2785
- completedBlocks2.push(block);
3125
+ let cleanInput = input;
3126
+ let isBracketedStart = false;
3127
+ let isBracketedEnd = false;
3128
+ if (cleanInput && typeof cleanInput === "string") {
3129
+ if (cleanInput.includes("\x1B[200~")) {
3130
+ isBracketedStart = true;
3131
+ cleanInput = cleanInput.replace(/\x1b\[200~/g, "");
2786
3132
  }
2787
- });
2788
- return {
2789
- completed: completedBlocks2,
2790
- active: activeBlock2 ? [activeBlock2] : []
2791
- };
2792
- }
2793
- if (text.includes("[DIFF_START]")) {
2794
- const match = text.match(/\[DIFF_START\]([\s\S]*?)(?:\[DIFF_END\]|$)/);
2795
- const diffBody = match ? match[1].trim() : "";
2796
- const diffLines = diffBody.split("\n").map((l) => l.replace(/\r$/, ""));
2797
- const completedBlocks2 = [];
2798
- let activeBlock2 = null;
2799
- diffLines.forEach((line, i) => {
2800
- const isLast = i === diffLines.length - 1;
2801
- const block = {
2802
- key: `${msg.id || Date.now()}-diff-${i}`,
2803
- msg,
2804
- type: "diff-line",
2805
- text: line,
2806
- isFirstLine: i === 0,
2807
- isLastLine: isLast
2808
- };
2809
- if (isLast && msg.isStreaming) {
2810
- activeBlock2 = block;
2811
- } else {
2812
- completedBlocks2.push(block);
3133
+ if (cleanInput.includes("\x1B[201~")) {
3134
+ isBracketedEnd = true;
3135
+ cleanInput = cleanInput.replace(/\x1b\[201~/g, "");
2813
3136
  }
2814
- });
2815
- return {
2816
- completed: completedBlocks2,
2817
- active: activeBlock2 ? [activeBlock2] : []
3137
+ }
3138
+ const curIdx = cursorIndexRef.current;
3139
+ const val = valueRef.current;
3140
+ const currentPasteBlocks = pasteBlocksRef.current;
3141
+ const wrapWidth = Math.max(20, columns - 10);
3142
+ const adjustPasteBlocksOnEdit = (editStart, delta) => {
3143
+ if (currentPasteBlocks.length === 0) return;
3144
+ const updated = currentPasteBlocks.map((block) => {
3145
+ if (editStart <= block.start) {
3146
+ return {
3147
+ ...block,
3148
+ start: block.start + delta,
3149
+ end: block.end + delta
3150
+ };
3151
+ }
3152
+ if (editStart > block.start && editStart < block.end) {
3153
+ return null;
3154
+ }
3155
+ return block;
3156
+ }).filter(Boolean);
3157
+ setPasteBlocks(updated);
2818
3158
  };
2819
- }
2820
- if (msg.role === "system" || msg.isLogo || msg.isHelpRecord || msg.isTerminalRecord || msg.isHomeWarning || msg.isImageStats || msg.isAskRecord || msg.isAboutRecord || msg.isUpdateNotification || msg.role === "user") {
2821
- return {
2822
- completed: [{
2823
- key: `${msg.id || Date.now()}-full`,
2824
- msg,
2825
- type: "full-message",
2826
- text
2827
- }],
2828
- active: []
3159
+ const adjustIndex = (idx) => {
3160
+ for (const block of currentPasteBlocks) {
3161
+ if (idx > block.start && idx < block.end) {
3162
+ return block.start;
3163
+ }
3164
+ }
3165
+ return idx;
2829
3166
  };
2830
- }
2831
- const completedBlocks = [];
2832
- let activeBlock = null;
2833
- if (msg.role === "think") {
2834
- completedBlocks.push({
2835
- key: `${msg.id}-header`,
2836
- msg,
2837
- type: "think-header",
2838
- text: ""
2839
- });
2840
- const lines = text.split("\n");
2841
- lines.forEach((line, idx) => {
2842
- const isLast = idx === lines.length - 1;
2843
- const block = {
2844
- key: `${msg.id}-${idx}`,
2845
- msg,
2846
- type: "think-line",
2847
- text: line
2848
- };
2849
- if (isLast && msg.isStreaming) {
2850
- block.isActiveBlock = true;
2851
- activeBlock = block;
2852
- } else {
2853
- completedBlocks.push(block);
3167
+ if (key.ctrl && (cleanInput === "o" || cleanInput === "")) {
3168
+ setPasteBlocks([]);
3169
+ return;
3170
+ }
3171
+ const isArrowKey = key.upArrow || key.downArrow || key.leftArrow || key.rightArrow;
3172
+ if (isArrowKey) {
3173
+ flushPasteTransaction();
3174
+ const now = Date.now();
3175
+ if (now - lastArrowTimeRef.current < 33) {
3176
+ return;
2854
3177
  }
2855
- });
2856
- if (!msg.isStreaming) {
2857
- completedBlocks.push({
2858
- key: `${msg.id}-footer-padding`,
2859
- msg,
2860
- type: "think-footer-padding",
2861
- text: ""
2862
- });
3178
+ lastArrowTimeRef.current = now;
2863
3179
  }
2864
- } else {
2865
- const lines = text.split("\n");
2866
- let inTable = false;
2867
- let tableLines = [];
2868
- let inCodeBlock = false;
2869
- let codeLines = [];
2870
- lines.forEach((line, idx) => {
2871
- const isLast = idx === lines.length - 1;
2872
- const isTableRow = line.trim().startsWith("|");
2873
- const isCodeBlockMarker = line.trim().startsWith("```");
2874
- if (inCodeBlock) {
2875
- codeLines.push(line);
2876
- if (isCodeBlockMarker || isLast) {
2877
- inCodeBlock = !isCodeBlockMarker;
2878
- if (!inCodeBlock || isLast) {
2879
- const block = {
2880
- key: `${msg.id}-code-${idx}`,
2881
- msg,
2882
- type: "agent-line",
2883
- text: codeLines.join("\n")
2884
- };
2885
- if (isLast && msg.isStreaming && inCodeBlock) {
2886
- block.isActiveBlock = true;
2887
- activeBlock = block;
2888
- } else {
2889
- completedBlocks.push(block);
2890
- }
2891
- codeLines = [];
2892
- }
3180
+ const submitKey = keyBindings?.submit ?? ((k) => k.return && k.ctrl);
3181
+ const newlineKey = keyBindings?.newline ?? ((k) => k.return);
3182
+ if (submitKey(key)) {
3183
+ flushPasteTransaction();
3184
+ onSubmit?.(val);
3185
+ return;
3186
+ } else if (newlineKey(key)) {
3187
+ flushPasteTransaction();
3188
+ adjustPasteBlocksOnEdit(curIdx, 1);
3189
+ const newValue = val.slice(0, curIdx) + "\n" + val.slice(curIdx);
3190
+ onChange(newValue);
3191
+ cursorIndexRef.current = curIdx + 1;
3192
+ setCursorIndex(curIdx + 1);
3193
+ setPasteLength(0);
3194
+ return;
3195
+ }
3196
+ if (key.tab || key.shift && key.tab || key.ctrl && cleanInput === "c") {
3197
+ return;
3198
+ }
3199
+ const identity = (t) => t;
3200
+ if (key.upArrow || key.downArrow) {
3201
+ flushPasteTransaction();
3202
+ if (showCursor) {
3203
+ const { visualLines, cursorLine, cursorCol } = computeVisualMatrix(val, curIdx, wrapWidth, identity, currentPasteBlocks);
3204
+ const targetLine = key.upArrow ? cursorLine - 1 : cursorLine + 1;
3205
+ if (targetLine >= 0 && targetLine < visualLines.length) {
3206
+ const targetLineObj = visualLines[targetLine];
3207
+ const targetCol = Math.min(cursorCol, targetLineObj.text.length);
3208
+ const targetFormattedIdx = targetLineObj.formattedStart + targetCol;
3209
+ let newIndex = formattedToRaw(targetFormattedIdx, currentPasteBlocks, val);
3210
+ newIndex = adjustIndex(newIndex);
3211
+ cursorIndexRef.current = newIndex;
3212
+ setCursorIndex(newIndex);
3213
+ setPasteLength(0);
3214
+ } else if (key.upArrow && cursorLine === 0) {
3215
+ cursorIndexRef.current = 0;
3216
+ setCursorIndex(0);
3217
+ setPasteLength(0);
3218
+ } else if (key.downArrow && cursorLine === visualLines.length - 1) {
3219
+ const lastLineObj = visualLines[visualLines.length - 1];
3220
+ const targetFormattedIdx = lastLineObj.formattedStart + lastLineObj.text.length;
3221
+ let newIndex = formattedToRaw(targetFormattedIdx, currentPasteBlocks, val);
3222
+ newIndex = adjustIndex(newIndex);
3223
+ cursorIndexRef.current = newIndex;
3224
+ setCursorIndex(newIndex);
3225
+ setPasteLength(0);
3226
+ }
3227
+ }
3228
+ } else if (key.leftArrow) {
3229
+ flushPasteTransaction();
3230
+ if (showCursor) {
3231
+ let newIndex = Math.max(0, curIdx - 1);
3232
+ const activeBlock = currentPasteBlocks.find((b) => curIdx === b.end);
3233
+ if (activeBlock) {
3234
+ newIndex = activeBlock.start;
3235
+ }
3236
+ cursorIndexRef.current = newIndex;
3237
+ setCursorIndex(newIndex);
3238
+ setPasteLength(0);
3239
+ }
3240
+ } else if (key.rightArrow) {
3241
+ flushPasteTransaction();
3242
+ if (showCursor) {
3243
+ let newIndex = Math.min(val.length, curIdx + 1);
3244
+ const activeBlock = currentPasteBlocks.find((b) => curIdx === b.start);
3245
+ if (activeBlock) {
3246
+ newIndex = activeBlock.end;
2893
3247
  }
2894
- } else if (isCodeBlockMarker) {
2895
- inCodeBlock = true;
2896
- codeLines.push(line);
2897
- if (isLast) {
2898
- const block = {
2899
- key: `${msg.id}-code-${idx}`,
2900
- msg,
2901
- type: "agent-line",
2902
- text: codeLines.join("\n")
2903
- };
2904
- if (msg.isStreaming) {
2905
- block.isActiveBlock = true;
2906
- activeBlock = block;
2907
- } else {
2908
- completedBlocks.push(block);
3248
+ cursorIndexRef.current = newIndex;
3249
+ setCursorIndex(newIndex);
3250
+ setPasteLength(0);
3251
+ }
3252
+ } else if (key.backspace) {
3253
+ flushPasteTransaction();
3254
+ const targetBlockIndex = currentPasteBlocks.findIndex((b) => curIdx === b.end);
3255
+ if (targetBlockIndex !== -1) {
3256
+ const targetBlock = currentPasteBlocks[targetBlockIndex];
3257
+ const delta = -(targetBlock.end - targetBlock.start);
3258
+ const newValue = val.slice(0, targetBlock.start) + val.slice(targetBlock.end);
3259
+ onChange(newValue);
3260
+ cursorIndexRef.current = targetBlock.start;
3261
+ setCursorIndex(targetBlock.start);
3262
+ setPasteLength(0);
3263
+ const updatedBlocks = currentPasteBlocks.filter((_, idx) => idx !== targetBlockIndex).map((block) => {
3264
+ if (block.start >= targetBlock.end) {
3265
+ return {
3266
+ ...block,
3267
+ start: block.start + delta,
3268
+ end: block.end + delta
3269
+ };
2909
3270
  }
2910
- }
2911
- } else if (isTableRow) {
2912
- inTable = true;
2913
- tableLines.push(line);
2914
- if (isLast) {
2915
- if (msg.isStreaming) {
2916
- activeBlock = {
2917
- key: `${msg.id}-table-${idx}`,
2918
- msg,
2919
- type: "table",
2920
- text: tableLines.join("\n"),
2921
- isStreaming: true,
2922
- isActiveBlock: true
3271
+ return block;
3272
+ });
3273
+ setPasteBlocks(updatedBlocks);
3274
+ } else if (curIdx > 0) {
3275
+ adjustPasteBlocksOnEdit(curIdx - 1, -1);
3276
+ const newValue = val.slice(0, curIdx - 1) + val.slice(curIdx);
3277
+ onChange(newValue);
3278
+ cursorIndexRef.current = curIdx - 1;
3279
+ setCursorIndex(curIdx - 1);
3280
+ setPasteLength(0);
3281
+ }
3282
+ } else if (key.delete) {
3283
+ flushPasteTransaction();
3284
+ const targetBlockIndex = currentPasteBlocks.findIndex((b) => curIdx === b.start);
3285
+ if (targetBlockIndex !== -1) {
3286
+ const targetBlock = currentPasteBlocks[targetBlockIndex];
3287
+ const delta = -(targetBlock.end - targetBlock.start);
3288
+ const newValue = val.slice(0, targetBlock.start) + val.slice(targetBlock.end);
3289
+ onChange(newValue);
3290
+ setPasteLength(0);
3291
+ const updatedBlocks = currentPasteBlocks.filter((_, idx) => idx !== targetBlockIndex).map((block) => {
3292
+ if (block.start >= targetBlock.end) {
3293
+ return {
3294
+ ...block,
3295
+ start: block.start + delta,
3296
+ end: block.end + delta
2923
3297
  };
2924
- } else {
2925
- completedBlocks.push({
2926
- key: `${msg.id}-table-${idx}`,
2927
- msg,
2928
- type: "table",
2929
- text: tableLines.join("\n"),
2930
- isStreaming: false
2931
- });
2932
3298
  }
2933
- }
3299
+ return block;
3300
+ });
3301
+ setPasteBlocks(updatedBlocks);
2934
3302
  } else {
2935
- if (inTable) {
2936
- completedBlocks.push({
2937
- key: `${msg.id}-table-${idx}`,
2938
- msg,
2939
- type: "table",
2940
- text: tableLines.join("\n"),
2941
- isStreaming: false
2942
- });
2943
- inTable = false;
2944
- tableLines = [];
2945
- }
2946
- const block = {
2947
- key: `${msg.id}-${idx}`,
2948
- msg,
2949
- type: "agent-line",
2950
- text: line
2951
- };
2952
- if (isLast && msg.isStreaming) {
2953
- block.isActiveBlock = true;
2954
- activeBlock = block;
2955
- } else {
2956
- completedBlocks.push(block);
3303
+ adjustPasteBlocksOnEdit(curIdx, -1);
3304
+ if (curIdx < val.length) {
3305
+ const newValue = val.slice(0, curIdx) + val.slice(curIdx + 1);
3306
+ onChange(newValue);
3307
+ setPasteLength(0);
2957
3308
  }
2958
3309
  }
2959
- });
2960
- if (!msg.isStreaming && msg.workedDuration) {
2961
- completedBlocks.push({
2962
- key: `${msg.id}-worked-duration`,
2963
- msg,
2964
- type: "worked-duration",
2965
- text: ""
2966
- });
2967
- }
2968
- }
2969
- return {
2970
- completed: completedBlocks,
2971
- active: activeBlock ? [activeBlock] : []
2972
- };
2973
- };
2974
- TOOL_LABELS = {
2975
- "write_file": "WriteFile",
2976
- "update_file": "UpdateFile",
2977
- "read_folder": "ReadFolder",
2978
- "view_file": "ViewFile",
2979
- "exec_command": "ExecuteCommand",
2980
- "web_search": "WebSearch",
2981
- "web_scrape": "ReadSite",
2982
- "search_keyword": "SearchKeyword",
2983
- "write_pdf": "CreatePDF",
2984
- "write_docx": "CreateDocument",
2985
- "generate_image": "GenerateImage",
2986
- // PascalCase Support
2987
- "WriteFile": "WriteFile",
2988
- "PatchFile": "PatchFile",
2989
- "ReadFolder": "ReadFolder",
2990
- "ReadFile": "ReadFile",
2991
- "Run": "RunCommand",
2992
- "WebSearch": "WebSearch",
2993
- "WebScrape": "WebScrape",
2994
- "SearchKeyword": "SearchKeyword",
2995
- "WritePDF": "WritePDF",
2996
- "WriteDoc": "WriteDoc",
2997
- "Memory": "Memory",
2998
- "Chat": "Chat",
2999
- "GenerateImage": "GenerateImage"
3000
- };
3001
- cleanSignals = (text) => {
3002
- if (!text) return text;
3003
- let result = text.replace(/<\/think>(\r?\n){2}/gi, "</think>").replace(/(\r?\n){2}(?=\[?(?:tool:functions|tool\.functions|\s*turn\s*:))/gi, "");
3004
- const trigger = "tool:functions.";
3005
- while (true) {
3006
- const lowerResult = result.toLowerCase();
3007
- let triggerIdx = lowerResult.indexOf(trigger);
3008
- if (triggerIdx === -1) break;
3009
- let startIdx = triggerIdx;
3010
- let hasOuterBracket = false;
3011
- let k = triggerIdx - 1;
3012
- while (k >= 0 && /\s/.test(result[k])) k--;
3013
- if (k >= 0 && result[k] === "[") {
3014
- startIdx = k;
3015
- hasOuterBracket = true;
3016
- }
3017
- let balance = 0;
3018
- let foundStart = false;
3019
- let inString = null;
3020
- let j = triggerIdx;
3021
- while (j < result.length) {
3022
- const char = result[j];
3023
- if (!inString && (char === "'" || char === '"' || char === "`")) {
3024
- inString = char;
3025
- } else if (inString && char === inString && result[j - 1] !== "\\") {
3026
- inString = null;
3027
- }
3028
- if (!inString) {
3029
- if (char === "(") {
3030
- balance++;
3031
- foundStart = true;
3032
- } else if (char === ")") {
3033
- balance--;
3310
+ } else if (key.home || key.end) {
3311
+ flushPasteTransaction();
3312
+ if (showCursor) {
3313
+ const { visualLines, cursorLine } = computeVisualMatrix(val, curIdx, wrapWidth, identity, currentPasteBlocks);
3314
+ const currentLineObj = visualLines[cursorLine];
3315
+ if (currentLineObj) {
3316
+ let newIndex;
3317
+ if (key.home) {
3318
+ newIndex = formattedToRaw(currentLineObj.formattedStart, currentPasteBlocks, val);
3319
+ } else if (key.end) {
3320
+ newIndex = formattedToRaw(currentLineObj.formattedStart + currentLineObj.text.length, currentPasteBlocks, val);
3321
+ }
3322
+ newIndex = adjustIndex(newIndex);
3323
+ cursorIndexRef.current = newIndex;
3324
+ setCursorIndex(newIndex);
3325
+ setPasteLength(0);
3034
3326
  }
3035
3327
  }
3036
- if (foundStart && balance === 0 && !inString) {
3037
- let endIdx = j;
3038
- if (hasOuterBracket) {
3039
- let m = j + 1;
3040
- while (m < result.length && /\s/.test(result[m])) m++;
3041
- if (m < result.length && result[m] === "]") {
3042
- endIdx = m;
3328
+ } else {
3329
+ if (cleanInput !== "" || isBracketedStart || isBracketedEnd) {
3330
+ const isPaste = isBracketedStart || isBracketedEnd || cleanInput.length > 1 || pasteTimerRef.current !== null;
3331
+ if (isPaste) {
3332
+ if (pasteTimerRef.current) {
3333
+ clearTimeout(pasteTimerRef.current);
3334
+ pasteBufferRef.current += cleanInput;
3335
+ } else {
3336
+ pasteBufferStartRef.current = curIdx;
3337
+ pasteBufferRef.current = cleanInput;
3338
+ }
3339
+ if (isBracketedEnd) {
3340
+ pasteTimerRef.current = null;
3341
+ finalizePasteTransaction();
3342
+ } else {
3343
+ pasteTimerRef.current = setTimeout(() => {
3344
+ finalizePasteTransaction();
3345
+ }, 100);
3043
3346
  }
3347
+ } else {
3348
+ adjustPasteBlocksOnEdit(curIdx, cleanInput.length);
3349
+ const newValue = val.slice(0, curIdx) + cleanInput + val.slice(curIdx);
3350
+ onChange(newValue);
3351
+ const newIndex = curIdx + cleanInput.length;
3352
+ cursorIndexRef.current = newIndex;
3353
+ setCursorIndex(newIndex);
3354
+ setPasteLength(0);
3044
3355
  }
3045
- result = result.substring(0, startIdx) + result.substring(endIdx + 1);
3046
- break;
3047
- }
3048
- j++;
3049
- if (j === result.length) {
3050
- result = result.substring(0, startIdx);
3051
- return result;
3052
3356
  }
3053
3357
  }
3054
- }
3055
- return result.replaceAll(/\[SYSTEM\][\s\S]*?\[\/SYSTEM\]/gi, "").replaceAll(/<(think|thought)>[\s\S]*?(?:<\/(think|thought)>|$)/gi, "").replace(/\[ANSWER\][\s\S]*?(?:\[\/ANSWER\]|$)/gi, "").replaceAll(/\[TOOL RESULT\]:?\s*/gi, "").split("\n").filter((line) => !line.trim().startsWith("SUCCESS:") && !line.trim().startsWith("ERROR:")).join("\n").replaceAll(/\[\s*turn\s*:\s*(continue|finish)\s*\]/gi, "").replaceAll(/\[\[END\]\]/gi, "").replaceAll(/\[\s*turn\s*:?.*?$/gi, "").replaceAll(/\n\s*turn\s*:?.*?$/gi, "").replaceAll(/\[\s*$/gi, "").replaceAll(/\n\nResponded on .*/g, "").replaceAll(/\n\n\[Prompted on: .*\]/g, "").replaceAll(/(\$?\\?\/?\\rightarrow\$?|\$\\rightarrow\$)/gi, "\u2192").replaceAll(/(\$?\\?\/?\\leftarrow\$?|\$\\leftarrow\$)/gi, "\u2190").replaceAll(/(\$?\\?\/?\\uparrow\$?|\$\\uparrow\$)/gi, "\u2191").replaceAll(/(\$?\\?\/?\\downarrow\$?|\$\\downarrow\$)/gi, "\u2193").replaceAll(/(\$?\\?\/?\\leftrightarrow\$?|\$\\leftrightarrow\$)/gi, "\u2194").replaceAll(/@\[TerminalName:.*?, ProcessId:.*?\]/gi, "").replaceAll(/\b(write_file|update_file|read_folder|view_file|exec_command|web_search|web_scrape|search_keyword|write_pdf|write_docx|generate_image)\b/gi, (match) => TOOL_LABELS[match.toLowerCase()] || match).trim();
3358
+ }, focus);
3359
+ return /* @__PURE__ */ React2.createElement(
3360
+ ControlledMultilineInput,
3361
+ {
3362
+ ...controlledProps,
3363
+ value,
3364
+ cursorIndex,
3365
+ showCursor,
3366
+ focus,
3367
+ columns,
3368
+ pasteBlocks
3369
+ }
3370
+ );
3056
3371
  };
3057
3372
  }
3058
3373
  });
3059
3374
 
3060
3375
  // src/components/TerminalBox.jsx
3061
- import React3 from "react";
3062
- import { Box as Box2, Text as Text3 } from "ink";
3376
+ import React3, { useState as useState3 } from "react";
3377
+ import { Box as Box2, Text as Text3, useInput as useInput2 } from "ink";
3063
3378
  var TerminalBox;
3064
3379
  var init_TerminalBox = __esm({
3065
3380
  "src/components/TerminalBox.jsx"() {
3066
3381
  init_text();
3067
- TerminalBox = React3.memo(({ command, output, completed = false, isFocused = false, columns = 80, isPty = false }) => {
3382
+ TerminalBox = React3.memo(({ command, output, completed = false, isFocused = false, columns = 80, isPty = false, terminalHeight = 24 }) => {
3068
3383
  const processPTY = (text) => {
3069
3384
  if (!text) return "";
3070
3385
  const lines = [[]];
@@ -3188,6 +3503,18 @@ var init_TerminalBox = __esm({
3188
3503
  };
3189
3504
  const cleanOutput = processPTY(output).replace(/\n{3,}/g, "\n\n");
3190
3505
  const displayOutput = isPty ? cleanOutput : cleanOutput ? wrapText(cleanOutput, columns - 6) : "";
3506
+ const [isExpanded, setIsExpanded] = useState3(false);
3507
+ useInput2((input, key) => {
3508
+ if (isFocused && key.ctrl && (input === "o" || input === "")) {
3509
+ setIsExpanded((prev) => !prev);
3510
+ }
3511
+ }, { isActive: isFocused });
3512
+ const rawLines = displayOutput ? displayOutput.split("\n") : [];
3513
+ const limit = Math.max(5, completed ? terminalHeight - 10 : terminalHeight - 20);
3514
+ const hasCollapsibleContent = rawLines.length > limit;
3515
+ const collapsedCount = rawLines.length - limit;
3516
+ const visibleLines = hasCollapsibleContent && !isExpanded ? rawLines.slice(rawLines.length - limit) : rawLines;
3517
+ const renderedOutput = visibleLines.join("\n");
3191
3518
  return /* @__PURE__ */ React3.createElement(
3192
3519
  Box2,
3193
3520
  {
@@ -3205,7 +3532,7 @@ var init_TerminalBox = __esm({
3205
3532
  width: "100%"
3206
3533
  },
3207
3534
  /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React3.createElement(Box2, { flexShrink: 1, paddingRight: 2 }, /* @__PURE__ */ React3.createElement(Text3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", bold: true }, completed ? "\u{1F3C1} FINISHED:" : "\u26A1 EXECUTING:", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "white" }, command))), isPty && /* @__PURE__ */ React3.createElement(Box2, { flexShrink: 0, paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", bold: true }, "ADVANCE"))),
3208
- displayOutput ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: completed ? 0 : 1, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: completed ? "gray" : void 0 }, displayOutput)) : !completed && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", italic: true }, "Waiting for output...")),
3535
+ displayOutput ? /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginTop: 0, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, hasCollapsibleContent && !isExpanded && /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, "...", collapsedCount, " lines collapsed... Press CTRL + O to expand.")), /* @__PURE__ */ React3.createElement(Text3, { color: completed ? "gray" : void 0 }, renderedOutput)) : !completed && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, backgroundColor: isPty ? void 0 : "#0a0a0a", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "white", italic: true }, "Waiting for output...")),
3209
3536
  /* @__PURE__ */ React3.createElement(Box2, { justifyContent: "space-between", marginTop: 1 }, !completed ? /* @__PURE__ */ React3.createElement(Text3, { color: "gray", italic: true }, isFocused ? "Press TAB to unfocus, then double-press ESC to terminate." : "Double-press ESC to terminate if hanging.") : /* @__PURE__ */ React3.createElement(Box2, null), /* @__PURE__ */ React3.createElement(Text3, { color: "gray", bold: true }, completed ? "\u25CF ARCHIVED" : isFocused ? "\u25B6 TERMINAL FOCUSED" : "\u25CF LIVE (Press TAB to focus)"))
3210
3537
  );
3211
3538
  });
@@ -3482,7 +3809,7 @@ ${coloredArt[7]}`;
3482
3809
  });
3483
3810
 
3484
3811
  // src/components/ChatLayout.jsx
3485
- import React4, { useState as useState3, useEffect as useEffect3, useRef as useRef2 } from "react";
3812
+ import React4, { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
3486
3813
  import { Box as Box3, Text as Text4 } from "ink";
3487
3814
  import { diffWordsWithSpace } from "diff";
3488
3815
  var useStreamingText, formatThinkText, parseMathSymbols, renderLatexText, InlineMarkdown, TableRenderer, MarkdownText, parseLineInfo, DiffLine, DiffBlock, CodeRenderer, formatThinkingDuration, MessageItem, BlockItem, ChatLayout;
@@ -3492,7 +3819,7 @@ var init_ChatLayout = __esm({
3492
3819
  init_text();
3493
3820
  init_terminal();
3494
3821
  useStreamingText = (targetText, isStreaming, isActiveBlock) => {
3495
- const [displayedText, setDisplayedText] = useState3(isActiveBlock && isStreaming ? "" : targetText);
3822
+ const [displayedText, setDisplayedText] = useState4(isActiveBlock && isStreaming ? "" : targetText);
3496
3823
  const targetTextRef = useRef2(targetText);
3497
3824
  useEffect3(() => {
3498
3825
  targetTextRef.current = targetText;
@@ -3887,7 +4214,7 @@ var init_ChatLayout = __esm({
3887
4214
  paddingRight: 0,
3888
4215
  width: "100%"
3889
4216
  },
3890
- /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "\u{1F4BB} ", lang.toUpperCase() || "CODE")),
4217
+ /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", bold: true }, "\u25B6_ ", lang.toUpperCase() || "CODE")),
3891
4218
  /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", width: "100%" }, codeLines.map((line, idx) => /* @__PURE__ */ React4.createElement(Box3, { key: idx, width: "100%" }, /* @__PURE__ */ React4.createElement(Box3, { width: gutterWidth + 2, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, String(idx + 1).padStart(gutterWidth, " "), " ")), /* @__PURE__ */ React4.createElement(Box3, { flexGrow: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "#fcfca4ff" }, line)))))
3892
4219
  );
3893
4220
  }
@@ -4453,7 +4780,6 @@ var init_main_tools = __esm({
4453
4780
  TOOL_PROTOCOL = (mode, osDetected, isMultiModal, aiProvider) => `
4454
4781
  -- TOOL DEFINITIONS --
4455
4782
  Internal tools. **MUST use the EXACT syntax** [tool:functions.ToolName(args)]. **NO OTHER SYNTAX/MARKERS/BOUNDARY ALLOWED**
4456
- NO TOOL CALL INSIDE THINKING
4457
4783
 
4458
4784
  **TOOL USAGE POLICY:**
4459
4785
  - **MAX 3 TOOL CALLS PER TURN${mode === "Flux" ? " (EXCEPTION FOR Todo TOOL: 3+ CALLS ALLOWED, Run: Limit 1 OR 2 CONSECUTIVE Run)" : ""}. Next Turn, verify tool results, plan next**
@@ -4472,7 +4798,7 @@ ${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative to CWD & WILL BE FIRST A
4472
4798
  4. [tool:functions.PatchFile(path="...", replaceContent1="full line/block", newContent1="...", ...MAX 6)]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
4473
4799
  5. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
4474
4800
  6. [tool:functions.SearchKeyword(keyword="...", file="optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
4475
- 7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user
4801
+ 7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL ONLY` : `WINDOWS CMD ONLY` : `BASH`} command. Destructive/Irreversible ops -> Ask user
4476
4802
  8. [tool:functions.Todo(method="create/append/get", tasks=[ARRAY OF STRINGS], markDone=[ARRAY OF TASK STRINGS])]. Task List, Markdown IN ARRAY NOT ALLOWED. USAGE: ANALYZE USER REQUEST **IF** MULTIPLE TASK \u2192 BREAK DOWN TASK \u2192 CREATE TODO **BEFORE** DIVING IN. 'tasks' & 'markDone' OPTIONAL PARAMETERS WITH method 'get'. USE 'get' method WITH 'markDone' to mark task completed`.trim() : `- CREATIVE TOOLS (path = relative to CWD & WILL BE FIRST ARGUMENT, path separator: '/') -
4477
4803
  1. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
4478
4804
  2. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document
@@ -5130,8 +5456,8 @@ ${finalOutput}`);
5130
5456
  });
5131
5457
 
5132
5458
  // src/components/SettingsMenu.jsx
5133
- import React7, { useState as useState4 } from "react";
5134
- import { Box as Box6, Text as Text7, useInput as useInput2 } from "ink";
5459
+ import React7, { useState as useState5 } from "react";
5460
+ import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
5135
5461
  import TextInput from "ink-text-input";
5136
5462
  function SettingsMenu({
5137
5463
  systemSettings,
@@ -5144,11 +5470,11 @@ function SettingsMenu({
5144
5470
  setMessages,
5145
5471
  aiProvider
5146
5472
  }) {
5147
- const [activeColumn, setActiveColumn] = useState4("categories");
5148
- const [selectedCategoryIndex, setSelectedCategoryIndex] = useState4(0);
5149
- const [selectedItemIndex, setSelectedItemIndex] = useState4(0);
5150
- const [editingItem, setEditingItem] = useState4(null);
5151
- const [editValue, setEditValue] = useState4("");
5473
+ const [activeColumn, setActiveColumn] = useState5("categories");
5474
+ const [selectedCategoryIndex, setSelectedCategoryIndex] = useState5(0);
5475
+ const [selectedItemIndex, setSelectedItemIndex] = useState5(0);
5476
+ const [editingItem, setEditingItem] = useState5(null);
5477
+ const [editValue, setEditValue] = useState5("");
5152
5478
  const getCategoryItems = (catId) => {
5153
5479
  switch (catId) {
5154
5480
  case "memory":
@@ -5186,7 +5512,7 @@ function SettingsMenu({
5186
5512
  };
5187
5513
  const currentCatId = CATEGORIES[selectedCategoryIndex].id;
5188
5514
  const currentItems = getCategoryItems(currentCatId);
5189
- useInput2((input, key) => {
5515
+ useInput3((input, key) => {
5190
5516
  if (editingItem) {
5191
5517
  if (key.escape) {
5192
5518
  setEditingItem(null);
@@ -5451,13 +5777,13 @@ var init_SettingsMenu = __esm({
5451
5777
  });
5452
5778
 
5453
5779
  // src/components/ProfileForm.jsx
5454
- import React8, { useState as useState5, useEffect as useEffect4 } from "react";
5780
+ import React8, { useState as useState6, useEffect as useEffect4 } from "react";
5455
5781
  import { Box as Box7, Text as Text8 } from "ink";
5456
5782
  import TextInput2 from "ink-text-input";
5457
5783
  function ProfileForm({ initialData, onSave, onCancel }) {
5458
- const [step, setStep] = useState5(0);
5459
- const [currentInput, setCurrentInput] = useState5("");
5460
- const [profile, setProfile] = useState5(() => ({
5784
+ const [step, setStep] = useState6(0);
5785
+ const [currentInput, setCurrentInput] = useState6("");
5786
+ const [profile, setProfile] = useState6(() => ({
5461
5787
  name: initialData?.name || "",
5462
5788
  nickname: initialData?.nickname || "",
5463
5789
  instructions: initialData?.instructions || ""
@@ -5515,19 +5841,19 @@ var init_ProfileForm = __esm({
5515
5841
  });
5516
5842
 
5517
5843
  // src/components/AskUserModal.jsx
5518
- import React9, { useState as useState6 } from "react";
5519
- import { Box as Box8, Text as Text9, useInput as useInput3 } from "ink";
5844
+ import React9, { useState as useState7 } from "react";
5845
+ import { Box as Box8, Text as Text9, useInput as useInput4 } from "ink";
5520
5846
  import TextInput3 from "ink-text-input";
5521
5847
  var AskUserModal, AskUserModal_default;
5522
5848
  var init_AskUserModal = __esm({
5523
5849
  "src/components/AskUserModal.jsx"() {
5524
5850
  init_terminal();
5525
5851
  AskUserModal = ({ question, options, onResolve }) => {
5526
- const [isSuggestingElse, setIsSuggestingElse] = useState6(false);
5527
- const [customInput, setCustomInput] = useState6("");
5528
- const [selectedIndex, setSelectedIndex] = useState6(0);
5852
+ const [isSuggestingElse, setIsSuggestingElse] = useState7(false);
5853
+ const [customInput, setCustomInput] = useState7("");
5854
+ const [selectedIndex, setSelectedIndex] = useState7(0);
5529
5855
  const allOptions = [...options, { id: "CUSTOM", label: "Suggest something else...", description: "Provide a custom response" }];
5530
- useInput3((input, key) => {
5856
+ useInput4((input, key) => {
5531
5857
  if (isSuggestingElse) return;
5532
5858
  if (key.leftArrow || key.upArrow) {
5533
5859
  setSelectedIndex((prev) => Math.max(0, prev - 1));
@@ -5757,8 +6083,8 @@ ${projectContextBlock}
5757
6083
 
5758
6084
  -- FORMATTING --
5759
6085
  - GFM Supported
5760
- - NO CHAT **AFTER** FIRING TOOLS IN THIS TURN
5761
- - End final response with summary of changes made and files edited
6086
+ - NO CHAT **AFTER** FIRING TOOLS IN CURRENT TURN
6087
+ - Task Complete & Results Verified? End response with summary of changes made and files edited
5762
6088
  - Basic LaTeX${mode === "Flux" ? "" : ". Kaomojis"}
5763
6089
  === END SYSTEM PROMPT ===`.trim();
5764
6090
  };
@@ -8796,7 +9122,7 @@ var init_editor = __esm({
8796
9122
  import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
8797
9123
  import path19 from "path";
8798
9124
  import fs20 from "fs";
8799
- var client, globalSettings, colorMainWords, TERMINATION_SIGNAL, MULTIMODAL_MODELS, isModelMultimodal, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getNVIDIAStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream;
9125
+ var client, globalSettings, colorMainWords, TERMINATION_SIGNAL, MULTIMODAL_MODELS, isModelMultimodal, getCleanGroupedLength, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getNVIDIAStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, translateKimiToolCalls, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, compressHistory, deleteChatSummary, getAIStream;
8800
9126
  var init_ai = __esm({
8801
9127
  async "src/utils/ai.js"() {
8802
9128
  await init_prompts();
@@ -8906,7 +9232,7 @@ var init_ai = __esm({
8906
9232
  }
8907
9233
  return fetch(url, options);
8908
9234
  };
8909
- getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.9) {
9235
+ getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.85) {
8910
9236
  const messages = [];
8911
9237
  if (systemInstruction) {
8912
9238
  messages.push({ role: "system", content: systemInstruction });
@@ -9038,7 +9364,7 @@ var init_ai = __esm({
9038
9364
  }
9039
9365
  }
9040
9366
  };
9041
- getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.8) {
9367
+ getNVIDIAStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal = false, signal, temperature = 0.7) {
9042
9368
  const messages = [];
9043
9369
  if (systemInstruction) {
9044
9370
  messages.push({ role: "system", content: systemInstruction });
@@ -9190,7 +9516,7 @@ var init_ai = __esm({
9190
9516
  }
9191
9517
  }
9192
9518
  };
9193
- getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.5) {
9519
+ getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal, signal, temperature = 0.45) {
9194
9520
  const messages = [];
9195
9521
  if (systemInstruction) {
9196
9522
  messages.push({ role: "system", content: systemInstruction });
@@ -9778,9 +10104,69 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
9778
10104
  getSanitizedText = (text) => {
9779
10105
  return getContextSafeText(text, true);
9780
10106
  };
10107
+ translateKimiToolCalls = (text) => {
10108
+ if (!text) return text;
10109
+ const PASCAL_MAP = {
10110
+ "patchfile": "PatchFile",
10111
+ "writefile": "WriteFile",
10112
+ "readfile": "ReadFile",
10113
+ "viewfile": "ReadFile",
10114
+ "run": "Run",
10115
+ "execcommand": "Run",
10116
+ "searchkeyword": "SearchKeyword",
10117
+ "websearch": "WebSearch",
10118
+ "webscrape": "WebScrape",
10119
+ "readfolder": "ReadFolder",
10120
+ "writepdf": "WritePDF",
10121
+ "writedoc": "WriteDoc",
10122
+ "writedocx": "WriteDoc",
10123
+ "filemap": "FileMap",
10124
+ "generateimage": "GenerateImage",
10125
+ "todo": "Todo",
10126
+ "ask": "Ask"
10127
+ };
10128
+ const toPascalCase = (str) => {
10129
+ return str.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
10130
+ };
10131
+ const kimiRegex = /<\|\s*tool_call_begin\s*\|>\s*(?:(?:tool|functions)\b[\s._]*)*([a-zA-Z0-9_]+)(?::\d+)?\s*<\|\s*tool_call_argument_begin\s*\|>([\s\S]*?)<\|\s*tool_call_end\s*\|>/gi;
10132
+ let result = text.replace(kimiRegex, (match, toolName, argsJsonStr) => {
10133
+ let parsedArgs = "";
10134
+ try {
10135
+ const argsObj = JSON.parse(argsJsonStr.trim());
10136
+ if (argsObj && typeof argsObj === "object") {
10137
+ const argPairs = Object.entries(argsObj).map(([key, val]) => {
10138
+ const stringVal = typeof val === "string" ? val : JSON.stringify(val);
10139
+ return `${key}=${JSON.stringify(stringVal)}`;
10140
+ });
10141
+ parsedArgs = argPairs.join(", ");
10142
+ }
10143
+ } catch (e) {
10144
+ const pairs = [];
10145
+ const pairRegex = /"([^"]+)"\s*:\s*(?:"([^"]*)"|(\d+)|true|false|null)/g;
10146
+ let pMatch;
10147
+ while ((pMatch = pairRegex.exec(argsJsonStr)) !== null) {
10148
+ const key = pMatch[1];
10149
+ const val = pMatch[2] !== void 0 ? pMatch[2] : pMatch[0].split(":").slice(1).join(":").trim();
10150
+ pairs.push(`${key}=${JSON.stringify(val)}`);
10151
+ }
10152
+ if (pairs.length > 0) {
10153
+ parsedArgs = pairs.join(", ");
10154
+ } else {
10155
+ parsedArgs = argsJsonStr.trim();
10156
+ }
10157
+ }
10158
+ const cleanKey = toolName.toLowerCase().replace(/_/g, "");
10159
+ const normToolName = PASCAL_MAP[cleanKey] || toPascalCase(toolName);
10160
+ return `[tool:functions.${normToolName}(${parsedArgs})]`;
10161
+ });
10162
+ result = result.replace(/<\|\s*tool_calls_section_begin\s*\|>/gi, "");
10163
+ result = result.replace(/<\|\s*tool_calls_section_end\s*\|>/gi, "");
10164
+ return result;
10165
+ };
9781
10166
  detectToolCalls = (text) => {
9782
10167
  if (!text) return [];
9783
- const cleanText = text.replace(/(?:<(think|thought|thoughts)>|\[(think|thought|thoughts)\])[\s\S]*?(?:<\/(think|thought|thoughts)>|\[\/(think|thought|thoughts)\]|$)/gi, "");
10168
+ const translatedText = translateKimiToolCalls(text);
10169
+ const cleanText = translatedText.replace(/(?:<(think|thought|thoughts)>|\[(think|thought|thoughts)\])[\s\S]*?(?:<\/(think|thought|thoughts)>|\[\/(think|thought|thoughts)\]|$)/gi, "");
9784
10170
  const results = [];
9785
10171
  const toolRegex = /\[\s*tool:functions\.([a-z0-9_]+)\s*\(/gi;
9786
10172
  let match;
@@ -10695,7 +11081,9 @@ ${boxMid}`) };
10695
11081
  if (taggedContextBlocks.length > 0) {
10696
11082
  taggedContextStr = "[TAGGED CONTEXT]\n" + taggedContextBlocks.join("\n\n") + "\n[/TAGGED CONTEXT]\n";
10697
11083
  }
11084
+ const osDetected = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
10698
11085
  const firstUserMsg = `[SYSTEM METADATA (PRIORITY: DYNAMIC), Chat Context >> Metadata] Time: ${dateTimeStr}
11086
+ OS: ${osDetected}
10699
11087
  CWD: ${process.cwd()}${isPlayground ? " [PLAYGROUND MODE]" : ""}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${lastCwd})` : ""}
10700
11088
  **DIRECTORY STRUCTURE**
10701
11089
  ${dirStructure}${memoryPrompt}${ideBlock}
@@ -10926,7 +11314,7 @@ ${ideErr} [/ERROR]`;
10926
11314
  mode,
10927
11315
  isMultiModal,
10928
11316
  abortController.signal,
10929
- 0.5
11317
+ 0.45
10930
11318
  );
10931
11319
  } else if (aiProvider === "DeepSeek") {
10932
11320
  stream = getDeepSeekStream(
@@ -10938,7 +11326,7 @@ ${ideErr} [/ERROR]`;
10938
11326
  mode,
10939
11327
  isMultiModal,
10940
11328
  abortController.signal,
10941
- 0.9
11329
+ 0.85
10942
11330
  );
10943
11331
  } else if (aiProvider === "NVIDIA") {
10944
11332
  stream = getNVIDIAStream(
@@ -10950,7 +11338,7 @@ ${ideErr} [/ERROR]`;
10950
11338
  mode,
10951
11339
  isMultiModal,
10952
11340
  abortController.signal,
10953
- 0.8
11341
+ 0.7
10954
11342
  );
10955
11343
  } else {
10956
11344
  const apiCallPromise = client.models.generateContentStream({
@@ -11037,9 +11425,13 @@ ${ideErr} [/ERROR]`;
11037
11425
  if (!isBufferingToolCall) {
11038
11426
  const toolIdx = remaining.indexOf("[tool");
11039
11427
  const endIdx = remaining.indexOf("[[END]]");
11428
+ const kimiSectionIdx = remaining.indexOf("<|tool_calls_section_begin|>");
11429
+ const kimiCallIdx = remaining.indexOf("<|tool_call_begin|>");
11040
11430
  const indices = [
11041
11431
  { type: "tool", idx: toolIdx, start: "[tool", end: "]" },
11042
- { type: "end", idx: endIdx, start: "[[END]]", end: "[[END]]" }
11432
+ { type: "end", idx: endIdx, start: "[[END]]", end: "[[END]]" },
11433
+ { type: "kimi_section", idx: kimiSectionIdx, start: "<|tool_calls_section_begin|>", end: "<|tool_calls_section_end|>" },
11434
+ { type: "kimi_call", idx: kimiCallIdx, start: "<|tool_call_begin|>", end: "<|tool_call_end|>" }
11043
11435
  ].filter((i) => i.idx !== -1).sort((a, b) => a.idx - b.idx);
11044
11436
  if (indices.length > 0) {
11045
11437
  const match2 = indices[0];
@@ -11051,13 +11443,17 @@ ${ideErr} [/ERROR]`;
11051
11443
  toolCallBuffer = "";
11052
11444
  remaining = remaining.substring(match2.idx);
11053
11445
  } else {
11054
- const potentialStarts = ["[tool", "[[END]]"];
11446
+ const potentialStarts = ["[tool", "[[END]]", "<|tool_calls_section_begin|>", "<|tool_call_begin|>"];
11055
11447
  let splitPoint = -1;
11056
11448
  for (const start of potentialStarts) {
11057
11449
  for (let len = start.length - 1; len > 0; len--) {
11058
11450
  if (remaining.endsWith(start.substring(0, len))) {
11059
11451
  splitPoint = remaining.length - len;
11060
- activeBufferType = potentialStarts.indexOf(start) === 0 ? "tool" : "end";
11452
+ const idx = potentialStarts.indexOf(start);
11453
+ if (idx === 0) activeBufferType = "tool";
11454
+ else if (idx === 1) activeBufferType = "end";
11455
+ else if (idx === 2) activeBufferType = "kimi_section";
11456
+ else activeBufferType = "kimi_call";
11061
11457
  break;
11062
11458
  }
11063
11459
  }
@@ -11076,7 +11472,6 @@ ${ideErr} [/ERROR]`;
11076
11472
  }
11077
11473
  }
11078
11474
  } else {
11079
- const endTag = activeBufferType === "tool" ? "]" : "[[END]]";
11080
11475
  const combined = toolCallBuffer + remaining;
11081
11476
  if (activeBufferType === "tool") {
11082
11477
  const protocolPrefix = "[tool:functions.";
@@ -11090,6 +11485,7 @@ ${ideErr} [/ERROR]`;
11090
11485
  }
11091
11486
  }
11092
11487
  let endIdx = -1;
11488
+ let endTag = "]";
11093
11489
  if (activeBufferType === "tool") {
11094
11490
  let balance = 0;
11095
11491
  let inString = null;
@@ -11127,19 +11523,27 @@ ${ideErr} [/ERROR]`;
11127
11523
  }
11128
11524
  }
11129
11525
  } else {
11526
+ if (activeBufferType === "end") endTag = "[[END]]";
11527
+ else if (activeBufferType === "kimi_section") endTag = "<|tool_calls_section_end|>";
11528
+ else if (activeBufferType === "kimi_call") endTag = "<|tool_call_end|>";
11130
11529
  endIdx = combined.indexOf(endTag);
11131
11530
  }
11132
11531
  if (endIdx !== -1) {
11133
- const fullMatch = combined.substring(0, endIdx + 1);
11134
- msgs.push({ type: "text", content: fullMatch });
11532
+ const endLen = endTag.length;
11533
+ if (!activeBufferType.startsWith("kimi")) {
11534
+ const fullMatch = combined.substring(0, endIdx + endLen);
11535
+ msgs.push({ type: "text", content: fullMatch });
11536
+ }
11135
11537
  toolCallBuffer = "";
11136
11538
  isBufferingToolCall = false;
11137
11539
  activeBufferType = null;
11138
- remaining = combined.substring(endIdx + 1);
11540
+ remaining = combined.substring(endIdx + endLen);
11139
11541
  } else {
11140
- const MAX_BUFFER = 512;
11542
+ const MAX_BUFFER = activeBufferType.startsWith("kimi") ? 8192 : 512;
11141
11543
  if (combined.length > MAX_BUFFER) {
11142
- msgs.push({ type: "text", content: combined });
11544
+ if (!activeBufferType.startsWith("kimi")) {
11545
+ msgs.push({ type: "text", content: combined });
11546
+ }
11143
11547
  toolCallBuffer = "";
11144
11548
  isBufferingToolCall = false;
11145
11549
  } else {
@@ -12548,12 +12952,12 @@ Error Log can be found in ${path19.join(LOGS_DIR, "agent", "error.log")}`);
12548
12952
  });
12549
12953
 
12550
12954
  // src/components/ResumeModal.jsx
12551
- import React10, { useState as useState7, useEffect as useEffect5 } from "react";
12552
- import { Box as Box9, Text as Text10, useInput as useInput4 } from "ink";
12955
+ import React10, { useState as useState8, useEffect as useEffect5 } from "react";
12956
+ import { Box as Box9, Text as Text10, useInput as useInput5 } from "ink";
12553
12957
  function ResumeModal({ onSelect, onDelete, onClose }) {
12554
- const [history, setHistory] = useState7({});
12555
- const [keys, setKeys] = useState7([]);
12556
- const [selectedIndex, setSelectedIndex] = useState7(0);
12958
+ const [history, setHistory] = useState8({});
12959
+ const [keys, setKeys] = useState8([]);
12960
+ const [selectedIndex, setSelectedIndex] = useState8(0);
12557
12961
  useEffect5(() => {
12558
12962
  const fetchHistory = async () => {
12559
12963
  const h = await loadHistory();
@@ -12562,7 +12966,7 @@ function ResumeModal({ onSelect, onDelete, onClose }) {
12562
12966
  };
12563
12967
  fetchHistory();
12564
12968
  }, []);
12565
- useInput4((input, key) => {
12969
+ useInput5((input, key) => {
12566
12970
  if (key.escape) onClose();
12567
12971
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
12568
12972
  if (key.downArrow) setSelectedIndex((prev) => Math.min(keys.length - 1, prev + 1));
@@ -12640,14 +13044,14 @@ var init_ResumeModal = __esm({
12640
13044
  });
12641
13045
 
12642
13046
  // src/components/MemoryModal.jsx
12643
- import React11, { useState as useState8, useEffect as useEffect6 } from "react";
12644
- import { Box as Box10, Text as Text11, useInput as useInput5, useStdout } from "ink";
13047
+ import React11, { useState as useState9, useEffect as useEffect6 } from "react";
13048
+ import { Box as Box10, Text as Text11, useInput as useInput6, useStdout } from "ink";
12645
13049
  function MemoryModal({ onClose }) {
12646
13050
  const { stdout } = useStdout();
12647
13051
  const columns = stdout?.columns || 80;
12648
- const [memories, setMemories] = useState8([]);
12649
- const [selectedIndex, setSelectedIndex] = useState8(0);
12650
- const [isMemoryOn, setIsMemoryOn] = useState8(true);
13052
+ const [memories, setMemories] = useState9([]);
13053
+ const [selectedIndex, setSelectedIndex] = useState9(0);
13054
+ const [isMemoryOn, setIsMemoryOn] = useState9(true);
12651
13055
  const loadMemories = () => {
12652
13056
  const data = readEncryptedJson(MEMORIES_FILE, []);
12653
13057
  setMemories(data);
@@ -12662,7 +13066,7 @@ function MemoryModal({ onClose }) {
12662
13066
  useEffect6(() => {
12663
13067
  loadMemories();
12664
13068
  }, []);
12665
- useInput5((input, key) => {
13069
+ useInput6((input, key) => {
12666
13070
  if (key.escape) onClose();
12667
13071
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
12668
13072
  if (key.downArrow) setSelectedIndex((prev) => Math.min(memories.length - 1, prev + 1));
@@ -12761,7 +13165,7 @@ var init_MemoryModal = __esm({
12761
13165
  });
12762
13166
 
12763
13167
  // src/components/UpdateProcessor.jsx
12764
- import React12, { useState as useState9, useEffect as useEffect7 } from "react";
13168
+ import React12, { useState as useState10, useEffect as useEffect7 } from "react";
12765
13169
  import { Box as Box11, Text as Text12 } from "ink";
12766
13170
  import { spawn as spawn2 } from "child_process";
12767
13171
  var pty2, SPINNER_FRAMES, UpdateProcessor, UpdateProcessor_default;
@@ -12776,10 +13180,10 @@ var init_UpdateProcessor = __esm({
12776
13180
  }
12777
13181
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
12778
13182
  UpdateProcessor = ({ latest, current, settings, onClose, onUpdateSettings, onSuccess }) => {
12779
- const [status, setStatus] = useState9("initializing");
12780
- const [log, setLog] = useState9("");
12781
- const [error, setError] = useState9(null);
12782
- const [tick, setTick] = useState9(0);
13183
+ const [status, setStatus] = useState10("initializing");
13184
+ const [log, setLog] = useState10("");
13185
+ const [error, setError] = useState10(null);
13186
+ const [tick, setTick] = useState10(0);
12783
13187
  useEffect7(() => {
12784
13188
  const interval = setInterval(() => {
12785
13189
  setTick((t) => (t + 1) % 1e3);
@@ -12919,11 +13323,11 @@ var init_UpdateProcessor = __esm({
12919
13323
  });
12920
13324
 
12921
13325
  // src/components/ParserDownloadModal.jsx
12922
- import React13, { useState as useState10, useEffect as useEffect8 } from "react";
12923
- import { Box as Box12, Text as Text13, useInput as useInput6 } from "ink";
13326
+ import React13, { useState as useState11, useEffect as useEffect8 } from "react";
13327
+ import { Box as Box12, Text as Text13, useInput as useInput7 } from "ink";
12924
13328
  function ParserDownloadModal({ onClose }) {
12925
- const [selectedIndex, setSelectedIndex] = useState10(0);
12926
- const [status, setStatus] = useState10({});
13329
+ const [selectedIndex, setSelectedIndex] = useState11(0);
13330
+ const [status, setStatus] = useState11({});
12927
13331
  useEffect8(() => {
12928
13332
  const initialStatus = {};
12929
13333
  EXTENSIONS.forEach((item) => {
@@ -12935,7 +13339,7 @@ function ParserDownloadModal({ onClose }) {
12935
13339
  });
12936
13340
  setStatus(initialStatus);
12937
13341
  }, []);
12938
- useInput6(async (input, key) => {
13342
+ useInput7(async (input, key) => {
12939
13343
  if (key.escape) onClose();
12940
13344
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
12941
13345
  if (key.downArrow) setSelectedIndex((prev) => Math.min(EXTENSIONS.length - 1, prev + 1));
@@ -13425,11 +13829,11 @@ var init_dist = __esm({
13425
13829
  });
13426
13830
 
13427
13831
  // src/components/RevertModal.jsx
13428
- import React14, { useState as useState11 } from "react";
13429
- import { Box as Box14, Text as Text15, useInput as useInput7 } from "ink";
13832
+ import React14, { useState as useState12 } from "react";
13833
+ import { Box as Box14, Text as Text15, useInput as useInput8 } from "ink";
13430
13834
  function RevertModal({ prompts, onSelect, onClose }) {
13431
- const [selectedIndex, setSelectedIndex] = useState11(0);
13432
- useInput7((input, key) => {
13835
+ const [selectedIndex, setSelectedIndex] = useState12(0);
13836
+ useInput8((input, key) => {
13433
13837
  if (key.escape) onClose();
13434
13838
  if (key.upArrow) setSelectedIndex((prev) => Math.max(0, prev - 1));
13435
13839
  if (key.downArrow) setSelectedIndex((prev) => Math.min(prompts.length - 1, prev + 1));
@@ -13551,8 +13955,8 @@ __export(app_exports, {
13551
13955
  default: () => App
13552
13956
  });
13553
13957
  import os4 from "os";
13554
- import React15, { useState as useState12, useEffect as useEffect9, useRef as useRef3, useMemo as useMemo2 } from "react";
13555
- import { Box as Box15, Text as Text16, useInput as useInput8, useStdout as useStdout2, Static } from "ink";
13958
+ import React15, { useState as useState13, useEffect as useEffect9, useRef as useRef3, useMemo as useMemo2 } from "react";
13959
+ import { Box as Box15, Text as Text16, useInput as useInput9, useStdout as useStdout2, Static } from "ink";
13556
13960
  import fs22 from "fs-extra";
13557
13961
  import path20 from "path";
13558
13962
  import { exec as exec2 } from "child_process";
@@ -13561,21 +13965,21 @@ import TextInput4 from "ink-text-input";
13561
13965
  import SelectInput2 from "ink-select-input";
13562
13966
  import gradient2 from "gradient-string";
13563
13967
  function App({ args = [] }) {
13564
- const [confirmExit, setConfirmExit] = useState12(false);
13565
- const [exitCountdown, setExitCountdown] = useState12(10);
13968
+ const [confirmExit, setConfirmExit] = useState13(false);
13969
+ const [exitCountdown, setExitCountdown] = useState13(10);
13566
13970
  const { stdout } = useStdout2();
13567
- const [input, setInput] = useState12("");
13568
- const [inputKey, setInputKey] = useState12(0);
13569
- const [isExpanded, setIsExpanded] = useState12(false);
13570
- const [mode, setMode] = useState12("Flux");
13571
- const [terminalSize, setTerminalSize] = useState12({
13971
+ const [input, setInput] = useState13("");
13972
+ const [inputKey, setInputKey] = useState13(0);
13973
+ const [isExpanded, setIsExpanded] = useState13(false);
13974
+ const [mode, setMode] = useState13("Flux");
13975
+ const [terminalSize, setTerminalSize] = useState13({
13572
13976
  columns: stdout?.columns || 80,
13573
13977
  rows: stdout?.rows || 24
13574
13978
  });
13575
- const [selectedIndex, setSelectedIndex] = useState12(0);
13576
- const [isFilePickerDismissed, setIsFilePickerDismissed] = useState12(false);
13577
- const [showBridgePromo, setShowBridgePromo] = useState12(false);
13578
- const [promoSelectedIndex, setPromoSelectedIndex] = useState12(0);
13979
+ const [selectedIndex, setSelectedIndex] = useState13(0);
13980
+ const [isFilePickerDismissed, setIsFilePickerDismissed] = useState13(false);
13981
+ const [showBridgePromo, setShowBridgePromo] = useState13(false);
13982
+ const [promoSelectedIndex, setPromoSelectedIndex] = useState13(0);
13579
13983
  const suggestionOffsetRef = useRef3(0);
13580
13984
  const persistedModelRef = useRef3(null);
13581
13985
  useEffect9(() => {
@@ -13766,18 +14170,18 @@ function App({ args = [] }) {
13766
14170
  stdout.off("resize", handleResize);
13767
14171
  };
13768
14172
  }, [stdout]);
13769
- const [thinkingLevel, setThinkingLevel] = useState12("Medium");
13770
- const [aiProvider, setAiProvider] = useState12("Google");
13771
- const [setupStep, setSetupStep] = useState12(0);
13772
- const [latestVer, setLatestVer] = useState12(null);
13773
- const [showFullThinking, setShowFullThinking] = useState12(false);
13774
- const [activeModel, setActiveModel] = useState12("gemma-4-31b-it");
13775
- const [janitorModel, setJanitorModel] = useState12("gemma-4-26b-a4b-it");
13776
- const [isInitializing, setIsInitializing] = useState12(true);
13777
- const [isAppFocused, setIsAppFocused] = useState12(true);
14173
+ const [thinkingLevel, setThinkingLevel] = useState13("Medium");
14174
+ const [aiProvider, setAiProvider] = useState13("Google");
14175
+ const [setupStep, setSetupStep] = useState13(0);
14176
+ const [latestVer, setLatestVer] = useState13(null);
14177
+ const [showFullThinking, setShowFullThinking] = useState13(false);
14178
+ const [activeModel, setActiveModel] = useState13("gemma-4-31b-it");
14179
+ const [janitorModel, setJanitorModel] = useState13("gemma-4-26b-a4b-it");
14180
+ const [isInitializing, setIsInitializing] = useState13(true);
14181
+ const [isAppFocused, setIsAppFocused] = useState13(true);
13778
14182
  const lastFocusEventTime = useRef3(0);
13779
- const [apiKey, setApiKey] = useState12(null);
13780
- const [tempKey, setTempKey] = useState12("");
14183
+ const [apiKey, setApiKey] = useState13(null);
14184
+ const [tempKey, setTempKey] = useState13("");
13781
14185
  const addShiftEnterBinding = async (ideName) => {
13782
14186
  const kbPath = getKeybindingsPath(ideName);
13783
14187
  if (!kbPath) return;
@@ -13828,34 +14232,34 @@ function App({ args = [] }) {
13828
14232
  });
13829
14233
  }
13830
14234
  };
13831
- const [activeView, setActiveView] = useState12("chat");
13832
- const [apiTier, setApiTier] = useState12("Free");
13833
- const [quotas, setQuotas] = useState12({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
13834
- const [inputConfig, setInputConfig] = useState12(null);
13835
- const [systemSettings, setSystemSettings] = useState12({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
13836
- const [profileData, setProfileData] = useState12({ name: null, nickname: null, instructions: null });
13837
- const [imageSettings, setImageSettings] = useState12({ keyType: "Default", quality: "Low-High", apiKey: "" });
13838
- const [sessionStats, setSessionStats] = useState12({ tokens: 0 });
13839
- const [sessionAgentCalls, setSessionAgentCalls] = useState12(0);
13840
- const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState12(0);
13841
- const [sessionTotalTokens, setSessionTotalTokens] = useState12(0);
13842
- const [chatTokens, setChatTokens] = useState12(0);
14235
+ const [activeView, setActiveView] = useState13("chat");
14236
+ const [apiTier, setApiTier] = useState13("Free");
14237
+ const [quotas, setQuotas] = useState13({ limitMode: "Daily", agentLimit: 99999999, tokenLimit: 99999999999999, backgroundLimit: 999999, searchLimit: 100, customModelId: "", customLimit: 0 });
14238
+ const [inputConfig, setInputConfig] = useState13(null);
14239
+ const [systemSettings, setSystemSettings] = useState13({ memory: true, compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
14240
+ const [profileData, setProfileData] = useState13({ name: null, nickname: null, instructions: null });
14241
+ const [imageSettings, setImageSettings] = useState13({ keyType: "Default", quality: "Low-High", apiKey: "" });
14242
+ const [sessionStats, setSessionStats] = useState13({ tokens: 0 });
14243
+ const [sessionAgentCalls, setSessionAgentCalls] = useState13(0);
14244
+ const [sessionBackgroundCalls, setSessionBackgroundCalls] = useState13(0);
14245
+ const [sessionTotalTokens, setSessionTotalTokens] = useState13(0);
14246
+ const [chatTokens, setChatTokens] = useState13(0);
13843
14247
  const chatTokenStartRef = useRef3(0);
13844
- const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState12(0);
13845
- const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState12(0);
13846
- const [sessionToolSuccess, setSessionToolSuccess] = useState12(0);
13847
- const [sessionToolFailure, setSessionToolFailure] = useState12(0);
13848
- const [sessionToolDenied, setSessionToolDenied] = useState12(0);
13849
- const [sessionApiTime, setSessionApiTime] = useState12(0);
13850
- const [sessionToolTime, setSessionToolTime] = useState12(0);
13851
- const [sessionImageCount, setSessionImageCount] = useState12(0);
13852
- const [sessionImageCredits, setSessionImageCredits] = useState12(0);
13853
- const [dailyUsage, setDailyUsage] = useState12(null);
13854
- const [monthlyUsage, setMonthlyUsage] = useState12(null);
13855
- const [customPeriodUsage, setCustomPeriodUsage] = useState12(null);
13856
- const [statsMode, setStatsMode] = useState12("daily");
14248
+ const [sessionTotalCachedTokens, setSessionTotalCachedTokens] = useState13(0);
14249
+ const [sessionTotalCandidateTokens, setSessionTotalCandidateTokens] = useState13(0);
14250
+ const [sessionToolSuccess, setSessionToolSuccess] = useState13(0);
14251
+ const [sessionToolFailure, setSessionToolFailure] = useState13(0);
14252
+ const [sessionToolDenied, setSessionToolDenied] = useState13(0);
14253
+ const [sessionApiTime, setSessionApiTime] = useState13(0);
14254
+ const [sessionToolTime, setSessionToolTime] = useState13(0);
14255
+ const [sessionImageCount, setSessionImageCount] = useState13(0);
14256
+ const [sessionImageCredits, setSessionImageCredits] = useState13(0);
14257
+ const [dailyUsage, setDailyUsage] = useState13(null);
14258
+ const [monthlyUsage, setMonthlyUsage] = useState13(null);
14259
+ const [customPeriodUsage, setCustomPeriodUsage] = useState13(null);
14260
+ const [statsMode, setStatsMode] = useState13("daily");
13857
14261
  const PLAYGROUND_CHAT_ID = "flow-playground";
13858
- const [chatId, setChatId] = useState12(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
14262
+ const [chatId, setChatId] = useState13(args.includes("--playground") ? PLAYGROUND_CHAT_ID : generateChatId());
13859
14263
  useEffect9(() => {
13860
14264
  const nextTokens = sessionTotalTokens - chatTokenStartRef.current;
13861
14265
  setChatTokens(nextTokens);
@@ -13877,10 +14281,10 @@ function App({ args = [] }) {
13877
14281
  load();
13878
14282
  }
13879
14283
  }, [activeView, quotas.resetDay]);
13880
- const [activeCommand, setActiveCommand] = useState12(null);
13881
- const [execOutput, setExecOutput] = useState12("");
13882
- const [isTerminalFocused, setIsTerminalFocused] = useState12(false);
13883
- const [tick, setTick] = useState12(0);
14284
+ const [activeCommand, setActiveCommand] = useState13(null);
14285
+ const [execOutput, setExecOutput] = useState13("");
14286
+ const [isTerminalFocused, setIsTerminalFocused] = useState13(false);
14287
+ const [tick, setTick] = useState13(0);
13884
14288
  const isFirstRender = useRef3(true);
13885
14289
  const isSecondRender = useRef3(true);
13886
14290
  const isThirdRender = useRef3(true);
@@ -13980,9 +14384,9 @@ function App({ args = [] }) {
13980
14384
  useEffect9(() => {
13981
14385
  execOutputRef.current = execOutput;
13982
14386
  }, [execOutput]);
13983
- const [autoAcceptWrites, setAutoAcceptWrites] = useState12(false);
13984
- const [pendingApproval, setPendingApproval] = useState12(null);
13985
- const [pendingAsk, setPendingAsk] = useState12(null);
14387
+ const [autoAcceptWrites, setAutoAcceptWrites] = useState13(false);
14388
+ const [pendingApproval, setPendingApproval] = useState13(null);
14389
+ const [pendingAsk, setPendingAsk] = useState13(null);
13986
14390
  const resetPendingApproval = (decision) => {
13987
14391
  setPendingApproval(null);
13988
14392
  setActiveView("chat");
@@ -14001,8 +14405,9 @@ function App({ args = [] }) {
14001
14405
  if (ms < 1e3) return `${ms}ms`;
14002
14406
  return formatDuration(Math.floor(ms / 1e3));
14003
14407
  };
14004
- const [statusText, setStatusText] = useState12(null);
14005
- const [wittyPhrase, setWittyPhrase] = useState12("");
14408
+ const [statusText, setStatusText] = useState13(null);
14409
+ const [wittyPhrase, setWittyPhrase] = useState13("");
14410
+ const [hasPasteBlock, setHasPasteBlock] = useState13(false);
14006
14411
  useEffect9(() => {
14007
14412
  let interval;
14008
14413
  if (statusText) {
@@ -14017,19 +14422,20 @@ function App({ args = [] }) {
14017
14422
  }
14018
14423
  return () => clearInterval(interval);
14019
14424
  }, [statusText]);
14020
- const [isSpinnerActive, setIsSpinnerActive] = useState12(true);
14021
- const [isProcessing, setIsProcessing] = useState12(false);
14022
- const [isCompressing, setIsCompressing] = useState12(false);
14023
- const [escPressed, setEscPressed] = useState12(false);
14024
- const [escTimer, setEscTimer] = useState12(null);
14025
- const [escPressCount, setEscPressCount] = useState12(0);
14026
- const [recentPrompts, setRecentPrompts] = useState12([]);
14425
+ const [isSpinnerActive, setIsSpinnerActive] = useState13(true);
14426
+ const [isProcessing, setIsProcessing] = useState13(false);
14427
+ const [isCompressing, setIsCompressing] = useState13(false);
14428
+ const [escPressed, setEscPressed] = useState13(false);
14429
+ const [escTimer, setEscTimer] = useState13(null);
14430
+ const [escPressCount, setEscPressCount] = useState13(0);
14431
+ const [recentPrompts, setRecentPrompts] = useState13([]);
14027
14432
  const escDoubleTimerRef = useRef3(null);
14028
- const [queuedPrompt, setQueuedPrompt] = useState12(null);
14029
- const [resolutionData, setResolutionData] = useState12(null);
14030
- const [tempModelOverride, setTempModelOverride] = useState12(null);
14433
+ const didSignalTerminationRef = useRef3(false);
14434
+ const [queuedPrompt, setQueuedPrompt] = useState13(null);
14435
+ const [resolutionData, setResolutionData] = useState13(null);
14436
+ const [tempModelOverride, setTempModelOverride] = useState13(null);
14031
14437
  useEffect9(() => setEscPressCount(0), [input]);
14032
- const [messages, setMessages] = useState12(() => {
14438
+ const [messages, rawSetMessages] = useState13(() => {
14033
14439
  const logoMsg = { id: "logo-" + Date.now(), role: "system", isLogo: true, isMeta: true };
14034
14440
  const isHomeDir = process.cwd() === os4.homedir();
14035
14441
  const isSystemDir = (() => {
@@ -14064,9 +14470,24 @@ function App({ args = [] }) {
14064
14470
  }
14065
14471
  return msgs;
14066
14472
  });
14473
+ const setMessages = (value) => {
14474
+ rawSetMessages((prev) => {
14475
+ const next = typeof value === "function" ? value(prev) : value;
14476
+ const cleaned = [];
14477
+ for (let i = 0; i < next.length; i++) {
14478
+ const msg = next[i];
14479
+ const prevMsg = cleaned[cleaned.length - 1];
14480
+ if (msg && msg.text && msg.text.includes("Request Cancelled") && prevMsg && prevMsg.text && prevMsg.text.includes("Request Cancelled")) {
14481
+ continue;
14482
+ }
14483
+ cleaned.push(msg);
14484
+ }
14485
+ return cleaned;
14486
+ });
14487
+ };
14067
14488
  const queuedPromptRef = useRef3(null);
14068
- const [btwResponse, setBtwResponse] = useState12("");
14069
- const [showBtwBox, setShowBtwBox] = useState12(false);
14489
+ const [btwResponse, setBtwResponse] = useState13("");
14490
+ const [showBtwBox, setShowBtwBox] = useState13(false);
14070
14491
  const btwResponseRef = useRef3("");
14071
14492
  const btwClosedRef = useRef3(null);
14072
14493
  useEffect9(() => {
@@ -14087,8 +14508,8 @@ function App({ args = [] }) {
14087
14508
  }
14088
14509
  }
14089
14510
  }, [messages]);
14090
- const [completedIndex, setCompletedIndex] = useState12(messages.length);
14091
- const [clearKey, setClearKey] = useState12(0);
14511
+ const [completedIndex, setCompletedIndex] = useState13(messages.length);
14512
+ const [clearKey, setClearKey] = useState13(0);
14092
14513
  const parsedBlocks = useMemo2(() => {
14093
14514
  const completed = [];
14094
14515
  const active = [];
@@ -14147,7 +14568,7 @@ function App({ args = [] }) {
14147
14568
  const lastChunk = execOutput.trim();
14148
14569
  return lastChunk.endsWith("?") || lastChunk.endsWith(":") || /\[[yYnN/]+\]\s*$/.test(lastChunk) || /\([yYnN]\)\s*$/.test(lastChunk);
14149
14570
  }, [activeCommand, execOutput]);
14150
- useInput8((inputText, key) => {
14571
+ useInput9((inputText, key) => {
14151
14572
  if (inputText === "\x1B[I" || inputText === "\x1B[O" || inputText === "[I" || inputText === "[O") {
14152
14573
  return;
14153
14574
  }
@@ -14189,9 +14610,13 @@ function App({ args = [] }) {
14189
14610
  }
14190
14611
  if (isTerminalFocused && activeCommand) {
14191
14612
  if (key.return) {
14192
- const isWin = process.platform === "win32";
14193
- writeToActiveCommand(isWin ? "\r\n" : "\n");
14194
- if (!isActiveCommandPty) setExecOutput((prev) => prev + "\n");
14613
+ if (isActiveCommandPty) {
14614
+ writeToActiveCommand("\r");
14615
+ } else {
14616
+ const isWin = process.platform === "win32";
14617
+ writeToActiveCommand(isWin ? "\r\n" : "\n");
14618
+ setExecOutput((prev) => prev + "\n");
14619
+ }
14195
14620
  } else if (key.backspace || key.delete) {
14196
14621
  if (isActiveCommandPty) {
14197
14622
  writeToActiveCommand("\x7F");
@@ -14242,16 +14667,11 @@ function App({ args = [] }) {
14242
14667
  return;
14243
14668
  }
14244
14669
  if (isProcessing || activeCommand) {
14245
- if (!escPressed) {
14246
- setEscPressed(true);
14247
- if (escTimer) clearTimeout(escTimer);
14248
- setEscTimer(setTimeout(() => setEscPressed(false), 3e3));
14249
- } else {
14250
- signalTermination();
14251
- terminateActiveCommand();
14252
- setEscPressed(false);
14253
- if (escTimer) clearTimeout(escTimer);
14254
- }
14670
+ didSignalTerminationRef.current = true;
14671
+ signalTermination();
14672
+ terminateActiveCommand();
14673
+ setEscPressed(false);
14674
+ if (escTimer) clearTimeout(escTimer);
14255
14675
  } else {
14256
14676
  if (activeView === "revert") {
14257
14677
  setActiveView("chat");
@@ -14973,6 +15393,7 @@ function App({ args = [] }) {
14973
15393
  setInputKey((prev) => prev + 1);
14974
15394
  return;
14975
15395
  }
15396
+ didSignalTerminationRef.current = false;
14976
15397
  const normalizedValue = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
14977
15398
  if (normalizedValue.endsWith("\\")) {
14978
15399
  setInput(normalizedValue.slice(0, -1) + "\n");
@@ -15006,7 +15427,7 @@ function App({ args = [] }) {
15006
15427
  setCompletedIndex(prev.length + 1);
15007
15428
  const isBtw = hintText.startsWith("/btw");
15008
15429
  const cleanText = isBtw ? hintText.replace(/^\/btw\s*/, "") : hintText;
15009
- const prefix = isBtw ? "[QUESTION: QUEUED]" : "[STEERING HINT: QUEUED]";
15430
+ const prefix = isBtw ? "[QUESTION]" : "[STEERING HINT]";
15010
15431
  return [...prev, { id: "hint-" + Date.now(), role: "user", text: `${prefix}
15011
15432
  ${cleanText}`, color: "magenta" }];
15012
15433
  });
@@ -15108,6 +15529,9 @@ ${cleanText}`, color: "magenta" }];
15108
15529
  case "/clear": {
15109
15530
  if (stdout) {
15110
15531
  stdout.write("\x1B[2J\x1B[3J\x1B[H");
15532
+ if (stdout.isTTY) {
15533
+ stdout.write("\x1B[?2004h");
15534
+ }
15111
15535
  }
15112
15536
  setMessages([
15113
15537
  { id: "logo-" + Date.now(), role: "system", isLogo: true, isMeta: true }
@@ -15780,6 +16204,26 @@ ${timestamp}` };
15780
16204
  return [...prev, userMessage];
15781
16205
  });
15782
16206
  const streamChat = async () => {
16207
+ let didAppendCancel = false;
16208
+ const appendCancelMessage = (prev) => {
16209
+ if (didAppendCancel) {
16210
+ return prev;
16211
+ }
16212
+ const lastMsg = prev[prev.length - 1];
16213
+ if (lastMsg && lastMsg.text && lastMsg.text.includes("Request Cancelled")) {
16214
+ return prev;
16215
+ }
16216
+ didAppendCancel = true;
16217
+ const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
16218
+ const newMsgs = [...updatedPrev, {
16219
+ id: "cancel-" + Date.now(),
16220
+ role: "system",
16221
+ text: "\n\n\x1B[33m\u2139 Request Cancelled\x1B[0m",
16222
+ isMeta: true
16223
+ }];
16224
+ setCompletedIndex(newMsgs.length);
16225
+ return newMsgs;
16226
+ };
15783
16227
  let hasFiredJanitor = false;
15784
16228
  setIsProcessing(true);
15785
16229
  setIsExpanded(false);
@@ -15983,17 +16427,7 @@ Selection: ${val}`,
15983
16427
  sendStatus(packet.content);
15984
16428
  }
15985
16429
  if (packet.content === "Request Cancelled") {
15986
- setMessages((prev) => {
15987
- const updatedPrev = prev.map((m) => m.isStreaming ? { ...m, isStreaming: false } : m);
15988
- const newMsgs = [...updatedPrev, {
15989
- id: "cancel-" + Date.now(),
15990
- role: "system",
15991
- text: "\n\n\x1B[33m\u2139 Request Cancelled\x1B[0m",
15992
- isMeta: true
15993
- }];
15994
- setCompletedIndex(newMsgs.length);
15995
- return newMsgs;
15996
- });
16430
+ setMessages((prev) => appendCancelMessage(prev));
15997
16431
  }
15998
16432
  continue;
15999
16433
  }
@@ -16289,6 +16723,9 @@ Selection: ${val}`,
16289
16723
  } finally {
16290
16724
  setIsProcessing(false);
16291
16725
  setStatusText(null);
16726
+ if (didSignalTerminationRef.current) {
16727
+ setMessages((prev) => appendCancelMessage(prev));
16728
+ }
16292
16729
  if (!hasFiredJanitor) {
16293
16730
  if (process.stdout.isTTY) {
16294
16731
  process.stdout.write("\x1B]0;FluxFlow | Idle\x07");
@@ -17143,7 +17580,7 @@ Selection: ${val}`,
17143
17580
  }
17144
17581
  )));
17145
17582
  default:
17146
- return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, showBtwBox && btwResponse && /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%", marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Box15, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Text16, { color: "white", bold: true, underline: true }, "INQUIRY RESPONSE"), /* @__PURE__ */ React15.createElement(Text16, { color: "gray" }, "[ ESC to Close ]")), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React15.createElement(CodeRenderer, { text: btwResponse, columns: terminalSize.columns - 6 }))), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, null, statusText ? /* @__PURE__ */ React15.createElement(Box15, { gap: 1 }, /* @__PURE__ */ React15.createElement(dist_default, { colors: ["#001a1a", "#080510", "#12021c"] }, /* @__PURE__ */ React15.createElement(build_default, null)), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true, italic: true }, statusText)) : /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : "Waiting for input...")), /* @__PURE__ */ React15.createElement(Box15, null, wittyPhrase && /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React15.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React15.createElement(
17583
+ return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", marginTop: 1, flexShrink: 0, width: "100%" }, showBtwBox && btwResponse && /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "grey", paddingX: 2, paddingY: 1, width: "100%", marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Box15, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Text16, { color: "white", bold: true, underline: true }, "INQUIRY RESPONSE"), /* @__PURE__ */ React15.createElement(Text16, { color: "gray" }, "[ ESC to Close ]")), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1, width: "100%" }, /* @__PURE__ */ React15.createElement(CodeRenderer, { text: btwResponse, columns: terminalSize.columns - 6 }))), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 0, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, null, statusText ? /* @__PURE__ */ React15.createElement(Box15, { gap: 1 }, /* @__PURE__ */ React15.createElement(dist_default, { colors: ["#001a1a", "#080510", "#12021c"] }, /* @__PURE__ */ React15.createElement(build_default, null)), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true, italic: true }, statusText)) : /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, input.length > 0 && escPressCount ? "Press ESC again to clear input" : hasPasteBlock ? "Press CTRL + O to expand" : "Waiting for input...")), /* @__PURE__ */ React15.createElement(Box15, null, wittyPhrase && /* @__PURE__ */ React15.createElement(Text16, { color: "gray", italic: true }, wittyPhrase, " "), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "[ "), /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, tempModelOverride || activeModel), /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, " ]"))), /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { width: "100%", height: 1, overflow: "hidden" }, /* @__PURE__ */ React15.createElement(Text16, { color: "#555555" }, "\u2584".repeat(Math.max(1, terminalSize.columns)))), /* @__PURE__ */ React15.createElement(
17147
17584
  Box15,
17148
17585
  {
17149
17586
  backgroundColor: "#555555",
@@ -17156,6 +17593,7 @@ Selection: ${val}`,
17156
17593
  MultilineInput,
17157
17594
  {
17158
17595
  key: `input-${inputKey}`,
17596
+ onPasteStateChange: setHasPasteBlock,
17159
17597
  focus: !isTerminalFocused && !isCompressing,
17160
17598
  showCursor: isAppFocused && !isCompressing,
17161
17599
  lastFocusEventTime: lastFocusEventTime.current,
@@ -17199,7 +17637,7 @@ Selection: ${val}`,
17199
17637
  aiProvider,
17200
17638
  version: versionFluxflow
17201
17639
  }
17202
- )), activeCommand && /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React15.createElement(Box15, { borderStyle: "double", borderColor: "grey", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, "Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React15.createElement(Box15, { borderStyle: "round", borderColor: "white", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "API KEY REQUIRED")), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, flexDirection: "column" }, setupStep === 0 ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, "Select your Preferred Provider:"), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
17640
+ )), activeCommand && /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty, terminalHeight: terminalSize.rows }))), isInitializing ? /* @__PURE__ */ React15.createElement(Box15, { borderStyle: "double", borderColor: "grey", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, "Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React15.createElement(Box15, { borderStyle: "round", borderColor: "white", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text16, { color: "gray", bold: true }, "API KEY REQUIRED")), /* @__PURE__ */ React15.createElement(Box15, { paddingX: 1, flexDirection: "column" }, setupStep === 0 ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Text16, { color: "white" }, "Select your Preferred Provider:"), /* @__PURE__ */ React15.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
17203
17641
  CommandMenu,
17204
17642
  {
17205
17643
  items: [
@@ -17693,7 +18131,7 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
17693
18131
  }
17694
18132
  const promptPackageManager = async () => {
17695
18133
  const React17 = (await import("react")).default;
17696
- const { useState: useState13 } = React17;
18134
+ const { useState: useState14 } = React17;
17697
18135
  const { render: render2, Box: Box16, Text: Text17 } = await import("ink");
17698
18136
  const SelectInput3 = (await import("ink-select-input")).default;
17699
18137
  const TextInput5 = (await import("ink-text-input")).default;
@@ -17710,8 +18148,8 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
17710
18148
  };
17711
18149
  let unmountFn;
17712
18150
  const PromptComponent = () => {
17713
- const [step, setStep] = useState13("select");
17714
- const [customCommand2, setCustomCommand] = useState13("");
18151
+ const [step, setStep] = useState14("select");
18152
+ const [customCommand2, setCustomCommand] = useState14("");
17715
18153
  const handleSelect = (item) => {
17716
18154
  if (item.value === "custom") {
17717
18155
  setStep("custom");
@@ -17812,7 +18250,20 @@ if (isBundled && !process.execArgv.some((arg) => arg.includes("max-old-space-siz
17812
18250
  if (process.stdout.isTTY) {
17813
18251
  process.stdout.write("\x1B]0;FluxFlow\x07");
17814
18252
  process.stdout.write("\x1B]633;P;TerminalTitle=FluxFlow\x07");
18253
+ process.stdout.write("\x1B[?2004h");
17815
18254
  }
18255
+ const disableBracketedPaste = () => {
18256
+ if (process.stdout.isTTY) {
18257
+ process.stdout.write("\x1B[?2004l");
18258
+ }
18259
+ };
18260
+ process.on("exit", disableBracketedPaste);
18261
+ ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
18262
+ process.once(sig, () => {
18263
+ disableBracketedPaste();
18264
+ process.exit(0);
18265
+ });
18266
+ });
17816
18267
  if (args.includes("--playground")) {
17817
18268
  const originalCwd = process.cwd();
17818
18269
  process.argv.push("--original-cwd", originalCwd);