token-goat 2.2.0 → 2.2.1

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 (2) hide show
  1. package/dist/token-goat.mjs +32 -12
  2. package/package.json +1 -1
@@ -9493,7 +9493,7 @@ init_define_import_meta_env();
9493
9493
  import { createRequire } from "node:module";
9494
9494
  function resolveVersion() {
9495
9495
  if (true) {
9496
- return "2.2.0";
9496
+ return "2.2.1";
9497
9497
  }
9498
9498
  const require2 = createRequire(import.meta.url);
9499
9499
  const pkg = require2("../package.json");
@@ -10786,8 +10786,9 @@ var BUILD_COMMAND_PATTERNS = [
10786
10786
  /^\s*cmake\s+--build\b/i,
10787
10787
  // Rake (Ruby)
10788
10788
  /^\s*rake\b/i,
10789
- // TypeScript compiler
10790
- /^\s*tsc\b/i,
10789
+ // TypeScript compiler (direct and via npx)
10790
+ /^\s*tsc(?:\s|$)/i,
10791
+ /^\s*npx\s+tsc(?:\s|$)/i,
10791
10792
  // Vite
10792
10793
  /^\s*vite\s+(build|dev|preview)\b/i,
10793
10794
  // Next.js
@@ -10872,6 +10873,7 @@ var MONITORING_COMMAND_PATTERNS = [
10872
10873
  // Linters / formatters run repeatedly
10873
10874
  { pattern: /^(?:npx\s+)?eslint(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
10874
10875
  { pattern: /^(?:npx\s+)?prettier(?:\s|$)/, recallHint: '--grep "unchanged|reformatted|error"' },
10876
+ { pattern: /^npx\s+tsc(?:\s|$)/, recallHint: '--grep "error TS|Cannot find|Type "' },
10875
10877
  { pattern: /^ruff(?:\s|$)/, recallHint: '--grep "error|warning|Found"' },
10876
10878
  { pattern: /^(?:cargo\s+)?clippy/, recallHint: '--grep "error\\[|warning\\["' },
10877
10879
  // git diff (full diff output — can be very large; excludes --stat which is small)
@@ -10881,6 +10883,8 @@ var MONITORING_COMMAND_PATTERNS = [
10881
10883
  { pattern: /^npm run (?:test|spec)(?:\s|$)/, recallHint: '--grep "FAIL|PASS|Error|Tests:|\u2713|\u2717"' },
10882
10884
  { pattern: /^npm run build(?:\s|$)/, recallHint: '--grep "error|Built|Failed|\u2713|\u2717"' },
10883
10885
  { pattern: /^npm run (?:lint|typecheck|check|type-check)(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
10886
+ // node scripts (migration runners, seed generators, etc. run repeatedly)
10887
+ { pattern: /^node\s+(?:scripts|src\/scripts)\/\S+\.m?js\b/, recallHint: '--tail 50 --grep "error|Error|done|complete|inserted|migrated"' },
10884
10888
  // External AI peer-review CLI tools (produce large outputs, run repeatedly per session)
10885
10889
  { pattern: /^codex(?:\s|$)/, recallHint: '--tail 100 --grep "error|suggestion|verdict|conclusion"' },
10886
10890
  { pattern: /^(?:~\/\.claude\/bin\/|\.claude\/bin\/)?glm\.sh(?:\s|$)/, recallHint: '--tail 100 --grep "error|verdict|conclusion|suggestion"' },
@@ -12956,6 +12960,10 @@ registerReset(() => {
12956
12960
  });
12957
12961
 
12958
12962
  // src/hooks_bash.ts
12963
+ function stripCdPrefix(cmd) {
12964
+ const stripped = cmd.replace(/^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)\s*&&\s*)+/, "");
12965
+ return stripped.trim() || cmd;
12966
+ }
12959
12967
  function extractCommand(event) {
12960
12968
  const cmd = event.toolInput["command"];
12961
12969
  return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
@@ -13168,7 +13176,10 @@ function extractSedLineRange(cmd) {
13168
13176
  return /^sed\s+-n\s+['"]?\d+,\d+p['"]?/.test(cmd);
13169
13177
  }
13170
13178
  function extractDirectoryListing(cmd) {
13171
- return /^eza\s+.*--long\s+\S+/.test(cmd) || /^eza\s+.*--tree/.test(cmd) || /^tree(\s|$)/.test(cmd) || /^ls\s+.*-[a-zA-Z]*R/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*head/.test(cmd);
13179
+ return /^eza\s+.*--long\s+\S+/.test(cmd) || /^eza\s+.*--tree/.test(cmd) || /^tree(\s|$)/.test(cmd) || /^ls\s+.*-[a-zA-Z]*R/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*head/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*grep/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*wc/.test(cmd);
13180
+ }
13181
+ function extractForLoopWcL(cmd) {
13182
+ return /^for\s+\w+\s+in\s+.*;\s*do\s+wc\s+-l/.test(cmd);
13172
13183
  }
13173
13184
  function extractFindCommand(cmd) {
13174
13185
  if (!/^find\b/.test(cmd)) return null;
@@ -13247,8 +13258,10 @@ function buildRecallHint(cmd, outputId) {
13247
13258
  return "Output from a prior `" + cmdPreview + "` run is cached. Use `token-goat bash-output " + outputId + "` (or `--tail 50`, `--grep ERROR`) to re-inspect it without re-running.";
13248
13259
  }
13249
13260
  function preBashHandler(event) {
13250
- const cmd = extractCommand(event);
13251
- if (cmd === void 0) return passOutput();
13261
+ const rawCmd = extractCommand(event);
13262
+ if (rawCmd === void 0) return passOutput();
13263
+ const cmd = stripCdPrefix(rawCmd);
13264
+ const cdStripped = cmd !== rawCmd;
13252
13265
  const taskOutput = extractTasksOutput(cmd);
13253
13266
  if (taskOutput !== null) {
13254
13267
  const { id } = taskOutput;
@@ -13277,6 +13290,12 @@ function preBashHandler(event) {
13277
13290
  "Use `token-goat map --compact` (~300 tokens) for a repo overview, or `token-goat map <dir>` for a subdirectory."
13278
13291
  );
13279
13292
  }
13293
+ if (extractForLoopWcL(cmd)) {
13294
+ recordStat("session_hint", 0, 0);
13295
+ return contextOutput(
13296
+ "Use `token-goat outline <file>` to see symbol names and line counts without loading files."
13297
+ );
13298
+ }
13280
13299
  if (extractSedLineRange(cmd)) {
13281
13300
  recordStat("session_hint", 0, 0);
13282
13301
  return contextOutput(
@@ -13301,7 +13320,7 @@ function preBashHandler(event) {
13301
13320
  );
13302
13321
  }
13303
13322
  const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
13304
- return denyOutput("`cat` loads the entire file into context. " + hint);
13323
+ return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
13305
13324
  }
13306
13325
  const wslCatResult = extractWslCatFile(cmd);
13307
13326
  if (wslCatResult !== null) {
@@ -13313,14 +13332,14 @@ function preBashHandler(event) {
13313
13332
  );
13314
13333
  }
13315
13334
  const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
13316
- return denyOutput("`cat` loads the entire file into context. " + hint);
13335
+ return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
13317
13336
  }
13318
13337
  const pyRead = extractPythonFileRead(cmd);
13319
13338
  if (pyRead !== null) {
13320
13339
  const { filePath, isDoc } = pyRead;
13321
13340
  const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
13322
13341
  recordStat("session_hint", 0, 0);
13323
- return denyOutput("Python `open()` file reads bypass read hooks. " + hint);
13342
+ return cdStripped ? contextOutput("Python `open()` file reads bypass read hooks. " + hint) : denyOutput("Python `open()` file reads bypass read hooks. " + hint);
13324
13343
  }
13325
13344
  const tailResult = extractTailFile(cmd);
13326
13345
  if (tailResult !== null) {
@@ -13341,7 +13360,7 @@ function preBashHandler(event) {
13341
13360
  const { filePath, isDoc, isConfig } = nodeRead;
13342
13361
  const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
13343
13362
  recordStat("session_hint", 0, 0);
13344
- return denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
13363
+ return cdStripped ? contextOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint) : denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
13345
13364
  }
13346
13365
  if (extractGrepPipeChain(cmd)) {
13347
13366
  recordStat("session_hint", 0, 0);
@@ -13442,8 +13461,9 @@ function extractBashOutput(raw) {
13442
13461
  }
13443
13462
  async function postBashHandler(event) {
13444
13463
  try {
13445
- const cmd = extractCommand(event);
13446
- if (cmd === void 0) return passOutput();
13464
+ const rawCmd = extractCommand(event);
13465
+ if (rawCmd === void 0) return passOutput();
13466
+ const cmd = stripCdPrefix(rawCmd);
13447
13467
  const curlDl = extractCurlDownload(cmd);
13448
13468
  if (curlDl !== null) {
13449
13469
  recordCurlDownload(curlDl.url, curlDl.outputPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-goat",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
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",