token-goat 2.9.30 → 2.9.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -7
- package/SECURITY.md +10 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/native/linux-arm64/tg-hook +0 -0
- package/dist/native/linux-x64/tg-hook +0 -0
- package/dist/native/win32-arm64/tg-hook.exe +0 -0
- package/dist/native/win32-x64/tg-hook.exe +0 -0
- package/dist/{token-goat-chunk-QSBRTGM2.mjs → token-goat-chunk-25TRAWET.mjs} +17 -7
- package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
- package/dist/{token-goat-chunk-IVKIZWAB.mjs → token-goat-chunk-2M7E4PF7.mjs} +41 -12
- package/dist/{token-goat-chunk-SMVRN2HU.mjs → token-goat-chunk-2UPZGKKY.mjs} +2 -2
- package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
- package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
- package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
- package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
- package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
- package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
- package/dist/{token-goat-chunk-KWPNJBDH.mjs → token-goat-chunk-4GILLLWY.mjs} +7 -4
- package/dist/{token-goat-chunk-67TQJ76B.mjs → token-goat-chunk-4NAPX7BA.mjs} +36 -3
- package/dist/{token-goat-chunk-PU7V3FD6.mjs → token-goat-chunk-4SC7UJYV.mjs} +3354 -2553
- package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
- package/dist/{token-goat-chunk-AFLYLHDH.mjs → token-goat-chunk-4ZBFWLXF.mjs} +283 -427
- package/dist/{token-goat-chunk-JDWCRD6M.mjs → token-goat-chunk-57BIAXJL.mjs} +73 -40
- package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
- package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
- package/dist/token-goat-chunk-646E6U44.mjs +398 -0
- package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
- package/dist/{token-goat-chunk-JN4XMLSD.mjs → token-goat-chunk-6DG6HWP3.mjs} +8 -2
- package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
- package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
- package/dist/{token-goat-chunk-VPBBTSJR.mjs → token-goat-chunk-76FGDLRO.mjs} +262 -255
- package/dist/{token-goat-chunk-7IN2MKDS.mjs → token-goat-chunk-7EZTZOMC.mjs} +121 -289
- package/dist/{token-goat-chunk-OJBNYTJP.mjs → token-goat-chunk-7MAOA6X4.mjs} +640 -80
- package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
- package/dist/{token-goat-chunk-PD5VKH46.mjs → token-goat-chunk-AUNGYYQX.mjs} +2 -2
- package/dist/{token-goat-chunk-HG45AF2B.mjs → token-goat-chunk-AUQYRMMH.mjs} +794 -37
- package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
- package/dist/{token-goat-chunk-A3CK6N5Z.mjs → token-goat-chunk-BA4HI6BW.mjs} +1309 -110
- package/dist/{token-goat-chunk-JB6QN6VF.mjs → token-goat-chunk-BFCWY73P.mjs} +59 -23
- package/dist/{token-goat-chunk-B45VMIIH.mjs → token-goat-chunk-BWGFUZZE.mjs} +7 -5
- package/dist/{token-goat-chunk-P4QMM4WK.mjs → token-goat-chunk-C75NA7PL.mjs} +50 -23
- package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
- package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
- package/dist/{token-goat-chunk-H2PHHGM5.mjs → token-goat-chunk-CIMQ2BB3.mjs} +57 -12
- package/dist/{token-goat-chunk-N2NMER56.mjs → token-goat-chunk-CJLS3CDL.mjs} +46 -4
- package/dist/{token-goat-chunk-VES7EL7O.mjs → token-goat-chunk-CO3UYX6G.mjs} +1 -1
- package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
- package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
- package/dist/{token-goat-chunk-4LCCNRTG.mjs → token-goat-chunk-CVCEVUGK.mjs} +8 -6
- package/dist/{token-goat-chunk-B2RZZCSS.mjs → token-goat-chunk-CXHOFN7R.mjs} +37 -20
- package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
- package/dist/{token-goat-chunk-APGZXSPS.mjs → token-goat-chunk-DGS2LVNA.mjs} +47 -30
- package/dist/{token-goat-chunk-54K3EUV3.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
- package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
- package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
- package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
- package/dist/{token-goat-chunk-5BCIJXMO.mjs → token-goat-chunk-EELTBKDM.mjs} +14 -10
- package/dist/{token-goat-chunk-W3QCJS6G.mjs → token-goat-chunk-F4HYL64R.mjs} +8 -6
- package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
- package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
- package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
- package/dist/{token-goat-chunk-C63JQV5K.mjs → token-goat-chunk-GL3ETKSC.mjs} +233 -15
- package/dist/token-goat-chunk-GVB2MUST.mjs +1298 -0
- package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
- package/dist/{token-goat-chunk-ZEJVMUQH.mjs → token-goat-chunk-HLPW63A7.mjs} +2 -2
- package/dist/{token-goat-chunk-GOLEOXZP.mjs → token-goat-chunk-HU4TORC5.mjs} +44 -26
- package/dist/{token-goat-chunk-Z57YODA2.mjs → token-goat-chunk-I7VKZZAW.mjs} +2 -2
- package/dist/{token-goat-chunk-NYKZLXMK.mjs → token-goat-chunk-IA6XSPE3.mjs} +6 -6
- package/dist/{token-goat-chunk-E3OQX2XT.mjs → token-goat-chunk-IAGXMHIK.mjs} +81 -42
- package/dist/{token-goat-chunk-HYBFA5X3.mjs → token-goat-chunk-IK2DRMFX.mjs} +24 -68
- package/dist/{token-goat-chunk-COBQGL5S.mjs → token-goat-chunk-INNPTRUX.mjs} +249 -299
- package/dist/{token-goat-chunk-7NADEDKJ.mjs → token-goat-chunk-JJ5BX4F4.mjs} +6 -1
- package/dist/{token-goat-chunk-PEPTHRFF.mjs → token-goat-chunk-JVFSHVFJ.mjs} +6 -6
- package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
- package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
- package/dist/{token-goat-chunk-Q5VTGRH7.mjs → token-goat-chunk-LCNQ2CNN.mjs} +55 -319
- package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
- package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
- package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
- package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
- package/dist/{token-goat-chunk-T4FK7VOV.mjs → token-goat-chunk-MHX7XCC3.mjs} +2 -1
- package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
- package/dist/{token-goat-chunk-LOBGHXPB.mjs → token-goat-chunk-N5MMR2IW.mjs} +1 -1
- package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
- package/dist/{token-goat-chunk-RHXKCZX3.mjs → token-goat-chunk-NISNMD7T.mjs} +2182 -2959
- package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
- package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
- package/dist/{token-goat-chunk-KQNZDCBD.mjs → token-goat-chunk-NSNSPPBG.mjs} +25 -3
- package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
- package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
- package/dist/{token-goat-chunk-JTQQGXZH.mjs → token-goat-chunk-ODBT2USM.mjs} +124 -57
- package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
- package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
- package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
- package/dist/{token-goat-chunk-DZX2YDPT.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -2
- package/dist/{token-goat-chunk-QCLDAQTS.mjs → token-goat-chunk-P6HQSWQ3.mjs} +50 -53
- package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
- package/dist/{token-goat-chunk-7BXSNBY5.mjs → token-goat-chunk-PFWIMH2E.mjs} +23 -15
- package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
- package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
- package/dist/{token-goat-chunk-GFBSN7BD.mjs → token-goat-chunk-PX5PQWTY.mjs} +22 -250
- package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
- package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
- package/dist/{token-goat-chunk-FBNQNSJK.mjs → token-goat-chunk-QH7YVYOY.mjs} +2198 -2782
- package/dist/{token-goat-chunk-64FBPDTK.mjs → token-goat-chunk-QLMUHEPB.mjs} +12 -9
- package/dist/{token-goat-chunk-RZRTDST7.mjs → token-goat-chunk-QQOJIHL3.mjs} +37 -11
- package/dist/{token-goat-chunk-XKI4SEMX.mjs → token-goat-chunk-QQTWJY2O.mjs} +19 -0
- package/dist/{token-goat-chunk-U4N3BN2W.mjs → token-goat-chunk-QYHO5CPH.mjs} +3 -2
- package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
- package/dist/{token-goat-chunk-ETBHVDB6.mjs → token-goat-chunk-RSLPOBKQ.mjs} +22 -11
- package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
- package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
- package/dist/{token-goat-chunk-4JJS54TR.mjs → token-goat-chunk-SOAFZNNZ.mjs} +161 -38
- package/dist/{token-goat-chunk-664RTTUV.mjs → token-goat-chunk-SRTHT7KV.mjs} +21 -16
- package/dist/{token-goat-chunk-4FVIAHSI.mjs → token-goat-chunk-T5P5ACNQ.mjs} +7 -6
- package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
- package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
- package/dist/{token-goat-chunk-COTXZHTS.mjs → token-goat-chunk-TM6MC754.mjs} +4 -3
- package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
- package/dist/{token-goat-chunk-3CHUNJ2O.mjs → token-goat-chunk-U2KSB4SG.mjs} +8 -5
- package/dist/{token-goat-chunk-3Z5S4KGM.mjs → token-goat-chunk-U4WHMG6Y.mjs} +29 -49
- package/dist/{token-goat-chunk-PY533T7F.mjs → token-goat-chunk-UGJHGR5A.mjs} +21 -15
- package/dist/{token-goat-chunk-CYCEYAEO.mjs → token-goat-chunk-UOUDVA5U.mjs} +1 -1
- package/dist/{token-goat-chunk-JDHE26RP.mjs → token-goat-chunk-URRJ33GR.mjs} +16 -5
- package/dist/{token-goat-chunk-56EIMS3E.mjs → token-goat-chunk-UZOROKIS.mjs} +23 -17
- package/dist/{token-goat-chunk-CZ3LUXYZ.mjs → token-goat-chunk-VIHGGGEI.mjs} +427 -308
- package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
- package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
- package/dist/{token-goat-chunk-YARZFCZS.mjs → token-goat-chunk-VWZA2H4P.mjs} +62 -53
- package/dist/{token-goat-chunk-SQSSNQPE.mjs → token-goat-chunk-VXEXMJDL.mjs} +3979 -4745
- package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
- package/dist/{token-goat-chunk-SJHWVNDQ.mjs → token-goat-chunk-WDH44VAU.mjs} +7 -4
- package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
- package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
- package/dist/{token-goat-chunk-FZ3NEW5O.mjs → token-goat-chunk-XLRBNZCC.mjs} +13 -8
- package/dist/{token-goat-chunk-Z44YO3QZ.mjs → token-goat-chunk-XRKUX6CM.mjs} +1 -1
- package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
- package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
- package/dist/{token-goat-chunk-WY3L4DVT.mjs → token-goat-chunk-Y2ZTQOCL.mjs} +13 -8
- package/dist/{token-goat-chunk-UQ5UK2T7.mjs → token-goat-chunk-YB4VMGK2.mjs} +1 -1
- package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
- package/dist/{token-goat-chunk-ZQSJMO2R.mjs → token-goat-chunk-YHVDKQBR.mjs} +105 -105
- package/dist/{token-goat-chunk-H2K3QP6H.mjs → token-goat-chunk-YJB5XLWI.mjs} +8 -6
- package/dist/{token-goat-chunk-ZCDTCVIS.mjs → token-goat-chunk-YKB6AQG3.mjs} +5 -2
- package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
- package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
- package/dist/{token-goat-chunk-HOJLCGDP.mjs → token-goat-chunk-YY6AVUFL.mjs} +2033 -2251
- package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
- package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
- package/dist/token-goat-hook-client.cjs +1 -1
- package/dist/token-goat-hook-client.mjs +3 -3
- package/dist/token-goat-hook.mjs +67 -38
- package/dist/token-goat.core.mjs +4 -4
- package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
- package/docs/cli.md +40 -21
- package/docs/install.md +19 -9
- package/docs/security.md +5 -3
- package/package.json +2 -1
- package/dist/token-goat-chunk-5KDMCMF2.mjs +0 -362
- package/dist/token-goat-chunk-6QMAS7AB.mjs +0 -42
- package/dist/token-goat-chunk-7F2UBPD3.mjs +0 -397
- package/dist/token-goat-chunk-ARDNEC2U.mjs +0 -248
- package/dist/token-goat-chunk-ATCPY7EQ.mjs +0 -134
- package/dist/token-goat-chunk-EFHMMIGP.mjs +0 -68
- package/dist/token-goat-chunk-IVALLT3S.mjs +0 -48
- package/dist/token-goat-chunk-JDU3EXSU.mjs +0 -65
- package/dist/token-goat-chunk-MKPF4CL5.mjs +0 -37
- package/dist/token-goat-chunk-RC35RBUL.mjs +0 -312
- package/dist/token-goat-chunk-USILZ3T3.mjs +0 -53
- package/dist/token-goat-chunk-VL3YIFHZ.mjs +0 -2975
- package/dist/token-goat-chunk-XU4P6Z24.mjs +0 -133
- package/dist/token-goat-chunk-Y776AENC.mjs +0 -1597
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
displaySafeText
|
|
5
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
6
|
+
import {
|
|
7
|
+
init_define_import_meta_env
|
|
8
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
9
|
+
|
|
10
|
+
// src/hint_suggestion_guard.ts
|
|
11
|
+
init_define_import_meta_env();
|
|
12
|
+
function looksLikeSuggestion(slice) {
|
|
13
|
+
return slice.includes('"');
|
|
14
|
+
}
|
|
15
|
+
var SAFE_OUTSIDE_QUOTES = /^[A-Za-z0-9 \t_./=:+-]*$/;
|
|
16
|
+
var CONTROL_OR_BIDI = new RegExp("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u009F\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069\\u061C\\u200B-\\u200D\\u2028\\u2029\\uFE00-\\uFE0F]|[\\u{E0000}-\\u{E007F}]|\\p{Cf}", "u");
|
|
17
|
+
var POWERSHELL_DOUBLE_QUOTE = /[\u201C\u201D\u201E]/;
|
|
18
|
+
function suggestionIsUnsafe(slice) {
|
|
19
|
+
if (slice.includes("\n") || slice.includes("\r") || slice.includes("`") || CONTROL_OR_BIDI.test(slice)) return true;
|
|
20
|
+
const scan = scanQuotes(slice);
|
|
21
|
+
if (scan.open !== null) return true;
|
|
22
|
+
if (scan.singleQuoted.some((body) => ENDS_SINGLE_QUOTES.test(body))) return true;
|
|
23
|
+
if ([...scan.gaps, ...scan.doubleQuoted].some((text) => text.includes("$") || POWERSHELL_DOUBLE_QUOTE.test(text))) return true;
|
|
24
|
+
if (scan.doubleQuoted.some((body) => body.includes('\\"'))) return true;
|
|
25
|
+
if ([...scan.singleQuoted, ...scan.doubleQuoted].some((body) => body.includes(UNQUOTABLE))) return true;
|
|
26
|
+
return scan.gaps.slice(1).some((gap) => !SAFE_OUTSIDE_QUOTES.test(gap));
|
|
27
|
+
}
|
|
28
|
+
function scanQuotes(slice, insideSingle = false, stopAtTick = false) {
|
|
29
|
+
const scan = { gaps: [], singleQuoted: [], doubleQuoted: [], open: null, tick: -1 };
|
|
30
|
+
let i = insideSingle ? slice.indexOf("'") + 1 : 0;
|
|
31
|
+
if (i === 0 && insideSingle) return scan;
|
|
32
|
+
let gapStart = i;
|
|
33
|
+
while (i < slice.length) {
|
|
34
|
+
const mark = slice[i];
|
|
35
|
+
if (mark === "\\") {
|
|
36
|
+
i += 2;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (stopAtTick && mark === "`") {
|
|
40
|
+
scan.tick = i;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
if (mark === '"' || mark === "'" && /\s/.test(slice[i - 1] ?? " ")) {
|
|
44
|
+
scan.gaps.push(slice.slice(gapStart, i));
|
|
45
|
+
const close = closingMark(slice, mark, i + 1);
|
|
46
|
+
if (close === -1) {
|
|
47
|
+
scan.open = mark;
|
|
48
|
+
return scan;
|
|
49
|
+
}
|
|
50
|
+
;
|
|
51
|
+
(mark === '"' ? scan.doubleQuoted : scan.singleQuoted).push(slice.slice(i + 1, close));
|
|
52
|
+
i = close + 1;
|
|
53
|
+
gapStart = i;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
scan.gaps.push(slice.slice(gapStart, Math.min(i, slice.length)));
|
|
59
|
+
return scan;
|
|
60
|
+
}
|
|
61
|
+
function closingMark(slice, mark, from) {
|
|
62
|
+
if (mark === "'") return slice.indexOf("'", from);
|
|
63
|
+
for (let i = from; i < slice.length; i++) {
|
|
64
|
+
if (slice[i] === "\\") i++;
|
|
65
|
+
else if (slice[i] === '"') return i;
|
|
66
|
+
}
|
|
67
|
+
return -1;
|
|
68
|
+
}
|
|
69
|
+
function singleQuoteLeftOpen(slice, insideSingle) {
|
|
70
|
+
return scanQuotes(slice, insideSingle).open === "'";
|
|
71
|
+
}
|
|
72
|
+
function holdsCommandSubstitution(line) {
|
|
73
|
+
return line.includes("$(");
|
|
74
|
+
}
|
|
75
|
+
var TRAILING_FLAGS = /^(?: -{1,2}[A-Za-z][A-Za-z0-9-]*(?: [0-9]+)?)*$/;
|
|
76
|
+
function fencedCommandEnd(line) {
|
|
77
|
+
const scan = scanQuotes(line, false, true);
|
|
78
|
+
if (scan.tick === -1 || !TRAILING_FLAGS.test(scan.gaps[scan.gaps.length - 1] ?? "")) return -1;
|
|
79
|
+
const tick = scan.tick;
|
|
80
|
+
const region = line.slice(0, line.lastIndexOf("`"));
|
|
81
|
+
return region.includes('"') && (ENDS_SINGLE_QUOTES.test(region) || CONTROL_OR_BIDI.test(region)) ? -1 : tick;
|
|
82
|
+
}
|
|
83
|
+
var SUGGESTED_PROGRAMS = ["pandoc", "duckdb", "rg"];
|
|
84
|
+
var SUGGESTION_START = new RegExp(`token-goat |(?<![\\w./-])(?:${SUGGESTED_PROGRAMS.join("|")}) `);
|
|
85
|
+
function nextSuggestionStart(text, from) {
|
|
86
|
+
const re = new RegExp(SUGGESTION_START.source, "g");
|
|
87
|
+
re.lastIndex = from;
|
|
88
|
+
const found = re.exec(text);
|
|
89
|
+
return found === null ? -1 : found.index;
|
|
90
|
+
}
|
|
91
|
+
function omitted(program) {
|
|
92
|
+
return program + " (command omitted: the path contains shell metacharacters)";
|
|
93
|
+
}
|
|
94
|
+
function suggestionProgram(text, start) {
|
|
95
|
+
return SUGGESTED_PROGRAMS.find((p) => text.startsWith(p + " ", start)) ?? "token-goat";
|
|
96
|
+
}
|
|
97
|
+
function stripUnsafeSuggestions(text) {
|
|
98
|
+
if (!SUGGESTION_START.test(text)) return text;
|
|
99
|
+
let out = "";
|
|
100
|
+
let at = 0;
|
|
101
|
+
for (; ; ) {
|
|
102
|
+
const start = nextSuggestionStart(text, at);
|
|
103
|
+
if (start === -1) return out + text.slice(at);
|
|
104
|
+
const lineBreak = text.slice(start).search(/[\r\n]/);
|
|
105
|
+
const line = lineBreak === -1 ? text.slice(start) : text.slice(start, start + lineBreak);
|
|
106
|
+
const firstTick = line.indexOf("`");
|
|
107
|
+
const narrow = firstTick === -1 ? line : line.slice(0, firstTick);
|
|
108
|
+
out += text.slice(at, start);
|
|
109
|
+
const placeholder = omitted(suggestionProgram(text, start));
|
|
110
|
+
if (!(looksLikeSuggestion(narrow) && suggestionIsUnsafe(narrow)) && !singleQuoteLeftOpen(narrow, text[start - 1] === "'") && !holdsCommandSubstitution(line)) {
|
|
111
|
+
out += narrow;
|
|
112
|
+
at = start + narrow.length;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const end = text[start - 1] === "`" ? fencedCommandEnd(line) : -1;
|
|
116
|
+
if (end !== -1) {
|
|
117
|
+
out += placeholder + "`";
|
|
118
|
+
at = start + end + 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const lastTick = line.lastIndexOf("`");
|
|
122
|
+
const wide = lastTick === -1 || text[start - 1] !== "`" ? line : line.slice(0, lastTick);
|
|
123
|
+
const tick = line.slice(wide.length).startsWith("`") ? "`" : "";
|
|
124
|
+
const paired = pairRemovedParens(out.slice(Math.max(out.lastIndexOf("\n"), out.lastIndexOf("\r")) + 1), wide, line.slice(wide.length + tick.length));
|
|
125
|
+
out += placeholder + tick + paired.close;
|
|
126
|
+
at = start + wide.length + tick.length + paired.skip;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function pairRemovedParens(before, removed, after) {
|
|
130
|
+
let open = 0;
|
|
131
|
+
for (const c of before) {
|
|
132
|
+
if (c === "(") open++;
|
|
133
|
+
else if (c === ")" && open > 0) open--;
|
|
134
|
+
}
|
|
135
|
+
let inner = 0;
|
|
136
|
+
for (let i = 0; i < after.length; i++) {
|
|
137
|
+
const c = after[i];
|
|
138
|
+
if (c === "(") inner++;
|
|
139
|
+
else if (c !== ")") continue;
|
|
140
|
+
else if (inner > 0) inner--;
|
|
141
|
+
else if (open > 0) open--;
|
|
142
|
+
else return { skip: i + 1, close: "" };
|
|
143
|
+
}
|
|
144
|
+
return { skip: 0, close: ")".repeat(Math.min(open, removed.split(")").length - 1)) };
|
|
145
|
+
}
|
|
146
|
+
var REWRITTEN_IN_DOUBLE_QUOTES = /[$`"\u201C-\u201E]|\\(?:\\|$)/;
|
|
147
|
+
var ENDS_SINGLE_QUOTES = /['\u2018-\u201B\r\n]/;
|
|
148
|
+
function quotedArg(value) {
|
|
149
|
+
if (unquotable(value)) return '"' + UNQUOTABLE + '"';
|
|
150
|
+
if (REWRITTEN_IN_DOUBLE_QUOTES.test(value)) return "'" + value + "'";
|
|
151
|
+
return '"' + value + '"';
|
|
152
|
+
}
|
|
153
|
+
function singleQuotable(value) {
|
|
154
|
+
return !ENDS_SINGLE_QUOTES.test(value) && !CONTROL_OR_BIDI.test(value);
|
|
155
|
+
}
|
|
156
|
+
function unquotable(value) {
|
|
157
|
+
return LINE_BREAK.test(value) || REWRITTEN_IN_DOUBLE_QUOTES.test(value) && !singleQuotable(value);
|
|
158
|
+
}
|
|
159
|
+
var LINE_BREAK = /[\r\n]/;
|
|
160
|
+
function canQuoteArg(value) {
|
|
161
|
+
return !unquotable(value);
|
|
162
|
+
}
|
|
163
|
+
var UNQUOTABLE = "<a value no quote mark can hold>";
|
|
164
|
+
function quotedArgs(...values) {
|
|
165
|
+
const held = values.map((v) => unquotable(v) ? UNQUOTABLE : v);
|
|
166
|
+
const single = held.some((v) => REWRITTEN_IN_DOUBLE_QUOTES.test(v)) && held.every(singleQuotable);
|
|
167
|
+
return held.map((v) => single ? "'" + v + "'" : '"' + (REWRITTEN_IN_DOUBLE_QUOTES.test(v) ? UNQUOTABLE : v) + '"');
|
|
168
|
+
}
|
|
169
|
+
function fileSubject(rest, shown, raw = shown) {
|
|
170
|
+
return rest.includes(raw) || rest.includes(shown) ? "this file" : proseQuoted(shown) ?? "this file";
|
|
171
|
+
}
|
|
172
|
+
function nameSubject(noun, value) {
|
|
173
|
+
const quoted = proseQuoted(displaySafeText(value));
|
|
174
|
+
return quoted === null ? "this " + noun : noun + " " + quoted;
|
|
175
|
+
}
|
|
176
|
+
function echoedValue(value) {
|
|
177
|
+
const safe = displaySafeText(value);
|
|
178
|
+
const quoted = quotedArg(safe);
|
|
179
|
+
return quoted.includes(UNQUOTABLE) ? safe : quoted;
|
|
180
|
+
}
|
|
181
|
+
var BLANK_LOOKING = /\u00a0|\u034f|\u115f|\u1160|\u17b4|\u17b5|\u2800|\u3164|\ufe0f|\uffa0|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/g;
|
|
182
|
+
function echoedCommand(value) {
|
|
183
|
+
return echoedValue(value.replace(BLANK_LOOKING, (ch) => String.fromCharCode(92) + "u" + ch.charCodeAt(0).toString(16).padStart(4, "0")));
|
|
184
|
+
}
|
|
185
|
+
function couldNotRead(file) {
|
|
186
|
+
return `Could not read: ${echoedValue(file)}`;
|
|
187
|
+
}
|
|
188
|
+
function proseQuoted(value) {
|
|
189
|
+
const quoted = quotedArg(value);
|
|
190
|
+
return quoted.includes("`") || quoted.includes(UNQUOTABLE) ? null : quoted;
|
|
191
|
+
}
|
|
192
|
+
function sentenceStart(subject) {
|
|
193
|
+
return subject.charAt(0).toUpperCase() + subject.slice(1);
|
|
194
|
+
}
|
|
195
|
+
function fencedCommand(command) {
|
|
196
|
+
return "`" + command + "`";
|
|
197
|
+
}
|
|
198
|
+
function leadWithCommand(command, purpose = "", reason = "") {
|
|
199
|
+
const tail = reason.trim();
|
|
200
|
+
return "Run " + fencedCommand(command) + (purpose === "" ? "" : " " + purpose) + "." + (tail === "" ? "" : (tail.includes("`") ? "\n" : " ") + tail);
|
|
201
|
+
}
|
|
202
|
+
function docNavigation(filePath) {
|
|
203
|
+
const ext = /\.(txt|rst)$/i.exec(filePath)?.[1]?.toLowerCase();
|
|
204
|
+
return { section: ext !== "txt", outline: ext === void 0 };
|
|
205
|
+
}
|
|
206
|
+
function grepLinesHint(pattern, shownPath, reason = "") {
|
|
207
|
+
const [quotedPattern, quotedPath] = quotedArgs(pattern, shownPath);
|
|
208
|
+
return leadWithCommand("token-goat grep " + quotedPattern + " " + quotedPath + " -C 3", "to read the matching lines", reason);
|
|
209
|
+
}
|
|
210
|
+
function configGetCommand(shownPath, key) {
|
|
211
|
+
return "token-goat config-get " + quotedArgs(shownPath, key).join(" ");
|
|
212
|
+
}
|
|
213
|
+
function docSectionHint(shownPath, heading, reason = "") {
|
|
214
|
+
const nav = docNavigation(shownPath);
|
|
215
|
+
if (!nav.section) return grepLinesHint("<pattern>", shownPath, reason);
|
|
216
|
+
return leadWithCommand("token-goat section " + quotedArg(shownPath + "::" + heading), "to read one section" + (nav.outline ? ", or " + fencedCommand("token-goat outline " + quotedArg(shownPath)) + " for every heading with line ranges" : ""), reason);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
stripUnsafeSuggestions,
|
|
221
|
+
quotedArg,
|
|
222
|
+
canQuoteArg,
|
|
223
|
+
quotedArgs,
|
|
224
|
+
fileSubject,
|
|
225
|
+
nameSubject,
|
|
226
|
+
echoedValue,
|
|
227
|
+
echoedCommand,
|
|
228
|
+
couldNotRead,
|
|
229
|
+
sentenceStart,
|
|
230
|
+
fencedCommand,
|
|
231
|
+
leadWithCommand,
|
|
232
|
+
docNavigation,
|
|
233
|
+
grepLinesHint,
|
|
234
|
+
configGetCommand,
|
|
235
|
+
docSectionHint
|
|
236
|
+
};
|
|
@@ -2,13 +2,16 @@ import { createRequire as __cjsRequire } from 'node:module';
|
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
redactSecrets
|
|
5
|
-
} from "./token-goat-chunk-
|
|
5
|
+
} from "./token-goat-chunk-T5P5ACNQ.mjs";
|
|
6
6
|
import {
|
|
7
7
|
shortFingerprint
|
|
8
|
-
} from "./token-goat-chunk-
|
|
8
|
+
} from "./token-goat-chunk-4GBVPH3D.mjs";
|
|
9
9
|
import {
|
|
10
10
|
registerReset
|
|
11
11
|
} from "./token-goat-chunk-YZAAZU2S.mjs";
|
|
12
|
+
import {
|
|
13
|
+
quotedArg
|
|
14
|
+
} from "./token-goat-chunk-GGGG7RWB.mjs";
|
|
12
15
|
import {
|
|
13
16
|
foldPath
|
|
14
17
|
} from "./token-goat-chunk-AM5V6GSX.mjs";
|
|
@@ -24,6 +27,127 @@ import {
|
|
|
24
27
|
init_define_import_meta_env();
|
|
25
28
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
26
29
|
import * as fs from "node:fs";
|
|
30
|
+
|
|
31
|
+
// src/read_range_evasion.ts
|
|
32
|
+
init_define_import_meta_env();
|
|
33
|
+
var states = /* @__PURE__ */ new Map();
|
|
34
|
+
var clock = 0;
|
|
35
|
+
function stamp() {
|
|
36
|
+
clock = Math.max(Date.now(), clock + 1);
|
|
37
|
+
return clock;
|
|
38
|
+
}
|
|
39
|
+
function stateFor(key) {
|
|
40
|
+
const state = states.get(key) ?? { resetAt: 0, denied: [], recent: [] };
|
|
41
|
+
states.set(key, state);
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
44
|
+
function evaluateRangeEvasion(options) {
|
|
45
|
+
if (options.locked) return "locked";
|
|
46
|
+
const [start, end] = options.span;
|
|
47
|
+
const denied = options.denied ?? [];
|
|
48
|
+
const recent = [...options.served.slice(-3), ...denied].slice(-3);
|
|
49
|
+
const overlap = ([s, e]) => Math.max(0, Math.min(end, e) - Math.max(start, s) + 1);
|
|
50
|
+
const anchored = recent.filter(([s]) => s === start);
|
|
51
|
+
if (anchored.length >= 3 || anchored.some(([, e]) => Math.abs(end - e) <= 20)) return "same_anchor";
|
|
52
|
+
const microCandidates = [...options.served.slice(-2), ...denied.slice(-1)];
|
|
53
|
+
if (microCandidates.some(([s, e]) => {
|
|
54
|
+
const startDelta = Math.abs(start - s);
|
|
55
|
+
const endDelta = Math.abs(end - e);
|
|
56
|
+
return startDelta >= 1 && startDelta <= 15 && endDelta >= 1 && endDelta <= 15 && overlap([s, e]) > 0;
|
|
57
|
+
})) return "micro_shift";
|
|
58
|
+
if (recent.some(([s, e]) => {
|
|
59
|
+
if (s === start && end - e > 20) return false;
|
|
60
|
+
return overlap([s, e]) >= Math.min(end - start + 1, e - s + 1) / 2;
|
|
61
|
+
})) return "overlap";
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function getReadRangeDenials(key) {
|
|
65
|
+
return states.get(key)?.denied.map((v) => v.span) ?? [];
|
|
66
|
+
}
|
|
67
|
+
function lockReadRange(key, span, identity) {
|
|
68
|
+
const state = stateFor(key);
|
|
69
|
+
state.denied.push({ span: [span[0], span[1]], at: stamp() });
|
|
70
|
+
state.denied = state.denied.slice(-3);
|
|
71
|
+
if (identity) state.identity = identity;
|
|
72
|
+
}
|
|
73
|
+
function recordRecentReadRange(key, span) {
|
|
74
|
+
const state = stateFor(key);
|
|
75
|
+
const last = state.recent.at(-1)?.span;
|
|
76
|
+
if (last?.[0] === span[0] && last[1] === span[1]) return;
|
|
77
|
+
const resync = state.resetAt > 0 && state.recent.length === 0 && state.denied.length === 0;
|
|
78
|
+
state.recent.push({ span: [span[0], span[1]], at: stamp(), ...resync ? { resync: true } : {} });
|
|
79
|
+
state.recent = state.recent.slice(-3);
|
|
80
|
+
}
|
|
81
|
+
function getRecentReadRanges(key) {
|
|
82
|
+
return states.get(key)?.recent.filter((v) => v.resync !== true).map((v) => v.span) ?? [];
|
|
83
|
+
}
|
|
84
|
+
function clearReadRangeIfChanged(key, identity) {
|
|
85
|
+
const prior = states.get(key)?.identity;
|
|
86
|
+
if (prior && identity && (prior.size !== identity.size || prior.mtimeMs !== identity.mtimeMs)) clearReadRangeEvasion(key);
|
|
87
|
+
}
|
|
88
|
+
function clearReadRangeEvasion(key) {
|
|
89
|
+
states.set(key, { resetAt: stamp(), denied: [], recent: [] });
|
|
90
|
+
}
|
|
91
|
+
function clearAllReadRangeEvasion() {
|
|
92
|
+
states.clear();
|
|
93
|
+
}
|
|
94
|
+
function exportReadRangeEvasion() {
|
|
95
|
+
return structuredClone(Array.from(states));
|
|
96
|
+
}
|
|
97
|
+
function importReadRangeEvasion(entries) {
|
|
98
|
+
states = new Map(structuredClone(entries));
|
|
99
|
+
for (const [, state] of states) {
|
|
100
|
+
clock = Math.max(clock, state.resetAt, ...state.recent.map((v) => v.at), ...state.denied.map((v) => v.at));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function coerceReadRangeEvasion(raw) {
|
|
104
|
+
if (!Array.isArray(raw)) return [];
|
|
105
|
+
const finite = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
106
|
+
const visits = (rawVisits) => {
|
|
107
|
+
if (!Array.isArray(rawVisits)) return [];
|
|
108
|
+
return rawVisits.flatMap((v) => {
|
|
109
|
+
if (typeof v !== "object" || v === null || !("span" in v) || !("at" in v)) return [];
|
|
110
|
+
const span = v.span;
|
|
111
|
+
if (!Array.isArray(span) || span.length !== 2 || !finite(span[0]) || !finite(span[1]) || !Number.isInteger(span[0]) || !Number.isInteger(span[1]) || span[0] < 1 || span[1] < span[0] || !finite(v.at)) return [];
|
|
112
|
+
return [{ span: [span[0], span[1]], at: v.at, ..."resync" in v && v.resync === true ? { resync: true } : {} }];
|
|
113
|
+
}).slice(-3);
|
|
114
|
+
};
|
|
115
|
+
return raw.flatMap((pair) => {
|
|
116
|
+
if (!Array.isArray(pair) || typeof pair[0] !== "string") return [];
|
|
117
|
+
const value = pair[1];
|
|
118
|
+
if (typeof value !== "object" || value === null || !("resetAt" in value) || !finite(value.resetAt)) return [];
|
|
119
|
+
const state = {
|
|
120
|
+
resetAt: value.resetAt,
|
|
121
|
+
denied: visits("denied" in value ? value.denied : void 0),
|
|
122
|
+
recent: visits("recent" in value ? value.recent : void 0)
|
|
123
|
+
};
|
|
124
|
+
if ("identity" in value && typeof value.identity === "object" && value.identity !== null && "size" in value.identity && "mtimeMs" in value.identity && finite(value.identity.size) && finite(value.identity.mtimeMs)) {
|
|
125
|
+
state.identity = { size: value.identity.size, mtimeMs: value.identity.mtimeMs };
|
|
126
|
+
}
|
|
127
|
+
return [[pair[0], state]];
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function mergeReadRangeEvasion(disk, mem) {
|
|
131
|
+
const merged = new Map(structuredClone(disk));
|
|
132
|
+
const mergeVisits = (a, b) => Array.from(new Map([...a, ...b].map((v) => [JSON.stringify(v), v])).values()).sort((a2, b2) => a2.at - b2.at).slice(-3);
|
|
133
|
+
for (const [key, state] of mem) {
|
|
134
|
+
const prior = merged.get(key);
|
|
135
|
+
if (!prior || state.resetAt > prior.resetAt) {
|
|
136
|
+
merged.set(key, state);
|
|
137
|
+
} else if (state.resetAt === prior.resetAt) {
|
|
138
|
+
const denied = mergeVisits(prior.denied, state.denied);
|
|
139
|
+
const recent = mergeVisits(prior.recent, state.recent);
|
|
140
|
+
const newestIdentity = (state.denied.at(-1)?.at ?? 0) >= (prior.denied.at(-1)?.at ?? 0) ? state.identity : prior.identity;
|
|
141
|
+
merged.set(key, { resetAt: state.resetAt, denied, recent, ...newestIdentity ? { identity: newestIdentity } : {} });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return Array.from(merged);
|
|
145
|
+
}
|
|
146
|
+
function rangeLockMessage(shown, span) {
|
|
147
|
+
return "Line-range reads of this file are locked for this compaction epoch. Run `token-goat read " + quotedArg(shown + "@" + span[0] + "-" + span[1]) + "` for this window, or `token-goat skeleton " + quotedArg(shown) + "` for structure. Do not shrink, grow, or shift the Read range.";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/session.ts
|
|
27
151
|
var _files = /* @__PURE__ */ new Map();
|
|
28
152
|
var _filesAtLoad = /* @__PURE__ */ new Map();
|
|
29
153
|
var _filesFullReadCountAtLoad = /* @__PURE__ */ new Map();
|
|
@@ -35,6 +159,7 @@ var _grepQueries = /* @__PURE__ */ new Map();
|
|
|
35
159
|
var _globQueries = /* @__PURE__ */ new Map();
|
|
36
160
|
var _lastTabContext = null;
|
|
37
161
|
var _seenImageHashes = [];
|
|
162
|
+
var _verificationRuns = [];
|
|
38
163
|
var _outstandingAgentSpawns = [];
|
|
39
164
|
var _outstandingAgentSpawnsAtLoad = [];
|
|
40
165
|
var _bashReruns = /* @__PURE__ */ new Set();
|
|
@@ -44,6 +169,8 @@ var _fileLineRanges = /* @__PURE__ */ new Map();
|
|
|
44
169
|
var _fileServedOutputs = /* @__PURE__ */ new Map();
|
|
45
170
|
var _fileLineRangesAtLoad = /* @__PURE__ */ new Map();
|
|
46
171
|
var _fileServedOutputsAtLoad = /* @__PURE__ */ new Map();
|
|
172
|
+
var _fileLineRangesReset = /* @__PURE__ */ new Set();
|
|
173
|
+
var _fileLineRangeIdentities = /* @__PURE__ */ new Map();
|
|
47
174
|
var _compactedAt = 0;
|
|
48
175
|
var _cliReads = /* @__PURE__ */ new Set();
|
|
49
176
|
var _pendingLargeFileHints = /* @__PURE__ */ new Map();
|
|
@@ -68,6 +195,9 @@ function resolveFilesKey(normalized) {
|
|
|
68
195
|
}
|
|
69
196
|
return normalized;
|
|
70
197
|
}
|
|
198
|
+
function newEntryEpochBase() {
|
|
199
|
+
return _compactedAt > 0 ? { epochBase: { at: _compactedAt, readCount: 0, fullReadCount: 0 } } : {};
|
|
200
|
+
}
|
|
71
201
|
function recordFileRead(filePath, isFullRead = true) {
|
|
72
202
|
const normalized = normalizePath(filePath);
|
|
73
203
|
const key = resolveFilesKey(normalized);
|
|
@@ -81,16 +211,35 @@ function recordFileRead(filePath, isFullRead = true) {
|
|
|
81
211
|
lastReadAt: now,
|
|
82
212
|
wasEdited: false,
|
|
83
213
|
sizeBytes: size,
|
|
84
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {}
|
|
214
|
+
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {},
|
|
215
|
+
...newEntryEpochBase()
|
|
85
216
|
});
|
|
86
217
|
return;
|
|
87
218
|
}
|
|
219
|
+
const opensEpoch = _compactedAt > 0 && prev.lastReadAt < _compactedAt && (prev.epochBase?.at ?? 0) < _compactedAt;
|
|
88
220
|
_files.set(key, {
|
|
89
221
|
...prev,
|
|
90
222
|
readCount: prev.readCount + 1,
|
|
91
223
|
lastReadAt: now,
|
|
92
224
|
sizeBytes: size,
|
|
93
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: (prev.fullReadCount ?? 0) + 1 } : {}
|
|
225
|
+
...isFullRead ? { lastFullReadAt: now, fullReadCount: (prev.fullReadCount ?? 0) + 1 } : {},
|
|
226
|
+
...opensEpoch ? { epochBase: { at: _compactedAt, readCount: prev.readCount, fullReadCount: prev.fullReadCount ?? 0 } } : {}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function unrecordRefusedRead(filePath, before) {
|
|
230
|
+
const key = resolveFilesKey(normalizePath(filePath));
|
|
231
|
+
const current = _files.get(key);
|
|
232
|
+
if (current === void 0) return;
|
|
233
|
+
if (before === void 0) {
|
|
234
|
+
_files.delete(key);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const { fullReadCount: _fullReadCount, lastFullReadAt: _lastFullReadAt, ...rest } = current;
|
|
238
|
+
_files.set(key, {
|
|
239
|
+
...rest,
|
|
240
|
+
readCount: before.readCount,
|
|
241
|
+
...before.fullReadCount !== void 0 ? { fullReadCount: before.fullReadCount } : {},
|
|
242
|
+
...before.lastFullReadAt !== void 0 ? { lastFullReadAt: before.lastFullReadAt } : {}
|
|
94
243
|
});
|
|
95
244
|
}
|
|
96
245
|
var MAX_SYMBOLS_PER_FILE = 25;
|
|
@@ -105,7 +254,8 @@ function recordSymbolRead(filePath, symbol) {
|
|
|
105
254
|
lastReadAt: Date.now(),
|
|
106
255
|
wasEdited: false,
|
|
107
256
|
sizeBytes: fileSize(normalized),
|
|
108
|
-
symbols_read: [symbol]
|
|
257
|
+
symbols_read: [symbol],
|
|
258
|
+
...newEntryEpochBase()
|
|
109
259
|
});
|
|
110
260
|
return;
|
|
111
261
|
}
|
|
@@ -123,19 +273,21 @@ function filesFullReadCountAtLoad() {
|
|
|
123
273
|
function recordFileEdit(filePath) {
|
|
124
274
|
const normalized = normalizePath(filePath);
|
|
125
275
|
const key = resolveFilesKey(normalized);
|
|
126
|
-
|
|
276
|
+
resetFileLineRanges(normalized);
|
|
127
277
|
const prev = _files.get(key);
|
|
278
|
+
const now = Date.now();
|
|
128
279
|
if (prev === void 0) {
|
|
129
280
|
_files.set(key, {
|
|
130
281
|
path: key,
|
|
131
282
|
readCount: 0,
|
|
132
283
|
lastReadAt: 0,
|
|
133
284
|
wasEdited: true,
|
|
285
|
+
lastEditedAt: now,
|
|
134
286
|
sizeBytes: fileSize(normalized)
|
|
135
287
|
});
|
|
136
288
|
return;
|
|
137
289
|
}
|
|
138
|
-
_files.set(key, { ...prev, wasEdited: true });
|
|
290
|
+
_files.set(key, { ...prev, wasEdited: true, lastEditedAt: now });
|
|
139
291
|
}
|
|
140
292
|
function getSessionFiles() {
|
|
141
293
|
return _files;
|
|
@@ -148,6 +300,24 @@ function wasFileFullyReadThisSession(filePath) {
|
|
|
148
300
|
const entry = _files.get(resolveFilesKey(normalizePath(filePath)));
|
|
149
301
|
return entry !== void 0 && entry.lastFullReadAt !== void 0 && entry.lastFullReadAt >= _compactedAt;
|
|
150
302
|
}
|
|
303
|
+
function epochReadCounts(entry, compactedAt = _compactedAt) {
|
|
304
|
+
if (entry.lastReadAt < compactedAt) return { reads: 0, fullReads: 0 };
|
|
305
|
+
const base = entry.epochBase !== void 0 && entry.epochBase.at === compactedAt ? entry.epochBase : void 0;
|
|
306
|
+
const fullInEpoch = entry.lastFullReadAt !== void 0 && entry.lastFullReadAt >= compactedAt;
|
|
307
|
+
if (base === void 0 && compactedAt > 0) return { reads: Math.min(entry.readCount, 1), fullReads: fullInEpoch ? 1 : 0 };
|
|
308
|
+
const reads = Math.max(0, entry.readCount - (base?.readCount ?? 0));
|
|
309
|
+
const fullReads = fullInEpoch ? Math.max(0, (entry.fullReadCount ?? 0) - (base?.fullReadCount ?? 0)) : 0;
|
|
310
|
+
return { reads, fullReads };
|
|
311
|
+
}
|
|
312
|
+
function wasEditedSinceCompaction(entry, compactedAt = _compactedAt) {
|
|
313
|
+
return entry.wasEdited && (entry.lastEditedAt === void 0 || entry.lastEditedAt >= compactedAt);
|
|
314
|
+
}
|
|
315
|
+
function mergeEpochBase(a, b) {
|
|
316
|
+
if (a === void 0) return b;
|
|
317
|
+
if (b === void 0 || a.at > b.at) return a;
|
|
318
|
+
if (b.at > a.at) return b;
|
|
319
|
+
return { at: a.at, readCount: Math.max(a.readCount, b.readCount), fullReadCount: Math.max(a.fullReadCount, b.fullReadCount) };
|
|
320
|
+
}
|
|
151
321
|
function getCompactedAt() {
|
|
152
322
|
return _compactedAt;
|
|
153
323
|
}
|
|
@@ -155,6 +325,8 @@ function markCompacted(now = Date.now()) {
|
|
|
155
325
|
if (now <= _compactedAt) return;
|
|
156
326
|
_compactedAt = now;
|
|
157
327
|
_fileLineRanges = /* @__PURE__ */ new Map();
|
|
328
|
+
_fileLineRangeIdentities = /* @__PURE__ */ new Map();
|
|
329
|
+
clearAllReadRangeEvasion();
|
|
158
330
|
_fileServedOutputs = /* @__PURE__ */ new Map();
|
|
159
331
|
_cliReads = /* @__PURE__ */ new Set();
|
|
160
332
|
}
|
|
@@ -276,6 +448,12 @@ function setLastTabContext(text) {
|
|
|
276
448
|
function lastTabContextMatches(text) {
|
|
277
449
|
return _lastTabContext !== null && _lastTabContext === shortFingerprint(text);
|
|
278
450
|
}
|
|
451
|
+
var MAX_VERIFICATION_RUNS = 8;
|
|
452
|
+
function recordVerificationRun(command, exitCode, at = Date.now()) {
|
|
453
|
+
_verificationRuns = _verificationRuns.filter((r) => r.command !== command);
|
|
454
|
+
_verificationRuns.push({ command, exitCode, at });
|
|
455
|
+
if (_verificationRuns.length > MAX_VERIFICATION_RUNS) _verificationRuns = _verificationRuns.slice(-MAX_VERIFICATION_RUNS);
|
|
456
|
+
}
|
|
279
457
|
var MAX_SEEN_IMAGE_HASHES = 16;
|
|
280
458
|
function hasSeenImage(hash) {
|
|
281
459
|
return _seenImageHashes.includes(hash);
|
|
@@ -340,11 +518,11 @@ function consumedCurlDownloadKeys() {
|
|
|
340
518
|
return consumed;
|
|
341
519
|
}
|
|
342
520
|
function consumedFileLineRangeKeys() {
|
|
343
|
-
const consumed =
|
|
521
|
+
const consumed = new Set(_fileLineRangesReset);
|
|
344
522
|
for (const key of _fileLineRangesAtLoad.keys()) {
|
|
345
|
-
if (!_fileLineRanges.has(key)) consumed.
|
|
523
|
+
if (!_fileLineRanges.has(key)) consumed.add(key);
|
|
346
524
|
}
|
|
347
|
-
return consumed;
|
|
525
|
+
return [...consumed];
|
|
348
526
|
}
|
|
349
527
|
function consumedFileServedOutputKeys() {
|
|
350
528
|
const consumed = [];
|
|
@@ -365,22 +543,34 @@ function statIdentity(absPath) {
|
|
|
365
543
|
function recordFileLineRange(filePath, start, end) {
|
|
366
544
|
const normalized = normalizePath(filePath);
|
|
367
545
|
const key = foldPath(normalized);
|
|
546
|
+
const entryKey = resolveFilesKey(normalized);
|
|
547
|
+
const entry = _files.get(entryKey);
|
|
548
|
+
const identity = dropFileLineRangesIfChanged(normalized);
|
|
368
549
|
const ranges = _fileLineRanges.get(key) ?? [];
|
|
369
550
|
if (!ranges.some(([s, e]) => s === start && e === end)) {
|
|
370
551
|
ranges.push([start, end]);
|
|
371
552
|
if (ranges.length > MAX_RANGES_PER_FILE) ranges.splice(0, ranges.length - MAX_RANGES_PER_FILE);
|
|
372
553
|
_fileLineRanges.set(key, ranges);
|
|
373
554
|
}
|
|
374
|
-
|
|
375
|
-
const entry = _files.get(entryKey);
|
|
376
|
-
const identity = statIdentity(normalized);
|
|
555
|
+
if (identity) _fileLineRangeIdentities.set(key, identity);
|
|
377
556
|
if (entry && identity) _files.set(entryKey, { ...entry, rangeFileIdentity: identity });
|
|
378
557
|
}
|
|
558
|
+
function dropFileLineRangesIfChanged(filePath) {
|
|
559
|
+
const normalized = normalizePath(filePath);
|
|
560
|
+
const identity = statIdentity(normalized);
|
|
561
|
+
const prior = _fileLineRangeIdentities.get(foldPath(normalized)) ?? _files.get(resolveFilesKey(normalized))?.rangeFileIdentity;
|
|
562
|
+
if (prior !== void 0 && identity !== void 0 && (prior.size !== identity.size || prior.mtimeMs !== identity.mtimeMs)) resetFileLineRanges(normalized);
|
|
563
|
+
return identity;
|
|
564
|
+
}
|
|
379
565
|
function getFileLineRanges(filePath) {
|
|
380
566
|
return _fileLineRanges.get(foldPath(normalizePath(filePath))) ?? [];
|
|
381
567
|
}
|
|
382
568
|
function resetFileLineRanges(filePath) {
|
|
383
|
-
|
|
569
|
+
const key = foldPath(normalizePath(filePath));
|
|
570
|
+
clearReadRangeEvasion(key);
|
|
571
|
+
_fileLineRanges.delete(key);
|
|
572
|
+
_fileLineRangeIdentities.delete(key);
|
|
573
|
+
_fileLineRangesReset.add(key);
|
|
384
574
|
}
|
|
385
575
|
var MAX_SERVED_OUTPUTS_PER_FILE = 8;
|
|
386
576
|
var GENERIC_SERVED_OUTPUT_KEY = "\0<bash-generic-served>";
|
|
@@ -410,7 +600,8 @@ function markFileTruncated(filePath, isFullRead = true) {
|
|
|
410
600
|
wasEdited: false,
|
|
411
601
|
sizeBytes: fileSize(normalized),
|
|
412
602
|
wasTruncated: true,
|
|
413
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {}
|
|
603
|
+
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {},
|
|
604
|
+
...newEntryEpochBase()
|
|
414
605
|
});
|
|
415
606
|
return;
|
|
416
607
|
}
|
|
@@ -451,6 +642,8 @@ function exportSessionState() {
|
|
|
451
642
|
bashReruns: Array.from(_bashReruns),
|
|
452
643
|
curlDownloads: Array.from(_curlDownloads.entries()),
|
|
453
644
|
fileLineRanges: Array.from(_fileLineRanges.entries()),
|
|
645
|
+
readRangeEvasion: exportReadRangeEvasion(),
|
|
646
|
+
..._fileLineRangeIdentities.size > 0 ? { fileLineRangeIdentities: Array.from(_fileLineRangeIdentities.entries()) } : {},
|
|
454
647
|
..._fileServedOutputs.size > 0 ? { fileServedOutputs: Array.from(_fileServedOutputs.entries()) } : {},
|
|
455
648
|
cliReads: Array.from(_cliReads),
|
|
456
649
|
pendingLargeFileHints: Array.from(_pendingLargeFileHints.entries()),
|
|
@@ -460,10 +653,12 @@ function exportSessionState() {
|
|
|
460
653
|
outstandingAgentSpawns: _outstandingAgentSpawns.map((e) => [e.prompt, e.ts]),
|
|
461
654
|
..._lastTabContext !== null ? { lastTabContextDigest: _lastTabContext } : {},
|
|
462
655
|
..._seenImageHashes.length > 0 ? { seenImageHashes: [..._seenImageHashes] } : {},
|
|
656
|
+
..._verificationRuns.length > 0 ? { verificationRuns: [..._verificationRuns] } : {},
|
|
463
657
|
..._compactedAt > 0 ? { compactedAt: _compactedAt } : {}
|
|
464
658
|
};
|
|
465
659
|
}
|
|
466
660
|
function importSessionState(s) {
|
|
661
|
+
importReadRangeEvasion(s.readRangeEvasion ?? []);
|
|
467
662
|
_files = /* @__PURE__ */ new Map();
|
|
468
663
|
for (const e of s.files) {
|
|
469
664
|
if (e && typeof e.path === "string") _files.set(e.path, e);
|
|
@@ -479,6 +674,8 @@ function importSessionState(s) {
|
|
|
479
674
|
_curlDownloadsAtLoad = new Map(_curlDownloads);
|
|
480
675
|
_fileLineRanges = new Map(s.fileLineRanges ?? []);
|
|
481
676
|
_fileLineRangesAtLoad = new Map(_fileLineRanges);
|
|
677
|
+
_fileLineRangesReset = /* @__PURE__ */ new Set();
|
|
678
|
+
_fileLineRangeIdentities = new Map(s.fileLineRangeIdentities ?? []);
|
|
482
679
|
_fileServedOutputs = new Map(s.fileServedOutputs ?? []);
|
|
483
680
|
_fileServedOutputsAtLoad = new Map(_fileServedOutputs);
|
|
484
681
|
_cliReads = new Set(s.cliReads ?? []);
|
|
@@ -492,9 +689,11 @@ function importSessionState(s) {
|
|
|
492
689
|
_outstandingAgentSpawnsAtLoad = [..._outstandingAgentSpawns];
|
|
493
690
|
_lastTabContext = s.lastTabContextDigest ?? null;
|
|
494
691
|
_seenImageHashes = [...s.seenImageHashes ?? []];
|
|
692
|
+
_verificationRuns = [...s.verificationRuns ?? []];
|
|
495
693
|
_compactedAt = s.compactedAt ?? 0;
|
|
496
694
|
}
|
|
497
695
|
registerReset(() => {
|
|
696
|
+
clearAllReadRangeEvasion();
|
|
498
697
|
_files = /* @__PURE__ */ new Map();
|
|
499
698
|
_filesAtLoad = /* @__PURE__ */ new Map();
|
|
500
699
|
_filesFullReadCountAtLoad = /* @__PURE__ */ new Map();
|
|
@@ -507,6 +706,8 @@ registerReset(() => {
|
|
|
507
706
|
_curlDownloadsAtLoad = /* @__PURE__ */ new Map();
|
|
508
707
|
_fileLineRanges = /* @__PURE__ */ new Map();
|
|
509
708
|
_fileLineRangesAtLoad = /* @__PURE__ */ new Map();
|
|
709
|
+
_fileLineRangesReset = /* @__PURE__ */ new Set();
|
|
710
|
+
_fileLineRangeIdentities = /* @__PURE__ */ new Map();
|
|
510
711
|
_fileServedOutputs = /* @__PURE__ */ new Map();
|
|
511
712
|
_fileServedOutputsAtLoad = /* @__PURE__ */ new Map();
|
|
512
713
|
_cliReads = /* @__PURE__ */ new Set();
|
|
@@ -520,13 +721,24 @@ registerReset(() => {
|
|
|
520
721
|
_outstandingAgentSpawnsAtLoad = [];
|
|
521
722
|
_lastTabContext = null;
|
|
522
723
|
_seenImageHashes = [];
|
|
724
|
+
_verificationRuns = [];
|
|
523
725
|
_compactedAt = 0;
|
|
524
726
|
_sessionId = null;
|
|
525
727
|
_transcriptPath = null;
|
|
526
728
|
}, { perRequest: true });
|
|
527
729
|
|
|
528
730
|
export {
|
|
731
|
+
evaluateRangeEvasion,
|
|
732
|
+
getReadRangeDenials,
|
|
733
|
+
lockReadRange,
|
|
734
|
+
recordRecentReadRange,
|
|
735
|
+
getRecentReadRanges,
|
|
736
|
+
clearReadRangeIfChanged,
|
|
737
|
+
coerceReadRangeEvasion,
|
|
738
|
+
mergeReadRangeEvasion,
|
|
739
|
+
rangeLockMessage,
|
|
529
740
|
recordFileRead,
|
|
741
|
+
unrecordRefusedRead,
|
|
530
742
|
recordSymbolRead,
|
|
531
743
|
filesReadCountAtLoad,
|
|
532
744
|
filesFullReadCountAtLoad,
|
|
@@ -534,6 +746,9 @@ export {
|
|
|
534
746
|
getSessionFiles,
|
|
535
747
|
wasFileReadThisSession,
|
|
536
748
|
wasFileFullyReadThisSession,
|
|
749
|
+
epochReadCounts,
|
|
750
|
+
wasEditedSinceCompaction,
|
|
751
|
+
mergeEpochBase,
|
|
537
752
|
getCompactedAt,
|
|
538
753
|
markCompacted,
|
|
539
754
|
getSessionFileEntry,
|
|
@@ -567,6 +782,8 @@ export {
|
|
|
567
782
|
getGlobMatchCount,
|
|
568
783
|
setLastTabContext,
|
|
569
784
|
lastTabContextMatches,
|
|
785
|
+
MAX_VERIFICATION_RUNS,
|
|
786
|
+
recordVerificationRun,
|
|
570
787
|
MAX_SEEN_IMAGE_HASHES,
|
|
571
788
|
hasSeenImage,
|
|
572
789
|
recordSeenImage,
|
|
@@ -586,6 +803,7 @@ export {
|
|
|
586
803
|
consumedFileServedOutputKeys,
|
|
587
804
|
MAX_RANGES_PER_FILE,
|
|
588
805
|
recordFileLineRange,
|
|
806
|
+
dropFileLineRangesIfChanged,
|
|
589
807
|
getFileLineRanges,
|
|
590
808
|
resetFileLineRanges,
|
|
591
809
|
MAX_SERVED_OUTPUTS_PER_FILE,
|