token-goat 2.8.2 → 2.8.3

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.
@@ -4,8 +4,13 @@ import {
4
4
  IMPORT_RE,
5
5
  ImageDecodeError,
6
6
  MAX_OVER_FETCH,
7
+ MAX_ZIP_INPUT_BYTES,
8
+ MAX_ZIP_OUTPUT_BYTES,
7
9
  OVER_FETCH_FACTOR,
8
10
  SKIP_DIRS,
11
+ UNTRUSTED_GITHUB_TAG,
12
+ ZipInputTooLargeError,
13
+ ZipOutputTooLargeError,
9
14
  capJsonRows,
10
15
  countRefs,
11
16
  countSymbols,
@@ -18,6 +23,7 @@ import {
18
23
  extractPdfMeta,
19
24
  extractPdfOutline,
20
25
  extractPdfText,
26
+ fenceUntrustedContent,
21
27
  formatCsvProfile,
22
28
  formatCsvTable,
23
29
  getFileEntry,
@@ -42,6 +48,7 @@ import {
42
48
  queryRefs,
43
49
  queryRefsByContext,
44
50
  querySymbols,
51
+ scanForInjectionPatterns,
45
52
  searchEvidenceSemantically,
46
53
  searchSemantic,
47
54
  searchSymbolsFts,
@@ -50,11 +57,12 @@ import {
50
57
  stripLeadingAttributes,
51
58
  tomlBracketDelta,
52
59
  trimToBudget,
60
+ unzipBounded,
53
61
  urlPolicyDenialReason,
54
62
  walkProject,
55
63
  yamlLineClosesQuote,
56
64
  yamlOpenQuoteAfter
57
- } from "./token-goat-chunk-AM23GDIS.mjs";
65
+ } from "./token-goat-chunk-PWVXXPCC.mjs";
58
66
  import {
59
67
  Database,
60
68
  PER_FILE_COUNTERFACTUAL_CEILING,
@@ -106,7 +114,7 @@ import {
106
114
  unsupportedLanguageName,
107
115
  windowsCmdQuoteArg,
108
116
  withExtension
109
- } from "./token-goat-chunk-IVCTQPZD.mjs";
117
+ } from "./token-goat-chunk-6ODZ6PZK.mjs";
110
118
  import {
111
119
  registerReset
112
120
  } from "./token-goat-chunk-AO2QD2AG.mjs";
@@ -3612,7 +3620,7 @@ function formatZipList(entries) {
3612
3620
  }
3613
3621
  async function extractZipEntry(data, entryPath) {
3614
3622
  const fflate = await requireFflate();
3615
- const result = fflate.unzipSync(data, { filter: (file) => file.name === entryPath });
3623
+ const result = unzipBounded(fflate, data, { limitBytes: MAX_ZIP_OUTPUT_BYTES, shouldExtract: (name) => name === entryPath });
3616
3624
  return result[entryPath];
3617
3625
  }
3618
3626
 
@@ -5262,10 +5270,16 @@ function readFileBytes(p) {
5262
5270
  verifyStillAbsent(p);
5263
5271
  return null;
5264
5272
  }
5265
- if (pinned !== void 0) return readPinnedBytes(p, pinned);
5273
+ if (pinned !== void 0) {
5274
+ const bytes = readPinnedBytes(p, pinned);
5275
+ if (bytes.length > MAX_ZIP_INPUT_BYTES) throw new ZipInputTooLargeError(p, bytes.length, MAX_ZIP_INPUT_BYTES);
5276
+ return bytes;
5277
+ }
5278
+ const stat = fs5.statSync(p);
5279
+ if (stat.size > MAX_ZIP_INPUT_BYTES) throw new ZipInputTooLargeError(p, stat.size, MAX_ZIP_INPUT_BYTES);
5266
5280
  return fs5.readFileSync(p);
5267
5281
  } catch (err) {
5268
- if (err instanceof ConfinementIdentityError) throw err;
5282
+ if (err instanceof ConfinementIdentityError || err instanceof ZipInputTooLargeError) throw err;
5269
5283
  return null;
5270
5284
  }
5271
5285
  }
@@ -5333,6 +5347,17 @@ function guardText(text, command) {
5333
5347
  const cfg = loadConfig();
5334
5348
  return cfg.overflow_guard.enabled ? trimToBudget(text, cfg.overflow_guard.max_tokens, command) : text;
5335
5349
  }
