token-goat 2.6.34 → 2.6.35

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 (24) hide show
  1. package/SECURITY.md +11 -10
  2. package/dist/{token-goat-chunk-IYYQOPY4.mjs → token-goat-chunk-D5IZEGN2.mjs} +18 -4
  3. package/dist/{token-goat-chunk-WA2ER6TZ.mjs → token-goat-chunk-DQIT5JIF.mjs} +1 -1
  4. package/dist/{token-goat-chunk-L7QLEVO7.mjs → token-goat-chunk-DRAIYVUI.mjs} +16 -14
  5. package/dist/{token-goat-chunk-GXBPEQR2.mjs → token-goat-chunk-HW4VUKJ5.mjs} +14 -8
  6. package/dist/{token-goat-chunk-CN7GUPX6.mjs → token-goat-chunk-I2KCEGIP.mjs} +378 -54
  7. package/dist/{token-goat-chunk-7FWBSPCT.mjs → token-goat-chunk-K7W3P2TJ.mjs} +139 -6
  8. package/dist/{token-goat-chunk-OA3GFKP2.mjs → token-goat-chunk-SIHYQCTM.mjs} +2 -2
  9. package/dist/{token-goat-chunk-I6EQH27G.mjs → token-goat-chunk-UIZVX3HN.mjs} +2 -2
  10. package/dist/{token-goat-chunk-FRMEOIRU.mjs → token-goat-chunk-Y2NH6DGZ.mjs} +208 -13
  11. package/dist/{token-goat-chunk-CKRATWCJ.mjs → token-goat-chunk-YF67EWRH.mjs} +5 -5
  12. package/dist/{token-goat-hook-chunk-CNLMPHXT.mjs → token-goat-hook-chunk-2O7P4Z6Q.mjs} +139 -6
  13. package/dist/{token-goat-hook-chunk-I5VM5PO5.mjs → token-goat-hook-chunk-3AAH72SO.mjs} +14 -8
  14. package/dist/{token-goat-hook-chunk-BU5OFDGQ.mjs → token-goat-hook-chunk-4POU6OHK.mjs} +208 -13
  15. package/dist/{token-goat-hook-chunk-6C5RN3CM.mjs → token-goat-hook-chunk-CRBMPT74.mjs} +2 -2
  16. package/dist/{token-goat-hook-chunk-QTZ6YUMQ.mjs → token-goat-hook-chunk-D6UJEFHX.mjs} +2 -2
  17. package/dist/{token-goat-hook-chunk-ATEGFQAU.mjs → token-goat-hook-chunk-J4HKWUWZ.mjs} +5 -5
  18. package/dist/{token-goat-hook-chunk-2ISZ4AZR.mjs → token-goat-hook-chunk-NIPXIAPA.mjs} +1 -1
  19. package/dist/{token-goat-hook-chunk-KGLMNOGD.mjs → token-goat-hook-chunk-NXVT4F3S.mjs} +18 -4
  20. package/dist/{token-goat-hook-chunk-OQML5EMA.mjs → token-goat-hook-chunk-VU6VGZBM.mjs} +16 -14
  21. package/dist/{token-goat-hook-chunk-6QTWMSRO.mjs → token-goat-hook-chunk-XM4W3WCO.mjs} +378 -54
  22. package/dist/token-goat-hook.mjs +5 -5
  23. package/dist/token-goat.core.mjs +5 -5
  24. package/package.json +4 -3
