token-goat 2.9.28 → 2.9.30

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.
Files changed (134) hide show
  1. package/README.md +36 -40
  2. package/SECURITY.md +28 -10
  3. package/THIRD_PARTY_NOTICES.md +40 -3
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/ort-wasm-simd-threaded.mjs +59 -0
  7. package/dist/token-goat-chunk-3CHUNJ2O.mjs +53 -0
  8. package/dist/token-goat-chunk-3Z5S4KGM.mjs +918 -0
  9. package/dist/token-goat-chunk-4FVIAHSI.mjs +211 -0
  10. package/dist/{token-goat-chunk-66LODAUT.mjs → token-goat-chunk-4JJS54TR.mjs} +4 -3
  11. package/dist/token-goat-chunk-4LCCNRTG.mjs +313 -0
  12. package/dist/token-goat-chunk-54K3EUV3.mjs +35 -0
  13. package/dist/token-goat-chunk-56EIMS3E.mjs +159 -0
  14. package/dist/token-goat-chunk-5BCIJXMO.mjs +609 -0
  15. package/dist/token-goat-chunk-5KDMCMF2.mjs +362 -0
  16. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  17. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  18. package/dist/{token-goat-chunk-NILVK7XM.mjs → token-goat-chunk-64FBPDTK.mjs} +12 -6
  19. package/dist/{token-goat-chunk-LEG3JNJ6.mjs → token-goat-chunk-664RTTUV.mjs} +31 -15
  20. package/dist/token-goat-chunk-67TQJ76B.mjs +57 -0
  21. package/dist/token-goat-chunk-6QMAS7AB.mjs +42 -0
  22. package/dist/token-goat-chunk-7BXSNBY5.mjs +253 -0
  23. package/dist/{token-goat-chunk-F7QZRIWM.mjs → token-goat-chunk-7F2UBPD3.mjs} +42 -35
  24. package/dist/{token-goat-chunk-CC2PYJM7.mjs → token-goat-chunk-7IN2MKDS.mjs} +718 -595
  25. package/dist/token-goat-chunk-7NADEDKJ.mjs +124 -0
  26. package/dist/{token-goat-chunk-6SGLIPQB.mjs → token-goat-chunk-A3CK6N5Z.mjs} +621 -72
  27. package/dist/{token-goat-chunk-HXNAC4ZF.mjs → token-goat-chunk-AFLYLHDH.mjs} +48 -33
  28. package/dist/token-goat-chunk-AM5V6GSX.mjs +367 -0
  29. package/dist/{token-goat-chunk-I7CB3X4K.mjs → token-goat-chunk-APGZXSPS.mjs} +44 -148
  30. package/dist/{token-goat-chunk-BJBRGPBX.mjs → token-goat-chunk-ARDNEC2U.mjs} +11 -7
  31. package/dist/token-goat-chunk-ATCPY7EQ.mjs +134 -0
  32. package/dist/token-goat-chunk-B2RZZCSS.mjs +354 -0
  33. package/dist/{token-goat-chunk-QM76S6YS.mjs → token-goat-chunk-B45VMIIH.mjs} +6 -5
  34. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  35. package/dist/{token-goat-chunk-GGLEE35R.mjs → token-goat-chunk-C63JQV5K.mjs} +49 -10
  36. package/dist/{token-goat-chunk-RJH64KQH.mjs → token-goat-chunk-COBQGL5S.mjs} +2661 -2440
  37. package/dist/token-goat-chunk-COTXZHTS.mjs +39 -0
  38. package/dist/token-goat-chunk-CYCEYAEO.mjs +265 -0
  39. package/dist/token-goat-chunk-CZ3LUXYZ.mjs +4115 -0
  40. package/dist/token-goat-chunk-DZX2YDPT.mjs +15 -0
  41. package/dist/token-goat-chunk-E3OQX2XT.mjs +824 -0
  42. package/dist/token-goat-chunk-EFHMMIGP.mjs +68 -0
  43. package/dist/token-goat-chunk-ETBHVDB6.mjs +328 -0
  44. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  45. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  46. package/dist/{token-goat-chunk-6Z5ULNE5.mjs → token-goat-chunk-FBNQNSJK.mjs} +2490 -4957
  47. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  48. package/dist/{token-goat-chunk-XI2VFAV6.mjs → token-goat-chunk-FZ3NEW5O.mjs} +33 -19
  49. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  50. package/dist/{token-goat-chunk-VE27HPIF.mjs → token-goat-chunk-GFBSN7BD.mjs} +30 -398
  51. package/dist/{token-goat-chunk-L45ZQRT7.mjs → token-goat-chunk-GOLEOXZP.mjs} +780 -786
  52. package/dist/token-goat-chunk-H2K3QP6H.mjs +24 -0
  53. package/dist/token-goat-chunk-H2PHHGM5.mjs +188 -0
  54. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  55. package/dist/token-goat-chunk-HG45AF2B.mjs +2228 -0
  56. package/dist/{token-goat-chunk-CBMY2FGI.mjs → token-goat-chunk-HOJLCGDP.mjs} +17113 -15554
  57. package/dist/{token-goat-chunk-HUDC5GS5.mjs → token-goat-chunk-HYBFA5X3.mjs} +120 -19
  58. package/dist/token-goat-chunk-IVALLT3S.mjs +48 -0
  59. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  60. package/dist/{token-goat-chunk-UBUKHVYW.mjs → token-goat-chunk-IVKIZWAB.mjs} +3 -3
  61. package/dist/{token-goat-chunk-4JMWPWCS.mjs → token-goat-chunk-JB6QN6VF.mjs} +6 -4
  62. package/dist/{token-goat-chunk-Q4S3UQGO.mjs → token-goat-chunk-JDHE26RP.mjs} +10 -3
  63. package/dist/{token-goat-chunk-7R2XYKC5.mjs → token-goat-chunk-JDU3EXSU.mjs} +14 -10
  64. package/dist/token-goat-chunk-JDWCRD6M.mjs +253 -0
  65. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-JN4XMLSD.mjs} +7 -4
  66. package/dist/token-goat-chunk-JTQQGXZH.mjs +733 -0
  67. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  68. package/dist/token-goat-chunk-KQNZDCBD.mjs +47 -0
  69. package/dist/{token-goat-chunk-4RN64ZND.mjs → token-goat-chunk-KWPNJBDH.mjs} +28 -3
  70. package/dist/token-goat-chunk-LOBGHXPB.mjs +242 -0
  71. package/dist/token-goat-chunk-MKPF4CL5.mjs +37 -0
  72. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  73. package/dist/{token-goat-chunk-YWSP6IU7.mjs → token-goat-chunk-N2NMER56.mjs} +25 -15
  74. package/dist/token-goat-chunk-NYKZLXMK.mjs +218 -0
  75. package/dist/token-goat-chunk-OJBNYTJP.mjs +3087 -0
  76. package/dist/token-goat-chunk-P4QMM4WK.mjs +295 -0
  77. package/dist/token-goat-chunk-PD5VKH46.mjs +184 -0
  78. package/dist/token-goat-chunk-PEPTHRFF.mjs +129 -0
  79. package/dist/{token-goat-chunk-VWZKZPSR.mjs → token-goat-chunk-PU7V3FD6.mjs} +8752 -11098
  80. package/dist/token-goat-chunk-PY533T7F.mjs +46 -0
  81. package/dist/token-goat-chunk-Q5VTGRH7.mjs +761 -0
  82. package/dist/{token-goat-chunk-IHKZ3QNA.mjs → token-goat-chunk-QCLDAQTS.mjs} +33 -19
  83. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-QSBRTGM2.mjs} +9 -2
  84. package/dist/{token-goat-chunk-4STDIGYC.mjs → token-goat-chunk-RC35RBUL.mjs} +7 -5
  85. package/dist/{token-goat-chunk-D5ICEPSB.mjs → token-goat-chunk-RHXKCZX3.mjs} +887 -507
  86. package/dist/{token-goat-chunk-RSS3TLXU.mjs → token-goat-chunk-RZRTDST7.mjs} +17 -7
  87. package/dist/{token-goat-chunk-MAMQPC43.mjs → token-goat-chunk-SJHWVNDQ.mjs} +15 -21
  88. package/dist/token-goat-chunk-SMVRN2HU.mjs +188 -0
  89. package/dist/{token-goat-chunk-EL7M26WP.mjs → token-goat-chunk-SQSSNQPE.mjs} +2100 -1442
  90. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-T4FK7VOV.mjs} +3 -3
  91. package/dist/token-goat-chunk-U4N3BN2W.mjs +92 -0
  92. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  93. package/dist/{token-goat-chunk-XKY4VKJ4.mjs → token-goat-chunk-UQ5UK2T7.mjs} +15 -4
  94. package/dist/token-goat-chunk-USILZ3T3.mjs +53 -0
  95. package/dist/token-goat-chunk-VES7EL7O.mjs +205 -0
  96. package/dist/{token-goat-chunk-M56BWPBN.mjs → token-goat-chunk-VL3YIFHZ.mjs} +550 -49
  97. package/dist/{token-goat-chunk-IZXKVT4A.mjs → token-goat-chunk-VPBBTSJR.mjs} +362 -128
  98. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-W3QCJS6G.mjs} +10 -2
  99. package/dist/{token-goat-chunk-FSTWAOW6.mjs → token-goat-chunk-WY3L4DVT.mjs} +11 -5
  100. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  101. package/dist/token-goat-chunk-XKI4SEMX.mjs +66 -0
  102. package/dist/token-goat-chunk-XU4P6Z24.mjs +133 -0
  103. package/dist/{token-goat-chunk-6CCQDAYY.mjs → token-goat-chunk-Y776AENC.mjs} +138 -33
  104. package/dist/token-goat-chunk-YARZFCZS.mjs +359 -0
  105. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  106. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-Z44YO3QZ.mjs} +12 -6
  107. package/dist/token-goat-chunk-Z57YODA2.mjs +35 -0
  108. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-ZCDTCVIS.mjs} +49 -30
  109. package/dist/token-goat-chunk-ZEJVMUQH.mjs +48 -0
  110. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  111. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  112. package/dist/{token-goat-chunk-SJEKA7Y2.mjs → token-goat-chunk-ZQSJMO2R.mjs} +381 -201
  113. package/dist/token-goat-hook-client.cjs +539 -0
  114. package/dist/token-goat-hook-client.mjs +26 -0
  115. package/dist/token-goat-hook.mjs +48 -28
  116. package/dist/token-goat.core.mjs +10 -45
  117. package/docs/C4_RUNTIME_ARCHITECTURE.md +3 -3
  118. package/docs/cli.md +82 -47
  119. package/docs/install.md +58 -23
  120. package/docs/security.md +7 -7
  121. package/package.json +17 -7
  122. package/scripts/verify-native-dist.mjs +386 -0
  123. package/dist/token-goat-chunk-4JJBFT7V.mjs +0 -20
  124. package/dist/token-goat-chunk-5NNYIUGV.mjs +0 -143
  125. package/dist/token-goat-chunk-6DQNNFJ6.mjs +0 -294
  126. package/dist/token-goat-chunk-7MAFDRVR.mjs +0 -47
  127. package/dist/token-goat-chunk-BCN2YQC6.mjs +0 -32
  128. package/dist/token-goat-chunk-D7GHQKQD.mjs +0 -30
  129. package/dist/token-goat-chunk-GMOUBOX4.mjs +0 -386
  130. package/dist/token-goat-chunk-IFORDBGC.mjs +0 -192
  131. package/dist/token-goat-chunk-JXK2HQXS.mjs +0 -318
  132. package/dist/token-goat-chunk-L7SDVGBT.mjs +0 -430
  133. package/dist/token-goat-chunk-MMLMALWK.mjs +0 -1381
  134. package/dist/token-goat-chunk-MVSWBNMD.mjs +0 -1985
