reasonix 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -16
- package/README.zh-CN.md +50 -11
- package/dist/cli/{chunk-7546PPEL.js → chunk-3ALFOYE6.js} +75 -73
- package/dist/cli/chunk-3ALFOYE6.js.map +1 -0
- package/dist/cli/index.js +776 -604
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-XPEUBA46.js → prompt-MAHJTS7Q.js} +2 -2
- package/dist/index.js +114 -114
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-7546PPEL.js.map +0 -1
- /package/dist/cli/{prompt-XPEUBA46.js.map → prompt-MAHJTS7Q.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
memoryEnabled,
|
|
13
13
|
readProjectMemory,
|
|
14
14
|
sanitizeMemoryName
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-3ALFOYE6.js";
|
|
16
16
|
|
|
17
17
|
// src/cli/index.ts
|
|
18
18
|
import { Command } from "commander";
|
|
@@ -1283,7 +1283,7 @@ function blockToString(block) {
|
|
|
1283
1283
|
return `[unknown block: ${JSON.stringify(block)}]`;
|
|
1284
1284
|
}
|
|
1285
1285
|
|
|
1286
|
-
// src/memory.ts
|
|
1286
|
+
// src/memory/runtime.ts
|
|
1287
1287
|
import { createHash } from "crypto";
|
|
1288
1288
|
var ImmutablePrefix = class {
|
|
1289
1289
|
system;
|
|
@@ -1375,6 +1375,120 @@ var VolatileScratch = class {
|
|
|
1375
1375
|
}
|
|
1376
1376
|
};
|
|
1377
1377
|
|
|
1378
|
+
// src/memory/session.ts
|
|
1379
|
+
import {
|
|
1380
|
+
appendFileSync,
|
|
1381
|
+
chmodSync as chmodSync2,
|
|
1382
|
+
existsSync as existsSync3,
|
|
1383
|
+
mkdirSync as mkdirSync2,
|
|
1384
|
+
readFileSync as readFileSync4,
|
|
1385
|
+
readdirSync,
|
|
1386
|
+
statSync,
|
|
1387
|
+
unlinkSync,
|
|
1388
|
+
writeFileSync as writeFileSync2
|
|
1389
|
+
} from "fs";
|
|
1390
|
+
import { homedir as homedir3 } from "os";
|
|
1391
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
1392
|
+
function sessionsDir() {
|
|
1393
|
+
return join4(homedir3(), ".reasonix", "sessions");
|
|
1394
|
+
}
|
|
1395
|
+
function sessionPath(name) {
|
|
1396
|
+
return join4(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
1397
|
+
}
|
|
1398
|
+
function sanitizeName(name) {
|
|
1399
|
+
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
1400
|
+
return cleaned || "default";
|
|
1401
|
+
}
|
|
1402
|
+
function loadSessionMessages(name) {
|
|
1403
|
+
const path5 = sessionPath(name);
|
|
1404
|
+
if (!existsSync3(path5)) return [];
|
|
1405
|
+
try {
|
|
1406
|
+
const raw = readFileSync4(path5, "utf8");
|
|
1407
|
+
const out = [];
|
|
1408
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
1409
|
+
const trimmed = line.trim();
|
|
1410
|
+
if (!trimmed) continue;
|
|
1411
|
+
try {
|
|
1412
|
+
const msg = JSON.parse(trimmed);
|
|
1413
|
+
if (msg && typeof msg === "object" && "role" in msg) out.push(msg);
|
|
1414
|
+
} catch {
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
return out;
|
|
1418
|
+
} catch {
|
|
1419
|
+
return [];
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
function appendSessionMessage(name, message) {
|
|
1423
|
+
const path5 = sessionPath(name);
|
|
1424
|
+
mkdirSync2(dirname3(path5), { recursive: true });
|
|
1425
|
+
appendFileSync(path5, `${JSON.stringify(message)}
|
|
1426
|
+
`, "utf8");
|
|
1427
|
+
try {
|
|
1428
|
+
chmodSync2(path5, 384);
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
function listSessions() {
|
|
1433
|
+
const dir = sessionsDir();
|
|
1434
|
+
if (!existsSync3(dir)) return [];
|
|
1435
|
+
try {
|
|
1436
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1437
|
+
return files.map((file) => {
|
|
1438
|
+
const path5 = join4(dir, file);
|
|
1439
|
+
const stat2 = statSync(path5);
|
|
1440
|
+
const name = file.replace(/\.jsonl$/, "");
|
|
1441
|
+
const messageCount = countLines(path5);
|
|
1442
|
+
return { name, path: path5, size: stat2.size, messageCount, mtime: stat2.mtime };
|
|
1443
|
+
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
1444
|
+
} catch {
|
|
1445
|
+
return [];
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
function pruneStaleSessions(daysOld = 90) {
|
|
1449
|
+
const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1e3;
|
|
1450
|
+
const deleted = [];
|
|
1451
|
+
for (const s of listSessions()) {
|
|
1452
|
+
if (s.mtime.getTime() < cutoff) {
|
|
1453
|
+
if (deleteSession(s.name)) deleted.push(s.name);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
return deleted;
|
|
1457
|
+
}
|
|
1458
|
+
function deleteSession(name) {
|
|
1459
|
+
const path5 = sessionPath(name);
|
|
1460
|
+
try {
|
|
1461
|
+
unlinkSync(path5);
|
|
1462
|
+
const sidecar = path5.replace(/\.jsonl$/, ".pending.json");
|
|
1463
|
+
try {
|
|
1464
|
+
unlinkSync(sidecar);
|
|
1465
|
+
} catch {
|
|
1466
|
+
}
|
|
1467
|
+
return true;
|
|
1468
|
+
} catch {
|
|
1469
|
+
return false;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function rewriteSession(name, messages) {
|
|
1473
|
+
const path5 = sessionPath(name);
|
|
1474
|
+
mkdirSync2(dirname3(path5), { recursive: true });
|
|
1475
|
+
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
1476
|
+
writeFileSync2(path5, body ? `${body}
|
|
1477
|
+
` : "", "utf8");
|
|
1478
|
+
try {
|
|
1479
|
+
chmodSync2(path5, 384);
|
|
1480
|
+
} catch {
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function countLines(path5) {
|
|
1484
|
+
try {
|
|
1485
|
+
const raw = readFileSync4(path5, "utf8");
|
|
1486
|
+
return raw.split(/\r?\n/).filter((l) => l.trim()).length;
|
|
1487
|
+
} catch {
|
|
1488
|
+
return 0;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1378
1492
|
// src/repair/scavenge.ts
|
|
1379
1493
|
function scavengeToolCalls(reasoningContent, opts) {
|
|
1380
1494
|
if (!reasoningContent) return { calls: [], notes: [] };
|
|
@@ -1676,121 +1790,7 @@ function signature(call) {
|
|
|
1676
1790
|
return `${call.function?.name ?? ""}::${call.function?.arguments ?? ""}`;
|
|
1677
1791
|
}
|
|
1678
1792
|
|
|
1679
|
-
// src/
|
|
1680
|
-
import {
|
|
1681
|
-
appendFileSync,
|
|
1682
|
-
chmodSync as chmodSync2,
|
|
1683
|
-
existsSync as existsSync3,
|
|
1684
|
-
mkdirSync as mkdirSync2,
|
|
1685
|
-
readFileSync as readFileSync4,
|
|
1686
|
-
readdirSync,
|
|
1687
|
-
statSync,
|
|
1688
|
-
unlinkSync,
|
|
1689
|
-
writeFileSync as writeFileSync2
|
|
1690
|
-
} from "fs";
|
|
1691
|
-
import { homedir as homedir3 } from "os";
|
|
1692
|
-
import { dirname as dirname3, join as join4 } from "path";
|
|
1693
|
-
function sessionsDir() {
|
|
1694
|
-
return join4(homedir3(), ".reasonix", "sessions");
|
|
1695
|
-
}
|
|
1696
|
-
function sessionPath(name) {
|
|
1697
|
-
return join4(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
1698
|
-
}
|
|
1699
|
-
function sanitizeName(name) {
|
|
1700
|
-
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
1701
|
-
return cleaned || "default";
|
|
1702
|
-
}
|
|
1703
|
-
function loadSessionMessages(name) {
|
|
1704
|
-
const path5 = sessionPath(name);
|
|
1705
|
-
if (!existsSync3(path5)) return [];
|
|
1706
|
-
try {
|
|
1707
|
-
const raw = readFileSync4(path5, "utf8");
|
|
1708
|
-
const out = [];
|
|
1709
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
1710
|
-
const trimmed = line.trim();
|
|
1711
|
-
if (!trimmed) continue;
|
|
1712
|
-
try {
|
|
1713
|
-
const msg = JSON.parse(trimmed);
|
|
1714
|
-
if (msg && typeof msg === "object" && "role" in msg) out.push(msg);
|
|
1715
|
-
} catch {
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
return out;
|
|
1719
|
-
} catch {
|
|
1720
|
-
return [];
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
function appendSessionMessage(name, message) {
|
|
1724
|
-
const path5 = sessionPath(name);
|
|
1725
|
-
mkdirSync2(dirname3(path5), { recursive: true });
|
|
1726
|
-
appendFileSync(path5, `${JSON.stringify(message)}
|
|
1727
|
-
`, "utf8");
|
|
1728
|
-
try {
|
|
1729
|
-
chmodSync2(path5, 384);
|
|
1730
|
-
} catch {
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
function listSessions() {
|
|
1734
|
-
const dir = sessionsDir();
|
|
1735
|
-
if (!existsSync3(dir)) return [];
|
|
1736
|
-
try {
|
|
1737
|
-
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1738
|
-
return files.map((file) => {
|
|
1739
|
-
const path5 = join4(dir, file);
|
|
1740
|
-
const stat2 = statSync(path5);
|
|
1741
|
-
const name = file.replace(/\.jsonl$/, "");
|
|
1742
|
-
const messageCount = countLines(path5);
|
|
1743
|
-
return { name, path: path5, size: stat2.size, messageCount, mtime: stat2.mtime };
|
|
1744
|
-
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
1745
|
-
} catch {
|
|
1746
|
-
return [];
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
function pruneStaleSessions(daysOld = 90) {
|
|
1750
|
-
const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1e3;
|
|
1751
|
-
const deleted = [];
|
|
1752
|
-
for (const s of listSessions()) {
|
|
1753
|
-
if (s.mtime.getTime() < cutoff) {
|
|
1754
|
-
if (deleteSession(s.name)) deleted.push(s.name);
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
return deleted;
|
|
1758
|
-
}
|
|
1759
|
-
function deleteSession(name) {
|
|
1760
|
-
const path5 = sessionPath(name);
|
|
1761
|
-
try {
|
|
1762
|
-
unlinkSync(path5);
|
|
1763
|
-
const sidecar = path5.replace(/\.jsonl$/, ".pending.json");
|
|
1764
|
-
try {
|
|
1765
|
-
unlinkSync(sidecar);
|
|
1766
|
-
} catch {
|
|
1767
|
-
}
|
|
1768
|
-
return true;
|
|
1769
|
-
} catch {
|
|
1770
|
-
return false;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
function rewriteSession(name, messages) {
|
|
1774
|
-
const path5 = sessionPath(name);
|
|
1775
|
-
mkdirSync2(dirname3(path5), { recursive: true });
|
|
1776
|
-
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
1777
|
-
writeFileSync2(path5, body ? `${body}
|
|
1778
|
-
` : "", "utf8");
|
|
1779
|
-
try {
|
|
1780
|
-
chmodSync2(path5, 384);
|
|
1781
|
-
} catch {
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
function countLines(path5) {
|
|
1785
|
-
try {
|
|
1786
|
-
const raw = readFileSync4(path5, "utf8");
|
|
1787
|
-
return raw.split(/\r?\n/).filter((l) => l.trim()).length;
|
|
1788
|
-
} catch {
|
|
1789
|
-
return 0;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
// src/telemetry.ts
|
|
1793
|
+
// src/telemetry/stats.ts
|
|
1794
1794
|
var DEEPSEEK_PRICING = {
|
|
1795
1795
|
"deepseek-v4-flash": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },
|
|
1796
1796
|
"deepseek-v4-pro": { inputCacheHit: 0.139, inputCacheMiss: 1.667, output: 3.333 },
|
|
@@ -2795,7 +2795,7 @@ ${summary}`;
|
|
|
2795
2795
|
assistantMessage(content, toolCalls, producingModel, reasoningContent) {
|
|
2796
2796
|
const msg = { role: "assistant", content };
|
|
2797
2797
|
if (toolCalls.length > 0) msg.tool_calls = toolCalls;
|
|
2798
|
-
if (isThinkingModeModel(producingModel)) {
|
|
2798
|
+
if (isThinkingModeModel(producingModel) || reasoningContent && reasoningContent.length > 0) {
|
|
2799
2799
|
msg.reasoning_content = reasoningContent ?? "";
|
|
2800
2800
|
}
|
|
2801
2801
|
return msg;
|
|
@@ -5706,7 +5706,7 @@ function loadDotenv(path5 = ".env") {
|
|
|
5706
5706
|
}
|
|
5707
5707
|
}
|
|
5708
5708
|
|
|
5709
|
-
// src/transcript.ts
|
|
5709
|
+
// src/transcript/log.ts
|
|
5710
5710
|
import { createWriteStream, readFileSync as readFileSync7 } from "fs";
|
|
5711
5711
|
function recordFromLoopEvent(ev, extra) {
|
|
5712
5712
|
const rec = {
|
|
@@ -5788,7 +5788,7 @@ function parseTranscript(raw) {
|
|
|
5788
5788
|
return out;
|
|
5789
5789
|
}
|
|
5790
5790
|
|
|
5791
|
-
// src/replay.ts
|
|
5791
|
+
// src/transcript/replay.ts
|
|
5792
5792
|
function groupRecordsByTurn(records) {
|
|
5793
5793
|
const byTurn = /* @__PURE__ */ new Map();
|
|
5794
5794
|
for (const rec of records) {
|
|
@@ -5895,7 +5895,7 @@ function round2(n, digits) {
|
|
|
5895
5895
|
return Math.round(n * f) / f;
|
|
5896
5896
|
}
|
|
5897
5897
|
|
|
5898
|
-
// src/diff.ts
|
|
5898
|
+
// src/transcript/diff.ts
|
|
5899
5899
|
function findNextDivergence(pairs, fromIdx) {
|
|
5900
5900
|
for (let i = fromIdx + 1; i < pairs.length; i++) {
|
|
5901
5901
|
if (pairs[i].kind !== "match") return i;
|
|
@@ -7208,7 +7208,7 @@ function sep() {
|
|
|
7208
7208
|
return process.platform === "win32" ? "\\" : "/";
|
|
7209
7209
|
}
|
|
7210
7210
|
|
|
7211
|
-
// src/usage.ts
|
|
7211
|
+
// src/telemetry/usage.ts
|
|
7212
7212
|
import {
|
|
7213
7213
|
appendFileSync as appendFileSync2,
|
|
7214
7214
|
existsSync as existsSync8,
|
|
@@ -7845,305 +7845,48 @@ var Eventizer = class {
|
|
|
7845
7845
|
errorEvent(turn, message, recoverable) {
|
|
7846
7846
|
return {
|
|
7847
7847
|
id: ++this.nextId,
|
|
7848
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7849
|
-
turn,
|
|
7850
|
-
type: "error",
|
|
7851
|
-
message,
|
|
7852
|
-
recoverable
|
|
7853
|
-
};
|
|
7854
|
-
}
|
|
7855
|
-
/** Pattern-match warning text since LoopEvent doesn't carry a typed kind. */
|
|
7856
|
-
classifyWarning(ev) {
|
|
7857
|
-
const c = ev.content;
|
|
7858
|
-
if (/\bauto-escalating to\b|\barmed\b.*pro|NEEDS_PRO/.test(c)) {
|
|
7859
|
-
return {
|
|
7860
|
-
id: ++this.nextId,
|
|
7861
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7862
|
-
turn: ev.turn,
|
|
7863
|
-
type: "policy.escalated",
|
|
7864
|
-
fromModel: "",
|
|
7865
|
-
toModel: "",
|
|
7866
|
-
reason: c.includes("armed") ? "user-request" : "self-report"
|
|
7867
|
-
};
|
|
7868
|
-
}
|
|
7869
|
-
if (/budget\b.*\$|\$\d.*\/\s*\$\d/.test(c)) {
|
|
7870
|
-
const blocked = /blocked|exceeded|refus/i.test(c);
|
|
7871
|
-
return {
|
|
7872
|
-
id: ++this.nextId,
|
|
7873
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7874
|
-
turn: ev.turn,
|
|
7875
|
-
type: blocked ? "policy.budget.blocked" : "policy.budget.warning",
|
|
7876
|
-
spentUsd: 0,
|
|
7877
|
-
capUsd: 0
|
|
7878
|
-
};
|
|
7879
|
-
}
|
|
7880
|
-
return this.errorEvent(ev.turn, c, true);
|
|
7881
|
-
}
|
|
7882
|
-
};
|
|
7883
|
-
function looksLikeToolError(content, _toolName) {
|
|
7884
|
-
if (!content) return false;
|
|
7885
|
-
if (content.startsWith("ERROR:")) return true;
|
|
7886
|
-
if (content.startsWith("[hook block]")) return true;
|
|
7887
|
-
if (/^\{"error"\s*:/.test(content)) return true;
|
|
7888
|
-
if (/\bConfirmationError:|\bNeedsConfirmationError\b/.test(content)) return true;
|
|
7889
|
-
return false;
|
|
7890
|
-
}
|
|
7891
|
-
|
|
7892
|
-
// src/frame/width.ts
|
|
7893
|
-
import stringWidthLib from "string-width";
|
|
7894
|
-
var segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
|
|
7895
|
-
function graphemes(s) {
|
|
7896
|
-
return Array.from(segmenter.segment(s), (seg) => seg.segment);
|
|
7897
|
-
}
|
|
7898
|
-
function graphemeWidth(g) {
|
|
7899
|
-
if (g.length === 0) return 0;
|
|
7900
|
-
const w = stringWidthLib(g);
|
|
7901
|
-
if (w <= 0) return 0;
|
|
7902
|
-
if (w >= 2) return 2;
|
|
7903
|
-
return 1;
|
|
7904
|
-
}
|
|
7905
|
-
|
|
7906
|
-
// src/frame/frame.ts
|
|
7907
|
-
var SPACE = { char: " ", width: 1 };
|
|
7908
|
-
var TAIL = { char: "", width: 1, tail: true };
|
|
7909
|
-
function empty(width = 0) {
|
|
7910
|
-
return { width, rows: [] };
|
|
7911
|
-
}
|
|
7912
|
-
function text(s, opts) {
|
|
7913
|
-
const { width, fg, bg, bold, dim, italic, underline, inverse, href } = opts;
|
|
7914
|
-
if (width <= 0) return empty(0);
|
|
7915
|
-
const styleOf = (g, w) => {
|
|
7916
|
-
const base = { char: g, width: w };
|
|
7917
|
-
if (fg !== void 0) base.fg = fg;
|
|
7918
|
-
if (bg !== void 0) base.bg = bg;
|
|
7919
|
-
if (bold) base.bold = true;
|
|
7920
|
-
if (dim) base.dim = true;
|
|
7921
|
-
if (italic) base.italic = true;
|
|
7922
|
-
if (underline) base.underline = true;
|
|
7923
|
-
if (inverse) base.inverse = true;
|
|
7924
|
-
if (href !== void 0) base.href = href;
|
|
7925
|
-
return base;
|
|
7926
|
-
};
|
|
7927
|
-
const rows = [];
|
|
7928
|
-
const lines = s.split("\n");
|
|
7929
|
-
for (const line of lines) {
|
|
7930
|
-
if (line.length === 0) {
|
|
7931
|
-
rows.push(padRowRight([], width));
|
|
7932
|
-
continue;
|
|
7933
|
-
}
|
|
7934
|
-
let buf = [];
|
|
7935
|
-
let bufWidth = 0;
|
|
7936
|
-
for (const g of graphemes(line)) {
|
|
7937
|
-
const w = graphemeWidth(g);
|
|
7938
|
-
if (w === 0) continue;
|
|
7939
|
-
if (bufWidth + w > width) {
|
|
7940
|
-
rows.push(padRowRight(buf, width - bufWidth));
|
|
7941
|
-
buf = [];
|
|
7942
|
-
bufWidth = 0;
|
|
7943
|
-
}
|
|
7944
|
-
buf.push(styleOf(g, w));
|
|
7945
|
-
if (w === 2) buf.push(TAIL);
|
|
7946
|
-
bufWidth += w;
|
|
7947
|
-
}
|
|
7948
|
-
rows.push(padRowRight(buf, width - bufWidth));
|
|
7949
|
-
}
|
|
7950
|
-
return { width, rows };
|
|
7951
|
-
}
|
|
7952
|
-
function padRowRight(cells, extraSpaces) {
|
|
7953
|
-
if (extraSpaces <= 0) return cells.slice();
|
|
7954
|
-
const out = cells.slice();
|
|
7955
|
-
for (let i = 0; i < extraSpaces; i++) out.push(SPACE);
|
|
7956
|
-
return out;
|
|
7957
|
-
}
|
|
7958
|
-
function spacerRow(width) {
|
|
7959
|
-
if (width <= 0) return [];
|
|
7960
|
-
return Array.from({ length: width }, () => SPACE);
|
|
7961
|
-
}
|
|
7962
|
-
function vstack(...frames) {
|
|
7963
|
-
if (frames.length === 0) return empty(0);
|
|
7964
|
-
const w = Math.max(...frames.map((f) => f.width));
|
|
7965
|
-
const rows = [];
|
|
7966
|
-
for (const f of frames) {
|
|
7967
|
-
if (f.width === w) {
|
|
7968
|
-
rows.push(...f.rows);
|
|
7969
|
-
} else {
|
|
7970
|
-
const extra = w - f.width;
|
|
7971
|
-
for (const r of f.rows) rows.push(padRowRight(r, extra));
|
|
7972
|
-
}
|
|
7973
|
-
}
|
|
7974
|
-
return { width: w, rows };
|
|
7975
|
-
}
|
|
7976
|
-
function hstack(...frames) {
|
|
7977
|
-
if (frames.length === 0) return empty(0);
|
|
7978
|
-
const h = Math.max(...frames.map((f) => f.rows.length));
|
|
7979
|
-
const w = frames.reduce((a, f) => a + f.width, 0);
|
|
7980
|
-
const rows = [];
|
|
7981
|
-
for (let i = 0; i < h; i++) {
|
|
7982
|
-
const cells = [];
|
|
7983
|
-
for (const f of frames) {
|
|
7984
|
-
const r = f.rows[i] ?? spacerRow(f.width);
|
|
7985
|
-
cells.push(...r);
|
|
7986
|
-
}
|
|
7987
|
-
rows.push(cells);
|
|
7988
|
-
}
|
|
7989
|
-
return { width: w, rows };
|
|
7990
|
-
}
|
|
7991
|
-
function pad(f, top, right, bottom2, left) {
|
|
7992
|
-
const newWidth = f.width + Math.max(0, left) + Math.max(0, right);
|
|
7993
|
-
const tPad = Math.max(0, top);
|
|
7994
|
-
const bPad = Math.max(0, bottom2);
|
|
7995
|
-
const blank2 = spacerRow(newWidth);
|
|
7996
|
-
const rows = [];
|
|
7997
|
-
for (let i = 0; i < tPad; i++) rows.push(blank2);
|
|
7998
|
-
if (left <= 0 && right <= 0) {
|
|
7999
|
-
rows.push(...f.rows);
|
|
8000
|
-
} else {
|
|
8001
|
-
const lPad = spacerRow(Math.max(0, left));
|
|
8002
|
-
const rPad = spacerRow(Math.max(0, right));
|
|
8003
|
-
for (const r of f.rows) rows.push([...lPad, ...r, ...rPad]);
|
|
8004
|
-
}
|
|
8005
|
-
for (let i = 0; i < bPad; i++) rows.push(blank2);
|
|
8006
|
-
return { width: newWidth, rows };
|
|
8007
|
-
}
|
|
8008
|
-
function borderLeft(f, color2, char = "\u2502") {
|
|
8009
|
-
const bar = { char, width: 1, fg: color2 };
|
|
8010
|
-
const newWidth = f.width + 1;
|
|
8011
|
-
const rows = [];
|
|
8012
|
-
for (const r of f.rows) rows.push([bar, ...r]);
|
|
8013
|
-
return { width: newWidth, rows };
|
|
8014
|
-
}
|
|
8015
|
-
|
|
8016
|
-
// src/frame/ansi.ts
|
|
8017
|
-
var ESC = "\x1B";
|
|
8018
|
-
var RESET = `${ESC}[0m`;
|
|
8019
|
-
function sameStyle(a, b) {
|
|
8020
|
-
return a.fg === b.fg && a.bg === b.bg && !!a.bold === !!b.bold && !!a.dim === !!b.dim && !!a.italic === !!b.italic && !!a.underline === !!b.underline && !!a.inverse === !!b.inverse && a.href === b.href;
|
|
8021
|
-
}
|
|
8022
|
-
function fgEscape(color2) {
|
|
8023
|
-
if (!color2) return null;
|
|
8024
|
-
const rgb = parseColor(color2);
|
|
8025
|
-
if (rgb) return `38;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
8026
|
-
const named = NAMED_FG[color2.toLowerCase()];
|
|
8027
|
-
if (named !== void 0) return String(named);
|
|
8028
|
-
return null;
|
|
8029
|
-
}
|
|
8030
|
-
function bgEscape(color2) {
|
|
8031
|
-
if (!color2) return null;
|
|
8032
|
-
const rgb = parseColor(color2);
|
|
8033
|
-
if (rgb) return `48;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
8034
|
-
const named = NAMED_BG[color2.toLowerCase()];
|
|
8035
|
-
if (named !== void 0) return String(named);
|
|
8036
|
-
return null;
|
|
8037
|
-
}
|
|
8038
|
-
function parseColor(s) {
|
|
8039
|
-
if (!s.startsWith("#")) return null;
|
|
8040
|
-
const hex = s.slice(1);
|
|
8041
|
-
if (hex.length !== 6) return null;
|
|
8042
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
8043
|
-
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
8044
|
-
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
8045
|
-
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
|
|
8046
|
-
return [r, g, b];
|
|
8047
|
-
}
|
|
8048
|
-
var NAMED_FG = {
|
|
8049
|
-
black: 30,
|
|
8050
|
-
red: 31,
|
|
8051
|
-
green: 32,
|
|
8052
|
-
yellow: 33,
|
|
8053
|
-
blue: 34,
|
|
8054
|
-
magenta: 35,
|
|
8055
|
-
cyan: 36,
|
|
8056
|
-
white: 37,
|
|
8057
|
-
gray: 90,
|
|
8058
|
-
grey: 90,
|
|
8059
|
-
brightred: 91,
|
|
8060
|
-
brightgreen: 92,
|
|
8061
|
-
brightyellow: 93,
|
|
8062
|
-
brightblue: 94,
|
|
8063
|
-
brightmagenta: 95,
|
|
8064
|
-
brightcyan: 96,
|
|
8065
|
-
brightwhite: 97
|
|
8066
|
-
};
|
|
8067
|
-
var NAMED_BG = {
|
|
8068
|
-
black: 40,
|
|
8069
|
-
red: 41,
|
|
8070
|
-
green: 42,
|
|
8071
|
-
yellow: 43,
|
|
8072
|
-
blue: 44,
|
|
8073
|
-
magenta: 45,
|
|
8074
|
-
cyan: 46,
|
|
8075
|
-
white: 47,
|
|
8076
|
-
gray: 100,
|
|
8077
|
-
grey: 100
|
|
8078
|
-
};
|
|
8079
|
-
function styleToAnsi(s) {
|
|
8080
|
-
const codes = [];
|
|
8081
|
-
if (s.bold) codes.push("1");
|
|
8082
|
-
if (s.dim) codes.push("2");
|
|
8083
|
-
if (s.italic) codes.push("3");
|
|
8084
|
-
if (s.underline) codes.push("4");
|
|
8085
|
-
if (s.inverse) codes.push("7");
|
|
8086
|
-
const fg = fgEscape(s.fg);
|
|
8087
|
-
if (fg) codes.push(fg);
|
|
8088
|
-
const bg = bgEscape(s.bg);
|
|
8089
|
-
if (bg) codes.push(bg);
|
|
8090
|
-
if (codes.length === 0) return "";
|
|
8091
|
-
return `${ESC}[${codes.join(";")}m`;
|
|
8092
|
-
}
|
|
8093
|
-
var EMPTY_STYLE = {};
|
|
8094
|
-
function frameToAnsi(f, opts = {}) {
|
|
8095
|
-
const out = [];
|
|
8096
|
-
for (let i = 0; i < f.rows.length; i++) {
|
|
8097
|
-
out.push(rowToAnsi(f.rows[i], opts));
|
|
8098
|
-
}
|
|
8099
|
-
return out.join("\n");
|
|
8100
|
-
}
|
|
8101
|
-
function rowToAnsi(row2, opts) {
|
|
8102
|
-
if (opts.plain) {
|
|
8103
|
-
let s = "";
|
|
8104
|
-
for (const c of row2) {
|
|
8105
|
-
if (c.tail) continue;
|
|
8106
|
-
s += c.char;
|
|
8107
|
-
}
|
|
8108
|
-
return s;
|
|
8109
|
-
}
|
|
8110
|
-
let result = "";
|
|
8111
|
-
let curStyle = EMPTY_STYLE;
|
|
8112
|
-
let inHref = false;
|
|
8113
|
-
let curHref;
|
|
8114
|
-
for (const c of row2) {
|
|
8115
|
-
if (c.tail) continue;
|
|
8116
|
-
const cellStyle = {
|
|
8117
|
-
fg: c.fg,
|
|
8118
|
-
bg: c.bg,
|
|
8119
|
-
bold: c.bold,
|
|
8120
|
-
dim: c.dim,
|
|
8121
|
-
italic: c.italic,
|
|
8122
|
-
underline: c.underline,
|
|
8123
|
-
inverse: c.inverse,
|
|
8124
|
-
href: c.href
|
|
7848
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7849
|
+
turn,
|
|
7850
|
+
type: "error",
|
|
7851
|
+
message,
|
|
7852
|
+
recoverable
|
|
8125
7853
|
};
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
7854
|
+
}
|
|
7855
|
+
/** Pattern-match warning text since LoopEvent doesn't carry a typed kind. */
|
|
7856
|
+
classifyWarning(ev) {
|
|
7857
|
+
const c = ev.content;
|
|
7858
|
+
if (/\bauto-escalating to\b|\barmed\b.*pro|NEEDS_PRO/.test(c)) {
|
|
7859
|
+
return {
|
|
7860
|
+
id: ++this.nextId,
|
|
7861
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7862
|
+
turn: ev.turn,
|
|
7863
|
+
type: "policy.escalated",
|
|
7864
|
+
fromModel: "",
|
|
7865
|
+
toModel: "",
|
|
7866
|
+
reason: c.includes("armed") ? "user-request" : "self-report"
|
|
7867
|
+
};
|
|
8136
7868
|
}
|
|
8137
|
-
if (
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
7869
|
+
if (/budget\b.*\$|\$\d.*\/\s*\$\d/.test(c)) {
|
|
7870
|
+
const blocked = /blocked|exceeded|refus/i.test(c);
|
|
7871
|
+
return {
|
|
7872
|
+
id: ++this.nextId,
|
|
7873
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7874
|
+
turn: ev.turn,
|
|
7875
|
+
type: blocked ? "policy.budget.blocked" : "policy.budget.warning",
|
|
7876
|
+
spentUsd: 0,
|
|
7877
|
+
capUsd: 0
|
|
7878
|
+
};
|
|
8141
7879
|
}
|
|
8142
|
-
|
|
7880
|
+
return this.errorEvent(ev.turn, c, true);
|
|
8143
7881
|
}
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
return
|
|
7882
|
+
};
|
|
7883
|
+
function looksLikeToolError(content, _toolName) {
|
|
7884
|
+
if (!content) return false;
|
|
7885
|
+
if (content.startsWith("ERROR:")) return true;
|
|
7886
|
+
if (content.startsWith("[hook block]")) return true;
|
|
7887
|
+
if (/^\{"error"\s*:/.test(content)) return true;
|
|
7888
|
+
if (/\bConfirmationError:|\bNeedsConfirmationError\b/.test(content)) return true;
|
|
7889
|
+
return false;
|
|
8147
7890
|
}
|
|
8148
7891
|
|
|
8149
7892
|
// src/server/index.ts
|
|
@@ -11444,6 +11187,14 @@ var StdinReader = class {
|
|
|
11444
11187
|
this.dispatch({ input: "", mouseClick: true, mouseRow: row2, mouseCol: col });
|
|
11445
11188
|
return;
|
|
11446
11189
|
}
|
|
11190
|
+
if (tail === "M" && btn === 32) {
|
|
11191
|
+
this.dispatch({ input: "", mouseDrag: true, mouseRow: row2, mouseCol: col });
|
|
11192
|
+
return;
|
|
11193
|
+
}
|
|
11194
|
+
if (tail === "m") {
|
|
11195
|
+
this.dispatch({ input: "", mouseRelease: true, mouseRow: row2, mouseCol: col });
|
|
11196
|
+
return;
|
|
11197
|
+
}
|
|
11447
11198
|
return;
|
|
11448
11199
|
}
|
|
11449
11200
|
}
|
|
@@ -11707,7 +11458,7 @@ var ChoiceConfirm = React5.memo(ChoiceConfirmInner);
|
|
|
11707
11458
|
// src/cli/ui/ChromeBar.tsx
|
|
11708
11459
|
import { Box as Box5, Text as Text5, useStdout as useStdout3 } from "ink";
|
|
11709
11460
|
import React7 from "react";
|
|
11710
|
-
import
|
|
11461
|
+
import stringWidth from "string-width";
|
|
11711
11462
|
|
|
11712
11463
|
// src/cli/ui/primitives.tsx
|
|
11713
11464
|
import { Text as Text4, useStdout as useStdout2 } from "ink";
|
|
@@ -11751,19 +11502,19 @@ function ChromeBar(props) {
|
|
|
11751
11502
|
const cachePct = Math.round(props.summary.cacheHitRatio * 100);
|
|
11752
11503
|
const cacheLabel = `cache ${"\u2588".repeat(CACHE_BAR_CELLS)} 100%`;
|
|
11753
11504
|
const costLabel = `$${props.summary.totalCostUsd.toFixed(4)}${props.budgetUsd && props.budgetUsd > 0 ? ` / $${props.budgetUsd.toFixed(2)}` : ""}`;
|
|
11754
|
-
const brandW =
|
|
11755
|
-
const projectW = projectName ? SEP +
|
|
11505
|
+
const brandW = stringWidth("\u25C8 reasonix");
|
|
11506
|
+
const projectW = projectName ? SEP + stringWidth(projectName) : 0;
|
|
11756
11507
|
const fixedLeft = brandW + projectW;
|
|
11757
|
-
const scrollW = scrollLabel ?
|
|
11758
|
-
const modeW = mode2 ?
|
|
11759
|
-
const proW = proPill ?
|
|
11760
|
-
const costW =
|
|
11508
|
+
const scrollW = scrollLabel ? stringWidth(scrollLabel) + GAP : 0;
|
|
11509
|
+
const modeW = mode2 ? stringWidth(`[${mode2.label}]`) + GAP : 0;
|
|
11510
|
+
const proW = proPill ? stringWidth(`[${proPill.label}]`) + GAP : 0;
|
|
11511
|
+
const costW = stringWidth(costLabel);
|
|
11761
11512
|
const fixedRight = scrollW + modeW + proW + costW;
|
|
11762
11513
|
let budget3 = cols - fixedLeft - fixedRight;
|
|
11763
|
-
const balanceOptW = balanceLabel ? GAP +
|
|
11764
|
-
const cacheOptW = GAP +
|
|
11765
|
-
const sessionOptW = props.sessionName ? SEP +
|
|
11766
|
-
const updateOptW = updateLabel ?
|
|
11514
|
+
const balanceOptW = balanceLabel ? GAP + stringWidth(balanceLabel) : 0;
|
|
11515
|
+
const cacheOptW = GAP + stringWidth(cacheLabel);
|
|
11516
|
+
const sessionOptW = props.sessionName ? SEP + stringWidth(props.sessionName) : 0;
|
|
11517
|
+
const updateOptW = updateLabel ? stringWidth(updateLabel) + GAP : 0;
|
|
11767
11518
|
const showBalance = balanceOptW > 0 && budget3 >= balanceOptW;
|
|
11768
11519
|
if (showBalance) budget3 -= balanceOptW;
|
|
11769
11520
|
const showCache = budget3 >= cacheOptW;
|
|
@@ -11827,7 +11578,7 @@ function basename(path5) {
|
|
|
11827
11578
|
// src/cli/ui/CtxFooter.tsx
|
|
11828
11579
|
import { Box as Box7, Text as Text7, useStdout as useStdout4 } from "ink";
|
|
11829
11580
|
import React9, { useMemo } from "react";
|
|
11830
|
-
import
|
|
11581
|
+
import stringWidth2 from "string-width";
|
|
11831
11582
|
|
|
11832
11583
|
// src/cli/ui/ctx-breakdown.tsx
|
|
11833
11584
|
import { Box as Box6, Text as Text6 } from "ink";
|
|
@@ -11918,21 +11669,21 @@ function CtxFooter({ loop: loop2, summary }) {
|
|
|
11918
11669
|
const totalStr = `${formatTokens(total)}/${formatTokens(data.ctxMax)}`;
|
|
11919
11670
|
const pctStr = ` \xB7 ${pct2}%`;
|
|
11920
11671
|
const warnStr = pct2 >= 80 ? " \xB7 /compact" : "";
|
|
11921
|
-
const fixedW =
|
|
11922
|
-
|
|
11672
|
+
const fixedW = stringWidth2(labelStr) + BAR_CELLS + 1 + // space after bar
|
|
11673
|
+
stringWidth2(totalStr) + stringWidth2(pctStr) + stringWidth2(warnStr);
|
|
11923
11674
|
let budget3 = cols - fixedW;
|
|
11924
11675
|
const sysSeg = ` \xB7 sys ${formatTokens(data.systemTokens)}`;
|
|
11925
11676
|
const toolsSeg = ` \xB7 tools ${formatTokens(data.toolsTokens)}`;
|
|
11926
11677
|
const logSeg = ` \xB7 log ${formatTokens(data.logTokens)}`;
|
|
11927
11678
|
const inputSeg = data.inputTokens > 0 ? ` \xB7 input ${formatTokens(data.inputTokens)}` : "";
|
|
11928
|
-
const showSys = budget3 >=
|
|
11929
|
-
if (showSys) budget3 -=
|
|
11930
|
-
const showTools = budget3 >=
|
|
11931
|
-
if (showTools) budget3 -=
|
|
11932
|
-
const showLog = budget3 >=
|
|
11933
|
-
if (showLog) budget3 -=
|
|
11934
|
-
const showInput = inputSeg !== "" && budget3 >=
|
|
11935
|
-
if (showInput) budget3 -=
|
|
11679
|
+
const showSys = budget3 >= stringWidth2(sysSeg);
|
|
11680
|
+
if (showSys) budget3 -= stringWidth2(sysSeg);
|
|
11681
|
+
const showTools = budget3 >= stringWidth2(toolsSeg);
|
|
11682
|
+
if (showTools) budget3 -= stringWidth2(toolsSeg);
|
|
11683
|
+
const showLog = budget3 >= stringWidth2(logSeg);
|
|
11684
|
+
if (showLog) budget3 -= stringWidth2(logSeg);
|
|
11685
|
+
const showInput = inputSeg !== "" && budget3 >= stringWidth2(inputSeg);
|
|
11686
|
+
if (showInput) budget3 -= stringWidth2(inputSeg);
|
|
11936
11687
|
return /* @__PURE__ */ React9.createElement(Box7, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(ChromeRule, null), /* @__PURE__ */ React9.createElement(Text7, null, /* @__PURE__ */ React9.createElement(Text7, { color: COLOR.info, dimColor: true }, labelStr), /* @__PURE__ */ React9.createElement(Bar, { ratio, color: severity, cells: BAR_CELLS }), /* @__PURE__ */ React9.createElement(Text7, null, " "), /* @__PURE__ */ React9.createElement(Text7, { color: severity, bold: true }, totalStr), /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, pctStr), showSys ? /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, sysSeg) : null, showTools ? /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, toolsSeg) : null, showLog ? /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, logSeg) : null, showInput ? /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, inputSeg) : null, warnStr ? /* @__PURE__ */ React9.createElement(Text7, { color: COLOR.err, bold: true }, warnStr) : null));
|
|
11937
11688
|
}
|
|
11938
11689
|
|
|
@@ -14548,7 +14299,7 @@ function PromptInput({
|
|
|
14548
14299
|
disabled: disabled === true
|
|
14549
14300
|
}
|
|
14550
14301
|
);
|
|
14551
|
-
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, !disabled && !narrow && value.length > 0 && !value.includes("\n") ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, !disabled && !narrow && value.length === 0 ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, "[PgUp/PgDn] scroll log \xB7 [End] jump to latest \xB7
|
|
14302
|
+
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, !disabled && !narrow && value.length > 0 && !value.includes("\n") ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, !disabled && !narrow && value.length === 0 ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, "[PgUp/PgDn] scroll log \xB7 [End] jump to latest \xB7 drag to select \xB7 auto-scrolls at edge")) : null, disabled ? /* @__PURE__ */ React24.createElement(Box21, null, /* @__PURE__ */ React24.createElement(Text20, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React24.createElement(Text20, { dimColor: true }, "[Esc] to stop")) : null);
|
|
14552
14303
|
}
|
|
14553
14304
|
function PromptLine({
|
|
14554
14305
|
line,
|
|
@@ -14921,12 +14672,10 @@ import { useEffect as useEffect3 } from "react";
|
|
|
14921
14672
|
function isInteractiveTty() {
|
|
14922
14673
|
return Boolean(process.stdout?.isTTY);
|
|
14923
14674
|
}
|
|
14924
|
-
var mouseTrackingOn = false;
|
|
14925
14675
|
function useAltScreen() {
|
|
14926
14676
|
useEffect3(() => {
|
|
14927
14677
|
if (!isInteractiveTty()) return;
|
|
14928
|
-
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?
|
|
14929
|
-
mouseTrackingOn = true;
|
|
14678
|
+
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?1002h\x1B[?1006h");
|
|
14930
14679
|
let restored = false;
|
|
14931
14680
|
const restore2 = () => {
|
|
14932
14681
|
if (restored) return;
|
|
@@ -14948,19 +14697,6 @@ function useAltScreen() {
|
|
|
14948
14697
|
return restore2;
|
|
14949
14698
|
}, []);
|
|
14950
14699
|
}
|
|
14951
|
-
function setMouseTracking(on) {
|
|
14952
|
-
if (!isInteractiveTty()) return;
|
|
14953
|
-
if (on === mouseTrackingOn) return;
|
|
14954
|
-
if (on) {
|
|
14955
|
-
process.stdout.write("\x1B[?1000h\x1B[?1006h");
|
|
14956
|
-
} else {
|
|
14957
|
-
process.stdout.write("\x1B[?1006l\x1B[?1002l\x1B[?1000l");
|
|
14958
|
-
}
|
|
14959
|
-
mouseTrackingOn = on;
|
|
14960
|
-
}
|
|
14961
|
-
function isMouseTrackingOn() {
|
|
14962
|
-
return mouseTrackingOn;
|
|
14963
|
-
}
|
|
14964
14700
|
|
|
14965
14701
|
// src/cli/ui/bang.ts
|
|
14966
14702
|
function detectBangCommand(text2) {
|
|
@@ -14974,6 +14710,28 @@ function formatBangUserMessage(cmd, output) {
|
|
|
14974
14710
|
${output}`;
|
|
14975
14711
|
}
|
|
14976
14712
|
|
|
14713
|
+
// src/cli/ui/clipboard.ts
|
|
14714
|
+
import { writeFileSync as writeFileSync12 } from "fs";
|
|
14715
|
+
import { tmpdir } from "os";
|
|
14716
|
+
import { join as join18 } from "path";
|
|
14717
|
+
var OSC_52_LIMIT = 75e3;
|
|
14718
|
+
function writeClipboard(text2) {
|
|
14719
|
+
const filePath = join18(tmpdir(), `reasonix-clip-${Date.now()}.txt`);
|
|
14720
|
+
let osc52 = false;
|
|
14721
|
+
if (text2.length <= OSC_52_LIMIT) {
|
|
14722
|
+
const b64 = Buffer.from(text2, "utf8").toString("base64");
|
|
14723
|
+
process.stdout.write(`\x1B]52;c;${b64}\x1B\\`);
|
|
14724
|
+
osc52 = true;
|
|
14725
|
+
}
|
|
14726
|
+
let writtenPath = null;
|
|
14727
|
+
try {
|
|
14728
|
+
writeFileSync12(filePath, text2, "utf8");
|
|
14729
|
+
writtenPath = filePath;
|
|
14730
|
+
} catch {
|
|
14731
|
+
}
|
|
14732
|
+
return { osc52, filePath: writtenPath, size: text2.length };
|
|
14733
|
+
}
|
|
14734
|
+
|
|
14977
14735
|
// src/cli/ui/edit-history.ts
|
|
14978
14736
|
function isEntryFullyUndone(e) {
|
|
14979
14737
|
return e.snapshots.length > 0 && e.snapshots.every((s) => e.undoneFiles.has(s.path));
|
|
@@ -15054,75 +14812,332 @@ function describeRepair(repair) {
|
|
|
15054
14812
|
return parts.length ? `[repair] ${parts.join(", ")}` : "";
|
|
15055
14813
|
}
|
|
15056
14814
|
|
|
15057
|
-
// src/cli/ui/hash-memory.ts
|
|
15058
|
-
import { appendFileSync as appendFileSync3, existsSync as existsSync18, mkdirSync as mkdirSync13, readFileSync as readFileSync20, writeFileSync as
|
|
15059
|
-
import { homedir as homedir9 } from "os";
|
|
15060
|
-
import { dirname as dirname16, join as
|
|
15061
|
-
var PROJECT_HEADER = `# Reasonix project memory
|
|
15062
|
-
|
|
15063
|
-
Notes the user pinned via the \`#\` prompt prefix. The whole file is
|
|
15064
|
-
loaded into the immutable system prefix every session \u2014 keep it terse.
|
|
15065
|
-
|
|
15066
|
-
`;
|
|
15067
|
-
var GLOBAL_HEADER = `# Reasonix global memory
|
|
15068
|
-
|
|
15069
|
-
Cross-project notes the user pinned via the \`#g\` prompt prefix. Loaded
|
|
15070
|
-
into every Reasonix session's prefix regardless of working directory.
|
|
15071
|
-
Private to this machine \u2014 not committed anywhere.
|
|
15072
|
-
|
|
15073
|
-
`;
|
|
15074
|
-
function detectHashMemory(text2) {
|
|
15075
|
-
if (text2.startsWith("\\#")) {
|
|
15076
|
-
return { kind: "escape", text: text2.slice(1) };
|
|
15077
|
-
}
|
|
15078
|
-
if (!text2.startsWith("#")) return null;
|
|
15079
|
-
if (text2.startsWith("##")) return null;
|
|
15080
|
-
if (/^#g\s*$/.test(text2)) return null;
|
|
15081
|
-
const globalMatch = /^#g\s+(.+)$/s.exec(text2);
|
|
15082
|
-
if (globalMatch) {
|
|
15083
|
-
const body2 = globalMatch[1].trim();
|
|
15084
|
-
if (!body2) return null;
|
|
15085
|
-
return { kind: "memory-global", note: body2 };
|
|
15086
|
-
}
|
|
15087
|
-
const body = text2.slice(1).trim();
|
|
15088
|
-
if (!body) return null;
|
|
15089
|
-
return { kind: "memory", note: body };
|
|
14815
|
+
// src/cli/ui/hash-memory.ts
|
|
14816
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync18, mkdirSync as mkdirSync13, readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
|
|
14817
|
+
import { homedir as homedir9 } from "os";
|
|
14818
|
+
import { dirname as dirname16, join as join19 } from "path";
|
|
14819
|
+
var PROJECT_HEADER = `# Reasonix project memory
|
|
14820
|
+
|
|
14821
|
+
Notes the user pinned via the \`#\` prompt prefix. The whole file is
|
|
14822
|
+
loaded into the immutable system prefix every session \u2014 keep it terse.
|
|
14823
|
+
|
|
14824
|
+
`;
|
|
14825
|
+
var GLOBAL_HEADER = `# Reasonix global memory
|
|
14826
|
+
|
|
14827
|
+
Cross-project notes the user pinned via the \`#g\` prompt prefix. Loaded
|
|
14828
|
+
into every Reasonix session's prefix regardless of working directory.
|
|
14829
|
+
Private to this machine \u2014 not committed anywhere.
|
|
14830
|
+
|
|
14831
|
+
`;
|
|
14832
|
+
function detectHashMemory(text2) {
|
|
14833
|
+
if (text2.startsWith("\\#")) {
|
|
14834
|
+
return { kind: "escape", text: text2.slice(1) };
|
|
14835
|
+
}
|
|
14836
|
+
if (!text2.startsWith("#")) return null;
|
|
14837
|
+
if (text2.startsWith("##")) return null;
|
|
14838
|
+
if (/^#g\s*$/.test(text2)) return null;
|
|
14839
|
+
const globalMatch = /^#g\s+(.+)$/s.exec(text2);
|
|
14840
|
+
if (globalMatch) {
|
|
14841
|
+
const body2 = globalMatch[1].trim();
|
|
14842
|
+
if (!body2) return null;
|
|
14843
|
+
return { kind: "memory-global", note: body2 };
|
|
14844
|
+
}
|
|
14845
|
+
const body = text2.slice(1).trim();
|
|
14846
|
+
if (!body) return null;
|
|
14847
|
+
return { kind: "memory", note: body };
|
|
14848
|
+
}
|
|
14849
|
+
function appendProjectMemory(rootDir, note) {
|
|
14850
|
+
return appendBulletToFile(join19(rootDir, PROJECT_MEMORY_FILE), note, PROJECT_HEADER);
|
|
14851
|
+
}
|
|
14852
|
+
var GLOBAL_MEMORY_DIR = ".reasonix";
|
|
14853
|
+
var GLOBAL_MEMORY_FILE = "REASONIX.md";
|
|
14854
|
+
function globalMemoryPath(homeDir = homedir9()) {
|
|
14855
|
+
return join19(homeDir, GLOBAL_MEMORY_DIR, GLOBAL_MEMORY_FILE);
|
|
14856
|
+
}
|
|
14857
|
+
function appendGlobalMemory(note, homeDir) {
|
|
14858
|
+
return appendBulletToFile(globalMemoryPath(homeDir), note, GLOBAL_HEADER);
|
|
14859
|
+
}
|
|
14860
|
+
function appendBulletToFile(path5, note, newFileHeader) {
|
|
14861
|
+
const trimmed = note.trim();
|
|
14862
|
+
if (!trimmed) throw new Error("note body cannot be empty");
|
|
14863
|
+
const bullet = `- ${trimmed}
|
|
14864
|
+
`;
|
|
14865
|
+
if (!existsSync18(path5)) {
|
|
14866
|
+
mkdirSync13(dirname16(path5), { recursive: true });
|
|
14867
|
+
writeFileSync13(path5, `${newFileHeader}${bullet}`, "utf8");
|
|
14868
|
+
return { path: path5, created: true };
|
|
14869
|
+
}
|
|
14870
|
+
let prefix = "";
|
|
14871
|
+
try {
|
|
14872
|
+
const existing = readFileSync20(path5, "utf8");
|
|
14873
|
+
if (existing.length > 0 && !existing.endsWith("\n")) prefix = "\n";
|
|
14874
|
+
} catch {
|
|
14875
|
+
}
|
|
14876
|
+
appendFileSync3(path5, `${prefix}${bullet}`, "utf8");
|
|
14877
|
+
return { path: path5, created: false };
|
|
14878
|
+
}
|
|
14879
|
+
|
|
14880
|
+
// src/cli/ui/log-frame.tsx
|
|
14881
|
+
import { Box as Box27, Text as Text26 } from "ink";
|
|
14882
|
+
import React30 from "react";
|
|
14883
|
+
|
|
14884
|
+
// src/frame/width.ts
|
|
14885
|
+
import stringWidthLib from "string-width";
|
|
14886
|
+
var segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
|
|
14887
|
+
function graphemes(s) {
|
|
14888
|
+
return Array.from(segmenter.segment(s), (seg) => seg.segment);
|
|
14889
|
+
}
|
|
14890
|
+
function graphemeWidth(g) {
|
|
14891
|
+
if (g.length === 0) return 0;
|
|
14892
|
+
const w = stringWidthLib(g);
|
|
14893
|
+
if (w <= 0) return 0;
|
|
14894
|
+
if (w >= 2) return 2;
|
|
14895
|
+
return 1;
|
|
14896
|
+
}
|
|
14897
|
+
|
|
14898
|
+
// src/frame/frame.ts
|
|
14899
|
+
var SPACE = { char: " ", width: 1 };
|
|
14900
|
+
var TAIL = { char: "", width: 1, tail: true };
|
|
14901
|
+
function empty(width = 0) {
|
|
14902
|
+
return { width, rows: [] };
|
|
14903
|
+
}
|
|
14904
|
+
function text(s, opts) {
|
|
14905
|
+
const { width, fg, bg, bold, dim, italic, underline, inverse, href } = opts;
|
|
14906
|
+
if (width <= 0) return empty(0);
|
|
14907
|
+
const styleOf = (g, w) => {
|
|
14908
|
+
const base = { char: g, width: w };
|
|
14909
|
+
if (fg !== void 0) base.fg = fg;
|
|
14910
|
+
if (bg !== void 0) base.bg = bg;
|
|
14911
|
+
if (bold) base.bold = true;
|
|
14912
|
+
if (dim) base.dim = true;
|
|
14913
|
+
if (italic) base.italic = true;
|
|
14914
|
+
if (underline) base.underline = true;
|
|
14915
|
+
if (inverse) base.inverse = true;
|
|
14916
|
+
if (href !== void 0) base.href = href;
|
|
14917
|
+
return base;
|
|
14918
|
+
};
|
|
14919
|
+
const rows = [];
|
|
14920
|
+
const lines = s.split("\n");
|
|
14921
|
+
for (const line of lines) {
|
|
14922
|
+
if (line.length === 0) {
|
|
14923
|
+
rows.push(padRowRight([], width));
|
|
14924
|
+
continue;
|
|
14925
|
+
}
|
|
14926
|
+
let buf = [];
|
|
14927
|
+
let bufWidth = 0;
|
|
14928
|
+
for (const g of graphemes(line)) {
|
|
14929
|
+
const w = graphemeWidth(g);
|
|
14930
|
+
if (w === 0) continue;
|
|
14931
|
+
if (bufWidth + w > width) {
|
|
14932
|
+
rows.push(padRowRight(buf, width - bufWidth));
|
|
14933
|
+
buf = [];
|
|
14934
|
+
bufWidth = 0;
|
|
14935
|
+
}
|
|
14936
|
+
buf.push(styleOf(g, w));
|
|
14937
|
+
if (w === 2) buf.push(TAIL);
|
|
14938
|
+
bufWidth += w;
|
|
14939
|
+
}
|
|
14940
|
+
rows.push(padRowRight(buf, width - bufWidth));
|
|
14941
|
+
}
|
|
14942
|
+
return { width, rows };
|
|
14943
|
+
}
|
|
14944
|
+
function padRowRight(cells, extraSpaces) {
|
|
14945
|
+
if (extraSpaces <= 0) return cells.slice();
|
|
14946
|
+
const out = cells.slice();
|
|
14947
|
+
for (let i = 0; i < extraSpaces; i++) out.push(SPACE);
|
|
14948
|
+
return out;
|
|
14949
|
+
}
|
|
14950
|
+
function spacerRow(width) {
|
|
14951
|
+
if (width <= 0) return [];
|
|
14952
|
+
return Array.from({ length: width }, () => SPACE);
|
|
14953
|
+
}
|
|
14954
|
+
function vstack(...frames) {
|
|
14955
|
+
if (frames.length === 0) return empty(0);
|
|
14956
|
+
const w = Math.max(...frames.map((f) => f.width));
|
|
14957
|
+
const rows = [];
|
|
14958
|
+
for (const f of frames) {
|
|
14959
|
+
if (f.width === w) {
|
|
14960
|
+
rows.push(...f.rows);
|
|
14961
|
+
} else {
|
|
14962
|
+
const extra = w - f.width;
|
|
14963
|
+
for (const r of f.rows) rows.push(padRowRight(r, extra));
|
|
14964
|
+
}
|
|
14965
|
+
}
|
|
14966
|
+
return { width: w, rows };
|
|
14967
|
+
}
|
|
14968
|
+
function hstack(...frames) {
|
|
14969
|
+
if (frames.length === 0) return empty(0);
|
|
14970
|
+
const h = Math.max(...frames.map((f) => f.rows.length));
|
|
14971
|
+
const w = frames.reduce((a, f) => a + f.width, 0);
|
|
14972
|
+
const rows = [];
|
|
14973
|
+
for (let i = 0; i < h; i++) {
|
|
14974
|
+
const cells = [];
|
|
14975
|
+
for (const f of frames) {
|
|
14976
|
+
const r = f.rows[i] ?? spacerRow(f.width);
|
|
14977
|
+
cells.push(...r);
|
|
14978
|
+
}
|
|
14979
|
+
rows.push(cells);
|
|
14980
|
+
}
|
|
14981
|
+
return { width: w, rows };
|
|
14982
|
+
}
|
|
14983
|
+
function pad(f, top, right, bottom2, left) {
|
|
14984
|
+
const newWidth = f.width + Math.max(0, left) + Math.max(0, right);
|
|
14985
|
+
const tPad = Math.max(0, top);
|
|
14986
|
+
const bPad = Math.max(0, bottom2);
|
|
14987
|
+
const blank2 = spacerRow(newWidth);
|
|
14988
|
+
const rows = [];
|
|
14989
|
+
for (let i = 0; i < tPad; i++) rows.push(blank2);
|
|
14990
|
+
if (left <= 0 && right <= 0) {
|
|
14991
|
+
rows.push(...f.rows);
|
|
14992
|
+
} else {
|
|
14993
|
+
const lPad = spacerRow(Math.max(0, left));
|
|
14994
|
+
const rPad = spacerRow(Math.max(0, right));
|
|
14995
|
+
for (const r of f.rows) rows.push([...lPad, ...r, ...rPad]);
|
|
14996
|
+
}
|
|
14997
|
+
for (let i = 0; i < bPad; i++) rows.push(blank2);
|
|
14998
|
+
return { width: newWidth, rows };
|
|
14999
|
+
}
|
|
15000
|
+
function borderLeft(f, color2, char = "\u2502") {
|
|
15001
|
+
const bar = { char, width: 1, fg: color2 };
|
|
15002
|
+
const newWidth = f.width + 1;
|
|
15003
|
+
const rows = [];
|
|
15004
|
+
for (const r of f.rows) rows.push([bar, ...r]);
|
|
15005
|
+
return { width: newWidth, rows };
|
|
15006
|
+
}
|
|
15007
|
+
|
|
15008
|
+
// src/frame/ansi.ts
|
|
15009
|
+
var ESC = "\x1B";
|
|
15010
|
+
var RESET = `${ESC}[0m`;
|
|
15011
|
+
function sameStyle(a, b) {
|
|
15012
|
+
return a.fg === b.fg && a.bg === b.bg && !!a.bold === !!b.bold && !!a.dim === !!b.dim && !!a.italic === !!b.italic && !!a.underline === !!b.underline && !!a.inverse === !!b.inverse && a.href === b.href;
|
|
15090
15013
|
}
|
|
15091
|
-
function
|
|
15092
|
-
|
|
15014
|
+
function fgEscape(color2) {
|
|
15015
|
+
if (!color2) return null;
|
|
15016
|
+
const rgb = parseColor(color2);
|
|
15017
|
+
if (rgb) return `38;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
15018
|
+
const named = NAMED_FG[color2.toLowerCase()];
|
|
15019
|
+
if (named !== void 0) return String(named);
|
|
15020
|
+
return null;
|
|
15093
15021
|
}
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15022
|
+
function bgEscape(color2) {
|
|
15023
|
+
if (!color2) return null;
|
|
15024
|
+
const rgb = parseColor(color2);
|
|
15025
|
+
if (rgb) return `48;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
15026
|
+
const named = NAMED_BG[color2.toLowerCase()];
|
|
15027
|
+
if (named !== void 0) return String(named);
|
|
15028
|
+
return null;
|
|
15098
15029
|
}
|
|
15099
|
-
function
|
|
15100
|
-
|
|
15030
|
+
function parseColor(s) {
|
|
15031
|
+
if (!s.startsWith("#")) return null;
|
|
15032
|
+
const hex = s.slice(1);
|
|
15033
|
+
if (hex.length !== 6) return null;
|
|
15034
|
+
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
15035
|
+
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
15036
|
+
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
15037
|
+
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
|
|
15038
|
+
return [r, g, b];
|
|
15101
15039
|
}
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15040
|
+
var NAMED_FG = {
|
|
15041
|
+
black: 30,
|
|
15042
|
+
red: 31,
|
|
15043
|
+
green: 32,
|
|
15044
|
+
yellow: 33,
|
|
15045
|
+
blue: 34,
|
|
15046
|
+
magenta: 35,
|
|
15047
|
+
cyan: 36,
|
|
15048
|
+
white: 37,
|
|
15049
|
+
gray: 90,
|
|
15050
|
+
grey: 90,
|
|
15051
|
+
brightred: 91,
|
|
15052
|
+
brightgreen: 92,
|
|
15053
|
+
brightyellow: 93,
|
|
15054
|
+
brightblue: 94,
|
|
15055
|
+
brightmagenta: 95,
|
|
15056
|
+
brightcyan: 96,
|
|
15057
|
+
brightwhite: 97
|
|
15058
|
+
};
|
|
15059
|
+
var NAMED_BG = {
|
|
15060
|
+
black: 40,
|
|
15061
|
+
red: 41,
|
|
15062
|
+
green: 42,
|
|
15063
|
+
yellow: 43,
|
|
15064
|
+
blue: 44,
|
|
15065
|
+
magenta: 45,
|
|
15066
|
+
cyan: 46,
|
|
15067
|
+
white: 47,
|
|
15068
|
+
gray: 100,
|
|
15069
|
+
grey: 100
|
|
15070
|
+
};
|
|
15071
|
+
function styleToAnsi(s) {
|
|
15072
|
+
const codes = [];
|
|
15073
|
+
if (s.bold) codes.push("1");
|
|
15074
|
+
if (s.dim) codes.push("2");
|
|
15075
|
+
if (s.italic) codes.push("3");
|
|
15076
|
+
if (s.underline) codes.push("4");
|
|
15077
|
+
if (s.inverse) codes.push("7");
|
|
15078
|
+
const fg = fgEscape(s.fg);
|
|
15079
|
+
if (fg) codes.push(fg);
|
|
15080
|
+
const bg = bgEscape(s.bg);
|
|
15081
|
+
if (bg) codes.push(bg);
|
|
15082
|
+
if (codes.length === 0) return "";
|
|
15083
|
+
return `${ESC}[${codes.join(";")}m`;
|
|
15084
|
+
}
|
|
15085
|
+
var EMPTY_STYLE = {};
|
|
15086
|
+
function frameToAnsi(f, opts = {}) {
|
|
15087
|
+
const out = [];
|
|
15088
|
+
for (let i = 0; i < f.rows.length; i++) {
|
|
15089
|
+
out.push(rowToAnsi(f.rows[i], opts));
|
|
15111
15090
|
}
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15091
|
+
return out.join("\n");
|
|
15092
|
+
}
|
|
15093
|
+
function rowToAnsi(row2, opts) {
|
|
15094
|
+
if (opts.plain) {
|
|
15095
|
+
let s = "";
|
|
15096
|
+
for (const c of row2) {
|
|
15097
|
+
if (c.tail) continue;
|
|
15098
|
+
s += c.char;
|
|
15099
|
+
}
|
|
15100
|
+
return s;
|
|
15117
15101
|
}
|
|
15118
|
-
|
|
15119
|
-
|
|
15102
|
+
let result = "";
|
|
15103
|
+
let curStyle = EMPTY_STYLE;
|
|
15104
|
+
let inHref = false;
|
|
15105
|
+
let curHref;
|
|
15106
|
+
for (const c of row2) {
|
|
15107
|
+
if (c.tail) continue;
|
|
15108
|
+
const cellStyle = {
|
|
15109
|
+
fg: c.fg,
|
|
15110
|
+
bg: c.bg,
|
|
15111
|
+
bold: c.bold,
|
|
15112
|
+
dim: c.dim,
|
|
15113
|
+
italic: c.italic,
|
|
15114
|
+
underline: c.underline,
|
|
15115
|
+
inverse: c.inverse,
|
|
15116
|
+
href: c.href
|
|
15117
|
+
};
|
|
15118
|
+
if (cellStyle.href !== curHref) {
|
|
15119
|
+
if (inHref) {
|
|
15120
|
+
result += `${ESC}]8;;${ESC}\\`;
|
|
15121
|
+
inHref = false;
|
|
15122
|
+
}
|
|
15123
|
+
if (cellStyle.href !== void 0) {
|
|
15124
|
+
result += `${ESC}]8;;${cellStyle.href}${ESC}\\`;
|
|
15125
|
+
inHref = true;
|
|
15126
|
+
}
|
|
15127
|
+
curHref = cellStyle.href;
|
|
15128
|
+
}
|
|
15129
|
+
if (!sameStyle(curStyle, cellStyle)) {
|
|
15130
|
+
result += RESET;
|
|
15131
|
+
result += styleToAnsi(cellStyle);
|
|
15132
|
+
curStyle = cellStyle;
|
|
15133
|
+
}
|
|
15134
|
+
result += c.char;
|
|
15135
|
+
}
|
|
15136
|
+
if (inHref) result += `${ESC}]8;;${ESC}\\`;
|
|
15137
|
+
result += RESET;
|
|
15138
|
+
return result;
|
|
15120
15139
|
}
|
|
15121
15140
|
|
|
15122
|
-
// src/cli/ui/log-frame.tsx
|
|
15123
|
-
import { Box as Box27, Text as Text26 } from "ink";
|
|
15124
|
-
import React30 from "react";
|
|
15125
|
-
|
|
15126
15141
|
// src/cli/ui/markdown-frame.ts
|
|
15127
15142
|
var INLINE_RE2 = /(\[([^\]\n]+)\]\(([^)\n]+)\)|\*\*\*([^*\n]+?)\*\*\*|\*\*([^*\n]+?)\*\*|```([^\n]+?)```|`([^`\n]+?)`|~~([^~\n]+?)~~|(?<![*\w])\*([^*\n]+?)\*(?!\w)|\\([*_~`[\](){}#+\-.!\\]))/g;
|
|
15128
15143
|
function parseInline(input, baseOpts) {
|
|
@@ -15942,7 +15957,14 @@ function estimatedHeight(e) {
|
|
|
15942
15957
|
}
|
|
15943
15958
|
function viewportLog(atoms, scrollOffset, available) {
|
|
15944
15959
|
if (atoms.length === 0 || available <= 0) {
|
|
15945
|
-
return {
|
|
15960
|
+
return {
|
|
15961
|
+
atoms: [],
|
|
15962
|
+
topSkip: 0,
|
|
15963
|
+
bottomSkip: 0,
|
|
15964
|
+
totalRows: 0,
|
|
15965
|
+
maxScrollRows: 0,
|
|
15966
|
+
firstRowAbs: 0
|
|
15967
|
+
};
|
|
15946
15968
|
}
|
|
15947
15969
|
const heights = atoms.map(atomRows);
|
|
15948
15970
|
const totalRows = heights.reduce((a, b) => a + b, 0);
|
|
@@ -15974,7 +15996,8 @@ function viewportLog(atoms, scrollOffset, available) {
|
|
|
15974
15996
|
topSkip: 0,
|
|
15975
15997
|
bottomSkip: 0,
|
|
15976
15998
|
totalRows,
|
|
15977
|
-
maxScrollRows
|
|
15999
|
+
maxScrollRows,
|
|
16000
|
+
firstRowAbs: Math.max(0, totalRows - heights[atoms.length - 1])
|
|
15978
16001
|
};
|
|
15979
16002
|
}
|
|
15980
16003
|
const sliced = atoms.slice(firstIdx, lastIdx + 1);
|
|
@@ -15988,19 +16011,95 @@ function viewportLog(atoms, scrollOffset, available) {
|
|
|
15988
16011
|
if (lastAtom.kind === "frame") {
|
|
15989
16012
|
bottomSkip = Math.max(0, lastEnd - viewportBottom);
|
|
15990
16013
|
}
|
|
15991
|
-
return {
|
|
16014
|
+
return {
|
|
16015
|
+
atoms: sliced,
|
|
16016
|
+
topSkip,
|
|
16017
|
+
bottomSkip,
|
|
16018
|
+
totalRows,
|
|
16019
|
+
maxScrollRows,
|
|
16020
|
+
firstRowAbs: firstStart + topSkip
|
|
16021
|
+
};
|
|
16022
|
+
}
|
|
16023
|
+
function highlightRow(row2, fromCol, toCol) {
|
|
16024
|
+
if (fromCol >= toCol) return row2;
|
|
16025
|
+
const out = [];
|
|
16026
|
+
let col = 0;
|
|
16027
|
+
for (const cell of row2) {
|
|
16028
|
+
const cellEnd = col + (cell.tail ? 0 : cell.width);
|
|
16029
|
+
const inRange = col < toCol && cellEnd > fromCol;
|
|
16030
|
+
out.push(inRange ? { ...cell, inverse: true } : cell);
|
|
16031
|
+
col = cellEnd;
|
|
16032
|
+
}
|
|
16033
|
+
return out;
|
|
15992
16034
|
}
|
|
15993
|
-
function
|
|
16035
|
+
function rowSelectionRange(sel, absRow, rowWidth) {
|
|
16036
|
+
if (sel.startRow === sel.endRow) {
|
|
16037
|
+
if (absRow !== sel.startRow) return null;
|
|
16038
|
+
return { from: Math.min(sel.startCol, sel.endCol), to: Math.max(sel.startCol, sel.endCol) };
|
|
16039
|
+
}
|
|
16040
|
+
const topRow = sel.startRow < sel.endRow ? sel.startRow : sel.endRow;
|
|
16041
|
+
const topCol = sel.startRow < sel.endRow ? sel.startCol : sel.endCol;
|
|
16042
|
+
const botRow = sel.startRow < sel.endRow ? sel.endRow : sel.startRow;
|
|
16043
|
+
const botCol = sel.startRow < sel.endRow ? sel.endCol : sel.startCol;
|
|
16044
|
+
if (absRow < topRow || absRow > botRow) return null;
|
|
16045
|
+
if (absRow === topRow) return { from: topCol, to: rowWidth };
|
|
16046
|
+
if (absRow === botRow) return { from: 0, to: botCol };
|
|
16047
|
+
return { from: 0, to: rowWidth };
|
|
16048
|
+
}
|
|
16049
|
+
function renderViewport(v, selection) {
|
|
16050
|
+
let absRow = v.firstRowAbs;
|
|
15994
16051
|
return /* @__PURE__ */ React30.createElement(React30.Fragment, null, v.atoms.map((atom, i) => {
|
|
15995
16052
|
if (atom.kind === "ink") {
|
|
16053
|
+
absRow += atom.rows;
|
|
15996
16054
|
return /* @__PURE__ */ React30.createElement(React30.Fragment, { key: atom.id }, atom.element);
|
|
15997
16055
|
}
|
|
15998
16056
|
const start = i === 0 ? v.topSkip : 0;
|
|
15999
16057
|
const end = i === v.atoms.length - 1 ? atom.frame.rows.length - v.bottomSkip : atom.frame.rows.length;
|
|
16000
16058
|
const rows = atom.frame.rows.slice(start, end);
|
|
16001
|
-
|
|
16059
|
+
const node = /* @__PURE__ */ React30.createElement(React30.Fragment, { key: atom.id }, rows.map((row2, ri) => {
|
|
16060
|
+
const rowAbs = absRow + ri;
|
|
16061
|
+
const range = selection ? rowSelectionRange(selection, rowAbs, atom.frame.width) : null;
|
|
16062
|
+
const painted = range ? highlightRow(row2, range.from, range.to) : row2;
|
|
16063
|
+
return /* @__PURE__ */ React30.createElement(Box27, { key: `${atom.id}/${start + ri}`, height: 1, flexShrink: 0 }, /* @__PURE__ */ React30.createElement(Text26, null, frameToAnsi({ width: atom.frame.width, rows: [painted] })));
|
|
16064
|
+
}));
|
|
16065
|
+
absRow += atom.frame.rows.length - (i === 0 ? v.topSkip : 0) - (i === v.atoms.length - 1 ? v.bottomSkip : 0);
|
|
16066
|
+
return node;
|
|
16002
16067
|
}));
|
|
16003
16068
|
}
|
|
16069
|
+
function extractSelection(atoms, selection) {
|
|
16070
|
+
const lines = [];
|
|
16071
|
+
let cursor = 0;
|
|
16072
|
+
for (const atom of atoms) {
|
|
16073
|
+
const atomStart = cursor;
|
|
16074
|
+
const atomEnd = cursor + atomRows(atom);
|
|
16075
|
+
cursor = atomEnd;
|
|
16076
|
+
const top = Math.min(selection.startRow, selection.endRow);
|
|
16077
|
+
const bot = Math.max(selection.startRow, selection.endRow);
|
|
16078
|
+
if (atomEnd <= top || atomStart > bot) continue;
|
|
16079
|
+
if (atom.kind === "ink") {
|
|
16080
|
+
lines.push("(non-text block)");
|
|
16081
|
+
continue;
|
|
16082
|
+
}
|
|
16083
|
+
const w = atom.frame.width;
|
|
16084
|
+
for (let r = 0; r < atom.frame.rows.length; r++) {
|
|
16085
|
+
const absRow = atomStart + r;
|
|
16086
|
+
const range = rowSelectionRange(selection, absRow, w);
|
|
16087
|
+
if (!range) continue;
|
|
16088
|
+
lines.push(rowSliceText(atom.frame.rows[r], range.from, range.to));
|
|
16089
|
+
}
|
|
16090
|
+
}
|
|
16091
|
+
return lines.join("\n").replace(/[ \t]+$/gm, "");
|
|
16092
|
+
}
|
|
16093
|
+
function rowSliceText(row2, fromCol, toCol) {
|
|
16094
|
+
let col = 0;
|
|
16095
|
+
let out = "";
|
|
16096
|
+
for (const cell of row2) {
|
|
16097
|
+
const cellEnd = col + (cell.tail ? 0 : cell.width);
|
|
16098
|
+
if (col >= fromCol && cellEnd <= toCol && !cell.tail) out += cell.char;
|
|
16099
|
+
col = cellEnd;
|
|
16100
|
+
}
|
|
16101
|
+
return out;
|
|
16102
|
+
}
|
|
16004
16103
|
function eventsToAtoms(events, projectRoot, width) {
|
|
16005
16104
|
const out = [];
|
|
16006
16105
|
for (const e of events) out.push(eventToAtom(e, projectRoot, width));
|
|
@@ -16446,10 +16545,6 @@ var SLASH_COMMANDS = [
|
|
|
16446
16545
|
cmd: "stats",
|
|
16447
16546
|
summary: "cross-session cost dashboard (today / week / month / all-time \xB7 cache hit \xB7 vs Claude)"
|
|
16448
16547
|
},
|
|
16449
|
-
{
|
|
16450
|
-
cmd: "copy",
|
|
16451
|
-
summary: "freeze + dump the rendered log to main screen so terminal scrollback + drag-select can copy across viewports \xB7 any key returns"
|
|
16452
|
-
},
|
|
16453
16548
|
{ cmd: "think", summary: "dump the last turn's full R1 reasoning (reasoner only)" },
|
|
16454
16549
|
{
|
|
16455
16550
|
cmd: "context",
|
|
@@ -16900,20 +16995,12 @@ var cwd = (args, _loop, ctx) => {
|
|
|
16900
16995
|
}
|
|
16901
16996
|
return { info: lines.join("\n") };
|
|
16902
16997
|
};
|
|
16903
|
-
var copy = (_args, _loop, ctx) => {
|
|
16904
|
-
if (!ctx.enterCopyMode) {
|
|
16905
|
-
return { info: "/copy is not available in this context (TUI-internal)." };
|
|
16906
|
-
}
|
|
16907
|
-
ctx.enterCopyMode();
|
|
16908
|
-
return {};
|
|
16909
|
-
};
|
|
16910
16998
|
var handlers = {
|
|
16911
16999
|
hook: hooks,
|
|
16912
17000
|
hooks,
|
|
16913
17001
|
cwd,
|
|
16914
17002
|
update,
|
|
16915
|
-
stats
|
|
16916
|
-
copy
|
|
17003
|
+
stats
|
|
16917
17004
|
};
|
|
16918
17005
|
|
|
16919
17006
|
// src/cli/ui/slash/handlers/basic.ts
|
|
@@ -17162,20 +17249,20 @@ var dashboard2 = (args, _loop, ctx) => {
|
|
|
17162
17249
|
var handlers3 = { dashboard: dashboard2 };
|
|
17163
17250
|
|
|
17164
17251
|
// src/code/checkpoints.ts
|
|
17165
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync14, readFileSync as readFileSync22, rmSync as rmSync2, writeFileSync as
|
|
17252
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync14, readFileSync as readFileSync22, rmSync as rmSync2, writeFileSync as writeFileSync14 } from "fs";
|
|
17166
17253
|
import { homedir as homedir10 } from "os";
|
|
17167
|
-
import { dirname as dirname17, join as
|
|
17254
|
+
import { dirname as dirname17, join as join21, relative as relative3, resolve as resolve10, sep as sep3 } from "path";
|
|
17168
17255
|
function sanitizeRoot(rootDir) {
|
|
17169
17256
|
return resolve10(rootDir).replace(/[\\/:]+/g, "_").replace(/^_+/, "");
|
|
17170
17257
|
}
|
|
17171
17258
|
function storeRoot(rootDir) {
|
|
17172
|
-
return
|
|
17259
|
+
return join21(homedir10(), ".reasonix", "sessions", sanitizeRoot(rootDir), "checkpoints");
|
|
17173
17260
|
}
|
|
17174
17261
|
function indexPath(rootDir) {
|
|
17175
|
-
return
|
|
17262
|
+
return join21(storeRoot(rootDir), "index.json");
|
|
17176
17263
|
}
|
|
17177
17264
|
function snapshotPath(rootDir, id) {
|
|
17178
|
-
return
|
|
17265
|
+
return join21(storeRoot(rootDir), `${id}.json`);
|
|
17179
17266
|
}
|
|
17180
17267
|
function listCheckpoints(rootDir) {
|
|
17181
17268
|
const path5 = indexPath(rootDir);
|
|
@@ -17194,7 +17281,7 @@ function listCheckpoints(rootDir) {
|
|
|
17194
17281
|
function writeIndex(rootDir, items) {
|
|
17195
17282
|
const path5 = indexPath(rootDir);
|
|
17196
17283
|
mkdirSync14(dirname17(path5), { recursive: true });
|
|
17197
|
-
|
|
17284
|
+
writeFileSync14(path5, JSON.stringify(items, null, 2), "utf8");
|
|
17198
17285
|
}
|
|
17199
17286
|
function loadCheckpoint(rootDir, id) {
|
|
17200
17287
|
const path5 = snapshotPath(rootDir, id);
|
|
@@ -17245,7 +17332,7 @@ function createCheckpoint(opts) {
|
|
|
17245
17332
|
};
|
|
17246
17333
|
const cpPath = snapshotPath(absRoot, id);
|
|
17247
17334
|
mkdirSync14(dirname17(cpPath), { recursive: true });
|
|
17248
|
-
|
|
17335
|
+
writeFileSync14(cpPath, JSON.stringify(checkpoint2), "utf8");
|
|
17249
17336
|
const meta = {
|
|
17250
17337
|
id,
|
|
17251
17338
|
name: opts.name,
|
|
@@ -17288,7 +17375,7 @@ function restoreCheckpoint(rootDir, id) {
|
|
|
17288
17375
|
}
|
|
17289
17376
|
} else {
|
|
17290
17377
|
mkdirSync14(dirname17(abs), { recursive: true });
|
|
17291
|
-
|
|
17378
|
+
writeFileSync14(abs, f.content, "utf8");
|
|
17292
17379
|
result.restored.push(f.path);
|
|
17293
17380
|
}
|
|
17294
17381
|
} catch (err) {
|
|
@@ -19518,8 +19605,13 @@ function App({
|
|
|
19518
19605
|
useAltScreen();
|
|
19519
19606
|
const [historical, setHistorical] = useState11([]);
|
|
19520
19607
|
const [streaming, setStreaming] = useState11(null);
|
|
19521
|
-
const [copyMode, setCopyMode] = useState11(false);
|
|
19522
19608
|
const [ctxFooterVisible, setCtxFooterVisible] = useState11(true);
|
|
19609
|
+
const [logSelection, setLogSelection] = useState11(null);
|
|
19610
|
+
const dragAnchorRef = useRef6(null);
|
|
19611
|
+
const autoScrollTimerRef = useRef6(null);
|
|
19612
|
+
const autoScrollDirRef = useRef6(0);
|
|
19613
|
+
const lastDragColRef = useRef6(0);
|
|
19614
|
+
const logGeomRef = useRef6({ contentTopRow: 1, contentBottomRow: 1, firstRowAbs: 0, visibleRows: 0, cols: 80 });
|
|
19523
19615
|
const [logScrollOffset, setLogScrollOffset] = useState11(0);
|
|
19524
19616
|
const scrollAnimRef = useRef6(null);
|
|
19525
19617
|
const scrollTargetRef = useRef6(0);
|
|
@@ -19881,49 +19973,6 @@ function App({
|
|
|
19881
19973
|
useEffect7(() => {
|
|
19882
19974
|
currentRootDirRef.current = currentRootDir;
|
|
19883
19975
|
}, [currentRootDir]);
|
|
19884
|
-
useEffect7(() => {
|
|
19885
|
-
if (!copyMode) return;
|
|
19886
|
-
const cols = (process.stdout?.columns ?? 80) - 2;
|
|
19887
|
-
const atoms = eventsToAtoms(historicalRef.current, currentRootDirRef.current, cols);
|
|
19888
|
-
const lines = [];
|
|
19889
|
-
for (const atom of atoms) {
|
|
19890
|
-
if (atom.kind === "frame") {
|
|
19891
|
-
const ansi = frameToAnsi(atom.frame);
|
|
19892
|
-
if (ansi) lines.push(ansi);
|
|
19893
|
-
} else {
|
|
19894
|
-
lines.push(`(${atom.id ?? "ink-block"} omitted from copy dump)`);
|
|
19895
|
-
}
|
|
19896
|
-
}
|
|
19897
|
-
const wasMouseOn = isMouseTrackingOn();
|
|
19898
|
-
setMouseTracking(false);
|
|
19899
|
-
process.stdout.write("\x1B[?1049l");
|
|
19900
|
-
process.stdout.write("\n=== reasonix \xB7 copy mode \u2014 terminal scrollback active ===\n\n");
|
|
19901
|
-
process.stdout.write(lines.join("\n"));
|
|
19902
|
-
process.stdout.write("\n\n=== end of dump \xB7 press any key to return to reasonix ===\n");
|
|
19903
|
-
const reader = getStdinReader();
|
|
19904
|
-
let exited = false;
|
|
19905
|
-
const restore2 = () => {
|
|
19906
|
-
if (exited) return;
|
|
19907
|
-
exited = true;
|
|
19908
|
-
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
|
|
19909
|
-
if (wasMouseOn) setMouseTracking(true);
|
|
19910
|
-
setCopyMode(false);
|
|
19911
|
-
};
|
|
19912
|
-
const unsub = reader.subscribe(() => {
|
|
19913
|
-
unsub();
|
|
19914
|
-
restore2();
|
|
19915
|
-
});
|
|
19916
|
-
return () => {
|
|
19917
|
-
unsub();
|
|
19918
|
-
if (!exited) {
|
|
19919
|
-
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
|
|
19920
|
-
if (wasMouseOn) setMouseTracking(true);
|
|
19921
|
-
}
|
|
19922
|
-
};
|
|
19923
|
-
}, [copyMode]);
|
|
19924
|
-
const enterCopyMode = useCallback4(() => {
|
|
19925
|
-
setCopyMode(true);
|
|
19926
|
-
}, []);
|
|
19927
19976
|
const toggleCtxFooter = useCallback4(
|
|
19928
19977
|
(force) => {
|
|
19929
19978
|
let next = false;
|
|
@@ -20183,6 +20232,76 @@ function App({
|
|
|
20183
20232
|
transcriptRef.current?.end();
|
|
20184
20233
|
process.exit(0);
|
|
20185
20234
|
}, []);
|
|
20235
|
+
const stopAutoScroll = useCallback4(() => {
|
|
20236
|
+
if (autoScrollTimerRef.current) {
|
|
20237
|
+
clearInterval(autoScrollTimerRef.current);
|
|
20238
|
+
autoScrollTimerRef.current = null;
|
|
20239
|
+
}
|
|
20240
|
+
autoScrollDirRef.current = 0;
|
|
20241
|
+
}, []);
|
|
20242
|
+
const mouseToAbsRow = useCallback4((mouseRow) => {
|
|
20243
|
+
const { contentTopRow, contentBottomRow, firstRowAbs, visibleRows } = logGeomRef.current;
|
|
20244
|
+
if (visibleRows <= 0) return null;
|
|
20245
|
+
const clamped = Math.max(contentTopRow, Math.min(contentBottomRow, mouseRow));
|
|
20246
|
+
return firstRowAbs + (clamped - contentTopRow);
|
|
20247
|
+
}, []);
|
|
20248
|
+
const startAutoScroll = useCallback4(
|
|
20249
|
+
(dir) => {
|
|
20250
|
+
if (autoScrollDirRef.current === dir) return;
|
|
20251
|
+
stopAutoScroll();
|
|
20252
|
+
autoScrollDirRef.current = dir;
|
|
20253
|
+
autoScrollTimerRef.current = setInterval(() => {
|
|
20254
|
+
const max = scrollMaxRowsRef.current;
|
|
20255
|
+
const cur = scrollTargetRef.current;
|
|
20256
|
+
const next = dir > 0 ? Math.max(0, cur - 1) : Math.min(max, cur + 1);
|
|
20257
|
+
if (next === cur) return;
|
|
20258
|
+
scrollTargetRef.current = next;
|
|
20259
|
+
scrollDisplayedRef.current = next;
|
|
20260
|
+
setLogScrollOffset(next);
|
|
20261
|
+
const anchor = dragAnchorRef.current;
|
|
20262
|
+
if (anchor) {
|
|
20263
|
+
const { firstRowAbs, visibleRows } = logGeomRef.current;
|
|
20264
|
+
const focusRow = dir > 0 ? firstRowAbs + visibleRows - 1 : firstRowAbs;
|
|
20265
|
+
setLogSelection({
|
|
20266
|
+
startRow: anchor.row,
|
|
20267
|
+
startCol: anchor.col,
|
|
20268
|
+
endRow: focusRow,
|
|
20269
|
+
endCol: lastDragColRef.current
|
|
20270
|
+
});
|
|
20271
|
+
}
|
|
20272
|
+
}, 60);
|
|
20273
|
+
},
|
|
20274
|
+
[stopAutoScroll]
|
|
20275
|
+
);
|
|
20276
|
+
const finishSelection = useCallback4(() => {
|
|
20277
|
+
stopAutoScroll();
|
|
20278
|
+
const sel = logSelection;
|
|
20279
|
+
dragAnchorRef.current = null;
|
|
20280
|
+
if (!sel) return;
|
|
20281
|
+
if (sel.startRow === sel.endRow && sel.startCol === sel.endCol) {
|
|
20282
|
+
setLogSelection(null);
|
|
20283
|
+
return;
|
|
20284
|
+
}
|
|
20285
|
+
const cols = stdout4?.columns ?? 80;
|
|
20286
|
+
const atoms = eventsToAtoms(historical, currentRootDir, cols);
|
|
20287
|
+
const text2 = extractSelection(atoms, sel);
|
|
20288
|
+
if (!text2.trim()) {
|
|
20289
|
+
setLogSelection(null);
|
|
20290
|
+
return;
|
|
20291
|
+
}
|
|
20292
|
+
const result = writeClipboard(text2);
|
|
20293
|
+
const noun = result.osc52 ? "copied" : "saved";
|
|
20294
|
+
const fileNote = result.filePath ? ` \xB7 ${result.filePath}` : "";
|
|
20295
|
+
setHistorical((prev) => [
|
|
20296
|
+
...prev,
|
|
20297
|
+
{
|
|
20298
|
+
id: `clip-${Date.now()}`,
|
|
20299
|
+
role: "info",
|
|
20300
|
+
text: `\u25B8 ${noun} ${result.size} char${result.size === 1 ? "" : "s"}${fileNote}`
|
|
20301
|
+
}
|
|
20302
|
+
]);
|
|
20303
|
+
setLogSelection(null);
|
|
20304
|
+
}, [historical, logSelection, stdout4?.columns, currentRootDir, stopAutoScroll]);
|
|
20186
20305
|
useEffect7(() => {
|
|
20187
20306
|
process.on("SIGINT", quitProcess);
|
|
20188
20307
|
return () => {
|
|
@@ -20207,6 +20326,48 @@ function App({
|
|
|
20207
20326
|
animateScrollTo((prev) => Math.max(0, prev - 3));
|
|
20208
20327
|
return;
|
|
20209
20328
|
}
|
|
20329
|
+
if (ev.mouseClick && ev.mouseRow !== void 0 && ev.mouseCol !== void 0) {
|
|
20330
|
+
const { contentTopRow, contentBottomRow } = logGeomRef.current;
|
|
20331
|
+
if (ev.mouseRow < contentTopRow || ev.mouseRow > contentBottomRow) {
|
|
20332
|
+
if (logSelection) setLogSelection(null);
|
|
20333
|
+
dragAnchorRef.current = null;
|
|
20334
|
+
return;
|
|
20335
|
+
}
|
|
20336
|
+
const absRow = mouseToAbsRow(ev.mouseRow);
|
|
20337
|
+
if (absRow === null) return;
|
|
20338
|
+
const col = Math.max(0, ev.mouseCol - 1);
|
|
20339
|
+
dragAnchorRef.current = { row: absRow, col };
|
|
20340
|
+
lastDragColRef.current = col;
|
|
20341
|
+
setLogSelection({ startRow: absRow, startCol: col, endRow: absRow, endCol: col });
|
|
20342
|
+
return;
|
|
20343
|
+
}
|
|
20344
|
+
if (ev.mouseDrag && ev.mouseRow !== void 0 && ev.mouseCol !== void 0) {
|
|
20345
|
+
const anchor = dragAnchorRef.current;
|
|
20346
|
+
if (!anchor) return;
|
|
20347
|
+
const { contentTopRow, contentBottomRow } = logGeomRef.current;
|
|
20348
|
+
const col = Math.max(0, ev.mouseCol - 1);
|
|
20349
|
+
lastDragColRef.current = col;
|
|
20350
|
+
if (ev.mouseRow <= contentTopRow) {
|
|
20351
|
+
startAutoScroll(-1);
|
|
20352
|
+
} else if (ev.mouseRow >= contentBottomRow) {
|
|
20353
|
+
startAutoScroll(1);
|
|
20354
|
+
} else {
|
|
20355
|
+
stopAutoScroll();
|
|
20356
|
+
}
|
|
20357
|
+
const absRow = mouseToAbsRow(ev.mouseRow);
|
|
20358
|
+
if (absRow === null) return;
|
|
20359
|
+
setLogSelection({
|
|
20360
|
+
startRow: anchor.row,
|
|
20361
|
+
startCol: anchor.col,
|
|
20362
|
+
endRow: absRow,
|
|
20363
|
+
endCol: col
|
|
20364
|
+
});
|
|
20365
|
+
return;
|
|
20366
|
+
}
|
|
20367
|
+
if (ev.mouseRelease) {
|
|
20368
|
+
finishSelection();
|
|
20369
|
+
return;
|
|
20370
|
+
}
|
|
20210
20371
|
if (ev.pageUp) {
|
|
20211
20372
|
if (maxOffset === 0) return;
|
|
20212
20373
|
animateScrollTo((prev) => Math.min(maxOffset, prev + (viewportRows - 2)));
|
|
@@ -21029,7 +21190,6 @@ function App({
|
|
|
21029
21190
|
return fresh.length;
|
|
21030
21191
|
},
|
|
21031
21192
|
setCwd: (newRoot) => applyCwdChange(newRoot),
|
|
21032
|
-
enterCopyMode,
|
|
21033
21193
|
toggleCtxFooter,
|
|
21034
21194
|
latestVersion,
|
|
21035
21195
|
refreshLatestVersion,
|
|
@@ -21677,7 +21837,6 @@ function App({
|
|
|
21677
21837
|
broadcastDashboardEvent,
|
|
21678
21838
|
applyCwdChange,
|
|
21679
21839
|
touchedPaths,
|
|
21680
|
-
enterCopyMode,
|
|
21681
21840
|
toggleCtxFooter,
|
|
21682
21841
|
model2,
|
|
21683
21842
|
prefixHash
|
|
@@ -22191,7 +22350,6 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
22191
22350
|
async (choice) => handleReviseConfirmRef.current(choice),
|
|
22192
22351
|
[]
|
|
22193
22352
|
);
|
|
22194
|
-
if (copyMode) return null;
|
|
22195
22353
|
return /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement(
|
|
22196
22354
|
TickerProvider,
|
|
22197
22355
|
{
|
|
@@ -22253,7 +22411,21 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
22253
22411
|
const v = viewportLog(atoms, logScrollOffset, available);
|
|
22254
22412
|
scrollMaxRowsRef.current = v.maxScrollRows;
|
|
22255
22413
|
lastTotalRowsRef.current = v.totalRows;
|
|
22256
|
-
|
|
22414
|
+
const logTopRow = 3;
|
|
22415
|
+
const logBottomRow = logTopRow + logHeight - 1;
|
|
22416
|
+
const isScrolled = logScrollOffset > 0;
|
|
22417
|
+
const contentBoxBottom = logBottomRow - (isScrolled ? 1 : 0);
|
|
22418
|
+
const renderedRows = Math.min(available, v.totalRows);
|
|
22419
|
+
const contentTopRow = isScrolled ? logTopRow : Math.max(logTopRow, contentBoxBottom - renderedRows + 1);
|
|
22420
|
+
const contentBottomRow = isScrolled ? logTopRow + renderedRows - 1 : contentBoxBottom;
|
|
22421
|
+
logGeomRef.current = {
|
|
22422
|
+
contentTopRow,
|
|
22423
|
+
contentBottomRow,
|
|
22424
|
+
firstRowAbs: v.firstRowAbs,
|
|
22425
|
+
visibleRows: renderedRows,
|
|
22426
|
+
cols
|
|
22427
|
+
};
|
|
22428
|
+
return renderViewport(v, logSelection);
|
|
22257
22429
|
})(),
|
|
22258
22430
|
!historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React32.createElement(WelcomeBanner, { inCodeMode: !!codeMode, dashboardUrl }) : null,
|
|
22259
22431
|
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React32.createElement(Box29, { marginY: 1 }, /* @__PURE__ */ React32.createElement(EventRow, { event: streaming, projectRoot: currentRootDir })) : null,
|
|
@@ -22669,7 +22841,7 @@ async function chatCommand(opts) {
|
|
|
22669
22841
|
// src/cli/commands/code.tsx
|
|
22670
22842
|
import { basename as basename3, resolve as resolve12 } from "path";
|
|
22671
22843
|
async function codeCommand(opts = {}) {
|
|
22672
|
-
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-
|
|
22844
|
+
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-MAHJTS7Q.js");
|
|
22673
22845
|
const rootDir = resolve12(opts.dir ?? process.cwd());
|
|
22674
22846
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename3(rootDir))}`;
|
|
22675
22847
|
const tools = new ToolRegistry();
|
|
@@ -22720,9 +22892,9 @@ async function codeCommand(opts = {}) {
|
|
|
22720
22892
|
|
|
22721
22893
|
// src/cli/commands/commit.ts
|
|
22722
22894
|
import { spawn as spawn6, spawnSync as spawnSync3 } from "child_process";
|
|
22723
|
-
import { mkdtempSync, readFileSync as readFileSync23, unlinkSync as unlinkSync6, writeFileSync as
|
|
22724
|
-
import { tmpdir } from "os";
|
|
22725
|
-
import { join as
|
|
22895
|
+
import { mkdtempSync, readFileSync as readFileSync23, unlinkSync as unlinkSync6, writeFileSync as writeFileSync15 } from "fs";
|
|
22896
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
22897
|
+
import { join as join24 } from "path";
|
|
22726
22898
|
import { stdin as stdin2, stdout } from "process";
|
|
22727
22899
|
import { createInterface } from "readline/promises";
|
|
22728
22900
|
var DEFAULT_MODEL = "deepseek-v4-flash";
|
|
@@ -22865,9 +23037,9 @@ function editInExternal(initial) {
|
|
|
22865
23037
|
);
|
|
22866
23038
|
return null;
|
|
22867
23039
|
}
|
|
22868
|
-
const dir = mkdtempSync(
|
|
22869
|
-
const path5 =
|
|
22870
|
-
|
|
23040
|
+
const dir = mkdtempSync(join24(tmpdir2(), "reasonix-commit-"));
|
|
23041
|
+
const path5 = join24(dir, "COMMIT_EDITMSG");
|
|
23042
|
+
writeFileSync15(path5, initial, "utf8");
|
|
22871
23043
|
const result = spawnSync3(`${editor} "${path5}"`, {
|
|
22872
23044
|
stdio: "inherit",
|
|
22873
23045
|
shell: true
|
|
@@ -22993,7 +23165,7 @@ async function commitCommand(opts = {}) {
|
|
|
22993
23165
|
}
|
|
22994
23166
|
|
|
22995
23167
|
// src/cli/commands/diff.ts
|
|
22996
|
-
import { writeFileSync as
|
|
23168
|
+
import { writeFileSync as writeFileSync16 } from "fs";
|
|
22997
23169
|
import { basename as basename4 } from "path";
|
|
22998
23170
|
import { render as render2 } from "ink";
|
|
22999
23171
|
import React38 from "react";
|
|
@@ -23140,7 +23312,7 @@ async function diffCommand(opts) {
|
|
|
23140
23312
|
if (wantMarkdown) {
|
|
23141
23313
|
console.log(renderSummaryTable(report));
|
|
23142
23314
|
const md = renderMarkdown(report);
|
|
23143
|
-
|
|
23315
|
+
writeFileSync16(opts.mdPath, md, "utf8");
|
|
23144
23316
|
console.log(`
|
|
23145
23317
|
markdown report written to ${opts.mdPath}`);
|
|
23146
23318
|
return;
|
|
@@ -23159,7 +23331,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
23159
23331
|
// src/cli/commands/doctor.ts
|
|
23160
23332
|
import { existsSync as existsSync24, statSync as statSync14 } from "fs";
|
|
23161
23333
|
import { homedir as homedir11 } from "os";
|
|
23162
|
-
import { dirname as dirname18, join as
|
|
23334
|
+
import { dirname as dirname18, join as join25, resolve as resolve13 } from "path";
|
|
23163
23335
|
var TTY = process.stdout.isTTY && process.env.TERM !== "dumb";
|
|
23164
23336
|
function color(text2, code) {
|
|
23165
23337
|
if (!TTY) return text2;
|
|
@@ -23282,7 +23454,7 @@ async function checkApiReach() {
|
|
|
23282
23454
|
}
|
|
23283
23455
|
async function checkTokenizer() {
|
|
23284
23456
|
const candidates = [
|
|
23285
|
-
|
|
23457
|
+
join25(
|
|
23286
23458
|
dirname18(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1")),
|
|
23287
23459
|
"..",
|
|
23288
23460
|
"..",
|
|
@@ -23290,7 +23462,7 @@ async function checkTokenizer() {
|
|
|
23290
23462
|
"data",
|
|
23291
23463
|
"deepseek-tokenizer.json.gz"
|
|
23292
23464
|
),
|
|
23293
|
-
|
|
23465
|
+
join25(process.cwd(), "data", "deepseek-tokenizer.json.gz")
|
|
23294
23466
|
];
|
|
23295
23467
|
for (const p of candidates) {
|
|
23296
23468
|
if (existsSync24(p)) {
|
|
@@ -23413,7 +23585,7 @@ async function checkOllama(projectRoot) {
|
|
|
23413
23585
|
}
|
|
23414
23586
|
async function checkProject(projectRoot) {
|
|
23415
23587
|
const markers = [".git", "REASONIX.md", "package.json", "pyproject.toml", "Cargo.toml", "go.mod"];
|
|
23416
|
-
const found = markers.filter((m) => existsSync24(
|
|
23588
|
+
const found = markers.filter((m) => existsSync24(join25(projectRoot, m)));
|
|
23417
23589
|
if (found.length === 0) {
|
|
23418
23590
|
return {
|
|
23419
23591
|
label: "project ",
|