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,603 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
buildProjectMap,
|
|
5
|
+
formatProjectMap
|
|
6
|
+
} from "./token-goat-chunk-ZNMNUPAZ.mjs";
|
|
7
|
+
import {
|
|
8
|
+
mcpHash,
|
|
9
|
+
mcpOutputId,
|
|
10
|
+
storeMcpOutput
|
|
11
|
+
} from "./token-goat-chunk-Z7N5OMMP.mjs";
|
|
12
|
+
import {
|
|
13
|
+
isRewriteWorthwhile,
|
|
14
|
+
resolveMinNetSavingsBytes
|
|
15
|
+
} from "./token-goat-chunk-INNPTRUX.mjs";
|
|
16
|
+
import {
|
|
17
|
+
agentTypeOf,
|
|
18
|
+
permissionNeutralRewrite
|
|
19
|
+
} from "./token-goat-chunk-QH7YVYOY.mjs";
|
|
20
|
+
import "./token-goat-chunk-NOSS5VWY.mjs";
|
|
21
|
+
import "./token-goat-chunk-NMD42SFQ.mjs";
|
|
22
|
+
import "./token-goat-chunk-SAMFDIS2.mjs";
|
|
23
|
+
import "./token-goat-chunk-4SMRO4TO.mjs";
|
|
24
|
+
import "./token-goat-chunk-WBA5SKT4.mjs";
|
|
25
|
+
import "./token-goat-chunk-MNWKPRAL.mjs";
|
|
26
|
+
import "./token-goat-chunk-CIMQ2BB3.mjs";
|
|
27
|
+
import "./token-goat-chunk-WDH44VAU.mjs";
|
|
28
|
+
import {
|
|
29
|
+
claudeConfigDir
|
|
30
|
+
} from "./token-goat-chunk-BPGCUMR7.mjs";
|
|
31
|
+
import {
|
|
32
|
+
getBashOutput
|
|
33
|
+
} from "./token-goat-chunk-KQBLRPBN.mjs";
|
|
34
|
+
import "./token-goat-chunk-4ZBFWLXF.mjs";
|
|
35
|
+
import "./token-goat-chunk-C75NA7PL.mjs";
|
|
36
|
+
import "./token-goat-chunk-P6VGNTQT.mjs";
|
|
37
|
+
import {
|
|
38
|
+
contextOutput,
|
|
39
|
+
denyOutput,
|
|
40
|
+
dropsResultRewrite,
|
|
41
|
+
emitRewrite,
|
|
42
|
+
extractToolResultText,
|
|
43
|
+
getCwd,
|
|
44
|
+
passOutput
|
|
45
|
+
} from "./token-goat-chunk-76FGDLRO.mjs";
|
|
46
|
+
import {
|
|
47
|
+
getOutstandingAgentSpawns,
|
|
48
|
+
getSessionBashOutputs,
|
|
49
|
+
markHintShown,
|
|
50
|
+
recordOutstandingAgentSpawn,
|
|
51
|
+
removeOutstandingAgentSpawn,
|
|
52
|
+
wasHintShown
|
|
53
|
+
} from "./token-goat-chunk-GL3ETKSC.mjs";
|
|
54
|
+
import "./token-goat-chunk-OXFMP75N.mjs";
|
|
55
|
+
import "./token-goat-chunk-NISNMD7T.mjs";
|
|
56
|
+
import "./token-goat-chunk-EVMZJ27Z.mjs";
|
|
57
|
+
import "./token-goat-chunk-IK2DRMFX.mjs";
|
|
58
|
+
import "./token-goat-chunk-5Y6ZYL6U.mjs";
|
|
59
|
+
import {
|
|
60
|
+
recordStat,
|
|
61
|
+
savedTokensFromBytes
|
|
62
|
+
} from "./token-goat-chunk-U4WHMG6Y.mjs";
|
|
63
|
+
import "./token-goat-chunk-GVB2MUST.mjs";
|
|
64
|
+
import "./token-goat-chunk-XB5KKOCG.mjs";
|
|
65
|
+
import "./token-goat-chunk-OUKDTVNU.mjs";
|
|
66
|
+
import "./token-goat-chunk-3BTK54F3.mjs";
|
|
67
|
+
import "./token-goat-chunk-4GILLLWY.mjs";
|
|
68
|
+
import {
|
|
69
|
+
estimateTokens,
|
|
70
|
+
sliceToEstimatedTokens
|
|
71
|
+
} from "./token-goat-chunk-BFCWY73P.mjs";
|
|
72
|
+
import "./token-goat-chunk-KGEFFSHD.mjs";
|
|
73
|
+
import "./token-goat-chunk-XX6O25RN.mjs";
|
|
74
|
+
import "./token-goat-chunk-HAVAOB3S.mjs";
|
|
75
|
+
import "./token-goat-chunk-F6PAUIEK.mjs";
|
|
76
|
+
import "./token-goat-chunk-65N4RHP4.mjs";
|
|
77
|
+
import "./token-goat-chunk-X2SUP3EI.mjs";
|
|
78
|
+
import {
|
|
79
|
+
redactSecrets
|
|
80
|
+
} from "./token-goat-chunk-T5P5ACNQ.mjs";
|
|
81
|
+
import {
|
|
82
|
+
loadConfig
|
|
83
|
+
} from "./token-goat-chunk-7EZTZOMC.mjs";
|
|
84
|
+
import {
|
|
85
|
+
getHarnessName
|
|
86
|
+
} from "./token-goat-chunk-QYHO5CPH.mjs";
|
|
87
|
+
import "./token-goat-chunk-4GBVPH3D.mjs";
|
|
88
|
+
import "./token-goat-chunk-YZAAZU2S.mjs";
|
|
89
|
+
import "./token-goat-chunk-IVE6U7KV.mjs";
|
|
90
|
+
import "./token-goat-chunk-Y4AFKTHK.mjs";
|
|
91
|
+
import {
|
|
92
|
+
toKB
|
|
93
|
+
} from "./token-goat-chunk-HU4TORC5.mjs";
|
|
94
|
+
import {
|
|
95
|
+
echoedValue
|
|
96
|
+
} from "./token-goat-chunk-GGGG7RWB.mjs";
|
|
97
|
+
import {
|
|
98
|
+
isInsideRoot
|
|
99
|
+
} from "./token-goat-chunk-AM5V6GSX.mjs";
|
|
100
|
+
import {
|
|
101
|
+
neutralizeSpokenMarkers
|
|
102
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
103
|
+
import "./token-goat-chunk-CO3UYX6G.mjs";
|
|
104
|
+
import {
|
|
105
|
+
init_define_import_meta_env
|
|
106
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
107
|
+
|
|
108
|
+
// src/hooks_agent_spawn.ts
|
|
109
|
+
init_define_import_meta_env();
|
|
110
|
+
import { createHash } from "node:crypto";
|
|
111
|
+
import * as fs from "node:fs";
|
|
112
|
+
import * as path from "node:path";
|
|
113
|
+
var loadAgentReceipt = () => import("./token-goat-chunk-CETM74KC.mjs");
|
|
114
|
+
var BRIEFING_TARGET_TOKENS = 550;
|
|
115
|
+
var CACHED_IDS_LISTED = 3;
|
|
116
|
+
var CACHED_COMMAND_PREVIEW_CHARS = 60;
|
|
117
|
+
function describeCachedOutput(entry) {
|
|
118
|
+
const ageMin = Math.max(0, Math.round((Date.now() - entry.storedAt) / 6e4));
|
|
119
|
+
const age = ageMin < 60 ? `${ageMin}m` : ageMin < 60 * 48 ? `${Math.round(ageMin / 60)}h` : `${Math.round(ageMin / 1440)}d`;
|
|
120
|
+
const flat = neutralizeSpokenMarkers(entry.command.replace(/\s+/g, " ").trim());
|
|
121
|
+
const preview = flat.length > CACHED_COMMAND_PREVIEW_CHARS ? flat.slice(0, CACHED_COMMAND_PREVIEW_CHARS) + "..." : flat;
|
|
122
|
+
return ` (~${toKB(entry.output.length)}KB, ${age} ago, ${"`"}${preview.replace(/`/g, "'")}${"`"})`;
|
|
123
|
+
}
|
|
124
|
+
function buildSubagentBriefing(projectRoot) {
|
|
125
|
+
try {
|
|
126
|
+
const head = [];
|
|
127
|
+
head.push("");
|
|
128
|
+
head.push("## Session briefing (for context)");
|
|
129
|
+
try {
|
|
130
|
+
if (projectRoot === null) throw new Error("no project root");
|
|
131
|
+
const map = buildProjectMap(projectRoot, { compact: true });
|
|
132
|
+
const mapText = formatProjectMap(map, map.compact);
|
|
133
|
+
head.push(mapText);
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
let cacheIdsBlock = "";
|
|
137
|
+
try {
|
|
138
|
+
const outputs = getSessionBashOutputs();
|
|
139
|
+
if (outputs.length > 0) {
|
|
140
|
+
const live = [];
|
|
141
|
+
for (const [, id] of [...outputs].reverse()) {
|
|
142
|
+
const entry = getBashOutput(id);
|
|
143
|
+
if (entry === null) continue;
|
|
144
|
+
live.push("`token-goat bash-output " + id + "`" + describeCachedOutput(entry));
|
|
145
|
+
if (live.length === CACHED_IDS_LISTED) break;
|
|
146
|
+
}
|
|
147
|
+
if (live.length > 0) cacheIdsBlock = "\n\nCached outputs this session: " + live.join(", ");
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
const tail = [];
|
|
152
|
+
tail.push("");
|
|
153
|
+
tail.push('Before your first read of any file, check for a token-goat command that returns just what you need and run it instead of a full-file read or wide grep: `token-goat symbol <name>`, `token-goat read "file::symbol"`, `token-goat section "file::<heading>"`, `token-goat json-query file \'a.b.c\'`. Skipping that check is a violation, not an oversight; the only exemptions are a file under ~200 lines you need whole, a never-indexed file, or an image.');
|
|
154
|
+
tail.push("");
|
|
155
|
+
tail.push('Report contract: cite evidence as `file::symbol` or a token-goat recall id (`token-goat mcp-output <id> --full`) rather than pasting bodies; paste a fenced block only when the exact bytes are load-bearing; state every unverified claim explicitly (e.g. "not verified: ...") rather than omitting it.');
|
|
156
|
+
const withCacheIds = head.join("\n") + cacheIdsBlock + "\n" + tail.join("\n");
|
|
157
|
+
if (estimateTokens(withCacheIds) <= BRIEFING_TARGET_TOKENS) {
|
|
158
|
+
return withCacheIds;
|
|
159
|
+
}
|
|
160
|
+
const withoutCacheIds = head.join("\n") + "\n" + tail.join("\n");
|
|
161
|
+
const tokens = estimateTokens(withoutCacheIds);
|
|
162
|
+
if (tokens <= BRIEFING_TARGET_TOKENS) {
|
|
163
|
+
return withoutCacheIds;
|
|
164
|
+
}
|
|
165
|
+
return sliceToEstimatedTokens(withoutCacheIds, BRIEFING_TARGET_TOKENS);
|
|
166
|
+
} catch {
|
|
167
|
+
return "";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
var DUPLICATE_PROMPT_JACCARD_THRESHOLD = 0.75;
|
|
171
|
+
function promptWordSet(text) {
|
|
172
|
+
const words = text.toLowerCase().replace(/[^\p{L}\p{N}\s]+/gu, " ").split(/\s+/).filter((w) => w.length > 0);
|
|
173
|
+
return new Set(words);
|
|
174
|
+
}
|
|
175
|
+
function jaccardSimilarity(a, b) {
|
|
176
|
+
if (a.size === 0 || b.size === 0) return 0;
|
|
177
|
+
let intersection = 0;
|
|
178
|
+
for (const word of a) {
|
|
179
|
+
if (b.has(word)) intersection++;
|
|
180
|
+
}
|
|
181
|
+
const union = a.size + b.size - intersection;
|
|
182
|
+
return union === 0 ? 0 : intersection / union;
|
|
183
|
+
}
|
|
184
|
+
function findDuplicateOutstandingPrompt(prompt) {
|
|
185
|
+
const words = promptWordSet(prompt);
|
|
186
|
+
for (const entry of getOutstandingAgentSpawns()) {
|
|
187
|
+
if (jaccardSimilarity(words, promptWordSet(entry.prompt)) >= DUPLICATE_PROMPT_JACCARD_THRESHOLD) {
|
|
188
|
+
return entry.prompt;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function truncateForWarning(text, max) {
|
|
194
|
+
return text.length > max ? text.slice(0, max) + "..." : text;
|
|
195
|
+
}
|
|
196
|
+
function briefingRoot(event) {
|
|
197
|
+
if (getHarnessName() === "vscode") return getCwd(event) ?? null;
|
|
198
|
+
return process.cwd();
|
|
199
|
+
}
|
|
200
|
+
function subagentStartWired() {
|
|
201
|
+
const harness = getHarnessName();
|
|
202
|
+
const dirVar = harness === "copilot_cli" ? "TOKEN_GOAT_COPILOT_HOOKS_DIR" : harness === "vscode" ? "TOKEN_GOAT_VSCODE_HOOKS_DIR" : void 0;
|
|
203
|
+
const dir = dirVar === void 0 ? void 0 : process.env[dirVar];
|
|
204
|
+
if (dir === void 0 || dir === "") return false;
|
|
205
|
+
try {
|
|
206
|
+
const config = JSON.parse(fs.readFileSync(path.join(dir, "token-goat.json"), "utf8"));
|
|
207
|
+
const entries = config.hooks?.[harness === "vscode" ? "SubagentStart" : "subagentStart"];
|
|
208
|
+
return Array.isArray(entries) && entries.length > 0;
|
|
209
|
+
} catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function subagentStartHandler(event) {
|
|
214
|
+
try {
|
|
215
|
+
const root = getCwd(event) ?? (getHarnessName() === "vscode" ? null : process.cwd());
|
|
216
|
+
const briefing = buildSubagentBriefing(root).trim();
|
|
217
|
+
return briefing ? contextOutput(briefing) : passOutput();
|
|
218
|
+
} catch {
|
|
219
|
+
return passOutput();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
var SPAWN_TOOL_BRIEF_FIELD = { Agent: "prompt", task: "prompt", Task: "prompt", spawn_agent: "message" };
|
|
223
|
+
function isAgentTool(toolName) {
|
|
224
|
+
return toolName !== void 0 && Object.hasOwn(SPAWN_TOOL_BRIEF_FIELD, toolName);
|
|
225
|
+
}
|
|
226
|
+
function readSpawnBrief(toolName, toolInput) {
|
|
227
|
+
const field = SPAWN_TOOL_BRIEF_FIELD[toolName ?? ""];
|
|
228
|
+
if (field === void 0) return null;
|
|
229
|
+
const written = toolInput[field];
|
|
230
|
+
if (typeof written === "string" && written.trim()) return { text: written, withSuffix: (suffix) => ({ ...toolInput, [field]: written + suffix }) };
|
|
231
|
+
const items = toolInput["items"];
|
|
232
|
+
if (toolName !== "spawn_agent" || !Array.isArray(items)) return null;
|
|
233
|
+
const joined = items.flatMap((item) => item?.type === "text" && typeof item.text === "string" ? [item.text] : []).join(" ");
|
|
234
|
+
if (!joined.trim()) return null;
|
|
235
|
+
return { text: joined, withSuffix: (suffix) => ({ ...toolInput, items: [...items, { type: "text", text: suffix }] }) };
|
|
236
|
+
}
|
|
237
|
+
function preAgentHandler(event) {
|
|
238
|
+
if (!isAgentTool(event.toolName)) return passOutput();
|
|
239
|
+
const toolInput = event.toolInput;
|
|
240
|
+
const brief = readSpawnBrief(event.toolName, toolInput);
|
|
241
|
+
if (brief === null) return passOutput();
|
|
242
|
+
const prompt = brief.text;
|
|
243
|
+
try {
|
|
244
|
+
const scopedDeny = buildScopedSpawnDeny(toolInput);
|
|
245
|
+
if (scopedDeny) return scopedDeny;
|
|
246
|
+
const duplicateOf = findDuplicateOutstandingPrompt(prompt);
|
|
247
|
+
recordOutstandingAgentSpawn(prompt);
|
|
248
|
+
const briefing = subagentStartWired() ? "" : buildSubagentBriefing(briefingRoot(event));
|
|
249
|
+
const advisory = duplicateOf ? `
|
|
250
|
+
|
|
251
|
+
[token-goat] A similar subagent spawn already appears to be outstanding this session (prompt starts: ${echoedValue(neutralizeSpokenMarkers(truncateForWarning(duplicateOf, 80)))}). This is advisory only -- proceeding is fine if intentional.` : "";
|
|
252
|
+
if (!briefing && !advisory) return passOutput();
|
|
253
|
+
const updatedPrompt = prompt + briefing + advisory;
|
|
254
|
+
const updatedInput = brief.withSuffix(briefing + advisory);
|
|
255
|
+
return permissionNeutralRewrite(updatedInput, { kind: "agent", harness: getHarnessName(), mode: event.raw["permission_mode"], cwd: getCwd(event) ?? process.cwd(), original: prompt, rewritten: updatedPrompt, agentType: agentTypeOf(event.raw) }) ?? passOutput();
|
|
256
|
+
} catch {
|
|
257
|
+
return passOutput();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
var FENCE_LINE_RE = /^ {0,3}(`{3,}|~{3,})([^\n]*)$/;
|
|
261
|
+
function findFencedBlockLines(lines) {
|
|
262
|
+
const blocks = [];
|
|
263
|
+
let fenceStart = -1;
|
|
264
|
+
let openMarker = "";
|
|
265
|
+
for (let i = 0; i < lines.length; i++) {
|
|
266
|
+
const line = lines[i];
|
|
267
|
+
const match = FENCE_LINE_RE.exec(line);
|
|
268
|
+
if (fenceStart === -1) {
|
|
269
|
+
if (match !== null) {
|
|
270
|
+
fenceStart = i;
|
|
271
|
+
openMarker = match[1];
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const isCloser = match !== null && match[1][0] === openMarker[0] && match[1].length >= openMarker.length && match[2].trim() === "";
|
|
276
|
+
if (!isCloser) continue;
|
|
277
|
+
blocks.push({ fenceStart, closerIndex: i });
|
|
278
|
+
fenceStart = -1;
|
|
279
|
+
}
|
|
280
|
+
return blocks;
|
|
281
|
+
}
|
|
282
|
+
function collapseFencedBlocks(text, recallHint, minLines, keepLines) {
|
|
283
|
+
const lines = text.split("\n");
|
|
284
|
+
const blocks = findFencedBlockLines(lines);
|
|
285
|
+
const out = [];
|
|
286
|
+
let cursor = 0;
|
|
287
|
+
for (const { fenceStart, closerIndex } of blocks) {
|
|
288
|
+
out.push(...lines.slice(cursor, fenceStart));
|
|
289
|
+
const bodyLines = closerIndex - fenceStart - 1;
|
|
290
|
+
if (bodyLines > minLines) {
|
|
291
|
+
out.push(...lines.slice(fenceStart, fenceStart + 1 + keepLines));
|
|
292
|
+
out.push(`[token-goat: ${bodyLines - keepLines * 2} lines elided -- full report via ${recallHint}]`);
|
|
293
|
+
out.push(...lines.slice(closerIndex - keepLines, closerIndex + 1));
|
|
294
|
+
} else {
|
|
295
|
+
out.push(...lines.slice(fenceStart, closerIndex + 1));
|
|
296
|
+
}
|
|
297
|
+
cursor = closerIndex + 1;
|
|
298
|
+
}
|
|
299
|
+
out.push(...lines.slice(cursor));
|
|
300
|
+
return out.join("\n");
|
|
301
|
+
}
|
|
302
|
+
function dedupeFencedBlocks(collapsed, original, recallHint) {
|
|
303
|
+
const originalLines = original.split("\n");
|
|
304
|
+
const originalBlocks = findFencedBlockLines(originalLines);
|
|
305
|
+
if (originalBlocks.length < 2) return collapsed;
|
|
306
|
+
const collapsedLines = collapsed.split("\n");
|
|
307
|
+
const collapsedBlocks = findFencedBlockLines(collapsedLines);
|
|
308
|
+
if (collapsedBlocks.length !== originalBlocks.length) return collapsed;
|
|
309
|
+
const bodyHashes = originalBlocks.map(
|
|
310
|
+
({ fenceStart, closerIndex }) => createHash("sha256").update(originalLines.slice(fenceStart + 1, closerIndex).join("\n")).digest("hex")
|
|
311
|
+
);
|
|
312
|
+
const firstOccurrenceOf = /* @__PURE__ */ new Map();
|
|
313
|
+
const out = [];
|
|
314
|
+
let cursor = 0;
|
|
315
|
+
let dedupedAny = false;
|
|
316
|
+
for (let i = 0; i < collapsedBlocks.length; i++) {
|
|
317
|
+
const { fenceStart, closerIndex } = collapsedBlocks[i];
|
|
318
|
+
const hash = bodyHashes[i];
|
|
319
|
+
if (!firstOccurrenceOf.has(hash)) {
|
|
320
|
+
firstOccurrenceOf.set(hash, i);
|
|
321
|
+
out.push(...collapsedLines.slice(cursor, closerIndex + 1));
|
|
322
|
+
} else {
|
|
323
|
+
out.push(...collapsedLines.slice(cursor, fenceStart));
|
|
324
|
+
out.push(`[token-goat: identical bytes to an earlier block in this report -- full report via ${recallHint}]`);
|
|
325
|
+
dedupedAny = true;
|
|
326
|
+
}
|
|
327
|
+
cursor = closerIndex + 1;
|
|
328
|
+
}
|
|
329
|
+
out.push(...collapsedLines.slice(cursor));
|
|
330
|
+
return dedupedAny ? out.join("\n") : collapsed;
|
|
331
|
+
}
|
|
332
|
+
var BLANK_RUN_KEEP = 2;
|
|
333
|
+
function collapseBlankRunsInFences(text) {
|
|
334
|
+
const lines = text.split("\n");
|
|
335
|
+
const blocks = findFencedBlockLines(lines);
|
|
336
|
+
if (blocks.length === 0) return text;
|
|
337
|
+
const out = [];
|
|
338
|
+
let cursor = 0;
|
|
339
|
+
let changedAny = false;
|
|
340
|
+
for (const { fenceStart, closerIndex } of blocks) {
|
|
341
|
+
out.push(...lines.slice(cursor, fenceStart + 1));
|
|
342
|
+
let blankRun = 0;
|
|
343
|
+
for (let i = fenceStart + 1; i < closerIndex; i++) {
|
|
344
|
+
const line = lines[i];
|
|
345
|
+
if (line === "") {
|
|
346
|
+
blankRun++;
|
|
347
|
+
if (blankRun <= BLANK_RUN_KEEP) out.push(line);
|
|
348
|
+
else changedAny = true;
|
|
349
|
+
} else {
|
|
350
|
+
blankRun = 0;
|
|
351
|
+
out.push(line);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
out.push(lines[closerIndex]);
|
|
355
|
+
cursor = closerIndex + 1;
|
|
356
|
+
}
|
|
357
|
+
out.push(...lines.slice(cursor));
|
|
358
|
+
return changedAny ? out.join("\n") : text;
|
|
359
|
+
}
|
|
360
|
+
var SPAWN_RESTRICT_HINT_KEY = "agent-spawn-restrict-hint";
|
|
361
|
+
var SPAWN_RESTRICT_MAX_NAMES = 3;
|
|
362
|
+
var ROSTER_WALK_MAX_DEPTH = 4;
|
|
363
|
+
var ROSTER_WALK_MAX_FILES = 400;
|
|
364
|
+
var AGENT_NAME_RE = /^[A-Za-z0-9._:-]{1,64}$/;
|
|
365
|
+
function parseAgentDefinition(text, fallbackName) {
|
|
366
|
+
const fmMatch = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
|
|
367
|
+
if (!fmMatch) return null;
|
|
368
|
+
const fm = fmMatch[1];
|
|
369
|
+
const nameMatch = /^name:(.*)$/m.exec(fm);
|
|
370
|
+
const rawName = nameMatch ? nameMatch[1].trim().replace(/^["']|["']$/g, "") : "";
|
|
371
|
+
const resolved = AGENT_NAME_RE.test(rawName) ? rawName : fallbackName;
|
|
372
|
+
if (!AGENT_NAME_RE.test(resolved)) return null;
|
|
373
|
+
const name = resolved;
|
|
374
|
+
const toolsMatch = /^tools:(.*)$/m.exec(fm);
|
|
375
|
+
if (!toolsMatch) return { name, restricted: false };
|
|
376
|
+
const inline = toolsMatch[1].trim();
|
|
377
|
+
if (inline === "*" || inline === '"*"' || inline === "'*'") return { name, restricted: false };
|
|
378
|
+
if (inline !== "") return { name, restricted: true };
|
|
379
|
+
const after = fm.slice(toolsMatch.index + toolsMatch[0].length);
|
|
380
|
+
for (const line of after.split(/\r?\n/)) {
|
|
381
|
+
if (/^\s+-\s*\S/.test(line)) return { name, restricted: true };
|
|
382
|
+
if (/^\S/.test(line)) break;
|
|
383
|
+
}
|
|
384
|
+
return { name, restricted: false };
|
|
385
|
+
}
|
|
386
|
+
function findRestrictedAgentNames(roots) {
|
|
387
|
+
const projectAgentsRoot = path.join(process.cwd(), ".claude", "agents");
|
|
388
|
+
const scanRoots = roots ?? [path.join(claudeConfigDir(), "agents"), projectAgentsRoot];
|
|
389
|
+
const names = /* @__PURE__ */ new Set();
|
|
390
|
+
const visited = /* @__PURE__ */ new Set();
|
|
391
|
+
let filesSeen = 0;
|
|
392
|
+
const walk = (dir, depth, confineTo) => {
|
|
393
|
+
if (depth > ROSTER_WALK_MAX_DEPTH || filesSeen >= ROSTER_WALK_MAX_FILES) return;
|
|
394
|
+
let real;
|
|
395
|
+
try {
|
|
396
|
+
real = fs.realpathSync(dir);
|
|
397
|
+
} catch {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (confineTo !== null && !isInsideRoot(real, confineTo)) return;
|
|
401
|
+
const key = process.platform === "win32" ? real.toLocaleLowerCase() : real;
|
|
402
|
+
if (visited.has(key)) return;
|
|
403
|
+
visited.add(key);
|
|
404
|
+
let entries;
|
|
405
|
+
try {
|
|
406
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
407
|
+
} catch {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
for (const entry of entries) {
|
|
411
|
+
if (filesSeen >= ROSTER_WALK_MAX_FILES) return;
|
|
412
|
+
const full = path.join(dir, entry.name);
|
|
413
|
+
let stat;
|
|
414
|
+
try {
|
|
415
|
+
stat = fs.statSync(full);
|
|
416
|
+
} catch {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (stat.isDirectory()) {
|
|
420
|
+
walk(full, depth + 1, confineTo);
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (!stat.isFile() || !entry.name.toLowerCase().endsWith(".md")) continue;
|
|
424
|
+
filesSeen++;
|
|
425
|
+
let text;
|
|
426
|
+
try {
|
|
427
|
+
text = fs.readFileSync(full, "utf-8");
|
|
428
|
+
} catch {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const parsed = parseAgentDefinition(text, path.basename(entry.name, path.extname(entry.name)));
|
|
432
|
+
if (parsed !== null && parsed.restricted) names.add(parsed.name);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
for (const root of scanRoots) {
|
|
436
|
+
const isProjectRoot = roots === void 0 && path.resolve(root) === path.resolve(projectAgentsRoot);
|
|
437
|
+
if (!isProjectRoot) {
|
|
438
|
+
walk(root, 0, null);
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
let rootIsLink;
|
|
442
|
+
try {
|
|
443
|
+
rootIsLink = fs.lstatSync(root).isSymbolicLink();
|
|
444
|
+
} catch {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (rootIsLink) continue;
|
|
448
|
+
let confineTo;
|
|
449
|
+
try {
|
|
450
|
+
confineTo = fs.realpathSync(root);
|
|
451
|
+
} catch {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
walk(root, 0, confineTo);
|
|
455
|
+
}
|
|
456
|
+
return Array.from(names).sort();
|
|
457
|
+
}
|
|
458
|
+
function buildUnrestrictedSpawnAdvisory(toolInput) {
|
|
459
|
+
try {
|
|
460
|
+
const harness = getHarnessName();
|
|
461
|
+
if (harness === "copilot_cli" || harness === "vscode") return "";
|
|
462
|
+
const rawType = toolInput["subagent_type"];
|
|
463
|
+
const spawnType = typeof rawType === "string" ? rawType.trim() : "";
|
|
464
|
+
if (spawnType !== "" && spawnType !== "general-purpose") return "";
|
|
465
|
+
if (wasHintShown(SPAWN_RESTRICT_HINT_KEY)) return "";
|
|
466
|
+
const names = findRestrictedAgentNames();
|
|
467
|
+
if (names.length === 0) return "";
|
|
468
|
+
markHintShown(SPAWN_RESTRICT_HINT_KEY);
|
|
469
|
+
recordStat("session_hint", 0, 0, void 0, "agent-spawn-restrict");
|
|
470
|
+
const shown = neutralizeSpokenMarkers(names.slice(0, SPAWN_RESTRICT_MAX_NAMES).join(", "));
|
|
471
|
+
const more = names.length > SPAWN_RESTRICT_MAX_NAMES ? ` and ${names.length - SPAWN_RESTRICT_MAX_NAMES} more` : "";
|
|
472
|
+
return `[token-goat] This spawn ran as general-purpose (the default when subagent_type is omitted), which is unrestricted: its lane starts by paying for every tool and MCP schema on the machine. Tools-restricted agent definitions exist here: ${shown}${more}. A future spawn that fits one of them can pass that name as subagent_type to start with a much smaller prefix. Advisory only: this spawn has already run, and this notice saved nothing.`;
|
|
473
|
+
} catch {
|
|
474
|
+
return "";
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
var SCOPED_SPAWN_DENY_KEY = "agent-scoped-spawn-deny";
|
|
478
|
+
function buildScopedSpawnDeny(toolInput) {
|
|
479
|
+
if (!loadConfig().hints.agent_scoped_spawn_deny) return null;
|
|
480
|
+
const harness = getHarnessName();
|
|
481
|
+
if (harness === "copilot_cli" || harness === "vscode") return null;
|
|
482
|
+
const rawType = toolInput["subagent_type"];
|
|
483
|
+
if (typeof rawType === "string" && rawType.trim() !== "") return null;
|
|
484
|
+
if (wasHintShown(SCOPED_SPAWN_DENY_KEY)) return null;
|
|
485
|
+
const names = findRestrictedAgentNames();
|
|
486
|
+
if (names.length === 0) return null;
|
|
487
|
+
markHintShown(SCOPED_SPAWN_DENY_KEY);
|
|
488
|
+
markHintShown(SPAWN_RESTRICT_HINT_KEY);
|
|
489
|
+
recordStat("agent_scoped_spawn_deny", 0, 0);
|
|
490
|
+
const shown = neutralizeSpokenMarkers(names.slice(0, SPAWN_RESTRICT_MAX_NAMES).join(", "));
|
|
491
|
+
const more = names.length > SPAWN_RESTRICT_MAX_NAMES ? ` and ${names.length - SPAWN_RESTRICT_MAX_NAMES} more` : "";
|
|
492
|
+
return denyOutput(`This Agent call omits subagent_type, so it would run as general-purpose, which is unrestricted: its lane starts by paying for every tool and MCP schema on the machine. Tools-restricted agent definitions exist here: ${shown}${more}. Re-issue the call with one of them as subagent_type if it fits the task. If none fits, re-issue it unchanged and it will run: this refusal fires once per session.`);
|
|
493
|
+
}
|
|
494
|
+
function reportNotice(resultText, recallHint, spawnAdvisory) {
|
|
495
|
+
return `[token-goat] This subagent report (${toKB(resultText.length)}KB) is cached for later recall: ${recallHint}${spawnAdvisory === "" ? "" : `
|
|
496
|
+
${spawnAdvisory}`}`;
|
|
497
|
+
}
|
|
498
|
+
var REWRITTEN_REPORT_RE = /\n\n\[token-goat\] This subagent report \([0-9.]+KB\) is cached for later recall: token-goat mcp-output mcp_[0-9a-f]{16} --full(?:\ntoken-goat: [^\n]*)*$/;
|
|
499
|
+
function planReportCompaction(resultText, recallHint, notice) {
|
|
500
|
+
const cfg = loadConfig().agent_report;
|
|
501
|
+
const collapsed = collapseFencedBlocks(resultText, recallHint, cfg.fence_collapse_min_lines, cfg.fence_collapse_keep_lines);
|
|
502
|
+
const deduped = dedupeFencedBlocks(collapsed, resultText, recallHint);
|
|
503
|
+
const final = collapseBlankRunsInFences(deduped);
|
|
504
|
+
if (final === resultText) return { final, worthwhile: false };
|
|
505
|
+
const worthwhile = isRewriteWorthwhile({
|
|
506
|
+
originalBytes: Buffer.byteLength(resultText, "utf-8"),
|
|
507
|
+
rewrittenBytes: Buffer.byteLength(final, "utf-8"),
|
|
508
|
+
noticeBytes: Buffer.byteLength(notice, "utf-8"),
|
|
509
|
+
minNetSavingsBytes: resolveMinNetSavingsBytes()
|
|
510
|
+
});
|
|
511
|
+
return { final, worthwhile };
|
|
512
|
+
}
|
|
513
|
+
function recordReportCompaction(resultText, updatedOutput) {
|
|
514
|
+
const savedBytes = Buffer.byteLength(resultText, "utf-8") - Buffer.byteLength(updatedOutput, "utf-8");
|
|
515
|
+
if (savedBytes > 0) recordStat("agent_report_compact", savedBytes, savedTokensFromBytes(savedBytes));
|
|
516
|
+
}
|
|
517
|
+
function receiptRewrite(resultText, receipt) {
|
|
518
|
+
recordStat("agent_receipt", 0, 0, void 0, "agent");
|
|
519
|
+
return emitRewrite(`${resultText}
|
|
520
|
+
|
|
521
|
+
${receipt}`, "agent");
|
|
522
|
+
}
|
|
523
|
+
async function subagentReportRewriteHandler(event) {
|
|
524
|
+
try {
|
|
525
|
+
if (getHarnessName() !== "copilot_cli" || !event.sessionId) return passOutput();
|
|
526
|
+
const raw = event.raw["last_assistant_message"];
|
|
527
|
+
if (typeof raw !== "string" || raw === "") return passOutput();
|
|
528
|
+
const redactedReport = redactSecrets(raw);
|
|
529
|
+
const resultText = redactedReport.text;
|
|
530
|
+
const receipt = (await loadAgentReceipt()).receiptForStoppedAgent(event, resultText);
|
|
531
|
+
const receiptOnly = () => receipt === null ? passOutput() : receiptRewrite(resultText, receipt);
|
|
532
|
+
if (resultText.length < loadConfig().agent_report.min_bytes) return receiptOnly();
|
|
533
|
+
const toolInput = { agent_id: event.agentId ?? "" };
|
|
534
|
+
const id = mcpOutputId(event.sessionId, mcpHash("task", toolInput));
|
|
535
|
+
const recallHint = `token-goat mcp-output ${id} --full`;
|
|
536
|
+
const notice = reportNotice(resultText, recallHint, receipt ?? "");
|
|
537
|
+
const { final, worthwhile } = planReportCompaction(resultText, recallHint, notice);
|
|
538
|
+
if (!worthwhile) return receiptOnly();
|
|
539
|
+
if (storeMcpOutput(event.sessionId, "task", toolInput, resultText) !== id) return receiptOnly();
|
|
540
|
+
if (redactedReport.count > 0) recordStat("secret_redacted", 0, redactedReport.count, void 0, "agent");
|
|
541
|
+
if (receipt !== null) recordStat("agent_receipt", 0, 0, void 0, "agent");
|
|
542
|
+
const updatedOutput = `${final}
|
|
543
|
+
|
|
544
|
+
${notice}`;
|
|
545
|
+
recordReportCompaction(resultText, updatedOutput);
|
|
546
|
+
return emitRewrite(updatedOutput, "agent", void 0, "counted-elsewhere");
|
|
547
|
+
} catch {
|
|
548
|
+
return passOutput();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
async function postAgentHandler(event) {
|
|
552
|
+
try {
|
|
553
|
+
if (!isAgentTool(event.toolName) || !event.sessionId) return passOutput();
|
|
554
|
+
const finished = readSpawnBrief(event.toolName, event.toolInput);
|
|
555
|
+
if (finished !== null) removeOutstandingAgentSpawn(finished.text);
|
|
556
|
+
if (event.toolName === "spawn_agent") return passOutput();
|
|
557
|
+
const redactedReport = redactSecrets(extractToolResultText(event.raw));
|
|
558
|
+
const resultText = redactedReport.text;
|
|
559
|
+
if (REWRITTEN_REPORT_RE.test(resultText)) return passOutput();
|
|
560
|
+
const agentReportCfg = loadConfig().agent_report;
|
|
561
|
+
const receipt = (await loadAgentReceipt()).takeAgentReceipt(event.sessionId, resultText);
|
|
562
|
+
if (receipt !== null) recordStat("agent_receipt", 0, 0, void 0, "agent");
|
|
563
|
+
const spawnAdvisory = [buildUnrestrictedSpawnAdvisory(event.toolInput), receipt ?? ""].filter((part) => part !== "").join("\n");
|
|
564
|
+
if (!resultText || resultText.length < agentReportCfg.min_bytes) {
|
|
565
|
+
return spawnAdvisory === "" ? passOutput() : contextOutput(spawnAdvisory);
|
|
566
|
+
}
|
|
567
|
+
const id = storeMcpOutput(event.sessionId, event.toolName ?? "Agent", event.toolInput, resultText);
|
|
568
|
+
if (id === null) return spawnAdvisory === "" ? passOutput() : contextOutput(spawnAdvisory);
|
|
569
|
+
if (redactedReport.count > 0) recordStat("secret_redacted", 0, redactedReport.count, void 0, "agent");
|
|
570
|
+
recordStat("session_hint", 0, 0);
|
|
571
|
+
const recallHint = `token-goat mcp-output ${id} --full`;
|
|
572
|
+
const notice = reportNotice(resultText, recallHint, spawnAdvisory);
|
|
573
|
+
const { final, worthwhile } = planReportCompaction(resultText, recallHint, notice);
|
|
574
|
+
if (final !== resultText && !dropsResultRewrite()) {
|
|
575
|
+
if (worthwhile) {
|
|
576
|
+
const updatedOutput = `${final}
|
|
577
|
+
|
|
578
|
+
${notice}`;
|
|
579
|
+
recordReportCompaction(resultText, updatedOutput);
|
|
580
|
+
return emitRewrite(updatedOutput, "agent", void 0, "counted-elsewhere");
|
|
581
|
+
}
|
|
582
|
+
recordStat("agent_report_compact_declined", 0, 0);
|
|
583
|
+
} else if (final !== resultText && worthwhile && spawnAdvisory === "") {
|
|
584
|
+
return passOutput();
|
|
585
|
+
}
|
|
586
|
+
return contextOutput(notice);
|
|
587
|
+
} catch {
|
|
588
|
+
return passOutput();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
export {
|
|
592
|
+
buildUnrestrictedSpawnAdvisory,
|
|
593
|
+
collapseBlankRunsInFences,
|
|
594
|
+
collapseFencedBlocks,
|
|
595
|
+
dedupeFencedBlocks,
|
|
596
|
+
findRestrictedAgentNames,
|
|
597
|
+
parseAgentDefinition,
|
|
598
|
+
postAgentHandler,
|
|
599
|
+
preAgentHandler,
|
|
600
|
+
subagentReportRewriteHandler,
|
|
601
|
+
subagentStartHandler,
|
|
602
|
+
subagentStartWired
|
|
603
|
+
};
|