token-goat 2.2.0 → 2.2.2

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 +42 -13
  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.2";
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,11 +10883,22 @@ 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"' },
10887
10891
  // cat of a single source file — output is the full file; pre-bash emits a token-goat read suggestion
10888
- { pattern: /^cat\s+\S+\.(java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj)\s*$/, recallHint: "--tail 50" }
10892
+ { pattern: /^cat\s+\S+\.(java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj)\s*$/, recallHint: "--tail 50" },
10893
+ // PowerShell read-only system-state queries (stable over 60-120s)
10894
+ {
10895
+ pattern: /^(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\s+(?:-\w+\s+)*-Command\s+["']?Get-(?:CimInstance|Process|Counter|Service|PSDrive|WmiObject)\b/i,
10896
+ recallHint: "--tail 50"
10897
+ },
10898
+ // token-goat section/outline/symbol repeat calls — output is stable until the file changes
10899
+ { pattern: /^token-goat\s+section\s+["'][^"']+["']/, recallHint: "" },
10900
+ { pattern: /^token-goat\s+outline\s+\S+/, recallHint: "" },
10901
+ { pattern: /^token-goat\s+symbol\s+\S+/, recallHint: "" }
10889
10902
  ];
10890
10903
  function getMonitoringRecallHint(cmd) {
10891
10904
  for (const { pattern, recallHint } of MONITORING_COMMAND_PATTERNS) {
@@ -12956,6 +12969,10 @@ registerReset(() => {
12956
12969
  });
12957
12970
 
12958
12971
  // src/hooks_bash.ts
12972
+ function stripCdPrefix(cmd) {
12973
+ const stripped = cmd.replace(/^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)\s*&&\s*)+/, "");
12974
+ return stripped.trim() || cmd;
12975
+ }
12959
12976
  function extractCommand(event) {
12960
12977
  const cmd = event.toolInput["command"];
12961
12978
  return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
@@ -13168,7 +13185,10 @@ function extractSedLineRange(cmd) {
13168
13185
  return /^sed\s+-n\s+['"]?\d+,\d+p['"]?/.test(cmd);
13169
13186
  }
13170
13187
  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);
13188
+ 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);
13189
+ }
13190
+ function extractForLoopWcL(cmd) {
13191
+ return /^for\s+\w+\s+in\s+.*;\s*do\s+wc\s+-l/.test(cmd);
13172
13192
  }
13173
13193
  function extractFindCommand(cmd) {
13174
13194
  if (!/^find\b/.test(cmd)) return null;
@@ -13247,8 +13267,10 @@ function buildRecallHint(cmd, outputId) {
13247
13267
  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
13268
  }
13249
13269
  function preBashHandler(event) {
13250
- const cmd = extractCommand(event);
13251
- if (cmd === void 0) return passOutput();
13270
+ const rawCmd = extractCommand(event);
13271
+ if (rawCmd === void 0) return passOutput();
13272
+ const cmd = stripCdPrefix(rawCmd);
13273
+ const cdStripped = cmd !== rawCmd;
13252
13274
  const taskOutput = extractTasksOutput(cmd);
13253
13275
  if (taskOutput !== null) {
13254
13276
  const { id } = taskOutput;
@@ -13277,6 +13299,12 @@ function preBashHandler(event) {
13277
13299
  "Use `token-goat map --compact` (~300 tokens) for a repo overview, or `token-goat map <dir>` for a subdirectory."
13278
13300
  );
13279
13301
  }
13302
+ if (extractForLoopWcL(cmd)) {
13303
+ recordStat("session_hint", 0, 0);
13304
+ return contextOutput(
13305
+ "Use `token-goat outline <file>` to see symbol names and line counts without loading files."
13306
+ );
13307
+ }
13280
13308
  if (extractSedLineRange(cmd)) {
13281
13309
  recordStat("session_hint", 0, 0);
13282
13310
  return contextOutput(
@@ -13301,7 +13329,7 @@ function preBashHandler(event) {
13301
13329
  );
13302
13330
  }
13303
13331
  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);
13332
+ return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
13305
13333
  }
13306
13334
  const wslCatResult = extractWslCatFile(cmd);
13307
13335
  if (wslCatResult !== null) {
@@ -13313,14 +13341,14 @@ function preBashHandler(event) {
13313
13341
  );
13314
13342
  }
13315
13343
  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);
13344
+ return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
13317
13345
  }
13318
13346
  const pyRead = extractPythonFileRead(cmd);
13319
13347
  if (pyRead !== null) {
13320
13348
  const { filePath, isDoc } = pyRead;
13321
13349
  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
13350
  recordStat("session_hint", 0, 0);
13323
- return denyOutput("Python `open()` file reads bypass read hooks. " + hint);
13351
+ return cdStripped ? contextOutput("Python `open()` file reads bypass read hooks. " + hint) : denyOutput("Python `open()` file reads bypass read hooks. " + hint);
13324
13352
  }
13325
13353
  const tailResult = extractTailFile(cmd);
13326
13354
  if (tailResult !== null) {
@@ -13341,7 +13369,7 @@ function preBashHandler(event) {
13341
13369
  const { filePath, isDoc, isConfig } = nodeRead;
13342
13370
  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
13371
  recordStat("session_hint", 0, 0);
13344
- return denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
13372
+ return cdStripped ? contextOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint) : denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
13345
13373
  }
13346
13374
  if (extractGrepPipeChain(cmd)) {
13347
13375
  recordStat("session_hint", 0, 0);
@@ -13442,8 +13470,9 @@ function extractBashOutput(raw) {
13442
13470
  }
13443
13471
  async function postBashHandler(event) {
13444
13472
  try {
13445
- const cmd = extractCommand(event);
13446
- if (cmd === void 0) return passOutput();
13473
+ const rawCmd = extractCommand(event);
13474
+ if (rawCmd === void 0) return passOutput();
13475
+ const cmd = stripCdPrefix(rawCmd);
13447
13476
  const curlDl = extractCurlDownload(cmd);
13448
13477
  if (curlDl !== null) {
13449
13478
  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.2",
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",