reasonix 0.5.0 → 0.5.2
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 +317 -204
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.js +351 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -617,6 +617,170 @@ async function runHooks(opts) {
|
|
|
617
617
|
return { event, outcomes, blocked };
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
+
// src/tokenizer.ts
|
|
621
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
622
|
+
import { createRequire } from "module";
|
|
623
|
+
import { dirname, join as join2 } from "path";
|
|
624
|
+
import { fileURLToPath } from "url";
|
|
625
|
+
import { gunzipSync } from "zlib";
|
|
626
|
+
function buildByteToChar() {
|
|
627
|
+
const result = new Array(256);
|
|
628
|
+
const bs = [];
|
|
629
|
+
for (let b = 33; b <= 126; b++) bs.push(b);
|
|
630
|
+
for (let b = 161; b <= 172; b++) bs.push(b);
|
|
631
|
+
for (let b = 174; b <= 255; b++) bs.push(b);
|
|
632
|
+
const cs = bs.slice();
|
|
633
|
+
let n = 0;
|
|
634
|
+
for (let b = 0; b < 256; b++) {
|
|
635
|
+
if (!bs.includes(b)) {
|
|
636
|
+
bs.push(b);
|
|
637
|
+
cs.push(256 + n);
|
|
638
|
+
n++;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
for (let i = 0; i < bs.length; i++) {
|
|
642
|
+
result[bs[i]] = String.fromCodePoint(cs[i]);
|
|
643
|
+
}
|
|
644
|
+
return result;
|
|
645
|
+
}
|
|
646
|
+
var cached = null;
|
|
647
|
+
function resolveDataPath() {
|
|
648
|
+
if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
|
|
649
|
+
try {
|
|
650
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
651
|
+
return join2(here, "..", "data", "deepseek-tokenizer.json.gz");
|
|
652
|
+
} catch {
|
|
653
|
+
const req = createRequire(import.meta.url);
|
|
654
|
+
return join2(
|
|
655
|
+
dirname(req.resolve("reasonix/package.json")),
|
|
656
|
+
"data",
|
|
657
|
+
"deepseek-tokenizer.json.gz"
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function loadTokenizer() {
|
|
662
|
+
if (cached) return cached;
|
|
663
|
+
const buf = readFileSync2(resolveDataPath());
|
|
664
|
+
const json = gunzipSync(buf).toString("utf8");
|
|
665
|
+
const data = JSON.parse(json);
|
|
666
|
+
const mergeRank = /* @__PURE__ */ new Map();
|
|
667
|
+
for (let i = 0; i < data.model.merges.length; i++) {
|
|
668
|
+
mergeRank.set(data.model.merges[i], i);
|
|
669
|
+
}
|
|
670
|
+
const splitRegexes = [];
|
|
671
|
+
for (const p of data.pre_tokenizer.pretokenizers) {
|
|
672
|
+
if (p.type === "Split") {
|
|
673
|
+
splitRegexes.push(new RegExp(p.pattern.Regex, "gu"));
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const addedMap = /* @__PURE__ */ new Map();
|
|
677
|
+
const addedContents = [];
|
|
678
|
+
for (const t of data.added_tokens) {
|
|
679
|
+
if (!t.special) {
|
|
680
|
+
addedMap.set(t.content, t.id);
|
|
681
|
+
addedContents.push(t.content);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
addedContents.sort((a, b) => b.length - a.length);
|
|
685
|
+
const addedPattern = addedContents.length ? new RegExp(addedContents.map(escapeRegex).join("|"), "g") : null;
|
|
686
|
+
cached = {
|
|
687
|
+
vocab: data.model.vocab,
|
|
688
|
+
mergeRank,
|
|
689
|
+
splitRegexes,
|
|
690
|
+
byteToChar: buildByteToChar(),
|
|
691
|
+
addedPattern,
|
|
692
|
+
addedMap
|
|
693
|
+
};
|
|
694
|
+
return cached;
|
|
695
|
+
}
|
|
696
|
+
function escapeRegex(s) {
|
|
697
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
698
|
+
}
|
|
699
|
+
function applySplit(chunks, re) {
|
|
700
|
+
const out = [];
|
|
701
|
+
for (const chunk of chunks) {
|
|
702
|
+
if (!chunk) continue;
|
|
703
|
+
re.lastIndex = 0;
|
|
704
|
+
let last = 0;
|
|
705
|
+
for (const m of chunk.matchAll(re)) {
|
|
706
|
+
const idx = m.index ?? 0;
|
|
707
|
+
if (idx > last) out.push(chunk.slice(last, idx));
|
|
708
|
+
if (m[0].length > 0) out.push(m[0]);
|
|
709
|
+
last = idx + m[0].length;
|
|
710
|
+
}
|
|
711
|
+
if (last < chunk.length) out.push(chunk.slice(last));
|
|
712
|
+
}
|
|
713
|
+
return out;
|
|
714
|
+
}
|
|
715
|
+
function byteLevelEncode(s, byteToChar) {
|
|
716
|
+
const bytes = new TextEncoder().encode(s);
|
|
717
|
+
let out = "";
|
|
718
|
+
for (let i = 0; i < bytes.length; i++) out += byteToChar[bytes[i]];
|
|
719
|
+
return out;
|
|
720
|
+
}
|
|
721
|
+
function bpeEncode(piece, mergeRank) {
|
|
722
|
+
if (piece.length <= 1) return piece ? [piece] : [];
|
|
723
|
+
let word = Array.from(piece);
|
|
724
|
+
while (true) {
|
|
725
|
+
let bestIdx = -1;
|
|
726
|
+
let bestRank = Number.POSITIVE_INFINITY;
|
|
727
|
+
for (let i = 0; i < word.length - 1; i++) {
|
|
728
|
+
const pair = `${word[i]} ${word[i + 1]}`;
|
|
729
|
+
const rank = mergeRank.get(pair);
|
|
730
|
+
if (rank !== void 0 && rank < bestRank) {
|
|
731
|
+
bestRank = rank;
|
|
732
|
+
bestIdx = i;
|
|
733
|
+
if (rank === 0) break;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (bestIdx < 0) break;
|
|
737
|
+
word = [
|
|
738
|
+
...word.slice(0, bestIdx),
|
|
739
|
+
word[bestIdx] + word[bestIdx + 1],
|
|
740
|
+
...word.slice(bestIdx + 2)
|
|
741
|
+
];
|
|
742
|
+
if (word.length === 1) break;
|
|
743
|
+
}
|
|
744
|
+
return word;
|
|
745
|
+
}
|
|
746
|
+
function encode(text) {
|
|
747
|
+
if (!text) return [];
|
|
748
|
+
const t = loadTokenizer();
|
|
749
|
+
const ids = [];
|
|
750
|
+
const process2 = (segment) => {
|
|
751
|
+
if (!segment) return;
|
|
752
|
+
let chunks = [segment];
|
|
753
|
+
for (const re of t.splitRegexes) chunks = applySplit(chunks, re);
|
|
754
|
+
for (const chunk of chunks) {
|
|
755
|
+
if (!chunk) continue;
|
|
756
|
+
const byteLevel = byteLevelEncode(chunk, t.byteToChar);
|
|
757
|
+
const pieces = bpeEncode(byteLevel, t.mergeRank);
|
|
758
|
+
for (const p of pieces) {
|
|
759
|
+
const id = t.vocab[p];
|
|
760
|
+
if (id !== void 0) ids.push(id);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
if (t.addedPattern) {
|
|
765
|
+
t.addedPattern.lastIndex = 0;
|
|
766
|
+
let last = 0;
|
|
767
|
+
for (const m of text.matchAll(t.addedPattern)) {
|
|
768
|
+
const idx = m.index ?? 0;
|
|
769
|
+
if (idx > last) process2(text.slice(last, idx));
|
|
770
|
+
const id = t.addedMap.get(m[0]);
|
|
771
|
+
if (id !== void 0) ids.push(id);
|
|
772
|
+
last = idx + m[0].length;
|
|
773
|
+
}
|
|
774
|
+
if (last < text.length) process2(text.slice(last));
|
|
775
|
+
} else {
|
|
776
|
+
process2(text);
|
|
777
|
+
}
|
|
778
|
+
return ids;
|
|
779
|
+
}
|
|
780
|
+
function countTokens(text) {
|
|
781
|
+
return encode(text).length;
|
|
782
|
+
}
|
|
783
|
+
|
|
620
784
|
// src/repair/flatten.ts
|
|
621
785
|
function analyzeSchema(schema) {
|
|
622
786
|
if (!schema) return { shouldFlatten: false, leafCount: 0, maxDepth: 0 };
|
|
@@ -767,7 +931,14 @@ var ToolRegistry = class {
|
|
|
767
931
|
try {
|
|
768
932
|
const result = await tool.fn(args, { signal: opts.signal });
|
|
769
933
|
const str = typeof result === "string" ? result : JSON.stringify(result);
|
|
770
|
-
|
|
934
|
+
let clipped = str;
|
|
935
|
+
if (opts.maxResultTokens !== void 0) {
|
|
936
|
+
clipped = truncateForModelByTokens(clipped, opts.maxResultTokens);
|
|
937
|
+
}
|
|
938
|
+
if (opts.maxResultChars !== void 0) {
|
|
939
|
+
clipped = truncateForModel(clipped, opts.maxResultChars);
|
|
940
|
+
}
|
|
941
|
+
return clipped;
|
|
771
942
|
} catch (err) {
|
|
772
943
|
const e = err;
|
|
773
944
|
if (typeof e.toToolResult === "function") {
|
|
@@ -801,6 +972,7 @@ function hasDotKey(obj) {
|
|
|
801
972
|
|
|
802
973
|
// src/mcp/registry.ts
|
|
803
974
|
var DEFAULT_MAX_RESULT_CHARS = 32e3;
|
|
975
|
+
var DEFAULT_MAX_RESULT_TOKENS = 8e3;
|
|
804
976
|
async function bridgeMcpTools(client, opts = {}) {
|
|
805
977
|
const registry = opts.registry ?? new ToolRegistry({ autoFlatten: opts.autoFlatten });
|
|
806
978
|
const prefix = opts.namePrefix ?? "";
|
|
@@ -857,6 +1029,61 @@ function truncateForModel(s, maxChars) {
|
|
|
857
1029
|
|
|
858
1030
|
${tail}`;
|
|
859
1031
|
}
|
|
1032
|
+
function truncateForModelByTokens(s, maxTokens) {
|
|
1033
|
+
if (maxTokens <= 0) return "";
|
|
1034
|
+
if (s.length <= maxTokens) return s;
|
|
1035
|
+
if (s.length <= maxTokens * 4) {
|
|
1036
|
+
const tokens = countTokens(s);
|
|
1037
|
+
if (tokens <= maxTokens) return s;
|
|
1038
|
+
}
|
|
1039
|
+
const markerOverhead = 48;
|
|
1040
|
+
const contentBudget = Math.max(0, maxTokens - markerOverhead);
|
|
1041
|
+
const tailBudget = Math.min(256, Math.floor(contentBudget * 0.1));
|
|
1042
|
+
const headBudget = Math.max(0, contentBudget - tailBudget);
|
|
1043
|
+
const head = sizePrefixToTokens(s, headBudget);
|
|
1044
|
+
const tail = sizeSuffixToTokens(s, tailBudget);
|
|
1045
|
+
const droppedChars = s.length - head.length - tail.length;
|
|
1046
|
+
const headTokens = head ? countTokens(head) : 0;
|
|
1047
|
+
const tailTokens = tail ? countTokens(tail) : 0;
|
|
1048
|
+
const sampleChars = head.length + tail.length;
|
|
1049
|
+
const sampleTokens = headTokens + tailTokens;
|
|
1050
|
+
const ratio = sampleChars > 0 ? sampleTokens / sampleChars : 0.3;
|
|
1051
|
+
const estTotalTokens = Math.ceil(s.length * ratio);
|
|
1052
|
+
const droppedTokens = Math.max(0, estTotalTokens - sampleTokens);
|
|
1053
|
+
return `${head}
|
|
1054
|
+
|
|
1055
|
+
[\u2026truncated ~${droppedTokens} tokens (${droppedChars} chars) \u2014 raise BridgeOptions.maxResultTokens, or call the tool with a narrower scope (filter, head, pagination)\u2026]
|
|
1056
|
+
|
|
1057
|
+
${tail}`;
|
|
1058
|
+
}
|
|
1059
|
+
function sizePrefixToTokens(s, budget) {
|
|
1060
|
+
if (budget <= 0 || s.length === 0) return "";
|
|
1061
|
+
let size = Math.min(s.length, budget * 4);
|
|
1062
|
+
for (let iter = 0; iter < 6; iter++) {
|
|
1063
|
+
if (size <= 0) return "";
|
|
1064
|
+
const slice = s.slice(0, size);
|
|
1065
|
+
const count = countTokens(slice);
|
|
1066
|
+
if (count <= budget) return slice;
|
|
1067
|
+
const next = Math.floor(size * (budget / count) * 0.95);
|
|
1068
|
+
if (next >= size) return s.slice(0, Math.max(0, size - 1));
|
|
1069
|
+
size = next;
|
|
1070
|
+
}
|
|
1071
|
+
return s.slice(0, Math.max(0, size));
|
|
1072
|
+
}
|
|
1073
|
+
function sizeSuffixToTokens(s, budget) {
|
|
1074
|
+
if (budget <= 0 || s.length === 0) return "";
|
|
1075
|
+
let size = Math.min(s.length, budget * 4);
|
|
1076
|
+
for (let iter = 0; iter < 6; iter++) {
|
|
1077
|
+
if (size <= 0) return "";
|
|
1078
|
+
const slice = s.slice(-size);
|
|
1079
|
+
const count = countTokens(slice);
|
|
1080
|
+
if (count <= budget) return slice;
|
|
1081
|
+
const next = Math.floor(size * (budget / count) * 0.95);
|
|
1082
|
+
if (next >= size) return s.slice(-Math.max(0, size - 1));
|
|
1083
|
+
size = next;
|
|
1084
|
+
}
|
|
1085
|
+
return s.slice(-Math.max(0, size));
|
|
1086
|
+
}
|
|
860
1087
|
function blockToString(block) {
|
|
861
1088
|
if (block.type === "text") return block.text;
|
|
862
1089
|
if (block.type === "image") return `[image ${block.mimeType}, ${block.data.length} chars base64]`;
|
|
@@ -1242,19 +1469,19 @@ import {
|
|
|
1242
1469
|
chmodSync,
|
|
1243
1470
|
existsSync as existsSync2,
|
|
1244
1471
|
mkdirSync,
|
|
1245
|
-
readFileSync as
|
|
1472
|
+
readFileSync as readFileSync3,
|
|
1246
1473
|
readdirSync,
|
|
1247
1474
|
statSync,
|
|
1248
1475
|
unlinkSync,
|
|
1249
1476
|
writeFileSync
|
|
1250
1477
|
} from "fs";
|
|
1251
1478
|
import { homedir as homedir2 } from "os";
|
|
1252
|
-
import { dirname, join as
|
|
1479
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
1253
1480
|
function sessionsDir() {
|
|
1254
|
-
return
|
|
1481
|
+
return join3(homedir2(), ".reasonix", "sessions");
|
|
1255
1482
|
}
|
|
1256
1483
|
function sessionPath(name) {
|
|
1257
|
-
return
|
|
1484
|
+
return join3(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
1258
1485
|
}
|
|
1259
1486
|
function sanitizeName(name) {
|
|
1260
1487
|
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
@@ -1264,7 +1491,7 @@ function loadSessionMessages(name) {
|
|
|
1264
1491
|
const path = sessionPath(name);
|
|
1265
1492
|
if (!existsSync2(path)) return [];
|
|
1266
1493
|
try {
|
|
1267
|
-
const raw =
|
|
1494
|
+
const raw = readFileSync3(path, "utf8");
|
|
1268
1495
|
const out = [];
|
|
1269
1496
|
for (const line of raw.split(/\r?\n/)) {
|
|
1270
1497
|
const trimmed = line.trim();
|
|
@@ -1282,7 +1509,7 @@ function loadSessionMessages(name) {
|
|
|
1282
1509
|
}
|
|
1283
1510
|
function appendSessionMessage(name, message) {
|
|
1284
1511
|
const path = sessionPath(name);
|
|
1285
|
-
mkdirSync(
|
|
1512
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
1286
1513
|
appendFileSync(path, `${JSON.stringify(message)}
|
|
1287
1514
|
`, "utf8");
|
|
1288
1515
|
try {
|
|
@@ -1296,7 +1523,7 @@ function listSessions() {
|
|
|
1296
1523
|
try {
|
|
1297
1524
|
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1298
1525
|
return files.map((file) => {
|
|
1299
|
-
const path =
|
|
1526
|
+
const path = join3(dir, file);
|
|
1300
1527
|
const stat = statSync(path);
|
|
1301
1528
|
const name = file.replace(/\.jsonl$/, "");
|
|
1302
1529
|
const messageCount = countLines(path);
|
|
@@ -1317,7 +1544,7 @@ function deleteSession(name) {
|
|
|
1317
1544
|
}
|
|
1318
1545
|
function rewriteSession(name, messages) {
|
|
1319
1546
|
const path = sessionPath(name);
|
|
1320
|
-
mkdirSync(
|
|
1547
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
1321
1548
|
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
1322
1549
|
writeFileSync(path, body ? `${body}
|
|
1323
1550
|
` : "", "utf8");
|
|
@@ -1328,7 +1555,7 @@ function rewriteSession(name, messages) {
|
|
|
1328
1555
|
}
|
|
1329
1556
|
function countLines(path) {
|
|
1330
1557
|
try {
|
|
1331
|
-
const raw =
|
|
1558
|
+
const raw = readFileSync3(path, "utf8");
|
|
1332
1559
|
return raw.split(/\r?\n/).filter((l) => l.trim()).length;
|
|
1333
1560
|
} catch {
|
|
1334
1561
|
return 0;
|
|
@@ -1975,7 +2202,7 @@ ${reason}`;
|
|
|
1975
2202
|
} else {
|
|
1976
2203
|
result = await this.tools.dispatch(name, args, {
|
|
1977
2204
|
signal,
|
|
1978
|
-
|
|
2205
|
+
maxResultTokens: DEFAULT_MAX_RESULT_TOKENS
|
|
1979
2206
|
});
|
|
1980
2207
|
const postReport = await runHooks({
|
|
1981
2208
|
hooks: this.hooks,
|
|
@@ -2177,16 +2404,16 @@ function formatLoopError(err) {
|
|
|
2177
2404
|
}
|
|
2178
2405
|
|
|
2179
2406
|
// src/project-memory.ts
|
|
2180
|
-
import { existsSync as existsSync3, readFileSync as
|
|
2181
|
-
import { join as
|
|
2407
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
2408
|
+
import { join as join4 } from "path";
|
|
2182
2409
|
var PROJECT_MEMORY_FILE = "REASONIX.md";
|
|
2183
2410
|
var PROJECT_MEMORY_MAX_CHARS = 8e3;
|
|
2184
2411
|
function readProjectMemory(rootDir) {
|
|
2185
|
-
const path =
|
|
2412
|
+
const path = join4(rootDir, PROJECT_MEMORY_FILE);
|
|
2186
2413
|
if (!existsSync3(path)) return null;
|
|
2187
2414
|
let raw;
|
|
2188
2415
|
try {
|
|
2189
|
-
raw =
|
|
2416
|
+
raw = readFileSync4(path, "utf8");
|
|
2190
2417
|
} catch {
|
|
2191
2418
|
return null;
|
|
2192
2419
|
}
|
|
@@ -2224,18 +2451,18 @@ import { createHash as createHash2 } from "crypto";
|
|
|
2224
2451
|
import {
|
|
2225
2452
|
existsSync as existsSync5,
|
|
2226
2453
|
mkdirSync as mkdirSync2,
|
|
2227
|
-
readFileSync as
|
|
2454
|
+
readFileSync as readFileSync6,
|
|
2228
2455
|
readdirSync as readdirSync3,
|
|
2229
2456
|
unlinkSync as unlinkSync2,
|
|
2230
2457
|
writeFileSync as writeFileSync2
|
|
2231
2458
|
} from "fs";
|
|
2232
2459
|
import { homedir as homedir4 } from "os";
|
|
2233
|
-
import { join as
|
|
2460
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
2234
2461
|
|
|
2235
2462
|
// src/skills.ts
|
|
2236
|
-
import { existsSync as existsSync4, readFileSync as
|
|
2463
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
2237
2464
|
import { homedir as homedir3 } from "os";
|
|
2238
|
-
import { join as
|
|
2465
|
+
import { join as join5, resolve } from "path";
|
|
2239
2466
|
var SKILLS_DIRNAME = "skills";
|
|
2240
2467
|
var SKILL_FILE = "SKILL.md";
|
|
2241
2468
|
var SKILLS_INDEX_MAX_CHARS = 4e3;
|
|
@@ -2282,11 +2509,11 @@ var SkillStore = class {
|
|
|
2282
2509
|
const out = [];
|
|
2283
2510
|
if (this.projectRoot) {
|
|
2284
2511
|
out.push({
|
|
2285
|
-
dir:
|
|
2512
|
+
dir: join5(this.projectRoot, ".reasonix", SKILLS_DIRNAME),
|
|
2286
2513
|
scope: "project"
|
|
2287
2514
|
});
|
|
2288
2515
|
}
|
|
2289
|
-
out.push({ dir:
|
|
2516
|
+
out.push({ dir: join5(this.homeDir, ".reasonix", SKILLS_DIRNAME), scope: "global" });
|
|
2290
2517
|
return out;
|
|
2291
2518
|
}
|
|
2292
2519
|
/**
|
|
@@ -2322,11 +2549,11 @@ var SkillStore = class {
|
|
|
2322
2549
|
if (!isValidSkillName(name)) return null;
|
|
2323
2550
|
for (const { dir, scope } of this.roots()) {
|
|
2324
2551
|
if (!existsSync4(dir)) continue;
|
|
2325
|
-
const dirCandidate =
|
|
2552
|
+
const dirCandidate = join5(dir, name, SKILL_FILE);
|
|
2326
2553
|
if (existsSync4(dirCandidate) && statSync2(dirCandidate).isFile()) {
|
|
2327
2554
|
return this.parse(dirCandidate, name, scope);
|
|
2328
2555
|
}
|
|
2329
|
-
const flatCandidate =
|
|
2556
|
+
const flatCandidate = join5(dir, `${name}.md`);
|
|
2330
2557
|
if (existsSync4(flatCandidate) && statSync2(flatCandidate).isFile()) {
|
|
2331
2558
|
return this.parse(flatCandidate, name, scope);
|
|
2332
2559
|
}
|
|
@@ -2341,21 +2568,21 @@ var SkillStore = class {
|
|
|
2341
2568
|
readEntry(dir, scope, entry) {
|
|
2342
2569
|
if (entry.isDirectory()) {
|
|
2343
2570
|
if (!isValidSkillName(entry.name)) return null;
|
|
2344
|
-
const file =
|
|
2571
|
+
const file = join5(dir, entry.name, SKILL_FILE);
|
|
2345
2572
|
if (!existsSync4(file)) return null;
|
|
2346
2573
|
return this.parse(file, entry.name, scope);
|
|
2347
2574
|
}
|
|
2348
2575
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2349
2576
|
const stem = entry.name.slice(0, -3);
|
|
2350
2577
|
if (!isValidSkillName(stem)) return null;
|
|
2351
|
-
return this.parse(
|
|
2578
|
+
return this.parse(join5(dir, entry.name), stem, scope);
|
|
2352
2579
|
}
|
|
2353
2580
|
return null;
|
|
2354
2581
|
}
|
|
2355
2582
|
parse(path, stem, scope) {
|
|
2356
2583
|
let raw;
|
|
2357
2584
|
try {
|
|
2358
|
-
raw =
|
|
2585
|
+
raw = readFileSync5(path, "utf8");
|
|
2359
2586
|
} catch {
|
|
2360
2587
|
return null;
|
|
2361
2588
|
}
|
|
@@ -2487,12 +2714,12 @@ function projectHash(rootDir) {
|
|
|
2487
2714
|
}
|
|
2488
2715
|
function scopeDir(opts) {
|
|
2489
2716
|
if (opts.scope === "global") {
|
|
2490
|
-
return
|
|
2717
|
+
return join6(opts.homeDir, USER_MEMORY_DIR, "global");
|
|
2491
2718
|
}
|
|
2492
2719
|
if (!opts.projectRoot) {
|
|
2493
2720
|
throw new Error("scope=project requires a projectRoot on MemoryStore");
|
|
2494
2721
|
}
|
|
2495
|
-
return
|
|
2722
|
+
return join6(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
|
|
2496
2723
|
}
|
|
2497
2724
|
function ensureDir(p) {
|
|
2498
2725
|
if (!existsSync5(p)) mkdirSync2(p, { recursive: true });
|
|
@@ -2540,7 +2767,7 @@ var MemoryStore = class {
|
|
|
2540
2767
|
homeDir;
|
|
2541
2768
|
projectRoot;
|
|
2542
2769
|
constructor(opts = {}) {
|
|
2543
|
-
this.homeDir = opts.homeDir ??
|
|
2770
|
+
this.homeDir = opts.homeDir ?? join6(homedir4(), ".reasonix");
|
|
2544
2771
|
this.projectRoot = opts.projectRoot ? resolve2(opts.projectRoot) : void 0;
|
|
2545
2772
|
}
|
|
2546
2773
|
/** Directory this store writes `scope` files into, creating it if needed. */
|
|
@@ -2551,7 +2778,7 @@ var MemoryStore = class {
|
|
|
2551
2778
|
}
|
|
2552
2779
|
/** Absolute path to a memory file (no existence check). */
|
|
2553
2780
|
pathFor(scope, name) {
|
|
2554
|
-
return
|
|
2781
|
+
return join6(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
|
|
2555
2782
|
}
|
|
2556
2783
|
/** True iff this store is configured with a project scope available. */
|
|
2557
2784
|
hasProjectScope() {
|
|
@@ -2563,14 +2790,14 @@ var MemoryStore = class {
|
|
|
2563
2790
|
*/
|
|
2564
2791
|
loadIndex(scope) {
|
|
2565
2792
|
if (scope === "project" && !this.projectRoot) return null;
|
|
2566
|
-
const file =
|
|
2793
|
+
const file = join6(
|
|
2567
2794
|
scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
|
|
2568
2795
|
MEMORY_INDEX_FILE
|
|
2569
2796
|
);
|
|
2570
2797
|
if (!existsSync5(file)) return null;
|
|
2571
2798
|
let raw;
|
|
2572
2799
|
try {
|
|
2573
|
-
raw =
|
|
2800
|
+
raw = readFileSync6(file, "utf8");
|
|
2574
2801
|
} catch {
|
|
2575
2802
|
return null;
|
|
2576
2803
|
}
|
|
@@ -2588,7 +2815,7 @@ var MemoryStore = class {
|
|
|
2588
2815
|
if (!existsSync5(file)) {
|
|
2589
2816
|
throw new Error(`memory not found: scope=${scope} name=${name}`);
|
|
2590
2817
|
}
|
|
2591
|
-
const raw =
|
|
2818
|
+
const raw = readFileSync6(file, "utf8");
|
|
2592
2819
|
const { data, body } = parseFrontmatter2(raw);
|
|
2593
2820
|
return {
|
|
2594
2821
|
name: data.name ?? name,
|
|
@@ -2650,7 +2877,7 @@ var MemoryStore = class {
|
|
|
2650
2877
|
createdAt: todayIso()
|
|
2651
2878
|
};
|
|
2652
2879
|
const dir = this.dir(input.scope);
|
|
2653
|
-
const file =
|
|
2880
|
+
const file = join6(dir, `${name}.md`);
|
|
2654
2881
|
const content = `${formatFrontmatter(entry)}${body}
|
|
2655
2882
|
`;
|
|
2656
2883
|
writeFileSync2(file, content, "utf8");
|
|
@@ -2684,7 +2911,7 @@ var MemoryStore = class {
|
|
|
2684
2911
|
return;
|
|
2685
2912
|
}
|
|
2686
2913
|
const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
|
|
2687
|
-
const indexPath =
|
|
2914
|
+
const indexPath = join6(dir, MEMORY_INDEX_FILE);
|
|
2688
2915
|
if (mdFiles.length === 0) {
|
|
2689
2916
|
if (existsSync5(indexPath)) unlinkSync2(indexPath);
|
|
2690
2917
|
return;
|
|
@@ -3717,6 +3944,50 @@ function tokenizeCommand(cmd) {
|
|
|
3717
3944
|
if (cur.length > 0) out.push(cur);
|
|
3718
3945
|
return out;
|
|
3719
3946
|
}
|
|
3947
|
+
function detectShellOperator(cmd) {
|
|
3948
|
+
const opPrefix = /^(?:2>&1|&>|\|{1,2}|&{1,2}|2>{1,2}|>{1,2}|<{1,2})/;
|
|
3949
|
+
let cur = "";
|
|
3950
|
+
let curQuoted = false;
|
|
3951
|
+
let quote = null;
|
|
3952
|
+
const check = () => {
|
|
3953
|
+
if (cur.length === 0 && !curQuoted) return null;
|
|
3954
|
+
if (!curQuoted) {
|
|
3955
|
+
const m = opPrefix.exec(cur);
|
|
3956
|
+
if (m) return m[0] ?? null;
|
|
3957
|
+
}
|
|
3958
|
+
return null;
|
|
3959
|
+
};
|
|
3960
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
3961
|
+
const ch = cmd[i];
|
|
3962
|
+
if (quote) {
|
|
3963
|
+
if (ch === quote) {
|
|
3964
|
+
quote = null;
|
|
3965
|
+
} else if (ch === "\\" && quote === '"' && i + 1 < cmd.length) {
|
|
3966
|
+
cur += cmd[++i];
|
|
3967
|
+
curQuoted = true;
|
|
3968
|
+
} else {
|
|
3969
|
+
cur += ch;
|
|
3970
|
+
curQuoted = true;
|
|
3971
|
+
}
|
|
3972
|
+
continue;
|
|
3973
|
+
}
|
|
3974
|
+
if (ch === '"' || ch === "'") {
|
|
3975
|
+
quote = ch;
|
|
3976
|
+
curQuoted = true;
|
|
3977
|
+
continue;
|
|
3978
|
+
}
|
|
3979
|
+
if (ch === " " || ch === " ") {
|
|
3980
|
+
const op = check();
|
|
3981
|
+
if (op) return op;
|
|
3982
|
+
cur = "";
|
|
3983
|
+
curQuoted = false;
|
|
3984
|
+
continue;
|
|
3985
|
+
}
|
|
3986
|
+
cur += ch;
|
|
3987
|
+
}
|
|
3988
|
+
if (quote) return null;
|
|
3989
|
+
return check();
|
|
3990
|
+
}
|
|
3720
3991
|
function isAllowed(cmd, extra = []) {
|
|
3721
3992
|
const normalized = cmd.trim().replace(/\s+/g, " ");
|
|
3722
3993
|
const allowlist = [...BUILTIN_ALLOWLIST, ...extra];
|
|
@@ -3729,6 +4000,12 @@ function isAllowed(cmd, extra = []) {
|
|
|
3729
4000
|
async function runCommand(cmd, opts) {
|
|
3730
4001
|
const argv = tokenizeCommand(cmd);
|
|
3731
4002
|
if (argv.length === 0) throw new Error("run_command: empty command");
|
|
4003
|
+
const operator = detectShellOperator(cmd);
|
|
4004
|
+
if (operator !== null) {
|
|
4005
|
+
throw new Error(
|
|
4006
|
+
`run_command: shell operator "${operator}" is not supported \u2014 this tool spawns one process, no shell expansion. Split into separate run_command calls and combine the output in your reasoning (e.g. instead of \`grep foo *.ts | wc -l\`, call \`grep -c foo *.ts\` or two separate commands). To pass "${operator}" as a literal argument, wrap it in quotes.`
|
|
4007
|
+
);
|
|
4008
|
+
}
|
|
3732
4009
|
const timeoutMs = (opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC) * 1e3;
|
|
3733
4010
|
const maxChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
3734
4011
|
const spawnOpts = {
|
|
@@ -3906,7 +4183,7 @@ function registerShellTools(registry, opts) {
|
|
|
3906
4183
|
properties: {
|
|
3907
4184
|
command: {
|
|
3908
4185
|
type: "string",
|
|
3909
|
-
description:
|
|
4186
|
+
description: 'Full command line. Tokenized with POSIX-ish quoting; no shell expansion. Pipes (`|`), redirects (`>`, `<`, `2>`), and `&&`/`||` chaining are rejected with an error \u2014 split into separate calls instead. To pass an operator character as a literal argument (e.g. a regex), wrap it in quotes: `grep "a|b" file.txt`.'
|
|
3910
4187
|
},
|
|
3911
4188
|
timeoutSec: {
|
|
3912
4189
|
type: "integer",
|
|
@@ -4125,12 +4402,12 @@ ${i + 1}. ${r.title}`);
|
|
|
4125
4402
|
}
|
|
4126
4403
|
|
|
4127
4404
|
// src/env.ts
|
|
4128
|
-
import { readFileSync as
|
|
4405
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
4129
4406
|
import { resolve as resolve5 } from "path";
|
|
4130
4407
|
function loadDotenv(path = ".env") {
|
|
4131
4408
|
let raw;
|
|
4132
4409
|
try {
|
|
4133
|
-
raw =
|
|
4410
|
+
raw = readFileSync7(resolve5(process.cwd(), path), "utf8");
|
|
4134
4411
|
} catch {
|
|
4135
4412
|
return;
|
|
4136
4413
|
}
|
|
@@ -4149,7 +4426,7 @@ function loadDotenv(path = ".env") {
|
|
|
4149
4426
|
}
|
|
4150
4427
|
|
|
4151
4428
|
// src/transcript.ts
|
|
4152
|
-
import { createWriteStream, readFileSync as
|
|
4429
|
+
import { createWriteStream, readFileSync as readFileSync8 } from "fs";
|
|
4153
4430
|
function recordFromLoopEvent(ev, extra) {
|
|
4154
4431
|
const rec = {
|
|
4155
4432
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4200,7 +4477,7 @@ function openTranscriptFile(path, meta) {
|
|
|
4200
4477
|
return stream;
|
|
4201
4478
|
}
|
|
4202
4479
|
function readTranscript(path) {
|
|
4203
|
-
const raw =
|
|
4480
|
+
const raw = readFileSync8(path, "utf8");
|
|
4204
4481
|
return parseTranscript(raw);
|
|
4205
4482
|
}
|
|
4206
4483
|
function isPlanStateEmptyShape(s) {
|
|
@@ -5255,8 +5532,8 @@ async function trySection(load) {
|
|
|
5255
5532
|
}
|
|
5256
5533
|
|
|
5257
5534
|
// src/code/edit-blocks.ts
|
|
5258
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as
|
|
5259
|
-
import { dirname as
|
|
5535
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync9, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5536
|
+
import { dirname as dirname4, resolve as resolve6 } from "path";
|
|
5260
5537
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
5261
5538
|
function parseEditBlocks(text) {
|
|
5262
5539
|
const out = [];
|
|
@@ -5294,11 +5571,11 @@ function applyEditBlock(block, rootDir) {
|
|
|
5294
5571
|
message: "file does not exist; to create it, use an empty SEARCH block"
|
|
5295
5572
|
};
|
|
5296
5573
|
}
|
|
5297
|
-
mkdirSync3(
|
|
5574
|
+
mkdirSync3(dirname4(absTarget), { recursive: true });
|
|
5298
5575
|
writeFileSync3(absTarget, block.replace, "utf8");
|
|
5299
5576
|
return { path: block.path, status: "created" };
|
|
5300
5577
|
}
|
|
5301
|
-
const content =
|
|
5578
|
+
const content = readFileSync9(absTarget, "utf8");
|
|
5302
5579
|
if (searchEmpty) {
|
|
5303
5580
|
return {
|
|
5304
5581
|
path: block.path,
|
|
@@ -5337,7 +5614,7 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
5337
5614
|
continue;
|
|
5338
5615
|
}
|
|
5339
5616
|
try {
|
|
5340
|
-
snapshots.push({ path: b.path, prevContent:
|
|
5617
|
+
snapshots.push({ path: b.path, prevContent: readFileSync9(abs, "utf8") });
|
|
5341
5618
|
} catch {
|
|
5342
5619
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5343
5620
|
}
|
|
@@ -5380,8 +5657,8 @@ function sep() {
|
|
|
5380
5657
|
}
|
|
5381
5658
|
|
|
5382
5659
|
// src/code/prompt.ts
|
|
5383
|
-
import { existsSync as existsSync8, readFileSync as
|
|
5384
|
-
import { join as
|
|
5660
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10 } from "fs";
|
|
5661
|
+
import { join as join8 } from "path";
|
|
5385
5662
|
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.
|
|
5386
5663
|
|
|
5387
5664
|
# Cite or shut up \u2014 non-negotiable
|
|
@@ -5502,11 +5779,11 @@ Two different rules depending on which tool:
|
|
|
5502
5779
|
`;
|
|
5503
5780
|
function codeSystemPrompt(rootDir) {
|
|
5504
5781
|
const withMemory = applyMemoryStack(CODE_SYSTEM_PROMPT, rootDir);
|
|
5505
|
-
const gitignorePath =
|
|
5782
|
+
const gitignorePath = join8(rootDir, ".gitignore");
|
|
5506
5783
|
if (!existsSync8(gitignorePath)) return withMemory;
|
|
5507
5784
|
let content;
|
|
5508
5785
|
try {
|
|
5509
|
-
content =
|
|
5786
|
+
content = readFileSync10(gitignorePath, "utf8");
|
|
5510
5787
|
} catch {
|
|
5511
5788
|
return withMemory;
|
|
5512
5789
|
}
|
|
@@ -5526,15 +5803,15 @@ ${truncated}
|
|
|
5526
5803
|
}
|
|
5527
5804
|
|
|
5528
5805
|
// src/config.ts
|
|
5529
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as
|
|
5806
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
5530
5807
|
import { homedir as homedir5 } from "os";
|
|
5531
|
-
import { dirname as
|
|
5808
|
+
import { dirname as dirname5, join as join9 } from "path";
|
|
5532
5809
|
function defaultConfigPath() {
|
|
5533
|
-
return
|
|
5810
|
+
return join9(homedir5(), ".reasonix", "config.json");
|
|
5534
5811
|
}
|
|
5535
5812
|
function readConfig(path = defaultConfigPath()) {
|
|
5536
5813
|
try {
|
|
5537
|
-
const raw =
|
|
5814
|
+
const raw = readFileSync11(path, "utf8");
|
|
5538
5815
|
const parsed = JSON.parse(raw);
|
|
5539
5816
|
if (parsed && typeof parsed === "object") return parsed;
|
|
5540
5817
|
} catch {
|
|
@@ -5542,7 +5819,7 @@ function readConfig(path = defaultConfigPath()) {
|
|
|
5542
5819
|
return {};
|
|
5543
5820
|
}
|
|
5544
5821
|
function writeConfig(cfg, path = defaultConfigPath()) {
|
|
5545
|
-
mkdirSync4(
|
|
5822
|
+
mkdirSync4(dirname5(path), { recursive: true });
|
|
5546
5823
|
writeFileSync4(path, JSON.stringify(cfg, null, 2), "utf8");
|
|
5547
5824
|
try {
|
|
5548
5825
|
chmodSync2(path, 384);
|
|
@@ -5569,25 +5846,25 @@ function redactKey(key) {
|
|
|
5569
5846
|
}
|
|
5570
5847
|
|
|
5571
5848
|
// src/version.ts
|
|
5572
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as
|
|
5849
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
5573
5850
|
import { homedir as homedir6 } from "os";
|
|
5574
|
-
import { dirname as
|
|
5575
|
-
import { fileURLToPath } from "url";
|
|
5851
|
+
import { dirname as dirname6, join as join10 } from "path";
|
|
5852
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5576
5853
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
5577
5854
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5578
5855
|
var LATEST_FETCH_TIMEOUT_MS = 2e3;
|
|
5579
5856
|
function readPackageVersion() {
|
|
5580
5857
|
try {
|
|
5581
|
-
let dir =
|
|
5858
|
+
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
5582
5859
|
for (let i = 0; i < 6; i++) {
|
|
5583
|
-
const p =
|
|
5860
|
+
const p = join10(dir, "package.json");
|
|
5584
5861
|
if (existsSync9(p)) {
|
|
5585
|
-
const pkg = JSON.parse(
|
|
5862
|
+
const pkg = JSON.parse(readFileSync12(p, "utf8"));
|
|
5586
5863
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
5587
5864
|
return pkg.version;
|
|
5588
5865
|
}
|
|
5589
5866
|
}
|
|
5590
|
-
const parent =
|
|
5867
|
+
const parent = dirname6(dir);
|
|
5591
5868
|
if (parent === dir) break;
|
|
5592
5869
|
dir = parent;
|
|
5593
5870
|
}
|
|
@@ -5597,11 +5874,11 @@ function readPackageVersion() {
|
|
|
5597
5874
|
}
|
|
5598
5875
|
var VERSION = readPackageVersion();
|
|
5599
5876
|
function cachePath(homeDirOverride) {
|
|
5600
|
-
return
|
|
5877
|
+
return join10(homeDirOverride ?? homedir6(), ".reasonix", "version-cache.json");
|
|
5601
5878
|
}
|
|
5602
5879
|
function readCache(homeDirOverride) {
|
|
5603
5880
|
try {
|
|
5604
|
-
const raw =
|
|
5881
|
+
const raw = readFileSync12(cachePath(homeDirOverride), "utf8");
|
|
5605
5882
|
const parsed = JSON.parse(raw);
|
|
5606
5883
|
if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
|
|
5607
5884
|
return parsed;
|
|
@@ -5613,7 +5890,7 @@ function readCache(homeDirOverride) {
|
|
|
5613
5890
|
function writeCache(entry, homeDirOverride) {
|
|
5614
5891
|
try {
|
|
5615
5892
|
const p = cachePath(homeDirOverride);
|
|
5616
|
-
mkdirSync5(
|
|
5893
|
+
mkdirSync5(dirname6(p), { recursive: true });
|
|
5617
5894
|
writeFileSync5(p, JSON.stringify(entry), "utf8");
|
|
5618
5895
|
} catch {
|
|
5619
5896
|
}
|
|
@@ -5621,8 +5898,8 @@ function writeCache(entry, homeDirOverride) {
|
|
|
5621
5898
|
async function getLatestVersion(opts = {}) {
|
|
5622
5899
|
const ttl = opts.ttlMs ?? LATEST_CACHE_TTL_MS;
|
|
5623
5900
|
if (!opts.force) {
|
|
5624
|
-
const
|
|
5625
|
-
if (
|
|
5901
|
+
const cached2 = readCache(opts.homeDir);
|
|
5902
|
+
if (cached2 && Date.now() - cached2.checkedAt < ttl) return cached2.version;
|
|
5626
5903
|
}
|
|
5627
5904
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
5628
5905
|
if (!fetchImpl) return null;
|
|
@@ -5670,11 +5947,11 @@ function isNpxInstall() {
|
|
|
5670
5947
|
}
|
|
5671
5948
|
|
|
5672
5949
|
// src/usage.ts
|
|
5673
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as
|
|
5950
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync13, statSync as statSync4 } from "fs";
|
|
5674
5951
|
import { homedir as homedir7 } from "os";
|
|
5675
|
-
import { dirname as
|
|
5952
|
+
import { dirname as dirname7, join as join11 } from "path";
|
|
5676
5953
|
function defaultUsageLogPath(homeDirOverride) {
|
|
5677
|
-
return
|
|
5954
|
+
return join11(homeDirOverride ?? homedir7(), ".reasonix", "usage.jsonl");
|
|
5678
5955
|
}
|
|
5679
5956
|
function appendUsage(input) {
|
|
5680
5957
|
const record = {
|
|
@@ -5690,7 +5967,7 @@ function appendUsage(input) {
|
|
|
5690
5967
|
};
|
|
5691
5968
|
const path = input.path ?? defaultUsageLogPath();
|
|
5692
5969
|
try {
|
|
5693
|
-
mkdirSync6(
|
|
5970
|
+
mkdirSync6(dirname7(path), { recursive: true });
|
|
5694
5971
|
appendFileSync2(path, `${JSON.stringify(record)}
|
|
5695
5972
|
`, "utf8");
|
|
5696
5973
|
} catch {
|
|
@@ -5701,7 +5978,7 @@ function readUsageLog(path = defaultUsageLogPath()) {
|
|
|
5701
5978
|
if (!existsSync10(path)) return [];
|
|
5702
5979
|
let raw;
|
|
5703
5980
|
try {
|
|
5704
|
-
raw =
|
|
5981
|
+
raw = readFileSync13(path, "utf8");
|
|
5705
5982
|
} catch {
|
|
5706
5983
|
return [];
|
|
5707
5984
|
}
|
|
@@ -5799,6 +6076,7 @@ export {
|
|
|
5799
6076
|
CODE_SYSTEM_PROMPT,
|
|
5800
6077
|
CacheFirstLoop,
|
|
5801
6078
|
DEFAULT_MAX_RESULT_CHARS,
|
|
6079
|
+
DEFAULT_MAX_RESULT_TOKENS,
|
|
5802
6080
|
DeepSeekClient,
|
|
5803
6081
|
HOOK_EVENTS,
|
|
5804
6082
|
HOOK_SETTINGS_DIRNAME,
|
|
@@ -5848,6 +6126,7 @@ export {
|
|
|
5848
6126
|
defaultSelector,
|
|
5849
6127
|
defaultUsageLogPath,
|
|
5850
6128
|
deleteSession,
|
|
6129
|
+
detectShellOperator,
|
|
5851
6130
|
diffTranscripts,
|
|
5852
6131
|
emptyPlanState,
|
|
5853
6132
|
fetchWithRetry,
|
|
@@ -5922,6 +6201,7 @@ export {
|
|
|
5922
6201
|
stripHallucinatedToolMarkup,
|
|
5923
6202
|
tokenizeCommand,
|
|
5924
6203
|
truncateForModel,
|
|
6204
|
+
truncateForModelByTokens,
|
|
5925
6205
|
webFetch,
|
|
5926
6206
|
webSearch,
|
|
5927
6207
|
withUtf8Codepage,
|