reasonix 0.5.4 → 0.5.6
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/dist/cli/index.js +210 -85
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +107 -1
- package/dist/index.js +213 -101
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -126,8 +126,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
|
|
|
126
126
|
}
|
|
127
127
|
function sleep(ms, signal) {
|
|
128
128
|
if (ms <= 0) return Promise.resolve();
|
|
129
|
-
return new Promise((
|
|
130
|
-
const timer = setTimeout(
|
|
129
|
+
return new Promise((resolve7, reject) => {
|
|
130
|
+
const timer = setTimeout(resolve7, ms);
|
|
131
131
|
if (signal) {
|
|
132
132
|
const onAbort = () => {
|
|
133
133
|
clearTimeout(timer);
|
|
@@ -599,7 +599,7 @@ function matchesTool(hook, toolName) {
|
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
601
|
function defaultSpawner(input) {
|
|
602
|
-
return new Promise((
|
|
602
|
+
return new Promise((resolve7) => {
|
|
603
603
|
const child = spawn(input.command, {
|
|
604
604
|
cwd: input.cwd,
|
|
605
605
|
shell: true,
|
|
@@ -626,7 +626,7 @@ function defaultSpawner(input) {
|
|
|
626
626
|
});
|
|
627
627
|
child.once("error", (err) => {
|
|
628
628
|
clearTimeout(timer);
|
|
629
|
-
|
|
629
|
+
resolve7({
|
|
630
630
|
exitCode: null,
|
|
631
631
|
stdout: stdout2,
|
|
632
632
|
stderr,
|
|
@@ -636,7 +636,7 @@ function defaultSpawner(input) {
|
|
|
636
636
|
});
|
|
637
637
|
child.once("close", (code) => {
|
|
638
638
|
clearTimeout(timer);
|
|
639
|
-
|
|
639
|
+
resolve7({
|
|
640
640
|
exitCode: code,
|
|
641
641
|
stdout: stdout2.trim(),
|
|
642
642
|
stderr: stderr.trim(),
|
|
@@ -697,7 +697,7 @@ async function runHooks(opts) {
|
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
// src/tokenizer.ts
|
|
700
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
700
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
701
701
|
import { createRequire } from "module";
|
|
702
702
|
import { dirname as dirname2, join as join3 } from "path";
|
|
703
703
|
import { fileURLToPath } from "url";
|
|
@@ -725,17 +725,24 @@ function buildByteToChar() {
|
|
|
725
725
|
var cached = null;
|
|
726
726
|
function resolveDataPath() {
|
|
727
727
|
if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
|
|
728
|
+
const candidates = [];
|
|
728
729
|
try {
|
|
729
730
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
730
|
-
|
|
731
|
+
candidates.push(join3(here, "..", "data", "deepseek-tokenizer.json.gz"));
|
|
732
|
+
candidates.push(join3(here, "..", "..", "data", "deepseek-tokenizer.json.gz"));
|
|
731
733
|
} catch {
|
|
734
|
+
}
|
|
735
|
+
try {
|
|
732
736
|
const req = createRequire(import.meta.url);
|
|
733
|
-
|
|
734
|
-
dirname2(req.resolve("reasonix/package.json")),
|
|
735
|
-
"data",
|
|
736
|
-
"deepseek-tokenizer.json.gz"
|
|
737
|
+
candidates.push(
|
|
738
|
+
join3(dirname2(req.resolve("reasonix/package.json")), "data", "deepseek-tokenizer.json.gz")
|
|
737
739
|
);
|
|
740
|
+
} catch {
|
|
738
741
|
}
|
|
742
|
+
for (const p of candidates) {
|
|
743
|
+
if (existsSync2(p)) return p;
|
|
744
|
+
}
|
|
745
|
+
return candidates[0] ?? join3(process.cwd(), "data", "deepseek-tokenizer.json.gz");
|
|
739
746
|
}
|
|
740
747
|
function loadTokenizer() {
|
|
741
748
|
if (cached) return cached;
|
|
@@ -1565,7 +1572,7 @@ function signature2(call) {
|
|
|
1565
1572
|
import {
|
|
1566
1573
|
appendFileSync,
|
|
1567
1574
|
chmodSync as chmodSync2,
|
|
1568
|
-
existsSync as
|
|
1575
|
+
existsSync as existsSync3,
|
|
1569
1576
|
mkdirSync as mkdirSync2,
|
|
1570
1577
|
readFileSync as readFileSync4,
|
|
1571
1578
|
readdirSync,
|
|
@@ -1587,7 +1594,7 @@ function sanitizeName(name) {
|
|
|
1587
1594
|
}
|
|
1588
1595
|
function loadSessionMessages(name) {
|
|
1589
1596
|
const path = sessionPath(name);
|
|
1590
|
-
if (!
|
|
1597
|
+
if (!existsSync3(path)) return [];
|
|
1591
1598
|
try {
|
|
1592
1599
|
const raw = readFileSync4(path, "utf8");
|
|
1593
1600
|
const out = [];
|
|
@@ -1617,7 +1624,7 @@ function appendSessionMessage(name, message) {
|
|
|
1617
1624
|
}
|
|
1618
1625
|
function listSessions() {
|
|
1619
1626
|
const dir = sessionsDir();
|
|
1620
|
-
if (!
|
|
1627
|
+
if (!existsSync3(dir)) return [];
|
|
1621
1628
|
try {
|
|
1622
1629
|
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1623
1630
|
return files.map((file) => {
|
|
@@ -1813,9 +1820,9 @@ var CacheFirstLoop = class {
|
|
|
1813
1820
|
this.sessionName = opts.session ?? null;
|
|
1814
1821
|
if (this.sessionName) {
|
|
1815
1822
|
const prior = loadSessionMessages(this.sessionName);
|
|
1816
|
-
const { messages, healedCount,
|
|
1823
|
+
const { messages, healedCount, tokensSaved } = healLoadedMessagesByTokens(
|
|
1817
1824
|
prior,
|
|
1818
|
-
|
|
1825
|
+
DEFAULT_MAX_RESULT_TOKENS
|
|
1819
1826
|
);
|
|
1820
1827
|
for (const msg of messages) this.log.append(msg);
|
|
1821
1828
|
this.resumedMessageCount = messages.length;
|
|
@@ -1825,7 +1832,7 @@ var CacheFirstLoop = class {
|
|
|
1825
1832
|
} catch {
|
|
1826
1833
|
}
|
|
1827
1834
|
process.stderr.write(
|
|
1828
|
-
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${
|
|
1835
|
+
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${tokensSaved > 0 ? ` (shrunk ${tokensSaved.toLocaleString()} tokens of oversized tool output)` : " (dropped dangling tool_calls tail)"}. Rewrote session file.
|
|
1829
1836
|
`
|
|
1830
1837
|
);
|
|
1831
1838
|
}
|
|
@@ -2094,8 +2101,8 @@ var CacheFirstLoop = class {
|
|
|
2094
2101
|
}
|
|
2095
2102
|
);
|
|
2096
2103
|
for (let k = 0; k < budget; k++) {
|
|
2097
|
-
const sample = queue.shift() ?? await new Promise((
|
|
2098
|
-
waiter =
|
|
2104
|
+
const sample = queue.shift() ?? await new Promise((resolve7) => {
|
|
2105
|
+
waiter = resolve7;
|
|
2099
2106
|
});
|
|
2100
2107
|
yield {
|
|
2101
2108
|
turn: this._turn,
|
|
@@ -2494,15 +2501,12 @@ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
|
|
|
2494
2501
|
});
|
|
2495
2502
|
return { messages: out, healedCount, tokensSaved, charsSaved };
|
|
2496
2503
|
}
|
|
2497
|
-
function
|
|
2498
|
-
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2499
|
-
let healedCount = shrunk.healedCount;
|
|
2504
|
+
function fixToolCallPairing(messages) {
|
|
2500
2505
|
const out = [];
|
|
2501
|
-
const openCallIds = /* @__PURE__ */ new Set();
|
|
2502
2506
|
let droppedAssistantCalls = 0;
|
|
2503
2507
|
let droppedStrayTools = 0;
|
|
2504
|
-
for (let i = 0; i <
|
|
2505
|
-
const msg =
|
|
2508
|
+
for (let i = 0; i < messages.length; i++) {
|
|
2509
|
+
const msg = messages[i];
|
|
2506
2510
|
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
2507
2511
|
const needed = /* @__PURE__ */ new Set();
|
|
2508
2512
|
for (const call of msg.tool_calls) {
|
|
@@ -2510,8 +2514,8 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2510
2514
|
}
|
|
2511
2515
|
const candidates = [];
|
|
2512
2516
|
let j = i + 1;
|
|
2513
|
-
while (j <
|
|
2514
|
-
const nxt =
|
|
2517
|
+
while (j < messages.length && needed.size > 0) {
|
|
2518
|
+
const nxt = messages[j];
|
|
2515
2519
|
if (nxt.role !== "tool") break;
|
|
2516
2520
|
const id = nxt.tool_call_id ?? "";
|
|
2517
2521
|
if (!needed.has(id)) break;
|
|
@@ -2536,8 +2540,24 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2536
2540
|
}
|
|
2537
2541
|
out.push(msg);
|
|
2538
2542
|
}
|
|
2539
|
-
|
|
2540
|
-
|
|
2543
|
+
return { messages: out, droppedAssistantCalls, droppedStrayTools };
|
|
2544
|
+
}
|
|
2545
|
+
function healLoadedMessages(messages, maxChars) {
|
|
2546
|
+
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2547
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2548
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2549
|
+
return { messages: paired.messages, healedCount, healedFrom: shrunk.healedFrom };
|
|
2550
|
+
}
|
|
2551
|
+
function healLoadedMessagesByTokens(messages, maxTokens) {
|
|
2552
|
+
const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);
|
|
2553
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2554
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2555
|
+
return {
|
|
2556
|
+
messages: paired.messages,
|
|
2557
|
+
healedCount,
|
|
2558
|
+
tokensSaved: shrunk.tokensSaved,
|
|
2559
|
+
charsSaved: shrunk.charsSaved
|
|
2560
|
+
};
|
|
2541
2561
|
}
|
|
2542
2562
|
function formatLoopError(err) {
|
|
2543
2563
|
const msg = err.message ?? "";
|
|
@@ -2549,6 +2569,93 @@ function formatLoopError(err) {
|
|
|
2549
2569
|
return msg;
|
|
2550
2570
|
}
|
|
2551
2571
|
|
|
2572
|
+
// src/at-mentions.ts
|
|
2573
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
2574
|
+
import { isAbsolute, relative, resolve } from "path";
|
|
2575
|
+
var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
|
|
2576
|
+
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
2577
|
+
function expandAtMentions(text, rootDir, opts = {}) {
|
|
2578
|
+
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
2579
|
+
const fs2 = opts.fs ?? defaultFs;
|
|
2580
|
+
const root = resolve(rootDir);
|
|
2581
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2582
|
+
const expansions = [];
|
|
2583
|
+
for (const match of text.matchAll(AT_MENTION_PATTERN)) {
|
|
2584
|
+
const rawPath = match[1] ?? "";
|
|
2585
|
+
const cleaned = rawPath.replace(/\.+$/, "");
|
|
2586
|
+
if (!cleaned) continue;
|
|
2587
|
+
const token = `@${cleaned}`;
|
|
2588
|
+
if (seen.has(token)) continue;
|
|
2589
|
+
const expansion = resolveMention(cleaned, root, maxBytes, fs2);
|
|
2590
|
+
seen.set(token, expansion);
|
|
2591
|
+
expansions.push(expansion);
|
|
2592
|
+
}
|
|
2593
|
+
if (expansions.length === 0) return { text, expansions };
|
|
2594
|
+
const blocks = [];
|
|
2595
|
+
for (const ex of expansions) {
|
|
2596
|
+
if (ex.ok) {
|
|
2597
|
+
const content = readSafe(root, ex.path, fs2);
|
|
2598
|
+
blocks.push(`<file path="${ex.path}">
|
|
2599
|
+
${content}
|
|
2600
|
+
</file>`);
|
|
2601
|
+
} else {
|
|
2602
|
+
blocks.push(`<file path="${ex.path}" skipped="${ex.skip}" />`);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
const augmented = `${text}
|
|
2606
|
+
|
|
2607
|
+
[Referenced files]
|
|
2608
|
+
${blocks.join("\n\n")}`;
|
|
2609
|
+
return { text: augmented, expansions };
|
|
2610
|
+
}
|
|
2611
|
+
function resolveMention(rawPath, root, maxBytes, fs2) {
|
|
2612
|
+
if (isAbsolute(rawPath)) {
|
|
2613
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2614
|
+
}
|
|
2615
|
+
const resolved = resolve(root, rawPath);
|
|
2616
|
+
const rel = relative(root, resolved);
|
|
2617
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
2618
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2619
|
+
}
|
|
2620
|
+
if (!fs2.exists(resolved)) {
|
|
2621
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "missing" };
|
|
2622
|
+
}
|
|
2623
|
+
if (!fs2.isFile(resolved)) {
|
|
2624
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
|
|
2625
|
+
}
|
|
2626
|
+
const size = fs2.size(resolved);
|
|
2627
|
+
if (size > maxBytes) {
|
|
2628
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "too-large", bytes: size };
|
|
2629
|
+
}
|
|
2630
|
+
return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };
|
|
2631
|
+
}
|
|
2632
|
+
function readSafe(root, rawPath, fs2) {
|
|
2633
|
+
const resolved = resolve(root, rawPath);
|
|
2634
|
+
try {
|
|
2635
|
+
return fs2.read(resolved);
|
|
2636
|
+
} catch {
|
|
2637
|
+
return "(read failed)";
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
var defaultFs = {
|
|
2641
|
+
exists: (p) => existsSync4(p),
|
|
2642
|
+
isFile: (p) => {
|
|
2643
|
+
try {
|
|
2644
|
+
return statSync2(p).isFile();
|
|
2645
|
+
} catch {
|
|
2646
|
+
return false;
|
|
2647
|
+
}
|
|
2648
|
+
},
|
|
2649
|
+
size: (p) => {
|
|
2650
|
+
try {
|
|
2651
|
+
return statSync2(p).size;
|
|
2652
|
+
} catch {
|
|
2653
|
+
return 0;
|
|
2654
|
+
}
|
|
2655
|
+
},
|
|
2656
|
+
read: (p) => readFileSync5(p, "utf8")
|
|
2657
|
+
};
|
|
2658
|
+
|
|
2552
2659
|
// src/tools/filesystem.ts
|
|
2553
2660
|
import { promises as fs } from "fs";
|
|
2554
2661
|
import * as pathMod from "path";
|
|
@@ -3359,7 +3466,7 @@ function forkRegistryExcluding(parent, exclude) {
|
|
|
3359
3466
|
|
|
3360
3467
|
// src/tools/shell.ts
|
|
3361
3468
|
import { spawn as spawn2 } from "child_process";
|
|
3362
|
-
import { existsSync as
|
|
3469
|
+
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
3363
3470
|
import * as pathMod2 from "path";
|
|
3364
3471
|
var DEFAULT_TIMEOUT_SEC = 60;
|
|
3365
3472
|
var DEFAULT_MAX_OUTPUT_CHARS = 32e3;
|
|
@@ -3529,7 +3636,7 @@ async function runCommand(cmd, opts) {
|
|
|
3529
3636
|
};
|
|
3530
3637
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
3531
3638
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
3532
|
-
return await new Promise((
|
|
3639
|
+
return await new Promise((resolve7, reject) => {
|
|
3533
3640
|
let child;
|
|
3534
3641
|
try {
|
|
3535
3642
|
child = spawn2(bin, args, effectiveSpawnOpts);
|
|
@@ -3562,7 +3669,7 @@ async function runCommand(cmd, opts) {
|
|
|
3562
3669
|
const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
|
|
3563
3670
|
|
|
3564
3671
|
[\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
|
|
3565
|
-
|
|
3672
|
+
resolve7({ exitCode: code, output, timedOut });
|
|
3566
3673
|
});
|
|
3567
3674
|
});
|
|
3568
3675
|
}
|
|
@@ -3587,7 +3694,7 @@ function resolveExecutable(cmd, opts = {}) {
|
|
|
3587
3694
|
}
|
|
3588
3695
|
function defaultIsFile(full) {
|
|
3589
3696
|
try {
|
|
3590
|
-
return
|
|
3697
|
+
return existsSync5(full) && statSync3(full).isFile();
|
|
3591
3698
|
} catch {
|
|
3592
3699
|
return false;
|
|
3593
3700
|
}
|
|
@@ -3914,12 +4021,12 @@ ${i + 1}. ${r.title}`);
|
|
|
3914
4021
|
}
|
|
3915
4022
|
|
|
3916
4023
|
// src/env.ts
|
|
3917
|
-
import { readFileSync as
|
|
3918
|
-
import { resolve as
|
|
4024
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
4025
|
+
import { resolve as resolve4 } from "path";
|
|
3919
4026
|
function loadDotenv(path = ".env") {
|
|
3920
4027
|
let raw;
|
|
3921
4028
|
try {
|
|
3922
|
-
raw =
|
|
4029
|
+
raw = readFileSync6(resolve4(process.cwd(), path), "utf8");
|
|
3923
4030
|
} catch {
|
|
3924
4031
|
return;
|
|
3925
4032
|
}
|
|
@@ -3938,7 +4045,7 @@ function loadDotenv(path = ".env") {
|
|
|
3938
4045
|
}
|
|
3939
4046
|
|
|
3940
4047
|
// src/transcript.ts
|
|
3941
|
-
import { createWriteStream, readFileSync as
|
|
4048
|
+
import { createWriteStream, readFileSync as readFileSync7 } from "fs";
|
|
3942
4049
|
function recordFromLoopEvent(ev, extra) {
|
|
3943
4050
|
const rec = {
|
|
3944
4051
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3989,7 +4096,7 @@ function openTranscriptFile(path, meta) {
|
|
|
3989
4096
|
return stream;
|
|
3990
4097
|
}
|
|
3991
4098
|
function readTranscript(path) {
|
|
3992
|
-
const raw =
|
|
4099
|
+
const raw = readFileSync7(path, "utf8");
|
|
3993
4100
|
return parseTranscript(raw);
|
|
3994
4101
|
}
|
|
3995
4102
|
function isPlanStateEmptyShape(s) {
|
|
@@ -4632,7 +4739,7 @@ var McpClient = class {
|
|
|
4632
4739
|
const id = this.nextId++;
|
|
4633
4740
|
const frame = { jsonrpc: "2.0", id, method, params };
|
|
4634
4741
|
let abortHandler = null;
|
|
4635
|
-
const promise = new Promise((
|
|
4742
|
+
const promise = new Promise((resolve7, reject) => {
|
|
4636
4743
|
const timeout = setTimeout(() => {
|
|
4637
4744
|
this.pending.delete(id);
|
|
4638
4745
|
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
@@ -4641,7 +4748,7 @@ var McpClient = class {
|
|
|
4641
4748
|
);
|
|
4642
4749
|
}, this.requestTimeoutMs);
|
|
4643
4750
|
this.pending.set(id, {
|
|
4644
|
-
resolve:
|
|
4751
|
+
resolve: resolve7,
|
|
4645
4752
|
reject,
|
|
4646
4753
|
timeout
|
|
4647
4754
|
});
|
|
@@ -4764,12 +4871,12 @@ var StdioTransport = class {
|
|
|
4764
4871
|
}
|
|
4765
4872
|
async send(message) {
|
|
4766
4873
|
if (this.closed) throw new Error("MCP transport is closed");
|
|
4767
|
-
return new Promise((
|
|
4874
|
+
return new Promise((resolve7, reject) => {
|
|
4768
4875
|
const line = `${JSON.stringify(message)}
|
|
4769
4876
|
`;
|
|
4770
4877
|
this.child.stdin.write(line, "utf8", (err) => {
|
|
4771
4878
|
if (err) reject(err);
|
|
4772
|
-
else
|
|
4879
|
+
else resolve7();
|
|
4773
4880
|
});
|
|
4774
4881
|
});
|
|
4775
4882
|
}
|
|
@@ -4780,8 +4887,8 @@ var StdioTransport = class {
|
|
|
4780
4887
|
continue;
|
|
4781
4888
|
}
|
|
4782
4889
|
if (this.closed) return;
|
|
4783
|
-
const next = await new Promise((
|
|
4784
|
-
this.waiters.push(
|
|
4890
|
+
const next = await new Promise((resolve7) => {
|
|
4891
|
+
this.waiters.push(resolve7);
|
|
4785
4892
|
});
|
|
4786
4893
|
if (next === null) return;
|
|
4787
4894
|
yield next;
|
|
@@ -4847,8 +4954,8 @@ var SseTransport = class {
|
|
|
4847
4954
|
constructor(opts) {
|
|
4848
4955
|
this.url = opts.url;
|
|
4849
4956
|
this.headers = opts.headers ?? {};
|
|
4850
|
-
this.endpointReady = new Promise((
|
|
4851
|
-
this.resolveEndpoint =
|
|
4957
|
+
this.endpointReady = new Promise((resolve7, reject) => {
|
|
4958
|
+
this.resolveEndpoint = resolve7;
|
|
4852
4959
|
this.rejectEndpoint = reject;
|
|
4853
4960
|
});
|
|
4854
4961
|
this.endpointReady.catch(() => void 0);
|
|
@@ -4875,8 +4982,8 @@ var SseTransport = class {
|
|
|
4875
4982
|
continue;
|
|
4876
4983
|
}
|
|
4877
4984
|
if (this.closed) return;
|
|
4878
|
-
const next = await new Promise((
|
|
4879
|
-
this.waiters.push(
|
|
4985
|
+
const next = await new Promise((resolve7) => {
|
|
4986
|
+
this.waiters.push(resolve7);
|
|
4880
4987
|
});
|
|
4881
4988
|
if (next === null) return;
|
|
4882
4989
|
yield next;
|
|
@@ -5075,8 +5182,8 @@ async function trySection(load) {
|
|
|
5075
5182
|
}
|
|
5076
5183
|
|
|
5077
5184
|
// src/code/edit-blocks.ts
|
|
5078
|
-
import { existsSync as
|
|
5079
|
-
import { dirname as dirname5, resolve as
|
|
5185
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
5186
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
5080
5187
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
5081
5188
|
function parseEditBlocks(text) {
|
|
5082
5189
|
const out = [];
|
|
@@ -5094,8 +5201,8 @@ function parseEditBlocks(text) {
|
|
|
5094
5201
|
return out;
|
|
5095
5202
|
}
|
|
5096
5203
|
function applyEditBlock(block, rootDir) {
|
|
5097
|
-
const absRoot =
|
|
5098
|
-
const absTarget =
|
|
5204
|
+
const absRoot = resolve5(rootDir);
|
|
5205
|
+
const absTarget = resolve5(absRoot, block.path);
|
|
5099
5206
|
if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {
|
|
5100
5207
|
return {
|
|
5101
5208
|
path: block.path,
|
|
@@ -5104,7 +5211,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5104
5211
|
};
|
|
5105
5212
|
}
|
|
5106
5213
|
const searchEmpty = block.search.length === 0;
|
|
5107
|
-
const exists =
|
|
5214
|
+
const exists = existsSync6(absTarget);
|
|
5108
5215
|
try {
|
|
5109
5216
|
if (!exists) {
|
|
5110
5217
|
if (!searchEmpty) {
|
|
@@ -5118,7 +5225,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5118
5225
|
writeFileSync3(absTarget, block.replace, "utf8");
|
|
5119
5226
|
return { path: block.path, status: "created" };
|
|
5120
5227
|
}
|
|
5121
|
-
const content =
|
|
5228
|
+
const content = readFileSync8(absTarget, "utf8");
|
|
5122
5229
|
if (searchEmpty) {
|
|
5123
5230
|
return {
|
|
5124
5231
|
path: block.path,
|
|
@@ -5145,19 +5252,19 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
5145
5252
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
5146
5253
|
}
|
|
5147
5254
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
5148
|
-
const absRoot =
|
|
5255
|
+
const absRoot = resolve5(rootDir);
|
|
5149
5256
|
const seen = /* @__PURE__ */ new Set();
|
|
5150
5257
|
const snapshots = [];
|
|
5151
5258
|
for (const b of blocks) {
|
|
5152
5259
|
if (seen.has(b.path)) continue;
|
|
5153
5260
|
seen.add(b.path);
|
|
5154
|
-
const abs =
|
|
5155
|
-
if (!
|
|
5261
|
+
const abs = resolve5(absRoot, b.path);
|
|
5262
|
+
if (!existsSync6(abs)) {
|
|
5156
5263
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5157
5264
|
continue;
|
|
5158
5265
|
}
|
|
5159
5266
|
try {
|
|
5160
|
-
snapshots.push({ path: b.path, prevContent:
|
|
5267
|
+
snapshots.push({ path: b.path, prevContent: readFileSync8(abs, "utf8") });
|
|
5161
5268
|
} catch {
|
|
5162
5269
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5163
5270
|
}
|
|
@@ -5165,9 +5272,9 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
5165
5272
|
return snapshots;
|
|
5166
5273
|
}
|
|
5167
5274
|
function restoreSnapshots(snapshots, rootDir) {
|
|
5168
|
-
const absRoot =
|
|
5275
|
+
const absRoot = resolve5(rootDir);
|
|
5169
5276
|
return snapshots.map((snap) => {
|
|
5170
|
-
const abs =
|
|
5277
|
+
const abs = resolve5(absRoot, snap.path);
|
|
5171
5278
|
if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {
|
|
5172
5279
|
return {
|
|
5173
5280
|
path: snap.path,
|
|
@@ -5177,7 +5284,7 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
5177
5284
|
}
|
|
5178
5285
|
try {
|
|
5179
5286
|
if (snap.prevContent === null) {
|
|
5180
|
-
if (
|
|
5287
|
+
if (existsSync6(abs)) unlinkSync2(abs);
|
|
5181
5288
|
return {
|
|
5182
5289
|
path: snap.path,
|
|
5183
5290
|
status: "applied",
|
|
@@ -5200,7 +5307,7 @@ function sep() {
|
|
|
5200
5307
|
}
|
|
5201
5308
|
|
|
5202
5309
|
// src/version.ts
|
|
5203
|
-
import { existsSync as
|
|
5310
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
5204
5311
|
import { homedir as homedir4 } from "os";
|
|
5205
5312
|
import { dirname as dirname6, join as join6 } from "path";
|
|
5206
5313
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -5212,8 +5319,8 @@ function readPackageVersion() {
|
|
|
5212
5319
|
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
5213
5320
|
for (let i = 0; i < 6; i++) {
|
|
5214
5321
|
const p = join6(dir, "package.json");
|
|
5215
|
-
if (
|
|
5216
|
-
const pkg = JSON.parse(
|
|
5322
|
+
if (existsSync7(p)) {
|
|
5323
|
+
const pkg = JSON.parse(readFileSync9(p, "utf8"));
|
|
5217
5324
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
5218
5325
|
return pkg.version;
|
|
5219
5326
|
}
|
|
@@ -5232,7 +5339,7 @@ function cachePath(homeDirOverride) {
|
|
|
5232
5339
|
}
|
|
5233
5340
|
function readCache(homeDirOverride) {
|
|
5234
5341
|
try {
|
|
5235
|
-
const raw =
|
|
5342
|
+
const raw = readFileSync9(cachePath(homeDirOverride), "utf8");
|
|
5236
5343
|
const parsed = JSON.parse(raw);
|
|
5237
5344
|
if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
|
|
5238
5345
|
return parsed;
|
|
@@ -5301,7 +5408,7 @@ function isNpxInstall() {
|
|
|
5301
5408
|
}
|
|
5302
5409
|
|
|
5303
5410
|
// src/usage.ts
|
|
5304
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
5411
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
5305
5412
|
import { homedir as homedir5 } from "os";
|
|
5306
5413
|
import { dirname as dirname7, join as join7 } from "path";
|
|
5307
5414
|
function defaultUsageLogPath(homeDirOverride) {
|
|
@@ -5329,10 +5436,10 @@ function appendUsage(input) {
|
|
|
5329
5436
|
return record;
|
|
5330
5437
|
}
|
|
5331
5438
|
function readUsageLog(path = defaultUsageLogPath()) {
|
|
5332
|
-
if (!
|
|
5439
|
+
if (!existsSync8(path)) return [];
|
|
5333
5440
|
let raw;
|
|
5334
5441
|
try {
|
|
5335
|
-
raw =
|
|
5442
|
+
raw = readFileSync10(path, "utf8");
|
|
5336
5443
|
} catch {
|
|
5337
5444
|
return [];
|
|
5338
5445
|
}
|
|
@@ -5414,9 +5521,9 @@ function aggregateUsage(records, opts = {}) {
|
|
|
5414
5521
|
};
|
|
5415
5522
|
}
|
|
5416
5523
|
function formatLogSize(path = defaultUsageLogPath()) {
|
|
5417
|
-
if (!
|
|
5524
|
+
if (!existsSync8(path)) return "";
|
|
5418
5525
|
try {
|
|
5419
|
-
const s =
|
|
5526
|
+
const s = statSync4(path);
|
|
5420
5527
|
const bytes = s.size;
|
|
5421
5528
|
if (bytes < 1024) return `${bytes} B`;
|
|
5422
5529
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -5427,7 +5534,7 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
5427
5534
|
}
|
|
5428
5535
|
|
|
5429
5536
|
// src/cli/commands/chat.tsx
|
|
5430
|
-
import { existsSync as
|
|
5537
|
+
import { existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
5431
5538
|
import { render } from "ink";
|
|
5432
5539
|
import React15, { useState as useState7 } from "react";
|
|
5433
5540
|
|
|
@@ -5525,8 +5632,8 @@ function PlanStateBlock({ planState }) {
|
|
|
5525
5632
|
}
|
|
5526
5633
|
|
|
5527
5634
|
// src/cli/ui/markdown.tsx
|
|
5528
|
-
import { readFileSync as
|
|
5529
|
-
import { isAbsolute as
|
|
5635
|
+
import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
|
|
5636
|
+
import { isAbsolute as isAbsolute4, join as join8 } from "path";
|
|
5530
5637
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
5531
5638
|
import React2 from "react";
|
|
5532
5639
|
var SUPERSCRIPT = {
|
|
@@ -5604,10 +5711,10 @@ function parseCitationUrl(url) {
|
|
|
5604
5711
|
function validateCitation(url, projectRoot) {
|
|
5605
5712
|
const parts = parseCitationUrl(url);
|
|
5606
5713
|
if (!parts || !parts.path) return { ok: false, reason: "empty path" };
|
|
5607
|
-
const fullPath =
|
|
5714
|
+
const fullPath = isAbsolute4(parts.path) ? parts.path : join8(projectRoot, parts.path);
|
|
5608
5715
|
let stat;
|
|
5609
5716
|
try {
|
|
5610
|
-
stat =
|
|
5717
|
+
stat = statSync5(fullPath);
|
|
5611
5718
|
} catch {
|
|
5612
5719
|
return { ok: false, reason: "file not found" };
|
|
5613
5720
|
}
|
|
@@ -5615,7 +5722,7 @@ function validateCitation(url, projectRoot) {
|
|
|
5615
5722
|
if (parts.startLine === void 0) return { ok: true };
|
|
5616
5723
|
let lineCount;
|
|
5617
5724
|
try {
|
|
5618
|
-
lineCount =
|
|
5725
|
+
lineCount = readFileSync11(fullPath, "utf8").split("\n").length;
|
|
5619
5726
|
} catch {
|
|
5620
5727
|
return { ok: false, reason: "unreadable" };
|
|
5621
5728
|
}
|
|
@@ -6795,7 +6902,7 @@ function formatTokens(n) {
|
|
|
6795
6902
|
import { spawnSync } from "child_process";
|
|
6796
6903
|
|
|
6797
6904
|
// src/cli/commands/stats.ts
|
|
6798
|
-
import { existsSync as
|
|
6905
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
|
|
6799
6906
|
function statsCommand(opts) {
|
|
6800
6907
|
if (opts.transcript) {
|
|
6801
6908
|
transcriptSummary(opts.transcript);
|
|
@@ -6804,11 +6911,11 @@ function statsCommand(opts) {
|
|
|
6804
6911
|
dashboard(opts);
|
|
6805
6912
|
}
|
|
6806
6913
|
function transcriptSummary(path) {
|
|
6807
|
-
if (!
|
|
6914
|
+
if (!existsSync9(path)) {
|
|
6808
6915
|
console.error(`no such transcript: ${path}`);
|
|
6809
6916
|
process.exit(1);
|
|
6810
6917
|
}
|
|
6811
|
-
const lines =
|
|
6918
|
+
const lines = readFileSync12(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
6812
6919
|
let assistantTurns = 0;
|
|
6813
6920
|
let toolCalls = 0;
|
|
6814
6921
|
let lastTurn = 0;
|
|
@@ -8342,8 +8449,26 @@ function App({
|
|
|
8342
8449
|
});
|
|
8343
8450
|
};
|
|
8344
8451
|
const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
|
|
8452
|
+
let modelInput = text;
|
|
8453
|
+
if (codeMode?.rootDir) {
|
|
8454
|
+
const expanded = expandAtMentions(text, codeMode.rootDir);
|
|
8455
|
+
if (expanded.expansions.length > 0) {
|
|
8456
|
+
modelInput = expanded.text;
|
|
8457
|
+
const inlined = expanded.expansions.filter((ex) => ex.ok).map((ex) => `${ex.path} (${(ex.bytes ?? 0).toLocaleString()} bytes)`);
|
|
8458
|
+
const skipped = expanded.expansions.filter((ex) => !ex.ok).map((ex) => `${ex.path} (${ex.skip})`);
|
|
8459
|
+
const parts = [];
|
|
8460
|
+
if (inlined.length > 0) parts.push(`inlined ${inlined.join(", ")}`);
|
|
8461
|
+
if (skipped.length > 0) parts.push(`skipped ${skipped.join(", ")}`);
|
|
8462
|
+
if (parts.length > 0) {
|
|
8463
|
+
setHistorical((prev) => [
|
|
8464
|
+
...prev,
|
|
8465
|
+
{ id: `at-${Date.now()}`, role: "info", text: `\u25B8 @mentions: ${parts.join("; ")}` }
|
|
8466
|
+
]);
|
|
8467
|
+
}
|
|
8468
|
+
}
|
|
8469
|
+
}
|
|
8345
8470
|
try {
|
|
8346
|
-
for await (const ev of loop.step(
|
|
8471
|
+
for await (const ev of loop.step(modelInput)) {
|
|
8347
8472
|
writeTranscript(ev);
|
|
8348
8473
|
if (ev.role !== "status") {
|
|
8349
8474
|
setStatusLine((cur) => cur ? null : cur);
|
|
@@ -9058,7 +9183,7 @@ async function chatCommand(opts) {
|
|
|
9058
9183
|
const prior = loadSessionMessages(opts.session);
|
|
9059
9184
|
if (prior.length > 0) {
|
|
9060
9185
|
const p = sessionPath(opts.session);
|
|
9061
|
-
const mtime =
|
|
9186
|
+
const mtime = existsSync10(p) ? statSync6(p).mtime : /* @__PURE__ */ new Date();
|
|
9062
9187
|
sessionPreview = { messageCount: prior.length, lastActive: mtime };
|
|
9063
9188
|
}
|
|
9064
9189
|
} else if (opts.session && opts.forceNew) {
|
|
@@ -9089,10 +9214,10 @@ async function chatCommand(opts) {
|
|
|
9089
9214
|
}
|
|
9090
9215
|
|
|
9091
9216
|
// src/cli/commands/code.tsx
|
|
9092
|
-
import { basename, resolve as
|
|
9217
|
+
import { basename, resolve as resolve6 } from "path";
|
|
9093
9218
|
async function codeCommand(opts = {}) {
|
|
9094
9219
|
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-75XLIUTO.js");
|
|
9095
|
-
const rootDir =
|
|
9220
|
+
const rootDir = resolve6(opts.dir ?? process.cwd());
|
|
9096
9221
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
|
|
9097
9222
|
const tools = new ToolRegistry();
|
|
9098
9223
|
registerFilesystemTools(tools, { rootDir });
|
|
@@ -10111,13 +10236,13 @@ function planUpdate(input) {
|
|
|
10111
10236
|
};
|
|
10112
10237
|
}
|
|
10113
10238
|
function defaultSpawn(argv) {
|
|
10114
|
-
return new Promise((
|
|
10239
|
+
return new Promise((resolve7, reject) => {
|
|
10115
10240
|
const child = spawn4(argv[0], argv.slice(1), {
|
|
10116
10241
|
stdio: "inherit",
|
|
10117
10242
|
shell: process.platform === "win32"
|
|
10118
10243
|
});
|
|
10119
10244
|
child.once("error", reject);
|
|
10120
|
-
child.once("exit", (code) =>
|
|
10245
|
+
child.once("exit", (code) => resolve7(code ?? 1));
|
|
10121
10246
|
});
|
|
10122
10247
|
}
|
|
10123
10248
|
async function updateCommand(opts = {}) {
|