token-goat 2.0.0 → 2.0.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.
- package/README.md +46 -124
- package/dist/token-goat.mjs +1481 -112
- package/package.json +1 -1
package/dist/token-goat.mjs
CHANGED
|
@@ -981,7 +981,7 @@ var require_command = __commonJS({
|
|
|
981
981
|
init_define_import_meta_env();
|
|
982
982
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
983
983
|
var childProcess = __require("node:child_process");
|
|
984
|
-
var
|
|
984
|
+
var path14 = __require("node:path");
|
|
985
985
|
var fs14 = __require("node:fs");
|
|
986
986
|
var process2 = __require("node:process");
|
|
987
987
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -1914,9 +1914,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1914
1914
|
let launchWithNode = false;
|
|
1915
1915
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1916
1916
|
function findFile(baseDir, baseName) {
|
|
1917
|
-
const localBin =
|
|
1917
|
+
const localBin = path14.resolve(baseDir, baseName);
|
|
1918
1918
|
if (fs14.existsSync(localBin)) return localBin;
|
|
1919
|
-
if (sourceExt.includes(
|
|
1919
|
+
if (sourceExt.includes(path14.extname(baseName))) return void 0;
|
|
1920
1920
|
const foundExt = sourceExt.find(
|
|
1921
1921
|
(ext) => fs14.existsSync(`${localBin}${ext}`)
|
|
1922
1922
|
);
|
|
@@ -1934,17 +1934,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1934
1934
|
} catch (err2) {
|
|
1935
1935
|
resolvedScriptPath = this._scriptPath;
|
|
1936
1936
|
}
|
|
1937
|
-
executableDir =
|
|
1938
|
-
|
|
1937
|
+
executableDir = path14.resolve(
|
|
1938
|
+
path14.dirname(resolvedScriptPath),
|
|
1939
1939
|
executableDir
|
|
1940
1940
|
);
|
|
1941
1941
|
}
|
|
1942
1942
|
if (executableDir) {
|
|
1943
1943
|
let localFile = findFile(executableDir, executableFile);
|
|
1944
1944
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1945
|
-
const legacyName =
|
|
1945
|
+
const legacyName = path14.basename(
|
|
1946
1946
|
this._scriptPath,
|
|
1947
|
-
|
|
1947
|
+
path14.extname(this._scriptPath)
|
|
1948
1948
|
);
|
|
1949
1949
|
if (legacyName !== this._name) {
|
|
1950
1950
|
localFile = findFile(
|
|
@@ -1955,7 +1955,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1955
1955
|
}
|
|
1956
1956
|
executableFile = localFile || executableFile;
|
|
1957
1957
|
}
|
|
1958
|
-
launchWithNode = sourceExt.includes(
|
|
1958
|
+
launchWithNode = sourceExt.includes(path14.extname(executableFile));
|
|
1959
1959
|
let proc;
|
|
1960
1960
|
if (process2.platform !== "win32") {
|
|
1961
1961
|
if (launchWithNode) {
|
|
@@ -2795,7 +2795,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2795
2795
|
* @return {Command}
|
|
2796
2796
|
*/
|
|
2797
2797
|
nameFromFilename(filename) {
|
|
2798
|
-
this._name =
|
|
2798
|
+
this._name = path14.basename(filename, path14.extname(filename));
|
|
2799
2799
|
return this;
|
|
2800
2800
|
}
|
|
2801
2801
|
/**
|
|
@@ -2809,9 +2809,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2809
2809
|
* @param {string} [path]
|
|
2810
2810
|
* @return {(string|null|Command)}
|
|
2811
2811
|
*/
|
|
2812
|
-
executableDir(
|
|
2813
|
-
if (
|
|
2814
|
-
this._executableDir =
|
|
2812
|
+
executableDir(path15) {
|
|
2813
|
+
if (path15 === void 0) return this._executableDir;
|
|
2814
|
+
this._executableDir = path15;
|
|
2815
2815
|
return this;
|
|
2816
2816
|
}
|
|
2817
2817
|
/**
|
|
@@ -3162,16 +3162,16 @@ var require_filesystem = __commonJS({
|
|
|
3162
3162
|
var LDD_PATH = "/usr/bin/ldd";
|
|
3163
3163
|
var SELF_PATH = "/proc/self/exe";
|
|
3164
3164
|
var MAX_LENGTH = 2048;
|
|
3165
|
-
var
|
|
3166
|
-
const fd = fs14.openSync(
|
|
3165
|
+
var readFileSync11 = (path14) => {
|
|
3166
|
+
const fd = fs14.openSync(path14, "r");
|
|
3167
3167
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
3168
3168
|
const bytesRead = fs14.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
3169
3169
|
fs14.close(fd, () => {
|
|
3170
3170
|
});
|
|
3171
3171
|
return buffer.subarray(0, bytesRead);
|
|
3172
3172
|
};
|
|
3173
|
-
var readFile2 = (
|
|
3174
|
-
fs14.open(
|
|
3173
|
+
var readFile2 = (path14) => new Promise((resolve4, reject) => {
|
|
3174
|
+
fs14.open(path14, "r", (err2, fd) => {
|
|
3175
3175
|
if (err2) {
|
|
3176
3176
|
reject(err2);
|
|
3177
3177
|
} else {
|
|
@@ -3187,7 +3187,7 @@ var require_filesystem = __commonJS({
|
|
|
3187
3187
|
module.exports = {
|
|
3188
3188
|
LDD_PATH,
|
|
3189
3189
|
SELF_PATH,
|
|
3190
|
-
readFileSync:
|
|
3190
|
+
readFileSync: readFileSync11,
|
|
3191
3191
|
readFile: readFile2
|
|
3192
3192
|
};
|
|
3193
3193
|
}
|
|
@@ -3238,7 +3238,7 @@ var require_detect_libc = __commonJS({
|
|
|
3238
3238
|
init_define_import_meta_env();
|
|
3239
3239
|
var childProcess = __require("child_process");
|
|
3240
3240
|
var { isLinux, getReport } = require_process();
|
|
3241
|
-
var { LDD_PATH, SELF_PATH, readFile: readFile2, readFileSync:
|
|
3241
|
+
var { LDD_PATH, SELF_PATH, readFile: readFile2, readFileSync: readFileSync11 } = require_filesystem();
|
|
3242
3242
|
var { interpreterPath } = require_elf();
|
|
3243
3243
|
var cachedFamilyInterpreter;
|
|
3244
3244
|
var cachedFamilyFilesystem;
|
|
@@ -3292,11 +3292,11 @@ var require_detect_libc = __commonJS({
|
|
|
3292
3292
|
}
|
|
3293
3293
|
return null;
|
|
3294
3294
|
};
|
|
3295
|
-
var familyFromInterpreterPath = (
|
|
3296
|
-
if (
|
|
3297
|
-
if (
|
|
3295
|
+
var familyFromInterpreterPath = (path14) => {
|
|
3296
|
+
if (path14) {
|
|
3297
|
+
if (path14.includes("/ld-musl-")) {
|
|
3298
3298
|
return MUSL;
|
|
3299
|
-
} else if (
|
|
3299
|
+
} else if (path14.includes("/ld-linux-")) {
|
|
3300
3300
|
return GLIBC;
|
|
3301
3301
|
}
|
|
3302
3302
|
}
|
|
@@ -3330,7 +3330,7 @@ var require_detect_libc = __commonJS({
|
|
|
3330
3330
|
}
|
|
3331
3331
|
cachedFamilyFilesystem = null;
|
|
3332
3332
|
try {
|
|
3333
|
-
const lddContent =
|
|
3333
|
+
const lddContent = readFileSync11(LDD_PATH);
|
|
3334
3334
|
cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
|
|
3335
3335
|
} catch (e) {
|
|
3336
3336
|
}
|
|
@@ -3343,8 +3343,8 @@ var require_detect_libc = __commonJS({
|
|
|
3343
3343
|
cachedFamilyInterpreter = null;
|
|
3344
3344
|
try {
|
|
3345
3345
|
const selfContent = await readFile2(SELF_PATH);
|
|
3346
|
-
const
|
|
3347
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
3346
|
+
const path14 = interpreterPath(selfContent);
|
|
3347
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path14);
|
|
3348
3348
|
} catch (e) {
|
|
3349
3349
|
}
|
|
3350
3350
|
return cachedFamilyInterpreter;
|
|
@@ -3355,9 +3355,9 @@ var require_detect_libc = __commonJS({
|
|
|
3355
3355
|
}
|
|
3356
3356
|
cachedFamilyInterpreter = null;
|
|
3357
3357
|
try {
|
|
3358
|
-
const selfContent =
|
|
3359
|
-
const
|
|
3360
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
3358
|
+
const selfContent = readFileSync11(SELF_PATH);
|
|
3359
|
+
const path14 = interpreterPath(selfContent);
|
|
3360
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path14);
|
|
3361
3361
|
} catch (e) {
|
|
3362
3362
|
}
|
|
3363
3363
|
return cachedFamilyInterpreter;
|
|
@@ -3419,7 +3419,7 @@ var require_detect_libc = __commonJS({
|
|
|
3419
3419
|
}
|
|
3420
3420
|
cachedVersionFilesystem = null;
|
|
3421
3421
|
try {
|
|
3422
|
-
const lddContent =
|
|
3422
|
+
const lddContent = readFileSync11(LDD_PATH);
|
|
3423
3423
|
const versionMatch = lddContent.match(RE_GLIBC_VERSION);
|
|
3424
3424
|
if (versionMatch) {
|
|
3425
3425
|
cachedVersionFilesystem = versionMatch[1];
|
|
@@ -5138,9 +5138,9 @@ var require_sharp = __commonJS({
|
|
|
5138
5138
|
];
|
|
5139
5139
|
var sharp;
|
|
5140
5140
|
var errors = [];
|
|
5141
|
-
for (const
|
|
5141
|
+
for (const path14 of paths) {
|
|
5142
5142
|
try {
|
|
5143
|
-
sharp = __require(
|
|
5143
|
+
sharp = __require(path14);
|
|
5144
5144
|
break;
|
|
5145
5145
|
} catch (err2) {
|
|
5146
5146
|
errors.push(err2);
|
|
@@ -6552,15 +6552,15 @@ var require_route = __commonJS({
|
|
|
6552
6552
|
};
|
|
6553
6553
|
}
|
|
6554
6554
|
function wrapConversion(toModel, graph) {
|
|
6555
|
-
const
|
|
6555
|
+
const path14 = [graph[toModel].parent, toModel];
|
|
6556
6556
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
6557
6557
|
let cur = graph[toModel].parent;
|
|
6558
6558
|
while (graph[cur].parent) {
|
|
6559
|
-
|
|
6559
|
+
path14.unshift(graph[cur].parent);
|
|
6560
6560
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
6561
6561
|
cur = graph[cur].parent;
|
|
6562
6562
|
}
|
|
6563
|
-
fn.conversion =
|
|
6563
|
+
fn.conversion = path14;
|
|
6564
6564
|
return fn;
|
|
6565
6565
|
}
|
|
6566
6566
|
module.exports = function(fromModel) {
|
|
@@ -8464,7 +8464,7 @@ var require_output = __commonJS({
|
|
|
8464
8464
|
"node_modules/sharp/lib/output.js"(exports, module) {
|
|
8465
8465
|
"use strict";
|
|
8466
8466
|
init_define_import_meta_env();
|
|
8467
|
-
var
|
|
8467
|
+
var path14 = __require("node:path");
|
|
8468
8468
|
var is = require_is();
|
|
8469
8469
|
var sharp = require_sharp();
|
|
8470
8470
|
var formats = /* @__PURE__ */ new Map([
|
|
@@ -8495,9 +8495,9 @@ var require_output = __commonJS({
|
|
|
8495
8495
|
let err2;
|
|
8496
8496
|
if (!is.string(fileOut)) {
|
|
8497
8497
|
err2 = new Error("Missing output file path");
|
|
8498
|
-
} else if (is.string(this.options.input.file) &&
|
|
8498
|
+
} else if (is.string(this.options.input.file) && path14.resolve(this.options.input.file) === path14.resolve(fileOut)) {
|
|
8499
8499
|
err2 = new Error("Cannot use same file for input and output");
|
|
8500
|
-
} else if (jp2Regex.test(
|
|
8500
|
+
} else if (jp2Regex.test(path14.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
|
|
8501
8501
|
err2 = errJp2Save();
|
|
8502
8502
|
}
|
|
8503
8503
|
if (err2) {
|
|
@@ -9492,7 +9492,7 @@ init_define_import_meta_env();
|
|
|
9492
9492
|
import { createRequire } from "node:module";
|
|
9493
9493
|
function resolveVersion() {
|
|
9494
9494
|
if (true) {
|
|
9495
|
-
return "2.0.
|
|
9495
|
+
return "2.0.1";
|
|
9496
9496
|
}
|
|
9497
9497
|
const require2 = createRequire(import.meta.url);
|
|
9498
9498
|
const pkg = require2("../package.json");
|
|
@@ -10125,23 +10125,23 @@ function isNoisePath(inputPath) {
|
|
|
10125
10125
|
}
|
|
10126
10126
|
}
|
|
10127
10127
|
const slashIdx = p.lastIndexOf("/");
|
|
10128
|
-
const
|
|
10129
|
-
if (NOISE_BASENAMES.has(
|
|
10128
|
+
const basename6 = slashIdx >= 0 ? p.slice(slashIdx + 1) : p;
|
|
10129
|
+
if (NOISE_BASENAMES.has(basename6)) {
|
|
10130
10130
|
return true;
|
|
10131
10131
|
}
|
|
10132
|
-
if (
|
|
10132
|
+
if (basename6.startsWith(".improve-state-") || basename6.startsWith("improve_commit_msg_")) {
|
|
10133
10133
|
return true;
|
|
10134
10134
|
}
|
|
10135
|
-
const dotIdx =
|
|
10135
|
+
const dotIdx = basename6.lastIndexOf(".");
|
|
10136
10136
|
if (dotIdx >= 0) {
|
|
10137
|
-
const ext =
|
|
10137
|
+
const ext = basename6.slice(dotIdx);
|
|
10138
10138
|
if (NOISE_EXTS.has(ext)) {
|
|
10139
10139
|
return true;
|
|
10140
10140
|
}
|
|
10141
10141
|
}
|
|
10142
10142
|
for (const ext of NOISE_EXTS) {
|
|
10143
10143
|
if (ext.includes(".") && ext.split(".").length > 2) {
|
|
10144
|
-
if (
|
|
10144
|
+
if (basename6.endsWith(ext)) {
|
|
10145
10145
|
return true;
|
|
10146
10146
|
}
|
|
10147
10147
|
}
|
|
@@ -10297,6 +10297,9 @@ function wasFileReadThisSession(filePath) {
|
|
|
10297
10297
|
function getSessionWebFetches() {
|
|
10298
10298
|
return _webFetches;
|
|
10299
10299
|
}
|
|
10300
|
+
function getBashOutputId(commandHash) {
|
|
10301
|
+
return _bashOutputs.get(commandHash) ?? null;
|
|
10302
|
+
}
|
|
10300
10303
|
registerReset(() => {
|
|
10301
10304
|
_files = /* @__PURE__ */ new Map();
|
|
10302
10305
|
_hintsShown = /* @__PURE__ */ new Set();
|
|
@@ -10362,6 +10365,7 @@ var HOOK_EVENTS = [
|
|
|
10362
10365
|
// src/hooks_read.ts
|
|
10363
10366
|
init_define_import_meta_env();
|
|
10364
10367
|
import * as fs4 from "node:fs";
|
|
10368
|
+
import * as path6 from "node:path";
|
|
10365
10369
|
|
|
10366
10370
|
// src/hooks_common.ts
|
|
10367
10371
|
init_define_import_meta_env();
|
|
@@ -10378,12 +10382,483 @@ function getFilePath(event) {
|
|
|
10378
10382
|
function passOutput() {
|
|
10379
10383
|
return { hookType: "pass" };
|
|
10380
10384
|
}
|
|
10385
|
+
function denyOutput(message) {
|
|
10386
|
+
return { hookType: "deny", message };
|
|
10387
|
+
}
|
|
10381
10388
|
function contextOutput(context) {
|
|
10382
10389
|
return { hookType: "context", context };
|
|
10383
10390
|
}
|
|
10384
10391
|
|
|
10392
|
+
// src/hints.ts
|
|
10393
|
+
init_define_import_meta_env();
|
|
10394
|
+
var HINT_PRIORITY_MEDIUM = 3;
|
|
10395
|
+
var STALE_READ_AGE_SECONDS = 30 * 60;
|
|
10396
|
+
function buildPackageManifestHint(options) {
|
|
10397
|
+
try {
|
|
10398
|
+
const hasOffset = options.offset !== null && options.offset !== void 0 && options.offset >= 0;
|
|
10399
|
+
const hasLimit = options.limit !== null && options.limit !== void 0 && options.limit > 0;
|
|
10400
|
+
if (hasOffset || hasLimit) {
|
|
10401
|
+
return null;
|
|
10402
|
+
}
|
|
10403
|
+
const fname = _sanitizeHintPath(options.file_path.split(/[/\\]/).pop() ?? "");
|
|
10404
|
+
const basenameLower = fname.toLowerCase();
|
|
10405
|
+
if (basenameLower === "package.json") {
|
|
10406
|
+
const text = `\`${fname}\` is a package manifest. Consider \`token-goat section package.json::dependencies\` or \`token-goat section package.json::devDependencies\` for focused reads.`;
|
|
10407
|
+
return {
|
|
10408
|
+
text,
|
|
10409
|
+
hint_priority: HINT_PRIORITY_MEDIUM
|
|
10410
|
+
};
|
|
10411
|
+
}
|
|
10412
|
+
if (basenameLower === "package-lock.json") {
|
|
10413
|
+
const text = `\`${fname}\` is a large lockfile. Consider \`npm ls\`, \`npm outdated\`, or \`npm audit\` instead for targeted info.`;
|
|
10414
|
+
return {
|
|
10415
|
+
text,
|
|
10416
|
+
hint_priority: HINT_PRIORITY_MEDIUM
|
|
10417
|
+
};
|
|
10418
|
+
}
|
|
10419
|
+
return null;
|
|
10420
|
+
} catch {
|
|
10421
|
+
return null;
|
|
10422
|
+
}
|
|
10423
|
+
}
|
|
10424
|
+
function _sanitizeHintPath(path14) {
|
|
10425
|
+
if (typeof path14 !== "string") {
|
|
10426
|
+
return "???";
|
|
10427
|
+
}
|
|
10428
|
+
return path14.replace(/[\x00]/g, "").slice(0, 200);
|
|
10429
|
+
}
|
|
10430
|
+
|
|
10431
|
+
// src/hints/lang_patterns.ts
|
|
10432
|
+
init_define_import_meta_env();
|
|
10433
|
+
var LOCK_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
10434
|
+
"package-lock.json",
|
|
10435
|
+
"yarn.lock",
|
|
10436
|
+
"pnpm-lock.yaml",
|
|
10437
|
+
"cargo.lock",
|
|
10438
|
+
"poetry.lock",
|
|
10439
|
+
"pipfile.lock",
|
|
10440
|
+
"uv.lock",
|
|
10441
|
+
"gemfile.lock",
|
|
10442
|
+
"go.sum",
|
|
10443
|
+
"composer.lock",
|
|
10444
|
+
"mix.lock",
|
|
10445
|
+
"pubspec.lock",
|
|
10446
|
+
"package.resolved"
|
|
10447
|
+
]);
|
|
10448
|
+
var MANIFEST_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
10449
|
+
"package.json",
|
|
10450
|
+
"pyproject.toml",
|
|
10451
|
+
"cargo.toml",
|
|
10452
|
+
"go.mod",
|
|
10453
|
+
"go.work",
|
|
10454
|
+
"pom.xml",
|
|
10455
|
+
"build.gradle",
|
|
10456
|
+
"build.gradle.kts",
|
|
10457
|
+
"settings.gradle",
|
|
10458
|
+
"composer.json",
|
|
10459
|
+
"gemfile",
|
|
10460
|
+
"mix.exs",
|
|
10461
|
+
"pubspec.yaml",
|
|
10462
|
+
"cmakelists.txt",
|
|
10463
|
+
"makefile",
|
|
10464
|
+
"project.clj",
|
|
10465
|
+
// TypeScript / JavaScript project configs
|
|
10466
|
+
"tsconfig.json",
|
|
10467
|
+
"jsconfig.json",
|
|
10468
|
+
// Bundler / framework configs
|
|
10469
|
+
"vite.config.ts",
|
|
10470
|
+
"vite.config.js",
|
|
10471
|
+
"webpack.config.js",
|
|
10472
|
+
"webpack.config.ts",
|
|
10473
|
+
"rollup.config.js",
|
|
10474
|
+
"rollup.config.ts",
|
|
10475
|
+
"esbuild.config.js",
|
|
10476
|
+
"next.config.js",
|
|
10477
|
+
"next.config.ts",
|
|
10478
|
+
"nuxt.config.ts"
|
|
10479
|
+
]);
|
|
10480
|
+
var MANIFEST_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
10481
|
+
".cabal"
|
|
10482
|
+
]);
|
|
10483
|
+
var MANIFEST_BASENAME_PATTERNS = [
|
|
10484
|
+
/^tsconfig(\..+)?\.json$/i
|
|
10485
|
+
];
|
|
10486
|
+
var BUILD_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
10487
|
+
"dist",
|
|
10488
|
+
"target",
|
|
10489
|
+
"build",
|
|
10490
|
+
"out",
|
|
10491
|
+
"__pycache__",
|
|
10492
|
+
".next",
|
|
10493
|
+
".nuxt",
|
|
10494
|
+
".output",
|
|
10495
|
+
".gradle",
|
|
10496
|
+
"_build",
|
|
10497
|
+
".build",
|
|
10498
|
+
"pkg",
|
|
10499
|
+
"obj"
|
|
10500
|
+
]);
|
|
10501
|
+
var ALWAYS_GENERATED_EXTS = /* @__PURE__ */ new Set([
|
|
10502
|
+
".pyc",
|
|
10503
|
+
".pyo",
|
|
10504
|
+
".pyd",
|
|
10505
|
+
".class",
|
|
10506
|
+
".o",
|
|
10507
|
+
".a",
|
|
10508
|
+
".so",
|
|
10509
|
+
".dylib",
|
|
10510
|
+
".dll",
|
|
10511
|
+
".tsbuildinfo"
|
|
10512
|
+
]);
|
|
10513
|
+
var CONDITIONALLY_GENERATED_EXTS = /* @__PURE__ */ new Set([
|
|
10514
|
+
".map",
|
|
10515
|
+
".d.ts"
|
|
10516
|
+
]);
|
|
10517
|
+
var BUILD_COMMAND_PATTERNS = [
|
|
10518
|
+
// Rust / Cargo
|
|
10519
|
+
/^\s*cargo\s+(build|test|run|check|clippy)\b/i,
|
|
10520
|
+
// Go
|
|
10521
|
+
/^\s*go\s+(build|test|run|vet)\b/i,
|
|
10522
|
+
// Maven
|
|
10523
|
+
/^\s*mvn\b/i,
|
|
10524
|
+
// Gradle (direct or wrapper)
|
|
10525
|
+
/^\s*(?:gradle|\.\/gradlew|gradlew)\b/i,
|
|
10526
|
+
// Python / pip
|
|
10527
|
+
/^\s*pip\s+(install|freeze)\b/i,
|
|
10528
|
+
// Poetry
|
|
10529
|
+
/^\s*poetry\s+(install|update)\b/i,
|
|
10530
|
+
// uv
|
|
10531
|
+
/^\s*uv\s+(sync|pip\s+install)\b/i,
|
|
10532
|
+
// Bundler (Ruby)
|
|
10533
|
+
/^\s*bundle\s+(install|update)\b/i,
|
|
10534
|
+
// Mix (Elixir)
|
|
10535
|
+
/^\s*mix\s+(deps\.get|compile|test)\b/i,
|
|
10536
|
+
// dotnet
|
|
10537
|
+
/^\s*dotnet\s+(build|test|restore)\b/i,
|
|
10538
|
+
// Make
|
|
10539
|
+
/^\s*make\b/i,
|
|
10540
|
+
// CMake build
|
|
10541
|
+
/^\s*cmake\s+--build\b/i,
|
|
10542
|
+
// Rake (Ruby)
|
|
10543
|
+
/^\s*rake\b/i,
|
|
10544
|
+
// TypeScript compiler
|
|
10545
|
+
/^\s*tsc\b/i,
|
|
10546
|
+
// Vite
|
|
10547
|
+
/^\s*vite\s+(build|dev|preview)\b/i,
|
|
10548
|
+
// Next.js
|
|
10549
|
+
/^\s*next\s+(build|dev|start)\b/i,
|
|
10550
|
+
// Nuxt
|
|
10551
|
+
/^\s*nuxt\s+(build|dev)\b/i,
|
|
10552
|
+
// Webpack
|
|
10553
|
+
/^\s*webpack\b/i,
|
|
10554
|
+
// esbuild
|
|
10555
|
+
/^\s*esbuild\b/i,
|
|
10556
|
+
// Rollup
|
|
10557
|
+
/^\s*rollup\b/i,
|
|
10558
|
+
// Turbo
|
|
10559
|
+
/^\s*turbo\s+(build|dev)\b/i
|
|
10560
|
+
];
|
|
10561
|
+
function isLockFile(basename6) {
|
|
10562
|
+
return LOCK_FILE_NAMES.has(basename6.toLowerCase());
|
|
10563
|
+
}
|
|
10564
|
+
function isManifestFile(basename6) {
|
|
10565
|
+
const lower = basename6.toLowerCase();
|
|
10566
|
+
if (MANIFEST_FILE_NAMES.has(lower)) return true;
|
|
10567
|
+
const dot = lower.lastIndexOf(".");
|
|
10568
|
+
if (dot !== -1 && MANIFEST_EXTENSIONS.has(lower.slice(dot))) return true;
|
|
10569
|
+
if (MANIFEST_BASENAME_PATTERNS.some((re) => re.test(basename6))) return true;
|
|
10570
|
+
return false;
|
|
10571
|
+
}
|
|
10572
|
+
function pathSegments(filePath) {
|
|
10573
|
+
return filePath.split(/[/\\]/).filter((s) => s.length > 0);
|
|
10574
|
+
}
|
|
10575
|
+
function isInBuildDir(filePath) {
|
|
10576
|
+
const segments = pathSegments(filePath);
|
|
10577
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
10578
|
+
const seg = segments[i];
|
|
10579
|
+
if (seg !== void 0 && BUILD_DIR_NAMES.has(seg.toLowerCase())) return true;
|
|
10580
|
+
}
|
|
10581
|
+
return false;
|
|
10582
|
+
}
|
|
10583
|
+
function isGeneratedFile(filePath) {
|
|
10584
|
+
const lower = filePath.toLowerCase();
|
|
10585
|
+
for (const ext of ALWAYS_GENERATED_EXTS) {
|
|
10586
|
+
if (lower.endsWith(ext)) return true;
|
|
10587
|
+
}
|
|
10588
|
+
for (const ext of CONDITIONALLY_GENERATED_EXTS) {
|
|
10589
|
+
if (lower.endsWith(ext) && isInBuildDir(filePath)) return true;
|
|
10590
|
+
}
|
|
10591
|
+
return false;
|
|
10592
|
+
}
|
|
10593
|
+
function isBuildCommand(cmd) {
|
|
10594
|
+
return BUILD_COMMAND_PATTERNS.some((re) => re.test(cmd));
|
|
10595
|
+
}
|
|
10596
|
+
var MONITORING_COMMAND_PATTERNS = [
|
|
10597
|
+
// GitHub CI
|
|
10598
|
+
{ pattern: /^gh run (?:watch|view|list)/, recallHint: '--grep "fail|error|pass|\u2713|\u2717|conclusion"' },
|
|
10599
|
+
{ pattern: /^gh run view.*--log/, recallHint: '--tail 100 --grep "Error|FAIL|error"' },
|
|
10600
|
+
{ pattern: /^gh pr checks/, recallHint: '--grep "fail|error|pass|pending"' },
|
|
10601
|
+
{ pattern: /^gh workflow (?:run|list|view)/, recallHint: '--grep "completed|failed|in_progress"' },
|
|
10602
|
+
// Dev servers (Next, Vite, Nuxt, Remix, Astro)
|
|
10603
|
+
{ pattern: /^(?:npx\s+)?next dev/, recallHint: '--tail 30 --grep "error|warn|ready|compiled"' },
|
|
10604
|
+
{ pattern: /^(?:npx\s+)?next build/, recallHint: '--grep "error|warn|Failed|\u2713"' },
|
|
10605
|
+
{ pattern: /^(?:npx\s+)?vite(?:\s+dev|\s+build|\s+preview)?$/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
10606
|
+
{ pattern: /^(?:npx\s+)?nuxt dev/, recallHint: '--tail 30 --grep "error|warn|ready"' },
|
|
10607
|
+
{ pattern: /^(?:npx\s+)?remix dev/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
10608
|
+
{ pattern: /^(?:npx\s+)?astro dev/, recallHint: '--tail 20 --grep "error|warn|ready"' },
|
|
10609
|
+
// Test watchers
|
|
10610
|
+
{ pattern: /^(?:npx\s+)?vitest(?:\s+run|\s+watch)?/, recallHint: '--grep "FAIL|PASS|Error|\u2713|\u2717"' },
|
|
10611
|
+
{ pattern: /^(?:npx\s+)?jest(?:\s+--watch)?/, recallHint: '--grep "FAIL|PASS|Error|Tests:"' },
|
|
10612
|
+
{ pattern: /^pytest(?:\s|$)/, recallHint: '--grep "FAILED|PASSED|ERROR|passed|failed"' },
|
|
10613
|
+
{ pattern: /^(?:cargo\s+test|cargo\s+watch)/, recallHint: '--grep "FAILED|ok|error\\["' },
|
|
10614
|
+
{ pattern: /^go test/, recallHint: '--grep "FAIL|ok|---"' },
|
|
10615
|
+
// Docker / compose
|
|
10616
|
+
{ pattern: /^docker(?:\s+compose)?\s+logs/, recallHint: '--tail 50 --grep "error|warn|Error|WARN"' },
|
|
10617
|
+
{ pattern: /^docker-compose\s+logs/, recallHint: '--tail 50 --grep "error|warn|Error|WARN"' },
|
|
10618
|
+
// File watchers / hot-reload
|
|
10619
|
+
{ pattern: /^nodemon/, recallHint: '--tail 20 --grep "error|crash|restart"' },
|
|
10620
|
+
{ pattern: /^air(?:\s|$)/, recallHint: '--tail 20 --grep "error|build failed"' },
|
|
10621
|
+
{ pattern: /^cargo watch/, recallHint: '--tail 20 --grep "error\\[|warning\\["' },
|
|
10622
|
+
{ pattern: /^watchexec/, recallHint: '--tail 20 --grep "error|warn"' },
|
|
10623
|
+
// Linters / formatters run repeatedly
|
|
10624
|
+
{ pattern: /^(?:npx\s+)?eslint(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
|
|
10625
|
+
{ pattern: /^(?:npx\s+)?prettier(?:\s|$)/, recallHint: '--grep "unchanged|reformatted|error"' },
|
|
10626
|
+
{ pattern: /^ruff(?:\s|$)/, recallHint: '--grep "error|warning|Found"' },
|
|
10627
|
+
{ pattern: /^(?:cargo\s+)?clippy/, recallHint: '--grep "error\\[|warning\\["' }
|
|
10628
|
+
];
|
|
10629
|
+
function getMonitoringRecallHint(cmd) {
|
|
10630
|
+
for (const { pattern, recallHint } of MONITORING_COMMAND_PATTERNS) {
|
|
10631
|
+
if (pattern.test(cmd.trim())) return recallHint;
|
|
10632
|
+
}
|
|
10633
|
+
return null;
|
|
10634
|
+
}
|
|
10635
|
+
|
|
10636
|
+
// src/hints/markdown_hints.ts
|
|
10637
|
+
init_define_import_meta_env();
|
|
10638
|
+
var MARKDOWN_SIZE_THRESHOLD = 8e3;
|
|
10639
|
+
var MAX_HEADINGS = 40;
|
|
10640
|
+
var MAX_OUTPUT_LINES = 60;
|
|
10641
|
+
function extractMarkdownHeadings(content) {
|
|
10642
|
+
const headings = [];
|
|
10643
|
+
const lines = content.split("\n");
|
|
10644
|
+
for (let i = 0; i < lines.length; i++) {
|
|
10645
|
+
const line = lines[i];
|
|
10646
|
+
if (!line) continue;
|
|
10647
|
+
const match = /^(#+)\s+(.+?)\s*$/.exec(line);
|
|
10648
|
+
if (!match || match.length < 3) continue;
|
|
10649
|
+
const hashes = match[1];
|
|
10650
|
+
const headingText = match[2];
|
|
10651
|
+
const level = hashes.length;
|
|
10652
|
+
if (level > 3) continue;
|
|
10653
|
+
const text = headingText.trim();
|
|
10654
|
+
if (!text) continue;
|
|
10655
|
+
headings.push({
|
|
10656
|
+
level,
|
|
10657
|
+
text,
|
|
10658
|
+
lineNumber: i + 1
|
|
10659
|
+
});
|
|
10660
|
+
if (headings.length >= MAX_HEADINGS) break;
|
|
10661
|
+
}
|
|
10662
|
+
return headings;
|
|
10663
|
+
}
|
|
10664
|
+
function formatHeadingTree(headings, filePath) {
|
|
10665
|
+
if (headings.length === 0) return "";
|
|
10666
|
+
const seenTexts = /* @__PURE__ */ new Map();
|
|
10667
|
+
const dedupedHeadings = [];
|
|
10668
|
+
for (const h of headings) {
|
|
10669
|
+
const count = (seenTexts.get(h.text) ?? 0) + 1;
|
|
10670
|
+
seenTexts.set(h.text, count);
|
|
10671
|
+
const suffix = count > 1 ? ` #${count}` : "";
|
|
10672
|
+
dedupedHeadings.push({
|
|
10673
|
+
text: h.text + suffix,
|
|
10674
|
+
level: h.level
|
|
10675
|
+
});
|
|
10676
|
+
}
|
|
10677
|
+
const lines = [];
|
|
10678
|
+
lines.push(`Large markdown file (${headings.length} headings). Use token-goat section to read a specific section:`);
|
|
10679
|
+
lines.push(` token-goat section "${filePath}::Heading Name"`);
|
|
10680
|
+
lines.push(``);
|
|
10681
|
+
lines.push(`Sections:`);
|
|
10682
|
+
let headingsAdded = 0;
|
|
10683
|
+
for (const h of dedupedHeadings) {
|
|
10684
|
+
if (lines.length + 1 >= MAX_OUTPUT_LINES) {
|
|
10685
|
+
const remaining = dedupedHeadings.length - headingsAdded;
|
|
10686
|
+
lines.push(` ... (${remaining} more headings)`);
|
|
10687
|
+
break;
|
|
10688
|
+
}
|
|
10689
|
+
const indent = h.level === 1 ? "" : h.level === 2 ? " " : " ";
|
|
10690
|
+
const marker = "#".repeat(h.level);
|
|
10691
|
+
lines.push(` ${indent}${marker} ${h.text}`);
|
|
10692
|
+
headingsAdded++;
|
|
10693
|
+
}
|
|
10694
|
+
return lines.join("\n");
|
|
10695
|
+
}
|
|
10696
|
+
var WELL_KNOWN_SECTIONS = {
|
|
10697
|
+
"CHANGELOG.md": ["Unreleased"],
|
|
10698
|
+
"README.md": ["Install", "Usage", "API", "Configuration", "Getting Started"],
|
|
10699
|
+
"CONTRIBUTING.md": ["Setup", "Commands", "Testing", "Development"],
|
|
10700
|
+
"CLAUDE.md": ["Commands", "Architecture"],
|
|
10701
|
+
"CLAUDE.arch.md": ["Component Map", "Architecture"]
|
|
10702
|
+
};
|
|
10703
|
+
function getWellKnownSections(basename6) {
|
|
10704
|
+
return WELL_KNOWN_SECTIONS[basename6] ?? [];
|
|
10705
|
+
}
|
|
10706
|
+
function extractChangelogVersionHint(content, filePath) {
|
|
10707
|
+
const lines = content.split("\n");
|
|
10708
|
+
let foundUnreleased = false;
|
|
10709
|
+
for (const line of lines) {
|
|
10710
|
+
const m = /^##\s+(\[?[\d]+\.[\d]+\.[\d]+\]?)/.exec(line);
|
|
10711
|
+
if (m) {
|
|
10712
|
+
if (foundUnreleased || !line.toLowerCase().includes("unreleased")) {
|
|
10713
|
+
const ver = m[1];
|
|
10714
|
+
return ` | token-goat section "${filePath}::${ver}"`;
|
|
10715
|
+
}
|
|
10716
|
+
}
|
|
10717
|
+
if (/^##\s+\[?unreleased\]?/i.test(line)) {
|
|
10718
|
+
foundUnreleased = true;
|
|
10719
|
+
}
|
|
10720
|
+
}
|
|
10721
|
+
return "";
|
|
10722
|
+
}
|
|
10723
|
+
|
|
10724
|
+
// src/hints/file_type_handler.ts
|
|
10725
|
+
init_define_import_meta_env();
|
|
10726
|
+
var FILE_TYPE_THRESHOLDS = {
|
|
10727
|
+
pdf: 0,
|
|
10728
|
+
// always intercept (any size)
|
|
10729
|
+
html: 5e4,
|
|
10730
|
+
txt: 2e4,
|
|
10731
|
+
csv: 1e4,
|
|
10732
|
+
tsv: 1e4,
|
|
10733
|
+
office: 0,
|
|
10734
|
+
// always block (.docx etc)
|
|
10735
|
+
generic: 1e5
|
|
10736
|
+
// catch-all for unrecognized large files
|
|
10737
|
+
};
|
|
10738
|
+
function formatBytes(n) {
|
|
10739
|
+
if (n < 1024) return `${n} B`;
|
|
10740
|
+
if (n < 1048576) return `${(n / 1024).toFixed(1)} KB`;
|
|
10741
|
+
return `${(n / 1048576).toFixed(1)} MB`;
|
|
10742
|
+
}
|
|
10743
|
+
function handlePdf(filePath, contentLength) {
|
|
10744
|
+
return {
|
|
10745
|
+
shouldBlock: true,
|
|
10746
|
+
message: [
|
|
10747
|
+
`PDF file (${formatBytes(contentLength)}).`,
|
|
10748
|
+
`Use the \`pages\` parameter to scope the read: Read({ file_path: "${filePath}", pages: "1-5" })`,
|
|
10749
|
+
`For the full page count, run: pdfinfo "${filePath}" | grep Pages`
|
|
10750
|
+
].join("\n")
|
|
10751
|
+
};
|
|
10752
|
+
}
|
|
10753
|
+
function handleHtml(filePath, content) {
|
|
10754
|
+
if (content.length < FILE_TYPE_THRESHOLDS.html) return { shouldBlock: false, message: "" };
|
|
10755
|
+
const title = content.match(/<title[^>]*>([^<]+)<\/title>/i)?.[1]?.trim();
|
|
10756
|
+
const headings = [...content.matchAll(/<h([1-6])[^>]*>([^<]+)<\/h\1>/gi)].slice(0, 20).map((m) => {
|
|
10757
|
+
const level = m[1];
|
|
10758
|
+
const text = m[2];
|
|
10759
|
+
if (!level || !text) return "";
|
|
10760
|
+
return `${" ".repeat(Number(level) - 1)}h${level}: ${text.trim()}`;
|
|
10761
|
+
}).filter(Boolean);
|
|
10762
|
+
const isMinified = !content.includes("\n") || content.length > 5e4 && content.split("\n").length < 10;
|
|
10763
|
+
if (isMinified) {
|
|
10764
|
+
return {
|
|
10765
|
+
shouldBlock: true,
|
|
10766
|
+
message: `HTML file appears minified (${formatBytes(content.length)}). Consider fetching the source or converting with: pandoc "${filePath}" -t plain`
|
|
10767
|
+
};
|
|
10768
|
+
}
|
|
10769
|
+
return {
|
|
10770
|
+
shouldBlock: true,
|
|
10771
|
+
message: [
|
|
10772
|
+
`Large HTML file (${formatBytes(content.length)})${title ? `: "${title}"` : ""}.`,
|
|
10773
|
+
headings.length > 0 ? `Headings:
|
|
10774
|
+
${headings.join("\n")}` : "",
|
|
10775
|
+
`Use token-goat section to extract a section by heading, or convert to text: pandoc "${filePath}" -t plain`
|
|
10776
|
+
].filter(Boolean).join("\n")
|
|
10777
|
+
};
|
|
10778
|
+
}
|
|
10779
|
+
function handleTxt(filePath, content) {
|
|
10780
|
+
if (content.length < FILE_TYPE_THRESHOLDS.txt) return { shouldBlock: false, message: "" };
|
|
10781
|
+
const lines = content.split("\n");
|
|
10782
|
+
const isLog = /\.(log|out|err|trace)$/i.test(filePath) || filePath.includes("/logs/");
|
|
10783
|
+
const preview = [
|
|
10784
|
+
"--- first 5 lines ---",
|
|
10785
|
+
...lines.slice(0, 5),
|
|
10786
|
+
`... (${lines.length.toLocaleString()} lines total) ...`,
|
|
10787
|
+
"--- last 5 lines ---",
|
|
10788
|
+
...lines.slice(-5)
|
|
10789
|
+
].join("\n");
|
|
10790
|
+
const recall = isLog ? 'Log file \u2014 use Read with offset/limit params, or: token-goat bash-output <id> --tail 100 --grep "error|ERROR"' : "Use Read with offset and limit params to sample specific line ranges.";
|
|
10791
|
+
return {
|
|
10792
|
+
shouldBlock: true,
|
|
10793
|
+
message: `Large text file (${formatBytes(content.length)}, ${lines.length.toLocaleString()} lines).
|
|
10794
|
+
${preview}
|
|
10795
|
+
|
|
10796
|
+
${recall}`
|
|
10797
|
+
};
|
|
10798
|
+
}
|
|
10799
|
+
function handleOfficeBinary(filePath) {
|
|
10800
|
+
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
10801
|
+
return {
|
|
10802
|
+
shouldBlock: true,
|
|
10803
|
+
message: [
|
|
10804
|
+
`Binary Office file (.${ext}) \u2014 cannot be read as text.`,
|
|
10805
|
+
`Extract content first: pandoc "${filePath}" -t plain > "${filePath}.txt"`,
|
|
10806
|
+
`Then read the extracted .txt file.`
|
|
10807
|
+
].join("\n")
|
|
10808
|
+
};
|
|
10809
|
+
}
|
|
10810
|
+
function handleCsv(filePath, content) {
|
|
10811
|
+
if (content.length < FILE_TYPE_THRESHOLDS.csv) return { shouldBlock: false, message: "" };
|
|
10812
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
10813
|
+
const headers = lines[0] ?? "";
|
|
10814
|
+
const sampleRows = lines.slice(1, 4);
|
|
10815
|
+
const sep = filePath.endsWith(".tsv") ? " " : ",";
|
|
10816
|
+
const colCount = headers.split(sep).length;
|
|
10817
|
+
return {
|
|
10818
|
+
shouldBlock: true,
|
|
10819
|
+
message: [
|
|
10820
|
+
`Large CSV file (${formatBytes(content.length)}, ~${lines.length.toLocaleString()} rows, ${colCount} columns).`,
|
|
10821
|
+
`Columns: ${headers}`,
|
|
10822
|
+
`Sample rows:
|
|
10823
|
+
${sampleRows.join("\n")}`,
|
|
10824
|
+
`Use Read with offset/limit to sample rows, or query with DuckDB: duckdb -c "SELECT * FROM '${filePath}' LIMIT 10"`
|
|
10825
|
+
].join("\n")
|
|
10826
|
+
};
|
|
10827
|
+
}
|
|
10828
|
+
function handleGenericLarge(filePath, contentLength) {
|
|
10829
|
+
if (contentLength < FILE_TYPE_THRESHOLDS.generic) return { shouldBlock: false, message: "" };
|
|
10830
|
+
return {
|
|
10831
|
+
shouldBlock: true,
|
|
10832
|
+
message: `Large file (${formatBytes(contentLength)}). Use Read with offset and limit parameters to read specific line ranges rather than loading the entire file.`
|
|
10833
|
+
};
|
|
10834
|
+
}
|
|
10835
|
+
function dispatchFileTypeHandler(filePath, content, contentLengthHint) {
|
|
10836
|
+
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
|
|
10837
|
+
if (["md", "mdx", "markdown", "rst"].includes(ext)) return null;
|
|
10838
|
+
const effectiveLength = contentLengthHint ?? content.length;
|
|
10839
|
+
if (ext === "pdf") return handlePdf(filePath, effectiveLength);
|
|
10840
|
+
if (["html", "htm", "xhtml"].includes(ext)) return handleHtml(filePath, content);
|
|
10841
|
+
if (["txt", "log", "out", "err", "trace"].includes(ext)) return handleTxt(filePath, content);
|
|
10842
|
+
if (["docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"].includes(ext)) return handleOfficeBinary(filePath);
|
|
10843
|
+
if (ext === "csv" || ext === "tsv") return handleCsv(filePath, content);
|
|
10844
|
+
return handleGenericLarge(filePath, effectiveLength);
|
|
10845
|
+
}
|
|
10846
|
+
|
|
10385
10847
|
// src/hooks_read.ts
|
|
10848
|
+
function isTsConfigFile(basename6) {
|
|
10849
|
+
const lower = basename6.toLowerCase();
|
|
10850
|
+
return /^tsconfig(\..+)?\.json$/i.test(lower) || lower === "jsconfig.json";
|
|
10851
|
+
}
|
|
10386
10852
|
var LARGE_FILE_BYTES = 100 * 1024;
|
|
10853
|
+
function isNodeModulesPath(path14) {
|
|
10854
|
+
const isWindows = process.platform === "win32";
|
|
10855
|
+
const check = isWindows ? path14.toLowerCase() : path14;
|
|
10856
|
+
return check.includes("/node_modules/") || check.includes("\\node_modules\\");
|
|
10857
|
+
}
|
|
10858
|
+
function _isDocFile(filePath) {
|
|
10859
|
+
const lower = filePath.toLowerCase();
|
|
10860
|
+
return lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".markdown") || lower.endsWith(".rst");
|
|
10861
|
+
}
|
|
10387
10862
|
function statSize(absPath) {
|
|
10388
10863
|
try {
|
|
10389
10864
|
return fs4.statSync(absPath).size;
|
|
@@ -10395,41 +10870,124 @@ function preReadHandler(event) {
|
|
|
10395
10870
|
const filePath = getFilePath(event);
|
|
10396
10871
|
if (filePath === void 0) return passOutput();
|
|
10397
10872
|
const normalized = normalizePath(filePath);
|
|
10873
|
+
if (isNodeModulesPath(normalized)) {
|
|
10874
|
+
return denyOutput(
|
|
10875
|
+
"node_modules is typically noise; use npm ls, npm outdated, or npm audit instead for dependency info. To force access, use: token-goat read node_modules/package/file.js::symbol-name or token-goat section node_modules/package/file.js::heading"
|
|
10876
|
+
);
|
|
10877
|
+
}
|
|
10878
|
+
const basename6 = path6.basename(normalized);
|
|
10879
|
+
if (isLockFile(basename6)) {
|
|
10880
|
+
return denyOutput(
|
|
10881
|
+
'Lock files are rarely useful to read in full. Use `token-goat section "' + normalized + '::<section>"` to extract a specific dependency, or read the relevant manifest instead.'
|
|
10882
|
+
);
|
|
10883
|
+
}
|
|
10884
|
+
if (normalized.toLowerCase().endsWith(".tsbuildinfo")) {
|
|
10885
|
+
return denyOutput(
|
|
10886
|
+
"This is a TypeScript incremental build cache file. You don't need to read it directly."
|
|
10887
|
+
);
|
|
10888
|
+
}
|
|
10889
|
+
if (isInBuildDir(normalized) || isGeneratedFile(normalized)) {
|
|
10890
|
+
return denyOutput(
|
|
10891
|
+
"Generated/build artifact \u2014 read the source file instead."
|
|
10892
|
+
);
|
|
10893
|
+
}
|
|
10894
|
+
const manifestHint = buildPackageManifestHint({ file_path: normalized });
|
|
10895
|
+
if (manifestHint) {
|
|
10896
|
+
recordFileRead(normalized);
|
|
10897
|
+
return contextOutput(manifestHint.text);
|
|
10898
|
+
}
|
|
10899
|
+
if (isTsConfigFile(basename6) && wasFileReadThisSession(normalized)) {
|
|
10900
|
+
recordFileRead(normalized);
|
|
10901
|
+
return contextOutput(
|
|
10902
|
+
"Already read " + basename6 + '. Use `token-goat section "' + normalized + '::compilerOptions"` to extract compiler options, or `token-goat config-get ' + normalized + " compilerOptions.target` for a single value."
|
|
10903
|
+
);
|
|
10904
|
+
}
|
|
10905
|
+
if (isManifestFile(basename6) && wasFileReadThisSession(normalized)) {
|
|
10906
|
+
recordFileRead(normalized);
|
|
10907
|
+
return contextOutput(
|
|
10908
|
+
"You've already read " + basename6 + '. Use `token-goat section "' + normalized + '::<field>"` or `token-goat config-get ' + normalized + " <key>` to extract just the value you need."
|
|
10909
|
+
);
|
|
10910
|
+
}
|
|
10911
|
+
const isMarkdown = /\.(md|mdx|markdown|rst)$/i.test(basename6);
|
|
10912
|
+
if (isMarkdown) {
|
|
10913
|
+
let fileContent = null;
|
|
10914
|
+
try {
|
|
10915
|
+
const sz = statSize(normalized);
|
|
10916
|
+
if (sz !== null && sz >= MARKDOWN_SIZE_THRESHOLD) {
|
|
10917
|
+
fileContent = fs4.readFileSync(normalized, "utf8");
|
|
10918
|
+
}
|
|
10919
|
+
} catch {
|
|
10920
|
+
}
|
|
10921
|
+
if (fileContent !== null) {
|
|
10922
|
+
const headings = extractMarkdownHeadings(fileContent);
|
|
10923
|
+
if (headings.length >= 3) {
|
|
10924
|
+
recordFileRead(normalized);
|
|
10925
|
+
const hintText = formatHeadingTree(headings, normalized);
|
|
10926
|
+
const wellKnown = getWellKnownSections(basename6);
|
|
10927
|
+
const wellKnownText = wellKnown.length > 0 ? "\nQuick access: " + wellKnown.map((s) => 'token-goat section "' + normalized + "::" + s + '"').join(" | ") : "";
|
|
10928
|
+
const changelogExtra = basename6.toLowerCase() === "changelog.md" ? extractChangelogVersionHint(fileContent, normalized) : "";
|
|
10929
|
+
return denyOutput(hintText + wellKnownText + changelogExtra);
|
|
10930
|
+
}
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10398
10933
|
if (wasFileReadThisSession(normalized)) {
|
|
10399
10934
|
const entry = getSessionFiles().get(normalized);
|
|
10400
10935
|
const reads = entry?.readCount ?? 1;
|
|
10401
10936
|
const plural = reads === 1 ? "read" : "reads";
|
|
10402
10937
|
recordFileRead(normalized);
|
|
10938
|
+
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
10403
10939
|
return contextOutput(
|
|
10404
|
-
|
|
10940
|
+
"Note: " + normalized + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
10405
10941
|
);
|
|
10406
10942
|
}
|
|
10407
10943
|
const size = statSize(normalized);
|
|
10408
10944
|
if (size !== null && size >= LARGE_FILE_BYTES) {
|
|
10409
10945
|
const kb = Math.round(size / 1024);
|
|
10410
10946
|
recordFileRead(normalized);
|
|
10947
|
+
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Consider token-goat skeleton or token-goat section.";
|
|
10411
10948
|
return contextOutput(
|
|
10412
|
-
|
|
10949
|
+
"Note: " + normalized + " is large (" + kb + "kb). " + hint
|
|
10413
10950
|
);
|
|
10414
10951
|
}
|
|
10952
|
+
const fileTypeExt = path6.extname(normalized).slice(1).toLowerCase();
|
|
10953
|
+
const binaryExts = /* @__PURE__ */ new Set(["pdf", "docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"]);
|
|
10954
|
+
const textTypeExts = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv"]);
|
|
10955
|
+
const fileStatSize = size ?? statSize(normalized) ?? 0;
|
|
10956
|
+
const isKnownFileType = binaryExts.has(fileTypeExt) || textTypeExts.has(fileTypeExt);
|
|
10957
|
+
if (isKnownFileType || fileStatSize >= FILE_TYPE_THRESHOLDS.generic) {
|
|
10958
|
+
let ftContent = "";
|
|
10959
|
+
if (!binaryExts.has(fileTypeExt)) {
|
|
10960
|
+
try {
|
|
10961
|
+
ftContent = fs4.readFileSync(normalized, "utf8");
|
|
10962
|
+
} catch {
|
|
10963
|
+
}
|
|
10964
|
+
}
|
|
10965
|
+
const ftResult = dispatchFileTypeHandler(normalized, ftContent, fileStatSize);
|
|
10966
|
+
if (ftResult?.shouldBlock) {
|
|
10967
|
+
recordFileRead(normalized);
|
|
10968
|
+
return denyOutput(ftResult.message);
|
|
10969
|
+
}
|
|
10970
|
+
}
|
|
10415
10971
|
recordFileRead(normalized);
|
|
10416
10972
|
return passOutput();
|
|
10417
10973
|
}
|
|
10418
10974
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Read" });
|
|
10975
|
+
registerHook("pre_tool_use", preReadHandler, { toolName: "Grep" });
|
|
10419
10976
|
|
|
10420
10977
|
// src/hooks_edit.ts
|
|
10421
10978
|
init_define_import_meta_env();
|
|
10979
|
+
import * as path8 from "node:path";
|
|
10422
10980
|
|
|
10423
10981
|
// src/hooks_index.ts
|
|
10424
10982
|
init_define_import_meta_env();
|
|
10425
10983
|
import * as fs5 from "node:fs";
|
|
10426
|
-
import * as
|
|
10984
|
+
import * as path7 from "node:path";
|
|
10427
10985
|
function dirtyQueuePath() {
|
|
10428
|
-
return
|
|
10986
|
+
return path7.join(dataDir(), "queue", "dirty.txt");
|
|
10429
10987
|
}
|
|
10430
10988
|
function appendDirtyPath(normalizedPath) {
|
|
10431
10989
|
const queuePath = dirtyQueuePath();
|
|
10432
|
-
fs5.mkdirSync(
|
|
10990
|
+
fs5.mkdirSync(path7.dirname(queuePath), { recursive: true });
|
|
10433
10991
|
fs5.appendFileSync(queuePath, `${normalizedPath}
|
|
10434
10992
|
`);
|
|
10435
10993
|
}
|
|
@@ -10460,9 +11018,9 @@ function clearDirtyQueue() {
|
|
|
10460
11018
|
function preCompactIndexHandler(_event) {
|
|
10461
11019
|
const paths = getDirtyPaths();
|
|
10462
11020
|
if (paths.length > 0) {
|
|
10463
|
-
const sidecar =
|
|
11021
|
+
const sidecar = path7.join(dataDir(), "queue", "pending.txt");
|
|
10464
11022
|
try {
|
|
10465
|
-
fs5.mkdirSync(
|
|
11023
|
+
fs5.mkdirSync(path7.dirname(sidecar), { recursive: true });
|
|
10466
11024
|
atomicWriteBytes(sidecar, Buffer.from(`${paths.join("\n")}
|
|
10467
11025
|
`, "utf8"));
|
|
10468
11026
|
} catch {
|
|
@@ -10480,6 +11038,12 @@ function postEditHandler(event) {
|
|
|
10480
11038
|
const normalized = normalizePath(filePath);
|
|
10481
11039
|
recordFileEdit(normalized);
|
|
10482
11040
|
appendDirtyPath(normalized);
|
|
11041
|
+
const editedBasename = path8.basename(normalized);
|
|
11042
|
+
if (/\.(md|mdx|markdown|rst)$/i.test(editedBasename)) {
|
|
11043
|
+
return contextOutput(
|
|
11044
|
+
editedBasename + ' was edited. Use `token-goat section "' + normalized + '::HeadingName"` to re-read a specific section rather than the full file.'
|
|
11045
|
+
);
|
|
11046
|
+
}
|
|
10483
11047
|
return passOutput();
|
|
10484
11048
|
}
|
|
10485
11049
|
registerHook("post_tool_use", postEditHandler, { toolName: "Write" });
|
|
@@ -10748,10 +11312,75 @@ function postSkillHandler(event) {
|
|
|
10748
11312
|
registerHook("pre_tool_use", preSkillHandler, { toolName: "Skill" });
|
|
10749
11313
|
registerHook("post_tool_use", postSkillHandler, { toolName: "Skill" });
|
|
10750
11314
|
|
|
10751
|
-
// src/
|
|
11315
|
+
// src/hooks_bash.ts
|
|
10752
11316
|
init_define_import_meta_env();
|
|
11317
|
+
|
|
11318
|
+
// src/fingerprint.ts
|
|
11319
|
+
init_define_import_meta_env();
|
|
11320
|
+
import { createHash } from "node:crypto";
|
|
10753
11321
|
import * as fs6 from "node:fs";
|
|
10754
|
-
|
|
11322
|
+
function fingerprintContent(content) {
|
|
11323
|
+
const hash = createHash("sha256");
|
|
11324
|
+
hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
|
|
11325
|
+
return hash.digest("hex");
|
|
11326
|
+
}
|
|
11327
|
+
function fingerprintFile(filePath) {
|
|
11328
|
+
let data;
|
|
11329
|
+
try {
|
|
11330
|
+
data = fs6.readFileSync(filePath);
|
|
11331
|
+
} catch {
|
|
11332
|
+
return null;
|
|
11333
|
+
}
|
|
11334
|
+
return fingerprintContent(data);
|
|
11335
|
+
}
|
|
11336
|
+
|
|
11337
|
+
// src/hooks_bash.ts
|
|
11338
|
+
function extractCommand(event) {
|
|
11339
|
+
const cmd = event.toolInput["command"];
|
|
11340
|
+
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
11341
|
+
}
|
|
11342
|
+
function isTscCommand(cmd) {
|
|
11343
|
+
return /^\s*tsc(\s|$)/i.test(cmd);
|
|
11344
|
+
}
|
|
11345
|
+
function isDevServerCommand(cmd) {
|
|
11346
|
+
return /^\s*(vite\s+dev|next\s+dev|nuxt\s+dev)\b/i.test(cmd);
|
|
11347
|
+
}
|
|
11348
|
+
function buildRecallHint(cmd, outputId) {
|
|
11349
|
+
const cmdPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
11350
|
+
if (isTscCommand(cmd)) {
|
|
11351
|
+
return "Output from a prior `" + cmdPreview + "` run is cached. Use `token-goat bash-output " + outputId + ' --grep "error TS"` to filter TypeScript errors, or `--grep "Cannot find"` for missing module errors.';
|
|
11352
|
+
}
|
|
11353
|
+
if (isDevServerCommand(cmd)) {
|
|
11354
|
+
return "Dev server output cached (`" + cmdPreview + "`). Use `token-goat bash-output " + outputId + ' --tail 20` to see the latest output, or `--grep "error\\|warn"` to filter issues.';
|
|
11355
|
+
}
|
|
11356
|
+
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.";
|
|
11357
|
+
}
|
|
11358
|
+
function preBashHandler(event) {
|
|
11359
|
+
const cmd = extractCommand(event);
|
|
11360
|
+
if (cmd === void 0) return passOutput();
|
|
11361
|
+
const monitoringHint = getMonitoringRecallHint(cmd);
|
|
11362
|
+
if (monitoringHint !== null) {
|
|
11363
|
+
const monCmdHash = fingerprintContent(cmd).slice(0, 16);
|
|
11364
|
+
const monOutputId = getBashOutputId(monCmdHash);
|
|
11365
|
+
if (monOutputId !== null) {
|
|
11366
|
+
const cmdSummary = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
11367
|
+
return contextOutput(
|
|
11368
|
+
"Prior output from `" + cmdSummary + "` is cached.\nUse `token-goat bash-output " + monOutputId + " " + monitoringHint + "` to re-inspect without re-running."
|
|
11369
|
+
);
|
|
11370
|
+
}
|
|
11371
|
+
}
|
|
11372
|
+
if (!isBuildCommand(cmd)) return passOutput();
|
|
11373
|
+
const cmdHash = fingerprintContent(cmd).slice(0, 16);
|
|
11374
|
+
const outputId = getBashOutputId(cmdHash);
|
|
11375
|
+
if (outputId === null) return passOutput();
|
|
11376
|
+
return contextOutput(buildRecallHint(cmd, outputId));
|
|
11377
|
+
}
|
|
11378
|
+
registerHook("pre_tool_use", preBashHandler, { toolName: "Bash" });
|
|
11379
|
+
|
|
11380
|
+
// src/image_shrink.ts
|
|
11381
|
+
init_define_import_meta_env();
|
|
11382
|
+
import * as fs7 from "node:fs";
|
|
11383
|
+
import * as path9 from "node:path";
|
|
10755
11384
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
10756
11385
|
".png",
|
|
10757
11386
|
".jpg",
|
|
@@ -10778,7 +11407,7 @@ async function loadSharp() {
|
|
|
10778
11407
|
return _sharpCache;
|
|
10779
11408
|
}
|
|
10780
11409
|
function isImagePath(p) {
|
|
10781
|
-
return IMAGE_EXTENSIONS.has(
|
|
11410
|
+
return IMAGE_EXTENSIONS.has(path9.extname(p).toLowerCase());
|
|
10782
11411
|
}
|
|
10783
11412
|
async function shrinkImage(input, opts) {
|
|
10784
11413
|
const maxDimension = opts?.maxDimension ?? DEFAULT_MAX_DIMENSION;
|
|
@@ -10816,7 +11445,7 @@ async function shrinkImage(input, opts) {
|
|
|
10816
11445
|
}
|
|
10817
11446
|
function statSize2(absPath) {
|
|
10818
11447
|
try {
|
|
10819
|
-
const st =
|
|
11448
|
+
const st = fs7.statSync(absPath);
|
|
10820
11449
|
return st.isFile() ? st.size : null;
|
|
10821
11450
|
} catch {
|
|
10822
11451
|
return null;
|
|
@@ -10830,7 +11459,7 @@ async function preReadImageHandler(event) {
|
|
|
10830
11459
|
if (size === null || size < DEFAULT_SIZE_THRESHOLD_BYTES) return passOutput();
|
|
10831
11460
|
let input;
|
|
10832
11461
|
try {
|
|
10833
|
-
input =
|
|
11462
|
+
input = fs7.readFileSync(filePath);
|
|
10834
11463
|
} catch {
|
|
10835
11464
|
return passOutput();
|
|
10836
11465
|
}
|
|
@@ -10839,7 +11468,7 @@ async function preReadImageHandler(event) {
|
|
|
10839
11468
|
const saved = result.originalBytes - result.shrunkBytes;
|
|
10840
11469
|
const pct = Math.round(saved / result.originalBytes * 100);
|
|
10841
11470
|
const dataUrl = `data:image/${result.format};base64,${result.data.toString("base64")}`;
|
|
10842
|
-
const summary = `token-goat shrank ${
|
|
11471
|
+
const summary = `token-goat shrank ${path9.basename(filePath)}: ${Math.round(result.originalBytes / 1024)}kb -> ${Math.round(result.shrunkBytes / 1024)}kb (${pct}% smaller, ${result.width}x${result.height} ${result.format}).`;
|
|
10843
11472
|
return contextOutput(`${summary}
|
|
10844
11473
|
${dataUrl}`);
|
|
10845
11474
|
}
|
|
@@ -10918,7 +11547,7 @@ async function relay(eventName) {
|
|
|
10918
11547
|
|
|
10919
11548
|
// src/section_reader.ts
|
|
10920
11549
|
init_define_import_meta_env();
|
|
10921
|
-
import { readFileSync as
|
|
11550
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
10922
11551
|
function parseHeadingSpec(spec) {
|
|
10923
11552
|
const m = /^(.*?)#(\d+)$/.exec(spec);
|
|
10924
11553
|
if (m !== null && m[1] !== void 0 && m[2] !== void 0) {
|
|
@@ -11000,7 +11629,7 @@ function sectionEndIndex(headers, headerPos, totalLines) {
|
|
|
11000
11629
|
function readSection(filePath, headingSpec) {
|
|
11001
11630
|
let text;
|
|
11002
11631
|
try {
|
|
11003
|
-
text =
|
|
11632
|
+
text = readFileSync5(filePath, "utf-8");
|
|
11004
11633
|
} catch {
|
|
11005
11634
|
return null;
|
|
11006
11635
|
}
|
|
@@ -11037,9 +11666,9 @@ function readSection(filePath, headingSpec) {
|
|
|
11037
11666
|
|
|
11038
11667
|
// src/install.ts
|
|
11039
11668
|
init_define_import_meta_env();
|
|
11040
|
-
import * as
|
|
11669
|
+
import * as fs8 from "node:fs";
|
|
11041
11670
|
import * as os2 from "node:os";
|
|
11042
|
-
import * as
|
|
11671
|
+
import * as path10 from "node:path";
|
|
11043
11672
|
var HOOK_EVENT_MAP = [
|
|
11044
11673
|
["PreToolUse", "pre_tool_use"],
|
|
11045
11674
|
["PostToolUse", "post_tool_use"],
|
|
@@ -11050,13 +11679,13 @@ function hookCommand(eventArg) {
|
|
|
11050
11679
|
return `token-goat hook ${eventArg}`;
|
|
11051
11680
|
}
|
|
11052
11681
|
function settingsPath(scope) {
|
|
11053
|
-
const base = scope === "user" ?
|
|
11054
|
-
return
|
|
11682
|
+
const base = scope === "user" ? path10.join(os2.homedir(), ".claude") : path10.join(process.cwd(), ".claude");
|
|
11683
|
+
return path10.join(base, "settings.json");
|
|
11055
11684
|
}
|
|
11056
11685
|
function readSettings(p) {
|
|
11057
11686
|
let raw;
|
|
11058
11687
|
try {
|
|
11059
|
-
raw =
|
|
11688
|
+
raw = fs8.readFileSync(p, "utf8");
|
|
11060
11689
|
} catch {
|
|
11061
11690
|
return {};
|
|
11062
11691
|
}
|
|
@@ -11096,7 +11725,7 @@ function installHooks(scope = "user") {
|
|
|
11096
11725
|
return { scope, settingsPath: p, alreadyInstalled: true };
|
|
11097
11726
|
}
|
|
11098
11727
|
settings.hooks = hooks;
|
|
11099
|
-
|
|
11728
|
+
fs8.mkdirSync(path10.dirname(p), { recursive: true });
|
|
11100
11729
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
11101
11730
|
`);
|
|
11102
11731
|
return { scope, settingsPath: p, alreadyInstalled: false };
|
|
@@ -11135,7 +11764,7 @@ function uninstallHooks(scope = "user") {
|
|
|
11135
11764
|
} else {
|
|
11136
11765
|
settings.hooks = hooks;
|
|
11137
11766
|
}
|
|
11138
|
-
|
|
11767
|
+
fs8.mkdirSync(path10.dirname(p), { recursive: true });
|
|
11139
11768
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
11140
11769
|
`);
|
|
11141
11770
|
return true;
|
|
@@ -11145,36 +11774,15 @@ function uninstallHooks(scope = "user") {
|
|
|
11145
11774
|
init_define_import_meta_env();
|
|
11146
11775
|
import { spawn } from "node:child_process";
|
|
11147
11776
|
import * as fs9 from "node:fs";
|
|
11148
|
-
import * as
|
|
11777
|
+
import * as path11 from "node:path";
|
|
11149
11778
|
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
|
|
11150
11779
|
import { fileURLToPath } from "node:url";
|
|
11151
|
-
|
|
11152
|
-
// src/fingerprint.ts
|
|
11153
|
-
init_define_import_meta_env();
|
|
11154
|
-
import { createHash } from "node:crypto";
|
|
11155
|
-
import * as fs8 from "node:fs";
|
|
11156
|
-
function fingerprintContent(content) {
|
|
11157
|
-
const hash = createHash("sha256");
|
|
11158
|
-
hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
|
|
11159
|
-
return hash.digest("hex");
|
|
11160
|
-
}
|
|
11161
|
-
function fingerprintFile(filePath) {
|
|
11162
|
-
let data;
|
|
11163
|
-
try {
|
|
11164
|
-
data = fs8.readFileSync(filePath);
|
|
11165
|
-
} catch {
|
|
11166
|
-
return null;
|
|
11167
|
-
}
|
|
11168
|
-
return fingerprintContent(data);
|
|
11169
|
-
}
|
|
11170
|
-
|
|
11171
|
-
// src/worker.ts
|
|
11172
11780
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
11173
11781
|
function dirtyQueuePathFor(dir) {
|
|
11174
|
-
return
|
|
11782
|
+
return path11.join(dir, "queue", "dirty.txt");
|
|
11175
11783
|
}
|
|
11176
11784
|
function workerPidPath(dir = dataDir()) {
|
|
11177
|
-
return
|
|
11785
|
+
return path11.join(dir, "worker.pid");
|
|
11178
11786
|
}
|
|
11179
11787
|
function getDirtyPathsFor(dir) {
|
|
11180
11788
|
let raw;
|
|
@@ -12683,7 +13291,686 @@ function _buildConfig(raw) {
|
|
|
12683
13291
|
|
|
12684
13292
|
// src/stats.ts
|
|
12685
13293
|
init_define_import_meta_env();
|
|
12686
|
-
import * as
|
|
13294
|
+
import * as path12 from "node:path";
|
|
13295
|
+
|
|
13296
|
+
// src/render/stats_renderer.ts
|
|
13297
|
+
init_define_import_meta_env();
|
|
13298
|
+
|
|
13299
|
+
// src/render/ansi.ts
|
|
13300
|
+
init_define_import_meta_env();
|
|
13301
|
+
function _colorStream(isatty) {
|
|
13302
|
+
if (process.env["NO_COLOR"]) return false;
|
|
13303
|
+
return isatty;
|
|
13304
|
+
}
|
|
13305
|
+
function colorStdout() {
|
|
13306
|
+
return _colorStream(process.stdout.isTTY === true);
|
|
13307
|
+
}
|
|
13308
|
+
var USE_COLOR = colorStdout();
|
|
13309
|
+
var _E = "\x1B";
|
|
13310
|
+
var RESET = `${_E}[0m`;
|
|
13311
|
+
var _ANSI_ESCAPE_RE = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\)|\x1B[PX^_].*?\x1B\\|\x1B[@-Z\\\-_]/gs;
|
|
13312
|
+
var _PUA_RE = /[\u{E000}-\u{F8FF}\u{F0000}-\u{FFFDD}]/gu;
|
|
13313
|
+
function stripAnsi(s) {
|
|
13314
|
+
if (!s.includes("\x1B")) {
|
|
13315
|
+
return s;
|
|
13316
|
+
}
|
|
13317
|
+
const text = s.replace(_ANSI_ESCAPE_RE, "");
|
|
13318
|
+
return text.replace(_PUA_RE, "");
|
|
13319
|
+
}
|
|
13320
|
+
function fg(r, g, b) {
|
|
13321
|
+
return `${_E}[38;2;${r};${g};${b}m`;
|
|
13322
|
+
}
|
|
13323
|
+
function vlen(s) {
|
|
13324
|
+
return stripAnsi(s).length;
|
|
13325
|
+
}
|
|
13326
|
+
function padR(s, w) {
|
|
13327
|
+
return s + " ".repeat(Math.max(0, w - vlen(s)));
|
|
13328
|
+
}
|
|
13329
|
+
function padL(s, w) {
|
|
13330
|
+
return " ".repeat(Math.max(0, w - vlen(s))) + s;
|
|
13331
|
+
}
|
|
13332
|
+
function lerpRgb(a, b, t) {
|
|
13333
|
+
return [
|
|
13334
|
+
Math.round(a[0] + (b[0] - a[0]) * t),
|
|
13335
|
+
Math.round(a[1] + (b[1] - a[1]) * t),
|
|
13336
|
+
Math.round(a[2] + (b[2] - a[2]) * t)
|
|
13337
|
+
];
|
|
13338
|
+
}
|
|
13339
|
+
var C = {
|
|
13340
|
+
TEXT_PRIMARY: [201, 209, 217],
|
|
13341
|
+
TEXT_BRIGHT: [240, 246, 252],
|
|
13342
|
+
TEXT_MUTED: [125, 133, 144],
|
|
13343
|
+
TEXT_DIM: [72, 79, 88],
|
|
13344
|
+
BG_TILE: [22, 27, 34],
|
|
13345
|
+
TRACK: [28, 35, 41],
|
|
13346
|
+
GREEN1: [31, 77, 44],
|
|
13347
|
+
GREEN2: [46, 160, 67],
|
|
13348
|
+
GREEN3: [63, 185, 80],
|
|
13349
|
+
GREEN4: [86, 211, 100],
|
|
13350
|
+
GREEN5: [126, 231, 135],
|
|
13351
|
+
BLUE: [88, 166, 255],
|
|
13352
|
+
PURPLE: [188, 140, 255],
|
|
13353
|
+
TEAL: [138, 212, 255],
|
|
13354
|
+
ORANGE: [235, 165, 80],
|
|
13355
|
+
YELLOW: [240, 215, 80],
|
|
13356
|
+
RED: [200, 60, 60]
|
|
13357
|
+
};
|
|
13358
|
+
|
|
13359
|
+
// src/render/stats_renderer.ts
|
|
13360
|
+
var _STATS_MESSAGES_FALLBACK = {
|
|
13361
|
+
bytesModeOnlyNote: "tracks bytes, not vision tokens",
|
|
13362
|
+
sessionHintSplitNote: "session_hint shows realized savings; session_hint_overhead shows injected hint cost",
|
|
13363
|
+
insights: {
|
|
13364
|
+
biggestSaver: "Biggest saver ",
|
|
13365
|
+
mostActive: "Most active ",
|
|
13366
|
+
tokenLeader: "Token leader "
|
|
13367
|
+
}
|
|
13368
|
+
};
|
|
13369
|
+
var _STATS_MESSAGES = _STATS_MESSAGES_FALLBACK;
|
|
13370
|
+
var _TERM_W = process.stdout.columns || 100;
|
|
13371
|
+
var _CONTENT_W = Math.min(Math.max(_TERM_W, 80), 140);
|
|
13372
|
+
var _M = " ";
|
|
13373
|
+
var _COL_NAME = 18;
|
|
13374
|
+
var _COL_DATA = 10;
|
|
13375
|
+
var _COL_TOKENS = 12;
|
|
13376
|
+
var _COL_SHARE = 6;
|
|
13377
|
+
var _COL_EVENTS = 6;
|
|
13378
|
+
var _COLS_FIXED = _COL_NAME + 1 + 2 + _COL_DATA + 2 + _COL_TOKENS + 2 + _COL_SHARE + 2 + _COL_EVENTS;
|
|
13379
|
+
var _BAR_W = Math.max(16, _CONTENT_W - _M.length * 2 - _COLS_FIXED);
|
|
13380
|
+
var _RULE = _M + fg(...C.TEXT_DIM) + "\u2500".repeat(_CONTENT_W - _M.length * 2) + RESET;
|
|
13381
|
+
var _BYTE_TIERS = [
|
|
13382
|
+
{ threshold: 1e15, divisor: 1e15, unit: "PB", color: C.PURPLE },
|
|
13383
|
+
{ threshold: 1e12, divisor: 1e12, unit: "TB", color: C.BLUE },
|
|
13384
|
+
{ threshold: 1e9, divisor: 1e9, unit: "GB", color: C.TEAL },
|
|
13385
|
+
{ threshold: 1e6, divisor: 1e6, unit: "MB", color: C.GREEN4 },
|
|
13386
|
+
{ threshold: 1e3, divisor: 1e3, unit: "KB", color: C.TEXT_MUTED },
|
|
13387
|
+
{ threshold: 0, divisor: 1, unit: "B", color: C.TEXT_DIM }
|
|
13388
|
+
];
|
|
13389
|
+
var _TOKEN_TIERS = [
|
|
13390
|
+
{ threshold: 1e12, divisor: 1e12, unit: "Tt", color: C.GREEN5 },
|
|
13391
|
+
{ threshold: 1e9, divisor: 1e9, unit: "Gt", color: C.TEAL },
|
|
13392
|
+
{ threshold: 1e6, divisor: 1e6, unit: "Mt", color: C.PURPLE },
|
|
13393
|
+
{ threshold: 1e3, divisor: 1e3, unit: "kt", color: C.BLUE },
|
|
13394
|
+
{ threshold: 0, divisor: 1, unit: "t", color: C.TEXT_DIM }
|
|
13395
|
+
];
|
|
13396
|
+
function _fmtMagnitude(n, tiers, zeroLabel) {
|
|
13397
|
+
if (zeroLabel !== void 0 && n === 0) {
|
|
13398
|
+
return `${fg(...C.TEXT_DIM)}${zeroLabel}${RESET}`;
|
|
13399
|
+
}
|
|
13400
|
+
if (n < 0) {
|
|
13401
|
+
const a = -n;
|
|
13402
|
+
const color = C.TEXT_DIM;
|
|
13403
|
+
for (const tier of tiers) {
|
|
13404
|
+
if (a >= tier.threshold && tier.threshold > 0) {
|
|
13405
|
+
return `${fg(...color)}-${(a / tier.divisor).toLocaleString("en", { maximumFractionDigits: 1 })} ${tier.unit}${RESET}`;
|
|
13406
|
+
}
|
|
13407
|
+
}
|
|
13408
|
+
const lastTier2 = tiers[tiers.length - 1];
|
|
13409
|
+
if (lastTier2) {
|
|
13410
|
+
return `${fg(...color)}-${a} ${lastTier2.unit}${RESET}`;
|
|
13411
|
+
}
|
|
13412
|
+
return `${fg(...color)}-${a}${RESET}`;
|
|
13413
|
+
}
|
|
13414
|
+
for (const tier of tiers) {
|
|
13415
|
+
if (n >= tier.threshold && tier.threshold > 0) {
|
|
13416
|
+
return `${fg(...tier.color)}${(n / tier.divisor).toLocaleString("en", { maximumFractionDigits: 1 })} ${tier.unit}${RESET}`;
|
|
13417
|
+
}
|
|
13418
|
+
}
|
|
13419
|
+
const lastTier = tiers[tiers.length - 1];
|
|
13420
|
+
if (lastTier) {
|
|
13421
|
+
return `${fg(...lastTier.color)}${n} ${lastTier.unit}${RESET}`;
|
|
13422
|
+
}
|
|
13423
|
+
return `${n}${RESET}`;
|
|
13424
|
+
}
|
|
13425
|
+
function _fmtBytes(n) {
|
|
13426
|
+
return _fmtMagnitude(n, _BYTE_TIERS);
|
|
13427
|
+
}
|
|
13428
|
+
function _fmtTokens(n) {
|
|
13429
|
+
return _fmtMagnitude(n, _TOKEN_TIERS, "0 t");
|
|
13430
|
+
}
|
|
13431
|
+
function _fmtPct(fraction) {
|
|
13432
|
+
return `${(fraction * 100).toFixed(1)}%`;
|
|
13433
|
+
}
|
|
13434
|
+
function _fmtDelta(delta) {
|
|
13435
|
+
if (!delta && delta !== 0) {
|
|
13436
|
+
return "";
|
|
13437
|
+
}
|
|
13438
|
+
const up = (delta ?? 0) >= 0;
|
|
13439
|
+
const color = up ? C.GREEN5 : C.RED;
|
|
13440
|
+
const arrow = up ? "\u2191" : "\u2193";
|
|
13441
|
+
return ` ${fg(...color)}${arrow} ${Math.round(Math.abs(delta ?? 0))}%${RESET}`;
|
|
13442
|
+
}
|
|
13443
|
+
var _EIGHTHS = ["\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589"];
|
|
13444
|
+
var _BLOCK = "\u2588";
|
|
13445
|
+
var _TRACK = "\u2591";
|
|
13446
|
+
var _GRADIENT = [C.GREEN1, C.GREEN2, C.GREEN3, C.GREEN4, C.GREEN5];
|
|
13447
|
+
function _distribute(total, n) {
|
|
13448
|
+
if (total <= 0 || n <= 0) {
|
|
13449
|
+
return Array(Math.max(0, n)).fill(0);
|
|
13450
|
+
}
|
|
13451
|
+
const base = Math.floor(total / n);
|
|
13452
|
+
const rem = total % n;
|
|
13453
|
+
return Array.from({ length: n }, (_, i) => base + (i >= n - rem ? 1 : 0));
|
|
13454
|
+
}
|
|
13455
|
+
function _renderBar(fraction, width = _BAR_W) {
|
|
13456
|
+
const f = Math.max(0, Math.min(1, fraction));
|
|
13457
|
+
const raw = f * width;
|
|
13458
|
+
let nFull = Math.floor(raw);
|
|
13459
|
+
const eighths = Math.round((raw - nFull) * 8);
|
|
13460
|
+
if (eighths >= 8) {
|
|
13461
|
+
nFull += 1;
|
|
13462
|
+
}
|
|
13463
|
+
const hasPartial = eighths > 0 && eighths < 8;
|
|
13464
|
+
const nTrack = Math.max(0, width - nFull - (hasPartial ? 1 : 0));
|
|
13465
|
+
const counts = _distribute(nFull, _GRADIENT.length);
|
|
13466
|
+
let bar = counts.map((count, i) => count > 0 ? `${fg(_GRADIENT[i][0], _GRADIENT[i][1], _GRADIENT[i][2])}${_BLOCK.repeat(count)}` : "").join("");
|
|
13467
|
+
if (hasPartial) {
|
|
13468
|
+
const lastGrad = _GRADIENT[_GRADIENT.length - 1];
|
|
13469
|
+
bar += `${fg(lastGrad[0], lastGrad[1], lastGrad[2])}${_EIGHTHS[eighths - 1]}`;
|
|
13470
|
+
}
|
|
13471
|
+
if (nTrack > 0) {
|
|
13472
|
+
bar += `${fg(...C.TRACK)}${_TRACK.repeat(nTrack)}`;
|
|
13473
|
+
}
|
|
13474
|
+
return bar + RESET;
|
|
13475
|
+
}
|
|
13476
|
+
var _SPARK = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
13477
|
+
function _resample(vals, length) {
|
|
13478
|
+
if (vals.length === 0) {
|
|
13479
|
+
return Array(length).fill(0);
|
|
13480
|
+
}
|
|
13481
|
+
if (vals.length === length) {
|
|
13482
|
+
return [...vals];
|
|
13483
|
+
}
|
|
13484
|
+
const result = [];
|
|
13485
|
+
for (let i = 0; i < length; i++) {
|
|
13486
|
+
const src = i / (length - 1 || 1) * (vals.length - 1);
|
|
13487
|
+
const lo = Math.floor(src);
|
|
13488
|
+
const hi = Math.min(vals.length - 1, lo + 1);
|
|
13489
|
+
const t = src - lo;
|
|
13490
|
+
const loVal = vals[lo] ?? 0;
|
|
13491
|
+
const hiVal = vals[hi] ?? 0;
|
|
13492
|
+
result.push(loVal * (1 - t) + hiVal * t);
|
|
13493
|
+
}
|
|
13494
|
+
return result;
|
|
13495
|
+
}
|
|
13496
|
+
function _renderSparkline(values, width = 8) {
|
|
13497
|
+
const pts = _resample(values, width);
|
|
13498
|
+
const hi = pts.length > 0 ? Math.max(...pts) : 1;
|
|
13499
|
+
const lo = pts.length > 0 ? Math.min(...pts) : 0;
|
|
13500
|
+
const span = hi - lo || 1;
|
|
13501
|
+
const chars = [];
|
|
13502
|
+
for (let i = 0; i < pts.length; i++) {
|
|
13503
|
+
const v = pts[i];
|
|
13504
|
+
if (v === void 0) continue;
|
|
13505
|
+
const idx = Math.min(7, Math.floor((v - lo) / span * 8));
|
|
13506
|
+
const color = lerpRgb(C.GREEN1, C.GREEN5, i / (width - 1 || 1));
|
|
13507
|
+
chars.push(`${fg(color[0], color[1], color[2])}${_SPARK[idx]}`);
|
|
13508
|
+
}
|
|
13509
|
+
return chars.join("") + RESET;
|
|
13510
|
+
}
|
|
13511
|
+
function _tokenOrByteShare(itemTokens, itemBytes, totalTokens, totalBytes) {
|
|
13512
|
+
if (totalTokens > 0) {
|
|
13513
|
+
return itemTokens / totalTokens;
|
|
13514
|
+
}
|
|
13515
|
+
if (totalBytes > 0) {
|
|
13516
|
+
return itemBytes / totalBytes;
|
|
13517
|
+
}
|
|
13518
|
+
return 0;
|
|
13519
|
+
}
|
|
13520
|
+
function _barFraction(itemBytes, grossBytes) {
|
|
13521
|
+
return itemBytes > 0 ? itemBytes / grossBytes : 0;
|
|
13522
|
+
}
|
|
13523
|
+
function _computeShareDenominators(items) {
|
|
13524
|
+
let grossBytesSum = 0;
|
|
13525
|
+
let shareByteSum = 0;
|
|
13526
|
+
let shareTokensSum = 0;
|
|
13527
|
+
for (const item of items) {
|
|
13528
|
+
if (item.bytes > 0) {
|
|
13529
|
+
grossBytesSum += item.bytes;
|
|
13530
|
+
}
|
|
13531
|
+
shareByteSum += Math.abs(item.bytes);
|
|
13532
|
+
shareTokensSum += Math.abs(item.tokens);
|
|
13533
|
+
}
|
|
13534
|
+
return {
|
|
13535
|
+
grossBytes: Math.max(grossBytesSum, 1),
|
|
13536
|
+
shareBytesDenom: Math.max(shareByteSum, 1),
|
|
13537
|
+
shareTokensDenom: shareTokensSum
|
|
13538
|
+
};
|
|
13539
|
+
}
|
|
13540
|
+
function _absShare(itemBytes, itemTokens, shareBytesDenom, shareTokensDenom) {
|
|
13541
|
+
if (shareTokensDenom === 0) {
|
|
13542
|
+
return itemBytes / shareBytesDenom;
|
|
13543
|
+
}
|
|
13544
|
+
return itemTokens / shareTokensDenom;
|
|
13545
|
+
}
|
|
13546
|
+
function _sectionHeader(title, subtitle = "") {
|
|
13547
|
+
const sub = subtitle ? ` ${fg(...C.TEXT_MUTED)}${subtitle}${RESET}` : "";
|
|
13548
|
+
return [
|
|
13549
|
+
"",
|
|
13550
|
+
`${_M}${fg(...C.TEXT_BRIGHT)}${title}${RESET}${sub}`,
|
|
13551
|
+
_RULE
|
|
13552
|
+
];
|
|
13553
|
+
}
|
|
13554
|
+
function _tableHeader(firstColLabel) {
|
|
13555
|
+
return [
|
|
13556
|
+
_M,
|
|
13557
|
+
padR(`${fg(...C.TEXT_DIM)}${firstColLabel}${RESET}`, _COL_NAME),
|
|
13558
|
+
" ",
|
|
13559
|
+
padR(`${fg(...C.TEXT_DIM)}savings${RESET}`, _BAR_W),
|
|
13560
|
+
" ",
|
|
13561
|
+
padL(`${fg(...C.TEXT_DIM)}data saved${RESET}`, _COL_DATA),
|
|
13562
|
+
" ",
|
|
13563
|
+
padL(`${fg(...C.TEXT_DIM)}tokens saved${RESET}`, _COL_TOKENS),
|
|
13564
|
+
" ",
|
|
13565
|
+
padL(`${fg(...C.TEXT_DIM)}share${RESET}`, _COL_SHARE),
|
|
13566
|
+
" ",
|
|
13567
|
+
padL(`${fg(...C.TEXT_DIM)}events${RESET}`, _COL_EVENTS)
|
|
13568
|
+
].join("");
|
|
13569
|
+
}
|
|
13570
|
+
function _tableRow({
|
|
13571
|
+
name,
|
|
13572
|
+
fraction,
|
|
13573
|
+
bytes,
|
|
13574
|
+
tokens,
|
|
13575
|
+
events,
|
|
13576
|
+
share,
|
|
13577
|
+
bytesModeOnly = false,
|
|
13578
|
+
namePrefix = "",
|
|
13579
|
+
nameColor = C.TEXT_PRIMARY
|
|
13580
|
+
}) {
|
|
13581
|
+
const prefixW = vlen(namePrefix);
|
|
13582
|
+
const maxName = _COL_NAME - prefixW;
|
|
13583
|
+
const truncated = name.length > maxName ? name.slice(0, maxName - 1) + "\u2026" : name;
|
|
13584
|
+
const nameStr = padR(`${namePrefix}${fg(...nameColor)}${truncated}${RESET}`, _COL_NAME);
|
|
13585
|
+
const dataStr = padL(_fmtBytes(bytes), _COL_DATA);
|
|
13586
|
+
const tokStr = bytesModeOnly ? padL(`${fg(...C.TEXT_DIM)}\u2014${RESET}`, _COL_TOKENS) : padL(_fmtTokens(tokens), _COL_TOKENS);
|
|
13587
|
+
const sharePct = share * 100;
|
|
13588
|
+
let shareColor;
|
|
13589
|
+
if (sharePct < 0) {
|
|
13590
|
+
shareColor = C.RED;
|
|
13591
|
+
} else if (sharePct >= 50) {
|
|
13592
|
+
shareColor = C.GREEN5;
|
|
13593
|
+
} else if (sharePct >= 10) {
|
|
13594
|
+
shareColor = C.TEXT_PRIMARY;
|
|
13595
|
+
} else {
|
|
13596
|
+
shareColor = C.TEXT_MUTED;
|
|
13597
|
+
}
|
|
13598
|
+
const shareStr = padL(`${fg(...shareColor)}${_fmtPct(share)}${RESET}`, _COL_SHARE);
|
|
13599
|
+
const evStr = padL(`${fg(...C.TEXT_PRIMARY)}${events.toLocaleString()}${RESET}`, _COL_EVENTS);
|
|
13600
|
+
return [_M, nameStr, " ", _renderBar(fraction), " ", dataStr, " ", tokStr, " ", shareStr, " ", evStr].join("");
|
|
13601
|
+
}
|
|
13602
|
+
function _renderKpiSection(stats) {
|
|
13603
|
+
const totals = stats.totals;
|
|
13604
|
+
const colW = Math.floor((_CONTENT_W - _M.length * 2) / 3);
|
|
13605
|
+
function card(label, value, delta, spark2) {
|
|
13606
|
+
return [
|
|
13607
|
+
padR(`${fg(C.TEXT_MUTED[0], C.TEXT_MUTED[1], C.TEXT_MUTED[2])}${label}${RESET}`, colW),
|
|
13608
|
+
padR(`${fg(C.TEXT_BRIGHT[0], C.TEXT_BRIGHT[1], C.TEXT_BRIGHT[2])}${value}${RESET}${delta}`, colW),
|
|
13609
|
+
spark2 !== null ? padR(spark2, colW) : padR("", colW)
|
|
13610
|
+
];
|
|
13611
|
+
}
|
|
13612
|
+
const spark = totals.sparklines;
|
|
13613
|
+
const c1 = card(
|
|
13614
|
+
"events",
|
|
13615
|
+
`${totals.events.toLocaleString()}`,
|
|
13616
|
+
_fmtDelta(totals.events_delta ?? null),
|
|
13617
|
+
spark ? _renderSparkline(spark.events) : null
|
|
13618
|
+
);
|
|
13619
|
+
const c2 = card(
|
|
13620
|
+
"data saved",
|
|
13621
|
+
_fmtBytes(totals.bytes),
|
|
13622
|
+
_fmtDelta(totals.bytes_delta ?? null),
|
|
13623
|
+
spark ? _renderSparkline(spark.bytes) : null
|
|
13624
|
+
);
|
|
13625
|
+
const c3 = card(
|
|
13626
|
+
"tokens saved",
|
|
13627
|
+
_fmtTokens(totals.tokens),
|
|
13628
|
+
_fmtDelta(totals.tokens_delta ?? null),
|
|
13629
|
+
spark ? _renderSparkline(spark.tokens) : null
|
|
13630
|
+
);
|
|
13631
|
+
const border = fg(C.TEXT_DIM[0], C.TEXT_DIM[1], C.TEXT_DIM[2]);
|
|
13632
|
+
const frameBar = "\u2500".repeat(colW * 3 + 2);
|
|
13633
|
+
function framed(content) {
|
|
13634
|
+
return `${_M}${border}\u2502${RESET} ${content} ${border}\u2502${RESET}`;
|
|
13635
|
+
}
|
|
13636
|
+
const lines = [
|
|
13637
|
+
"",
|
|
13638
|
+
`${_M}${border}\u256D${frameBar}\u256E${RESET}`,
|
|
13639
|
+
framed(c1[0] + c2[0] + c3[0]),
|
|
13640
|
+
framed(c1[1] + c2[1] + c3[1])
|
|
13641
|
+
];
|
|
13642
|
+
if (spark) {
|
|
13643
|
+
lines.push(framed(c1[2] + c2[2] + c3[2]));
|
|
13644
|
+
}
|
|
13645
|
+
lines.push(`${_M}${border}\u2570${frameBar}\u256F${RESET}`);
|
|
13646
|
+
return lines;
|
|
13647
|
+
}
|
|
13648
|
+
var _KIND_GROUPS = [
|
|
13649
|
+
{
|
|
13650
|
+
label: "Read savings",
|
|
13651
|
+
members: /* @__PURE__ */ new Set([
|
|
13652
|
+
"read_replacement",
|
|
13653
|
+
"section_replacement",
|
|
13654
|
+
"symbol_read",
|
|
13655
|
+
"section_read",
|
|
13656
|
+
"stub_view",
|
|
13657
|
+
"outline",
|
|
13658
|
+
"exports"
|
|
13659
|
+
])
|
|
13660
|
+
},
|
|
13661
|
+
{ label: "Lookups", members: /* @__PURE__ */ new Set(["symbol_lookup", "semantic_search", "map_lookup"]) },
|
|
13662
|
+
{
|
|
13663
|
+
label: "Images",
|
|
13664
|
+
members: /* @__PURE__ */ new Set(["image_shrink", "gdrive_image", "webfetch_image", "image_shrink_skipped"])
|
|
13665
|
+
},
|
|
13666
|
+
{
|
|
13667
|
+
label: "Hints",
|
|
13668
|
+
members: /* @__PURE__ */ new Set([
|
|
13669
|
+
"session_hint",
|
|
13670
|
+
"session_hint_overhead",
|
|
13671
|
+
"read_dedup_hint",
|
|
13672
|
+
"grep_dedup_hint",
|
|
13673
|
+
"diff_hint",
|
|
13674
|
+
"predictive_prefetch_hit",
|
|
13675
|
+
"read_partial_overlap_hint"
|
|
13676
|
+
])
|
|
13677
|
+
},
|
|
13678
|
+
{
|
|
13679
|
+
label: "Bash",
|
|
13680
|
+
members: /* @__PURE__ */ new Set([
|
|
13681
|
+
"bash_dedup_hint",
|
|
13682
|
+
"bash_output_cached",
|
|
13683
|
+
"bash_output_recall",
|
|
13684
|
+
"bash_output_recall_miss",
|
|
13685
|
+
"bash_dedup_stale",
|
|
13686
|
+
"bash_range_read_hint",
|
|
13687
|
+
"bash_streak_hint",
|
|
13688
|
+
"bash_poll_hint",
|
|
13689
|
+
"env_probe_cache_hit",
|
|
13690
|
+
"git_diff_scope_hint",
|
|
13691
|
+
"dep_list_cache_hit",
|
|
13692
|
+
"bash_read_equiv_already_read",
|
|
13693
|
+
"bash_grep_result_cache_hit",
|
|
13694
|
+
"git_diff_context_trimmed"
|
|
13695
|
+
])
|
|
13696
|
+
},
|
|
13697
|
+
{
|
|
13698
|
+
label: "Web",
|
|
13699
|
+
members: /* @__PURE__ */ new Set([
|
|
13700
|
+
"web_dedup_hint",
|
|
13701
|
+
"web_output_cached",
|
|
13702
|
+
"web_output_recall",
|
|
13703
|
+
"web_output_recall_miss",
|
|
13704
|
+
"web_dedup_stale"
|
|
13705
|
+
])
|
|
13706
|
+
},
|
|
13707
|
+
{
|
|
13708
|
+
label: "Compact / Skills",
|
|
13709
|
+
members: /* @__PURE__ */ new Set([
|
|
13710
|
+
"compact_manifest",
|
|
13711
|
+
"compact_assist",
|
|
13712
|
+
"compact_recovery",
|
|
13713
|
+
"skill_body_recall",
|
|
13714
|
+
"skill_compact_served",
|
|
13715
|
+
"skill_cached",
|
|
13716
|
+
"resume_packet",
|
|
13717
|
+
"decision_log"
|
|
13718
|
+
])
|
|
13719
|
+
}
|
|
13720
|
+
];
|
|
13721
|
+
function _kindGroupLabel(kind) {
|
|
13722
|
+
if (kind.startsWith("bash_compress:")) {
|
|
13723
|
+
return "Bash";
|
|
13724
|
+
}
|
|
13725
|
+
for (const group of _KIND_GROUPS) {
|
|
13726
|
+
if (group.members.has(kind)) {
|
|
13727
|
+
return group.label;
|
|
13728
|
+
}
|
|
13729
|
+
}
|
|
13730
|
+
return "Other";
|
|
13731
|
+
}
|
|
13732
|
+
function _groupSeparator(label) {
|
|
13733
|
+
return `${_M} ${fg(...C.TEXT_DIM)}${label}${RESET}`;
|
|
13734
|
+
}
|
|
13735
|
+
function _renderByKindSection(stats) {
|
|
13736
|
+
if (stats.by_kind.length === 0) {
|
|
13737
|
+
return [];
|
|
13738
|
+
}
|
|
13739
|
+
const lines = [..._sectionHeader("By kind"), _tableHeader("name")];
|
|
13740
|
+
const { grossBytes, shareBytesDenom, shareTokensDenom } = _computeShareDenominators(stats.by_kind);
|
|
13741
|
+
const kindNames = new Set(stats.by_kind.map((k) => k.kind));
|
|
13742
|
+
const bytesModeKinds = stats.by_kind.filter((k) => k.bytes_mode_only).map((k) => k.kind);
|
|
13743
|
+
function share(k) {
|
|
13744
|
+
if (k.bytes_mode_only) {
|
|
13745
|
+
return k.bytes / shareBytesDenom;
|
|
13746
|
+
}
|
|
13747
|
+
return _absShare(k.bytes, k.tokens, shareBytesDenom, shareTokensDenom);
|
|
13748
|
+
}
|
|
13749
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
13750
|
+
for (const k of stats.by_kind) {
|
|
13751
|
+
const grp = _kindGroupLabel(k.kind);
|
|
13752
|
+
if (!byGroup.has(grp)) {
|
|
13753
|
+
byGroup.set(grp, []);
|
|
13754
|
+
}
|
|
13755
|
+
byGroup.get(grp).push(k);
|
|
13756
|
+
}
|
|
13757
|
+
for (const grpKinds of byGroup.values()) {
|
|
13758
|
+
grpKinds.sort((a, b) => share(b) - share(a));
|
|
13759
|
+
}
|
|
13760
|
+
let firstGroup = true;
|
|
13761
|
+
for (const group of _KIND_GROUPS) {
|
|
13762
|
+
const groupKinds = byGroup.get(group.label);
|
|
13763
|
+
if (!groupKinds || groupKinds.length === 0) {
|
|
13764
|
+
continue;
|
|
13765
|
+
}
|
|
13766
|
+
if (!firstGroup) {
|
|
13767
|
+
lines.push("");
|
|
13768
|
+
}
|
|
13769
|
+
firstGroup = false;
|
|
13770
|
+
lines.push(_groupSeparator(group.label));
|
|
13771
|
+
for (const k of groupKinds) {
|
|
13772
|
+
const s = share(k);
|
|
13773
|
+
lines.push(
|
|
13774
|
+
_tableRow({
|
|
13775
|
+
name: k.kind,
|
|
13776
|
+
fraction: _barFraction(k.bytes, grossBytes),
|
|
13777
|
+
bytes: k.bytes,
|
|
13778
|
+
tokens: k.tokens,
|
|
13779
|
+
events: k.events,
|
|
13780
|
+
share: s,
|
|
13781
|
+
bytesModeOnly: k.bytes_mode_only ?? false
|
|
13782
|
+
})
|
|
13783
|
+
);
|
|
13784
|
+
}
|
|
13785
|
+
}
|
|
13786
|
+
if (bytesModeKinds.length > 0) {
|
|
13787
|
+
const names = bytesModeKinds.join(", ");
|
|
13788
|
+
lines.push(`${_M}${fg(...C.TEXT_DIM)}i ${names} ${_STATS_MESSAGES.bytesModeOnlyNote}${RESET}`);
|
|
13789
|
+
}
|
|
13790
|
+
if (kindNames.has("session_hint") && kindNames.has("session_hint_overhead")) {
|
|
13791
|
+
lines.push(`${_M}${fg(...C.TEXT_DIM)}i ${_STATS_MESSAGES.sessionHintSplitNote}${RESET}`);
|
|
13792
|
+
}
|
|
13793
|
+
return lines;
|
|
13794
|
+
}
|
|
13795
|
+
var _SOURCE_COLORS = {
|
|
13796
|
+
image: C.PURPLE,
|
|
13797
|
+
hint: C.BLUE,
|
|
13798
|
+
read: C.GREEN4,
|
|
13799
|
+
compact: C.TEAL,
|
|
13800
|
+
bash: C.ORANGE,
|
|
13801
|
+
web: C.YELLOW,
|
|
13802
|
+
other: C.TEXT_MUTED
|
|
13803
|
+
};
|
|
13804
|
+
function _sourceColor(source) {
|
|
13805
|
+
const color = _SOURCE_COLORS[source];
|
|
13806
|
+
return color || C.TEXT_MUTED;
|
|
13807
|
+
}
|
|
13808
|
+
function _renderBySourceSection(stats) {
|
|
13809
|
+
if (!stats.by_source || stats.by_source.length === 0) {
|
|
13810
|
+
return [];
|
|
13811
|
+
}
|
|
13812
|
+
const lines = [..._sectionHeader("By source"), _tableHeader("source")];
|
|
13813
|
+
const { grossBytes, shareBytesDenom, shareTokensDenom } = _computeShareDenominators(stats.by_source);
|
|
13814
|
+
function share(s) {
|
|
13815
|
+
return _absShare(s.bytes, s.tokens, shareBytesDenom, shareTokensDenom);
|
|
13816
|
+
}
|
|
13817
|
+
for (const s of [...stats.by_source].sort((a, b) => share(b) - share(a))) {
|
|
13818
|
+
const s_val = share(s);
|
|
13819
|
+
const color = _sourceColor(s.source);
|
|
13820
|
+
lines.push(
|
|
13821
|
+
_tableRow({
|
|
13822
|
+
name: s.source,
|
|
13823
|
+
fraction: _barFraction(s.bytes, grossBytes),
|
|
13824
|
+
bytes: s.bytes,
|
|
13825
|
+
tokens: s.tokens,
|
|
13826
|
+
events: s.events,
|
|
13827
|
+
share: s_val,
|
|
13828
|
+
namePrefix: `${fg(...color)}\u25CF${RESET} `,
|
|
13829
|
+
nameColor: C.TEXT_PRIMARY
|
|
13830
|
+
})
|
|
13831
|
+
);
|
|
13832
|
+
}
|
|
13833
|
+
return lines;
|
|
13834
|
+
}
|
|
13835
|
+
function _renderByCommandSection(stats) {
|
|
13836
|
+
if (!stats.by_command || stats.by_command.length === 0) {
|
|
13837
|
+
return [];
|
|
13838
|
+
}
|
|
13839
|
+
const lines = [..._sectionHeader("By command"), _tableHeader("command")];
|
|
13840
|
+
const { grossBytes, shareBytesDenom, shareTokensDenom } = _computeShareDenominators(stats.by_command);
|
|
13841
|
+
function share(c) {
|
|
13842
|
+
return _absShare(c.bytes, c.tokens, shareBytesDenom, shareTokensDenom);
|
|
13843
|
+
}
|
|
13844
|
+
for (const c of [...stats.by_command].sort((a, b) => share(b) - share(a))) {
|
|
13845
|
+
const s_val = share(c);
|
|
13846
|
+
lines.push(
|
|
13847
|
+
_tableRow({
|
|
13848
|
+
name: c.command,
|
|
13849
|
+
fraction: _barFraction(c.bytes, grossBytes),
|
|
13850
|
+
bytes: c.bytes,
|
|
13851
|
+
tokens: c.tokens,
|
|
13852
|
+
events: c.events,
|
|
13853
|
+
share: s_val,
|
|
13854
|
+
nameColor: C.TEXT_PRIMARY
|
|
13855
|
+
})
|
|
13856
|
+
);
|
|
13857
|
+
}
|
|
13858
|
+
return lines;
|
|
13859
|
+
}
|
|
13860
|
+
function _renderByDaySection(stats) {
|
|
13861
|
+
if (stats.by_day.length === 0) {
|
|
13862
|
+
return [];
|
|
13863
|
+
}
|
|
13864
|
+
const lines = [..._sectionHeader("By day"), _tableHeader("date")];
|
|
13865
|
+
function share(d) {
|
|
13866
|
+
return _tokenOrByteShare(d.tokens, d.bytes, stats.totals.tokens, stats.totals.bytes);
|
|
13867
|
+
}
|
|
13868
|
+
for (const d of [...stats.by_day].sort((a, b) => b.date.localeCompare(a.date))) {
|
|
13869
|
+
const s = share(d);
|
|
13870
|
+
lines.push(
|
|
13871
|
+
_tableRow({
|
|
13872
|
+
name: d.date,
|
|
13873
|
+
fraction: s,
|
|
13874
|
+
bytes: d.bytes,
|
|
13875
|
+
tokens: d.tokens,
|
|
13876
|
+
events: d.events,
|
|
13877
|
+
share: s
|
|
13878
|
+
})
|
|
13879
|
+
);
|
|
13880
|
+
}
|
|
13881
|
+
return lines;
|
|
13882
|
+
}
|
|
13883
|
+
var _PROJECT_COLORS = [C.PURPLE, C.TEAL, C.BLUE, C.GREEN4, C.TEXT_MUTED];
|
|
13884
|
+
function _hashColor(hashStr) {
|
|
13885
|
+
let n = 0;
|
|
13886
|
+
for (const c of hashStr) {
|
|
13887
|
+
n += c.charCodeAt(0);
|
|
13888
|
+
}
|
|
13889
|
+
return _PROJECT_COLORS[n % _PROJECT_COLORS.length] ?? C.TEXT_MUTED;
|
|
13890
|
+
}
|
|
13891
|
+
function _renderByProjectSection(stats) {
|
|
13892
|
+
if (stats.by_project.length === 0) {
|
|
13893
|
+
return [];
|
|
13894
|
+
}
|
|
13895
|
+
const projectTotalBytes = stats.by_project.reduce((s, p) => s + p.bytes, 0);
|
|
13896
|
+
const projectTotalTokens = stats.by_project.reduce((s, p) => s + p.tokens, 0);
|
|
13897
|
+
const lines = [..._sectionHeader(`By project (top ${stats.by_project.length})`), _tableHeader("project")];
|
|
13898
|
+
function share(p) {
|
|
13899
|
+
return _tokenOrByteShare(p.tokens, p.bytes, projectTotalTokens, projectTotalBytes);
|
|
13900
|
+
}
|
|
13901
|
+
for (const p of [...stats.by_project].sort((a, b) => share(b) - share(a))) {
|
|
13902
|
+
const s = share(p);
|
|
13903
|
+
const color = _hashColor(p.hash);
|
|
13904
|
+
lines.push(
|
|
13905
|
+
_tableRow({
|
|
13906
|
+
name: p.project,
|
|
13907
|
+
fraction: s,
|
|
13908
|
+
bytes: p.bytes,
|
|
13909
|
+
tokens: p.tokens,
|
|
13910
|
+
events: p.events,
|
|
13911
|
+
share: s,
|
|
13912
|
+
namePrefix: `${fg(...color)}\u25CF${RESET} `,
|
|
13913
|
+
nameColor: C.TEXT_PRIMARY
|
|
13914
|
+
})
|
|
13915
|
+
);
|
|
13916
|
+
lines.push(`${_M} ${fg(...C.TEXT_DIM)}\u2514\u2500 ${p.hash} ${stripAnsi(p.path)}${RESET}`);
|
|
13917
|
+
}
|
|
13918
|
+
return lines;
|
|
13919
|
+
}
|
|
13920
|
+
function _renderInsightsSection(stats) {
|
|
13921
|
+
const lines = [..._sectionHeader("Insights")];
|
|
13922
|
+
const bullet = `${fg(...C.GREEN3)}\u25B8${RESET}`;
|
|
13923
|
+
function dim(s) {
|
|
13924
|
+
return `${fg(...C.TEXT_MUTED)}${s}${RESET}`;
|
|
13925
|
+
}
|
|
13926
|
+
const topKind = stats.by_kind.reduce((max, k) => k.bytes > (max?.bytes || -Infinity) ? k : max, stats.by_kind[0]);
|
|
13927
|
+
if (topKind) {
|
|
13928
|
+
const share = stats.totals.bytes > 0 ? topKind.bytes / stats.totals.bytes : 0;
|
|
13929
|
+
lines.push(
|
|
13930
|
+
`${_M}${bullet} ${dim(_STATS_MESSAGES.insights.biggestSaver)}${fg(...C.TEXT_PRIMARY)}${topKind.kind}${RESET}${dim(" \u2014 ")}${fg(...C.GREEN5)}${_fmtPct(share)}${RESET}${dim(` of saved data across ${topKind.events.toLocaleString()} events`)}`
|
|
13931
|
+
);
|
|
13932
|
+
}
|
|
13933
|
+
const topDay = stats.by_day.reduce((max, d) => d.events > (max?.events || -Infinity) ? d : max, stats.by_day[0]);
|
|
13934
|
+
if (topDay) {
|
|
13935
|
+
lines.push(
|
|
13936
|
+
`${_M}${bullet} ${dim(_STATS_MESSAGES.insights.mostActive)}${fg(...C.TEXT_PRIMARY)}${topDay.date}${RESET}${dim(" \u2014 ")}${topDay.events.toLocaleString()} events, ${_fmtBytes(topDay.bytes)}${dim(" saved")}`
|
|
13937
|
+
);
|
|
13938
|
+
}
|
|
13939
|
+
const tokenKinds = stats.by_kind.filter((k) => !k.bytes_mode_only);
|
|
13940
|
+
const topToken = tokenKinds.reduce((max, k) => k.tokens > (max?.tokens || -Infinity) ? k : max, tokenKinds[0]);
|
|
13941
|
+
if (topToken) {
|
|
13942
|
+
lines.push(
|
|
13943
|
+
`${_M}${bullet} ${dim(_STATS_MESSAGES.insights.tokenLeader)}${fg(...C.TEXT_PRIMARY)}${topToken.kind}${RESET}${dim(" \u2014 ")}${_fmtTokens(topToken.tokens)}${dim(` saved in ${topToken.events.toLocaleString()} events`)}`
|
|
13944
|
+
);
|
|
13945
|
+
}
|
|
13946
|
+
return lines;
|
|
13947
|
+
}
|
|
13948
|
+
function _renderHeader(stats) {
|
|
13949
|
+
let line = `${_M}${fg(...C.TEXT_BRIGHT)}token-goat${RESET}`;
|
|
13950
|
+
if (stats.version) {
|
|
13951
|
+
line += ` ${fg(...C.TEXT_MUTED)}v${stats.version}${RESET}`;
|
|
13952
|
+
}
|
|
13953
|
+
if (stats.window_label) {
|
|
13954
|
+
line += ` ${fg(...C.TEXT_DIM)}\xB7 ${stats.window_label}${RESET}`;
|
|
13955
|
+
}
|
|
13956
|
+
return [line];
|
|
13957
|
+
}
|
|
13958
|
+
function renderStats(stats) {
|
|
13959
|
+
const sections = [
|
|
13960
|
+
_renderHeader(stats),
|
|
13961
|
+
_renderKpiSection(stats),
|
|
13962
|
+
_renderByKindSection(stats),
|
|
13963
|
+
_renderBySourceSection(stats),
|
|
13964
|
+
_renderByCommandSection(stats),
|
|
13965
|
+
_renderByDaySection(stats),
|
|
13966
|
+
_renderByProjectSection(stats),
|
|
13967
|
+
_renderInsightsSection(stats),
|
|
13968
|
+
[""]
|
|
13969
|
+
];
|
|
13970
|
+
return sections.flatMap((s) => s).join("\n");
|
|
13971
|
+
}
|
|
13972
|
+
|
|
13973
|
+
// src/stats.ts
|
|
12687
13974
|
var SOURCE_IMAGE = "image";
|
|
12688
13975
|
var SOURCE_HINT = "hint";
|
|
12689
13976
|
var SOURCE_READ = "read";
|
|
@@ -12692,6 +13979,7 @@ var SOURCE_WEB = "web";
|
|
|
12692
13979
|
var SOURCE_MCP = "mcp";
|
|
12693
13980
|
var SOURCE_SKILL = "skill";
|
|
12694
13981
|
var SOURCE_OTHER = "other";
|
|
13982
|
+
var _BYTES_MODE_ONLY_KINDS = /* @__PURE__ */ new Set(["webfetch_image", "gdrive_image"]);
|
|
12695
13983
|
var KIND_TO_SOURCE = {
|
|
12696
13984
|
image_shrink: SOURCE_IMAGE,
|
|
12697
13985
|
image_shrink_cache_hit: SOURCE_IMAGE,
|
|
@@ -12734,7 +14022,15 @@ var COMMAND_KINDS = {
|
|
|
12734
14022
|
skeleton: /* @__PURE__ */ new Set(["stub_view"]),
|
|
12735
14023
|
refs: /* @__PURE__ */ new Set(["symbol_read"]),
|
|
12736
14024
|
map: /* @__PURE__ */ new Set(["map_lookup"]),
|
|
12737
|
-
changed: /* @__PURE__ */ new Set(["changed_lookup"])
|
|
14025
|
+
changed: /* @__PURE__ */ new Set(["changed_lookup"]),
|
|
14026
|
+
npm: /* @__PURE__ */ new Set([
|
|
14027
|
+
"bash_compress:npm_install",
|
|
14028
|
+
"bash_compress:npm_ci",
|
|
14029
|
+
"bash_compress:npm_audit",
|
|
14030
|
+
"bash_compress:npm_ls",
|
|
14031
|
+
"bash_compress:npm_outdated",
|
|
14032
|
+
"bash_compress:npx"
|
|
14033
|
+
])
|
|
12738
14034
|
};
|
|
12739
14035
|
var OVERHEAD_SUFFIX = "_overhead";
|
|
12740
14036
|
function kindToSource(kind) {
|
|
@@ -12759,7 +14055,7 @@ function incBucket(bucket, bytesSaved, tokensSaved) {
|
|
|
12759
14055
|
bucket.tokens_saved += tokensSaved;
|
|
12760
14056
|
}
|
|
12761
14057
|
function getGlobalDb() {
|
|
12762
|
-
const dbPath =
|
|
14058
|
+
const dbPath = path12.join(dataDir(), "global.db");
|
|
12763
14059
|
return getDb(dbPath);
|
|
12764
14060
|
}
|
|
12765
14061
|
function summarize(windowDays = 30, testDb) {
|
|
@@ -12833,12 +14129,7 @@ function summarize(windowDays = 30, testDb) {
|
|
|
12833
14129
|
window_days: windowDays
|
|
12834
14130
|
};
|
|
12835
14131
|
}
|
|
12836
|
-
function
|
|
12837
|
-
const summary = summarize(opts?.windowDays ?? 30);
|
|
12838
|
-
if (summary.total_events === 0) {
|
|
12839
|
-
console.log("No stats recorded yet.");
|
|
12840
|
-
return;
|
|
12841
|
-
}
|
|
14132
|
+
function _plainTextStats(summary) {
|
|
12842
14133
|
const fmtBytes = (n) => {
|
|
12843
14134
|
if (n < 1024) return `${n}B`;
|
|
12844
14135
|
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
|
|
@@ -12878,11 +14169,71 @@ function renderStats(opts) {
|
|
|
12878
14169
|
}
|
|
12879
14170
|
console.log(lines.join("\n"));
|
|
12880
14171
|
}
|
|
14172
|
+
function renderStats2(opts) {
|
|
14173
|
+
const windowDays = opts?.windowDays ?? 30;
|
|
14174
|
+
const summary = summarize(windowDays);
|
|
14175
|
+
if (summary.total_events === 0) {
|
|
14176
|
+
console.log("No stats recorded yet.");
|
|
14177
|
+
return;
|
|
14178
|
+
}
|
|
14179
|
+
const useTty = process.stdout.isTTY === true && !process.env["NO_COLOR"];
|
|
14180
|
+
if (!useTty) {
|
|
14181
|
+
_plainTextStats(summary);
|
|
14182
|
+
return;
|
|
14183
|
+
}
|
|
14184
|
+
const now = /* @__PURE__ */ new Date();
|
|
14185
|
+
const periodStart = windowDays > 0 ? new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1e3) : /* @__PURE__ */ new Date(0);
|
|
14186
|
+
const sparkDays = [...summary.by_day].reverse().slice(-30);
|
|
14187
|
+
const sparklines = sparkDays.length > 1 ? {
|
|
14188
|
+
events: sparkDays.map((d) => d.events),
|
|
14189
|
+
bytes: sparkDays.map((d) => d.bytes_saved),
|
|
14190
|
+
tokens: sparkDays.map((d) => d.tokens_saved)
|
|
14191
|
+
} : null;
|
|
14192
|
+
const statsData = {
|
|
14193
|
+
period_start: periodStart,
|
|
14194
|
+
period_end: now,
|
|
14195
|
+
version: VERSION,
|
|
14196
|
+
window_label: windowDays > 0 ? `last ${windowDays} days` : "all time",
|
|
14197
|
+
totals: {
|
|
14198
|
+
events: summary.total_events,
|
|
14199
|
+
bytes: summary.total_bytes_saved,
|
|
14200
|
+
tokens: summary.total_tokens_saved,
|
|
14201
|
+
sparklines
|
|
14202
|
+
},
|
|
14203
|
+
by_kind: Object.entries(summary.by_kind).map(([kind, bucket]) => ({
|
|
14204
|
+
kind,
|
|
14205
|
+
bytes: bucket.bytes_saved,
|
|
14206
|
+
tokens: bucket.tokens_saved,
|
|
14207
|
+
events: bucket.events,
|
|
14208
|
+
bytes_mode_only: _BYTES_MODE_ONLY_KINDS.has(kind)
|
|
14209
|
+
})).sort((a, b) => b.bytes - a.bytes),
|
|
14210
|
+
by_day: summary.by_day.map((d) => ({
|
|
14211
|
+
date: d.date,
|
|
14212
|
+
bytes: d.bytes_saved,
|
|
14213
|
+
tokens: d.tokens_saved,
|
|
14214
|
+
events: d.events
|
|
14215
|
+
})),
|
|
14216
|
+
by_project: [],
|
|
14217
|
+
by_source: Object.entries(summary.by_source).filter(([, b]) => b.events > 0).map(([source, bucket]) => ({
|
|
14218
|
+
source,
|
|
14219
|
+
bytes: bucket.bytes_saved,
|
|
14220
|
+
tokens: bucket.tokens_saved,
|
|
14221
|
+
events: bucket.events
|
|
14222
|
+
})).sort((a, b) => b.bytes - a.bytes),
|
|
14223
|
+
by_command: summary.by_command.map((c) => ({
|
|
14224
|
+
command: c.command,
|
|
14225
|
+
bytes: c.bytes_saved,
|
|
14226
|
+
tokens: c.tokens_saved,
|
|
14227
|
+
events: c.events
|
|
14228
|
+
}))
|
|
14229
|
+
};
|
|
14230
|
+
process.stdout.write(renderStats(statsData) + "\n");
|
|
14231
|
+
}
|
|
12881
14232
|
|
|
12882
14233
|
// src/cli_doctor.ts
|
|
12883
14234
|
init_define_import_meta_env();
|
|
12884
14235
|
import * as fs12 from "fs";
|
|
12885
|
-
import * as
|
|
14236
|
+
import * as path13 from "path";
|
|
12886
14237
|
import { execSync } from "child_process";
|
|
12887
14238
|
function checkWorkerRunning() {
|
|
12888
14239
|
try {
|
|
@@ -12893,7 +14244,7 @@ function checkWorkerRunning() {
|
|
|
12893
14244
|
}
|
|
12894
14245
|
}
|
|
12895
14246
|
function checkDbExists(dataDir2) {
|
|
12896
|
-
const dbPath =
|
|
14247
|
+
const dbPath = path13.join(dataDir2, "index.db");
|
|
12897
14248
|
if (!fs12.existsSync(dbPath)) {
|
|
12898
14249
|
return {
|
|
12899
14250
|
name: "Database",
|
|
@@ -12966,9 +14317,9 @@ function runDoctor(dataDir2, configPath2) {
|
|
|
12966
14317
|
results.push(checkInstall());
|
|
12967
14318
|
results.push(checkWorkerRunning() ? { name: "Worker", status: "ok", message: "running" } : { name: "Worker", status: "warn", message: "not running" });
|
|
12968
14319
|
const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
12969
|
-
const actualDataDir = dataDir2 ||
|
|
14320
|
+
const actualDataDir = dataDir2 || path13.join(homeDir, ".token-goat");
|
|
12970
14321
|
results.push(checkDbExists(actualDataDir));
|
|
12971
|
-
const actualConfigPath = configPath2 ||
|
|
14322
|
+
const actualConfigPath = configPath2 || path13.join(actualDataDir, "config.json");
|
|
12972
14323
|
results.push(checkConfigValid(actualConfigPath));
|
|
12973
14324
|
results.push(checkDiskSpace(actualDataDir));
|
|
12974
14325
|
return results;
|
|
@@ -13258,7 +14609,7 @@ function cmdWorkerStatus() {
|
|
|
13258
14609
|
out(isWorkerRunning() ? "Worker is running." : "Worker is not running.");
|
|
13259
14610
|
}
|
|
13260
14611
|
function cmdStats() {
|
|
13261
|
-
|
|
14612
|
+
renderStats2({ windowDays: 30 });
|
|
13262
14613
|
}
|
|
13263
14614
|
function cmdDoctor() {
|
|
13264
14615
|
const code = runDoctorAndExit();
|
|
@@ -13266,14 +14617,12 @@ function cmdDoctor() {
|
|
|
13266
14617
|
throw new CliError("doctor checks failed");
|
|
13267
14618
|
}
|
|
13268
14619
|
}
|
|
13269
|
-
function
|
|
13270
|
-
const entry = getBashOutput(id);
|
|
13271
|
-
if (entry === null) {
|
|
13272
|
-
throw new CliError(`no cached bash output for id: ${id}`);
|
|
13273
|
-
}
|
|
13274
|
-
let content = entry.output;
|
|
14620
|
+
function _applyFiltersAndPrint(content, opts) {
|
|
13275
14621
|
if (opts.grep !== void 0) {
|
|
13276
|
-
|
|
14622
|
+
let pattern = opts.grep;
|
|
14623
|
+
if (pattern.startsWith("-E ") || pattern.startsWith("--extended-regexp ")) {
|
|
14624
|
+
pattern = pattern.replace(/^(?:-E\s+|--extended-regexp\s+)/, "");
|
|
14625
|
+
}
|
|
13277
14626
|
try {
|
|
13278
14627
|
const re = new RegExp(pattern);
|
|
13279
14628
|
content = content.split(/\r?\n/).filter((line) => re.test(line)).join("\n");
|
|
@@ -13294,6 +14643,26 @@ function cmdBashOutput(id, opts) {
|
|
|
13294
14643
|
}
|
|
13295
14644
|
out(result.join("\n"));
|
|
13296
14645
|
}
|
|
14646
|
+
function cmdBashOutput(id, opts) {
|
|
14647
|
+
if (opts.file !== void 0) {
|
|
14648
|
+
let content;
|
|
14649
|
+
try {
|
|
14650
|
+
content = fs13.readFileSync(opts.file, "utf-8");
|
|
14651
|
+
} catch {
|
|
14652
|
+
throw new CliError(`cannot read file: ${opts.file}`);
|
|
14653
|
+
}
|
|
14654
|
+
_applyFiltersAndPrint(content, opts);
|
|
14655
|
+
return;
|
|
14656
|
+
}
|
|
14657
|
+
if (id === void 0) {
|
|
14658
|
+
throw new CliError("provide an <id> or --file <path>");
|
|
14659
|
+
}
|
|
14660
|
+
const entry = getBashOutput(id);
|
|
14661
|
+
if (entry === null) {
|
|
14662
|
+
throw new CliError(`no cached bash output for id: ${id}`);
|
|
14663
|
+
}
|
|
14664
|
+
_applyFiltersAndPrint(entry.output, opts);
|
|
14665
|
+
}
|
|
13297
14666
|
async function cmdSkillBody(name, opts) {
|
|
13298
14667
|
const filePath = await getSkillFilePath(name);
|
|
13299
14668
|
if (filePath === null) {
|
|
@@ -13445,7 +14814,7 @@ function buildProgram() {
|
|
|
13445
14814
|
worker.command("status").description("check if the indexer is running").action(guard(cmdWorkerStatus));
|
|
13446
14815
|
program2.command("stats").description("show session statistics").action(guard(cmdStats));
|
|
13447
14816
|
program2.command("doctor").description("diagnose token-goat health").action(guard(cmdDoctor));
|
|
13448
|
-
program2.command("bash-output
|
|
14817
|
+
program2.command("bash-output [id]").description("retrieve cached bash output by ID or file").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--file <path>", "read from raw output file instead of cache").action(guard(cmdBashOutput));
|
|
13449
14818
|
program2.command("skill-body <name>").description("retrieve a skill's cached body").option("-c, --compact", "print compact slice instead of full body").action(guard(cmdSkillBody));
|
|
13450
14819
|
program2.command("skill-compact <name>").description("regenerate and cache compact slice for a skill").action(guard(cmdSkillCompact));
|
|
13451
14820
|
program2.command("skill-list").description("list all cached skills with token counts").option("-j, --json", "output as JSON").option("--session-id <id>", "filter by session").action(guard(cmdSkillList));
|