@@ -8,7 +8,7 @@ import {
8
8
  import { createRequire } from "node:module";
9
9
  function resolveVersion() {
10
10
  if (true) {
11
- return "2.6.34";
11
+ return "2.6.35";
12
12
  }
13
13
  const require2 = createRequire(import.meta.url);
14
14
  const pkg = require2("../package.json");
@@ -1183,6 +1183,9 @@ function getDisplayRoot(explicitRoot) {
1183
1183
  _displayRootCache = { cwd, root };
1184
1184
  return root;
1185
1185
  }
1186
+ registerReset(() => {
1187
+ _displayRootCache = null;
1188
+ });
1186
1189
  function isUnderSystemTemp(filePath) {
1187
1190
  let sysTemp;
1188
1191
  try {
@@ -2495,7 +2498,7 @@ function getLastProjectConfigParseError() {
2495
2498
  return _lastProjectConfigParseError;
2496
2499
  }
2497
2500
  var PROJECT_LOCKED_SECTIONS = ["injection", "webfetch", "gdrive", "mcp", "network"];
2498
- var PROJECT_LOCKED_KEYS = ["indexing.cross_project_symbols"];
2501
+ var PROJECT_LOCKED_KEYS = ["indexing.cross_project_symbols", "worker.blocked_roots"];
2499
2502
  var _lastProjectConfigLockedKeys = [];
2500
2503
  function stripLockedProjectKeys(projectRaw) {
2501
2504
  const cleaned = {};
@@ -2667,6 +2670,9 @@ function resolveConfigProjectRoot() {
2667
2670
  _projectRootCache = { cwd, root };
2668
2671
  return root;
2669
2672
  }
2673
+ registerReset(() => {
2674
+ _projectRootCache = null;
2675
+ });
2670
2676
  function isAutoTriggerMultiplierExplicit() {
2671
2677
  const setsMultiplier = (text) => {
2672
2678
  const raw = parse(text);
@@ -4158,7 +4164,8 @@ function propagateEndLinesToSymbols(symbols, sections) {
4158
4164
  return sym;
4159
4165
  });
4160
4166
  }
4161
- function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex, lineCommentPrefix) {
4167
+ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex, lineCommentPrefix, opts) {
4168
+ const block = opts?.blockComment;
4162
4169
  let depth = 0;
4163
4170
  let quote = null;
4164
4171
  for (let i = openBraceIndex; i < content.length; i++) {
@@ -4171,6 +4178,11 @@ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex
4171
4178
  if (ch === quote) quote = null;
4172
4179
  continue;
4173
4180
  }
4181
+ if (block !== void 0 && content.startsWith(block[0], i)) {
4182
+ const close = content.indexOf(block[1], i + block[0].length);
4183
+ i = close === -1 ? content.length : close + block[1].length - 1;
4184
+ continue;
4185
+ }
4174
4186
  if (lineCommentPrefix !== void 0 && content.startsWith(lineCommentPrefix, i)) {
4175
4187
  while (i < content.length && content[i] !== "\n") i++;
4176
4188
  continue;
@@ -4187,7 +4199,106 @@ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex
4187
4199
  }
4188
4200
  }
4189
4201
  }
4190
- return totalLines;
4202
+ return opts?.noMatchValue ?? totalLines;
4203
+ }
4204
+ function assignBraceBlockSpans(symbols, content, lineCommentPrefix) {
4205
+ if (symbols.length === 0) return [...symbols];
4206
+ const lines = content.split("\n");
4207
+ const totalLines = lines.length;
4208
+ const lineIndex = buildLineIndex(content);
4209
+ const starts = [...new Set(symbols.map((s) => s.lineStart))].sort((a, b) => a - b);
4210
+ const blockComment = lineCommentPrefix === "//" ? ["/*", "*/"] : lineCommentPrefix === "#" ? ["<#", "#>"] : void 0;
4211
+ return symbols.map((sym) => {
4212
+ if (sym.lineEnd !== sym.lineStart) return sym;
4213
+ const nextStart = starts.find((s) => s > sym.lineStart);
4214
+ const lastSearchLine = Math.min(nextStart !== void 0 ? nextStart - 1 : totalLines, sym.lineStart + BRACE_SEARCH_MAX_LINES);
4215
+ const openIndex = findBlockOpenBrace(content, lineIndex, sym.lineStart, lastSearchLine, lineCommentPrefix, blockComment);
4216
+ if (openIndex === null) return sym;
4217
+ const endLine = findMatchingBraceEndLine(
4218
+ content,
4219
+ openIndex,
4220
+ totalLines,
4221
+ lineIndex,
4222
+ lineCommentPrefix,
4223
+ blockComment === void 0 ? { noMatchValue: -1 } : { blockComment, noMatchValue: -1 }
4224
+ );
4225
+ if (endLine <= sym.lineStart) return sym;
4226
+ return { ...sym, lineEnd: endLine, body: lines.slice(sym.lineStart - 1, endLine).join("\n") };
4227
+ });
4228
+ }
4229
+ var BRACE_SEARCH_MAX_LINES = 10;
4230
+ function findBlockOpenBrace(content, lineIndex, startLine, lastSearchLine, lineCommentPrefix, blockComment) {
4231
+ const from = lineIndex[startLine - 1];
4232
+ if (from === void 0) return null;
4233
+ const to = lineIndex[lastSearchLine] ?? content.length;
4234
+ let quote = null;
4235
+ let parenDepth = 0;
4236
+ let linesSeen = 0;
4237
+ let atLineStart = false;
4238
+ for (let i = from; i < to; i++) {
4239
+ const ch = content[i];
4240
+ if (ch === void 0) break;
4241
+ if (quote !== null) {
4242
+ if (ch === "\\") {
4243
+ i++;
4244
+ continue;
4245
+ }
4246
+ if (ch === quote) quote = null;
4247
+ continue;
4248
+ }
4249
+ if (ch === "\n") {
4250
+ linesSeen++;
4251
+ atLineStart = true;
4252
+ continue;
4253
+ }
4254
+ if (blockComment !== void 0 && content.startsWith(blockComment[0], i)) {
4255
+ const close = content.indexOf(blockComment[1], i + blockComment[0].length);
4256
+ if (close === -1) return null;
4257
+ i = close + blockComment[1].length - 1;
4258
+ continue;
4259
+ }
4260
+ if (lineCommentPrefix !== void 0 && content.startsWith(lineCommentPrefix, i)) {
4261
+ while (i + 1 < to && content[i + 1] !== "\n") i++;
4262
+ continue;
4263
+ }
4264
+ if (atLineStart && !/\s/.test(ch)) {
4265
+ atLineStart = false;
4266
+ if (parenDepth === 0 && linesSeen >= 1 && startsWithBlockKeyword(content, i, to)) return null;
4267
+ }
4268
+ if (ch === '"' || ch === "'") {
4269
+ quote = ch;
4270
+ continue;
4271
+ }
4272
+ if (ch === "(" || ch === "[") parenDepth++;
4273
+ else if (ch === ")" || ch === "]") {
4274
+ if (parenDepth > 0) parenDepth--;
4275
+ } else if (ch === ";") return null;
4276
+ else if (ch === "{") return i;
4277
+ }
4278
+ return null;
4279
+ }
4280
+ var BLOCK_OPENING_KEYWORDS = /* @__PURE__ */ new Set([
4281
+ "if",
4282
+ "for",
4283
+ "while",
4284
+ "do",
4285
+ "switch",
4286
+ "when",
4287
+ "match",
4288
+ "try",
4289
+ "foreach",
4290
+ "loop",
4291
+ "guard",
4292
+ "repeat",
4293
+ "unless",
4294
+ "until"
4295
+ ]);
4296
+ function startsWithBlockKeyword(content, i, to) {
4297
+ const first = content[i];
4298
+ if (first === void 0 || !/[A-Za-z_]/.test(first)) return false;
4299
+ let j = i + 1;
4300
+ while (j < to && /[A-Za-z0-9_]/.test(content[j])) j++;
4301
+ return BLOCK_OPENING_KEYWORDS.has(content.slice(i, j));
4191
4302
  }
4192
4303
 
4193
4304
  // src/languages/ini_idx.ts
@@ -5970,7 +6081,13 @@ var SECRET_PATTERNS = [
5970
6081
  // directly against the header name and the scheme directly against the space, so a body like
5971
6082
  // {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in
5972
6083
  // -- matched nothing and the token was cached verbatim.
5973
- ["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Bearer[ \t])[A-Za-z0-9\-._~+/]{10,}=*/gi],
6084
+ // `token` is the second scheme spelling in wide use -- it is what curl and gh examples pass for
6085
+ // GitHub and many other APIs -- and an opaque value behind it carries exactly the same authority
6086
+ // as one behind `Bearer`. The trailing gap is `{1,8}` rather than a single space for the same
6087
+ // reason every other gap in this lookbehind already is: a hand-aligned or reformatted header
6088
+ // ("Authorization: Bearer <token>") is ordinary, and demanding exactly one space there made
6089
+ // this the one position in the pattern that a second space defeated.
6090
+ ["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}(?:Bearer|token)[ \t]{1,8})[A-Za-z0-9\-._~+/]{10,}=*/gi],
5974
6091
  ["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t])[A-Za-z0-9+/]{6,}=*/gi],
5975
6092
  // JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest
5976
6093
  // realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
@@ -6024,7 +6141,22 @@ var SECRET_PATTERNS = [
6024
6141
  // SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches
6025
6142
  // identifier characters only, so prose that merely mentions a keyword still never reaches
6026
6143
  // a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
6027
- ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token)[a-z0-9_-]{0,64}["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)(?:\\[^\n]|[^\s\\&;#'"[\],{}:]){4,}/gi]
6144
+ // `& ; # , :` play two incompatible roles. They separate one field from the next (a query
6145
+ // string, a cookie header, an inline env list), and they are also perfectly ordinary password
6146
+ // characters. Rejecting them outright got the first role right and the second badly wrong: the
6147
+ // match stopped at the first one and left everything after it in plain text, so
6148
+ // `password=corr&horse&battery` redacted four characters and printed the rest, and
6149
+ // `DB_PASSWORD=Aa1:xyz` matched nothing at all because the run before the `:` was under the
6150
+ // four-character floor. A tail left sitting in the open is the outcome this module's header
6151
+ // calls worse than no redaction, because it reads as handled.
6152
+ //
6153
+ // So the separator role is decided by what follows rather than assumed: one of these characters
6154
+ // ends the value only when the next thing along is another `name=` / `name:` pair, which is what
6155
+ // an actual field separator is always followed by. `,OTHER=public` and `; other=1` still end it;
6156
+ // the `&` in the middle of a passphrase does not. Whitespace, quotes and brackets are unchanged
6157
+ // -- they end a value unconditionally, which is also what keeps this pattern from re-matching
6158
+ // the `[REDACTED:...]` placeholder it just wrote.
6159
+ ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token)[a-z0-9_-]{0,64}["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)(?:\\[^\n]|[^\s\\&;#,:'"[\]{}]|[&;#,:](?![ \t]*[A-Za-z_][A-Za-z0-9_.-]*[ \t]*[:=])){4,}/gi]
6028
6160
  ];
6029
6161
  function redactSecrets(text) {
6030
6162
  let count = 0;
@@ -6221,6 +6353,7 @@ export {
6221
6353
  assignFlatEndLines,
6222
6354
  propagateEndLinesToSymbols,
6223
6355
  findMatchingBraceEndLine,
6356
+ assignBraceBlockSpans,
6224
6357
  extractIni,
6225
6358
  _lineClosesQuote,
6226
6359
  _detectOpenQuote,
@@ -84,7 +84,7 @@ import {
84
84
  runZipRead,
85
85
  symbolNamesInFile,
86
86
  upsertNote
87
- } from "./token-goat-hook-chunk-KGLMNOGD.mjs";
87
+ } from "./token-goat-hook-chunk-NXVT4F3S.mjs";
88
88
  import {
89
89
  BASH_OUTPUT_SUBDIR,
90
90
  GEMINI_TOOL_NAME_MAP,
@@ -105,7 +105,7 @@ import {
105
105
  readStdinJson,
106
106
  searchRecall,
107
107
  storeWebOutput
108
- } from "./token-goat-hook-chunk-6C5RN3CM.mjs";
108
+ } from "./token-goat-hook-chunk-CRBMPT74.mjs";
109
109
  import {
110
110
  AGENT_SALT_MARKER,
111
111
  CONTEXT_AUTOCOMPACT_TOKENS,
@@ -243,7 +243,7 @@ import {
243
243
  vscodeDecoderConfigured,
244
244
  walkProject,
245
245
  writeCompact
246
- } from "./token-goat-hook-chunk-6QTWMSRO.mjs";
246
+ } from "./token-goat-hook-chunk-XM4W3WCO.mjs";
247
247
  import {
248
248
  C,
249
249
  CONFIG_KEY_ENV_OVERRIDES,
@@ -322,7 +322,7 @@ import {
322
322
  withFileLock,
323
323
  withRetryOnLock,
324
324
  writeJsonSettings
325
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
325
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
326
326
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
327
327
  import {
328
328
  __export
@@ -13447,7 +13447,7 @@ async function cmdMcpServe() {
13447
13447
  let StdioServerTransport;
13448
13448
  try {
13449
13449
  ;
13450
- ({ createMcpServer } = await import("./token-goat-hook-chunk-OQML5EMA.mjs"));
13450
+ ({ createMcpServer } = await import("./token-goat-hook-chunk-VU6VGZBM.mjs"));
13451
13451
  ({ StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"));
13452
13452
  } catch (err2) {
13453
13453
  process.stderr.write(
@@ -13468,7 +13468,7 @@ async function cmdHook(event, opts) {
13468
13468
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
13469
13469
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
13470
13470
  }
13471
- const { relay } = await import("./token-goat-hook-chunk-ATEGFQAU.mjs");
13471
+ const { relay } = await import("./token-goat-hook-chunk-J4HKWUWZ.mjs");
13472
13472
  await relay(event);
13473
13473
  }
13474
13474
  async function cmdInstall(opts) {
@@ -14325,7 +14325,7 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
14325
14325
  }
14326
14326
  async function cmdCompress(opts) {
14327
14327
  try {
14328
- const bashRunner = await import("./token-goat-hook-chunk-QTZ6YUMQ.mjs");
14328
+ const bashRunner = await import("./token-goat-hook-chunk-D6UJEFHX.mjs");
14329
14329
  if (opts.compress === false) {
14330
14330
  process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
14331
14331
  return;
@@ -15003,7 +15003,13 @@ function writeReplacedBuffer(file, replacedBuf, preWriteStat) {
15003
15003
  const testDelayMs = Number(process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_MS"] ?? "");
15004
15004
  if (Number.isFinite(testDelayMs) && testDelayMs > 0) {
15005
15005
  process.stderr.write("TOKEN_GOAT_TEST_REPLACE_DELAY_READY\n");
15006
- sleepSync(testDelayMs);
15006
+ const until = process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_UNTIL"];
15007
+ const deadline = Date.now() + testDelayMs;
15008
+ if (until !== void 0 && until !== "") {
15009
+ while (Date.now() < deadline && !fs26.existsSync(until)) sleepSync(5);
15010
+ } else {
15011
+ sleepSync(testDelayMs);
15012
+ }
15007
15013
  }
15008
15014
  let preRenameStat;
15009
15015
  try {
@@ -2,13 +2,15 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  canRunWrappedShell,
5
+ compressOutput,
5
6
  dedupeConsecutive,
6
7
  detectFromCommand,
8
+ filterByName,
7
9
  hasBareBackgroundOrNewline,
8
10
  isRewriteWorthwhile,
9
11
  resolveMinNetSavingsBytes,
10
12
  shlexSplit
11
- } from "./token-goat-hook-chunk-2ISZ4AZR.mjs";
13
+ } from "./token-goat-hook-chunk-NIPXIAPA.mjs";
12
14
  import {
13
15
  BASH_OUTPUT_SUBDIR,
14
16
  HOOK_EVENTS,
@@ -26,7 +28,7 @@ import {
26
28
  storeBashOutput,
27
29
  storeWebOutput,
28
30
  summarizeOutputDelta
29
- } from "./token-goat-hook-chunk-6C5RN3CM.mjs";
31
+ } from "./token-goat-hook-chunk-CRBMPT74.mjs";
30
32
  import {
31
33
  BODY_FIRST_TOOL_RESPONSE_KEYS,
32
34
  OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
@@ -116,7 +118,7 @@ import {
116
118
  wasCliReadThisSession,
117
119
  wasFileReadThisSession,
118
120
  wasHintShown
119
- } from "./token-goat-hook-chunk-6QTWMSRO.mjs";
121
+ } from "./token-goat-hook-chunk-XM4W3WCO.mjs";
120
122
  import {
121
123
  VERSION,
122
124
  detectHarness,
@@ -135,7 +137,7 @@ import {
135
137
  runGit,
136
138
  shortFingerprint,
137
139
  toKB
138
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
140
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
139
141
 
140
142
  // src/hooks_grep.ts
141
143
  function grepIntInput(toolInput, key) {
@@ -573,7 +575,7 @@ import crypto from "node:crypto";
573
575
  var TRACKED_SKILL = "token-goat";
574
576
  var MAX_COMMANDS_SHOWN = 8;
575
577
  async function currentCommandNames() {
576
- const { buildProgram } = await import("./token-goat-hook-chunk-I5VM5PO5.mjs");
578
+ const { buildProgram } = await import("./token-goat-hook-chunk-3AAH72SO.mjs");
577
579
  return flattenCommandNames(buildCommandManifest(buildProgram()));
578
580
  }
579
581
  async function recordSkillVersionSnapshot(sessionId, skillName) {
@@ -7902,12 +7904,151 @@ function extractRgStructuralSearch(cmd) {
7902
7904
  function extractGrepPipeChain(cmd) {
7903
7905
  return /^(?:rg|grep)\b.*\|\s*(?:rg|grep)\b/.test(cmd);
7904
7906
  }
7907
+ function splitCommandWords(cmd) {
7908
+ const words = [];
7909
+ let cur = "";
7910
+ let quote = null;
7911
+ let started = false;
7912
+ for (let i = 0; i < cmd.length; i++) {
7913
+ const ch = cmd[i];
7914
+ if (quote !== null) {
7915
+ if (ch === "\\" && quote === '"' && i + 1 < cmd.length) {
7916
+ cur += cmd[i + 1];
7917
+ i++;
7918
+ continue;
7919
+ }
7920
+ if (ch === quote) quote = null;
7921
+ else cur += ch;
7922
+ continue;
7923
+ }
7924
+ if (ch === "\\" && i + 1 < cmd.length) {
7925
+ cur += cmd[i + 1];
7926
+ i++;
7927
+ started = true;
7928
+ continue;
7929
+ }
7930
+ if (ch === '"' || ch === "'") {
7931
+ quote = ch;
7932
+ started = true;
7933
+ continue;
7934
+ }
7935
+ if (/\s/.test(ch)) {
7936
+ if (started) words.push(cur);
7937
+ cur = "";
7938
+ started = false;
7939
+ continue;
7940
+ }
7941
+ cur += ch;
7942
+ started = true;
7943
+ }
7944
+ if (started) words.push(cur);
7945
+ return words;
7946
+ }
7947
+ var CURL_VALUE_FLAGS = /* @__PURE__ */ new Set([
7948
+ "-H",
7949
+ "--header",
7950
+ "-A",
7951
+ "--user-agent",
7952
+ "-e",
7953
+ "--referer",
7954
+ "-b",
7955
+ "--cookie",
7956
+ "-c",
7957
+ "--cookie-jar",
7958
+ "-o",
7959
+ "--output",
7960
+ "--output-dir",
7961
+ "-u",
7962
+ "--user",
7963
+ "-U",
7964
+ "--proxy-user",
7965
+ "-x",
7966
+ "--proxy",
7967
+ "-X",
7968
+ "--request",
7969
+ "-d",
7970
+ "--data",
7971
+ "--data-raw",
7972
+ "--data-binary",
7973
+ "--data-urlencode",
7974
+ "-F",
7975
+ "--form",
7976
+ "-T",
7977
+ "--upload-file",
7978
+ "-K",
7979
+ "--config",
7980
+ "-w",
7981
+ "--write-out",
7982
+ "-m",
7983
+ "--max-time",
7984
+ "--connect-to",
7985
+ "--resolve",
7986
+ "--retry",
7987
+ "--cacert",
7988
+ "-E",
7989
+ "--cert",
7990
+ "--key",
7991
+ "--range",
7992
+ "-r",
7993
+ "--interface",
7994
+ // Options whose own value is a URL or a host. Leaving these out was the same defect as reading
7995
+ // the first URL in the string: `curl --doh-url https://doh/ -o f https://target` answered with
7996
+ // the DoH resolver rather than the file being fetched. `--url-query` belongs here too -- it
7997
+ // appends query data to the request, it does not name the request target.
7998
+ "--url-query",
7999
+ "--doh-url",
8000
+ "--preproxy",
8001
+ "--proxy1.0",
8002
+ "--socks4",
8003
+ "--socks4a",
8004
+ "--socks5",
8005
+ "--socks5-hostname",
8006
+ "--proxy-header",
8007
+ "--noproxy",
8008
+ "--dns-servers",
8009
+ "--aws-sigv4",
8010
+ "--proxy-cacert",
8011
+ "--proxy-cert",
8012
+ "--proxy-key",
8013
+ "--oauth2-bearer",
8014
+ "--hsts",
8015
+ "--alt-svc",
8016
+ "--etag-save",
8017
+ "--etag-compare",
8018
+ "--trace",
8019
+ "--trace-ascii",
8020
+ "--dump-header",
8021
+ "-D"
8022
+ ]);
7905
8023
  function extractCurlUrl(cmd) {
7906
- const m = /(https?:\/\/[^\s'"]+)/.exec(cmd);
7907
- return m?.[1] ?? null;
8024
+ const words = splitCommandWords(cmd);
8025
+ let positional = null;
8026
+ for (let i = 0; i < words.length; i++) {
8027
+ const w = words[i];
8028
+ if (w === "--url") {
8029
+ const next = words[i + 1];
8030
+ if (next !== void 0 && /^https?:\/\//.test(next)) return next;
8031
+ i++;
8032
+ continue;
8033
+ }
8034
+ const eq = w.indexOf("=");
8035
+ if (w.startsWith("--") && eq > 0) {
8036
+ if (w.slice(0, eq) === "--url" && /^https?:\/\//.test(w.slice(eq + 1))) return w.slice(eq + 1);
8037
+ continue;
8038
+ }
8039
+ if (CURL_VALUE_FLAGS.has(w)) {
8040
+ i++;
8041
+ continue;
8042
+ }
8043
+ if (w.startsWith("-") && w !== "-") continue;
8044
+ if (/^https?:\/\//.test(w)) return w;
8045
+ positional ??= /https?:\/\/[^\s'")}`]+/.exec(w)?.[0] ?? null;
8046
+ }
8047
+ if (positional !== null) return positional;
8048
+ return null;
7908
8049
  }
7909
8050
  function extractTgSurgicalRead(cmd, cwd) {
7910
- const m = /^token-goat\s+(symbol|read|section|skill-body|skill-compact|map)(?:\s+(.*))?$/.exec(cmd);
8051
+ const m = /^(?:token-goat|tg)\s+(symbol|read|section|skill-body|skill-compact|map)(?:\s+(.*))?$/.exec(cmd);
7911
8052
  if (!m) return null;
7912
8053
  const sub = m[1];
7913
8054
  const rest = (m[2] ?? "").trim();
@@ -7986,9 +8127,9 @@ function extractCurlDownload(cmd) {
7986
8127
  const outputPath = outputMatch[1] ?? outputMatch[2] ?? outputMatch[3];
7987
8128
  if (!outputPath) return null;
7988
8129
  if (curlHasUnsafeFlags(cmd)) return null;
7989
- const urlMatch = /(https?:\/\/[^\s'"]+)/.exec(cmd);
7990
- if (!urlMatch?.[1]) return null;
7991
- return { url: urlMatch[1], outputPath };
8130
+ const url = extractCurlUrl(cmd);
8131
+ if (url === null) return null;
8132
+ return { url, outputPath };
7992
8133
  }
7993
8134
  function isTscCommand(cmd) {
7994
8135
  return /^\s*tsc(\s|$)/i.test(cmd);
@@ -8041,9 +8182,34 @@ function maybeCompressRewrite(event, rawCmd, cmd) {
8041
8182
  const wrapped = `token-goat compress -f ${filterName} --timeout ${cfg.timeout_seconds} -c ${shellQuoteSingle(rawCmd)}`;
8042
8183
  return { hookType: "rewriteInput", updatedInput: { ...event.toolInput, command: wrapped } };
8043
8184
  }
8185
+ async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes) {
8186
+ if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
8187
+ if (isCompressibleSingleCommand(cmd)) return null;
8188
+ if (exitCode !== null && exitCode !== 0) return null;
8189
+ let cfg;
8190
+ try {
8191
+ cfg = loadConfig().bash_compress;
8192
+ } catch {
8193
+ return null;
8194
+ }
8195
+ if (!cfg.enabled || cfg.disabled_filters.includes("generic")) return null;
8196
+ if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return null;
8197
+ const filter3 = filterByName("generic");
8198
+ if (filter3 === null) return null;
8199
+ const compressed = compressOutput(filter3, output, "", exitCode ?? 0, [], {
8200
+ maxLines: cfg.max_lines,
8201
+ maxBytes: cfg.max_bytes
8202
+ });
8203
+ const minNet = resolveMinNetSavingsBytes();
8204
+ if (!compressed.worthApplying(minNet)) return null;
8205
+ const id = await storeBashOutput(cmd, output, exitCode ?? 0, cwd);
8206
+ recordStat("bash_compress:generic", compressed.bytesSaved, compressed.tokensSaved);
8207
+ const body = compressed.withMarker(minNet) + "\n[token-goat] full output: bash-output " + id + " --full";
8208
+ return { hookType: "rewriteOutput", updatedOutput: body };
8209
+ }
8044
8210
  function unwrapCompressCommand(executed) {
8045
8211
  const t = executed.trim();
8046
- if (!/^token-goat\s+compress\b/.test(t)) return null;
8212
+ if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
8047
8213
  let argv;
8048
8214
  try {
8049
8215
  argv = shlexSplit(t);
@@ -8095,6 +8261,28 @@ function detectUnbalancedShellSyntax(cmd) {
8095
8261
  i = j;
8096
8262
  continue;
8097
8263
  }
8264
+ if (ch === "$" && cmd[i + 1] === "'") {
8265
+ let j = i + 2;
8266
+ let closed = false;
8267
+ while (j < cmd.length) {
8268
+ if (cmd[j] === "\\") {
8269
+ j += 2;
8270
+ continue;
8271
+ }
8272
+ if (cmd[j] === "'") {
8273
+ j++;
8274
+ closed = true;
8275
+ break;
8276
+ }
8277
+ j++;
8278
+ }
8279
+ if (!closed) {
8280
+ inSingle = true;
8281
+ break;
8282
+ }
8283
+ i = j;
8284
+ continue;
8285
+ }
8098
8286
  if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
8099
8287
  const nl2 = cmd.indexOf("\n", i);
8100
8288
  i = nl2 === -1 ? cmd.length : nl2 + 1;
@@ -8701,7 +8889,11 @@ async function postBashHandler(event) {
8701
8889
  recordBashOutput(gitScopedCacheHash, gitScopedCacheId, Buffer.byteLength(output, "utf-8"));
8702
8890
  }
8703
8891
  const isMonitoring = getMonitoringRecallHint(cmd) !== null;
8704
- if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) return passOutput();
8892
+ if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) {
8893
+ const compound = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes);
8894
+ if (compound !== null) return compound;
8895
+ return passOutput();
8896
+ }
8705
8897
  if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return passOutput();
8706
8898
  const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : stripOutputPipeline(cmd);
8707
8899
  const simpleHash = shortFingerprint(cacheKey);
@@ -9827,6 +10019,9 @@ async function relayInProcess(eventName, rawPayload) {
9827
10019
  async function relay(eventName) {
9828
10020
  try {
9829
10021
  if (!isHookEventName(eventName)) {
10022
+ console.error(
10023
+ `[relay] unknown hook event '${eventName}'; nothing ran. Valid events: ${HOOK_EVENTS.join(", ")}`
10024
+ );
9830
10025
  process.stdout.write("{}");
9831
10026
  return;
9832
10027
  }
@@ -6,7 +6,7 @@ import {
6
6
  loadBlob,
7
7
  sanitizeFtsQuery,
8
8
  storeBlob
9
- } from "./token-goat-hook-chunk-6QTWMSRO.mjs";
9
+ } from "./token-goat-hook-chunk-XM4W3WCO.mjs";
10
10
  import {
11
11
  SYMBOL_BODY_CHAR_CAP,
12
12
  extractErrorMessage,
@@ -16,7 +16,7 @@ import {
16
16
  redactSecrets,
17
17
  runGit,
18
18
  shortFingerprint
19
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
19
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
20
20
  import {
21
21
  registerReset
22
22
  } from "./token-goat-hook-chunk-BUOCULAM.mjs";
@@ -10,11 +10,11 @@ import {
10
10
  selectFilter,
11
11
  shlexSplit,
12
12
  wrappedShell
13
- } from "./token-goat-hook-chunk-2ISZ4AZR.mjs";
13
+ } from "./token-goat-hook-chunk-NIPXIAPA.mjs";
14
14
  import {
15
15
  loadConfig,
16
16
  recordStat
17
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
17
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
18
18
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
19
19
  import "./token-goat-hook-chunk-RFRLWOQH.mjs";
20
20
 
@@ -4,14 +4,14 @@ import {
4
4
  buildEvent,
5
5
  relay,
6
6
  relayInProcess
7
- } from "./token-goat-hook-chunk-BU5OFDGQ.mjs";
8
- import "./token-goat-hook-chunk-2ISZ4AZR.mjs";
7
+ } from "./token-goat-hook-chunk-4POU6OHK.mjs";
8
+ import "./token-goat-hook-chunk-NIPXIAPA.mjs";
9
9
  import {
10
10
  MAX_STDIN_BYTES,
11
11
  readStdinJson
12
- } from "./token-goat-hook-chunk-6C5RN3CM.mjs";
13
- import "./token-goat-hook-chunk-6QTWMSRO.mjs";
14
- import "./token-goat-hook-chunk-CNLMPHXT.mjs";
12
+ } from "./token-goat-hook-chunk-CRBMPT74.mjs";
13
+ import "./token-goat-hook-chunk-XM4W3WCO.mjs";
14
+ import "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
15
15
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
16
16
  import "./token-goat-hook-chunk-RFRLWOQH.mjs";
17
17
  export {
@@ -4,7 +4,7 @@ import {
4
4
  loadConfig,
5
5
  redactSecrets,
6
6
  stripAnsiCodes
7
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
7
+ } from "./token-goat-hook-chunk-2O7P4Z6Q.mjs";
8
8
 
9
9
  // src/tool_filters/helpers.ts
10
10
  import * as fs from "node:fs";