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,366 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
registerHook,
|
|
5
|
+
sessionStateKey
|
|
6
|
+
} from "./token-goat-chunk-C75NA7PL.mjs";
|
|
7
|
+
import {
|
|
8
|
+
passOutput
|
|
9
|
+
} from "./token-goat-chunk-76FGDLRO.mjs";
|
|
10
|
+
import {
|
|
11
|
+
HOOK_PROBE_ENV
|
|
12
|
+
} from "./token-goat-chunk-U4WHMG6Y.mjs";
|
|
13
|
+
import {
|
|
14
|
+
getDb
|
|
15
|
+
} from "./token-goat-chunk-GVB2MUST.mjs";
|
|
16
|
+
import {
|
|
17
|
+
loadConfig
|
|
18
|
+
} from "./token-goat-chunk-7EZTZOMC.mjs";
|
|
19
|
+
import {
|
|
20
|
+
getHarnessName
|
|
21
|
+
} from "./token-goat-chunk-QYHO5CPH.mjs";
|
|
22
|
+
import {
|
|
23
|
+
globalDbPath
|
|
24
|
+
} from "./token-goat-chunk-CO3UYX6G.mjs";
|
|
25
|
+
import {
|
|
26
|
+
init_define_import_meta_env
|
|
27
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
28
|
+
|
|
29
|
+
// src/hint_stats.ts
|
|
30
|
+
init_define_import_meta_env();
|
|
31
|
+
var HINT_CATEGORIES = [
|
|
32
|
+
"bash_redirect",
|
|
33
|
+
"bash_recall",
|
|
34
|
+
"read_reread_dedup",
|
|
35
|
+
"read_structural_nav",
|
|
36
|
+
"edit_reread_suggest",
|
|
37
|
+
// call_streak.ts: serial read-only calls that could have gone out in one message, and consecutive searches that found nothing. Both are scored by that module itself (see SELF_SCORED_HINT_CATEGORIES).
|
|
38
|
+
"read_batch",
|
|
39
|
+
"search_brake",
|
|
40
|
+
// The Grep/Glob dedup notes from hooks_common.ts's makeDedupHintHandlers. Logged with no correlator, so they count as spend and emissions but never as a verdict: the note is attached to the re-run it describes, so no later call can show whether it was heeded.
|
|
41
|
+
"grep_dedup_hint",
|
|
42
|
+
"glob_dedup_hint",
|
|
43
|
+
// recovery_pairs.ts: a failed Bash command that an earlier session learned a fix for. Logged with no correlator: the fix may be run in many spellings, so the pair store scores it (helped and hurt) rather than a pointer match.
|
|
44
|
+
"recovery_pair",
|
|
45
|
+
// edit_near_miss.ts: a failed Edit whose old_string differs from the file only by whitespace, punctuation or indentation. Logged with no correlator: the corrected edit may be retyped in any spelling, so it counts as spend and emissions but never a verdict.
|
|
46
|
+
"edit_near_miss",
|
|
47
|
+
// path_miss.ts: a tool call named a path that does not exist and an existing path is plausibly the one meant. Logged with no correlator: the corrected call may name the path in any spelling, so it counts as spend and emissions but never a verdict.
|
|
48
|
+
"path_miss"
|
|
49
|
+
];
|
|
50
|
+
function isHintCategory(value) {
|
|
51
|
+
return HINT_CATEGORIES.includes(value);
|
|
52
|
+
}
|
|
53
|
+
var ACTED_ON_WINDOW = 5;
|
|
54
|
+
var KNOWN_CORRELATOR_PLACEHOLDERS = /* @__PURE__ */ new Set([
|
|
55
|
+
"Heading",
|
|
56
|
+
"HeadingName",
|
|
57
|
+
"SectionHeading",
|
|
58
|
+
"SectionName",
|
|
59
|
+
"sectionName",
|
|
60
|
+
"Symbol",
|
|
61
|
+
"SymbolName",
|
|
62
|
+
"table_name",
|
|
63
|
+
"name"
|
|
64
|
+
]);
|
|
65
|
+
function joinCorrelators(correlators) {
|
|
66
|
+
const kept = correlators.filter((c) => c !== "" && !c.includes("\n"));
|
|
67
|
+
return kept.length === 0 ? null : [...new Set(kept)].join("\n");
|
|
68
|
+
}
|
|
69
|
+
function splitCorrelators(correlator) {
|
|
70
|
+
return correlator.split("\n").filter((c) => c !== "");
|
|
71
|
+
}
|
|
72
|
+
function extractPathCorrelator(text) {
|
|
73
|
+
const m = /(?:[A-Za-z]:[\\/]|\.{1,2}\/|\/)[^\s"'`]+/.exec(text);
|
|
74
|
+
if (m === null) return null;
|
|
75
|
+
const cleaned = m[0].replace(/[`"'.,;:)]+$/, "");
|
|
76
|
+
const sepIdx = cleaned.indexOf("::");
|
|
77
|
+
if (sepIdx === -1) return cleaned;
|
|
78
|
+
const suffix = cleaned.slice(sepIdx + 2);
|
|
79
|
+
if (/^<[^<>]*>$/.test(suffix) || KNOWN_CORRELATOR_PLACEHOLDERS.has(suffix)) {
|
|
80
|
+
return cleaned.slice(0, sepIdx);
|
|
81
|
+
}
|
|
82
|
+
return cleaned;
|
|
83
|
+
}
|
|
84
|
+
function classifyBashHint(text) {
|
|
85
|
+
const fileMatch = /token-goat bash-output --file "([^"]+)"/.exec(text);
|
|
86
|
+
if (fileMatch?.[1] !== void 0) {
|
|
87
|
+
return { category: "bash_recall", correlator: fileMatch[1] };
|
|
88
|
+
}
|
|
89
|
+
const idMatch = /token-goat bash-output ([A-Za-z0-9_.-]+)/.exec(text);
|
|
90
|
+
if (idMatch?.[1] !== void 0) {
|
|
91
|
+
return { category: "bash_recall", correlator: idMatch[1] };
|
|
92
|
+
}
|
|
93
|
+
return { category: "bash_redirect", correlator: extractPathCorrelator(text) };
|
|
94
|
+
}
|
|
95
|
+
function classifyReadHint(text) {
|
|
96
|
+
const category = /already read|already been read/i.test(text) ? "read_reread_dedup" : "read_structural_nav";
|
|
97
|
+
return { category, correlator: extractPathCorrelator(text) };
|
|
98
|
+
}
|
|
99
|
+
function classifyEditHint(text) {
|
|
100
|
+
return { category: "edit_reread_suggest", correlator: extractPathCorrelator(text) };
|
|
101
|
+
}
|
|
102
|
+
function uncorrelatedHint(category) {
|
|
103
|
+
return () => ({ category, correlator: null });
|
|
104
|
+
}
|
|
105
|
+
var SELF_SCORED_HINT_CATEGORIES = /* @__PURE__ */ new Set(["read_batch", "search_brake"]);
|
|
106
|
+
function settleSelfScoredHints(category, event, actedOn) {
|
|
107
|
+
try {
|
|
108
|
+
getDb(globalDbPath()).prepare(`UPDATE hint_emissions SET acted_on = ?, observable = ?, resolved = 1 WHERE category = ? AND session_id = ? AND correlator IS ? AND resolved = 0`).run(actedOn === true ? 1 : 0, actedOn === null ? 0 : 1, category, event.sessionId, sessionStateKey(event));
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function isProbeOccasion(occasion, thresholds) {
|
|
113
|
+
const sorted = [...new Set(thresholds.filter((t) => t > 0))].sort((a, b) => a - b);
|
|
114
|
+
if (sorted.length === 0) return false;
|
|
115
|
+
if (sorted.includes(occasion)) return true;
|
|
116
|
+
const last = sorted[sorted.length - 1];
|
|
117
|
+
return occasion > last && occasion % last === 0;
|
|
118
|
+
}
|
|
119
|
+
function bumpSuppressionStreak(category) {
|
|
120
|
+
try {
|
|
121
|
+
const db = getDb(globalDbPath());
|
|
122
|
+
const harness = getHarnessName();
|
|
123
|
+
db.prepare(
|
|
124
|
+
`INSERT INTO hint_suppression_probes (category, harness, streak) VALUES (@category, @harness, 1)
|
|
125
|
+
ON CONFLICT(category, harness) DO UPDATE SET streak = streak + 1`
|
|
126
|
+
).run({ category, harness });
|
|
127
|
+
const row = db.prepare(`SELECT streak FROM hint_suppression_probes WHERE category = ? AND harness = ?`).get(category, harness);
|
|
128
|
+
return row?.streak ?? 0;
|
|
129
|
+
} catch {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function resetSuppressionStreak(category) {
|
|
134
|
+
try {
|
|
135
|
+
const db = getDb(globalDbPath());
|
|
136
|
+
db.prepare(`UPDATE hint_suppression_probes SET streak = 0 WHERE category = ? AND harness = ?`).run(category, getHarnessName());
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function applyHintTracking(event, output, classify) {
|
|
141
|
+
if (output.hookType !== "context") return output;
|
|
142
|
+
if (process.env[HOOK_PROBE_ENV] === "1") return output;
|
|
143
|
+
const classified = classify(output.context);
|
|
144
|
+
const { category } = classified;
|
|
145
|
+
const correlator = output.correlators === void 0 ? classified.correlator : joinCorrelators(output.correlators);
|
|
146
|
+
const compensateSelfResolve = event.eventName === "pre_tool_use";
|
|
147
|
+
if (shouldSuppress(category, event.sessionId)) {
|
|
148
|
+
const occasion = bumpSuppressionStreak(category);
|
|
149
|
+
const thresholds = loadConfig().hints.backoff_thresholds;
|
|
150
|
+
if (!isProbeOccasion(occasion, thresholds)) {
|
|
151
|
+
logSuppressedDetection(category, event.sessionId, correlator);
|
|
152
|
+
return passOutput();
|
|
153
|
+
}
|
|
154
|
+
logHintEmission(category, event.sessionId, correlator, compensateSelfResolve, output.context.length);
|
|
155
|
+
return output;
|
|
156
|
+
}
|
|
157
|
+
resetSuppressionStreak(category);
|
|
158
|
+
logHintEmission(category, event.sessionId, correlator, compensateSelfResolve, output.context.length);
|
|
159
|
+
return output;
|
|
160
|
+
}
|
|
161
|
+
function logSuppressedDetection(category, sessionId, correlator) {
|
|
162
|
+
try {
|
|
163
|
+
getDb(globalDbPath()).prepare(
|
|
164
|
+
`INSERT INTO hint_emissions (category, session_id, harness, correlator, emitted_at, resolved, acted_on, calls_remaining, bytes_emitted, observable, displayed)
|
|
165
|
+
VALUES (@category, @sessionId, @harness, @correlator, @emittedAt, 1, 0, 0, 0, 0, 0)`
|
|
166
|
+
).run({ category, sessionId, harness: getHarnessName(), correlator, emittedAt: Date.now() });
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function logHintEmission(category, sessionId, correlator, compensateSelfResolve = false, bytesEmitted = null) {
|
|
171
|
+
try {
|
|
172
|
+
const db = getDb(globalDbPath());
|
|
173
|
+
const observable = correlator !== null || SELF_SCORED_HINT_CATEGORIES.has(category);
|
|
174
|
+
const resolved = observable ? 0 : 1;
|
|
175
|
+
const window = ACTED_ON_WINDOW + (compensateSelfResolve ? 1 : 0);
|
|
176
|
+
db.prepare(
|
|
177
|
+
`INSERT INTO hint_emissions (category, session_id, harness, correlator, emitted_at, resolved, acted_on, calls_remaining, bytes_emitted, observable)
|
|
178
|
+
VALUES (@category, @sessionId, @harness, @correlator, @emittedAt, @resolved, 0, @callsRemaining, @bytesEmitted, @observable)`
|
|
179
|
+
).run({
|
|
180
|
+
category,
|
|
181
|
+
sessionId,
|
|
182
|
+
harness: getHarnessName(),
|
|
183
|
+
correlator,
|
|
184
|
+
emittedAt: Date.now(),
|
|
185
|
+
resolved,
|
|
186
|
+
callsRemaining: observable ? window : 0,
|
|
187
|
+
bytesEmitted,
|
|
188
|
+
observable: observable ? 1 : 0
|
|
189
|
+
});
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
var TOKEN_GOAT_INVOCATION_RE = /(?:^|[\s;&|])(?:token-goat|tg)(?=[\s]|$)/;
|
|
194
|
+
function commandMentionsCorrelator(command, correlator) {
|
|
195
|
+
let idx = command.indexOf(correlator);
|
|
196
|
+
while (idx !== -1) {
|
|
197
|
+
const before = idx > 0 ? command[idx - 1] : void 0;
|
|
198
|
+
const after = command[idx + correlator.length];
|
|
199
|
+
const beforeOk = before === void 0 || !/[A-Za-z0-9_.-]/.test(before);
|
|
200
|
+
const afterOk = after === void 0 || !/[A-Za-z0-9_.-]/.test(after);
|
|
201
|
+
if (beforeOk && afterOk) return true;
|
|
202
|
+
idx = command.indexOf(correlator, idx + 1);
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
var SUPPRESSION_HINT_CATEGORIES = /* @__PURE__ */ new Set([
|
|
207
|
+
"read_reread_dedup",
|
|
208
|
+
"edit_reread_suggest",
|
|
209
|
+
"read_structural_nav"
|
|
210
|
+
]);
|
|
211
|
+
function isSuppressionCategory(category) {
|
|
212
|
+
return SUPPRESSION_HINT_CATEGORIES.has(category);
|
|
213
|
+
}
|
|
214
|
+
var EVENT_PATH_KEYS = ["file_path", "filePath", "notebook_path", "path"];
|
|
215
|
+
function eventTargetText(event) {
|
|
216
|
+
if (event.toolName === "Bash") {
|
|
217
|
+
const c = event.toolInput["command"];
|
|
218
|
+
return typeof c === "string" ? c : "";
|
|
219
|
+
}
|
|
220
|
+
for (const key of EVENT_PATH_KEYS) {
|
|
221
|
+
const v = event.toolInput[key];
|
|
222
|
+
if (typeof v === "string" && v !== "") return v;
|
|
223
|
+
}
|
|
224
|
+
return "";
|
|
225
|
+
}
|
|
226
|
+
function isDefiance(correlator, target) {
|
|
227
|
+
if (target === "") return false;
|
|
228
|
+
if (TOKEN_GOAT_INVOCATION_RE.test(target)) return false;
|
|
229
|
+
return splitCorrelators(correlator).some((c) => commandMentionsCorrelator(target, c));
|
|
230
|
+
}
|
|
231
|
+
function isActedOn(category, correlator, command) {
|
|
232
|
+
if (!TOKEN_GOAT_INVOCATION_RE.test(command)) return false;
|
|
233
|
+
const anyMatch = splitCorrelators(correlator).some((c) => commandMentionsCorrelator(command, c));
|
|
234
|
+
if (category === "bash_recall") return command.includes("bash-output") && anyMatch;
|
|
235
|
+
return anyMatch;
|
|
236
|
+
}
|
|
237
|
+
function resolvePendingHintsForEvent(event) {
|
|
238
|
+
try {
|
|
239
|
+
const db = getDb(globalDbPath());
|
|
240
|
+
const command = event.toolName === "Bash" && typeof event.toolInput["command"] === "string" ? event.toolInput["command"] : "";
|
|
241
|
+
const target = eventTargetText(event);
|
|
242
|
+
const pending = db.prepare(`SELECT id, category, correlator, calls_remaining FROM hint_emissions WHERE session_id = ? AND resolved = 0`).all(event.sessionId);
|
|
243
|
+
for (const row of pending) {
|
|
244
|
+
if (isHintCategory(row.category) && SELF_SCORED_HINT_CATEGORIES.has(row.category)) continue;
|
|
245
|
+
if (!isHintCategory(row.category) || row.correlator === null) {
|
|
246
|
+
db.prepare(`UPDATE hint_emissions SET acted_on = 0, resolved = 1, observable = 0 WHERE id = ?`).run(row.id);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (isSuppressionCategory(row.category)) {
|
|
250
|
+
if (isDefiance(row.correlator, target)) {
|
|
251
|
+
db.prepare(`UPDATE hint_emissions SET acted_on = 0, resolved = 1 WHERE id = ?`).run(row.id);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (command !== "" && isActedOn(row.category, row.correlator, command)) {
|
|
255
|
+
db.prepare(`UPDATE hint_emissions SET acted_on = 1, resolved = 1 WHERE id = ?`).run(row.id);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const left = row.calls_remaining - 1;
|
|
259
|
+
if (left <= 0) {
|
|
260
|
+
db.prepare(`UPDATE hint_emissions SET acted_on = 1, resolved = 1 WHERE id = ?`).run(row.id);
|
|
261
|
+
} else {
|
|
262
|
+
db.prepare(`UPDATE hint_emissions SET calls_remaining = ? WHERE id = ?`).run(left, row.id);
|
|
263
|
+
}
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (command !== "" && isActedOn(row.category, row.correlator, command)) {
|
|
267
|
+
db.prepare(`UPDATE hint_emissions SET acted_on = 1, resolved = 1 WHERE id = ?`).run(row.id);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const remaining = row.calls_remaining - 1;
|
|
271
|
+
if (remaining <= 0) {
|
|
272
|
+
db.prepare(`UPDATE hint_emissions SET resolved = 1 WHERE id = ?`).run(row.id);
|
|
273
|
+
} else {
|
|
274
|
+
db.prepare(`UPDATE hint_emissions SET calls_remaining = ? WHERE id = ?`).run(remaining, row.id);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
registerHook(
|
|
281
|
+
"post_tool_use",
|
|
282
|
+
(event) => {
|
|
283
|
+
resolvePendingHintsForEvent(event);
|
|
284
|
+
return passOutput();
|
|
285
|
+
},
|
|
286
|
+
{ advisory: true, followsMatcher: true }
|
|
287
|
+
);
|
|
288
|
+
function categoryStats(category, sessionId) {
|
|
289
|
+
const db = getDb(globalDbPath());
|
|
290
|
+
const scope = sessionId === void 0 ? "harness = ?" : "session_id = ?";
|
|
291
|
+
const row = db.prepare(
|
|
292
|
+
`SELECT COALESCE(SUM(CASE WHEN displayed = 1 AND observable = 1 AND resolved = 1 THEN 1 ELSE 0 END), 0) AS emitted,
|
|
293
|
+
SUM(CASE WHEN displayed = 1 AND observable = 1 AND resolved = 1 THEN acted_on ELSE 0 END) AS actedOn,
|
|
294
|
+
COALESCE(SUM(CASE WHEN displayed = 1 AND observable = 1 AND resolved = 0 THEN 1 ELSE 0 END), 0) AS pending,
|
|
295
|
+
COALESCE(SUM(CASE WHEN displayed = 1 AND observable = 0 THEN 1 ELSE 0 END), 0) AS unobservable,
|
|
296
|
+
COALESCE(SUM(CASE WHEN displayed = 0 THEN 1 ELSE 0 END), 0) AS detected,
|
|
297
|
+
SUM(bytes_emitted) AS bytesEmitted,
|
|
298
|
+
SUM(CASE WHEN bytes_emitted IS NULL THEN 1 ELSE 0 END) AS legacyEmissions
|
|
299
|
+
FROM hint_emissions WHERE category = ? AND ${scope}`
|
|
300
|
+
).get(category, sessionId ?? getHarnessName());
|
|
301
|
+
return row ?? { emitted: 0, actedOn: 0, pending: 0, unobservable: 0, detected: 0, bytesEmitted: null, legacyEmissions: 0 };
|
|
302
|
+
}
|
|
303
|
+
function shouldSuppress(category, _sessionId) {
|
|
304
|
+
try {
|
|
305
|
+
const { emitted, actedOn } = categoryStats(category);
|
|
306
|
+
return suppressesAt(emitted, actedOn ?? 0, loadConfig().hint_stats, isSuppressionCategory(category));
|
|
307
|
+
} catch {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function suppressesAt(emitted, actedOn, cfg, inverted) {
|
|
312
|
+
if (emitted < cfg.min_sample_size) return false;
|
|
313
|
+
const barPct = inverted ? 100 - cfg.defiance_threshold_pct : cfg.suppress_threshold_pct;
|
|
314
|
+
return 100 * wilsonInterval(actedOn, emitted).hi < barPct;
|
|
315
|
+
}
|
|
316
|
+
function wilsonInterval(k, n, z = 1.96) {
|
|
317
|
+
if (n <= 0) return { lo: 0, hi: 1 };
|
|
318
|
+
const phat = k / n;
|
|
319
|
+
const z2 = z * z;
|
|
320
|
+
const denom = 1 + z2 / n;
|
|
321
|
+
const centre = phat + z2 / (2 * n);
|
|
322
|
+
const margin = z * Math.sqrt(phat * (1 - phat) / n + z2 / (4 * n * n));
|
|
323
|
+
return { lo: k <= 0 ? 0 : Math.max(0, (centre - margin) / denom), hi: k >= n ? 1 : Math.min(1, (centre + margin) / denom) };
|
|
324
|
+
}
|
|
325
|
+
function meetsSavingsFloor(bytesSaved) {
|
|
326
|
+
return bytesSaved >= loadConfig().hints.min_session_hint_savings_bytes;
|
|
327
|
+
}
|
|
328
|
+
function resetHintStats() {
|
|
329
|
+
const db = getDb(globalDbPath());
|
|
330
|
+
db.exec("DELETE FROM hint_emissions");
|
|
331
|
+
db.exec("DELETE FROM hint_manual_marks");
|
|
332
|
+
db.exec("DELETE FROM hint_suppression_probes");
|
|
333
|
+
}
|
|
334
|
+
function bumpManualMark(category, column) {
|
|
335
|
+
const db = getDb(globalDbPath());
|
|
336
|
+
db.prepare(
|
|
337
|
+
`INSERT INTO hint_manual_marks (category, effective_count, ineffective_count) VALUES (?, 0, 0)
|
|
338
|
+
ON CONFLICT(category) DO NOTHING`
|
|
339
|
+
).run(category);
|
|
340
|
+
db.prepare(`UPDATE hint_manual_marks SET ${column} = ${column} + 1 WHERE category = ?`).run(category);
|
|
341
|
+
}
|
|
342
|
+
function markCategoryEffective(category) {
|
|
343
|
+
bumpManualMark(category, "effective_count");
|
|
344
|
+
}
|
|
345
|
+
function markCategoryIneffective(category) {
|
|
346
|
+
bumpManualMark(category, "ineffective_count");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export {
|
|
350
|
+
HINT_CATEGORIES,
|
|
351
|
+
isHintCategory,
|
|
352
|
+
classifyBashHint,
|
|
353
|
+
classifyReadHint,
|
|
354
|
+
classifyEditHint,
|
|
355
|
+
uncorrelatedHint,
|
|
356
|
+
settleSelfScoredHints,
|
|
357
|
+
applyHintTracking,
|
|
358
|
+
logSuppressedDetection,
|
|
359
|
+
isSuppressionCategory,
|
|
360
|
+
categoryStats,
|
|
361
|
+
shouldSuppress,
|
|
362
|
+
meetsSavingsFloor,
|
|
363
|
+
resetHintStats,
|
|
364
|
+
markCategoryEffective,
|
|
365
|
+
markCategoryIneffective
|
|
366
|
+
};
|