@@ -0,0 +1,295 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ ANTIGRAVITY_TOOL_NAME_KEY,
5
+ BODY_FIRST_TOOL_RESPONSE_KEYS,
6
+ OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
7
+ VSCODE_TOOL_NAME_KEY,
8
+ antigravityNativeToolInput,
9
+ foldToolName,
10
+ replaceToolResponseField,
11
+ vscodeNativeToolInput
12
+ } from "./token-goat-chunk-VPBBTSJR.mjs";
13
+ import {
14
+ recordUnmappedTool
15
+ } from "./token-goat-chunk-3Z5S4KGM.mjs";
16
+ import {
17
+ registerReset
18
+ } from "./token-goat-chunk-YZAAZU2S.mjs";
19
+ import {
20
+ init_define_import_meta_env
21
+ } from "./token-goat-chunk-A37V4PBF.mjs";
22
+
23
+ // src/hook_registry.ts
24
+ init_define_import_meta_env();
25
+
26
+ // src/bridges/vscode_hooks.ts
27
+ init_define_import_meta_env();
28
+ import * as crypto from "node:crypto";
29
+ import * as fs from "node:fs";
30
+ import * as os from "node:os";
31
+ import * as path from "node:path";
32
+ function vscodeToolName(event) {
33
+ const name = event?.raw[VSCODE_TOOL_NAME_KEY];
34
+ return typeof name === "string" ? name : void 0;
35
+ }
36
+ var SHRINK_PREFIX = "token-goat-shrink-";
37
+ var MATERIALIZED_MAX_AGE_MS = 60 * 60 * 1e3;
38
+ var lastMaterializedSweepAtMs = 0;
39
+ function pruneMaterialized() {
40
+ const now = Date.now();
41
+ if (now - lastMaterializedSweepAtMs < MATERIALIZED_MAX_AGE_MS) return;
42
+ lastMaterializedSweepAtMs = now;
43
+ try {
44
+ const dir = os.tmpdir();
45
+ for (const file of fs.readdirSync(dir)) {
46
+ if (!file.startsWith(SHRINK_PREFIX)) continue;
47
+ const full = path.join(dir, file);
48
+ try {
49
+ const st = fs.statSync(full);
50
+ if (st.isFile() && now - st.mtimeMs > MATERIALIZED_MAX_AGE_MS) fs.unlinkSync(full);
51
+ } catch {
52
+ }
53
+ }
54
+ } catch {
55
+ }
56
+ }
57
+ function materializeShrunkImageFile(context) {
58
+ const idx = context.indexOf("data:image/");
59
+ if (idx === -1) return void 0;
60
+ const match = /^data:image\/([a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/.exec(context.slice(idx).trim());
61
+ if (!match) return void 0;
62
+ try {
63
+ pruneMaterialized();
64
+ const file = path.join(os.tmpdir(), `${SHRINK_PREFIX}${process.pid}-${Date.now()}-${crypto.randomUUID()}.${match[1]}`);
65
+ fs.writeFileSync(file, Buffer.from(match[2], "base64"), { mode: 384 });
66
+ return file;
67
+ } catch {
68
+ return void 0;
69
+ }
70
+ }
71
+ var NESTED_DECISION_EVENTS = /* @__PURE__ */ new Set(["stop", "subagent_stop"]);
72
+ function serializeVscodeOutput(output, eventName, hookEventName, event) {
73
+ switch (output.hookType) {
74
+ case "deny":
75
+ if (eventName === "pre_tool_use") {
76
+ return JSON.stringify({
77
+ hookSpecificOutput: { hookEventName, permissionDecision: "deny", permissionDecisionReason: output.message }
78
+ });
79
+ }
80
+ if (NESTED_DECISION_EVENTS.has(eventName)) {
81
+ return JSON.stringify({ hookSpecificOutput: { hookEventName, decision: "block", reason: output.message } });
82
+ }
83
+ return JSON.stringify({ decision: "block", reason: output.message });
84
+ case "context": {
85
+ if (NESTED_DECISION_EVENTS.has(eventName)) return "{}";
86
+ if (eventName === "pre_compact" || eventName === "notification") return JSON.stringify({ systemMessage: output.context });
87
+ if (eventName === "pre_tool_use" && output.context.includes("data:image/")) return "{}";
88
+ return JSON.stringify({ hookSpecificOutput: { hookEventName, additionalContext: output.context } });
89
+ }
90
+ case "rewriteInput": {
91
+ const tool = vscodeToolName(event);
92
+ const updatedInput = tool === void 0 ? output.updatedInput : vscodeNativeToolInput(tool, output.updatedInput);
93
+ return JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", updatedInput } });
94
+ }
95
+ case "rewriteOutput":
96
+ return "{}";
97
+ case "pass":
98
+ return "{}";
99
+ }
100
+ }
101
+
102
+ // src/bridges/antigravity_hooks.ts
103
+ init_define_import_meta_env();
104
+ function antigravityToolName(event) {
105
+ const name = event?.raw[ANTIGRAVITY_TOOL_NAME_KEY];
106
+ return typeof name === "string" ? name : void 0;
107
+ }
108
+ function serializeAntigravityOutput(output, eventName, event) {
109
+ if (eventName === "pre_tool_use") {
110
+ switch (output.hookType) {
111
+ case "deny":
112
+ return JSON.stringify({ decision: "deny", reason: output.message });
113
+ case "context":
114
+ if (output.context.includes("data:image/")) return "{}";
115
+ return JSON.stringify({ reason: output.context });
116
+ case "rewriteInput": {
117
+ const tool = antigravityToolName(event);
118
+ const overwrite = tool === void 0 ? output.updatedInput : antigravityNativeToolInput(tool, output.updatedInput);
119
+ return JSON.stringify({ overwrite });
120
+ }
121
+ default:
122
+ return "{}";
123
+ }
124
+ }
125
+ if (eventName === "post_tool_use" && output.hookType === "rewriteOutput" && typeof event?.raw["result"] === "string") {
126
+ return JSON.stringify({ overwriteResult: output.updatedOutput });
127
+ }
128
+ return "{}";
129
+ }
130
+
131
+ // src/hook_registry.ts
132
+ function sessionStateKey(event) {
133
+ return event.agentId !== void 0 ? `${event.sessionId}:agent:${event.agentId}` : event.sessionId;
134
+ }
135
+ var _handlers = /* @__PURE__ */ new Map();
136
+ function registerHook(eventName, handler, opts) {
137
+ let list = _handlers.get(eventName);
138
+ if (list === void 0) {
139
+ list = [];
140
+ _handlers.set(eventName, list);
141
+ }
142
+ list.push({
143
+ handler,
144
+ toolName: opts?.toolName,
145
+ toolPattern: opts?.toolPattern,
146
+ advisory: opts?.advisory === true,
147
+ followsMatcher: opts?.followsMatcher === true
148
+ });
149
+ }
150
+ function toolMatcherFor(eventName) {
151
+ const list = _handlers.get(eventName);
152
+ if (list === void 0 || list.length === 0) return null;
153
+ const parts = [];
154
+ for (const { toolName, toolPattern, followsMatcher } of list) {
155
+ if (followsMatcher) continue;
156
+ if (toolName === void 0 && toolPattern === void 0) return null;
157
+ for (const part of [toolName === void 0 ? void 0 : `^${toolName}$`, toolPattern]) {
158
+ if (part !== void 0 && part !== "" && !parts.includes(part)) parts.push(part);
159
+ }
160
+ }
161
+ if (parts.length === 0) return null;
162
+ return parts.join("|");
163
+ }
164
+ function noteUnrecognizedTool(event, list) {
165
+ const toolName = event.toolName;
166
+ if (typeof toolName !== "string" || toolName === "") return;
167
+ const named = [];
168
+ for (const { toolName: want, toolPattern } of list) {
169
+ if (toolPattern !== void 0) {
170
+ let matches = false;
171
+ try {
172
+ matches = new RegExp(toolPattern).test(toolName);
173
+ } catch {
174
+ }
175
+ if (matches) return;
176
+ }
177
+ if (want === void 0) continue;
178
+ if (want === toolName) return;
179
+ named.push(want);
180
+ }
181
+ if (named.length === 0) return;
182
+ const folded = foldToolName(toolName);
183
+ const nearMiss = named.find((n) => foldToolName(n) === folded) ?? null;
184
+ recordUnmappedTool(toolName, event.eventName, nearMiss);
185
+ }
186
+ async function runHook(event) {
187
+ const list = _handlers.get(event.eventName);
188
+ if (list === void 0) return { hookType: "pass" };
189
+ noteUnrecognizedTool(event, list);
190
+ let advisoryResult;
191
+ let noticeResult;
192
+ for (const { handler, toolName, advisory } of list) {
193
+ if (toolName !== void 0 && toolName !== event.toolName) continue;
194
+ let result;
195
+ try {
196
+ result = await handler(event);
197
+ } catch {
198
+ continue;
199
+ }
200
+ if (result.hookType !== "pass") {
201
+ if (advisory) {
202
+ advisoryResult = result;
203
+ continue;
204
+ }
205
+ return result;
206
+ }
207
+ if (result.notice !== void 0) noticeResult ??= result;
208
+ }
209
+ return advisoryResult ?? noticeResult ?? { hookType: "pass" };
210
+ }
211
+ function clearHooks() {
212
+ _handlers.clear();
213
+ }
214
+ registerReset(clearHooks);
215
+ var CLAUDE_CODE_EVENT_NAMES = {
216
+ pre_tool_use: "PreToolUse",
217
+ post_tool_use: "PostToolUse",
218
+ notification: "Notification",
219
+ stop: "Stop",
220
+ pre_compact: "PreCompact",
221
+ post_compact: "PostCompact",
222
+ user_prompt_submit: "UserPromptSubmit",
223
+ subagent_stop: "SubagentStop",
224
+ // Wired for Copilot CLI (`subagentStart`) and VS Code (`SubagentStart`) only; hooks_agent_spawn.ts's subagentStartHandler answers it with the spawn briefing as additionalContext, which both harnesses read.
225
+ subagent_start: "SubagentStart",
226
+ session_start: "SessionStart",
227
+ // Claude Code sends a failed tool call here rather than to PostToolUse, and its PostToolUseFailure output schema accepts hookSpecificOutput.additionalContext (captured and read from claude.exe 2.1.281); install.ts HOOK_EVENT_MAP registers it.
228
+ post_tool_use_failure: "PostToolUseFailure"
229
+ };
230
+ var EVENTS_WITHOUT_ADDITIONAL_CONTEXT = /* @__PURE__ */ new Set([
231
+ "notification",
232
+ "pre_compact"
233
+ ]);
234
+ var EVENTS_WITH_RAW_STDOUT_CONTEXT = /* @__PURE__ */ new Set(["pre_compact"]);
235
+ var BODY_FIRST_REWRITE_TOOLS = /* @__PURE__ */ new Set(["WebFetch", "Skill"]);
236
+ function shapedUpdatedToolOutput(updatedOutput, harness, event) {
237
+ if (harness !== "claudecode") return updatedOutput;
238
+ const resp = event?.raw["tool_response"];
239
+ if (resp === null || resp === void 0 || typeof resp !== "object") return updatedOutput;
240
+ const keys = BODY_FIRST_REWRITE_TOOLS.has(event?.toolName ?? "") ? BODY_FIRST_TOOL_RESPONSE_KEYS : OUTPUT_FIRST_TOOL_RESPONSE_KEYS;
241
+ return replaceToolResponseField(resp, keys, updatedOutput) ?? updatedOutput;
242
+ }
243
+ function serializeOutput(output, eventName, harness, event) {
244
+ if (harness === "vscode") return serializeVscodeOutput(output, eventName, CLAUDE_CODE_EVENT_NAMES[eventName], event);
245
+ if (harness === "antigravity") return serializeAntigravityOutput(output, eventName, event);
246
+ switch (output.hookType) {
247
+ case "deny":
248
+ return JSON.stringify({ decision: "block", reason: output.message });
249
+ case "context":
250
+ if (EVENTS_WITH_RAW_STDOUT_CONTEXT.has(eventName) && harness === "claudecode") {
251
+ return output.context;
252
+ }
253
+ if (EVENTS_WITHOUT_ADDITIONAL_CONTEXT.has(eventName)) {
254
+ return JSON.stringify({ systemMessage: output.context });
255
+ }
256
+ return JSON.stringify({
257
+ ...noticeField(output.notice, harness),
258
+ hookSpecificOutput: {
259
+ hookEventName: CLAUDE_CODE_EVENT_NAMES[eventName],
260
+ additionalContext: output.context
261
+ }
262
+ });
263
+ case "rewriteInput":
264
+ return JSON.stringify({
265
+ hookSpecificOutput: {
266
+ hookEventName: "PreToolUse",
267
+ permissionDecision: "allow",
268
+ updatedInput: output.updatedInput
269
+ }
270
+ });
271
+ case "rewriteOutput":
272
+ return JSON.stringify({
273
+ hookSpecificOutput: {
274
+ hookEventName: "PostToolUse",
275
+ // A block array is emitted only when the handler built one, and only for Claude Code: every other harness token-goat bridges to reads this field as a plain string into a text block of its own, so handing it an array there is the same mistake in the other direction. See HookOutput's `updatedBlocks` for the capture that proves Claude Code takes the array.
276
+ updatedToolOutput: output.updatedBlocks !== void 0 && harness === "claudecode" ? output.updatedBlocks : shapedUpdatedToolOutput(output.updatedOutput, harness, event),
277
+ ...output.context !== void 0 ? { additionalContext: output.context } : {}
278
+ }
279
+ });
280
+ case "pass":
281
+ return JSON.stringify(noticeField(output.notice, harness));
282
+ }
283
+ }
284
+ function noticeField(notice, harness) {
285
+ return notice !== void 0 && harness === "claudecode" ? { systemMessage: notice } : {};
286
+ }
287
+
288
+ export {
289
+ materializeShrunkImageFile,
290
+ sessionStateKey,
291
+ registerHook,
292
+ toolMatcherFor,
293
+ runHook,
294
+ serializeOutput
295
+ };
@@ -0,0 +1,184 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ DownloadCooldownError,
5
+ DownloadFailedError,
6
+ activeDownloadCooldown,
7
+ clearDownloadFailure,
8
+ describeCause,
9
+ isExplicitDownload,
10
+ recordDownloadFailure
11
+ } from "./token-goat-chunk-SMVRN2HU.mjs";
12
+ import {
13
+ loadConfig
14
+ } from "./token-goat-chunk-7IN2MKDS.mjs";
15
+ import {
16
+ init_define_import_meta_env
17
+ } from "./token-goat-chunk-A37V4PBF.mjs";
18
+
19
+ // src/pinned_fetch.ts
20
+ init_define_import_meta_env();
21
+ import { createHash } from "node:crypto";
22
+ import * as fs from "node:fs";
23
+ import * as path from "node:path";
24
+ import { pipeline } from "node:stream/promises";
25
+ var ATTEMPTS = 3;
26
+ var retryDelayMs = 250;
27
+ function setPinnedRetryDelayForTesting(ms) {
28
+ retryDelayMs = ms ?? 250;
29
+ }
30
+ var DETERMINISTIC_CODE = /^(?:ENOTFOUND|EAI_NONAME|ERR_INVALID_URL|ERR_TLS_|ERR_SSL_|CERT_|DEPTH_ZERO_SELF_SIGNED_CERT$|SELF_SIGNED_CERT_IN_CHAIN$|UNABLE_TO_)/;
31
+ function causeCodes(e) {
32
+ const codes = [];
33
+ let cursor = e;
34
+ for (let depth = 0; cursor !== null && typeof cursor === "object" && depth < 5; depth++) {
35
+ const code = cursor.code;
36
+ if (typeof code === "string") codes.push(code);
37
+ cursor = cursor.cause;
38
+ }
39
+ return codes;
40
+ }
41
+ function transient(e) {
42
+ if (e instanceof TypeError) return !causeCodes(e).some((code) => DETERMINISTIC_CODE.test(code)) && !/ENOTFOUND/.test(describeCause(e));
43
+ return e instanceof Error && (e.name === "TimeoutError" || e.name === "AbortError");
44
+ }
45
+ var HostFailure = class extends Error {
46
+ retry;
47
+ constructor(message, retry, cause) {
48
+ super(message, cause === void 0 ? void 0 : { cause });
49
+ this.retry = retry;
50
+ }
51
+ };
52
+ function failure(url, message, cause, startedAt) {
53
+ let at = Date.now();
54
+ try {
55
+ at = recordDownloadFailure(url, message, at, startedAt).at;
56
+ } catch {
57
+ }
58
+ return new DownloadFailedError(message, url, at, cause);
59
+ }
60
+ function forgetFailure(url) {
61
+ try {
62
+ clearDownloadFailure(url);
63
+ } catch {
64
+ }
65
+ }
66
+ async function fetchOk(url) {
67
+ let response;
68
+ try {
69
+ response = await fetch(url, { redirect: "follow" });
70
+ } catch (e) {
71
+ throw new HostFailure(`GET ${url} failed: ${describeCause(e)}`, transient(e), e);
72
+ }
73
+ if (response.ok) return response;
74
+ await response.body?.cancel().catch(() => void 0);
75
+ throw new HostFailure(`GET ${url} returned ${response.status} ${response.statusText}`, response.status >= 500 || response.status === 429);
76
+ }
77
+ async function* bodyChunks(url, body, expected) {
78
+ let received = 0;
79
+ try {
80
+ for await (const chunk of body) {
81
+ received += chunk.byteLength;
82
+ yield chunk;
83
+ }
84
+ } catch (e) {
85
+ throw new HostFailure(`GET ${url} broke off after ${received} of ${expected} bytes: ${describeCause(e)}`, transient(e), e);
86
+ }
87
+ }
88
+ function sha256Of(filePath) {
89
+ return new Promise((resolve, reject) => {
90
+ const hash = createHash("sha256");
91
+ const stream = fs.createReadStream(filePath);
92
+ stream.on("error", reject);
93
+ stream.on("data", (chunk) => hash.update(chunk));
94
+ stream.on("end", () => resolve(hash.digest("hex")));
95
+ });
96
+ }
97
+ async function copyFromSharedCache(shared, file, target) {
98
+ const source = path.join(shared, file.name);
99
+ const temp = `${target}.${process.pid}.shared`;
100
+ try {
101
+ const info = fs.lstatSync(source, { throwIfNoEntry: false });
102
+ if (!info?.isFile() || info.size !== file.bytes) return false;
103
+ fs.copyFileSync(source, temp);
104
+ if (await sha256Of(temp) !== file.sha256) {
105
+ fs.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
106
+ fs.rmSync(source, { force: true, maxRetries: 20, retryDelay: 25 });
107
+ return false;
108
+ }
109
+ fs.renameSync(temp, target);
110
+ return true;
111
+ } catch {
112
+ try {
113
+ fs.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
114
+ } catch {
115
+ }
116
+ return false;
117
+ }
118
+ }
119
+ async function downloadPinned(url, file, target) {
120
+ if (loadConfig().network.offline) throw new Error(`Offline mode is on (network.offline): refusing to download ${url}`);
121
+ if (!isExplicitDownload()) {
122
+ const cooldown = activeDownloadCooldown(url);
123
+ if (cooldown) throw new DownloadCooldownError(url, cooldown);
124
+ }
125
+ const startedAt = Date.now();
126
+ for (let attempt = 1; ; attempt++) {
127
+ try {
128
+ await fetchAndPlace(url, file, target);
129
+ forgetFailure(url);
130
+ return;
131
+ } catch (e) {
132
+ if (!(e instanceof HostFailure)) throw e;
133
+ if (attempt < ATTEMPTS && e.retry) {
134
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs * attempt));
135
+ continue;
136
+ }
137
+ throw failure(url, e.message, e.cause, startedAt);
138
+ }
139
+ }
140
+ }
141
+ async function fetchAndPlace(url, file, target) {
142
+ const response = await fetchOk(url);
143
+ const body = response.body;
144
+ if (!body) throw new Error(`GET ${url} returned no body`);
145
+ const temp = `${target}.${process.pid}.partial`;
146
+ const hash = createHash("sha256");
147
+ let written = 0;
148
+ const out = fs.createWriteStream(temp);
149
+ try {
150
+ await pipeline(async function* () {
151
+ for await (const chunk of bodyChunks(url, body, file.bytes)) {
152
+ written += chunk.byteLength;
153
+ if (written > file.bytes) throw new Error(`${file.name} is longer than the pinned ${file.bytes} bytes`);
154
+ hash.update(chunk);
155
+ yield chunk;
156
+ }
157
+ }, out);
158
+ if (written !== file.bytes) {
159
+ throw new Error(`${file.name} is ${written} bytes, expected the pinned ${file.bytes}`);
160
+ }
161
+ const digest = hash.digest("hex");
162
+ if (digest !== file.sha256) {
163
+ throw new Error(`${file.name} has sha256 ${digest}, expected the pinned ${file.sha256}`);
164
+ }
165
+ fs.renameSync(temp, target);
166
+ } catch (e) {
167
+ await new Promise((resolve) => {
168
+ if (out.closed) resolve();
169
+ else out.once("close", () => resolve());
170
+ });
171
+ try {
172
+ fs.rmSync(temp, { force: true, maxRetries: 20, retryDelay: 25 });
173
+ } catch {
174
+ }
175
+ throw e;
176
+ }
177
+ }
178
+
179
+ export {
180
+ setPinnedRetryDelayForTesting,
181
+ sha256Of,
182
+ copyFromSharedCache,
183
+ downloadPinned
184
+ };
@@ -0,0 +1,129 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ DELIVERS_CONTENT_RE
5
+ } from "./token-goat-chunk-MNWKPRAL.mjs";
6
+ import {
7
+ splitShellSegments,
8
+ stripLeadingAssignments
9
+ } from "./token-goat-chunk-APGZXSPS.mjs";
10
+ import {
11
+ safeSlice
12
+ } from "./token-goat-chunk-GOLEOXZP.mjs";
13
+ import {
14
+ init_define_import_meta_env
15
+ } from "./token-goat-chunk-A37V4PBF.mjs";
16
+
17
+ // src/tool_error_class.ts
18
+ init_define_import_meta_env();
19
+ var UNKNOWN_REASON = "unclassified";
20
+ var DENIAL_KIND_REASONS = {
21
+ "permission-rule": "hook_deny",
22
+ // 73 in the census: the user declined an approval prompt.
23
+ "user-rejected": "user_rejected",
24
+ // 1 in the census; kept because it is an enumerated harness value, not a text guess.
25
+ "automode-blocked": "auto_mode_blocked"
26
+ };
27
+ var TG_DENY_RE = /\[tg\]|token-goat/;
28
+ var CONTENT_DELIVERED_REASON = "tg_content_delivered";
29
+ function tgDenyReason(text) {
30
+ return DELIVERS_CONTENT_RE.test(text) ? CONTENT_DELIVERED_REASON : "tg_deny";
31
+ }
32
+ var HOOK_DENY_TEXT_RE = /^PreToolUse:\S+ hook error: /;
33
+ var TEST_OR_BUILD_COMMAND_RE = /^(?:npm\s+(?:test|run\s+(?:test|build|lint|typecheck))|npx\s+(?:vitest|tsc|eslint|jest|playwright)|vitest|jest|pytest|tsc|eslint|cargo\s+(?:test|build|check|clippy)|go\s+(?:test|build|vet)|make|gradle|mvn|dotnet\s+(?:test|build)|ruff|mypy|python3?\s+-m\s+(?:pytest|unittest))\b/;
34
+ var SEARCH_COMMAND_RE = /^(?:grep|egrep|fgrep|rg|findstr)\b/;
35
+ function runsCommand(command, head) {
36
+ return splitShellSegments(command).some((segment) => head.test(stripLeadingAssignments(segment)));
37
+ }
38
+ var EXPECTED_PATTERNS = [
39
+ // 176: the Bash tool's own timeout, reported as SIGTERM's 143 plus this line.
40
+ { reason: "command_timeout", tools: ["Bash"], re: /^Exit code \d+\s+Command timed out after / },
41
+ // 289: exit 1 with no output from a search command, which is how grep and rg report zero hits.
42
+ { reason: "search_no_match", tools: ["Bash"], re: /^Exit code 1\s*$/, command: SEARCH_COMMAND_RE },
43
+ // 252: a test, build, lint or typecheck run reporting failures, which is the tool doing its job.
44
+ { reason: "test_or_build_failed", tools: ["Bash"], re: /^Exit code \d+/, command: TEST_OR_BUILD_COMMAND_RE },
45
+ // 302: an unbalanced quote or bracket in the command itself.
46
+ { reason: "shell_syntax_error", tools: ["Bash"], re: /unexpected EOF while looking for matching|syntax error near unexpected token/ },
47
+ // 29: a binary missing from PATH.
48
+ { reason: "command_not_found", tools: ["Bash"], re: /command not found/ },
49
+ // 272: the harness refusing a bare or leading `sleep` and pointing at Monitor instead.
50
+ { reason: "sleep_blocked", tools: ["Bash"], re: /^Blocked: (?:sleep \d+ followed by|standalone sleep)/ },
51
+ // 114: old_string absent from the file.
52
+ { reason: "edit_string_not_found", tools: ["Edit", "MultiEdit"], re: /^String to replace not found in file/ },
53
+ // 37: old_string present more than once with replace_all false.
54
+ { reason: "edit_multiple_matches", tools: ["Edit", "MultiEdit"], re: /^Found \d+ matches of the string to replace/ },
55
+ // 37: the harness's read-before-write guard.
56
+ { reason: "file_not_read_yet", tools: ["Edit", "MultiEdit", "Write"], re: /^File has not been read yet/ },
57
+ // 16: the file changed on disk after the last read.
58
+ { reason: "file_modified_since_read", tools: ["Edit", "MultiEdit", "Write"], re: /^File has been modified since read/ },
59
+ // 643 (578 Bash, 53 Read, 11 Grep, 1 Edit): a path that does not exist, in each tool's own wording.
60
+ { reason: "path_not_found", re: /No such file or directory|^File does not exist\.|^Path does not exist:/ },
61
+ // 1,171: an interpreter raising: a Python traceback header, the `Node.js vN.N.N` line Node prints under every uncaught error, or a named error line (`SyntaxError: ...`). After path_not_found, so a missing file stays a missing file whichever language reported it.
62
+ { reason: "script_exception", tools: ["Bash"], re: /^(?:Traceback \(most recent call last\):|Node\.js v\d+\.\d+\.\d+\b|[A-Z]\w*(?:Error|Exception)(?: \[\w+\])?: )/m },
63
+ // 14: a Read over the harness's size ceiling.
64
+ { reason: "file_too_large", tools: ["Read"], re: /^File content \([^)]*\) exceeds maximum allowed/ },
65
+ // 85: arguments the tool's schema rejected before it ran.
66
+ { reason: "input_validation", re: /^InputValidationError/ },
67
+ // 68: a StructuredOutput call that did not match the requested schema.
68
+ { reason: "schema_mismatch", tools: ["StructuredOutput"], re: /^Output does not match required schema/ },
69
+ // 35: the harness's concurrent-subagent ceiling.
70
+ { reason: "subagent_limit", tools: ["Agent", "Task"], re: /^Concurrent subagent limit reached/ },
71
+ // 37: a tool disabled for this session or a misspelled tool name.
72
+ { reason: "tool_unavailable", re: /^Error: No such tool available/ }
73
+ ];
74
+ var EXPECTED_REASONS = [
75
+ "interrupted",
76
+ "tg_deny",
77
+ CONTENT_DELIVERED_REASON,
78
+ ...new Set(Object.values(DENIAL_KIND_REASONS)),
79
+ ...EXPECTED_PATTERNS.map((p) => p.reason)
80
+ ];
81
+ var TOOL_USE_ERROR_OPEN = "<tool_use_error>";
82
+ var TOOL_USE_ERROR_CLOSE = "</tool_use_error>";
83
+ function unwrapToolError(errorText) {
84
+ let text = errorText.trim();
85
+ if (text.startsWith(TOOL_USE_ERROR_OPEN)) text = text.slice(TOOL_USE_ERROR_OPEN.length);
86
+ if (text.endsWith(TOOL_USE_ERROR_CLOSE)) text = text.slice(0, text.length - TOOL_USE_ERROR_CLOSE.length);
87
+ return text.trim();
88
+ }
89
+ function expected(reason) {
90
+ return { kind: "expected", reason };
91
+ }
92
+ function classifyToolError(tool, errorText, flags = {}) {
93
+ if (flags.isInterrupt === true) return expected("interrupted");
94
+ const text = unwrapToolError(errorText);
95
+ const denial = flags.denialKind;
96
+ if (denial !== void 0 && denial !== "") {
97
+ const reason = DENIAL_KIND_REASONS[denial] ?? "hook_deny";
98
+ return expected(reason === "hook_deny" && TG_DENY_RE.test(text) ? tgDenyReason(text) : reason);
99
+ }
100
+ if (HOOK_DENY_TEXT_RE.test(text)) return expected(TG_DENY_RE.test(text) ? tgDenyReason(text) : "hook_deny");
101
+ for (const p of EXPECTED_PATTERNS) {
102
+ if (p.tools !== void 0 && (tool === void 0 || !p.tools.includes(tool))) continue;
103
+ if (!p.re.test(text)) continue;
104
+ if (p.command !== void 0 && (flags.command === void 0 || !runsCommand(flags.command, p.command))) continue;
105
+ return expected(p.reason);
106
+ }
107
+ return { kind: "unknown", reason: UNKNOWN_REASON };
108
+ }
109
+ var ERROR_PREFIX_CHARS = 60;
110
+ var EXIT_CODE_HEADER_RE = /^Exit code (\d+)\s*/;
111
+ function errorPrefix(errorText) {
112
+ let text = unwrapToolError(errorText);
113
+ let lead = "";
114
+ const exit = EXIT_CODE_HEADER_RE.exec(text);
115
+ if (exit !== null) {
116
+ lead = `exit ${exit[1] ?? ""}: `;
117
+ text = text.slice(exit[0].length);
118
+ }
119
+ const line = text.split("\n").find((l) => l.trim() !== "") ?? "";
120
+ const masked = line.trim().replace(/\b[A-Za-z]:[\\/]\S*|~?\/[\w.~-]+(?:\/[\w.~-]*)+/g, "<path>").replace(/'[^'\n]*'|"[^"\n]*"|`[^`\n]*`/g, "<q>").replace(/\d+/g, "N");
121
+ return safeSlice(`${lead}${masked === "" ? "(empty)" : masked}`, ERROR_PREFIX_CHARS);
122
+ }
123
+
124
+ export {
125
+ CONTENT_DELIVERED_REASON,
126
+ SEARCH_COMMAND_RE,
127
+ classifyToolError,
128
+ errorPrefix
129
+ };