token-goat 2.6.34 → 2.6.36

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 (26) hide show
  1. package/README.md +4 -2
  2. package/SECURITY.md +14 -11
  3. package/dist/{token-goat-chunk-L7QLEVO7.mjs → token-goat-chunk-65BKISIS.mjs} +16 -14
  4. package/dist/{token-goat-chunk-I6EQH27G.mjs → token-goat-chunk-CNDOJ3ZP.mjs} +2 -2
  5. package/dist/{token-goat-chunk-FRMEOIRU.mjs → token-goat-chunk-FRTBMRP7.mjs} +208 -13
  6. package/dist/{token-goat-chunk-IYYQOPY4.mjs → token-goat-chunk-IYTVE6KN.mjs} +29 -10
  7. package/dist/{token-goat-chunk-GXBPEQR2.mjs → token-goat-chunk-KYFJC37X.mjs} +21 -14
  8. package/dist/{token-goat-chunk-CKRATWCJ.mjs → token-goat-chunk-LN6OUHTV.mjs} +5 -5
  9. package/dist/{token-goat-chunk-WA2ER6TZ.mjs → token-goat-chunk-MGOUYAA2.mjs} +1 -1
  10. package/dist/{token-goat-chunk-CN7GUPX6.mjs → token-goat-chunk-UFOVM7ZN.mjs} +461 -97
  11. package/dist/{token-goat-chunk-7FWBSPCT.mjs → token-goat-chunk-V465YKOR.mjs} +198 -21
  12. package/dist/{token-goat-chunk-OA3GFKP2.mjs → token-goat-chunk-VYMGEVZS.mjs} +16 -4
  13. package/dist/{token-goat-hook-chunk-2ISZ4AZR.mjs → token-goat-hook-chunk-3ZDBWJDF.mjs} +1 -1
  14. package/dist/{token-goat-hook-chunk-6C5RN3CM.mjs → token-goat-hook-chunk-5UH54CW6.mjs} +16 -4
  15. package/dist/{token-goat-hook-chunk-OQML5EMA.mjs → token-goat-hook-chunk-6ODM3MP7.mjs} +16 -14
  16. package/dist/{token-goat-hook-chunk-6QTWMSRO.mjs → token-goat-hook-chunk-A77A26A7.mjs} +461 -97
  17. package/dist/{token-goat-hook-chunk-BU5OFDGQ.mjs → token-goat-hook-chunk-BDR6C6IE.mjs} +208 -13
  18. package/dist/{token-goat-hook-chunk-I5VM5PO5.mjs → token-goat-hook-chunk-C6GIABOX.mjs} +21 -14
  19. package/dist/{token-goat-hook-chunk-QTZ6YUMQ.mjs → token-goat-hook-chunk-E257IGSN.mjs} +2 -2
  20. package/dist/{token-goat-hook-chunk-KGLMNOGD.mjs → token-goat-hook-chunk-MW5HPEGD.mjs} +29 -10
  21. package/dist/{token-goat-hook-chunk-ATEGFQAU.mjs → token-goat-hook-chunk-QSCYNJ2B.mjs} +5 -5
  22. package/dist/{token-goat-hook-chunk-CNLMPHXT.mjs → token-goat-hook-chunk-Y2WHX2P3.mjs} +198 -21
  23. package/dist/token-goat-hook.mjs +5 -5
  24. package/dist/token-goat.core.mjs +5 -5
  25. package/package.json +13 -11
  26. package/scripts/install-git-hooks.mjs +55 -0
@@ -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-3ZDBWJDF.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-5UH54CW6.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-A77A26A7.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-Y2WHX2P3.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-C6GIABOX.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
  }
