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
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
|
-
import {
|
|
4
|
-
estimateTokensFromLength
|
|
5
|
-
} from "./token-goat-chunk-JB6QN6VF.mjs";
|
|
6
3
|
import {
|
|
7
4
|
recordStat,
|
|
8
5
|
savedTokensFromBytes
|
|
9
|
-
} from "./token-goat-chunk-
|
|
6
|
+
} from "./token-goat-chunk-U4WHMG6Y.mjs";
|
|
7
|
+
import {
|
|
8
|
+
estimateTokensFromLength
|
|
9
|
+
} from "./token-goat-chunk-BFCWY73P.mjs";
|
|
10
10
|
import {
|
|
11
11
|
countRedactionPlaceholders
|
|
12
|
-
} from "./token-goat-chunk-
|
|
12
|
+
} from "./token-goat-chunk-T5P5ACNQ.mjs";
|
|
13
13
|
import {
|
|
14
14
|
loadConfig,
|
|
15
15
|
ownGet
|
|
16
|
-
} from "./token-goat-chunk-
|
|
16
|
+
} from "./token-goat-chunk-7EZTZOMC.mjs";
|
|
17
17
|
import {
|
|
18
18
|
detectHarness
|
|
19
|
-
} from "./token-goat-chunk-
|
|
19
|
+
} from "./token-goat-chunk-QYHO5CPH.mjs";
|
|
20
20
|
import {
|
|
21
21
|
registerReset
|
|
22
22
|
} from "./token-goat-chunk-YZAAZU2S.mjs";
|
|
23
|
+
import {
|
|
24
|
+
echoedValue
|
|
25
|
+
} from "./token-goat-chunk-GGGG7RWB.mjs";
|
|
23
26
|
import {
|
|
24
27
|
displaySafeText,
|
|
25
28
|
neutralizeOutsideFences,
|
|
@@ -29,6 +32,253 @@ import {
|
|
|
29
32
|
init_define_import_meta_env
|
|
30
33
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
31
34
|
|
|
35
|
+
// src/hooks_common.ts
|
|
36
|
+
init_define_import_meta_env();
|
|
37
|
+
function getToolName(event) {
|
|
38
|
+
return event.toolName;
|
|
39
|
+
}
|
|
40
|
+
function getToolInput(event) {
|
|
41
|
+
return event.toolInput;
|
|
42
|
+
}
|
|
43
|
+
function getFilePath(event) {
|
|
44
|
+
const value = event.toolInput["file_path"];
|
|
45
|
+
if (typeof value === "string" && value !== "") return resolveEventPath(event, value);
|
|
46
|
+
const notebookValue = event.toolInput["notebook_path"];
|
|
47
|
+
return typeof notebookValue === "string" && notebookValue !== "" ? resolveEventPath(event, notebookValue) : void 0;
|
|
48
|
+
}
|
|
49
|
+
function resolveEventPath(event, file) {
|
|
50
|
+
return resolveToolPath(file, getCwd(event));
|
|
51
|
+
}
|
|
52
|
+
function getFilePaths(event) {
|
|
53
|
+
const out = [];
|
|
54
|
+
const list = event.toolInput["file_paths"];
|
|
55
|
+
if (Array.isArray(list)) {
|
|
56
|
+
for (const entry of list) {
|
|
57
|
+
if (typeof entry !== "string" || entry === "") continue;
|
|
58
|
+
const resolved = resolveEventPath(event, entry);
|
|
59
|
+
if (!out.includes(resolved)) out.push(resolved);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const single = getFilePath(event);
|
|
63
|
+
if (single !== void 0 && !out.includes(single)) out.push(single);
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function getCwd(event) {
|
|
67
|
+
const value = event.raw && typeof event.raw === "object" ? event.raw["cwd"] : void 0;
|
|
68
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
69
|
+
}
|
|
70
|
+
function getTranscriptPath(event) {
|
|
71
|
+
const value = event.raw && typeof event.raw === "object" ? event.raw["transcript_path"] : void 0;
|
|
72
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
73
|
+
}
|
|
74
|
+
function extractToolResponseField(raw, keys) {
|
|
75
|
+
const resp = raw["tool_response"];
|
|
76
|
+
if (typeof resp === "string") return resp;
|
|
77
|
+
if (resp !== null && typeof resp === "object") {
|
|
78
|
+
const r = resp;
|
|
79
|
+
const path3 = resolveToolResponseFieldPath(r, keys);
|
|
80
|
+
if (path3 !== null) return readAtPath(r, path3);
|
|
81
|
+
}
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
84
|
+
var NESTED_TOOL_RESPONSE_PATHS = [["file", "content"]];
|
|
85
|
+
function readAtPath(resp, path3) {
|
|
86
|
+
let cur = resp;
|
|
87
|
+
for (const seg of path3) {
|
|
88
|
+
if (cur === null || typeof cur !== "object") return "";
|
|
89
|
+
cur = cur[seg];
|
|
90
|
+
}
|
|
91
|
+
return typeof cur === "string" ? cur : "";
|
|
92
|
+
}
|
|
93
|
+
function resolveToolResponseFieldPath(resp, keys) {
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
if (typeof resp[key] === "string" && resp[key] !== "") return [key];
|
|
96
|
+
}
|
|
97
|
+
for (const path3 of NESTED_TOOL_RESPONSE_PATHS) {
|
|
98
|
+
if (readAtPath(resp, path3) !== "") return path3;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
function replaceToolResponseField(resp, keys, newText) {
|
|
103
|
+
const path3 = resolveToolResponseFieldPath(resp, keys);
|
|
104
|
+
if (path3 === null) return null;
|
|
105
|
+
const root = { ...resp };
|
|
106
|
+
let cur = root;
|
|
107
|
+
for (let i = 0; i < path3.length - 1; i++) {
|
|
108
|
+
const seg = path3[i];
|
|
109
|
+
const child = cur[seg];
|
|
110
|
+
if (child === null || typeof child !== "object") return null;
|
|
111
|
+
const cloned = { ...child };
|
|
112
|
+
cur[seg] = cloned;
|
|
113
|
+
cur = cloned;
|
|
114
|
+
}
|
|
115
|
+
cur[path3[path3.length - 1]] = newText;
|
|
116
|
+
return root;
|
|
117
|
+
}
|
|
118
|
+
var OUTPUT_FIRST_TOOL_RESPONSE_KEYS = ["output", "content", "text", "body", "stdout", "stderr"];
|
|
119
|
+
var BODY_FIRST_TOOL_RESPONSE_KEYS = ["output", "body", "text", "content", "result"];
|
|
120
|
+
function isMcpErrorResponse(raw) {
|
|
121
|
+
const tr = raw["tool_response"];
|
|
122
|
+
if (!tr || typeof tr !== "object") return false;
|
|
123
|
+
return tr["isError"] === true;
|
|
124
|
+
}
|
|
125
|
+
var MCP_CONTENT_BLOCK_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "resource", "resource_link"]);
|
|
126
|
+
function blocksToText(blocks) {
|
|
127
|
+
if (!Array.isArray(blocks)) return null;
|
|
128
|
+
const parts = [];
|
|
129
|
+
let recognised = false;
|
|
130
|
+
for (const block of blocks) {
|
|
131
|
+
if (!block || typeof block !== "object") continue;
|
|
132
|
+
const rec = block;
|
|
133
|
+
const type = rec["type"];
|
|
134
|
+
if (typeof type === "string" && MCP_CONTENT_BLOCK_TYPES.has(type)) recognised = true;
|
|
135
|
+
if (typeof rec["text"] === "string") {
|
|
136
|
+
parts.push(rec["text"]);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const resource = rec["resource"];
|
|
140
|
+
if (resource !== null && typeof resource === "object") {
|
|
141
|
+
const nested = resource["text"];
|
|
142
|
+
if (typeof nested === "string") parts.push(nested);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (rec["type"] === "resource_link") {
|
|
146
|
+
const link = ["name", "uri", "description"].map((k) => rec[k]).filter((v) => typeof v === "string" && v !== "");
|
|
147
|
+
if (link.length > 0) parts.push(link.join(" "));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (parts.length > 0) return parts.join("\n");
|
|
151
|
+
return recognised ? "" : null;
|
|
152
|
+
}
|
|
153
|
+
function extractToolResultText(raw) {
|
|
154
|
+
const tr = raw["tool_response"];
|
|
155
|
+
if (typeof tr === "string") return tr;
|
|
156
|
+
if (!tr || typeof tr !== "object") return "";
|
|
157
|
+
const bare = blocksToText(tr);
|
|
158
|
+
if (bare !== null) return bare;
|
|
159
|
+
const resp = tr;
|
|
160
|
+
const content = resp["content"];
|
|
161
|
+
const joined = blocksToText(content);
|
|
162
|
+
if (joined !== null) return joined;
|
|
163
|
+
for (const key of ["output", "text", "body"]) {
|
|
164
|
+
if (typeof resp[key] === "string") return resp[key];
|
|
165
|
+
}
|
|
166
|
+
if (typeof content === "string") return content;
|
|
167
|
+
try {
|
|
168
|
+
return JSON.stringify(resp);
|
|
169
|
+
} catch {
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function asContentBlocks(value) {
|
|
174
|
+
if (!Array.isArray(value)) return null;
|
|
175
|
+
const blocks = value.filter((b) => b !== null && typeof b === "object");
|
|
176
|
+
const typed = blocks.some((b) => typeof b["type"] === "string" && MCP_CONTENT_BLOCK_TYPES.has(b["type"]));
|
|
177
|
+
return typed ? blocks : null;
|
|
178
|
+
}
|
|
179
|
+
function mcpContentBlocks(raw) {
|
|
180
|
+
const tr = raw["tool_response"];
|
|
181
|
+
if (tr === null || typeof tr !== "object") return null;
|
|
182
|
+
return asContentBlocks(tr) ?? asContentBlocks(tr["content"]);
|
|
183
|
+
}
|
|
184
|
+
function isTextualContentBlock(block) {
|
|
185
|
+
if (block === null || typeof block !== "object") return false;
|
|
186
|
+
const rec = block;
|
|
187
|
+
if (typeof rec["text"] === "string") return true;
|
|
188
|
+
if (rec["type"] === "resource_link") return true;
|
|
189
|
+
const resource = rec["resource"];
|
|
190
|
+
return resource !== null && typeof resource === "object" && typeof resource["text"] === "string";
|
|
191
|
+
}
|
|
192
|
+
function withPreservedBlocks(output, blocks) {
|
|
193
|
+
if (output.hookType !== "rewriteOutput" || blocks.length === 0) return output;
|
|
194
|
+
return { ...output, updatedBlocks: [{ type: "text", text: output.updatedOutput }, ...blocks] };
|
|
195
|
+
}
|
|
196
|
+
function dropsResultRewrite() {
|
|
197
|
+
return detectHarness() === "vscode";
|
|
198
|
+
}
|
|
199
|
+
function passOutput() {
|
|
200
|
+
return { hookType: "pass" };
|
|
201
|
+
}
|
|
202
|
+
function denyOutput(message) {
|
|
203
|
+
return { hookType: "deny", message: `[tg] ${neutralizeOutsideFences(message)}` };
|
|
204
|
+
}
|
|
205
|
+
function contextOutput(context, correlators) {
|
|
206
|
+
return correlators === void 0 ? { hookType: "context", context } : { hookType: "context", context, correlators };
|
|
207
|
+
}
|
|
208
|
+
function emitRewrite(updatedOutput, detail, savings, redaction = "count-here") {
|
|
209
|
+
if (dropsResultRewrite()) return passOutput();
|
|
210
|
+
if (redaction === "count-here") {
|
|
211
|
+
const count = countRedactionPlaceholders(updatedOutput);
|
|
212
|
+
if (count > 0) recordStat("secret_redacted", 0, count, void 0, detail);
|
|
213
|
+
}
|
|
214
|
+
if (savings !== void 0) {
|
|
215
|
+
const bytesSaved = savings.originalBytes - Buffer.byteLength(updatedOutput, "utf-8");
|
|
216
|
+
const credited = Math.max(0, bytesSaved);
|
|
217
|
+
recordStat(savings.kind, credited, savedTokensFromBytes(credited), void 0, savings.detail);
|
|
218
|
+
}
|
|
219
|
+
return { hookType: "rewriteOutput", updatedOutput };
|
|
220
|
+
}
|
|
221
|
+
function emitRewriteIfChanged(original, emitted, detail) {
|
|
222
|
+
if (emitted === original) return passOutput();
|
|
223
|
+
return emitRewrite(emitted, detail);
|
|
224
|
+
}
|
|
225
|
+
function emitRewriteWithContext(updatedOutput, context, detail, savings) {
|
|
226
|
+
const out = emitRewrite(updatedOutput, detail, { ...savings, originalBytes: savings.originalBytes - Buffer.byteLength(context, "utf-8") });
|
|
227
|
+
return out.hookType === "rewriteOutput" ? { ...out, context } : out;
|
|
228
|
+
}
|
|
229
|
+
function countNonEmptyLines(text) {
|
|
230
|
+
return text.split(/\r\n|\r|\n/).filter((line) => line.length > 0).length;
|
|
231
|
+
}
|
|
232
|
+
function estimateResultCount(text) {
|
|
233
|
+
const firstLine = text.split(/\r\n|\r|\n/).find((line) => line.trim().length > 0);
|
|
234
|
+
if (firstLine !== void 0) {
|
|
235
|
+
const trimmed = firstLine.trim();
|
|
236
|
+
if (/^No (?:files|matches) found\.?$/i.test(trimmed)) return 0;
|
|
237
|
+
const found = /^Found (\d+) (?:files?|matches?)\.?$/i.exec(trimmed);
|
|
238
|
+
if (found) return Number.parseInt(found[1], 10);
|
|
239
|
+
}
|
|
240
|
+
return countNonEmptyLines(text);
|
|
241
|
+
}
|
|
242
|
+
var RESULT_COUNT_KEYS = ["numFiles", "numLines", "numMatches"];
|
|
243
|
+
function structuredResultCount(raw) {
|
|
244
|
+
const response = raw["tool_response"];
|
|
245
|
+
if (response === null || typeof response !== "object") return null;
|
|
246
|
+
const counts = RESULT_COUNT_KEYS.map((k) => response[k]).filter((v) => typeof v === "number");
|
|
247
|
+
return counts.length > 0 ? Math.max(...counts) : null;
|
|
248
|
+
}
|
|
249
|
+
function makeDedupHintHandlers(opts) {
|
|
250
|
+
const post = (event) => {
|
|
251
|
+
try {
|
|
252
|
+
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
253
|
+
const signature = opts.buildSignature(getToolInput(event));
|
|
254
|
+
if (signature === null) return passOutput();
|
|
255
|
+
opts.recordQuery(signature, structuredResultCount(event.raw) ?? estimateResultCount(extractToolResponseField(event.raw, OUTPUT_FIRST_TOOL_RESPONSE_KEYS)));
|
|
256
|
+
return passOutput();
|
|
257
|
+
} catch {
|
|
258
|
+
return passOutput();
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
const pre = (event) => {
|
|
262
|
+
try {
|
|
263
|
+
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
264
|
+
const toolInput = getToolInput(event);
|
|
265
|
+
const signature = opts.buildSignature(toolInput);
|
|
266
|
+
if (signature === null) return passOutput();
|
|
267
|
+
const priorCount = opts.getMatchCount(signature);
|
|
268
|
+
if (priorCount === null) return passOutput();
|
|
269
|
+
if (priorCount < loadConfig().hints[opts.minMatchesConfigKey]) return passOutput();
|
|
270
|
+
recordStat(opts.statName, 0, 0);
|
|
271
|
+
const pattern = displaySafeText(typeof toolInput["pattern"] === "string" ? toolInput["pattern"] : "");
|
|
272
|
+
return contextOutput(
|
|
273
|
+
"Note: an identical " + opts.toolName + " for " + echoedValue(pattern) + " already ran this session and returned " + priorCount + (priorCount === 1 ? " match" : " matches") + ". If that result already answers this, you can skip re-running it."
|
|
274
|
+
);
|
|
275
|
+
} catch {
|
|
276
|
+
return passOutput();
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
return { post, pre };
|
|
280
|
+
}
|
|
281
|
+
|
|
32
282
|
// src/hooks_cli.ts
|
|
33
283
|
init_define_import_meta_env();
|
|
34
284
|
|
|
@@ -152,8 +402,7 @@ function readCopilotMcpTools(dir = copilotCliMcpToolsDir(), userRoot = copilotCl
|
|
|
152
402
|
definitionBytes,
|
|
153
403
|
estimatedTokens: estimateTokensFromLength(definitionBytes),
|
|
154
404
|
updatedAt,
|
|
155
|
-
// `tools` is an unchecked cast off a JSON array, so every element is
|
|
156
|
-
// treated as untrusted here rather than trusted to match CachedTool.
|
|
405
|
+
// `tools` is an unchecked cast off a JSON array, so every element is treated as untrusted here rather than trusted to match CachedTool.
|
|
157
406
|
toolNames: tools.map((t) => t?.name).filter((n) => typeof n === "string" && n !== "")
|
|
158
407
|
};
|
|
159
408
|
const existing = newest.get(serverName);
|
|
@@ -281,7 +530,8 @@ function normalizeToolNameWithMap(toolName, nameMap) {
|
|
|
281
530
|
}
|
|
282
531
|
var COPILOT_CLI_INPUT_KEY_MAP = {
|
|
283
532
|
Read: { path: "file_path" },
|
|
284
|
-
|
|
533
|
+
// CAPTURE: the real Copilot CLI `create` arguments {path, file_text} in a session log (events.jsonl, tool.execution_start, toolName "create"); the `edit` entry below is FORMAT-DERIVED from the tool description in a Copilot CLI 1.0.88 session log.
|
|
534
|
+
Write: { path: "file_path", file_text: "content" },
|
|
285
535
|
Edit: { path: "file_path", old_str: "old_string", new_str: "new_string" },
|
|
286
536
|
BashOutput: { shellId: "bash_id" }
|
|
287
537
|
};
|
|
@@ -660,251 +910,8 @@ function normalizePayload(payload, harness = "claude") {
|
|
|
660
910
|
return result;
|
|
661
911
|
}
|
|
662
912
|
|
|
663
|
-
// src/hooks_common.ts
|
|
664
|
-
init_define_import_meta_env();
|
|
665
|
-
function getToolName(event) {
|
|
666
|
-
return event.toolName;
|
|
667
|
-
}
|
|
668
|
-
function getToolInput(event) {
|
|
669
|
-
return event.toolInput;
|
|
670
|
-
}
|
|
671
|
-
function getFilePath(event) {
|
|
672
|
-
const value = event.toolInput["file_path"];
|
|
673
|
-
if (typeof value === "string" && value !== "") return resolveEventPath(event, value);
|
|
674
|
-
const notebookValue = event.toolInput["notebook_path"];
|
|
675
|
-
return typeof notebookValue === "string" && notebookValue !== "" ? resolveEventPath(event, notebookValue) : void 0;
|
|
676
|
-
}
|
|
677
|
-
function resolveEventPath(event, file) {
|
|
678
|
-
return resolveToolPath(file, getCwd(event));
|
|
679
|
-
}
|
|
680
|
-
function getFilePaths(event) {
|
|
681
|
-
const out = [];
|
|
682
|
-
const list = event.toolInput["file_paths"];
|
|
683
|
-
if (Array.isArray(list)) {
|
|
684
|
-
for (const entry of list) {
|
|
685
|
-
if (typeof entry !== "string" || entry === "") continue;
|
|
686
|
-
const resolved = resolveEventPath(event, entry);
|
|
687
|
-
if (!out.includes(resolved)) out.push(resolved);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
const single = getFilePath(event);
|
|
691
|
-
if (single !== void 0 && !out.includes(single)) out.push(single);
|
|
692
|
-
return out;
|
|
693
|
-
}
|
|
694
|
-
function getCwd(event) {
|
|
695
|
-
const value = event.raw && typeof event.raw === "object" ? event.raw["cwd"] : void 0;
|
|
696
|
-
return typeof value === "string" && value !== "" ? value : void 0;
|
|
697
|
-
}
|
|
698
|
-
function getTranscriptPath(event) {
|
|
699
|
-
const value = event.raw && typeof event.raw === "object" ? event.raw["transcript_path"] : void 0;
|
|
700
|
-
return typeof value === "string" && value !== "" ? value : void 0;
|
|
701
|
-
}
|
|
702
|
-
function extractToolResponseField(raw, keys) {
|
|
703
|
-
const resp = raw["tool_response"];
|
|
704
|
-
if (typeof resp === "string") return resp;
|
|
705
|
-
if (resp !== null && typeof resp === "object") {
|
|
706
|
-
const r = resp;
|
|
707
|
-
const path3 = resolveToolResponseFieldPath(r, keys);
|
|
708
|
-
if (path3 !== null) return readAtPath(r, path3);
|
|
709
|
-
}
|
|
710
|
-
return "";
|
|
711
|
-
}
|
|
712
|
-
var NESTED_TOOL_RESPONSE_PATHS = [["file", "content"]];
|
|
713
|
-
function readAtPath(resp, path3) {
|
|
714
|
-
let cur = resp;
|
|
715
|
-
for (const seg of path3) {
|
|
716
|
-
if (cur === null || typeof cur !== "object") return "";
|
|
717
|
-
cur = cur[seg];
|
|
718
|
-
}
|
|
719
|
-
return typeof cur === "string" ? cur : "";
|
|
720
|
-
}
|
|
721
|
-
function resolveToolResponseFieldPath(resp, keys) {
|
|
722
|
-
for (const key of keys) {
|
|
723
|
-
if (typeof resp[key] === "string" && resp[key] !== "") return [key];
|
|
724
|
-
}
|
|
725
|
-
for (const path3 of NESTED_TOOL_RESPONSE_PATHS) {
|
|
726
|
-
if (readAtPath(resp, path3) !== "") return path3;
|
|
727
|
-
}
|
|
728
|
-
return null;
|
|
729
|
-
}
|
|
730
|
-
function replaceToolResponseField(resp, keys, newText) {
|
|
731
|
-
const path3 = resolveToolResponseFieldPath(resp, keys);
|
|
732
|
-
if (path3 === null) return null;
|
|
733
|
-
const root = { ...resp };
|
|
734
|
-
let cur = root;
|
|
735
|
-
for (let i = 0; i < path3.length - 1; i++) {
|
|
736
|
-
const seg = path3[i];
|
|
737
|
-
const child = cur[seg];
|
|
738
|
-
if (child === null || typeof child !== "object") return null;
|
|
739
|
-
const cloned = { ...child };
|
|
740
|
-
cur[seg] = cloned;
|
|
741
|
-
cur = cloned;
|
|
742
|
-
}
|
|
743
|
-
cur[path3[path3.length - 1]] = newText;
|
|
744
|
-
return root;
|
|
745
|
-
}
|
|
746
|
-
var OUTPUT_FIRST_TOOL_RESPONSE_KEYS = ["output", "content", "text", "body", "stdout", "stderr"];
|
|
747
|
-
var BODY_FIRST_TOOL_RESPONSE_KEYS = ["output", "body", "text", "content", "result"];
|
|
748
|
-
function isMcpErrorResponse(raw) {
|
|
749
|
-
const tr = raw["tool_response"];
|
|
750
|
-
if (!tr || typeof tr !== "object") return false;
|
|
751
|
-
return tr["isError"] === true;
|
|
752
|
-
}
|
|
753
|
-
var MCP_CONTENT_BLOCK_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "resource", "resource_link"]);
|
|
754
|
-
function blocksToText(blocks) {
|
|
755
|
-
if (!Array.isArray(blocks)) return null;
|
|
756
|
-
const parts = [];
|
|
757
|
-
let recognised = false;
|
|
758
|
-
for (const block of blocks) {
|
|
759
|
-
if (!block || typeof block !== "object") continue;
|
|
760
|
-
const rec = block;
|
|
761
|
-
const type = rec["type"];
|
|
762
|
-
if (typeof type === "string" && MCP_CONTENT_BLOCK_TYPES.has(type)) recognised = true;
|
|
763
|
-
if (typeof rec["text"] === "string") {
|
|
764
|
-
parts.push(rec["text"]);
|
|
765
|
-
continue;
|
|
766
|
-
}
|
|
767
|
-
const resource = rec["resource"];
|
|
768
|
-
if (resource !== null && typeof resource === "object") {
|
|
769
|
-
const nested = resource["text"];
|
|
770
|
-
if (typeof nested === "string") parts.push(nested);
|
|
771
|
-
continue;
|
|
772
|
-
}
|
|
773
|
-
if (rec["type"] === "resource_link") {
|
|
774
|
-
const link = ["name", "uri", "description"].map((k) => rec[k]).filter((v) => typeof v === "string" && v !== "");
|
|
775
|
-
if (link.length > 0) parts.push(link.join(" "));
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
if (parts.length > 0) return parts.join("\n");
|
|
779
|
-
return recognised ? "" : null;
|
|
780
|
-
}
|
|
781
|
-
function extractToolResultText(raw) {
|
|
782
|
-
const tr = raw["tool_response"];
|
|
783
|
-
if (typeof tr === "string") return tr;
|
|
784
|
-
if (!tr || typeof tr !== "object") return "";
|
|
785
|
-
const bare = blocksToText(tr);
|
|
786
|
-
if (bare !== null) return bare;
|
|
787
|
-
const resp = tr;
|
|
788
|
-
const content = resp["content"];
|
|
789
|
-
const joined = blocksToText(content);
|
|
790
|
-
if (joined !== null) return joined;
|
|
791
|
-
for (const key of ["output", "text", "body"]) {
|
|
792
|
-
if (typeof resp[key] === "string") return resp[key];
|
|
793
|
-
}
|
|
794
|
-
if (typeof content === "string") return content;
|
|
795
|
-
try {
|
|
796
|
-
return JSON.stringify(resp);
|
|
797
|
-
} catch {
|
|
798
|
-
return "";
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
function asContentBlocks(value) {
|
|
802
|
-
if (!Array.isArray(value)) return null;
|
|
803
|
-
const blocks = value.filter((b) => b !== null && typeof b === "object");
|
|
804
|
-
const typed = blocks.some((b) => typeof b["type"] === "string" && MCP_CONTENT_BLOCK_TYPES.has(b["type"]));
|
|
805
|
-
return typed ? blocks : null;
|
|
806
|
-
}
|
|
807
|
-
function mcpContentBlocks(raw) {
|
|
808
|
-
const tr = raw["tool_response"];
|
|
809
|
-
if (tr === null || typeof tr !== "object") return null;
|
|
810
|
-
return asContentBlocks(tr) ?? asContentBlocks(tr["content"]);
|
|
811
|
-
}
|
|
812
|
-
function isTextualContentBlock(block) {
|
|
813
|
-
if (block === null || typeof block !== "object") return false;
|
|
814
|
-
const rec = block;
|
|
815
|
-
if (typeof rec["text"] === "string") return true;
|
|
816
|
-
if (rec["type"] === "resource_link") return true;
|
|
817
|
-
const resource = rec["resource"];
|
|
818
|
-
return resource !== null && typeof resource === "object" && typeof resource["text"] === "string";
|
|
819
|
-
}
|
|
820
|
-
function withPreservedBlocks(output, blocks) {
|
|
821
|
-
if (output.hookType !== "rewriteOutput" || blocks.length === 0) return output;
|
|
822
|
-
return { ...output, updatedBlocks: [{ type: "text", text: output.updatedOutput }, ...blocks] };
|
|
823
|
-
}
|
|
824
|
-
function passOutput() {
|
|
825
|
-
return { hookType: "pass" };
|
|
826
|
-
}
|
|
827
|
-
function denyOutput(message) {
|
|
828
|
-
return { hookType: "deny", message: `[tg] ${neutralizeOutsideFences(message)}` };
|
|
829
|
-
}
|
|
830
|
-
function contextOutput(context, correlators) {
|
|
831
|
-
return correlators === void 0 ? { hookType: "context", context } : { hookType: "context", context, correlators };
|
|
832
|
-
}
|
|
833
|
-
function emitRewrite(updatedOutput, detail, savings, redaction = "count-here") {
|
|
834
|
-
if (detectHarness() === "vscode") return passOutput();
|
|
835
|
-
if (redaction === "count-here") {
|
|
836
|
-
const count = countRedactionPlaceholders(updatedOutput);
|
|
837
|
-
if (count > 0) recordStat("secret_redacted", 0, count, void 0, detail);
|
|
838
|
-
}
|
|
839
|
-
if (savings !== void 0) {
|
|
840
|
-
const bytesSaved = savings.originalBytes - Buffer.byteLength(updatedOutput, "utf-8");
|
|
841
|
-
const credited = Math.max(0, bytesSaved);
|
|
842
|
-
recordStat(savings.kind, credited, savedTokensFromBytes(credited), void 0, savings.detail);
|
|
843
|
-
}
|
|
844
|
-
return { hookType: "rewriteOutput", updatedOutput };
|
|
845
|
-
}
|
|
846
|
-
function emitRewriteIfChanged(original, emitted, detail) {
|
|
847
|
-
if (emitted === original) return passOutput();
|
|
848
|
-
return emitRewrite(emitted, detail);
|
|
849
|
-
}
|
|
850
|
-
function emitRewriteWithContext(updatedOutput, context, detail, savings) {
|
|
851
|
-
const out = emitRewrite(updatedOutput, detail, { ...savings, originalBytes: savings.originalBytes - Buffer.byteLength(context, "utf-8") });
|
|
852
|
-
return out.hookType === "rewriteOutput" ? { ...out, context } : out;
|
|
853
|
-
}
|
|
854
|
-
function countNonEmptyLines(text) {
|
|
855
|
-
return text.split(/\r\n|\r|\n/).filter((line) => line.length > 0).length;
|
|
856
|
-
}
|
|
857
|
-
function estimateResultCount(text) {
|
|
858
|
-
const firstLine = text.split(/\r\n|\r|\n/).find((line) => line.trim().length > 0);
|
|
859
|
-
if (firstLine !== void 0) {
|
|
860
|
-
const trimmed = firstLine.trim();
|
|
861
|
-
if (/^No (?:files|matches) found\.?$/i.test(trimmed)) return 0;
|
|
862
|
-
const found = /^Found (\d+) (?:files?|matches?)\.?$/i.exec(trimmed);
|
|
863
|
-
if (found) return Number.parseInt(found[1], 10);
|
|
864
|
-
}
|
|
865
|
-
return countNonEmptyLines(text);
|
|
866
|
-
}
|
|
867
|
-
var RESULT_COUNT_KEYS = ["numFiles", "numLines", "numMatches"];
|
|
868
|
-
function structuredResultCount(raw) {
|
|
869
|
-
const response = raw["tool_response"];
|
|
870
|
-
if (response === null || typeof response !== "object") return null;
|
|
871
|
-
const counts = RESULT_COUNT_KEYS.map((k) => response[k]).filter((v) => typeof v === "number");
|
|
872
|
-
return counts.length > 0 ? Math.max(...counts) : null;
|
|
873
|
-
}
|
|
874
|
-
function makeDedupHintHandlers(opts) {
|
|
875
|
-
const post = (event) => {
|
|
876
|
-
try {
|
|
877
|
-
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
878
|
-
const signature = opts.buildSignature(getToolInput(event));
|
|
879
|
-
if (signature === null) return passOutput();
|
|
880
|
-
opts.recordQuery(signature, structuredResultCount(event.raw) ?? estimateResultCount(extractToolResponseField(event.raw, OUTPUT_FIRST_TOOL_RESPONSE_KEYS)));
|
|
881
|
-
return passOutput();
|
|
882
|
-
} catch {
|
|
883
|
-
return passOutput();
|
|
884
|
-
}
|
|
885
|
-
};
|
|
886
|
-
const pre = (event) => {
|
|
887
|
-
try {
|
|
888
|
-
if (getToolName(event) !== opts.toolName) return passOutput();
|
|
889
|
-
const toolInput = getToolInput(event);
|
|
890
|
-
const signature = opts.buildSignature(toolInput);
|
|
891
|
-
if (signature === null) return passOutput();
|
|
892
|
-
const priorCount = opts.getMatchCount(signature);
|
|
893
|
-
if (priorCount === null) return passOutput();
|
|
894
|
-
if (priorCount < loadConfig().hints[opts.minMatchesConfigKey]) return passOutput();
|
|
895
|
-
recordStat(opts.statName, 0, 0);
|
|
896
|
-
const pattern = displaySafeText(typeof toolInput["pattern"] === "string" ? toolInput["pattern"] : "");
|
|
897
|
-
return contextOutput(
|
|
898
|
-
"Note: an identical " + opts.toolName + ' for "' + pattern + '" already ran this session and returned ' + priorCount + (priorCount === 1 ? " match" : " matches") + ". If that result already answers this, you can skip re-running it."
|
|
899
|
-
);
|
|
900
|
-
} catch {
|
|
901
|
-
return passOutput();
|
|
902
|
-
}
|
|
903
|
-
};
|
|
904
|
-
return { post, pre };
|
|
905
|
-
}
|
|
906
|
-
|
|
907
913
|
export {
|
|
914
|
+
foldToolName,
|
|
908
915
|
getToolName,
|
|
909
916
|
getToolInput,
|
|
910
917
|
getFilePath,
|
|
@@ -922,6 +929,7 @@ export {
|
|
|
922
929
|
mcpContentBlocks,
|
|
923
930
|
isTextualContentBlock,
|
|
924
931
|
withPreservedBlocks,
|
|
932
|
+
dropsResultRewrite,
|
|
925
933
|
passOutput,
|
|
926
934
|
denyOutput,
|
|
927
935
|
contextOutput,
|
|
@@ -935,7 +943,6 @@ export {
|
|
|
935
943
|
copilotCliMcpToolsDir,
|
|
936
944
|
readCopilotMcpTools,
|
|
937
945
|
COPILOT_CLI_TOOL_NAME_MAP,
|
|
938
|
-
foldToolName,
|
|
939
946
|
GEMINI_TOOL_NAME_MAP,
|
|
940
947
|
VSCODE_TOOL_NAME_KEY,
|
|
941
948
|
vscodeNativeToolInput,
|