token-goat 2.9.29 → 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 +53 -42
- package/SECURITY.md +37 -11
- package/THIRD_PARTY_NOTICES.md +41 -4
- 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/ort-wasm-simd-threaded.mjs +59 -0
- package/dist/{token-goat-chunk-SE6E4BKJ.mjs → token-goat-chunk-25TRAWET.mjs} +23 -6
- package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
- package/dist/{token-goat-chunk-UXSXQQIY.mjs → token-goat-chunk-2M7E4PF7.mjs} +43 -14
- package/dist/token-goat-chunk-2UPZGKKY.mjs +188 -0
- 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-2WOUYWLM.mjs → token-goat-chunk-4GILLLWY.mjs} +34 -7
- package/dist/token-goat-chunk-4NAPX7BA.mjs +90 -0
- package/dist/{token-goat-chunk-NMBWLRHW.mjs → token-goat-chunk-4SC7UJYV.mjs} +9981 -11563
- package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
- package/dist/{token-goat-chunk-O6I2XU4P.mjs → token-goat-chunk-4ZBFWLXF.mjs} +310 -441
- package/dist/token-goat-chunk-57BIAXJL.mjs +286 -0
- package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
- package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
- package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
- package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
- package/dist/token-goat-chunk-646E6U44.mjs +398 -0
- package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
- package/dist/{token-goat-chunk-6AK46ZT7.mjs → token-goat-chunk-6DG6HWP3.mjs} +13 -3
- package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
- package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
- package/dist/{token-goat-chunk-E5TK5DNO.mjs → token-goat-chunk-76FGDLRO.mjs} +574 -340
- package/dist/{token-goat-chunk-TGOXNAHW.mjs → token-goat-chunk-7EZTZOMC.mjs} +780 -767
- package/dist/token-goat-chunk-7MAOA6X4.mjs +3647 -0
- package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
- package/dist/{token-goat-chunk-TCQANXYC.mjs → token-goat-chunk-AM5V6GSX.mjs} +18 -2
- package/dist/token-goat-chunk-AUNGYYQX.mjs +184 -0
- package/dist/token-goat-chunk-AUQYRMMH.mjs +2985 -0
- package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
- package/dist/{token-goat-chunk-KOPIR3KZ.mjs → token-goat-chunk-BA4HI6BW.mjs} +1910 -165
- package/dist/{token-goat-chunk-52NSDWYY.mjs → token-goat-chunk-BFCWY73P.mjs} +58 -20
- package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
- package/dist/token-goat-chunk-BWGFUZZE.mjs +25 -0
- package/dist/token-goat-chunk-C75NA7PL.mjs +322 -0
- package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
- package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
- package/dist/token-goat-chunk-CIMQ2BB3.mjs +233 -0
- package/dist/{token-goat-chunk-DNSPXQXQ.mjs → token-goat-chunk-CJLS3CDL.mjs} +70 -18
- package/dist/{token-goat-chunk-MELOKFDJ.mjs → token-goat-chunk-CO3UYX6G.mjs} +7 -1
- package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
- package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
- package/dist/token-goat-chunk-CVCEVUGK.mjs +315 -0
- package/dist/token-goat-chunk-CXHOFN7R.mjs +371 -0
- package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
- package/dist/{token-goat-chunk-E4ZOJIZK.mjs → token-goat-chunk-DGS2LVNA.mjs} +70 -160
- package/dist/{token-goat-chunk-L7H3U27L.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-EELTBKDM.mjs +613 -0
- package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
- package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
- package/dist/{token-goat-chunk-YOOVFPTP.mjs → token-goat-chunk-F4HYL64R.mjs} +12 -2
- package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
- package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
- package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
- package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
- package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
- package/dist/{token-goat-chunk-TDUT2CL6.mjs → token-goat-chunk-GL3ETKSC.mjs} +276 -19
- package/dist/{token-goat-chunk-7CPMDFGB.mjs → token-goat-chunk-GVB2MUST.mjs} +265 -1567
- package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
- package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
- package/dist/token-goat-chunk-HLPW63A7.mjs +48 -0
- package/dist/token-goat-chunk-HU4TORC5.mjs +1377 -0
- package/dist/token-goat-chunk-I7VKZZAW.mjs +35 -0
- package/dist/token-goat-chunk-IA6XSPE3.mjs +218 -0
- package/dist/token-goat-chunk-IAGXMHIK.mjs +863 -0
- package/dist/{token-goat-chunk-435UQTKD.mjs → token-goat-chunk-IK2DRMFX.mjs} +129 -74
- package/dist/{token-goat-chunk-ZER6EAXZ.mjs → token-goat-chunk-INNPTRUX.mjs} +2954 -2783
- package/dist/token-goat-chunk-JJ5BX4F4.mjs +129 -0
- package/dist/token-goat-chunk-JVFSHVFJ.mjs +129 -0
- package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
- package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
- package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
- package/dist/token-goat-chunk-LCNQ2CNN.mjs +497 -0
- 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-2AWQ2R5X.mjs → token-goat-chunk-MHX7XCC3.mjs} +3 -2
- package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
- package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
- package/dist/{token-goat-chunk-DPNLUJWB.mjs → token-goat-chunk-N5MMR2IW.mjs} +30 -8
- package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
- package/dist/{token-goat-chunk-VMFWNHGR.mjs → token-goat-chunk-NISNMD7T.mjs} +2545 -2953
- package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
- package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
- package/dist/token-goat-chunk-NSNSPPBG.mjs +69 -0
- package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
- package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
- package/dist/token-goat-chunk-ODBT2USM.mjs +800 -0
- 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-ASLWOQ3I.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -1
- package/dist/{token-goat-chunk-67BNIKKO.mjs → token-goat-chunk-P6HQSWQ3.mjs} +55 -47
- package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
- package/dist/token-goat-chunk-PFWIMH2E.mjs +261 -0
- package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
- package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
- package/dist/token-goat-chunk-PX5PQWTY.mjs +462 -0
- package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
- package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
- package/dist/token-goat-chunk-QH7YVYOY.mjs +3957 -0
- package/dist/token-goat-chunk-QLMUHEPB.mjs +43 -0
- package/dist/{token-goat-chunk-PYSUADX4.mjs → token-goat-chunk-QQOJIHL3.mjs} +50 -14
- package/dist/token-goat-chunk-QQTWJY2O.mjs +85 -0
- package/dist/token-goat-chunk-QYHO5CPH.mjs +93 -0
- package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
- package/dist/token-goat-chunk-RSLPOBKQ.mjs +339 -0
- package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
- package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
- package/dist/{token-goat-chunk-PGTH2U4C.mjs → token-goat-chunk-SOAFZNNZ.mjs} +164 -40
- package/dist/{token-goat-chunk-G23DWHV4.mjs → token-goat-chunk-SRTHT7KV.mjs} +33 -15
- package/dist/token-goat-chunk-T5P5ACNQ.mjs +212 -0
- package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
- package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
- package/dist/token-goat-chunk-TM6MC754.mjs +40 -0
- package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
- package/dist/token-goat-chunk-U2KSB4SG.mjs +56 -0
- package/dist/token-goat-chunk-U4WHMG6Y.mjs +898 -0
- package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
- package/dist/token-goat-chunk-UGJHGR5A.mjs +52 -0
- package/dist/{token-goat-chunk-RQGGMPCR.mjs → token-goat-chunk-UOUDVA5U.mjs} +76 -16
- package/dist/{token-goat-chunk-HNFZZHFW.mjs → token-goat-chunk-URRJ33GR.mjs} +22 -4
- package/dist/token-goat-chunk-UZOROKIS.mjs +165 -0
- package/dist/token-goat-chunk-VIHGGGEI.mjs +4234 -0
- package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
- package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
- package/dist/token-goat-chunk-VWZA2H4P.mjs +368 -0
- package/dist/{token-goat-chunk-QO3LXVVR.mjs → token-goat-chunk-VXEXMJDL.mjs} +2964 -3153
- package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
- package/dist/{token-goat-chunk-ONXH6NZ5.mjs → token-goat-chunk-WDH44VAU.mjs} +19 -22
- package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
- package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
- package/dist/{token-goat-chunk-RLP6J7WR.mjs → token-goat-chunk-XLRBNZCC.mjs} +40 -21
- package/dist/{token-goat-chunk-S4VSXURL.mjs → token-goat-chunk-XRKUX6CM.mjs} +4 -0
- package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
- package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
- package/dist/token-goat-chunk-Y2ZTQOCL.mjs +35 -0
- package/dist/{token-goat-chunk-UA5BKWWQ.mjs → token-goat-chunk-YB4VMGK2.mjs} +15 -4
- package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
- package/dist/{token-goat-chunk-PKRWMHVP.mjs → token-goat-chunk-YHVDKQBR.mjs} +389 -221
- package/dist/token-goat-chunk-YJB5XLWI.mjs +26 -0
- package/dist/{token-goat-chunk-PQ53BSCF.mjs → token-goat-chunk-YKB6AQG3.mjs} +53 -31
- package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
- package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
- package/dist/{token-goat-chunk-HUYUHODZ.mjs → token-goat-chunk-YY6AVUFL.mjs} +13246 -12247
- package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
- package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
- package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
- package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
- package/dist/token-goat-hook-client.cjs +87 -23
- package/dist/token-goat-hook-client.mjs +3 -3
- package/dist/token-goat-hook.mjs +76 -31
- package/dist/token-goat.core.mjs +6 -6
- package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
- package/docs/cli.md +113 -60
- package/docs/install.md +63 -20
- package/docs/security.md +10 -8
- package/package.json +18 -7
- package/scripts/verify-native-dist.mjs +386 -0
- package/dist/token-goat-chunk-2NNUA2LR.mjs +0 -143
- package/dist/token-goat-chunk-44BM7DDQ.mjs +0 -294
- package/dist/token-goat-chunk-BGYOZ6DO.mjs +0 -24
- package/dist/token-goat-chunk-C5YPNZKQ.mjs +0 -318
- package/dist/token-goat-chunk-CIQ2FTY3.mjs +0 -1990
- package/dist/token-goat-chunk-D4ETHJD6.mjs +0 -246
- package/dist/token-goat-chunk-DNRPXHYH.mjs +0 -1062
- package/dist/token-goat-chunk-EUSDXRXU.mjs +0 -1429
- package/dist/token-goat-chunk-FTP4U4QA.mjs +0 -64
- package/dist/token-goat-chunk-G7IWXCFF.mjs +0 -456
- package/dist/token-goat-chunk-GLXRTTLE.mjs +0 -36
- package/dist/token-goat-chunk-H5J3C56Q.mjs +0 -1511
- package/dist/token-goat-chunk-IVWI2OCK.mjs +0 -368
- package/dist/token-goat-chunk-JTKCQMQA.mjs +0 -418
- package/dist/token-goat-chunk-LZNBQTDK.mjs +0 -26
- package/dist/token-goat-chunk-ORNFMIER.mjs +0 -295
- package/dist/token-goat-chunk-RTMVLHWX.mjs +0 -7113
- package/dist/token-goat-chunk-VQ6F6T7X.mjs +0 -36
- package/dist/token-goat-chunk-VZQEWRVH.mjs +0 -312
- package/dist/token-goat-chunk-XYWPOSCN.mjs +0 -807
- package/dist/token-goat-chunk-YAGLESS3.mjs +0 -23
- package/dist/token-goat-chunk-YKSRAWUU.mjs +0 -33
- package/dist/token-goat-chunk-Z6KBMOBI.mjs +0 -53
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
init_define_import_meta_env
|
|
5
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
6
|
+
|
|
7
|
+
// src/code_fold.ts
|
|
8
|
+
init_define_import_meta_env();
|
|
9
|
+
var FOLDABLE_KINDS = /* @__PURE__ */ new Set(["function", "method", "func", "def", "fn", "procedure", "constructor", "variable"]);
|
|
10
|
+
var MIN_FOLDED_ROWS = 3;
|
|
11
|
+
function planBodyFolds(rows, spans, keep, minSpan) {
|
|
12
|
+
if (rows.length === 0 || spans.length === 0 || keep < 1) return [];
|
|
13
|
+
const rowAt = /* @__PURE__ */ new Map();
|
|
14
|
+
for (let i = 0; i < rows.length; i++) {
|
|
15
|
+
const row = rows[i];
|
|
16
|
+
if (row !== void 0) rowAt.set(row.no, i);
|
|
17
|
+
}
|
|
18
|
+
const ordered = [...spans].sort((a, b) => a.lineStart - b.lineStart || b.lineEnd - a.lineEnd);
|
|
19
|
+
let firstDeliveredLine = null;
|
|
20
|
+
for (const line of rowAt.keys()) if (firstDeliveredLine === null || line < firstDeliveredLine) firstDeliveredLine = line;
|
|
21
|
+
const folds = [];
|
|
22
|
+
let foldedThrough = -1;
|
|
23
|
+
for (const span of ordered) {
|
|
24
|
+
if (!FOLDABLE_KINDS.has(span.kind)) continue;
|
|
25
|
+
if (span.lineEnd - span.lineStart + 1 < minSpan) continue;
|
|
26
|
+
if (span.lineStart <= foldedThrough) continue;
|
|
27
|
+
if (firstDeliveredLine !== null && span.lineStart < firstDeliveredLine) continue;
|
|
28
|
+
const firstFolded = span.lineStart + keep;
|
|
29
|
+
if (firstFolded > span.lineEnd) continue;
|
|
30
|
+
let startIdx = -1;
|
|
31
|
+
let endIdx = -1;
|
|
32
|
+
for (let line = firstFolded; line <= span.lineEnd; line++) {
|
|
33
|
+
const idx = rowAt.get(line);
|
|
34
|
+
if (idx === void 0) continue;
|
|
35
|
+
if (startIdx < 0) startIdx = idx;
|
|
36
|
+
endIdx = idx;
|
|
37
|
+
}
|
|
38
|
+
if (startIdx < 0 || endIdx < startIdx) continue;
|
|
39
|
+
const len = endIdx - startIdx + 1;
|
|
40
|
+
const firstRow = rows[startIdx];
|
|
41
|
+
const lastRow = rows[endIdx];
|
|
42
|
+
if (firstRow === void 0 || lastRow === void 0) continue;
|
|
43
|
+
if (lastRow.no - firstRow.no + 1 !== len) continue;
|
|
44
|
+
if (len < MIN_FOLDED_ROWS) continue;
|
|
45
|
+
folds.push({ startIdx, len, name: span.name, kind: "body", declLine: span.lineStart, firstLine: firstRow.no, lastLine: lastRow.no });
|
|
46
|
+
foldedThrough = span.lineEnd;
|
|
47
|
+
}
|
|
48
|
+
return folds;
|
|
49
|
+
}
|
|
50
|
+
var SLASH_STAR = { line: ["//"], open: "/*", close: "*/" };
|
|
51
|
+
function advanceTemplateState(text, inTemplate) {
|
|
52
|
+
let t = inTemplate;
|
|
53
|
+
for (let i = 0; i < text.length; i++) {
|
|
54
|
+
const c = text[i];
|
|
55
|
+
if (c === "\\") {
|
|
56
|
+
i++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (c === "`") {
|
|
60
|
+
t = !t;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (t) continue;
|
|
64
|
+
if (c === "/" && text[i + 1] === "/") return t;
|
|
65
|
+
if (c === "'" || c === '"') {
|
|
66
|
+
const q = c;
|
|
67
|
+
i++;
|
|
68
|
+
while (i < text.length && text[i] !== q) {
|
|
69
|
+
if (text[i] === "\\") i++;
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return t;
|
|
75
|
+
}
|
|
76
|
+
var HASH = { line: ["#"] };
|
|
77
|
+
var DOUBLE_DASH = { line: ["--"] };
|
|
78
|
+
var COMMENT_SYNTAX = new Map([
|
|
79
|
+
...["ts", "tsx", "js", "jsx", "mjs", "cjs", "java", "c", "h", "cc", "cpp", "hpp", "cs", "go", "rs", "swift", "kt", "scala", "php", "dart"].map(
|
|
80
|
+
(ext) => [ext, SLASH_STAR]
|
|
81
|
+
),
|
|
82
|
+
...["py", "rb", "sh", "bash", "zsh", "pl", "r"].map((ext) => [ext, HASH]),
|
|
83
|
+
...["sql", "lua", "hs"].map((ext) => [ext, DOUBLE_DASH])
|
|
84
|
+
]);
|
|
85
|
+
function commentSyntaxFor(path) {
|
|
86
|
+
const dot = path.lastIndexOf(".");
|
|
87
|
+
if (dot < 0) return null;
|
|
88
|
+
return COMMENT_SYNTAX.get(path.slice(dot + 1).toLowerCase()) ?? null;
|
|
89
|
+
}
|
|
90
|
+
function planCommentFolds(rows, syntax, commentKeep, commentMinBlock, occupied) {
|
|
91
|
+
if (syntax === null || rows.length === 0 || commentKeep < 1 || commentMinBlock < 1) return [];
|
|
92
|
+
const folds = [];
|
|
93
|
+
let i = 0;
|
|
94
|
+
let inBlock = false;
|
|
95
|
+
const tracksTemplates = syntax.open === "/*";
|
|
96
|
+
let inTemplate = false;
|
|
97
|
+
while (i < rows.length) {
|
|
98
|
+
const start = i;
|
|
99
|
+
while (i < rows.length) {
|
|
100
|
+
const text = rows[i]?.text ?? "";
|
|
101
|
+
const trimmed = text.trim();
|
|
102
|
+
if (tracksTemplates) {
|
|
103
|
+
const wasInTemplate = inTemplate;
|
|
104
|
+
inTemplate = advanceTemplateState(text, inTemplate);
|
|
105
|
+
if (wasInTemplate || inTemplate) {
|
|
106
|
+
inBlock = false;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (inBlock) {
|
|
111
|
+
if (syntax.close !== void 0 && trimmed.includes(syntax.close)) inBlock = false;
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (syntax.open !== void 0 && trimmed.startsWith(syntax.open)) {
|
|
116
|
+
if (syntax.close === void 0 || !trimmed.slice(syntax.open.length).includes(syntax.close)) inBlock = true;
|
|
117
|
+
i++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (syntax.line.some((p) => trimmed.startsWith(p))) {
|
|
121
|
+
i++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
const runLen = i - start;
|
|
127
|
+
if (runLen >= commentMinBlock) {
|
|
128
|
+
const foldStart = start + commentKeep;
|
|
129
|
+
const len = i - foldStart;
|
|
130
|
+
const firstRow = rows[foldStart];
|
|
131
|
+
const lastRow = rows[i - 1];
|
|
132
|
+
if (len >= MIN_FOLDED_ROWS && firstRow !== void 0 && lastRow !== void 0 && lastRow.no - firstRow.no + 1 === len) {
|
|
133
|
+
let clear = true;
|
|
134
|
+
for (let k = foldStart; k < i; k++) {
|
|
135
|
+
if (occupied.has(k)) {
|
|
136
|
+
clear = false;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (clear) folds.push({ startIdx: foldStart, len, name: "comment", kind: "comment", firstLine: firstRow.no, lastLine: lastRow.no });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (i === start) i++;
|
|
144
|
+
}
|
|
145
|
+
return folds;
|
|
146
|
+
}
|
|
147
|
+
function mergeFolds(body, comment) {
|
|
148
|
+
const merged = [...body, ...comment].sort((a, b) => a.startIdx - b.startIdx || b.len - a.len);
|
|
149
|
+
const out = [];
|
|
150
|
+
let through = -1;
|
|
151
|
+
for (const fold of merged) {
|
|
152
|
+
if (fold.startIdx <= through) continue;
|
|
153
|
+
out.push(fold);
|
|
154
|
+
through = fold.startIdx + fold.len - 1;
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
var MAX_FOLD_DETAIL = 400;
|
|
159
|
+
var FOLD_DETAIL_SUFFIX_BUDGET = 16;
|
|
160
|
+
var PROSE_FOLD_MIN_CHARS = 400;
|
|
161
|
+
var PROSE_FOLD_MAX_KEEP_RATIO = 0.6;
|
|
162
|
+
var PROSE_FOLD_MIN_SENTENCE = 40;
|
|
163
|
+
var PROSE_STRUCTURAL_RE = /^\s*(?:#{1,6}\s|```|~~~|\||>|\d+[.)]\s*$|[-*+]\s*$)/;
|
|
164
|
+
var PROSE_FENCE_RE = /^\s*(?:```|~~~)/;
|
|
165
|
+
var PROSE_ABBREV_RE = /(?:\b(?:e\.g|i\.e|vs|cf|etc|approx|al|Dr|Mr|Ms|St|Fig|No)\.|\b[^\W\d_]\.)$/;
|
|
166
|
+
function proseSentenceEnd(text) {
|
|
167
|
+
for (const m of text.matchAll(/[.!?][*_`)\]"'”’]*(?=\s|$)/gu)) {
|
|
168
|
+
const term = m.index + 1;
|
|
169
|
+
const end = m.index + m[0].length;
|
|
170
|
+
if (end < PROSE_FOLD_MIN_SENTENCE) continue;
|
|
171
|
+
if (PROSE_ABBREV_RE.test(text.slice(0, term))) continue;
|
|
172
|
+
return end;
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
function planProseFolds(rows, claimed) {
|
|
177
|
+
const folds = [];
|
|
178
|
+
let inFence = false;
|
|
179
|
+
for (let i = 0; i < rows.length; i++) {
|
|
180
|
+
if (claimed.has(i)) continue;
|
|
181
|
+
const row = rows[i];
|
|
182
|
+
if (row === void 0) continue;
|
|
183
|
+
const text = row.text;
|
|
184
|
+
if (PROSE_FENCE_RE.test(text)) {
|
|
185
|
+
inFence = !inFence;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (inFence) continue;
|
|
189
|
+
if (text.length < PROSE_FOLD_MIN_CHARS) continue;
|
|
190
|
+
if (PROSE_STRUCTURAL_RE.test(text)) continue;
|
|
191
|
+
const end = proseSentenceEnd(text);
|
|
192
|
+
if (end === null || end > text.length * PROSE_FOLD_MAX_KEEP_RATIO) continue;
|
|
193
|
+
folds.push({ startIdx: i, len: 1, name: "paragraph", kind: "prose", keep: text.slice(0, end), firstLine: row.no, lastLine: row.no });
|
|
194
|
+
}
|
|
195
|
+
return folds;
|
|
196
|
+
}
|
|
197
|
+
function foldDetail(path, folds, maxLen = MAX_FOLD_DETAIL) {
|
|
198
|
+
const head = `${path}::`;
|
|
199
|
+
const ids = folds.map((f) => f.kind === "body" ? f.name : `#${f.firstLine}-${f.lastLine}`);
|
|
200
|
+
const budget = maxLen - head.length - FOLD_DETAIL_SUFFIX_BUDGET;
|
|
201
|
+
const kept = [];
|
|
202
|
+
let used = 0;
|
|
203
|
+
for (const id of ids) {
|
|
204
|
+
const add = kept.length === 0 ? id.length : id.length + 1;
|
|
205
|
+
if (used + add > budget) break;
|
|
206
|
+
kept.push(id);
|
|
207
|
+
used += add;
|
|
208
|
+
}
|
|
209
|
+
const dropped = ids.length - kept.length;
|
|
210
|
+
if (kept.length === 0) return `${head}+${ids.length} folds`;
|
|
211
|
+
return dropped > 0 ? `${head}${kept.join(",")},+${dropped} more` : `${head}${kept.join(",")}`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export {
|
|
215
|
+
planBodyFolds,
|
|
216
|
+
commentSyntaxFor,
|
|
217
|
+
planCommentFolds,
|
|
218
|
+
mergeFolds,
|
|
219
|
+
planProseFolds,
|
|
220
|
+
foldDetail
|
|
221
|
+
};
|
|
@@ -3107,6 +3107,21 @@ function encodePng(width, height, rgba) {
|
|
|
3107
3107
|
const iendChunk = makePngChunk("IEND", Buffer.alloc(0));
|
|
3108
3108
|
return Buffer.concat([signature, ihdrChunk, idatChunk, iendChunk]);
|
|
3109
3109
|
}
|
|
3110
|
+
function bmpHasAlpha(buf, layout) {
|
|
3111
|
+
const { compression, bpp, pixelOffset, rowStride, width, height } = layout;
|
|
3112
|
+
if (bpp !== 32) return false;
|
|
3113
|
+
const dibSize = buf.readUInt32LE(14);
|
|
3114
|
+
if (compression === 3 && dibSize >= 56 && buf.length >= 14 + 56) {
|
|
3115
|
+
return buf.readUInt32LE(14 + 52) !== 0;
|
|
3116
|
+
}
|
|
3117
|
+
for (let y = 0; y < height; y++) {
|
|
3118
|
+
const rowOffset = pixelOffset + y * rowStride;
|
|
3119
|
+
for (let x = 0; x < width; x++) {
|
|
3120
|
+
if (buf[rowOffset + x * 4 + 3] !== 0) return true;
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return false;
|
|
3124
|
+
}
|
|
3110
3125
|
function decodeBmp(buf) {
|
|
3111
3126
|
if (buf.length < 54 || buf[0] !== 66 || buf[1] !== 77) {
|
|
3112
3127
|
throw new Error("Invalid BMP signature");
|
|
@@ -3125,8 +3140,12 @@ function decodeBmp(buf) {
|
|
|
3125
3140
|
throw new Error("Unsupported BMP bit depth: " + bpp);
|
|
3126
3141
|
}
|
|
3127
3142
|
assertDecodableSize("BMP", width, height, 4);
|
|
3128
|
-
const outRgba = Buffer.alloc(width * height * 4);
|
|
3129
3143
|
const rowStride = Math.floor((bpp * width + 31) / 32) * 4;
|
|
3144
|
+
if (pixelOffset + (height - 1) * rowStride + width * (bpp / 8) > buf.length) {
|
|
3145
|
+
throw new Error("BMP pixel data truncated");
|
|
3146
|
+
}
|
|
3147
|
+
const outRgba = Buffer.alloc(width * height * 4);
|
|
3148
|
+
const alphaIsReal = bmpHasAlpha(buf, { compression, bpp, pixelOffset, rowStride, width, height });
|
|
3130
3149
|
for (let y = 0; y < height; y++) {
|
|
3131
3150
|
const srcY = topDown ? y : height - 1 - y;
|
|
3132
3151
|
const rowOffset = pixelOffset + srcY * rowStride;
|
|
@@ -3143,7 +3162,7 @@ function decodeBmp(buf) {
|
|
|
3143
3162
|
outRgba[outIdx] = buf[pxOffset + 2] ?? 0;
|
|
3144
3163
|
outRgba[outIdx + 1] = buf[pxOffset + 1] ?? 0;
|
|
3145
3164
|
outRgba[outIdx + 2] = buf[pxOffset] ?? 0;
|
|
3146
|
-
outRgba[outIdx + 3] = buf[pxOffset + 3] ?? 255;
|
|
3165
|
+
outRgba[outIdx + 3] = alphaIsReal ? buf[pxOffset + 3] ?? 255 : 255;
|
|
3147
3166
|
}
|
|
3148
3167
|
}
|
|
3149
3168
|
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
MAX_LINES_FOR_DIFF,
|
|
5
|
+
lcsLength,
|
|
6
|
+
readKnownText,
|
|
7
|
+
readShapeOf,
|
|
8
|
+
splitLines
|
|
9
|
+
} from "./token-goat-chunk-5AC66HNP.mjs";
|
|
10
|
+
import "./token-goat-chunk-WBA5SKT4.mjs";
|
|
11
|
+
import {
|
|
12
|
+
sessionStateKey
|
|
13
|
+
} from "./token-goat-chunk-C75NA7PL.mjs";
|
|
14
|
+
import {
|
|
15
|
+
preToolPathDeclined
|
|
16
|
+
} from "./token-goat-chunk-P6VGNTQT.mjs";
|
|
17
|
+
import {
|
|
18
|
+
contextOutput,
|
|
19
|
+
denyOutput,
|
|
20
|
+
getCwd,
|
|
21
|
+
getFilePath,
|
|
22
|
+
getToolInput,
|
|
23
|
+
getToolName,
|
|
24
|
+
passOutput,
|
|
25
|
+
resolveEventPath
|
|
26
|
+
} from "./token-goat-chunk-76FGDLRO.mjs";
|
|
27
|
+
import {
|
|
28
|
+
dropFileLineRangesIfChanged,
|
|
29
|
+
getFileLineRanges,
|
|
30
|
+
markHintShown,
|
|
31
|
+
wasFileFullyReadThisSession,
|
|
32
|
+
wasHintShown
|
|
33
|
+
} from "./token-goat-chunk-GL3ETKSC.mjs";
|
|
34
|
+
import {
|
|
35
|
+
recordStat
|
|
36
|
+
} from "./token-goat-chunk-U4WHMG6Y.mjs";
|
|
37
|
+
import "./token-goat-chunk-GVB2MUST.mjs";
|
|
38
|
+
import "./token-goat-chunk-XB5KKOCG.mjs";
|
|
39
|
+
import "./token-goat-chunk-OUKDTVNU.mjs";
|
|
40
|
+
import "./token-goat-chunk-BFCWY73P.mjs";
|
|
41
|
+
import "./token-goat-chunk-KGEFFSHD.mjs";
|
|
42
|
+
import "./token-goat-chunk-XX6O25RN.mjs";
|
|
43
|
+
import "./token-goat-chunk-HAVAOB3S.mjs";
|
|
44
|
+
import "./token-goat-chunk-T5P5ACNQ.mjs";
|
|
45
|
+
import {
|
|
46
|
+
loadConfig
|
|
47
|
+
} from "./token-goat-chunk-7EZTZOMC.mjs";
|
|
48
|
+
import "./token-goat-chunk-QYHO5CPH.mjs";
|
|
49
|
+
import {
|
|
50
|
+
fingerprintContent,
|
|
51
|
+
resolveProjectRoot
|
|
52
|
+
} from "./token-goat-chunk-4GBVPH3D.mjs";
|
|
53
|
+
import "./token-goat-chunk-YZAAZU2S.mjs";
|
|
54
|
+
import "./token-goat-chunk-IVE6U7KV.mjs";
|
|
55
|
+
import {
|
|
56
|
+
isWithinQuietHours
|
|
57
|
+
} from "./token-goat-chunk-HU4TORC5.mjs";
|
|
58
|
+
import {
|
|
59
|
+
canQuoteArg,
|
|
60
|
+
echoedValue,
|
|
61
|
+
fencedCommand,
|
|
62
|
+
fileSubject,
|
|
63
|
+
quotedArg
|
|
64
|
+
} from "./token-goat-chunk-GGGG7RWB.mjs";
|
|
65
|
+
import {
|
|
66
|
+
canonicalize
|
|
67
|
+
} from "./token-goat-chunk-AM5V6GSX.mjs";
|
|
68
|
+
import {
|
|
69
|
+
displaySafePath,
|
|
70
|
+
normalizePath
|
|
71
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
72
|
+
import "./token-goat-chunk-CO3UYX6G.mjs";
|
|
73
|
+
import {
|
|
74
|
+
init_define_import_meta_env
|
|
75
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
76
|
+
|
|
77
|
+
// src/write_guard_hooks.ts
|
|
78
|
+
init_define_import_meta_env();
|
|
79
|
+
|
|
80
|
+
// src/sibling_copy.ts
|
|
81
|
+
init_define_import_meta_env();
|
|
82
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
83
|
+
var BACKUP_EXTENSIONS = /* @__PURE__ */ new Set([".bak", ".orig", ".new"]);
|
|
84
|
+
var VERSIONED_STEM = /^(.*\D)[_.-]?v\d+$/i;
|
|
85
|
+
var COPY_SUFFIX_STEM = /^(.+?)(?:[_.-](?:new|fixed|copy|old|orig|backup|bak)| copy| - copy| \(\d+\))$/i;
|
|
86
|
+
var SERIES_DIRECTORIES = /* @__PURE__ */ new Set(["migrations", "versions", "fixtures", "__snapshots__"]);
|
|
87
|
+
var VERSION_DIRECTORY = /^v\d+$/i;
|
|
88
|
+
function siblingCandidates(filePath) {
|
|
89
|
+
const dir = dirname(filePath);
|
|
90
|
+
const base = basename(filePath);
|
|
91
|
+
const ext = extname(base);
|
|
92
|
+
const stem = ext === "" ? base : base.slice(0, -ext.length);
|
|
93
|
+
const names = [];
|
|
94
|
+
if (BACKUP_EXTENSIONS.has(ext.toLowerCase()) && extname(stem) !== "") names.push(stem);
|
|
95
|
+
const versioned = VERSIONED_STEM.exec(stem);
|
|
96
|
+
if (versioned !== null) names.push(versioned[1].replace(/[_.-]+$/, "") + ext);
|
|
97
|
+
const copied = COPY_SUFFIX_STEM.exec(stem);
|
|
98
|
+
if (copied !== null) names.push(copied[1] + ext);
|
|
99
|
+
return names.filter((name, i) => name !== "" && name !== ext && name !== base && names.indexOf(name) === i).map((name) => join(dir, name));
|
|
100
|
+
}
|
|
101
|
+
function globToRegExp(glob) {
|
|
102
|
+
let source = "";
|
|
103
|
+
for (let i = 0; i < glob.length; i++) {
|
|
104
|
+
const c = glob[i];
|
|
105
|
+
if (c === "*" && glob[i + 1] === "*") {
|
|
106
|
+
source += ".*";
|
|
107
|
+
i++;
|
|
108
|
+
} else if (c === "*") {
|
|
109
|
+
source += "[^/]*";
|
|
110
|
+
} else if (c === "?") {
|
|
111
|
+
source += "[^/]";
|
|
112
|
+
} else {
|
|
113
|
+
source += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return new RegExp("(?:^|/)" + source + "$", "i");
|
|
117
|
+
}
|
|
118
|
+
function directorySegments(normalized, projectRoot) {
|
|
119
|
+
const root = projectRoot === null ? "" : projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
120
|
+
if (root !== "" && normalized.toLowerCase().startsWith(root.toLowerCase() + "/")) return normalized.slice(root.length + 1).split("/").slice(0, -1).map((s) => s.toLowerCase());
|
|
121
|
+
if (root === "") return normalized.split("/").slice(0, -1).map((s) => s.toLowerCase());
|
|
122
|
+
return normalized.split("/").slice(-2, -1).map((s) => s.toLowerCase());
|
|
123
|
+
}
|
|
124
|
+
function siblingCopyExcluded(filePath, allow, projectRoot) {
|
|
125
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
126
|
+
const segments = directorySegments(normalized, projectRoot);
|
|
127
|
+
if (segments.some((s) => SERIES_DIRECTORIES.has(s) || VERSION_DIRECTORY.test(s))) return true;
|
|
128
|
+
return allow.some((glob) => glob !== "" && globToRegExp(glob.replace(/\\/g, "/")).test(normalized));
|
|
129
|
+
}
|
|
130
|
+
function siblingCopyMessage(original, unchangedPct) {
|
|
131
|
+
const shown = displaySafePath(original);
|
|
132
|
+
const outline = canQuoteArg(shown) ? `, or run ${fencedCommand("token-goat outline " + quotedArg(shown))} to find the part to change` : "";
|
|
133
|
+
return `This new file repeats about ${Math.round(unchangedPct)}% of an existing file in the same directory. Edit the original with \`Edit\` or \`token-goat replace\` instead of writing a second copy of it${outline}. If a separate copy is intended, carry on.`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/write_guards.ts
|
|
137
|
+
init_define_import_meta_env();
|
|
138
|
+
var ELLIPSIS = String.raw`(?:\.{3}|…)`;
|
|
139
|
+
var COMMENT_LEAD = String.raw`(?:/{2,}|#+|/\*+|\*+|<!--|--|;+|%+|"""|''')`;
|
|
140
|
+
var COMMENT_CLOSE = String.raw`(?:\*+/|-->|"""|''')`;
|
|
141
|
+
var KEYWORD = String.raw`(?:rest|remainder|remaining|existing|unchanged|omitted|truncated|previous|same as|other)`;
|
|
142
|
+
var SUBJECT = String.raw`(?:rest of (?:the )?(?:file|code|content|function|class|module|implementation|method)|existing (?:code|content|implementation)|remaining (?:code|content|lines|implementation)|previous (?:code|content))`;
|
|
143
|
+
var REST_SUBJECT = String.raw`(?:rest of (?:the )?(?:file|code|content|function|class|module|implementation|method)|remaining (?:code|content|lines|implementation))`;
|
|
144
|
+
var TRAILER = String.raw`(?:(?:is |remains |stays |goes )?(?:unchanged|here|omitted|as[- ]is|the same|same as before|as before|above|below))`;
|
|
145
|
+
var MAX_ELISION_LINE_CHARS = 120;
|
|
146
|
+
var LEADING_COMMENT = new RegExp(`^${COMMENT_LEAD}`);
|
|
147
|
+
var TRAILING_COMMENT = new RegExp(`${COMMENT_CLOSE}$`);
|
|
148
|
+
var ANY_ELLIPSIS = new RegExp(ELLIPSIS, "g");
|
|
149
|
+
var HAS_ELLIPSIS = new RegExp(ELLIPSIS);
|
|
150
|
+
var STARTS_WITH_ELLIPSIS = new RegExp(`^${ELLIPSIS}`);
|
|
151
|
+
var ENDS_WITH_ELLIPSIS = new RegExp(`${ELLIPSIS}$`);
|
|
152
|
+
var LEAD_THEN_TRAILER = new RegExp(`^(?:keep )?(?:the )?${KEYWORD}(?: \\S+){0,4}? (?:unchanged|here|omitted|truncated|as[- ]is|the same|as before|above|below)$`, "i");
|
|
153
|
+
var WRAPPED_MARKER = new RegExp(`^(?:the )?${KEYWORD}(?: \\S+){0,3}$`, "i");
|
|
154
|
+
var SUBJECT_ONLY = new RegExp(`^${SUBJECT}(?: ${TRAILER})?$`, "i");
|
|
155
|
+
var SUBJECT_QUALIFIED = new RegExp(`^${SUBJECT} (?:(?:is |are |remains? |stays? )?(?:unchanged|omitted|truncated|not shown|as[- ]is|as before|same as before)|(?:remains?|stays?|is|are) (?:the )?same)$`, "i");
|
|
156
|
+
var REST_PLACED = new RegExp(`^(?:${REST_SUBJECT} (?:(?:goes |is |comes )?(?:here|above|below)|follows)|rest of (?:the )?implementation)$`, "i");
|
|
157
|
+
var ELLIPSIS_QUALIFIER = new RegExp(`^(?:(?:the )?(?:same as before|as before|unchanged|omitted|truncated|not shown)|\\d+ (?:more )?\\S+ (?:omitted|truncated|not shown|unchanged|hidden|elided))$`, "i");
|
|
158
|
+
var BRACKET_NOTE = new RegExp(`^(?:truncated|omitted|content (?:truncated|omitted)|(?:remaining|rest of)[^\\]]{0,60}(?:omitted|truncated|unchanged)|\\d+ (?:more )?lines? (?:omitted|truncated|folded))$`, "i");
|
|
159
|
+
var FOLD_MARKER = new RegExp(`^${ELLIPSIS}\\s*\\d+\\s+(?:more\\s+)?lines?\\b.*\\bfolded\\b`, "i");
|
|
160
|
+
var TOKEN_GOAT_NOTICE = /^\[token-goat[: ].{0,200}\]$/;
|
|
161
|
+
function spaced(text) {
|
|
162
|
+
return text.replace(ANY_ELLIPSIS, " ").replace(/\s+/g, " ").trim();
|
|
163
|
+
}
|
|
164
|
+
function isElisionLine(trimmed) {
|
|
165
|
+
if (trimmed === "" || trimmed.length > MAX_ELISION_LINE_CHARS) return false;
|
|
166
|
+
if (TOKEN_GOAT_NOTICE.test(trimmed) || FOLD_MARKER.test(trimmed)) return true;
|
|
167
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) return BRACKET_NOTE.test(spaced(trimmed.slice(1, -1)));
|
|
168
|
+
const led = LEADING_COMMENT.test(trimmed);
|
|
169
|
+
if (!led && !STARTS_WITH_ELLIPSIS.test(trimmed)) return false;
|
|
170
|
+
const body = led ? trimmed.replace(LEADING_COMMENT, "").replace(TRAILING_COMMENT, "").trim() : trimmed;
|
|
171
|
+
const payload = spaced(body).replace(/^[([](.*)[)\]]$/, "$1").trim();
|
|
172
|
+
const hasEllipsis = HAS_ELLIPSIS.test(body);
|
|
173
|
+
if (!hasEllipsis) return SUBJECT_QUALIFIED.test(payload) || REST_PLACED.test(payload);
|
|
174
|
+
if (SUBJECT_ONLY.test(payload) || ELLIPSIS_QUALIFIER.test(payload)) return true;
|
|
175
|
+
return LEAD_THEN_TRAILER.test(payload) || STARTS_WITH_ELLIPSIS.test(body) && ENDS_WITH_ELLIPSIS.test(body) && WRAPPED_MARKER.test(payload);
|
|
176
|
+
}
|
|
177
|
+
function findNewElisionLine(newText, knownText) {
|
|
178
|
+
let known;
|
|
179
|
+
for (const raw of splitLines(newText)) {
|
|
180
|
+
const trimmed = raw.trim();
|
|
181
|
+
if (!isElisionLine(trimmed)) continue;
|
|
182
|
+
known ??= new Set(splitLines(typeof knownText === "function" ? knownText() : knownText).map((l) => l.trim()));
|
|
183
|
+
if (!known.has(trimmed)) return trimmed;
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
function patchAddedLines(patch) {
|
|
188
|
+
const files = [];
|
|
189
|
+
let current;
|
|
190
|
+
for (const line of patch.split(/\r\n|\r|\n/)) {
|
|
191
|
+
const header = /^\*\*\* (?:Add|Update) File: (.+)$/.exec(line);
|
|
192
|
+
const moved = /^\*\*\* Move to: (.+)$/.exec(line);
|
|
193
|
+
if (header !== null) {
|
|
194
|
+
current = { path: header[1].trim(), added: [] };
|
|
195
|
+
files.push(current);
|
|
196
|
+
} else if (moved !== null && current !== void 0) {
|
|
197
|
+
current.path = moved[1].trim();
|
|
198
|
+
} else if (line.startsWith("*** ")) {
|
|
199
|
+
current = void 0;
|
|
200
|
+
} else if (current !== void 0 && line.startsWith("+")) {
|
|
201
|
+
current.added.push(line.slice(1));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return files;
|
|
205
|
+
}
|
|
206
|
+
var MAX_DIFF_SPAN = 2e3;
|
|
207
|
+
function removedLineIndexes(oldLines, newLines) {
|
|
208
|
+
let head = 0;
|
|
209
|
+
while (head < oldLines.length && head < newLines.length && oldLines[head] === newLines[head]) head++;
|
|
210
|
+
let tail = 0;
|
|
211
|
+
while (tail < oldLines.length - head && tail < newLines.length - head && oldLines[oldLines.length - 1 - tail] === newLines[newLines.length - 1 - tail]) tail++;
|
|
212
|
+
const n = oldLines.length - head - tail;
|
|
213
|
+
const m = newLines.length - head - tail;
|
|
214
|
+
const removed = [];
|
|
215
|
+
if (m === 0 || n > MAX_DIFF_SPAN || m > MAX_DIFF_SPAN) {
|
|
216
|
+
for (let i2 = 0; i2 < n; i2++) removed.push(head + i2);
|
|
217
|
+
return removed;
|
|
218
|
+
}
|
|
219
|
+
const width = m + 1;
|
|
220
|
+
const goesLeft = new Uint8Array(Math.ceil((n + 1) * width / 8));
|
|
221
|
+
let above = new Uint16Array(width);
|
|
222
|
+
let row = new Uint16Array(width);
|
|
223
|
+
for (let i2 = 1; i2 <= n; i2++) {
|
|
224
|
+
for (let j2 = 1; j2 <= m; j2++) {
|
|
225
|
+
if (oldLines[head + i2 - 1] === newLines[head + j2 - 1]) {
|
|
226
|
+
row[j2] = (above[j2 - 1] ?? 0) + 1;
|
|
227
|
+
} else {
|
|
228
|
+
const left = row[j2 - 1] ?? 0;
|
|
229
|
+
const up = above[j2] ?? 0;
|
|
230
|
+
row[j2] = Math.max(left, up);
|
|
231
|
+
if (left >= up) goesLeft[i2 * width + j2 >> 3] |= 1 << (i2 * width + j2 & 7);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
;
|
|
235
|
+
[above, row] = [row, above];
|
|
236
|
+
}
|
|
237
|
+
let i = n;
|
|
238
|
+
let j = m;
|
|
239
|
+
while (i > 0) {
|
|
240
|
+
if (j > 0 && oldLines[head + i - 1] === newLines[head + j - 1]) {
|
|
241
|
+
i--;
|
|
242
|
+
j--;
|
|
243
|
+
} else if (j > 0 && ((goesLeft[i * width + j >> 3] ?? 0) & 1 << (i * width + j & 7)) !== 0) {
|
|
244
|
+
j--;
|
|
245
|
+
} else {
|
|
246
|
+
removed.push(head + i - 1);
|
|
247
|
+
i--;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return removed.reverse();
|
|
251
|
+
}
|
|
252
|
+
function unseenRemovedRuns(oldLines, newLines, served) {
|
|
253
|
+
const unseen = removedLineIndexes(oldLines, newLines).map((i) => i + 1).filter((line) => !served.some(([s, e]) => line >= s && line <= e));
|
|
254
|
+
const runs = [];
|
|
255
|
+
for (const line of unseen) {
|
|
256
|
+
const last = runs[runs.length - 1];
|
|
257
|
+
if (last !== void 0 && last[1] === line - 1) last[1] = line;
|
|
258
|
+
else runs.push([line, line]);
|
|
259
|
+
}
|
|
260
|
+
return runs;
|
|
261
|
+
}
|
|
262
|
+
var BLIND_DROP_MIN_LINES = 5;
|
|
263
|
+
function countRunLines(runs) {
|
|
264
|
+
return runs.reduce((sum, [s, e]) => sum + (e - s + 1), 0);
|
|
265
|
+
}
|
|
266
|
+
var ELISION_ADVICE = "Write the real content, or change only the part you mean to with `Edit` or `token-goat replace`. If this exact text is intended, repeat the identical call and it goes through.";
|
|
267
|
+
function placeholderMessage(line) {
|
|
268
|
+
const shown = echoedValue(line.length > 100 ? line.slice(0, 100) + "..." : line);
|
|
269
|
+
return `This call writes a placeholder line (${shown}) that is not in the file now. Written as it stands, that line replaces whatever it stands for. ${ELISION_ADVICE}`;
|
|
270
|
+
}
|
|
271
|
+
var MAX_QUOTED_PLACEHOLDERS = 3;
|
|
272
|
+
function placeholdersMessage(found) {
|
|
273
|
+
if (found.length === 1) return placeholderMessage(found[0]);
|
|
274
|
+
const quoted = found.slice(0, MAX_QUOTED_PLACEHOLDERS).map((line) => echoedValue(line.length > 100 ? line.slice(0, 100) + "..." : line));
|
|
275
|
+
const more = found.length > quoted.length ? ` and ${found.length - quoted.length} more` : "";
|
|
276
|
+
return `This call writes ${found.length} placeholder lines (${quoted.join(", ")}${more}) that are not in the files now. Written as they stand, each replaces whatever it stands for. ${ELISION_ADVICE}`;
|
|
277
|
+
}
|
|
278
|
+
function blindDropMessage(filePath, runs) {
|
|
279
|
+
const total = countRunLines(runs);
|
|
280
|
+
const named = [...runs].sort((a, b) => b[1] - b[0] - (a[1] - a[0])).slice(0, 3).sort((a, b) => a[0] - b[0]);
|
|
281
|
+
const shownPath = displaySafePath(filePath);
|
|
282
|
+
const commands = named.map(([s, e]) => fencedCommand("token-goat read " + quotedArg(`${shownPath}@${s}-${e}`)));
|
|
283
|
+
return `This Write would delete ${total} lines of ${fileSubject(commands.join(" "), shownPath, filePath)} that this session never read in full (lines ${named.map(([s, e]) => s === e ? String(s) : `${s}-${e}`).join(", ")}). Read them first with ${commands.join(" or ")}, or change only what you mean to with \`Edit\` or \`token-goat replace\`. If dropping them is intended, repeat the identical call and it goes through.`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/write_guard_hooks.ts
|
|
287
|
+
function guardVerdict(key, message, detail) {
|
|
288
|
+
const hints = loadConfig().hints;
|
|
289
|
+
const policy = hints.write_blind_drop;
|
|
290
|
+
if (policy === "off" || wasHintShown(key)) return passOutput();
|
|
291
|
+
if (policy === "warn" && isWithinQuietHours(hints.quiet_hours)) return passOutput();
|
|
292
|
+
markHintShown(key);
|
|
293
|
+
recordStat("write_blind_drop", 0, 0, void 0, detail);
|
|
294
|
+
return policy === "deny" ? denyOutput(message) : contextOutput(message);
|
|
295
|
+
}
|
|
296
|
+
function guardKey(kind, file, text) {
|
|
297
|
+
return "write_blind_drop:" + kind + ":" + fingerprintContent(file + "\0" + text);
|
|
298
|
+
}
|
|
299
|
+
function placeholderGuard(event, filePath, newText, knownText) {
|
|
300
|
+
if (loadConfig().hints.write_blind_drop === "off") return passOutput();
|
|
301
|
+
const line = findNewElisionLine(newText, knownText);
|
|
302
|
+
if (line === null) return passOutput();
|
|
303
|
+
return guardVerdict(guardKey("placeholder", filePath, newText), placeholderMessage(line), "kind=placeholder tool=" + (getToolName(event) ?? "unknown"));
|
|
304
|
+
}
|
|
305
|
+
function blindDropGuard(event, filePath, newContent, oldLines, newLines) {
|
|
306
|
+
if (loadConfig().hints.write_blind_drop === "off") return passOutput();
|
|
307
|
+
const normalized = normalizePath(filePath);
|
|
308
|
+
const shape = readShapeOf(sessionStateKey(event), normalized);
|
|
309
|
+
if (shape === null || shape === "fold" || shape === "truncated") return passOutput();
|
|
310
|
+
if (wasFileFullyReadThisSession(normalized)) return passOutput();
|
|
311
|
+
dropFileLineRangesIfChanged(normalized);
|
|
312
|
+
const served = getFileLineRanges(normalized);
|
|
313
|
+
if (shape === "partial" && served.length === 0) return passOutput();
|
|
314
|
+
const runs = unseenRemovedRuns(oldLines, newLines, served);
|
|
315
|
+
if (countRunLines(runs) < BLIND_DROP_MIN_LINES) return passOutput();
|
|
316
|
+
return guardVerdict(guardKey("blind", filePath, newContent), blindDropMessage(filePath, runs), "kind=blind_drop last_read=" + shape + " lines=" + countRunLines(runs));
|
|
317
|
+
}
|
|
318
|
+
function siblingCopyGuard(event, filePath, newContent) {
|
|
319
|
+
const cfg = loadConfig().hints;
|
|
320
|
+
if (!cfg.write_sibling_copy) return passOutput();
|
|
321
|
+
const candidates = siblingCandidates(filePath);
|
|
322
|
+
if (candidates.length === 0) return passOutput();
|
|
323
|
+
const cwd = getCwd(event);
|
|
324
|
+
if (siblingCopyExcluded(canonicalize(filePath, cwd), cfg.write_sibling_copy_allow, cwd === void 0 ? null : resolveProjectRoot({ project: cwd }))) return passOutput();
|
|
325
|
+
const newLines = splitLines(newContent);
|
|
326
|
+
if (newLines.length > MAX_LINES_FOR_DIFF) return passOutput();
|
|
327
|
+
for (const original of candidates) {
|
|
328
|
+
const oldLines = splitLines(readKnownText(original));
|
|
329
|
+
if (oldLines.length < cfg.write_rewrite_min_lines || oldLines.length > MAX_LINES_FOR_DIFF) continue;
|
|
330
|
+
const unchangedPct = lcsLength(oldLines, newLines) / oldLines.length * 100;
|
|
331
|
+
if (unchangedPct < cfg.write_rewrite_unchanged_pct) continue;
|
|
332
|
+
const key = "write_sibling_copy:" + fingerprintContent(original);
|
|
333
|
+
if (wasHintShown(key)) return passOutput();
|
|
334
|
+
markHintShown(key);
|
|
335
|
+
const shownPct = Math.round(unchangedPct);
|
|
336
|
+
recordStat("write_sibling_copy", 0, 0, void 0, "unchanged_pct=" + shownPct);
|
|
337
|
+
return contextOutput(siblingCopyMessage(original, unchangedPct));
|
|
338
|
+
}
|
|
339
|
+
return passOutput();
|
|
340
|
+
}
|
|
341
|
+
var MAX_EDIT_FILES_CHECKED = 20;
|
|
342
|
+
function preEditPlaceholderGuard(event) {
|
|
343
|
+
if (loadConfig().hints.write_blind_drop === "off") return passOutput();
|
|
344
|
+
const input = getToolInput(event);
|
|
345
|
+
const patch = typeof input["command"] === "string" ? input["command"] : input["input"];
|
|
346
|
+
if (typeof patch === "string" && input["new_string"] === void 0 && input["edits"] === void 0 && input["replacements"] === void 0) {
|
|
347
|
+
for (const file of patchAddedLines(patch)) {
|
|
348
|
+
const target = resolveEventPath(event, file.path);
|
|
349
|
+
if (preToolPathDeclined(event, target)) continue;
|
|
350
|
+
const verdict2 = placeholderGuard(event, target, file.added.join("\n"), () => readKnownText(target));
|
|
351
|
+
if (verdict2.hookType !== "pass") return verdict2;
|
|
352
|
+
}
|
|
353
|
+
return passOutput();
|
|
354
|
+
}
|
|
355
|
+
const known = /* @__PURE__ */ new Map();
|
|
356
|
+
const fileText = (path) => {
|
|
357
|
+
let text = known.get(path);
|
|
358
|
+
if (text === void 0) known.set(path, text = readKnownText(path));
|
|
359
|
+
return text;
|
|
360
|
+
};
|
|
361
|
+
const edits = [];
|
|
362
|
+
if (Array.isArray(input["replacements"])) {
|
|
363
|
+
for (const raw of input["replacements"]) {
|
|
364
|
+
const named = raw !== null && typeof raw === "object" ? raw["filePath"] : void 0;
|
|
365
|
+
edits.push({ path: typeof named === "string" && named !== "" ? resolveEventPath(event, named) : void 0, raw });
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
const filePath = getFilePath(event);
|
|
369
|
+
for (const raw of Array.isArray(input["edits"]) ? input["edits"] : [input]) edits.push({ path: filePath, raw });
|
|
370
|
+
}
|
|
371
|
+
const flagged = [];
|
|
372
|
+
const examined = /* @__PURE__ */ new Set();
|
|
373
|
+
for (const { path, raw } of edits) {
|
|
374
|
+
if (path === void 0 || raw === null || typeof raw !== "object" || preToolPathDeclined(event, path)) continue;
|
|
375
|
+
const edit = raw;
|
|
376
|
+
const newString = edit["new_string"] ?? edit["newString"];
|
|
377
|
+
if (typeof newString !== "string") continue;
|
|
378
|
+
if (!examined.has(path)) {
|
|
379
|
+
if (examined.size >= MAX_EDIT_FILES_CHECKED) continue;
|
|
380
|
+
examined.add(path);
|
|
381
|
+
}
|
|
382
|
+
const oldString = edit["old_string"] ?? edit["oldString"];
|
|
383
|
+
const replaced = typeof oldString === "string" ? oldString : "";
|
|
384
|
+
const line = findNewElisionLine(newString, () => fileText(path) + "\n" + replaced);
|
|
385
|
+
const key = guardKey("placeholder", path, newString);
|
|
386
|
+
if (line !== null && !wasHintShown(key)) flagged.push({ line, key });
|
|
387
|
+
}
|
|
388
|
+
if (flagged.length === 0) return passOutput();
|
|
389
|
+
const verdict = guardVerdict(flagged[0].key, placeholdersMessage(flagged.map((f) => f.line)), "kind=placeholder tool=" + (getToolName(event) ?? "unknown") + " entries=" + flagged.length);
|
|
390
|
+
if (verdict.hookType !== "pass") for (const { key } of flagged) markHintShown(key);
|
|
391
|
+
return verdict;
|
|
392
|
+
}
|
|
393
|
+
export {
|
|
394
|
+
blindDropGuard,
|
|
395
|
+
placeholderGuard,
|
|
396
|
+
preEditPlaceholderGuard,
|
|
397
|
+
siblingCopyGuard
|
|
398
|
+
};
|