reasonix 0.5.4 → 0.5.7
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 +564 -272
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +166 -1
- package/dist/index.js +316 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47,8 +47,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
|
|
|
47
47
|
}
|
|
48
48
|
function sleep(ms, signal) {
|
|
49
49
|
if (ms <= 0) return Promise.resolve();
|
|
50
|
-
return new Promise((
|
|
51
|
-
const timer = setTimeout(
|
|
50
|
+
return new Promise((resolve8, reject) => {
|
|
51
|
+
const timer = setTimeout(resolve8, ms);
|
|
52
52
|
if (signal) {
|
|
53
53
|
const onAbort = () => {
|
|
54
54
|
clearTimeout(timer);
|
|
@@ -520,7 +520,7 @@ function matchesTool(hook, toolName) {
|
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
function defaultSpawner(input) {
|
|
523
|
-
return new Promise((
|
|
523
|
+
return new Promise((resolve8) => {
|
|
524
524
|
const child = spawn(input.command, {
|
|
525
525
|
cwd: input.cwd,
|
|
526
526
|
shell: true,
|
|
@@ -547,7 +547,7 @@ function defaultSpawner(input) {
|
|
|
547
547
|
});
|
|
548
548
|
child.once("error", (err) => {
|
|
549
549
|
clearTimeout(timer);
|
|
550
|
-
|
|
550
|
+
resolve8({
|
|
551
551
|
exitCode: null,
|
|
552
552
|
stdout,
|
|
553
553
|
stderr,
|
|
@@ -557,7 +557,7 @@ function defaultSpawner(input) {
|
|
|
557
557
|
});
|
|
558
558
|
child.once("close", (code) => {
|
|
559
559
|
clearTimeout(timer);
|
|
560
|
-
|
|
560
|
+
resolve8({
|
|
561
561
|
exitCode: code,
|
|
562
562
|
stdout: stdout.trim(),
|
|
563
563
|
stderr: stderr.trim(),
|
|
@@ -618,7 +618,7 @@ async function runHooks(opts) {
|
|
|
618
618
|
}
|
|
619
619
|
|
|
620
620
|
// src/tokenizer.ts
|
|
621
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
621
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
622
622
|
import { createRequire } from "module";
|
|
623
623
|
import { dirname, join as join2 } from "path";
|
|
624
624
|
import { fileURLToPath } from "url";
|
|
@@ -646,17 +646,24 @@ function buildByteToChar() {
|
|
|
646
646
|
var cached = null;
|
|
647
647
|
function resolveDataPath() {
|
|
648
648
|
if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
|
|
649
|
+
const candidates = [];
|
|
649
650
|
try {
|
|
650
651
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
651
|
-
|
|
652
|
+
candidates.push(join2(here, "..", "data", "deepseek-tokenizer.json.gz"));
|
|
653
|
+
candidates.push(join2(here, "..", "..", "data", "deepseek-tokenizer.json.gz"));
|
|
652
654
|
} catch {
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
653
657
|
const req = createRequire(import.meta.url);
|
|
654
|
-
|
|
655
|
-
dirname(req.resolve("reasonix/package.json")),
|
|
656
|
-
"data",
|
|
657
|
-
"deepseek-tokenizer.json.gz"
|
|
658
|
+
candidates.push(
|
|
659
|
+
join2(dirname(req.resolve("reasonix/package.json")), "data", "deepseek-tokenizer.json.gz")
|
|
658
660
|
);
|
|
661
|
+
} catch {
|
|
662
|
+
}
|
|
663
|
+
for (const p of candidates) {
|
|
664
|
+
if (existsSync2(p)) return p;
|
|
659
665
|
}
|
|
666
|
+
return candidates[0] ?? join2(process.cwd(), "data", "deepseek-tokenizer.json.gz");
|
|
660
667
|
}
|
|
661
668
|
function loadTokenizer() {
|
|
662
669
|
if (cached) return cached;
|
|
@@ -1486,7 +1493,7 @@ function signature2(call) {
|
|
|
1486
1493
|
import {
|
|
1487
1494
|
appendFileSync,
|
|
1488
1495
|
chmodSync,
|
|
1489
|
-
existsSync as
|
|
1496
|
+
existsSync as existsSync3,
|
|
1490
1497
|
mkdirSync,
|
|
1491
1498
|
readFileSync as readFileSync3,
|
|
1492
1499
|
readdirSync,
|
|
@@ -1508,7 +1515,7 @@ function sanitizeName(name) {
|
|
|
1508
1515
|
}
|
|
1509
1516
|
function loadSessionMessages(name) {
|
|
1510
1517
|
const path = sessionPath(name);
|
|
1511
|
-
if (!
|
|
1518
|
+
if (!existsSync3(path)) return [];
|
|
1512
1519
|
try {
|
|
1513
1520
|
const raw = readFileSync3(path, "utf8");
|
|
1514
1521
|
const out = [];
|
|
@@ -1538,7 +1545,7 @@ function appendSessionMessage(name, message) {
|
|
|
1538
1545
|
}
|
|
1539
1546
|
function listSessions() {
|
|
1540
1547
|
const dir = sessionsDir();
|
|
1541
|
-
if (!
|
|
1548
|
+
if (!existsSync3(dir)) return [];
|
|
1542
1549
|
try {
|
|
1543
1550
|
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1544
1551
|
return files.map((file) => {
|
|
@@ -1734,9 +1741,9 @@ var CacheFirstLoop = class {
|
|
|
1734
1741
|
this.sessionName = opts.session ?? null;
|
|
1735
1742
|
if (this.sessionName) {
|
|
1736
1743
|
const prior = loadSessionMessages(this.sessionName);
|
|
1737
|
-
const { messages, healedCount,
|
|
1744
|
+
const { messages, healedCount, tokensSaved } = healLoadedMessagesByTokens(
|
|
1738
1745
|
prior,
|
|
1739
|
-
|
|
1746
|
+
DEFAULT_MAX_RESULT_TOKENS
|
|
1740
1747
|
);
|
|
1741
1748
|
for (const msg of messages) this.log.append(msg);
|
|
1742
1749
|
this.resumedMessageCount = messages.length;
|
|
@@ -1746,7 +1753,7 @@ var CacheFirstLoop = class {
|
|
|
1746
1753
|
} catch {
|
|
1747
1754
|
}
|
|
1748
1755
|
process.stderr.write(
|
|
1749
|
-
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${
|
|
1756
|
+
`\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.
|
|
1750
1757
|
`
|
|
1751
1758
|
);
|
|
1752
1759
|
}
|
|
@@ -2015,8 +2022,8 @@ var CacheFirstLoop = class {
|
|
|
2015
2022
|
}
|
|
2016
2023
|
);
|
|
2017
2024
|
for (let k = 0; k < budget; k++) {
|
|
2018
|
-
const sample = queue.shift() ?? await new Promise((
|
|
2019
|
-
waiter =
|
|
2025
|
+
const sample = queue.shift() ?? await new Promise((resolve8) => {
|
|
2026
|
+
waiter = resolve8;
|
|
2020
2027
|
});
|
|
2021
2028
|
yield {
|
|
2022
2029
|
turn: this._turn,
|
|
@@ -2415,15 +2422,12 @@ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
|
|
|
2415
2422
|
});
|
|
2416
2423
|
return { messages: out, healedCount, tokensSaved, charsSaved };
|
|
2417
2424
|
}
|
|
2418
|
-
function
|
|
2419
|
-
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2420
|
-
let healedCount = shrunk.healedCount;
|
|
2425
|
+
function fixToolCallPairing(messages) {
|
|
2421
2426
|
const out = [];
|
|
2422
|
-
const openCallIds = /* @__PURE__ */ new Set();
|
|
2423
2427
|
let droppedAssistantCalls = 0;
|
|
2424
2428
|
let droppedStrayTools = 0;
|
|
2425
|
-
for (let i = 0; i <
|
|
2426
|
-
const msg =
|
|
2429
|
+
for (let i = 0; i < messages.length; i++) {
|
|
2430
|
+
const msg = messages[i];
|
|
2427
2431
|
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
2428
2432
|
const needed = /* @__PURE__ */ new Set();
|
|
2429
2433
|
for (const call of msg.tool_calls) {
|
|
@@ -2431,8 +2435,8 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2431
2435
|
}
|
|
2432
2436
|
const candidates = [];
|
|
2433
2437
|
let j = i + 1;
|
|
2434
|
-
while (j <
|
|
2435
|
-
const nxt =
|
|
2438
|
+
while (j < messages.length && needed.size > 0) {
|
|
2439
|
+
const nxt = messages[j];
|
|
2436
2440
|
if (nxt.role !== "tool") break;
|
|
2437
2441
|
const id = nxt.tool_call_id ?? "";
|
|
2438
2442
|
if (!needed.has(id)) break;
|
|
@@ -2457,8 +2461,24 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2457
2461
|
}
|
|
2458
2462
|
out.push(msg);
|
|
2459
2463
|
}
|
|
2460
|
-
|
|
2461
|
-
|
|
2464
|
+
return { messages: out, droppedAssistantCalls, droppedStrayTools };
|
|
2465
|
+
}
|
|
2466
|
+
function healLoadedMessages(messages, maxChars) {
|
|
2467
|
+
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2468
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2469
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2470
|
+
return { messages: paired.messages, healedCount, healedFrom: shrunk.healedFrom };
|
|
2471
|
+
}
|
|
2472
|
+
function healLoadedMessagesByTokens(messages, maxTokens) {
|
|
2473
|
+
const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);
|
|
2474
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2475
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2476
|
+
return {
|
|
2477
|
+
messages: paired.messages,
|
|
2478
|
+
healedCount,
|
|
2479
|
+
tokensSaved: shrunk.tokensSaved,
|
|
2480
|
+
charsSaved: shrunk.charsSaved
|
|
2481
|
+
};
|
|
2462
2482
|
}
|
|
2463
2483
|
function formatLoopError(err) {
|
|
2464
2484
|
const msg = err.message ?? "";
|
|
@@ -2470,17 +2490,174 @@ function formatLoopError(err) {
|
|
|
2470
2490
|
return msg;
|
|
2471
2491
|
}
|
|
2472
2492
|
|
|
2493
|
+
// src/at-mentions.ts
|
|
2494
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
2495
|
+
import { isAbsolute, join as join4, relative, resolve } from "path";
|
|
2496
|
+
var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
|
|
2497
|
+
var DEFAULT_PICKER_IGNORE_DIRS = [
|
|
2498
|
+
"node_modules",
|
|
2499
|
+
".git",
|
|
2500
|
+
"dist",
|
|
2501
|
+
"build",
|
|
2502
|
+
".next",
|
|
2503
|
+
"out",
|
|
2504
|
+
"coverage",
|
|
2505
|
+
".cache",
|
|
2506
|
+
".vscode",
|
|
2507
|
+
".idea",
|
|
2508
|
+
"target",
|
|
2509
|
+
".venv",
|
|
2510
|
+
"venv",
|
|
2511
|
+
"__pycache__"
|
|
2512
|
+
];
|
|
2513
|
+
function listFilesSync(root, opts = {}) {
|
|
2514
|
+
const maxResults = Math.max(1, opts.maxResults ?? 500);
|
|
2515
|
+
const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
2516
|
+
const rootAbs = resolve(root);
|
|
2517
|
+
const out = [];
|
|
2518
|
+
const walk2 = (dirAbs, dirRel) => {
|
|
2519
|
+
if (out.length >= maxResults) return;
|
|
2520
|
+
let entries;
|
|
2521
|
+
try {
|
|
2522
|
+
entries = readdirSync2(dirAbs, { withFileTypes: true });
|
|
2523
|
+
} catch {
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
2527
|
+
for (const ent of entries) {
|
|
2528
|
+
if (out.length >= maxResults) return;
|
|
2529
|
+
const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
|
|
2530
|
+
if (ent.isDirectory()) {
|
|
2531
|
+
if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
|
|
2532
|
+
walk2(join4(dirAbs, ent.name), relPath);
|
|
2533
|
+
} else if (ent.isFile()) {
|
|
2534
|
+
out.push(relPath);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2538
|
+
walk2(rootAbs, "");
|
|
2539
|
+
return out;
|
|
2540
|
+
}
|
|
2541
|
+
var AT_PICKER_PREFIX = /(?:^|\s)@([a-zA-Z0-9_./\\-]*)$/;
|
|
2542
|
+
function detectAtPicker(input) {
|
|
2543
|
+
const m = AT_PICKER_PREFIX.exec(input);
|
|
2544
|
+
if (!m) return null;
|
|
2545
|
+
const query = m[1] ?? "";
|
|
2546
|
+
const atOffset = input.length - query.length - 1;
|
|
2547
|
+
return { query, atOffset };
|
|
2548
|
+
}
|
|
2549
|
+
function rankPickerCandidates(files, query, limit = 40) {
|
|
2550
|
+
if (!query) return files.slice(0, limit);
|
|
2551
|
+
const needle = query.toLowerCase();
|
|
2552
|
+
const scored = [];
|
|
2553
|
+
for (const f of files) {
|
|
2554
|
+
const lower = f.toLowerCase();
|
|
2555
|
+
const hit = lower.indexOf(needle);
|
|
2556
|
+
if (hit < 0) continue;
|
|
2557
|
+
const slash = lower.lastIndexOf("/");
|
|
2558
|
+
const base = slash >= 0 ? lower.slice(slash + 1) : lower;
|
|
2559
|
+
let score = 2;
|
|
2560
|
+
if (base.startsWith(needle)) score = 0;
|
|
2561
|
+
else if (lower.startsWith(needle)) score = 1;
|
|
2562
|
+
scored.push({ path: f, score: score * 1e4 + hit });
|
|
2563
|
+
}
|
|
2564
|
+
scored.sort((a, b) => a.score - b.score);
|
|
2565
|
+
return scored.slice(0, limit).map((s) => s.path);
|
|
2566
|
+
}
|
|
2567
|
+
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
2568
|
+
function expandAtMentions(text, rootDir, opts = {}) {
|
|
2569
|
+
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
2570
|
+
const fs2 = opts.fs ?? defaultFs;
|
|
2571
|
+
const root = resolve(rootDir);
|
|
2572
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2573
|
+
const expansions = [];
|
|
2574
|
+
for (const match of text.matchAll(AT_MENTION_PATTERN)) {
|
|
2575
|
+
const rawPath = match[1] ?? "";
|
|
2576
|
+
const cleaned = rawPath.replace(/\.+$/, "");
|
|
2577
|
+
if (!cleaned) continue;
|
|
2578
|
+
const token = `@${cleaned}`;
|
|
2579
|
+
if (seen.has(token)) continue;
|
|
2580
|
+
const expansion = resolveMention(cleaned, root, maxBytes, fs2);
|
|
2581
|
+
seen.set(token, expansion);
|
|
2582
|
+
expansions.push(expansion);
|
|
2583
|
+
}
|
|
2584
|
+
if (expansions.length === 0) return { text, expansions };
|
|
2585
|
+
const blocks = [];
|
|
2586
|
+
for (const ex of expansions) {
|
|
2587
|
+
if (ex.ok) {
|
|
2588
|
+
const content = readSafe(root, ex.path, fs2);
|
|
2589
|
+
blocks.push(`<file path="${ex.path}">
|
|
2590
|
+
${content}
|
|
2591
|
+
</file>`);
|
|
2592
|
+
} else {
|
|
2593
|
+
blocks.push(`<file path="${ex.path}" skipped="${ex.skip}" />`);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
const augmented = `${text}
|
|
2597
|
+
|
|
2598
|
+
[Referenced files]
|
|
2599
|
+
${blocks.join("\n\n")}`;
|
|
2600
|
+
return { text: augmented, expansions };
|
|
2601
|
+
}
|
|
2602
|
+
function resolveMention(rawPath, root, maxBytes, fs2) {
|
|
2603
|
+
if (isAbsolute(rawPath)) {
|
|
2604
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2605
|
+
}
|
|
2606
|
+
const resolved = resolve(root, rawPath);
|
|
2607
|
+
const rel = relative(root, resolved);
|
|
2608
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
2609
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2610
|
+
}
|
|
2611
|
+
if (!fs2.exists(resolved)) {
|
|
2612
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "missing" };
|
|
2613
|
+
}
|
|
2614
|
+
if (!fs2.isFile(resolved)) {
|
|
2615
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
|
|
2616
|
+
}
|
|
2617
|
+
const size = fs2.size(resolved);
|
|
2618
|
+
if (size > maxBytes) {
|
|
2619
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "too-large", bytes: size };
|
|
2620
|
+
}
|
|
2621
|
+
return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };
|
|
2622
|
+
}
|
|
2623
|
+
function readSafe(root, rawPath, fs2) {
|
|
2624
|
+
const resolved = resolve(root, rawPath);
|
|
2625
|
+
try {
|
|
2626
|
+
return fs2.read(resolved);
|
|
2627
|
+
} catch {
|
|
2628
|
+
return "(read failed)";
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
var defaultFs = {
|
|
2632
|
+
exists: (p) => existsSync4(p),
|
|
2633
|
+
isFile: (p) => {
|
|
2634
|
+
try {
|
|
2635
|
+
return statSync2(p).isFile();
|
|
2636
|
+
} catch {
|
|
2637
|
+
return false;
|
|
2638
|
+
}
|
|
2639
|
+
},
|
|
2640
|
+
size: (p) => {
|
|
2641
|
+
try {
|
|
2642
|
+
return statSync2(p).size;
|
|
2643
|
+
} catch {
|
|
2644
|
+
return 0;
|
|
2645
|
+
}
|
|
2646
|
+
},
|
|
2647
|
+
read: (p) => readFileSync4(p, "utf8")
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2473
2650
|
// src/project-memory.ts
|
|
2474
|
-
import { existsSync as
|
|
2475
|
-
import { join as
|
|
2651
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
2652
|
+
import { join as join5 } from "path";
|
|
2476
2653
|
var PROJECT_MEMORY_FILE = "REASONIX.md";
|
|
2477
2654
|
var PROJECT_MEMORY_MAX_CHARS = 8e3;
|
|
2478
2655
|
function readProjectMemory(rootDir) {
|
|
2479
|
-
const path =
|
|
2480
|
-
if (!
|
|
2656
|
+
const path = join5(rootDir, PROJECT_MEMORY_FILE);
|
|
2657
|
+
if (!existsSync5(path)) return null;
|
|
2481
2658
|
let raw;
|
|
2482
2659
|
try {
|
|
2483
|
-
raw =
|
|
2660
|
+
raw = readFileSync5(path, "utf8");
|
|
2484
2661
|
} catch {
|
|
2485
2662
|
return null;
|
|
2486
2663
|
}
|
|
@@ -2516,20 +2693,20 @@ ${mem.content}
|
|
|
2516
2693
|
// src/user-memory.ts
|
|
2517
2694
|
import { createHash as createHash2 } from "crypto";
|
|
2518
2695
|
import {
|
|
2519
|
-
existsSync as
|
|
2696
|
+
existsSync as existsSync7,
|
|
2520
2697
|
mkdirSync as mkdirSync2,
|
|
2521
|
-
readFileSync as
|
|
2522
|
-
readdirSync as
|
|
2698
|
+
readFileSync as readFileSync7,
|
|
2699
|
+
readdirSync as readdirSync4,
|
|
2523
2700
|
unlinkSync as unlinkSync2,
|
|
2524
2701
|
writeFileSync as writeFileSync2
|
|
2525
2702
|
} from "fs";
|
|
2526
2703
|
import { homedir as homedir4 } from "os";
|
|
2527
|
-
import { join as
|
|
2704
|
+
import { join as join7, resolve as resolve3 } from "path";
|
|
2528
2705
|
|
|
2529
2706
|
// src/skills.ts
|
|
2530
|
-
import { existsSync as
|
|
2707
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
2531
2708
|
import { homedir as homedir3 } from "os";
|
|
2532
|
-
import { join as
|
|
2709
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
2533
2710
|
var SKILLS_DIRNAME = "skills";
|
|
2534
2711
|
var SKILL_FILE = "SKILL.md";
|
|
2535
2712
|
var SKILLS_INDEX_MAX_CHARS = 4e3;
|
|
@@ -2560,7 +2737,7 @@ var SkillStore = class {
|
|
|
2560
2737
|
disableBuiltins;
|
|
2561
2738
|
constructor(opts = {}) {
|
|
2562
2739
|
this.homeDir = opts.homeDir ?? homedir3();
|
|
2563
|
-
this.projectRoot = opts.projectRoot ?
|
|
2740
|
+
this.projectRoot = opts.projectRoot ? resolve2(opts.projectRoot) : void 0;
|
|
2564
2741
|
this.disableBuiltins = opts.disableBuiltins === true;
|
|
2565
2742
|
}
|
|
2566
2743
|
/** True iff this store was configured with a project root. */
|
|
@@ -2576,11 +2753,11 @@ var SkillStore = class {
|
|
|
2576
2753
|
const out = [];
|
|
2577
2754
|
if (this.projectRoot) {
|
|
2578
2755
|
out.push({
|
|
2579
|
-
dir:
|
|
2756
|
+
dir: join6(this.projectRoot, ".reasonix", SKILLS_DIRNAME),
|
|
2580
2757
|
scope: "project"
|
|
2581
2758
|
});
|
|
2582
2759
|
}
|
|
2583
|
-
out.push({ dir:
|
|
2760
|
+
out.push({ dir: join6(this.homeDir, ".reasonix", SKILLS_DIRNAME), scope: "global" });
|
|
2584
2761
|
return out;
|
|
2585
2762
|
}
|
|
2586
2763
|
/**
|
|
@@ -2591,10 +2768,10 @@ var SkillStore = class {
|
|
|
2591
2768
|
list() {
|
|
2592
2769
|
const byName = /* @__PURE__ */ new Map();
|
|
2593
2770
|
for (const { dir, scope } of this.roots()) {
|
|
2594
|
-
if (!
|
|
2771
|
+
if (!existsSync6(dir)) continue;
|
|
2595
2772
|
let entries;
|
|
2596
2773
|
try {
|
|
2597
|
-
entries =
|
|
2774
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
2598
2775
|
} catch {
|
|
2599
2776
|
continue;
|
|
2600
2777
|
}
|
|
@@ -2615,13 +2792,13 @@ var SkillStore = class {
|
|
|
2615
2792
|
read(name) {
|
|
2616
2793
|
if (!isValidSkillName(name)) return null;
|
|
2617
2794
|
for (const { dir, scope } of this.roots()) {
|
|
2618
|
-
if (!
|
|
2619
|
-
const dirCandidate =
|
|
2620
|
-
if (
|
|
2795
|
+
if (!existsSync6(dir)) continue;
|
|
2796
|
+
const dirCandidate = join6(dir, name, SKILL_FILE);
|
|
2797
|
+
if (existsSync6(dirCandidate) && statSync3(dirCandidate).isFile()) {
|
|
2621
2798
|
return this.parse(dirCandidate, name, scope);
|
|
2622
2799
|
}
|
|
2623
|
-
const flatCandidate =
|
|
2624
|
-
if (
|
|
2800
|
+
const flatCandidate = join6(dir, `${name}.md`);
|
|
2801
|
+
if (existsSync6(flatCandidate) && statSync3(flatCandidate).isFile()) {
|
|
2625
2802
|
return this.parse(flatCandidate, name, scope);
|
|
2626
2803
|
}
|
|
2627
2804
|
}
|
|
@@ -2635,21 +2812,21 @@ var SkillStore = class {
|
|
|
2635
2812
|
readEntry(dir, scope, entry) {
|
|
2636
2813
|
if (entry.isDirectory()) {
|
|
2637
2814
|
if (!isValidSkillName(entry.name)) return null;
|
|
2638
|
-
const file =
|
|
2639
|
-
if (!
|
|
2815
|
+
const file = join6(dir, entry.name, SKILL_FILE);
|
|
2816
|
+
if (!existsSync6(file)) return null;
|
|
2640
2817
|
return this.parse(file, entry.name, scope);
|
|
2641
2818
|
}
|
|
2642
2819
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2643
2820
|
const stem = entry.name.slice(0, -3);
|
|
2644
2821
|
if (!isValidSkillName(stem)) return null;
|
|
2645
|
-
return this.parse(
|
|
2822
|
+
return this.parse(join6(dir, entry.name), stem, scope);
|
|
2646
2823
|
}
|
|
2647
2824
|
return null;
|
|
2648
2825
|
}
|
|
2649
2826
|
parse(path, stem, scope) {
|
|
2650
2827
|
let raw;
|
|
2651
2828
|
try {
|
|
2652
|
-
raw =
|
|
2829
|
+
raw = readFileSync6(path, "utf8");
|
|
2653
2830
|
} catch {
|
|
2654
2831
|
return null;
|
|
2655
2832
|
}
|
|
@@ -2776,20 +2953,20 @@ function sanitizeMemoryName(raw) {
|
|
|
2776
2953
|
return trimmed;
|
|
2777
2954
|
}
|
|
2778
2955
|
function projectHash(rootDir) {
|
|
2779
|
-
const abs =
|
|
2956
|
+
const abs = resolve3(rootDir);
|
|
2780
2957
|
return createHash2("sha1").update(abs).digest("hex").slice(0, 16);
|
|
2781
2958
|
}
|
|
2782
2959
|
function scopeDir(opts) {
|
|
2783
2960
|
if (opts.scope === "global") {
|
|
2784
|
-
return
|
|
2961
|
+
return join7(opts.homeDir, USER_MEMORY_DIR, "global");
|
|
2785
2962
|
}
|
|
2786
2963
|
if (!opts.projectRoot) {
|
|
2787
2964
|
throw new Error("scope=project requires a projectRoot on MemoryStore");
|
|
2788
2965
|
}
|
|
2789
|
-
return
|
|
2966
|
+
return join7(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
|
|
2790
2967
|
}
|
|
2791
2968
|
function ensureDir(p) {
|
|
2792
|
-
if (!
|
|
2969
|
+
if (!existsSync7(p)) mkdirSync2(p, { recursive: true });
|
|
2793
2970
|
}
|
|
2794
2971
|
function parseFrontmatter2(raw) {
|
|
2795
2972
|
const lines = raw.split(/\r?\n/);
|
|
@@ -2834,8 +3011,8 @@ var MemoryStore = class {
|
|
|
2834
3011
|
homeDir;
|
|
2835
3012
|
projectRoot;
|
|
2836
3013
|
constructor(opts = {}) {
|
|
2837
|
-
this.homeDir = opts.homeDir ??
|
|
2838
|
-
this.projectRoot = opts.projectRoot ?
|
|
3014
|
+
this.homeDir = opts.homeDir ?? join7(homedir4(), ".reasonix");
|
|
3015
|
+
this.projectRoot = opts.projectRoot ? resolve3(opts.projectRoot) : void 0;
|
|
2839
3016
|
}
|
|
2840
3017
|
/** Directory this store writes `scope` files into, creating it if needed. */
|
|
2841
3018
|
dir(scope) {
|
|
@@ -2845,7 +3022,7 @@ var MemoryStore = class {
|
|
|
2845
3022
|
}
|
|
2846
3023
|
/** Absolute path to a memory file (no existence check). */
|
|
2847
3024
|
pathFor(scope, name) {
|
|
2848
|
-
return
|
|
3025
|
+
return join7(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
|
|
2849
3026
|
}
|
|
2850
3027
|
/** True iff this store is configured with a project scope available. */
|
|
2851
3028
|
hasProjectScope() {
|
|
@@ -2857,14 +3034,14 @@ var MemoryStore = class {
|
|
|
2857
3034
|
*/
|
|
2858
3035
|
loadIndex(scope) {
|
|
2859
3036
|
if (scope === "project" && !this.projectRoot) return null;
|
|
2860
|
-
const file =
|
|
3037
|
+
const file = join7(
|
|
2861
3038
|
scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
|
|
2862
3039
|
MEMORY_INDEX_FILE
|
|
2863
3040
|
);
|
|
2864
|
-
if (!
|
|
3041
|
+
if (!existsSync7(file)) return null;
|
|
2865
3042
|
let raw;
|
|
2866
3043
|
try {
|
|
2867
|
-
raw =
|
|
3044
|
+
raw = readFileSync7(file, "utf8");
|
|
2868
3045
|
} catch {
|
|
2869
3046
|
return null;
|
|
2870
3047
|
}
|
|
@@ -2879,10 +3056,10 @@ var MemoryStore = class {
|
|
|
2879
3056
|
/** Read one memory file's body (frontmatter stripped). Throws if missing. */
|
|
2880
3057
|
read(scope, name) {
|
|
2881
3058
|
const file = this.pathFor(scope, name);
|
|
2882
|
-
if (!
|
|
3059
|
+
if (!existsSync7(file)) {
|
|
2883
3060
|
throw new Error(`memory not found: scope=${scope} name=${name}`);
|
|
2884
3061
|
}
|
|
2885
|
-
const raw =
|
|
3062
|
+
const raw = readFileSync7(file, "utf8");
|
|
2886
3063
|
const { data, body } = parseFrontmatter2(raw);
|
|
2887
3064
|
return {
|
|
2888
3065
|
name: data.name ?? name,
|
|
@@ -2903,10 +3080,10 @@ var MemoryStore = class {
|
|
|
2903
3080
|
const scopes = this.projectRoot ? ["global", "project"] : ["global"];
|
|
2904
3081
|
for (const scope of scopes) {
|
|
2905
3082
|
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
2906
|
-
if (!
|
|
3083
|
+
if (!existsSync7(dir)) continue;
|
|
2907
3084
|
let entries;
|
|
2908
3085
|
try {
|
|
2909
|
-
entries =
|
|
3086
|
+
entries = readdirSync4(dir);
|
|
2910
3087
|
} catch {
|
|
2911
3088
|
continue;
|
|
2912
3089
|
}
|
|
@@ -2944,7 +3121,7 @@ var MemoryStore = class {
|
|
|
2944
3121
|
createdAt: todayIso()
|
|
2945
3122
|
};
|
|
2946
3123
|
const dir = this.dir(input.scope);
|
|
2947
|
-
const file =
|
|
3124
|
+
const file = join7(dir, `${name}.md`);
|
|
2948
3125
|
const content = `${formatFrontmatter(entry)}${body}
|
|
2949
3126
|
`;
|
|
2950
3127
|
writeFileSync2(file, content, "utf8");
|
|
@@ -2957,7 +3134,7 @@ var MemoryStore = class {
|
|
|
2957
3134
|
throw new Error("cannot delete project-scoped memory: no projectRoot configured");
|
|
2958
3135
|
}
|
|
2959
3136
|
const file = this.pathFor(scope, rawName);
|
|
2960
|
-
if (!
|
|
3137
|
+
if (!existsSync7(file)) return false;
|
|
2961
3138
|
unlinkSync2(file);
|
|
2962
3139
|
this.regenerateIndex(scope);
|
|
2963
3140
|
return true;
|
|
@@ -2970,17 +3147,17 @@ var MemoryStore = class {
|
|
|
2970
3147
|
*/
|
|
2971
3148
|
regenerateIndex(scope) {
|
|
2972
3149
|
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
2973
|
-
if (!
|
|
3150
|
+
if (!existsSync7(dir)) return;
|
|
2974
3151
|
let files;
|
|
2975
3152
|
try {
|
|
2976
|
-
files =
|
|
3153
|
+
files = readdirSync4(dir);
|
|
2977
3154
|
} catch {
|
|
2978
3155
|
return;
|
|
2979
3156
|
}
|
|
2980
3157
|
const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
|
|
2981
|
-
const indexPath =
|
|
3158
|
+
const indexPath = join7(dir, MEMORY_INDEX_FILE);
|
|
2982
3159
|
if (mdFiles.length === 0) {
|
|
2983
|
-
if (
|
|
3160
|
+
if (existsSync7(indexPath)) unlinkSync2(indexPath);
|
|
2984
3161
|
return;
|
|
2985
3162
|
}
|
|
2986
3163
|
const lines = [];
|
|
@@ -3914,7 +4091,7 @@ function forkRegistryExcluding(parent, exclude) {
|
|
|
3914
4091
|
|
|
3915
4092
|
// src/tools/shell.ts
|
|
3916
4093
|
import { spawn as spawn2 } from "child_process";
|
|
3917
|
-
import { existsSync as
|
|
4094
|
+
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
3918
4095
|
import * as pathMod2 from "path";
|
|
3919
4096
|
var DEFAULT_TIMEOUT_SEC = 60;
|
|
3920
4097
|
var DEFAULT_MAX_OUTPUT_CHARS = 32e3;
|
|
@@ -4084,7 +4261,7 @@ async function runCommand(cmd, opts) {
|
|
|
4084
4261
|
};
|
|
4085
4262
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
4086
4263
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
4087
|
-
return await new Promise((
|
|
4264
|
+
return await new Promise((resolve8, reject) => {
|
|
4088
4265
|
let child;
|
|
4089
4266
|
try {
|
|
4090
4267
|
child = spawn2(bin, args, effectiveSpawnOpts);
|
|
@@ -4117,7 +4294,7 @@ async function runCommand(cmd, opts) {
|
|
|
4117
4294
|
const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
|
|
4118
4295
|
|
|
4119
4296
|
[\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
|
|
4120
|
-
|
|
4297
|
+
resolve8({ exitCode: code, output, timedOut });
|
|
4121
4298
|
});
|
|
4122
4299
|
});
|
|
4123
4300
|
}
|
|
@@ -4142,7 +4319,7 @@ function resolveExecutable(cmd, opts = {}) {
|
|
|
4142
4319
|
}
|
|
4143
4320
|
function defaultIsFile(full) {
|
|
4144
4321
|
try {
|
|
4145
|
-
return
|
|
4322
|
+
return existsSync8(full) && statSync4(full).isFile();
|
|
4146
4323
|
} catch {
|
|
4147
4324
|
return false;
|
|
4148
4325
|
}
|
|
@@ -4469,12 +4646,12 @@ ${i + 1}. ${r.title}`);
|
|
|
4469
4646
|
}
|
|
4470
4647
|
|
|
4471
4648
|
// src/env.ts
|
|
4472
|
-
import { readFileSync as
|
|
4473
|
-
import { resolve as
|
|
4649
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
4650
|
+
import { resolve as resolve6 } from "path";
|
|
4474
4651
|
function loadDotenv(path = ".env") {
|
|
4475
4652
|
let raw;
|
|
4476
4653
|
try {
|
|
4477
|
-
raw =
|
|
4654
|
+
raw = readFileSync8(resolve6(process.cwd(), path), "utf8");
|
|
4478
4655
|
} catch {
|
|
4479
4656
|
return;
|
|
4480
4657
|
}
|
|
@@ -4493,7 +4670,7 @@ function loadDotenv(path = ".env") {
|
|
|
4493
4670
|
}
|
|
4494
4671
|
|
|
4495
4672
|
// src/transcript.ts
|
|
4496
|
-
import { createWriteStream, readFileSync as
|
|
4673
|
+
import { createWriteStream, readFileSync as readFileSync9 } from "fs";
|
|
4497
4674
|
function recordFromLoopEvent(ev, extra) {
|
|
4498
4675
|
const rec = {
|
|
4499
4676
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4544,7 +4721,7 @@ function openTranscriptFile(path, meta) {
|
|
|
4544
4721
|
return stream;
|
|
4545
4722
|
}
|
|
4546
4723
|
function readTranscript(path) {
|
|
4547
|
-
const raw =
|
|
4724
|
+
const raw = readFileSync9(path, "utf8");
|
|
4548
4725
|
return parseTranscript(raw);
|
|
4549
4726
|
}
|
|
4550
4727
|
function isPlanStateEmptyShape(s) {
|
|
@@ -5156,7 +5333,7 @@ var McpClient = class {
|
|
|
5156
5333
|
const id = this.nextId++;
|
|
5157
5334
|
const frame = { jsonrpc: "2.0", id, method, params };
|
|
5158
5335
|
let abortHandler = null;
|
|
5159
|
-
const promise = new Promise((
|
|
5336
|
+
const promise = new Promise((resolve8, reject) => {
|
|
5160
5337
|
const timeout = setTimeout(() => {
|
|
5161
5338
|
this.pending.delete(id);
|
|
5162
5339
|
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
@@ -5165,7 +5342,7 @@ var McpClient = class {
|
|
|
5165
5342
|
);
|
|
5166
5343
|
}, this.requestTimeoutMs);
|
|
5167
5344
|
this.pending.set(id, {
|
|
5168
|
-
resolve:
|
|
5345
|
+
resolve: resolve8,
|
|
5169
5346
|
reject,
|
|
5170
5347
|
timeout
|
|
5171
5348
|
});
|
|
@@ -5288,12 +5465,12 @@ var StdioTransport = class {
|
|
|
5288
5465
|
}
|
|
5289
5466
|
async send(message) {
|
|
5290
5467
|
if (this.closed) throw new Error("MCP transport is closed");
|
|
5291
|
-
return new Promise((
|
|
5468
|
+
return new Promise((resolve8, reject) => {
|
|
5292
5469
|
const line = `${JSON.stringify(message)}
|
|
5293
5470
|
`;
|
|
5294
5471
|
this.child.stdin.write(line, "utf8", (err) => {
|
|
5295
5472
|
if (err) reject(err);
|
|
5296
|
-
else
|
|
5473
|
+
else resolve8();
|
|
5297
5474
|
});
|
|
5298
5475
|
});
|
|
5299
5476
|
}
|
|
@@ -5304,8 +5481,8 @@ var StdioTransport = class {
|
|
|
5304
5481
|
continue;
|
|
5305
5482
|
}
|
|
5306
5483
|
if (this.closed) return;
|
|
5307
|
-
const next = await new Promise((
|
|
5308
|
-
this.waiters.push(
|
|
5484
|
+
const next = await new Promise((resolve8) => {
|
|
5485
|
+
this.waiters.push(resolve8);
|
|
5309
5486
|
});
|
|
5310
5487
|
if (next === null) return;
|
|
5311
5488
|
yield next;
|
|
@@ -5371,8 +5548,8 @@ var SseTransport = class {
|
|
|
5371
5548
|
constructor(opts) {
|
|
5372
5549
|
this.url = opts.url;
|
|
5373
5550
|
this.headers = opts.headers ?? {};
|
|
5374
|
-
this.endpointReady = new Promise((
|
|
5375
|
-
this.resolveEndpoint =
|
|
5551
|
+
this.endpointReady = new Promise((resolve8, reject) => {
|
|
5552
|
+
this.resolveEndpoint = resolve8;
|
|
5376
5553
|
this.rejectEndpoint = reject;
|
|
5377
5554
|
});
|
|
5378
5555
|
this.endpointReady.catch(() => void 0);
|
|
@@ -5399,8 +5576,8 @@ var SseTransport = class {
|
|
|
5399
5576
|
continue;
|
|
5400
5577
|
}
|
|
5401
5578
|
if (this.closed) return;
|
|
5402
|
-
const next = await new Promise((
|
|
5403
|
-
this.waiters.push(
|
|
5579
|
+
const next = await new Promise((resolve8) => {
|
|
5580
|
+
this.waiters.push(resolve8);
|
|
5404
5581
|
});
|
|
5405
5582
|
if (next === null) return;
|
|
5406
5583
|
yield next;
|
|
@@ -5599,8 +5776,8 @@ async function trySection(load) {
|
|
|
5599
5776
|
}
|
|
5600
5777
|
|
|
5601
5778
|
// src/code/edit-blocks.ts
|
|
5602
|
-
import { existsSync as
|
|
5603
|
-
import { dirname as dirname4, resolve as
|
|
5779
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5780
|
+
import { dirname as dirname4, resolve as resolve7 } from "path";
|
|
5604
5781
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
5605
5782
|
function parseEditBlocks(text) {
|
|
5606
5783
|
const out = [];
|
|
@@ -5618,8 +5795,8 @@ function parseEditBlocks(text) {
|
|
|
5618
5795
|
return out;
|
|
5619
5796
|
}
|
|
5620
5797
|
function applyEditBlock(block, rootDir) {
|
|
5621
|
-
const absRoot =
|
|
5622
|
-
const absTarget =
|
|
5798
|
+
const absRoot = resolve7(rootDir);
|
|
5799
|
+
const absTarget = resolve7(absRoot, block.path);
|
|
5623
5800
|
if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {
|
|
5624
5801
|
return {
|
|
5625
5802
|
path: block.path,
|
|
@@ -5628,7 +5805,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5628
5805
|
};
|
|
5629
5806
|
}
|
|
5630
5807
|
const searchEmpty = block.search.length === 0;
|
|
5631
|
-
const exists =
|
|
5808
|
+
const exists = existsSync9(absTarget);
|
|
5632
5809
|
try {
|
|
5633
5810
|
if (!exists) {
|
|
5634
5811
|
if (!searchEmpty) {
|
|
@@ -5642,7 +5819,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5642
5819
|
writeFileSync3(absTarget, block.replace, "utf8");
|
|
5643
5820
|
return { path: block.path, status: "created" };
|
|
5644
5821
|
}
|
|
5645
|
-
const content =
|
|
5822
|
+
const content = readFileSync10(absTarget, "utf8");
|
|
5646
5823
|
if (searchEmpty) {
|
|
5647
5824
|
return {
|
|
5648
5825
|
path: block.path,
|
|
@@ -5669,19 +5846,19 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
5669
5846
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
5670
5847
|
}
|
|
5671
5848
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
5672
|
-
const absRoot =
|
|
5849
|
+
const absRoot = resolve7(rootDir);
|
|
5673
5850
|
const seen = /* @__PURE__ */ new Set();
|
|
5674
5851
|
const snapshots = [];
|
|
5675
5852
|
for (const b of blocks) {
|
|
5676
5853
|
if (seen.has(b.path)) continue;
|
|
5677
5854
|
seen.add(b.path);
|
|
5678
|
-
const abs =
|
|
5679
|
-
if (!
|
|
5855
|
+
const abs = resolve7(absRoot, b.path);
|
|
5856
|
+
if (!existsSync9(abs)) {
|
|
5680
5857
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5681
5858
|
continue;
|
|
5682
5859
|
}
|
|
5683
5860
|
try {
|
|
5684
|
-
snapshots.push({ path: b.path, prevContent:
|
|
5861
|
+
snapshots.push({ path: b.path, prevContent: readFileSync10(abs, "utf8") });
|
|
5685
5862
|
} catch {
|
|
5686
5863
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5687
5864
|
}
|
|
@@ -5689,9 +5866,9 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
5689
5866
|
return snapshots;
|
|
5690
5867
|
}
|
|
5691
5868
|
function restoreSnapshots(snapshots, rootDir) {
|
|
5692
|
-
const absRoot =
|
|
5869
|
+
const absRoot = resolve7(rootDir);
|
|
5693
5870
|
return snapshots.map((snap) => {
|
|
5694
|
-
const abs =
|
|
5871
|
+
const abs = resolve7(absRoot, snap.path);
|
|
5695
5872
|
if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {
|
|
5696
5873
|
return {
|
|
5697
5874
|
path: snap.path,
|
|
@@ -5701,7 +5878,7 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
5701
5878
|
}
|
|
5702
5879
|
try {
|
|
5703
5880
|
if (snap.prevContent === null) {
|
|
5704
|
-
if (
|
|
5881
|
+
if (existsSync9(abs)) unlinkSync3(abs);
|
|
5705
5882
|
return {
|
|
5706
5883
|
path: snap.path,
|
|
5707
5884
|
status: "applied",
|
|
@@ -5724,8 +5901,8 @@ function sep() {
|
|
|
5724
5901
|
}
|
|
5725
5902
|
|
|
5726
5903
|
// src/code/prompt.ts
|
|
5727
|
-
import { existsSync as
|
|
5728
|
-
import { join as
|
|
5904
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "fs";
|
|
5905
|
+
import { join as join9 } from "path";
|
|
5729
5906
|
var CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, list_directory, search_files, etc.) rooted at the user's working directory.
|
|
5730
5907
|
|
|
5731
5908
|
# Cite or shut up \u2014 non-negotiable
|
|
@@ -5846,11 +6023,11 @@ Two different rules depending on which tool:
|
|
|
5846
6023
|
`;
|
|
5847
6024
|
function codeSystemPrompt(rootDir) {
|
|
5848
6025
|
const withMemory = applyMemoryStack(CODE_SYSTEM_PROMPT, rootDir);
|
|
5849
|
-
const gitignorePath =
|
|
5850
|
-
if (!
|
|
6026
|
+
const gitignorePath = join9(rootDir, ".gitignore");
|
|
6027
|
+
if (!existsSync10(gitignorePath)) return withMemory;
|
|
5851
6028
|
let content;
|
|
5852
6029
|
try {
|
|
5853
|
-
content =
|
|
6030
|
+
content = readFileSync11(gitignorePath, "utf8");
|
|
5854
6031
|
} catch {
|
|
5855
6032
|
return withMemory;
|
|
5856
6033
|
}
|
|
@@ -5870,15 +6047,15 @@ ${truncated}
|
|
|
5870
6047
|
}
|
|
5871
6048
|
|
|
5872
6049
|
// src/config.ts
|
|
5873
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as
|
|
6050
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
5874
6051
|
import { homedir as homedir5 } from "os";
|
|
5875
|
-
import { dirname as dirname5, join as
|
|
6052
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
5876
6053
|
function defaultConfigPath() {
|
|
5877
|
-
return
|
|
6054
|
+
return join10(homedir5(), ".reasonix", "config.json");
|
|
5878
6055
|
}
|
|
5879
6056
|
function readConfig(path = defaultConfigPath()) {
|
|
5880
6057
|
try {
|
|
5881
|
-
const raw =
|
|
6058
|
+
const raw = readFileSync12(path, "utf8");
|
|
5882
6059
|
const parsed = JSON.parse(raw);
|
|
5883
6060
|
if (parsed && typeof parsed === "object") return parsed;
|
|
5884
6061
|
} catch {
|
|
@@ -5913,9 +6090,9 @@ function redactKey(key) {
|
|
|
5913
6090
|
}
|
|
5914
6091
|
|
|
5915
6092
|
// src/version.ts
|
|
5916
|
-
import { existsSync as
|
|
6093
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
5917
6094
|
import { homedir as homedir6 } from "os";
|
|
5918
|
-
import { dirname as dirname6, join as
|
|
6095
|
+
import { dirname as dirname6, join as join11 } from "path";
|
|
5919
6096
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5920
6097
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
5921
6098
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -5924,9 +6101,9 @@ function readPackageVersion() {
|
|
|
5924
6101
|
try {
|
|
5925
6102
|
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
5926
6103
|
for (let i = 0; i < 6; i++) {
|
|
5927
|
-
const p =
|
|
5928
|
-
if (
|
|
5929
|
-
const pkg = JSON.parse(
|
|
6104
|
+
const p = join11(dir, "package.json");
|
|
6105
|
+
if (existsSync11(p)) {
|
|
6106
|
+
const pkg = JSON.parse(readFileSync13(p, "utf8"));
|
|
5930
6107
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
5931
6108
|
return pkg.version;
|
|
5932
6109
|
}
|
|
@@ -5941,11 +6118,11 @@ function readPackageVersion() {
|
|
|
5941
6118
|
}
|
|
5942
6119
|
var VERSION = readPackageVersion();
|
|
5943
6120
|
function cachePath(homeDirOverride) {
|
|
5944
|
-
return
|
|
6121
|
+
return join11(homeDirOverride ?? homedir6(), ".reasonix", "version-cache.json");
|
|
5945
6122
|
}
|
|
5946
6123
|
function readCache(homeDirOverride) {
|
|
5947
6124
|
try {
|
|
5948
|
-
const raw =
|
|
6125
|
+
const raw = readFileSync13(cachePath(homeDirOverride), "utf8");
|
|
5949
6126
|
const parsed = JSON.parse(raw);
|
|
5950
6127
|
if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
|
|
5951
6128
|
return parsed;
|
|
@@ -6014,11 +6191,11 @@ function isNpxInstall() {
|
|
|
6014
6191
|
}
|
|
6015
6192
|
|
|
6016
6193
|
// src/usage.ts
|
|
6017
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
6194
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync14, statSync as statSync5 } from "fs";
|
|
6018
6195
|
import { homedir as homedir7 } from "os";
|
|
6019
|
-
import { dirname as dirname7, join as
|
|
6196
|
+
import { dirname as dirname7, join as join12 } from "path";
|
|
6020
6197
|
function defaultUsageLogPath(homeDirOverride) {
|
|
6021
|
-
return
|
|
6198
|
+
return join12(homeDirOverride ?? homedir7(), ".reasonix", "usage.jsonl");
|
|
6022
6199
|
}
|
|
6023
6200
|
function appendUsage(input) {
|
|
6024
6201
|
const record = {
|
|
@@ -6042,10 +6219,10 @@ function appendUsage(input) {
|
|
|
6042
6219
|
return record;
|
|
6043
6220
|
}
|
|
6044
6221
|
function readUsageLog(path = defaultUsageLogPath()) {
|
|
6045
|
-
if (!
|
|
6222
|
+
if (!existsSync12(path)) return [];
|
|
6046
6223
|
let raw;
|
|
6047
6224
|
try {
|
|
6048
|
-
raw =
|
|
6225
|
+
raw = readFileSync14(path, "utf8");
|
|
6049
6226
|
} catch {
|
|
6050
6227
|
return [];
|
|
6051
6228
|
}
|
|
@@ -6127,9 +6304,9 @@ function aggregateUsage(records, opts = {}) {
|
|
|
6127
6304
|
};
|
|
6128
6305
|
}
|
|
6129
6306
|
function formatLogSize(path = defaultUsageLogPath()) {
|
|
6130
|
-
if (!
|
|
6307
|
+
if (!existsSync12(path)) return "";
|
|
6131
6308
|
try {
|
|
6132
|
-
const s =
|
|
6309
|
+
const s = statSync5(path);
|
|
6133
6310
|
const bytes = s.size;
|
|
6134
6311
|
if (bytes < 1024) return `${bytes} B`;
|
|
6135
6312
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -6139,11 +6316,15 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
6139
6316
|
}
|
|
6140
6317
|
}
|
|
6141
6318
|
export {
|
|
6319
|
+
AT_MENTION_PATTERN,
|
|
6320
|
+
AT_PICKER_PREFIX,
|
|
6142
6321
|
AppendOnlyLog,
|
|
6143
6322
|
CODE_SYSTEM_PROMPT,
|
|
6144
6323
|
CacheFirstLoop,
|
|
6324
|
+
DEFAULT_AT_MENTION_MAX_BYTES,
|
|
6145
6325
|
DEFAULT_MAX_RESULT_CHARS,
|
|
6146
6326
|
DEFAULT_MAX_RESULT_TOKENS,
|
|
6327
|
+
DEFAULT_PICKER_IGNORE_DIRS,
|
|
6147
6328
|
DeepSeekClient,
|
|
6148
6329
|
HOOK_EVENTS,
|
|
6149
6330
|
HOOK_SETTINGS_DIRNAME,
|
|
@@ -6193,10 +6374,13 @@ export {
|
|
|
6193
6374
|
defaultSelector,
|
|
6194
6375
|
defaultUsageLogPath,
|
|
6195
6376
|
deleteSession,
|
|
6377
|
+
detectAtPicker,
|
|
6196
6378
|
detectShellOperator,
|
|
6197
6379
|
diffTranscripts,
|
|
6198
6380
|
emptyPlanState,
|
|
6381
|
+
expandAtMentions,
|
|
6199
6382
|
fetchWithRetry,
|
|
6383
|
+
fixToolCallPairing,
|
|
6200
6384
|
flattenMcpResult,
|
|
6201
6385
|
flattenSchema,
|
|
6202
6386
|
forkRegistryExcluding,
|
|
@@ -6209,6 +6393,7 @@ export {
|
|
|
6209
6393
|
globalSettingsPath,
|
|
6210
6394
|
harvest,
|
|
6211
6395
|
healLoadedMessages,
|
|
6396
|
+
healLoadedMessagesByTokens,
|
|
6212
6397
|
htmlToText,
|
|
6213
6398
|
injectPowerShellUtf8,
|
|
6214
6399
|
inputCostUsd,
|
|
@@ -6218,6 +6403,7 @@ export {
|
|
|
6218
6403
|
isNpxInstall,
|
|
6219
6404
|
isPlanStateEmpty,
|
|
6220
6405
|
isPlausibleKey,
|
|
6406
|
+
listFilesSync,
|
|
6221
6407
|
listSessions,
|
|
6222
6408
|
loadApiKey,
|
|
6223
6409
|
loadDotenv,
|
|
@@ -6236,6 +6422,7 @@ export {
|
|
|
6236
6422
|
projectHash,
|
|
6237
6423
|
projectSettingsPath,
|
|
6238
6424
|
quoteForCmdExe,
|
|
6425
|
+
rankPickerCandidates,
|
|
6239
6426
|
readConfig,
|
|
6240
6427
|
readProjectMemory,
|
|
6241
6428
|
readTranscript,
|