@@ -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-MW5HPEGD.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-5UH54CW6.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-A77A26A7.mjs";
247
247
  import {
248
248
  C,
249
249
  CONFIG_KEY_ENV_OVERRIDES,
@@ -294,6 +294,8 @@ import {
294
294
  normalizePath,
295
295
  pad,
296
296
  parse,
297
+ pushAll,
298
+ readConfigSource,
297
299
  recordStat,
298
300
  redactIfDotenv,
299
301
  redactUrlQuery,
@@ -322,7 +324,7 @@ import {
322
324
  withFileLock,
323
325
  withRetryOnLock,
324
326
  writeJsonSettings
325
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
327
+ } from "./token-goat-hook-chunk-Y2WHX2P3.mjs";
326
328
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
327
329
  import {
328
330
  __export
@@ -5874,7 +5876,7 @@ function checkConfigValid(configPath2) {
5874
5876
  };
5875
5877
  }
5876
5878
  try {
5877
- const content = fs12.readFileSync(configPath2, "utf-8");
5879
+ const content = readConfigSource(configPath2);
5878
5880
  parse(content);
5879
5881
  return {
5880
5882
  name: "Config",
@@ -9562,7 +9564,7 @@ function collectTodoFiles(patterns) {
9562
9564
  try {
9563
9565
  const stat = fs16.statSync(abs);
9564
9566
  if (stat.isDirectory()) {
9565
- results.push(...walkProject(abs).files);
9567
+ pushAll(results, walkProject(abs).files);
9566
9568
  } else {
9567
9569
  results.push(abs);
9568
9570
  }
@@ -9580,7 +9582,7 @@ function cmdTodo(patterns, opts) {
9580
9582
  const files = collectTodoFiles(patterns);
9581
9583
  const items = [];
9582
9584
  for (const f of files) {
9583
- items.push(...scanFileForTodos(f, kindSet));
9585
+ pushAll(items, scanFileForTodos(f, kindSet));
9584
9586
  }
9585
9587
  if (opts.json === true) {
9586
9588
  process.stdout.write(JSON.stringify({ items }, null, 2) + "\n");
@@ -11333,7 +11335,7 @@ function reclaimIndex(dbPath, opts = {}) {
11333
11335
  db.prepare(`DELETE FROM "${table}"`).run();
11334
11336
  dropped[table] = before;
11335
11337
  }
11336
- })();
11338
+ }).immediate();
11337
11339
  if (tableExists(db, "symbols_fts")) {
11338
11340
  try {
11339
11341
  db.prepare(`INSERT INTO symbols_fts(symbols_fts) VALUES('rebuild')`).run();
@@ -11702,8 +11704,7 @@ function cmdConfig(opts) {
11702
11704
  let raw = {};
11703
11705
  let parseErr = null;
11704
11706
  try {
11705
- const text = fs19.readFileSync(cfgFile, "utf8");
11706
- raw = parse(text);
11707
+ raw = parse(readConfigSource(cfgFile));
11707
11708
  } catch (e) {
11708
11709
  const code = e.code;
11709
11710
  if (code !== "ENOENT") {
@@ -13447,7 +13448,7 @@ async function cmdMcpServe() {
13447
13448
  let StdioServerTransport;
13448
13449
  try {
13449
13450
  ;
13450
- ({ createMcpServer } = await import("./token-goat-hook-chunk-OQML5EMA.mjs"));
13451
+ ({ createMcpServer } = await import("./token-goat-hook-chunk-6ODM3MP7.mjs"));
13451
13452
  ({ StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"));
13452
13453
  } catch (err2) {
13453
13454
  process.stderr.write(
@@ -13468,7 +13469,7 @@ async function cmdHook(event, opts) {
13468
13469
  if (typeof opts.harness === "string" && opts.harness.length > 0) {
13469
13470
  process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
13470
13471
  }
13471
- const { relay } = await import("./token-goat-hook-chunk-ATEGFQAU.mjs");
13472
+ const { relay } = await import("./token-goat-hook-chunk-QSCYNJ2B.mjs");
13472
13473
  await relay(event);
13473
13474
  }
13474
13475
  async function cmdInstall(opts) {
@@ -14325,7 +14326,7 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
14325
14326
  }
14326
14327
  async function cmdCompress(opts) {
14327
14328
  try {
14328
- const bashRunner = await import("./token-goat-hook-chunk-QTZ6YUMQ.mjs");
14329
+ const bashRunner = await import("./token-goat-hook-chunk-E257IGSN.mjs");
14329
14330
  if (opts.compress === false) {
14330
14331
  process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
14331
14332
  return;
@@ -15003,7 +15004,13 @@ function writeReplacedBuffer(file, replacedBuf, preWriteStat) {
15003
15004
  const testDelayMs = Number(process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_MS"] ?? "");
15004
15005
  if (Number.isFinite(testDelayMs) && testDelayMs > 0) {
15005
15006
  process.stderr.write("TOKEN_GOAT_TEST_REPLACE_DELAY_READY\n");
15006
- sleepSync(testDelayMs);
15007
+ const until = process.env["TOKEN_GOAT_TEST_REPLACE_DELAY_UNTIL"];
15008
+ const deadline = Date.now() + testDelayMs;
15009
+ if (until !== void 0 && until !== "") {
15010
+ while (Date.now() < deadline && !fs26.existsSync(until)) sleepSync(5);
15011
+ } else {
15012
+ sleepSync(testDelayMs);
15013
+ }
15007
15014
  }
15008
15015
  let preRenameStat;
15009
15016
  try {
@@ -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-3ZDBWJDF.mjs";
14
14
  import {
15
15
  loadConfig,
16
16
  recordStat
17
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
17
+ } from "./token-goat-hook-chunk-Y2WHX2P3.mjs";
18
18
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
19
19
  import "./token-goat-hook-chunk-RFRLWOQH.mjs";
20
20
 
@@ -50,7 +50,7 @@ import {
50
50
  walkProject,
51
51
  yamlLineClosesQuote,
52
52
  yamlOpenQuoteAfter
53
- } from "./token-goat-hook-chunk-6QTWMSRO.mjs";
53
+ } from "./token-goat-hook-chunk-A77A26A7.mjs";
54
54
  import {
55
55
  PER_FILE_COUNTERFACTUAL_CEILING,
56
56
  _detectOpenQuote,
@@ -83,6 +83,7 @@ import {
83
83
  loadConfig,
84
84
  normalizePath,
85
85
  offsetToLine,
86
+ pushAll,
86
87
  recordStat,
87
88
  redactIfDotenv,
88
89
  redactSecrets,
@@ -100,7 +101,7 @@ import {
100
101
  unsupportedLanguageName,
101
102
  windowsCmdQuoteArg,
102
103
  withExtension
103
- } from "./token-goat-hook-chunk-CNLMPHXT.mjs";
104
+ } from "./token-goat-hook-chunk-Y2WHX2P3.mjs";
104
105
  import {
105
106
  registerReset
106
107
  } from "./token-goat-hook-chunk-BUOCULAM.mjs";
@@ -563,9 +564,9 @@ function evalJsonPath(data, ops) {
563
564
  } else if (op.kind === "wildcard") {
564
565
  fanned = true;
565
566
  if (Array.isArray(item)) {
566
- next.push(...item);
567
+ pushAll(next, item);
567
568
  } else if (typeof item === "object" && item !== null) {
568
- next.push(...Object.values(item));
569
+ pushAll(next, Object.values(item));
569
570
  }
570
571
  } else {
571
572
  fanned = true;
@@ -997,7 +998,7 @@ function queryXml(xmlText, pathStr) {
997
998
  const attrName = step.attributeSelect;
998
999
  for (const cand of currentCandidates) {
999
1000
  if (attrName === "*") {
1000
- attrVals.push(...Object.values(cand.attributes));
1001
+ pushAll(attrVals, Object.values(cand.attributes));
1001
1002
  } else if (cand.attributes[attrName] !== void 0) {
1002
1003
  attrVals.push(cand.attributes[attrName]);
1003
1004
  }
@@ -1046,7 +1047,7 @@ function queryXml(xmlText, pathStr) {
1046
1047
  if (step.allIndices || matching.length > 1 || step.attributeFilter !== void 0) {
1047
1048
  hasFanned = true;
1048
1049
  }
1049
- nextCandidates.push(...matching);
1050
+ pushAll(nextCandidates, matching);
1050
1051
  }
1051
1052
  }
1052
1053
  currentCandidates = nextCandidates;
@@ -6552,6 +6553,10 @@ function mergeListingJson(files, blocks, anyOk) {
6552
6553
  const payload = { items, truncated, totalCount, ...errors.length > 0 ? { errors } : {} };
6553
6554
  return { text: JSON.stringify(payload, null, 2), code: anyOk ? 0 : 1 };
6554
6555
  }
6556
+ function symbolCountLabel(shown, truncated, trueCount) {
6557
+ if (!truncated || trueCount === void 0 || trueCount <= shown) return countNoun(shown, "symbol");
6558
+ return `${shown} of ${countNoun(trueCount, "symbol")}`;
6559
+ }
6555
6560
  function runSkeleton(opts) {
6556
6561
  const multiFiles = parseMultiFileSpec(opts.file);
6557
6562
  if (multiFiles !== null) return runPerFileListing(multiFiles, (file) => runSkeleton({ ...opts, file, includeFilePath: true }), opts.json === true);
@@ -6584,7 +6589,7 @@ function runSkeleton(opts) {
6584
6589
  return { text: text2, code: 0 };
6585
6590
  }
6586
6591
  const totalLines = filtered.length > 0 ? Math.max(...filtered.map((s) => s.lineEnd)) : 0;
6587
- const lines = [`# Skeleton: ${opts.file} (${countNoun(filtered.length, "symbol")}, ${countNoun(totalLines, "line")})`];
6592
+ const lines = [`# Skeleton: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)}, ${countNoun(totalLines, "line")})`];
6588
6593
  if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
6589
6594
  for (const sym of filtered) {
6590
6595
  const lineStr = sym.lineStart.toString().padStart(6);
@@ -6626,7 +6631,7 @@ function runOutline(opts) {
6626
6631
  recordReadStat("outline", fullSourceBytes, text2, opts.file);
6627
6632
  return { text: text2, code: 0 };
6628
6633
  }
6629
- const lines = [`# Outline: ${opts.file} (${countNoun(filtered.length, "symbol")})`];
6634
+ const lines = [`# Outline: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)})`];
6630
6635
  if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
6631
6636
  for (const sym of filtered) {
6632
6637
  const rangeStr = `${sym.lineStart.toString().padStart(4)}-${sym.lineEnd.toString().padEnd(6)}`;
@@ -7644,10 +7649,16 @@ function buildChangedRefHint(cwd, ref) {
7644
7649
  const commitWord = commitCount === 1 ? "1 commit" : `${commitCount} commits`;
7645
7650
  return `Hint: this repo has only ${commitWord}; '${ref}' does not exist. Try: token-goat changed --since ${suggestedRef}`;
7646
7651
  }
7652
+ function refIsSafe(ref) {
7653
+ return !ref.startsWith("-");
7654
+ }
7655
+ function emitUnsafeRef(ref) {
7656
+ emitErr(`Refusing a git ref that starts with '-': ${ref}`);
7657
+ }
7647
7658
  function runChanged(opts = {}) {
7648
7659
  const ref = opts.ref ?? "HEAD~5";
7649
- if (ref.startsWith("-")) {
7650
- emitErr(`Refusing a git ref that starts with '-': ${ref}`);
7660
+ if (!refIsSafe(ref)) {
7661
+ emitUnsafeRef(ref);
7651
7662
  return 1;
7652
7663
  }
7653
7664
  const cwd = opts.projectRoot ?? process.cwd();
@@ -7824,6 +7835,10 @@ function resolveSymbolSpecOrEmitError(commandName, spec, projectRoot) {
7824
7835
  return resolution.entry;
7825
7836
  }
7826
7837
  function runDiff(opts) {
7838
+ if (opts.ref !== void 0 && !refIsSafe(opts.ref)) {
7839
+ emitUnsafeRef(opts.ref);
7840
+ return 1;
7841
+ }
7827
7842
  const match = resolveSymbolSpecOrEmitError("diff", opts.spec, opts.projectRoot);
7828
7843
  if (match === null) return 1;
7829
7844
  const cwd = opts.projectRoot ?? process.cwd();
@@ -7911,6 +7926,10 @@ function parseLogDashLOutput(stdout) {
7911
7926
  return entries;
7912
7927
  }
7913
7928
  function runLog(opts) {
7929
+ if (opts.ref !== void 0 && !refIsSafe(opts.ref)) {
7930
+ emitUnsafeRef(opts.ref);
7931
+ return 1;
7932
+ }
7914
7933
  const match = resolveSymbolSpecOrEmitError("log", opts.spec, opts.projectRoot);
7915
7934
  if (match === null) return 1;
7916
7935
  const cwd = opts.projectRoot ?? process.cwd();
@@ -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-BDR6C6IE.mjs";
8
+ import "./token-goat-hook-chunk-3ZDBWJDF.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-5UH54CW6.mjs";
13
+ import "./token-goat-hook-chunk-A77A26A7.mjs";
14
+ import "./token-goat-hook-chunk-Y2WHX2P3.mjs";
15
15
  import "./token-goat-hook-chunk-BUOCULAM.mjs";
16
16
  import "./token-goat-hook-chunk-RFRLWOQH.mjs";
17
17
  export {