5350
+ function fenceGithubTextIfMatched(text) {
5351
+ let matches = [];
5352
+ try {
5353
+ if (loadConfig().injection.enabled) matches = scanForInjectionPatterns(text);
5354
+ } catch {
5355
+ matches = [];
5356
+ }
5357
+ if (matches.length === 0) return text;
5358
+ recordStat("injection_detected", 0, 0, void 0, matches.join(","));
5359
+ return fenceUntrustedContent(text, matches, UNTRUSTED_GITHUB_TAG);
5360
+ }
5336
5361
  function guardJsonRows(items) {
5337
5362
  const cfg = loadConfig();
5338
5363
  if (!cfg.overflow_guard.enabled) return { items: [...items], truncated: false, totalCount: items.length };
@@ -7021,11 +7046,20 @@ function runOpenApiOp(opts) {
7021
7046
  return 0;
7022
7047
  }
7023
7048
  function archiveReadFailure(err, file) {
7024
- if (err instanceof ArchiveDependencyMissingError) return err.message;
7049
+ if (err instanceof ArchiveDependencyMissingError || err instanceof ZipOutputTooLargeError) return err.message;
7025
7050
  return `Failed to read archive (not a valid zip-format file): ${file}`;
7026
7051
  }
7027
7052
  async function runZipList(opts) {
7028
- const data = readFileBytes(opts.file);
7053
+ let data;
7054
+ try {
7055
+ data = readFileBytes(opts.file);
7056
+ } catch (err) {
7057
+ if (err instanceof ZipInputTooLargeError) {
7058
+ emitErr(err.message);
7059
+ return 1;
7060
+ }
7061
+ throw err;
7062
+ }
7029
7063
  if (data === null) {
7030
7064
  emitErr(`Could not read: ${opts.file}`);
7031
7065
  return 1;
@@ -7050,7 +7084,16 @@ async function runZipList(opts) {
7050
7084
  return 0;
7051
7085
  }
7052
7086
  async function runZipRead(opts) {
7053
- const data = readFileBytes(opts.file);
7087
+ let data;
7088
+ try {
7089
+ data = readFileBytes(opts.file);
7090
+ } catch (err) {
7091
+ if (err instanceof ZipInputTooLargeError) {
7092
+ emitErr(err.message);
7093
+ return 1;
7094
+ }
7095
+ throw err;
7096
+ }
7054
7097
  if (data === null) {
7055
7098
  emitErr(`Could not read: ${opts.file}`);
7056
7099
  return 1;
@@ -7146,11 +7189,11 @@ function runPrSlice(opts) {
7146
7189
  }
7147
7190
  const fullSourceBytes = Buffer.byteLength(diffText, "utf8");
7148
7191
  if (opts.json === true) {
7149
- const jsonText = JSON.stringify({ path: parsed.path, diff: fileDiff });
7192
+ const jsonText = JSON.stringify({ path: parsed.path, diff: fenceGithubTextIfMatched(fileDiff) });
7150
7193
  emit(jsonText);
7151
7194
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} diff:${parsed.path}`);
7152
7195
  } else {
7153
- emitGuarded(fileDiff, "pr-slice");
7196
+ emitGuarded(fenceGithubTextIfMatched(fileDiff), "pr-slice");
7154
7197
  recordReadStat("pr_slice", fullSourceBytes, fileDiff, `${repo}#${opts.pr} diff:${parsed.path}`);
7155
7198
  }
7156
7199
  return 0;
@@ -7159,13 +7202,14 @@ function runPrSlice(opts) {
7159
7202
  const comments = fetchPrComments(opts.pr, repo);
7160
7203
  const fullSourceBytes = Buffer.byteLength(JSON.stringify(comments), "utf8");
7161
7204
  if (opts.json === true) {
7162
- const capped = guardJsonRows(comments);
7205
+ const fencedComments = comments.map((c) => ({ ...c, body: fenceGithubTextIfMatched(c.body) }));
7206
+ const capped = guardJsonRows(fencedComments);
7163
7207
  const jsonText = JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
7164
7208
  emit(jsonText);
7165
7209
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} comments`);
7166
7210
  } else {
7167
7211
  const text = formatCommentsSlice(comments);
7168
- emitGuarded(text, "pr-slice");
7212
+ emitGuarded(fenceGithubTextIfMatched(text), "pr-slice");
7169
7213
  recordReadStat("pr_slice", fullSourceBytes, text, `${repo}#${opts.pr} comments`);
7170
7214
  }
7171
7215
  return 0;
@@ -7174,12 +7218,17 @@ function runPrSlice(opts) {
7174
7218
  const desc = fetchPrDescription(opts.pr, repo);
7175
7219
  const fullSourceBytes = Buffer.byteLength(JSON.stringify(desc), "utf8");
7176
7220
  if (opts.json === true) {
7177
- const jsonText = JSON.stringify(desc);
7221
+ const fencedDesc = {
7222
+ ...desc,
7223
+ title: fenceGithubTextIfMatched(desc.title),
7224
+ body: desc.body !== null ? fenceGithubTextIfMatched(desc.body) : null
7225
+ };
7226
+ const jsonText = JSON.stringify(fencedDesc);
7178
7227
  emit(jsonText);
7179
7228
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} description`);
7180
7229
  } else {
7181
7230
  const text = formatDescriptionSlice(desc);
7182
- emitGuarded(text, "pr-slice");
7231
+ emitGuarded(fenceGithubTextIfMatched(text), "pr-slice");
7183
7232
  recordReadStat("pr_slice", fullSourceBytes, text, `${repo}#${opts.pr} description`);
7184
7233
  }
7185
7234
  return 0;
@@ -7222,7 +7271,6 @@ function runSqliteQuery(opts) {
7222
7271
  const totalCount = result.rows.length;
7223
7272
  const headTruncated = head !== void 0 && result.rows.length > head;
7224
7273
  const rows = head !== void 0 ? result.rows.slice(0, head) : result.rows;
7225
- const fullSourceBytes = sumFileSizes([opts.file]);
7226
7274
  if (opts.json === true) {
7227
7275
  const capped = guardJsonRows(rows);
7228
7276
  const jsonText = JSON.stringify({
@@ -7233,11 +7281,20 @@ function runSqliteQuery(opts) {
7233
7281
  rowCapped: result.rowCapped
7234
7282
  });
7235
7283
  emit(jsonText);
7236
- recordReadStat("sqlite_query", fullSourceBytes, jsonText, opts.file);
7284
+ const uncappedFull = guardJsonRows(result.rows);
7285
+ const baselineJsonText = JSON.stringify({
7286
+ columns: result.columns,
7287
+ items: uncappedFull.items,
7288
+ truncated: uncappedFull.truncated || result.rowCapped,
7289
+ totalCount,
7290
+ rowCapped: result.rowCapped
7291
+ });
7292
+ recordReadStat("sqlite_query", Buffer.byteLength(baselineJsonText, "utf8"), jsonText, opts.file);
7237
7293
  } else {
7238
7294
  const text = formatSqliteQueryTable({ ...result, rows }, { headTruncated });
7239
7295
  emit(text);
7240
- recordReadStat("sqlite_query", fullSourceBytes, text, opts.file);
7296
+ const baselineText = formatSqliteQueryTable({ ...result, rows: result.rows }, { headTruncated: false });
7297
+ recordReadStat("sqlite_query", Buffer.byteLength(baselineText, "utf8"), text, opts.file);
7241
7298
  }
7242
7299
  return 0;
7243
7300
  } catch (e) {
@@ -10,11 +10,11 @@ import {
10
10
  selectFilter,
11
11
  shlexSplit,
12
12
  wrappedShell
13
- } from "./token-goat-chunk-TF5NT3H5.mjs";
13
+ } from "./token-goat-chunk-EFF2XCLB.mjs";
14
14
  import {
15
15
  loadConfig,
16
16
  recordStat
17
- } from "./token-goat-chunk-IVCTQPZD.mjs";
17
+ } from "./token-goat-chunk-6ODZ6PZK.mjs";
18
18
  import "./token-goat-chunk-AO2QD2AG.mjs";
19
19
  import "./token-goat-chunk-AEX54RUZ.mjs";
20
20
 
@@ -2,11 +2,11 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  relayInProcess
5
- } from "./token-goat-chunk-KBVN4ELV.mjs";
6
- import "./token-goat-chunk-5MLXFSRI.mjs";
7
- import "./token-goat-chunk-AM23GDIS.mjs";
8
- import "./token-goat-chunk-TF5NT3H5.mjs";
9
- import "./token-goat-chunk-IVCTQPZD.mjs";
5
+ } from "./token-goat-chunk-NKNCHJ4H.mjs";
6
+ import "./token-goat-chunk-4HIMCBYK.mjs";
7
+ import "./token-goat-chunk-PWVXXPCC.mjs";
8
+ import "./token-goat-chunk-EFF2XCLB.mjs";
9
+ import "./token-goat-chunk-6ODZ6PZK.mjs";
10
10
  import "./token-goat-chunk-AO2QD2AG.mjs";
11
11
  import "./token-goat-chunk-AEX54RUZ.mjs";
12
12
  export {
@@ -2,13 +2,13 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./token-goat-chunk-2MWF3OGR.mjs";
6
- import "./token-goat-chunk-LILS6TIU.mjs";
7
- import "./token-goat-chunk-5MLXFSRI.mjs";
8
- import "./token-goat-chunk-AM23GDIS.mjs";
5
+ } from "./token-goat-chunk-222VPFP2.mjs";
6
+ import "./token-goat-chunk-TX4JFJTD.mjs";
7
+ import "./token-goat-chunk-4HIMCBYK.mjs";
8
+ import "./token-goat-chunk-PWVXXPCC.mjs";
9
9
  import {
10
10
  installEpipeGuard
11
- } from "./token-goat-chunk-IVCTQPZD.mjs";
11
+ } from "./token-goat-chunk-6ODZ6PZK.mjs";
12
12
  import "./token-goat-chunk-AO2QD2AG.mjs";
13
13
  import "./token-goat-chunk-AEX54RUZ.mjs";
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-goat",
3
- "version": "2.8.2",
3
+ "version": "2.8.3",
4
4
  "description": "Surgical token-reduction companion for Claude Code and other AI coding agents",
5
5
  "type": "module",
6
6
  "main": "./dist/token-goat.mjs",