token-goat 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/token-goat.mjs +1118 -393
- package/package.json +1 -1
package/dist/token-goat.mjs
CHANGED
|
@@ -981,8 +981,8 @@ 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
|
|
985
|
-
var
|
|
984
|
+
var path17 = __require("node:path");
|
|
985
|
+
var fs16 = __require("node:fs");
|
|
986
986
|
var process2 = __require("node:process");
|
|
987
987
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
988
988
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1914,11 +1914,11 @@ 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 =
|
|
1918
|
-
if (
|
|
1919
|
-
if (sourceExt.includes(
|
|
1917
|
+
const localBin = path17.resolve(baseDir, baseName);
|
|
1918
|
+
if (fs16.existsSync(localBin)) return localBin;
|
|
1919
|
+
if (sourceExt.includes(path17.extname(baseName))) return void 0;
|
|
1920
1920
|
const foundExt = sourceExt.find(
|
|
1921
|
-
(ext) =>
|
|
1921
|
+
(ext) => fs16.existsSync(`${localBin}${ext}`)
|
|
1922
1922
|
);
|
|
1923
1923
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1924
1924
|
return void 0;
|
|
@@ -1930,21 +1930,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1930
1930
|
if (this._scriptPath) {
|
|
1931
1931
|
let resolvedScriptPath;
|
|
1932
1932
|
try {
|
|
1933
|
-
resolvedScriptPath =
|
|
1933
|
+
resolvedScriptPath = fs16.realpathSync(this._scriptPath);
|
|
1934
1934
|
} catch (err2) {
|
|
1935
1935
|
resolvedScriptPath = this._scriptPath;
|
|
1936
1936
|
}
|
|
1937
|
-
executableDir =
|
|
1938
|
-
|
|
1937
|
+
executableDir = path17.resolve(
|
|
1938
|
+
path17.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 = path17.basename(
|
|
1946
1946
|
this._scriptPath,
|
|
1947
|
-
|
|
1947
|
+
path17.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(path17.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 = path17.basename(filename, path17.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(path18) {
|
|
2813
|
+
if (path18 === void 0) return this._executableDir;
|
|
2814
|
+
this._executableDir = path18;
|
|
2815
2815
|
return this;
|
|
2816
2816
|
}
|
|
2817
2817
|
/**
|
|
@@ -3158,27 +3158,27 @@ var require_filesystem = __commonJS({
|
|
|
3158
3158
|
"node_modules/detect-libc/lib/filesystem.js"(exports, module) {
|
|
3159
3159
|
"use strict";
|
|
3160
3160
|
init_define_import_meta_env();
|
|
3161
|
-
var
|
|
3161
|
+
var fs16 = __require("fs");
|
|
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 =
|
|
3165
|
+
var readFileSync12 = (path17) => {
|
|
3166
|
+
const fd = fs16.openSync(path17, "r");
|
|
3167
3167
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
3168
|
-
const bytesRead =
|
|
3169
|
-
|
|
3168
|
+
const bytesRead = fs16.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
3169
|
+
fs16.close(fd, () => {
|
|
3170
3170
|
});
|
|
3171
3171
|
return buffer.subarray(0, bytesRead);
|
|
3172
3172
|
};
|
|
3173
|
-
var readFile3 = (
|
|
3174
|
-
|
|
3173
|
+
var readFile3 = (path17) => new Promise((resolve6, reject) => {
|
|
3174
|
+
fs16.open(path17, "r", (err2, fd) => {
|
|
3175
3175
|
if (err2) {
|
|
3176
3176
|
reject(err2);
|
|
3177
3177
|
} else {
|
|
3178
3178
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
3179
|
-
|
|
3179
|
+
fs16.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
3180
3180
|
resolve6(buffer.subarray(0, bytesRead));
|
|
3181
|
-
|
|
3181
|
+
fs16.close(fd, () => {
|
|
3182
3182
|
});
|
|
3183
3183
|
});
|
|
3184
3184
|
}
|
|
@@ -3187,7 +3187,7 @@ var require_filesystem = __commonJS({
|
|
|
3187
3187
|
module.exports = {
|
|
3188
3188
|
LDD_PATH,
|
|
3189
3189
|
SELF_PATH,
|
|
3190
|
-
readFileSync:
|
|
3190
|
+
readFileSync: readFileSync12,
|
|
3191
3191
|
readFile: readFile3
|
|
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: readFile3, readFileSync:
|
|
3241
|
+
var { LDD_PATH, SELF_PATH, readFile: readFile3, readFileSync: readFileSync12 } = 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 = (path17) => {
|
|
3296
|
+
if (path17) {
|
|
3297
|
+
if (path17.includes("/ld-musl-")) {
|
|
3298
3298
|
return MUSL;
|
|
3299
|
-
} else if (
|
|
3299
|
+
} else if (path17.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 = readFileSync12(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 readFile3(SELF_PATH);
|
|
3346
|
-
const
|
|
3347
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
3346
|
+
const path17 = interpreterPath(selfContent);
|
|
3347
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path17);
|
|
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 = readFileSync12(SELF_PATH);
|
|
3359
|
+
const path17 = interpreterPath(selfContent);
|
|
3360
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path17);
|
|
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 = readFileSync12(LDD_PATH);
|
|
3423
3423
|
const versionMatch = lddContent.match(RE_GLIBC_VERSION);
|
|
3424
3424
|
if (versionMatch) {
|
|
3425
3425
|
cachedVersionFilesystem = versionMatch[1];
|
|
@@ -4947,8 +4947,8 @@ var require_libvips = __commonJS({
|
|
|
4947
4947
|
"node_modules/sharp/lib/libvips.js"(exports, module) {
|
|
4948
4948
|
"use strict";
|
|
4949
4949
|
init_define_import_meta_env();
|
|
4950
|
-
var { spawnSync:
|
|
4951
|
-
var { createHash:
|
|
4950
|
+
var { spawnSync: spawnSync3 } = __require("node:child_process");
|
|
4951
|
+
var { createHash: createHash3 } = __require("node:crypto");
|
|
4952
4952
|
var semverCoerce = require_coerce();
|
|
4953
4953
|
var semverGreaterThanOrEqualTo = require_gte();
|
|
4954
4954
|
var semverSatisfies = require_satisfies();
|
|
@@ -5032,12 +5032,12 @@ var require_libvips = __commonJS({
|
|
|
5032
5032
|
};
|
|
5033
5033
|
var isRosetta = () => {
|
|
5034
5034
|
if (process.platform === "darwin" && process.arch === "x64") {
|
|
5035
|
-
const translated =
|
|
5035
|
+
const translated = spawnSync3("sysctl sysctl.proc_translated", spawnSyncOptions).stdout;
|
|
5036
5036
|
return (translated || "").trim() === "sysctl.proc_translated: 1";
|
|
5037
5037
|
}
|
|
5038
5038
|
return false;
|
|
5039
5039
|
};
|
|
5040
|
-
var sha512 = (s) =>
|
|
5040
|
+
var sha512 = (s) => createHash3("sha512").update(s).digest("hex");
|
|
5041
5041
|
var yarnLocator = () => {
|
|
5042
5042
|
try {
|
|
5043
5043
|
const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
|
|
@@ -5047,13 +5047,13 @@ var require_libvips = __commonJS({
|
|
|
5047
5047
|
}
|
|
5048
5048
|
return "";
|
|
5049
5049
|
};
|
|
5050
|
-
var spawnRebuild = () =>
|
|
5050
|
+
var spawnRebuild = () => spawnSync3(`node-gyp rebuild --directory=src ${isEmscripten() ? "--nodedir=emscripten" : ""}`, {
|
|
5051
5051
|
...spawnSyncOptions,
|
|
5052
5052
|
stdio: "inherit"
|
|
5053
5053
|
}).status;
|
|
5054
5054
|
var globalLibvipsVersion = () => {
|
|
5055
5055
|
if (process.platform !== "win32") {
|
|
5056
|
-
const globalLibvipsVersion2 =
|
|
5056
|
+
const globalLibvipsVersion2 = spawnSync3("pkg-config --modversion vips-cpp", {
|
|
5057
5057
|
...spawnSyncOptions,
|
|
5058
5058
|
env: {
|
|
5059
5059
|
...process.env,
|
|
@@ -5067,7 +5067,7 @@ var require_libvips = __commonJS({
|
|
|
5067
5067
|
};
|
|
5068
5068
|
var pkgConfigPath = () => {
|
|
5069
5069
|
if (process.platform !== "win32") {
|
|
5070
|
-
const brewPkgConfigPath =
|
|
5070
|
+
const brewPkgConfigPath = spawnSync3(
|
|
5071
5071
|
'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
|
|
5072
5072
|
spawnSyncOptions
|
|
5073
5073
|
).stdout || "";
|
|
@@ -5138,9 +5138,9 @@ var require_sharp = __commonJS({
|
|
|
5138
5138
|
];
|
|
5139
5139
|
var sharp;
|
|
5140
5140
|
var errors = [];
|
|
5141
|
-
for (const
|
|
5141
|
+
for (const path17 of paths) {
|
|
5142
5142
|
try {
|
|
5143
|
-
sharp = __require(
|
|
5143
|
+
sharp = __require(path17);
|
|
5144
5144
|
break;
|
|
5145
5145
|
} catch (err2) {
|
|
5146
5146
|
errors.push(err2);
|
|
@@ -5149,7 +5149,7 @@ var require_sharp = __commonJS({
|
|
|
5149
5149
|
if (sharp) {
|
|
5150
5150
|
module.exports = sharp;
|
|
5151
5151
|
} else {
|
|
5152
|
-
const [isLinux, isMacOs,
|
|
5152
|
+
const [isLinux, isMacOs, isWindows2] = ["linux", "darwin", "win32"].map((os4) => runtimePlatform.startsWith(os4));
|
|
5153
5153
|
const help = [`Could not load the "sharp" module using the ${runtimePlatform} runtime`];
|
|
5154
5154
|
errors.forEach((err2) => {
|
|
5155
5155
|
if (err2.code !== "MODULE_NOT_FOUND") {
|
|
@@ -5166,15 +5166,15 @@ var require_sharp = __commonJS({
|
|
|
5166
5166
|
` Requires ${expected}`
|
|
5167
5167
|
);
|
|
5168
5168
|
} else if (prebuiltPlatforms.includes(runtimePlatform)) {
|
|
5169
|
-
const [
|
|
5170
|
-
const libc =
|
|
5169
|
+
const [os4, cpu] = runtimePlatform.split("-");
|
|
5170
|
+
const libc = os4.endsWith("musl") ? " --libc=musl" : "";
|
|
5171
5171
|
help.push(
|
|
5172
5172
|
"- Ensure optional dependencies can be installed:",
|
|
5173
5173
|
" npm install --include=optional sharp",
|
|
5174
5174
|
"- Ensure your package manager supports multi-platform installation:",
|
|
5175
5175
|
" See https://sharp.pixelplumbing.com/install#cross-platform",
|
|
5176
5176
|
"- Add platform-specific dependencies:",
|
|
5177
|
-
` npm install --os=${
|
|
5177
|
+
` npm install --os=${os4.replace("musl", "")}${libc} --cpu=${cpu} sharp`
|
|
5178
5178
|
);
|
|
5179
5179
|
} else {
|
|
5180
5180
|
help.push(
|
|
@@ -5212,7 +5212,7 @@ var require_sharp = __commonJS({
|
|
|
5212
5212
|
if (errors.some((err2) => err2.code === "ERR_DLOPEN_DISABLED")) {
|
|
5213
5213
|
help.push("- Run Node.js without using the --no-addons flag");
|
|
5214
5214
|
}
|
|
5215
|
-
if (
|
|
5215
|
+
if (isWindows2 && /The specified procedure could not be found/.test(messages)) {
|
|
5216
5216
|
help.push(
|
|
5217
5217
|
"- Using the canvas package on Windows?",
|
|
5218
5218
|
" See https://sharp.pixelplumbing.com/install#canvas-and-windows",
|
|
@@ -6552,15 +6552,15 @@ var require_route = __commonJS({
|
|
|
6552
6552
|
};
|
|
6553
6553
|
}
|
|
6554
6554
|
function wrapConversion(toModel, graph) {
|
|
6555
|
-
const
|
|
6555
|
+
const path17 = [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
|
+
path17.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 = path17;
|
|
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 path17 = __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) && path17.resolve(this.options.input.file) === path17.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(path17.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
|
|
8501
8501
|
err2 = errJp2Save();
|
|
8502
8502
|
}
|
|
8503
8503
|
if (err2) {
|
|
@@ -9475,13 +9475,13 @@ var {
|
|
|
9475
9475
|
} = import_index.default;
|
|
9476
9476
|
|
|
9477
9477
|
// src/cli.ts
|
|
9478
|
-
import * as
|
|
9479
|
-
import * as
|
|
9478
|
+
import * as fs15 from "fs";
|
|
9479
|
+
import * as path16 from "path";
|
|
9480
9480
|
|
|
9481
9481
|
// src/baseline.ts
|
|
9482
9482
|
init_define_import_meta_env();
|
|
9483
9483
|
import * as fs2 from "node:fs";
|
|
9484
|
-
import * as
|
|
9484
|
+
import * as path5 from "node:path";
|
|
9485
9485
|
|
|
9486
9486
|
// src/constants.ts
|
|
9487
9487
|
init_define_import_meta_env();
|
|
@@ -9493,7 +9493,7 @@ init_define_import_meta_env();
|
|
|
9493
9493
|
import { createRequire } from "node:module";
|
|
9494
9494
|
function resolveVersion() {
|
|
9495
9495
|
if (true) {
|
|
9496
|
-
return "2.1
|
|
9496
|
+
return "2.2.1";
|
|
9497
9497
|
}
|
|
9498
9498
|
const require2 = createRequire(import.meta.url);
|
|
9499
9499
|
const pkg = require2("../package.json");
|
|
@@ -9543,9 +9543,42 @@ function configPath() {
|
|
|
9543
9543
|
init_define_import_meta_env();
|
|
9544
9544
|
import * as fs from "node:fs";
|
|
9545
9545
|
import { createRequire as createRequire2 } from "node:module";
|
|
9546
|
-
import * as
|
|
9546
|
+
import * as path3 from "node:path";
|
|
9547
9547
|
import Database from "better-sqlite3";
|
|
9548
9548
|
|
|
9549
|
+
// src/paths.ts
|
|
9550
|
+
init_define_import_meta_env();
|
|
9551
|
+
import * as path2 from "node:path";
|
|
9552
|
+
var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
|
|
9553
|
+
function normalizePath(p) {
|
|
9554
|
+
let s = p;
|
|
9555
|
+
if (s.includes("\\")) {
|
|
9556
|
+
s = s.replace(/\\/g, "/");
|
|
9557
|
+
}
|
|
9558
|
+
const m = WSL_PATH_RE.exec(s);
|
|
9559
|
+
if (m) {
|
|
9560
|
+
const driveLetter = m[1].toLowerCase();
|
|
9561
|
+
const rest = m[2];
|
|
9562
|
+
const restStripped = rest.replace(/^\/+/, "");
|
|
9563
|
+
s = `${driveLetter}:/${restStripped}`;
|
|
9564
|
+
}
|
|
9565
|
+
if (s.length >= 2 && s[1] === ":") {
|
|
9566
|
+
const c = s[0];
|
|
9567
|
+
if (/^[A-Z]$/.test(c)) {
|
|
9568
|
+
s = c.toLowerCase() + s.slice(1);
|
|
9569
|
+
}
|
|
9570
|
+
}
|
|
9571
|
+
return s;
|
|
9572
|
+
}
|
|
9573
|
+
function safeJoin(base, ...parts) {
|
|
9574
|
+
for (const part of parts) {
|
|
9575
|
+
if (part.includes(":")) {
|
|
9576
|
+
throw new Error(`safeJoin: path component contains colon: ${JSON.stringify(part)}`);
|
|
9577
|
+
}
|
|
9578
|
+
}
|
|
9579
|
+
return path2.join(base, ...parts);
|
|
9580
|
+
}
|
|
9581
|
+
|
|
9549
9582
|
// src/reset.ts
|
|
9550
9583
|
init_define_import_meta_env();
|
|
9551
9584
|
var _resets = [];
|
|
@@ -9589,6 +9622,16 @@ CREATE TABLE IF NOT EXISTS refs (
|
|
|
9589
9622
|
);
|
|
9590
9623
|
CREATE INDEX IF NOT EXISTS idx_refs_name ON refs(name);
|
|
9591
9624
|
CREATE INDEX IF NOT EXISTS idx_refs_file ON refs(file_path);
|
|
9625
|
+
|
|
9626
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
9627
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
9628
|
+
file_path TEXT,
|
|
9629
|
+
start_line INTEGER,
|
|
9630
|
+
end_line INTEGER,
|
|
9631
|
+
text TEXT,
|
|
9632
|
+
kind TEXT
|
|
9633
|
+
);
|
|
9634
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_file ON chunks(file_path);
|
|
9592
9635
|
`;
|
|
9593
9636
|
var FTS_SQL = `
|
|
9594
9637
|
CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(
|
|
@@ -9636,15 +9679,15 @@ function initConnection(conn) {
|
|
|
9636
9679
|
}
|
|
9637
9680
|
}
|
|
9638
9681
|
function resolveDbPath(dbPath) {
|
|
9639
|
-
if (
|
|
9640
|
-
if (dbPath.includes("/") || dbPath.includes("\\")) return
|
|
9641
|
-
return
|
|
9682
|
+
if (path3.isAbsolute(dbPath)) return dbPath;
|
|
9683
|
+
if (dbPath.includes("/") || dbPath.includes("\\")) return path3.resolve(dbPath);
|
|
9684
|
+
return safeJoin(dataDir(), dbPath);
|
|
9642
9685
|
}
|
|
9643
9686
|
function getDb(dbPath) {
|
|
9644
9687
|
const resolved = resolveDbPath(dbPath);
|
|
9645
9688
|
const existing = _connections.get(resolved);
|
|
9646
9689
|
if (existing !== void 0) return existing;
|
|
9647
|
-
const dir =
|
|
9690
|
+
const dir = path3.dirname(resolved);
|
|
9648
9691
|
try {
|
|
9649
9692
|
fs.mkdirSync(dir, { recursive: true });
|
|
9650
9693
|
} catch (e) {
|
|
@@ -9668,7 +9711,7 @@ registerReset(closeAllDbs);
|
|
|
9668
9711
|
|
|
9669
9712
|
// src/parser_types.ts
|
|
9670
9713
|
init_define_import_meta_env();
|
|
9671
|
-
import * as
|
|
9714
|
+
import * as path4 from "node:path";
|
|
9672
9715
|
var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
|
|
9673
9716
|
[".py", "python"],
|
|
9674
9717
|
[".pyi", "python"],
|
|
@@ -9738,10 +9781,10 @@ var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
|
|
|
9738
9781
|
[".envrc", "env_file"]
|
|
9739
9782
|
]);
|
|
9740
9783
|
function detectLanguage(filePath) {
|
|
9741
|
-
const base =
|
|
9784
|
+
const base = path4.basename(filePath).toLowerCase();
|
|
9742
9785
|
const byName = FILENAME_LANGUAGE.get(base);
|
|
9743
9786
|
if (byName !== void 0) return byName;
|
|
9744
|
-
const ext =
|
|
9787
|
+
const ext = path4.extname(base).toLowerCase();
|
|
9745
9788
|
return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
|
|
9746
9789
|
}
|
|
9747
9790
|
|
|
@@ -9782,7 +9825,7 @@ function walkProject(rootDir) {
|
|
|
9782
9825
|
continue;
|
|
9783
9826
|
}
|
|
9784
9827
|
for (const entry of entries) {
|
|
9785
|
-
const full =
|
|
9828
|
+
const full = path5.join(dir, entry.name);
|
|
9786
9829
|
if (entry.isDirectory()) {
|
|
9787
9830
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
9788
9831
|
if (entry.name.startsWith(".") && entry.name !== ".") {
|
|
@@ -9825,7 +9868,7 @@ function fetchTopSymbols(limit, dbPath) {
|
|
|
9825
9868
|
}
|
|
9826
9869
|
}
|
|
9827
9870
|
function buildProjectMap(rootDir = process.cwd(), opts = {}) {
|
|
9828
|
-
const root =
|
|
9871
|
+
const root = path5.resolve(rootDir);
|
|
9829
9872
|
const { files, languages } = walkProject(root);
|
|
9830
9873
|
const symbolLimit = opts.compact ? 10 : 30;
|
|
9831
9874
|
const topSymbols = fetchTopSymbols(symbolLimit, globalDbPath());
|
|
@@ -9837,7 +9880,7 @@ function buildProjectMap(rootDir = process.cwd(), opts = {}) {
|
|
|
9837
9880
|
mtime = 0;
|
|
9838
9881
|
}
|
|
9839
9882
|
return { f, mtime };
|
|
9840
|
-
}).sort((a, b) => b.mtime - a.mtime).slice(0, opts.compact ? 5 : 15).map((x) =>
|
|
9883
|
+
}).sort((a, b) => b.mtime - a.mtime).slice(0, opts.compact ? 5 : 15).map((x) => path5.relative(root, x.f));
|
|
9841
9884
|
return {
|
|
9842
9885
|
rootDir: root,
|
|
9843
9886
|
fileCount: files.length,
|
|
@@ -9848,7 +9891,7 @@ function buildProjectMap(rootDir = process.cwd(), opts = {}) {
|
|
|
9848
9891
|
}
|
|
9849
9892
|
function formatProjectMap(map, compact = false) {
|
|
9850
9893
|
const lines = [];
|
|
9851
|
-
const rel =
|
|
9894
|
+
const rel = path5.basename(map.rootDir);
|
|
9852
9895
|
lines.push(`# Project map: ${rel}`);
|
|
9853
9896
|
lines.push(`Files: ${map.fileCount}`);
|
|
9854
9897
|
const langPairs = Object.entries(map.languages).sort((a, b) => b[1] - a[1]);
|
|
@@ -9861,7 +9904,7 @@ function formatProjectMap(map, compact = false) {
|
|
|
9861
9904
|
if (compact) {
|
|
9862
9905
|
lines.push(`- ${s.name} (${s.kind})`);
|
|
9863
9906
|
} else {
|
|
9864
|
-
const loc = `${
|
|
9907
|
+
const loc = `${path5.basename(s.filePath)}:${s.lineStart}-${s.lineEnd}`;
|
|
9865
9908
|
lines.push(`- ${s.name} (${s.kind}) \u2014 ${loc}`);
|
|
9866
9909
|
}
|
|
9867
9910
|
}
|
|
@@ -9878,42 +9921,19 @@ function formatProjectMap(map, compact = false) {
|
|
|
9878
9921
|
|
|
9879
9922
|
// src/repomap.ts
|
|
9880
9923
|
init_define_import_meta_env();
|
|
9881
|
-
import * as
|
|
9924
|
+
import * as path6 from "path";
|
|
9882
9925
|
|
|
9883
9926
|
// src/util.ts
|
|
9884
9927
|
init_define_import_meta_env();
|
|
9885
9928
|
import { spawnSync } from "node:child_process";
|
|
9886
9929
|
import { closeSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
9887
|
-
|
|
9888
|
-
// src/paths.ts
|
|
9889
|
-
init_define_import_meta_env();
|
|
9890
|
-
var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
|
|
9891
|
-
function normalizePath(p) {
|
|
9892
|
-
let s = p;
|
|
9893
|
-
if (s.includes("\\")) {
|
|
9894
|
-
s = s.replace(/\\/g, "/");
|
|
9895
|
-
}
|
|
9896
|
-
const m = WSL_PATH_RE.exec(s);
|
|
9897
|
-
if (m) {
|
|
9898
|
-
const driveLetter = m[1].toLowerCase();
|
|
9899
|
-
const rest = m[2];
|
|
9900
|
-
const restStripped = rest.replace(/^\/+/, "");
|
|
9901
|
-
s = `${driveLetter}:/${restStripped}`;
|
|
9902
|
-
}
|
|
9903
|
-
if (s.length >= 2 && s[1] === ":") {
|
|
9904
|
-
const c = s[0];
|
|
9905
|
-
if (/^[A-Z]$/.test(c)) {
|
|
9906
|
-
s = c.toLowerCase() + s.slice(1);
|
|
9907
|
-
}
|
|
9908
|
-
}
|
|
9909
|
-
return s;
|
|
9910
|
-
}
|
|
9911
|
-
|
|
9912
|
-
// src/util.ts
|
|
9913
9930
|
function sleepSync(ms) {
|
|
9914
9931
|
if (ms <= 0) return;
|
|
9915
9932
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
9916
9933
|
}
|
|
9934
|
+
function isWindows() {
|
|
9935
|
+
return process.platform === "win32";
|
|
9936
|
+
}
|
|
9917
9937
|
function runGit(args, opts = {}) {
|
|
9918
9938
|
const fullArgs = ["-c", "core.fsmonitor=", ...args];
|
|
9919
9939
|
const result = spawnSync("git", fullArgs, {
|
|
@@ -9979,6 +9999,21 @@ function atomicWriteText(filePath, content) {
|
|
|
9979
9999
|
function atomicWriteBytes(filePath, content) {
|
|
9980
10000
|
atomicWriteCore(filePath, content);
|
|
9981
10001
|
}
|
|
10002
|
+
function ensureNewline(text) {
|
|
10003
|
+
return text.endsWith("\n") ? text : text + "\n";
|
|
10004
|
+
}
|
|
10005
|
+
function extractErrorMessage(err2, fallback = "") {
|
|
10006
|
+
return err2 instanceof Error ? err2.message : fallback || String(err2);
|
|
10007
|
+
}
|
|
10008
|
+
function isCodeFenceDelimiter(line) {
|
|
10009
|
+
const s = line.trim();
|
|
10010
|
+
return s.startsWith("```") || s.startsWith("~~~");
|
|
10011
|
+
}
|
|
10012
|
+
function normalizePathForwardSlash(p, toLowerCase) {
|
|
10013
|
+
let result = normalizePath(p).replace(/\\/g, "/");
|
|
10014
|
+
if (toLowerCase) result = result.toLowerCase();
|
|
10015
|
+
return result;
|
|
10016
|
+
}
|
|
9982
10017
|
|
|
9983
10018
|
// src/index_reader.ts
|
|
9984
10019
|
init_define_import_meta_env();
|
|
@@ -10124,7 +10159,7 @@ function isNoisePath(inputPath) {
|
|
|
10124
10159
|
if (!inputPath) {
|
|
10125
10160
|
return false;
|
|
10126
10161
|
}
|
|
10127
|
-
const p =
|
|
10162
|
+
const p = normalizePathForwardSlash(inputPath, true);
|
|
10128
10163
|
for (const segment of NOISE_SEGMENTS) {
|
|
10129
10164
|
if (p.includes(segment)) {
|
|
10130
10165
|
return true;
|
|
@@ -10162,7 +10197,7 @@ function getTrackedFiles(cwd = process.cwd()) {
|
|
|
10162
10197
|
if (result.exitCode !== 0 || !result.stdout) {
|
|
10163
10198
|
return [];
|
|
10164
10199
|
}
|
|
10165
|
-
return result.stdout.split("\n").filter((line) => line.trim().length > 0).map((rel) =>
|
|
10200
|
+
return result.stdout.split("\n").filter((line) => line.trim().length > 0).map((rel) => path6.join(cwd, rel));
|
|
10166
10201
|
} catch {
|
|
10167
10202
|
return [];
|
|
10168
10203
|
}
|
|
@@ -10218,7 +10253,7 @@ function formatMap(entries, opts = {}) {
|
|
|
10218
10253
|
lines.push("");
|
|
10219
10254
|
lines.push("## Files");
|
|
10220
10255
|
for (const e of shown) {
|
|
10221
|
-
const rel =
|
|
10256
|
+
const rel = path6.relative(cwd, e.filePath);
|
|
10222
10257
|
if (compact) {
|
|
10223
10258
|
lines.push(`- ${rel} (${e.language})`);
|
|
10224
10259
|
} else {
|
|
@@ -10236,11 +10271,13 @@ function formatMap(entries, opts = {}) {
|
|
|
10236
10271
|
|
|
10237
10272
|
// src/session.ts
|
|
10238
10273
|
init_define_import_meta_env();
|
|
10274
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
10239
10275
|
import * as fs3 from "node:fs";
|
|
10240
10276
|
var _files = /* @__PURE__ */ new Map();
|
|
10241
10277
|
var _hintsShown = /* @__PURE__ */ new Set();
|
|
10242
10278
|
var _webFetches = /* @__PURE__ */ new Map();
|
|
10243
10279
|
var _bashOutputs = /* @__PURE__ */ new Map();
|
|
10280
|
+
var _curlDownloads = /* @__PURE__ */ new Map();
|
|
10244
10281
|
var _sessionId = null;
|
|
10245
10282
|
function fileSize(absPath) {
|
|
10246
10283
|
try {
|
|
@@ -10265,10 +10302,9 @@ function recordFileRead(filePath) {
|
|
|
10265
10302
|
return;
|
|
10266
10303
|
}
|
|
10267
10304
|
_files.set(key, {
|
|
10268
|
-
|
|
10305
|
+
...prev,
|
|
10269
10306
|
readCount: prev.readCount + 1,
|
|
10270
10307
|
lastReadAt: now,
|
|
10271
|
-
wasEdited: prev.wasEdited,
|
|
10272
10308
|
sizeBytes: size
|
|
10273
10309
|
});
|
|
10274
10310
|
}
|
|
@@ -10309,11 +10345,51 @@ function recordBashOutput(commandHash2, outputId, _sizeBytes) {
|
|
|
10309
10345
|
function getBashOutputId(commandHash2) {
|
|
10310
10346
|
return _bashOutputs.get(commandHash2) ?? null;
|
|
10311
10347
|
}
|
|
10348
|
+
function recordCurlDownload(url, savedPath) {
|
|
10349
|
+
_curlDownloads.set(url, savedPath);
|
|
10350
|
+
}
|
|
10351
|
+
function getCurlDownloadPath(url) {
|
|
10352
|
+
return _curlDownloads.get(url) ?? null;
|
|
10353
|
+
}
|
|
10354
|
+
function markFileTruncated(filePath) {
|
|
10355
|
+
const key = normalizePath(filePath);
|
|
10356
|
+
const prev = _files.get(key);
|
|
10357
|
+
if (prev === void 0) {
|
|
10358
|
+
_files.set(key, {
|
|
10359
|
+
path: key,
|
|
10360
|
+
readCount: 1,
|
|
10361
|
+
lastReadAt: Date.now(),
|
|
10362
|
+
wasEdited: false,
|
|
10363
|
+
sizeBytes: fileSize(key),
|
|
10364
|
+
wasTruncated: true
|
|
10365
|
+
});
|
|
10366
|
+
return;
|
|
10367
|
+
}
|
|
10368
|
+
_files.set(key, { ...prev, wasTruncated: true });
|
|
10369
|
+
}
|
|
10370
|
+
function wasFileTruncatedThisSession(filePath) {
|
|
10371
|
+
const entry = _files.get(normalizePath(filePath));
|
|
10372
|
+
return entry?.wasTruncated === true;
|
|
10373
|
+
}
|
|
10374
|
+
function generateSessionId() {
|
|
10375
|
+
try {
|
|
10376
|
+
return randomUUID();
|
|
10377
|
+
} catch {
|
|
10378
|
+
return randomBytes(16).toString("hex");
|
|
10379
|
+
}
|
|
10380
|
+
}
|
|
10381
|
+
function getSessionId() {
|
|
10382
|
+
if (_sessionId !== null) return _sessionId;
|
|
10383
|
+
const fromEnv = process.env["CLAUDE_SESSION_ID"];
|
|
10384
|
+
_sessionId = fromEnv !== void 0 && fromEnv !== "" ? fromEnv : generateSessionId();
|
|
10385
|
+
return _sessionId;
|
|
10386
|
+
}
|
|
10312
10387
|
registerReset(() => {
|
|
10313
10388
|
_files = /* @__PURE__ */ new Map();
|
|
10314
10389
|
_hintsShown = /* @__PURE__ */ new Set();
|
|
10315
10390
|
_webFetches = /* @__PURE__ */ new Map();
|
|
10316
10391
|
_bashOutputs = /* @__PURE__ */ new Map();
|
|
10392
|
+
_curlDownloads = /* @__PURE__ */ new Map();
|
|
10317
10393
|
_sessionId = null;
|
|
10318
10394
|
});
|
|
10319
10395
|
|
|
@@ -10373,8 +10449,8 @@ var HOOK_EVENTS = [
|
|
|
10373
10449
|
|
|
10374
10450
|
// src/hooks_read.ts
|
|
10375
10451
|
init_define_import_meta_env();
|
|
10376
|
-
import * as
|
|
10377
|
-
import * as
|
|
10452
|
+
import * as fs5 from "node:fs";
|
|
10453
|
+
import * as path9 from "node:path";
|
|
10378
10454
|
|
|
10379
10455
|
// src/hooks_common.ts
|
|
10380
10456
|
init_define_import_meta_env();
|
|
@@ -10398,6 +10474,166 @@ function contextOutput(context) {
|
|
|
10398
10474
|
return { hookType: "context", context };
|
|
10399
10475
|
}
|
|
10400
10476
|
|
|
10477
|
+
// src/snapshots.ts
|
|
10478
|
+
init_define_import_meta_env();
|
|
10479
|
+
import * as fs4 from "node:fs";
|
|
10480
|
+
import * as path7 from "node:path";
|
|
10481
|
+
import * as crypto from "node:crypto";
|
|
10482
|
+
import * as os2 from "node:os";
|
|
10483
|
+
var MAX_SNAPSHOTS_PER_SESSION = 150;
|
|
10484
|
+
var MAX_SNAPSHOT_BYTES = 256 * 1024;
|
|
10485
|
+
var SNAPSHOT_TRUNCATE_BYTES = 50 * 1024;
|
|
10486
|
+
var KIND_READ = "read";
|
|
10487
|
+
var KIND_PREDICTIVE = "predictive";
|
|
10488
|
+
var VALID_KINDS = /* @__PURE__ */ new Set([KIND_READ, KIND_PREDICTIVE]);
|
|
10489
|
+
var _TRUNCATED_MARKER = Buffer.from("\n<snapshot truncated at ");
|
|
10490
|
+
var SESSION_DIR_RE = /[^a-zA-Z0-9_-]/g;
|
|
10491
|
+
function sessionDir(sessionId) {
|
|
10492
|
+
if (!sessionId) return null;
|
|
10493
|
+
const safe = sessionId.replace(SESSION_DIR_RE, "_").slice(0, 64) || "anon";
|
|
10494
|
+
const base = path7.join(os2.homedir(), ".token-goat", "session_snapshots");
|
|
10495
|
+
const candidate = path7.join(base, safe);
|
|
10496
|
+
try {
|
|
10497
|
+
const rel = path7.relative(base, candidate);
|
|
10498
|
+
if (rel.startsWith("..")) return null;
|
|
10499
|
+
} catch {
|
|
10500
|
+
return null;
|
|
10501
|
+
}
|
|
10502
|
+
return candidate;
|
|
10503
|
+
}
|
|
10504
|
+
function pathKey(filePath) {
|
|
10505
|
+
return crypto.createHash("sha256").update(filePath, "utf8").digest("hex").slice(0, 32);
|
|
10506
|
+
}
|
|
10507
|
+
function snapshot_path(sessionId, filePath) {
|
|
10508
|
+
const d = sessionDir(sessionId);
|
|
10509
|
+
if (!d) return null;
|
|
10510
|
+
return path7.join(d, `${pathKey(filePath)}.bin`);
|
|
10511
|
+
}
|
|
10512
|
+
function kindSidecarPath(snapshotPath) {
|
|
10513
|
+
return snapshotPath + ".kind";
|
|
10514
|
+
}
|
|
10515
|
+
function writeSnapshotKind(sidecarPath, kind) {
|
|
10516
|
+
try {
|
|
10517
|
+
const safeKind = VALID_KINDS.has(kind) ? kind : KIND_READ;
|
|
10518
|
+
const dir = path7.dirname(sidecarPath);
|
|
10519
|
+
if (!fs4.existsSync(dir)) {
|
|
10520
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
10521
|
+
}
|
|
10522
|
+
fs4.writeFileSync(sidecarPath, safeKind, "utf8");
|
|
10523
|
+
return true;
|
|
10524
|
+
} catch {
|
|
10525
|
+
return false;
|
|
10526
|
+
}
|
|
10527
|
+
}
|
|
10528
|
+
function evictOldest(d, maxCount) {
|
|
10529
|
+
try {
|
|
10530
|
+
const entries = [];
|
|
10531
|
+
const files = fs4.readdirSync(d);
|
|
10532
|
+
for (const file of files) {
|
|
10533
|
+
const fullPath = path7.join(d, file);
|
|
10534
|
+
if (!file.endsWith(".bin")) continue;
|
|
10535
|
+
try {
|
|
10536
|
+
const stat3 = fs4.statSync(fullPath);
|
|
10537
|
+
entries.push([fullPath, stat3.mtimeMs]);
|
|
10538
|
+
} catch {
|
|
10539
|
+
continue;
|
|
10540
|
+
}
|
|
10541
|
+
}
|
|
10542
|
+
if (entries.length <= maxCount) return 0;
|
|
10543
|
+
entries.sort((a, b) => a[1] - b[1]);
|
|
10544
|
+
let removed = 0;
|
|
10545
|
+
const over = entries.length - maxCount;
|
|
10546
|
+
for (const [p] of entries.slice(0, over)) {
|
|
10547
|
+
try {
|
|
10548
|
+
fs4.unlinkSync(p);
|
|
10549
|
+
removed++;
|
|
10550
|
+
try {
|
|
10551
|
+
fs4.unlinkSync(kindSidecarPath(p));
|
|
10552
|
+
} catch {
|
|
10553
|
+
}
|
|
10554
|
+
} catch {
|
|
10555
|
+
continue;
|
|
10556
|
+
}
|
|
10557
|
+
}
|
|
10558
|
+
return removed;
|
|
10559
|
+
} catch {
|
|
10560
|
+
return 0;
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
function store(sessionId, filePath, content, opts = {}) {
|
|
10564
|
+
const kind = opts.kind ?? KIND_READ;
|
|
10565
|
+
const origLen = content.length;
|
|
10566
|
+
if (origLen > MAX_SNAPSHOT_BYTES) {
|
|
10567
|
+
return null;
|
|
10568
|
+
}
|
|
10569
|
+
let stored = content;
|
|
10570
|
+
if (origLen > SNAPSHOT_TRUNCATE_BYTES) {
|
|
10571
|
+
const marker = Buffer.from(`
|
|
10572
|
+
<snapshot truncated at ${origLen} bytes>
|
|
10573
|
+
`);
|
|
10574
|
+
stored = Buffer.concat([content.slice(0, SNAPSHOT_TRUNCATE_BYTES), marker]);
|
|
10575
|
+
}
|
|
10576
|
+
const p = snapshot_path(sessionId, filePath);
|
|
10577
|
+
if (!p) return null;
|
|
10578
|
+
const sha = crypto.createHash("sha256").update(stored).digest("hex");
|
|
10579
|
+
try {
|
|
10580
|
+
if (fs4.existsSync(p)) {
|
|
10581
|
+
try {
|
|
10582
|
+
const existing = fs4.readFileSync(p);
|
|
10583
|
+
if (Buffer.from(existing).equals(stored)) {
|
|
10584
|
+
return {
|
|
10585
|
+
path: p,
|
|
10586
|
+
content_sha: sha,
|
|
10587
|
+
size_bytes: stored.length
|
|
10588
|
+
};
|
|
10589
|
+
}
|
|
10590
|
+
} catch {
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
const dir = path7.dirname(p);
|
|
10594
|
+
if (!fs4.existsSync(dir)) {
|
|
10595
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
10596
|
+
}
|
|
10597
|
+
evictOldest(dir, MAX_SNAPSHOTS_PER_SESSION - 1);
|
|
10598
|
+
const tempPath = p + ".tmp";
|
|
10599
|
+
fs4.writeFileSync(tempPath, stored);
|
|
10600
|
+
fs4.renameSync(tempPath, p);
|
|
10601
|
+
const sidecar = kindSidecarPath(p);
|
|
10602
|
+
writeSnapshotKind(sidecar, kind);
|
|
10603
|
+
return {
|
|
10604
|
+
path: p,
|
|
10605
|
+
content_sha: sha,
|
|
10606
|
+
size_bytes: stored.length
|
|
10607
|
+
};
|
|
10608
|
+
} catch {
|
|
10609
|
+
return null;
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
function load(sessionId, filePath, opts = {}) {
|
|
10613
|
+
const p = snapshot_path(sessionId, filePath);
|
|
10614
|
+
if (!p || !fs4.existsSync(p)) return null;
|
|
10615
|
+
try {
|
|
10616
|
+
const stat3 = fs4.statSync(p);
|
|
10617
|
+
if (stat3.size > MAX_SNAPSHOT_BYTES) {
|
|
10618
|
+
return null;
|
|
10619
|
+
}
|
|
10620
|
+
} catch {
|
|
10621
|
+
return null;
|
|
10622
|
+
}
|
|
10623
|
+
try {
|
|
10624
|
+
const data = fs4.readFileSync(p);
|
|
10625
|
+
if (opts.expected_sha) {
|
|
10626
|
+
const actualSha = crypto.createHash("sha256").update(data).digest("hex");
|
|
10627
|
+
if (actualSha.toLowerCase() !== opts.expected_sha.toLowerCase()) {
|
|
10628
|
+
return null;
|
|
10629
|
+
}
|
|
10630
|
+
}
|
|
10631
|
+
return data;
|
|
10632
|
+
} catch {
|
|
10633
|
+
return null;
|
|
10634
|
+
}
|
|
10635
|
+
}
|
|
10636
|
+
|
|
10401
10637
|
// src/hints.ts
|
|
10402
10638
|
init_define_import_meta_env();
|
|
10403
10639
|
var HINT_PRIORITY_MEDIUM = 3;
|
|
@@ -10430,11 +10666,11 @@ function buildPackageManifestHint(options) {
|
|
|
10430
10666
|
return null;
|
|
10431
10667
|
}
|
|
10432
10668
|
}
|
|
10433
|
-
function _sanitizeHintPath(
|
|
10434
|
-
if (typeof
|
|
10669
|
+
function _sanitizeHintPath(path17) {
|
|
10670
|
+
if (typeof path17 !== "string") {
|
|
10435
10671
|
return "???";
|
|
10436
10672
|
}
|
|
10437
|
-
return
|
|
10673
|
+
return path17.replace(/[\x00]/g, "").slice(0, 200);
|
|
10438
10674
|
}
|
|
10439
10675
|
|
|
10440
10676
|
// src/hints/lang_patterns.ts
|
|
@@ -10550,8 +10786,9 @@ var BUILD_COMMAND_PATTERNS = [
|
|
|
10550
10786
|
/^\s*cmake\s+--build\b/i,
|
|
10551
10787
|
// Rake (Ruby)
|
|
10552
10788
|
/^\s*rake\b/i,
|
|
10553
|
-
// TypeScript compiler
|
|
10554
|
-
/^\s*tsc
|
|
10789
|
+
// TypeScript compiler (direct and via npx)
|
|
10790
|
+
/^\s*tsc(?:\s|$)/i,
|
|
10791
|
+
/^\s*npx\s+tsc(?:\s|$)/i,
|
|
10555
10792
|
// Vite
|
|
10556
10793
|
/^\s*vite\s+(build|dev|preview)\b/i,
|
|
10557
10794
|
// Next.js
|
|
@@ -10636,6 +10873,7 @@ var MONITORING_COMMAND_PATTERNS = [
|
|
|
10636
10873
|
// Linters / formatters run repeatedly
|
|
10637
10874
|
{ pattern: /^(?:npx\s+)?eslint(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
|
|
10638
10875
|
{ pattern: /^(?:npx\s+)?prettier(?:\s|$)/, recallHint: '--grep "unchanged|reformatted|error"' },
|
|
10876
|
+
{ pattern: /^npx\s+tsc(?:\s|$)/, recallHint: '--grep "error TS|Cannot find|Type "' },
|
|
10639
10877
|
{ pattern: /^ruff(?:\s|$)/, recallHint: '--grep "error|warning|Found"' },
|
|
10640
10878
|
{ pattern: /^(?:cargo\s+)?clippy/, recallHint: '--grep "error\\[|warning\\["' },
|
|
10641
10879
|
// git diff (full diff output — can be very large; excludes --stat which is small)
|
|
@@ -10645,6 +10883,8 @@ var MONITORING_COMMAND_PATTERNS = [
|
|
|
10645
10883
|
{ pattern: /^npm run (?:test|spec)(?:\s|$)/, recallHint: '--grep "FAIL|PASS|Error|Tests:|\u2713|\u2717"' },
|
|
10646
10884
|
{ pattern: /^npm run build(?:\s|$)/, recallHint: '--grep "error|Built|Failed|\u2713|\u2717"' },
|
|
10647
10885
|
{ pattern: /^npm run (?:lint|typecheck|check|type-check)(?:\s|$)/, recallHint: '--grep "error|warning|\u2716|problems"' },
|
|
10886
|
+
// node scripts (migration runners, seed generators, etc. run repeatedly)
|
|
10887
|
+
{ pattern: /^node\s+(?:scripts|src\/scripts)\/\S+\.m?js\b/, recallHint: '--tail 50 --grep "error|Error|done|complete|inserted|migrated"' },
|
|
10648
10888
|
// External AI peer-review CLI tools (produce large outputs, run repeatedly per session)
|
|
10649
10889
|
{ pattern: /^codex(?:\s|$)/, recallHint: '--tail 100 --grep "error|suggestion|verdict|conclusion"' },
|
|
10650
10890
|
{ pattern: /^(?:~\/\.claude\/bin\/|\.claude\/bin\/)?glm\.sh(?:\s|$)/, recallHint: '--tail 100 --grep "error|verdict|conclusion|suggestion"' },
|
|
@@ -10874,7 +11114,7 @@ function dispatchFileTypeHandler(filePath, content, contentLengthHint) {
|
|
|
10874
11114
|
|
|
10875
11115
|
// src/stats.ts
|
|
10876
11116
|
init_define_import_meta_env();
|
|
10877
|
-
import * as
|
|
11117
|
+
import * as path8 from "node:path";
|
|
10878
11118
|
|
|
10879
11119
|
// src/render/stats_renderer.ts
|
|
10880
11120
|
init_define_import_meta_env();
|
|
@@ -11654,7 +11894,7 @@ CREATE INDEX IF NOT EXISTS idx_stats_kind ON stats(kind);
|
|
|
11654
11894
|
var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
11655
11895
|
registerReset(() => _globalSchemaApplied.clear());
|
|
11656
11896
|
function getGlobalDb() {
|
|
11657
|
-
const dbPath =
|
|
11897
|
+
const dbPath = path8.join(dataDir(), "global.db");
|
|
11658
11898
|
const db = getDb(dbPath);
|
|
11659
11899
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
11660
11900
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
@@ -11688,7 +11928,9 @@ function summarize(windowDays = 30, testDb) {
|
|
|
11688
11928
|
const bytesSaved = row.bytes_saved ?? 0;
|
|
11689
11929
|
const tokensSaved = row.tokens_saved ?? 0;
|
|
11690
11930
|
const kind = row.kind;
|
|
11691
|
-
const
|
|
11931
|
+
const tsRaw = row.ts;
|
|
11932
|
+
if (tsRaw === void 0) continue;
|
|
11933
|
+
const ts = tsRaw;
|
|
11692
11934
|
totalEvents += 1;
|
|
11693
11935
|
totalBytes += bytesSaved;
|
|
11694
11936
|
totalTokens += tokensSaved;
|
|
@@ -11851,22 +12093,59 @@ function isTsConfigFile(basename7) {
|
|
|
11851
12093
|
var LARGE_FILE_BYTES = 100 * 1024;
|
|
11852
12094
|
var REREAD_DENY_BYTES = 50 * 1024;
|
|
11853
12095
|
var LARGE_FILE_DENY_BYTES = 500 * 1024;
|
|
11854
|
-
function isNodeModulesPath(
|
|
11855
|
-
const
|
|
11856
|
-
const check = isWindows ? path15.toLowerCase() : path15;
|
|
12096
|
+
function isNodeModulesPath(p) {
|
|
12097
|
+
const check = isWindows() ? p.toLowerCase() : p;
|
|
11857
12098
|
return check.includes("/node_modules/") || check.includes("\\node_modules\\");
|
|
11858
12099
|
}
|
|
11859
12100
|
function _isDocFile(filePath) {
|
|
11860
12101
|
const lower = filePath.toLowerCase();
|
|
11861
12102
|
return lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".markdown") || lower.endsWith(".rst");
|
|
11862
12103
|
}
|
|
12104
|
+
function isSessionArtifactFile(filePath) {
|
|
12105
|
+
if (/[/\\]tasks[/\\][a-z0-9]+\.output$/i.test(filePath)) return true;
|
|
12106
|
+
if (/[/\\]tool-results[/\\][a-z0-9]+\.txt$/i.test(filePath)) return true;
|
|
12107
|
+
return false;
|
|
12108
|
+
}
|
|
11863
12109
|
function statSize(absPath) {
|
|
11864
12110
|
try {
|
|
11865
|
-
return
|
|
12111
|
+
return fs5.statSync(absPath).size;
|
|
11866
12112
|
} catch {
|
|
11867
12113
|
return null;
|
|
11868
12114
|
}
|
|
11869
12115
|
}
|
|
12116
|
+
function buildLineDiff(oldContent, newContent, label) {
|
|
12117
|
+
const oldLines = oldContent.split("\n");
|
|
12118
|
+
const newLines = newContent.split("\n");
|
|
12119
|
+
let prefix = 0;
|
|
12120
|
+
while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix]) {
|
|
12121
|
+
prefix++;
|
|
12122
|
+
}
|
|
12123
|
+
let oldSuffix = oldLines.length;
|
|
12124
|
+
let newSuffix = newLines.length;
|
|
12125
|
+
while (oldSuffix > prefix && newSuffix > prefix && oldLines[oldSuffix - 1] === newLines[newSuffix - 1]) {
|
|
12126
|
+
oldSuffix--;
|
|
12127
|
+
newSuffix--;
|
|
12128
|
+
}
|
|
12129
|
+
if (prefix === oldLines.length && prefix === newLines.length) return "";
|
|
12130
|
+
const changedOld = oldLines.slice(prefix, oldSuffix);
|
|
12131
|
+
const changedNew = newLines.slice(prefix, newSuffix);
|
|
12132
|
+
const MAX_LINES = 50;
|
|
12133
|
+
const out2 = [
|
|
12134
|
+
`--- ${label} (prev)`,
|
|
12135
|
+
`+++ ${label} (current)`,
|
|
12136
|
+
`@@ -${prefix + 1},${changedOld.length} +${prefix + 1},${changedNew.length} @@`
|
|
12137
|
+
];
|
|
12138
|
+
const removedLines = changedOld.map((l) => `-${l}`);
|
|
12139
|
+
const addedLines = changedNew.map((l) => `+${l}`);
|
|
12140
|
+
const allChanges = [...removedLines, ...addedLines];
|
|
12141
|
+
if (allChanges.length <= MAX_LINES) {
|
|
12142
|
+
out2.push(...allChanges);
|
|
12143
|
+
} else {
|
|
12144
|
+
out2.push(...allChanges.slice(0, MAX_LINES));
|
|
12145
|
+
out2.push(`... (${allChanges.length - MAX_LINES} more changed lines)`);
|
|
12146
|
+
}
|
|
12147
|
+
return out2.join("\n");
|
|
12148
|
+
}
|
|
11870
12149
|
function preReadHandler(event) {
|
|
11871
12150
|
const filePath = getFilePath(event);
|
|
11872
12151
|
if (filePath === void 0) return passOutput();
|
|
@@ -11876,7 +12155,7 @@ function preReadHandler(event) {
|
|
|
11876
12155
|
"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"
|
|
11877
12156
|
);
|
|
11878
12157
|
}
|
|
11879
|
-
const basename7 =
|
|
12158
|
+
const basename7 = path9.basename(normalized);
|
|
11880
12159
|
if (isLockFile(basename7)) {
|
|
11881
12160
|
return denyOutput(
|
|
11882
12161
|
'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.'
|
|
@@ -11915,7 +12194,7 @@ function preReadHandler(event) {
|
|
|
11915
12194
|
try {
|
|
11916
12195
|
const sz = statSize(normalized);
|
|
11917
12196
|
if (sz !== null && sz >= MARKDOWN_SIZE_THRESHOLD) {
|
|
11918
|
-
fileContent =
|
|
12197
|
+
fileContent = fs5.readFileSync(normalized, "utf8");
|
|
11919
12198
|
}
|
|
11920
12199
|
} catch {
|
|
11921
12200
|
}
|
|
@@ -11931,6 +12210,22 @@ function preReadHandler(event) {
|
|
|
11931
12210
|
}
|
|
11932
12211
|
}
|
|
11933
12212
|
}
|
|
12213
|
+
const isMemoryMd = normalized.toLowerCase().includes("memory/memory.md") || /[/\\]memory[/\\][^/\\]+\.md$/i.test(normalized);
|
|
12214
|
+
if (isMemoryMd && wasFileReadThisSession(normalized)) {
|
|
12215
|
+
recordFileRead(normalized);
|
|
12216
|
+
recordStat("session_hint", 0, 0);
|
|
12217
|
+
const isMainMemory = basename7.toLowerCase() === "memory.md";
|
|
12218
|
+
return denyOutput(
|
|
12219
|
+
isMainMemory ? "MEMORY.md was read this session. Its content is in the compact manifest as 'session memory'." : normalized + ' was already read this session. Memory files rarely change mid-session. Use `token-goat section "' + normalized + '::SectionHeading"` to extract one section.'
|
|
12220
|
+
);
|
|
12221
|
+
}
|
|
12222
|
+
if (/^\.improve-state-.*\.json$/.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
12223
|
+
recordFileRead(normalized);
|
|
12224
|
+
recordStat("session_hint", 0, 0);
|
|
12225
|
+
return denyOutput(
|
|
12226
|
+
"Orchestrator state already read this session. Use `token-goat bash-output <id>` or recall it from the compact manifest."
|
|
12227
|
+
);
|
|
12228
|
+
}
|
|
11934
12229
|
if (/^\.env(\.\w+)?$/.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
11935
12230
|
recordFileRead(normalized);
|
|
11936
12231
|
recordStat("session_hint", 0, 0);
|
|
@@ -11938,14 +12233,124 @@ function preReadHandler(event) {
|
|
|
11938
12233
|
normalized + " was already read this session. Environment files rarely change mid-session. Use `token-goat config-get " + normalized + " KEY_NAME` to extract a specific variable."
|
|
11939
12234
|
);
|
|
11940
12235
|
}
|
|
12236
|
+
if (isSessionArtifactFile(normalized)) {
|
|
12237
|
+
if (wasFileReadThisSession(normalized)) {
|
|
12238
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12239
|
+
recordFileRead(normalized);
|
|
12240
|
+
recordStat("session_hint", 0, 0);
|
|
12241
|
+
return denyOutput(
|
|
12242
|
+
"File was truncated on last read. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12243
|
+
);
|
|
12244
|
+
}
|
|
12245
|
+
const artifactSessionId = getSessionId();
|
|
12246
|
+
const oldArtifactSnap = load(artifactSessionId, normalized);
|
|
12247
|
+
if (oldArtifactSnap !== null) {
|
|
12248
|
+
try {
|
|
12249
|
+
const sz = statSize(normalized);
|
|
12250
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12251
|
+
const currentContent = fs5.readFileSync(normalized, "utf8");
|
|
12252
|
+
const TRUNC_MARKER = "\n<snapshot truncated at ";
|
|
12253
|
+
const oldRaw = oldArtifactSnap.toString("utf8");
|
|
12254
|
+
const truncIdx = oldRaw.indexOf(TRUNC_MARKER);
|
|
12255
|
+
const oldContent = truncIdx >= 0 ? oldRaw.slice(0, truncIdx) : oldRaw;
|
|
12256
|
+
if (oldContent === currentContent) {
|
|
12257
|
+
recordFileRead(normalized);
|
|
12258
|
+
recordStat("session_hint", 0, 0);
|
|
12259
|
+
return denyOutput(
|
|
12260
|
+
basename7 + " is unchanged since last read. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12261
|
+
);
|
|
12262
|
+
}
|
|
12263
|
+
const diff = buildLineDiff(oldContent, currentContent, basename7);
|
|
12264
|
+
if (diff !== "") {
|
|
12265
|
+
recordFileRead(normalized);
|
|
12266
|
+
const savedBytes = Math.max(0, currentContent.length - diff.length);
|
|
12267
|
+
recordStat("session_hint", savedBytes, Math.round(savedBytes / 4));
|
|
12268
|
+
return denyOutput(
|
|
12269
|
+
"Content changed since last read of " + basename7 + ". Here is what changed:\n\n```diff\n" + diff + "\n```\n\nUse `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12270
|
+
);
|
|
12271
|
+
}
|
|
12272
|
+
}
|
|
12273
|
+
} catch {
|
|
12274
|
+
}
|
|
12275
|
+
}
|
|
12276
|
+
recordFileRead(normalized);
|
|
12277
|
+
recordStat("session_hint", 0, 0);
|
|
12278
|
+
return denyOutput(
|
|
12279
|
+
normalized + " was already read this session. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12280
|
+
);
|
|
12281
|
+
}
|
|
12282
|
+
if (/[/\\]tasks[/\\][a-z0-9]+\.output$/i.test(normalized)) {
|
|
12283
|
+
recordFileRead(normalized);
|
|
12284
|
+
return contextOutput(
|
|
12285
|
+
"Session transcript: use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice instead of the full file."
|
|
12286
|
+
);
|
|
12287
|
+
}
|
|
12288
|
+
}
|
|
12289
|
+
if (/\.(md|mdx|rst|txt)$/i.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
12290
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12291
|
+
recordFileRead(normalized);
|
|
12292
|
+
recordStat("session_hint", 0, 0);
|
|
12293
|
+
return denyOutput(
|
|
12294
|
+
'File was truncated on last read (>33K tokens). Use `token-goat skeleton "' + normalized + '"` for structure or `token-goat read "' + normalized + '::SymbolName"` for one function.'
|
|
12295
|
+
);
|
|
12296
|
+
}
|
|
12297
|
+
const sessionId = getSessionId();
|
|
12298
|
+
const oldSnap = load(sessionId, normalized);
|
|
12299
|
+
if (oldSnap !== null) {
|
|
12300
|
+
try {
|
|
12301
|
+
const sz = statSize(normalized);
|
|
12302
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12303
|
+
const currentContent = fs5.readFileSync(normalized, "utf8");
|
|
12304
|
+
const TRUNC_MARKER = "\n<snapshot truncated at ";
|
|
12305
|
+
const oldRaw = oldSnap.toString("utf8");
|
|
12306
|
+
const truncIdx = oldRaw.indexOf(TRUNC_MARKER);
|
|
12307
|
+
const oldContent = truncIdx >= 0 ? oldRaw.slice(0, truncIdx) : oldRaw;
|
|
12308
|
+
if (oldContent === currentContent) {
|
|
12309
|
+
recordFileRead(normalized);
|
|
12310
|
+
recordStat("session_hint", 0, 0);
|
|
12311
|
+
return denyOutput(
|
|
12312
|
+
basename7 + ' is unchanged since last read. Use `token-goat section "' + normalized + '::HeadingName"` to extract a part.'
|
|
12313
|
+
);
|
|
12314
|
+
}
|
|
12315
|
+
const diff = buildLineDiff(oldContent, currentContent, basename7);
|
|
12316
|
+
if (diff !== "") {
|
|
12317
|
+
recordFileRead(normalized);
|
|
12318
|
+
const savedBytes = Math.max(0, currentContent.length - diff.length);
|
|
12319
|
+
recordStat("session_hint", savedBytes, Math.round(savedBytes / 4));
|
|
12320
|
+
return denyOutput(
|
|
12321
|
+
"Content changed since last read of " + basename7 + ". Here is what changed:\n\n```diff\n" + diff + '\n```\n\nUse `token-goat section "' + normalized + '::HeadingName"` to read a specific section.'
|
|
12322
|
+
);
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
} catch {
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12328
|
+
}
|
|
11941
12329
|
if (wasFileReadThisSession(normalized)) {
|
|
11942
12330
|
const entry = getSessionFiles().get(normalized);
|
|
11943
12331
|
const reads = entry?.readCount ?? 1;
|
|
11944
12332
|
const plural = reads === 1 ? "read" : "reads";
|
|
11945
12333
|
recordFileRead(normalized);
|
|
11946
|
-
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
11947
12334
|
const rereadBytes = statSize(normalized) ?? 0;
|
|
11948
12335
|
recordStat("session_hint", rereadBytes, Math.round(rereadBytes / 4));
|
|
12336
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12337
|
+
return denyOutput(
|
|
12338
|
+
'File was truncated on last read (>33K tokens). Use `token-goat skeleton "' + normalized + '"` for structure or `token-goat read "' + normalized + '::SymbolName"` for one function.'
|
|
12339
|
+
);
|
|
12340
|
+
}
|
|
12341
|
+
if (/\.(md|mdx)$/i.test(basename7)) {
|
|
12342
|
+
return denyOutput(
|
|
12343
|
+
'Markdown file already read this session. Use `token-goat section "' + normalized + '::HeadingName"` to read one section.'
|
|
12344
|
+
);
|
|
12345
|
+
}
|
|
12346
|
+
const isSourceExt = /\.(ts|tsx|js|jsx|py|go|rs|java|rb|php|swift|kt|cpp|c|h)$/i.test(basename7);
|
|
12347
|
+
if (isSourceExt && reads >= 2) {
|
|
12348
|
+
recordStat("read_count_deny", rereadBytes, Math.round(rereadBytes / 4));
|
|
12349
|
+
return denyOutput(
|
|
12350
|
+
"Read this file " + reads + ' times already \u2014 use `token-goat read "' + normalized + '::Symbol"`, `token-goat skeleton ' + normalized + "`, or `token-goat outline " + normalized + "` to pull just the part you need."
|
|
12351
|
+
);
|
|
12352
|
+
}
|
|
12353
|
+
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
11949
12354
|
if (rereadBytes >= REREAD_DENY_BYTES || reads >= 2) {
|
|
11950
12355
|
return denyOutput(
|
|
11951
12356
|
normalized + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
@@ -11967,10 +12372,10 @@ function preReadHandler(event) {
|
|
|
11967
12372
|
);
|
|
11968
12373
|
}
|
|
11969
12374
|
return contextOutput(
|
|
11970
|
-
"Note: " + normalized + " is large (" + kb + "
|
|
12375
|
+
"Note: " + normalized + " is large (" + kb + "KB). " + hint
|
|
11971
12376
|
);
|
|
11972
12377
|
}
|
|
11973
|
-
const fileTypeExt =
|
|
12378
|
+
const fileTypeExt = path9.extname(normalized).slice(1).toLowerCase();
|
|
11974
12379
|
const binaryExts = /* @__PURE__ */ new Set(["pdf", "docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"]);
|
|
11975
12380
|
const textTypeExts = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv"]);
|
|
11976
12381
|
const fileStatSize = size ?? statSize(normalized) ?? 0;
|
|
@@ -11979,7 +12384,7 @@ function preReadHandler(event) {
|
|
|
11979
12384
|
let ftContent = "";
|
|
11980
12385
|
if (!binaryExts.has(fileTypeExt)) {
|
|
11981
12386
|
try {
|
|
11982
|
-
ftContent =
|
|
12387
|
+
ftContent = fs5.readFileSync(normalized, "utf8");
|
|
11983
12388
|
} catch {
|
|
11984
12389
|
}
|
|
11985
12390
|
}
|
|
@@ -11994,29 +12399,67 @@ function preReadHandler(event) {
|
|
|
11994
12399
|
}
|
|
11995
12400
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Read" });
|
|
11996
12401
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Grep" });
|
|
12402
|
+
function extractReadOutput(raw) {
|
|
12403
|
+
const resp = raw["tool_response"];
|
|
12404
|
+
if (typeof resp === "string") return resp;
|
|
12405
|
+
if (resp !== null && typeof resp === "object") {
|
|
12406
|
+
const r = resp;
|
|
12407
|
+
for (const key of ["output", "content", "text", "body"]) {
|
|
12408
|
+
if (typeof r[key] === "string") return r[key];
|
|
12409
|
+
}
|
|
12410
|
+
}
|
|
12411
|
+
return "";
|
|
12412
|
+
}
|
|
12413
|
+
function postReadHandler(event) {
|
|
12414
|
+
const filePath = getFilePath(event);
|
|
12415
|
+
if (filePath === void 0) return passOutput();
|
|
12416
|
+
const normalized = normalizePath(filePath);
|
|
12417
|
+
const respText = extractReadOutput(event.raw);
|
|
12418
|
+
if (respText.includes("[Truncated:") || respText.includes("Truncated: PARTIAL view")) {
|
|
12419
|
+
markFileTruncated(normalized);
|
|
12420
|
+
}
|
|
12421
|
+
const postBasename = path9.basename(normalized);
|
|
12422
|
+
if (/\.(md|mdx|rst|txt)$/i.test(postBasename) || isSessionArtifactFile(normalized)) {
|
|
12423
|
+
try {
|
|
12424
|
+
const sz = statSize(normalized);
|
|
12425
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12426
|
+
const content = fs5.readFileSync(normalized);
|
|
12427
|
+
store(getSessionId(), normalized, content);
|
|
12428
|
+
}
|
|
12429
|
+
} catch {
|
|
12430
|
+
}
|
|
12431
|
+
}
|
|
12432
|
+
return passOutput();
|
|
12433
|
+
}
|
|
12434
|
+
registerHook("post_tool_use", postReadHandler, { toolName: "Read" });
|
|
11997
12435
|
|
|
11998
12436
|
// src/hooks_edit.ts
|
|
11999
12437
|
init_define_import_meta_env();
|
|
12000
|
-
import * as
|
|
12438
|
+
import * as path11 from "node:path";
|
|
12001
12439
|
|
|
12002
12440
|
// src/hooks_index.ts
|
|
12003
12441
|
init_define_import_meta_env();
|
|
12004
|
-
import * as
|
|
12005
|
-
import * as
|
|
12442
|
+
import * as fs6 from "node:fs";
|
|
12443
|
+
import * as path10 from "node:path";
|
|
12006
12444
|
function dirtyQueuePath() {
|
|
12007
|
-
return
|
|
12445
|
+
return path10.join(dataDir(), "queue", "dirty.txt");
|
|
12008
12446
|
}
|
|
12009
12447
|
function appendDirtyPath(normalizedPath) {
|
|
12010
12448
|
const queuePath = dirtyQueuePath();
|
|
12011
|
-
|
|
12012
|
-
|
|
12449
|
+
const dir = path10.dirname(queuePath);
|
|
12450
|
+
try {
|
|
12451
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
12452
|
+
} catch (e) {
|
|
12453
|
+
if (e.code !== "EEXIST" || !fs6.existsSync(dir)) throw e;
|
|
12454
|
+
}
|
|
12455
|
+
fs6.appendFileSync(queuePath, `${normalizedPath}
|
|
12013
12456
|
`);
|
|
12014
12457
|
}
|
|
12015
12458
|
function getDirtyPaths() {
|
|
12016
12459
|
const queuePath = dirtyQueuePath();
|
|
12017
12460
|
let raw;
|
|
12018
12461
|
try {
|
|
12019
|
-
raw =
|
|
12462
|
+
raw = fs6.readFileSync(queuePath, "utf8");
|
|
12020
12463
|
} catch {
|
|
12021
12464
|
return [];
|
|
12022
12465
|
}
|
|
@@ -12032,21 +12475,21 @@ function getDirtyPaths() {
|
|
|
12032
12475
|
}
|
|
12033
12476
|
function clearDirtyQueue() {
|
|
12034
12477
|
try {
|
|
12035
|
-
|
|
12478
|
+
fs6.rmSync(dirtyQueuePath(), { force: true });
|
|
12036
12479
|
} catch {
|
|
12037
12480
|
}
|
|
12038
12481
|
}
|
|
12039
12482
|
function preCompactIndexHandler(_event) {
|
|
12040
12483
|
const paths = getDirtyPaths();
|
|
12041
12484
|
if (paths.length > 0) {
|
|
12042
|
-
const sidecar =
|
|
12485
|
+
const sidecar = path10.join(dataDir(), "queue", "pending.txt");
|
|
12043
12486
|
try {
|
|
12044
|
-
|
|
12487
|
+
fs6.mkdirSync(path10.dirname(sidecar), { recursive: true });
|
|
12045
12488
|
atomicWriteBytes(sidecar, Buffer.from(`${paths.join("\n")}
|
|
12046
12489
|
`, "utf8"));
|
|
12490
|
+
clearDirtyQueue();
|
|
12047
12491
|
} catch {
|
|
12048
12492
|
}
|
|
12049
|
-
clearDirtyQueue();
|
|
12050
12493
|
}
|
|
12051
12494
|
return passOutput();
|
|
12052
12495
|
}
|
|
@@ -12059,10 +12502,11 @@ function postEditHandler(event) {
|
|
|
12059
12502
|
const normalized = normalizePath(filePath);
|
|
12060
12503
|
recordFileEdit(normalized);
|
|
12061
12504
|
appendDirtyPath(normalized);
|
|
12062
|
-
const editedBasename =
|
|
12505
|
+
const editedBasename = path11.basename(normalized);
|
|
12063
12506
|
if (/\.(md|mdx|markdown|rst)$/i.test(editedBasename)) {
|
|
12507
|
+
const escapedPath = normalized.replace(/`/g, "\\`");
|
|
12064
12508
|
return contextOutput(
|
|
12065
|
-
editedBasename + ' was edited. Use `token-goat section "' +
|
|
12509
|
+
editedBasename + ' was edited. Use `token-goat section "' + escapedPath + '::HeadingName"` to re-read a specific section rather than the full file.'
|
|
12066
12510
|
);
|
|
12067
12511
|
}
|
|
12068
12512
|
return passOutput();
|
|
@@ -12340,17 +12784,20 @@ init_define_import_meta_env();
|
|
|
12340
12784
|
|
|
12341
12785
|
// src/fingerprint.ts
|
|
12342
12786
|
init_define_import_meta_env();
|
|
12343
|
-
import { createHash } from "node:crypto";
|
|
12344
|
-
import * as
|
|
12787
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12788
|
+
import * as fs7 from "node:fs";
|
|
12345
12789
|
function fingerprintContent(content) {
|
|
12346
|
-
const hash =
|
|
12790
|
+
const hash = createHash2("sha256");
|
|
12347
12791
|
hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
|
|
12348
12792
|
return hash.digest("hex");
|
|
12349
12793
|
}
|
|
12794
|
+
function shortFingerprint(content) {
|
|
12795
|
+
return fingerprintContent(content).slice(0, 16);
|
|
12796
|
+
}
|
|
12350
12797
|
function fingerprintFile(filePath) {
|
|
12351
12798
|
let data;
|
|
12352
12799
|
try {
|
|
12353
|
-
data =
|
|
12800
|
+
data = fs7.readFileSync(filePath);
|
|
12354
12801
|
} catch {
|
|
12355
12802
|
return null;
|
|
12356
12803
|
}
|
|
@@ -12359,15 +12806,24 @@ function fingerprintFile(filePath) {
|
|
|
12359
12806
|
|
|
12360
12807
|
// src/bash_output_cache.ts
|
|
12361
12808
|
init_define_import_meta_env();
|
|
12362
|
-
import * as
|
|
12809
|
+
import * as fs8 from "fs/promises";
|
|
12363
12810
|
import { resolve as resolve3 } from "path";
|
|
12364
12811
|
var _byId = /* @__PURE__ */ new Map();
|
|
12365
12812
|
var _globsByKey = /* @__PURE__ */ new Map();
|
|
12366
12813
|
var _grepsByKey = /* @__PURE__ */ new Map();
|
|
12367
|
-
var
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12814
|
+
var COMMAND_PATTERNS = {
|
|
12815
|
+
gitMutable: /^\s*git\s+(diff|status)\b/i,
|
|
12816
|
+
gitImmutable: /^\s*git\s+show\s+[0-9a-f]{40}\b/i,
|
|
12817
|
+
gitDiffUnscoped: /^\s*git\s+diff\b/i,
|
|
12818
|
+
gitDiffScoped: /\s--\s+\S/,
|
|
12819
|
+
dirListing: /^\s*(?:ls|eza|exa|dir|Get-ChildItem|gci)\b/i,
|
|
12820
|
+
depList: /^\s*(?:npm\s+(?:-\S+\s+)*(?:ls|list)\b|pip\s+(?:-\S+\s+)*(?:list|freeze)\b|uv\s+pip\s+(?:-\S+\s+)*(?:list|freeze)\b|pnpm\s+(?:-\S+\s+)*(?:list|ls)\b|yarn\s+(?:-\S+\s+)*(?:list)\b|cargo\s+(?:-\S+\s+)*tree\b|bundle\s+(?:-\S+\s+)*(?:list|show)\b|composer\s+(?:-\S+\s+)*show\b)/i,
|
|
12821
|
+
npmInstall: /^\s*npm\s+(?:-\S+\s+)*(?:install|ci)\b/i,
|
|
12822
|
+
npmAudit: /^\s*npm\s+(?:-\S+\s+)*audit\b(?!.*(?:--fix|fix)\b)/i,
|
|
12823
|
+
npmOutdated: /^\s*npm\s+(?:-\S+\s+)*outdated\b/i,
|
|
12824
|
+
envProbe: /^\s*(?:node\s+(?:-v|--version)|npm\s+(?:-v|--version)|python3?\s+(?:(?:-V)\b|--?version)|git\s+--version|uv\s+--version|go\s+version|rustc\s+--version|cargo\s+--version|java\s+--version|ruby\s+--version|gem\s+--version|php\s+--version|which\b|where\b)/i,
|
|
12825
|
+
npx: /^\s*npx\s+(?:--?yes\s+)?(?!.*\b(?:install|add|remove|uninstall|i|rm|update|upgrade|set|get|publish|link|ci|audit|shrinkwrap|dedupe|prune|rebuild)\b)/i
|
|
12826
|
+
};
|
|
12371
12827
|
var DEP_LOCKFILES = {
|
|
12372
12828
|
npm: ["package-lock.json", "yarn.lock"],
|
|
12373
12829
|
pip: ["requirements.txt"],
|
|
@@ -12378,18 +12834,14 @@ var DEP_LOCKFILES = {
|
|
|
12378
12834
|
bundle: ["Gemfile.lock"],
|
|
12379
12835
|
composer: ["composer.lock"]
|
|
12380
12836
|
};
|
|
12381
|
-
function
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
}
|
|
12390
|
-
function isNpmInstallCommand(cmd) {
|
|
12391
|
-
return NPM_INSTALL_RE.test(cmd);
|
|
12392
|
-
}
|
|
12837
|
+
function isCommandOfType(cmd, type) {
|
|
12838
|
+
const pattern = COMMAND_PATTERNS[type];
|
|
12839
|
+
return pattern?.test(cmd) ?? false;
|
|
12840
|
+
}
|
|
12841
|
+
var isGitMutableCommand = (cmd) => isCommandOfType(cmd, "gitMutable");
|
|
12842
|
+
var isDirListingCommand = (cmd) => isCommandOfType(cmd, "dirListing");
|
|
12843
|
+
var isDepListCommand = (cmd) => isCommandOfType(cmd, "depList");
|
|
12844
|
+
var isNpmInstallCommand = (cmd) => isCommandOfType(cmd, "npmInstall");
|
|
12393
12845
|
async function gitStateFingerprint(cwd) {
|
|
12394
12846
|
try {
|
|
12395
12847
|
const headResult = runGit(["rev-parse", "HEAD"], { cwd });
|
|
@@ -12397,21 +12849,21 @@ async function gitStateFingerprint(cwd) {
|
|
|
12397
12849
|
const headSha = headResult.stdout.trim();
|
|
12398
12850
|
let indexMtime = "";
|
|
12399
12851
|
try {
|
|
12400
|
-
const stat3 = await
|
|
12852
|
+
const stat3 = await fs8.stat(resolve3(cwd, ".git", "index"));
|
|
12401
12853
|
indexMtime = stat3.mtimeMs.toString();
|
|
12402
12854
|
} catch {
|
|
12403
12855
|
}
|
|
12404
12856
|
const key = `${headSha}\0${indexMtime}`;
|
|
12405
|
-
return
|
|
12857
|
+
return shortFingerprint(key);
|
|
12406
12858
|
} catch {
|
|
12407
12859
|
return null;
|
|
12408
12860
|
}
|
|
12409
12861
|
}
|
|
12410
|
-
async function dirStateFingerprint(
|
|
12862
|
+
async function dirStateFingerprint(path17) {
|
|
12411
12863
|
try {
|
|
12412
|
-
const stat3 = await
|
|
12864
|
+
const stat3 = await fs8.stat(path17);
|
|
12413
12865
|
if (!stat3.isDirectory()) return null;
|
|
12414
|
-
return
|
|
12866
|
+
return shortFingerprint(stat3.mtimeMs.toString());
|
|
12415
12867
|
} catch {
|
|
12416
12868
|
return null;
|
|
12417
12869
|
}
|
|
@@ -12425,8 +12877,8 @@ async function depLockfileFingerprint(cmd, cwd) {
|
|
|
12425
12877
|
if (!candidates) return null;
|
|
12426
12878
|
for (const lockfile of candidates) {
|
|
12427
12879
|
try {
|
|
12428
|
-
const content = await
|
|
12429
|
-
return
|
|
12880
|
+
const content = await fs8.readFile(resolve3(cwd, lockfile));
|
|
12881
|
+
return shortFingerprint(content);
|
|
12430
12882
|
} catch {
|
|
12431
12883
|
continue;
|
|
12432
12884
|
}
|
|
@@ -12474,7 +12926,7 @@ async function commandHash(command, cwd = null) {
|
|
|
12474
12926
|
const fp = await depLockfileFingerprint(command, cwd);
|
|
12475
12927
|
if (fp) key = `${key}\0npm-install:${fp}`;
|
|
12476
12928
|
}
|
|
12477
|
-
return
|
|
12929
|
+
return shortFingerprint(key);
|
|
12478
12930
|
}
|
|
12479
12931
|
function extractLsTarget(cmd, cwd) {
|
|
12480
12932
|
const tokens = cmd.trim().split(/\s+/);
|
|
@@ -12508,6 +12960,10 @@ registerReset(() => {
|
|
|
12508
12960
|
});
|
|
12509
12961
|
|
|
12510
12962
|
// src/hooks_bash.ts
|
|
12963
|
+
function stripCdPrefix(cmd) {
|
|
12964
|
+
const stripped = cmd.replace(/^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)\s*&&\s*)+/, "");
|
|
12965
|
+
return stripped.trim() || cmd;
|
|
12966
|
+
}
|
|
12511
12967
|
function extractCommand(event) {
|
|
12512
12968
|
const cmd = event.toolInput["command"];
|
|
12513
12969
|
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
@@ -12521,7 +12977,7 @@ function isOrchestratorStateFile(filePath) {
|
|
|
12521
12977
|
return /^\.improve-state-/.test(basename7);
|
|
12522
12978
|
}
|
|
12523
12979
|
function extractCatSourceFile(cmd) {
|
|
12524
|
-
const m = /^cat\s+(\S+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj))\s*$/.exec(cmd);
|
|
12980
|
+
const m = /^cat\s+(\S+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less))\s*$/.exec(cmd);
|
|
12525
12981
|
return m?.[1] ?? null;
|
|
12526
12982
|
}
|
|
12527
12983
|
function extractCatFile(cmd) {
|
|
@@ -12530,14 +12986,39 @@ function extractCatFile(cmd) {
|
|
|
12530
12986
|
const filePath = m[1] ?? m[2] ?? m[3];
|
|
12531
12987
|
if (filePath === void 0) return null;
|
|
12532
12988
|
if (isTempPath(filePath)) return null;
|
|
12533
|
-
const basename7 = filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1) ?? filePath;
|
|
12989
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12534
12990
|
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
12535
|
-
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
12991
|
+
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
12536
12992
|
if (!hasKnownExt && !isEnvFile) return null;
|
|
12537
|
-
const
|
|
12993
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
12994
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12538
12995
|
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
12539
12996
|
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
12540
|
-
return { filePath, isDoc, isEnv, isConfig };
|
|
12997
|
+
return { filePath, isDoc, isEnv, isConfig, isSql };
|
|
12998
|
+
}
|
|
12999
|
+
function extractRgSymbolSearch(cmd) {
|
|
13000
|
+
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
13001
|
+
if (!/-n\b/.test(cmd)) return null;
|
|
13002
|
+
const patternMatch = /["']([^"']+)["']/.exec(cmd);
|
|
13003
|
+
const pattern = patternMatch?.[1];
|
|
13004
|
+
if (!pattern) return null;
|
|
13005
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*(\|[A-Za-z_][A-Za-z0-9_]*)*$/.test(pattern)) return null;
|
|
13006
|
+
const fileMatch = /(?:^|\s)(?:"([^"]+\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|php|swift|kt|cpp|cc|cxx|c|h))"|'([^']+\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|php|swift|kt|cpp|cc|cxx|c|h))'|([^\s"'|<>]+\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|php|swift|kt|cpp|cc|cxx|c|h)))(?:\s|$|\|)/i.exec(cmd);
|
|
13007
|
+
if (!fileMatch) return null;
|
|
13008
|
+
const filePath = fileMatch[1] ?? fileMatch[2] ?? fileMatch[3];
|
|
13009
|
+
if (!filePath) return null;
|
|
13010
|
+
if (isTempPath(filePath)) return null;
|
|
13011
|
+
if (/-[a-zA-Z]*r[a-zA-Z]*\b/.test(cmd) || /--recursive\b/.test(cmd)) return null;
|
|
13012
|
+
return { filePath, identifier: pattern };
|
|
13013
|
+
}
|
|
13014
|
+
function extractCatJsonPipe(cmd) {
|
|
13015
|
+
const m = /^cat\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*\|\s*jq\b/.exec(cmd);
|
|
13016
|
+
if (!m) return null;
|
|
13017
|
+
const filePath = m[1] ?? m[2] ?? m[3];
|
|
13018
|
+
if (!filePath) return null;
|
|
13019
|
+
if (isTempPath(filePath)) return null;
|
|
13020
|
+
if (!/\.(?:json|yaml|yml|toml)$/i.test(filePath)) return null;
|
|
13021
|
+
return { filePath };
|
|
12541
13022
|
}
|
|
12542
13023
|
function extractWslCatFile(cmd) {
|
|
12543
13024
|
const wslMatch = /^wsl(?:\s+-d\s+\S+)?\s+bash\s+-c\s+"cat(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+\/mnt\/([a-z])\/([^"]*)"/.exec(cmd);
|
|
@@ -12547,18 +13028,44 @@ function extractWslCatFile(cmd) {
|
|
|
12547
13028
|
if (!drive || !pathRest) return null;
|
|
12548
13029
|
const filePath = drive + ":/" + pathRest;
|
|
12549
13030
|
if (isTempPath(filePath)) return null;
|
|
12550
|
-
const basename7 = filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1) ?? filePath;
|
|
13031
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12551
13032
|
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
12552
|
-
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
13033
|
+
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
12553
13034
|
if (!hasKnownExt && !isEnvFile) return null;
|
|
12554
|
-
const
|
|
13035
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
13036
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12555
13037
|
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
12556
13038
|
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
12557
|
-
return { filePath, isDoc, isEnv, isConfig };
|
|
13039
|
+
return { filePath, isDoc, isEnv, isConfig, isSql };
|
|
12558
13040
|
}
|
|
12559
13041
|
function extractPythonFileRead(cmd) {
|
|
12560
13042
|
if (!/python3?/.test(cmd)) return null;
|
|
12561
|
-
|
|
13043
|
+
if (/open\s*\([^)]*,\s*['"][wa]/i.test(cmd) || /\.write\s*\(/.test(cmd)) return null;
|
|
13044
|
+
const OPEN_EXT = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties)/i;
|
|
13045
|
+
const heredocMatch = /^python3?\s+-\s+<<\s*'?(\w+)'?\s*\n([\s\S]*?)\n\1\s*$/.exec(cmd);
|
|
13046
|
+
if (heredocMatch) {
|
|
13047
|
+
const body = heredocMatch[2] ?? "";
|
|
13048
|
+
if (/open\s*\([^)]*,\s*['"][wa]/i.test(body) || /\.write\s*\(/.test(body) || /\.writelines\s*\(/.test(body)) return null;
|
|
13049
|
+
const heredocOpen = /open\s*\(\s*r?['"]([^'"]+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties))['"]/i.exec(body);
|
|
13050
|
+
if (heredocOpen?.[1]) {
|
|
13051
|
+
const filePath = heredocOpen[1];
|
|
13052
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13053
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13054
|
+
return { filePath, isDoc };
|
|
13055
|
+
}
|
|
13056
|
+
if (/open\s*\(/.test(body)) {
|
|
13057
|
+
const literal = /['"]([^'"]+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties))['"]/i.exec(body);
|
|
13058
|
+
if (literal?.[1]) {
|
|
13059
|
+
const filePath = literal[1];
|
|
13060
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13061
|
+
if (OPEN_EXT.test(filePath)) {
|
|
13062
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13063
|
+
return { filePath, isDoc };
|
|
13064
|
+
}
|
|
13065
|
+
}
|
|
13066
|
+
}
|
|
13067
|
+
return null;
|
|
13068
|
+
}
|
|
12562
13069
|
const direct = /open\(['"]([^'"]+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties))['"]/i.exec(cmd);
|
|
12563
13070
|
if (direct) {
|
|
12564
13071
|
const filePath = direct[1] ?? "";
|
|
@@ -12573,7 +13080,7 @@ function extractPythonFileRead(cmd) {
|
|
|
12573
13080
|
const filePath = literal[1] ?? "";
|
|
12574
13081
|
if (filePath) {
|
|
12575
13082
|
if (isOrchestratorStateFile(filePath)) return null;
|
|
12576
|
-
if (
|
|
13083
|
+
if (OPEN_EXT.test(filePath)) {
|
|
12577
13084
|
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12578
13085
|
return { filePath, isDoc };
|
|
12579
13086
|
}
|
|
@@ -12586,7 +13093,7 @@ function extractHeadFile(cmd) {
|
|
|
12586
13093
|
const m = /^head(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
12587
13094
|
if (!m) return null;
|
|
12588
13095
|
const n = parseInt(m[1] ?? m[2] ?? "0", 10);
|
|
12589
|
-
if (n
|
|
13096
|
+
if (n < 10) return null;
|
|
12590
13097
|
const filePath = m[3] ?? m[4] ?? m[5];
|
|
12591
13098
|
if (filePath === void 0) return null;
|
|
12592
13099
|
if (isTempPath(filePath)) return null;
|
|
@@ -12597,13 +13104,24 @@ function extractHeadFile(cmd) {
|
|
|
12597
13104
|
}
|
|
12598
13105
|
function extractNodeFileRead(cmd) {
|
|
12599
13106
|
if (!/^node\s+-e/.test(cmd)) return null;
|
|
12600
|
-
const
|
|
12601
|
-
if (
|
|
12602
|
-
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
13107
|
+
const readSync = /readFileSync\(['"]([^'"]+\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql))['"]/i.exec(cmd);
|
|
13108
|
+
if (readSync?.[1]) {
|
|
13109
|
+
const filePath = readSync[1];
|
|
13110
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13111
|
+
if (isTempPath(filePath)) return null;
|
|
13112
|
+
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
13113
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
13114
|
+
return { filePath, isDoc, isConfig };
|
|
13115
|
+
}
|
|
13116
|
+
const requireM = /require\(['"]([^'"]+\.json)['"]\)/i.exec(cmd);
|
|
13117
|
+
if (requireM?.[1]) {
|
|
13118
|
+
const filePath = requireM[1];
|
|
13119
|
+
if (filePath.includes("node_modules")) return null;
|
|
13120
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13121
|
+
if (isTempPath(filePath)) return null;
|
|
13122
|
+
return { filePath, isDoc: false, isConfig: true };
|
|
13123
|
+
}
|
|
13124
|
+
return null;
|
|
12607
13125
|
}
|
|
12608
13126
|
function extractTailFile(cmd) {
|
|
12609
13127
|
if (/-f\b/.test(cmd)) return null;
|
|
@@ -12620,9 +13138,70 @@ function extractTailFile(cmd) {
|
|
|
12620
13138
|
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
12621
13139
|
return { filePath, isDoc };
|
|
12622
13140
|
}
|
|
13141
|
+
function extractTasksOutput(cmd) {
|
|
13142
|
+
const taskOutputRe = /[/\\]tasks[/\\]([a-z0-9]+)\.output$/;
|
|
13143
|
+
const catM = /^cat(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13144
|
+
if (catM) {
|
|
13145
|
+
const fp = catM[1] ?? catM[2] ?? catM[3];
|
|
13146
|
+
if (fp) {
|
|
13147
|
+
const m = taskOutputRe.exec(fp);
|
|
13148
|
+
if (m) return { id: m[1] };
|
|
13149
|
+
}
|
|
13150
|
+
}
|
|
13151
|
+
if (!/-f\b/.test(cmd) && !/-n\s*\+/.test(cmd)) {
|
|
13152
|
+
const tailM = /^tail(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13153
|
+
if (tailM) {
|
|
13154
|
+
const fp = tailM[3] ?? tailM[4] ?? tailM[5];
|
|
13155
|
+
if (fp) {
|
|
13156
|
+
const m = taskOutputRe.exec(fp);
|
|
13157
|
+
if (m) {
|
|
13158
|
+
const nStr = tailM[1] ?? tailM[2];
|
|
13159
|
+
const n = nStr !== void 0 ? parseInt(nStr, 10) : void 0;
|
|
13160
|
+
return n !== void 0 ? { id: m[1], n } : { id: m[1] };
|
|
13161
|
+
}
|
|
13162
|
+
}
|
|
13163
|
+
}
|
|
13164
|
+
const byteTailM = /^tail\s+-c\s+\d+\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13165
|
+
if (byteTailM) {
|
|
13166
|
+
const fp = byteTailM[1] ?? byteTailM[2] ?? byteTailM[3];
|
|
13167
|
+
if (fp) {
|
|
13168
|
+
const m = taskOutputRe.exec(fp);
|
|
13169
|
+
if (m) return { id: m[1] };
|
|
13170
|
+
}
|
|
13171
|
+
}
|
|
13172
|
+
}
|
|
13173
|
+
return null;
|
|
13174
|
+
}
|
|
13175
|
+
function extractSedLineRange(cmd) {
|
|
13176
|
+
return /^sed\s+-n\s+['"]?\d+,\d+p['"]?/.test(cmd);
|
|
13177
|
+
}
|
|
13178
|
+
function extractDirectoryListing(cmd) {
|
|
13179
|
+
return /^eza\s+.*--long\s+\S+/.test(cmd) || /^eza\s+.*--tree/.test(cmd) || /^tree(\s|$)/.test(cmd) || /^ls\s+.*-[a-zA-Z]*R/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*head/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*grep/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*wc/.test(cmd);
|
|
13180
|
+
}
|
|
13181
|
+
function extractForLoopWcL(cmd) {
|
|
13182
|
+
return /^for\s+\w+\s+in\s+.*;\s*do\s+wc\s+-l/.test(cmd);
|
|
13183
|
+
}
|
|
13184
|
+
function extractFindCommand(cmd) {
|
|
13185
|
+
if (!/^find\b/.test(cmd)) return null;
|
|
13186
|
+
const isXargsGrepL = /[|]\s*xargs\s+(?:grep|rg)\s+.*-l\b/.test(cmd) || /[|]\s*xargs\s+grep\s+-l\b/.test(cmd);
|
|
13187
|
+
const nameMatch = /-name\s+['"]([^'"]+)['"]/i.exec(cmd);
|
|
13188
|
+
const extGlob = nameMatch ? nameMatch[1] ?? null : null;
|
|
13189
|
+
return { extGlob, isXargsGrepL };
|
|
13190
|
+
}
|
|
13191
|
+
function extractMarkdownHeadingGrep(cmd) {
|
|
13192
|
+
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
13193
|
+
if (!/-n\b/.test(cmd)) return null;
|
|
13194
|
+
const hasHeadingPattern = /["']?\^#{1,6}["']?/.test(cmd) || /["']?\^#\+["']?/.test(cmd) || /["']?\^#\\+["']?/.test(cmd);
|
|
13195
|
+
if (!hasHeadingPattern) return null;
|
|
13196
|
+
const fileMatch = /(?:^|\s)(?:"([^"]+\.(?:md|markdown))"|'([^']+\.(?:md|markdown))'|([^\s"'|<>]+\.(?:md|markdown)))\s*(?:\||$)/.exec(cmd);
|
|
13197
|
+
if (!fileMatch) return null;
|
|
13198
|
+
const filePath = fileMatch[1] ?? fileMatch[2] ?? fileMatch[3];
|
|
13199
|
+
if (!filePath) return null;
|
|
13200
|
+
return { filePath };
|
|
13201
|
+
}
|
|
12623
13202
|
function extractRgStructuralSearch(cmd) {
|
|
12624
13203
|
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
12625
|
-
const hasStructural = /["']?\^?(?:def\s|class\s|function\s|func\s|fn\s|pub fn\s|import\s|from\s)/.test(cmd) || /["']\^(?:def|class|function|func|import|from)["']/.test(cmd) || /\\bdef\\b|\\bclass\\b/.test(cmd);
|
|
13204
|
+
const hasStructural = /["']?\^?(?:def\s|class\s|function\s|func\s|fn\s|pub fn\s|import\s|from\s)/.test(cmd) || /["']\^(?:def|class|function|func|import|from)["']/.test(cmd) || /\\bdef\\b|\\bclass\\b/.test(cmd) || /["']?\^[ \t]+def\b/.test(cmd);
|
|
12626
13205
|
if (!hasStructural) return null;
|
|
12627
13206
|
const fileMatch = /(?:^|\s)(?:"([^"]+\.(?:py|ts|tsx|js|jsx|go|rs|rb|cs|java|cpp|cc|cxx|c|h|sh|bash))"|('([^']+\.(?:py|ts|tsx|js|jsx|go|rs|rb|cs|java|cpp|cc|cxx|c|h|sh|bash))')|([^\s"']+\.(?:py|ts|tsx|js|jsx|go|rs|rb|cs|java|cpp|cc|cxx|c|h|sh|bash)))\s*$/.exec(cmd);
|
|
12628
13207
|
if (!fileMatch) return null;
|
|
@@ -12631,6 +13210,37 @@ function extractRgStructuralSearch(cmd) {
|
|
|
12631
13210
|
if (isTempPath(filePath)) return null;
|
|
12632
13211
|
return { filePath };
|
|
12633
13212
|
}
|
|
13213
|
+
function extractGrepPipeChain(cmd) {
|
|
13214
|
+
return /^(?:rg|grep)\b.*\|\s*(?:rg|grep)\b/.test(cmd);
|
|
13215
|
+
}
|
|
13216
|
+
function extractCurlUrl(cmd) {
|
|
13217
|
+
const m = /(https?:\/\/[^\s'"]+)/.exec(cmd);
|
|
13218
|
+
return m?.[1] ?? null;
|
|
13219
|
+
}
|
|
13220
|
+
function isCurlGetCommand(cmd) {
|
|
13221
|
+
if (!/^curl\b/.test(cmd)) return false;
|
|
13222
|
+
if (/-X\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return false;
|
|
13223
|
+
if (/--request\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return false;
|
|
13224
|
+
if (/\s(?:-d|--data(?:-raw|-binary|-urlencode)?|-F|--form)\b/.test(cmd)) return false;
|
|
13225
|
+
if (/\s(?:-u|--user)\b/.test(cmd)) return false;
|
|
13226
|
+
if (/-H\s+['"]?Authorization/i.test(cmd)) return false;
|
|
13227
|
+
return true;
|
|
13228
|
+
}
|
|
13229
|
+
function extractCurlDownload(cmd) {
|
|
13230
|
+
if (!/^curl\b/.test(cmd)) return null;
|
|
13231
|
+
const outputMatch = /(?:^|\s)(?:-o|--output)\s+(?:"([^"]+)"|'([^']+)'|(\S+))/.exec(cmd);
|
|
13232
|
+
if (!outputMatch) return null;
|
|
13233
|
+
const outputPath = outputMatch[1] ?? outputMatch[2] ?? outputMatch[3];
|
|
13234
|
+
if (!outputPath) return null;
|
|
13235
|
+
if (/-X\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return null;
|
|
13236
|
+
if (/--request\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return null;
|
|
13237
|
+
if (/(?:^|\s)(?:-d|--data(?:-raw|-binary|-urlencode)?|-F|--form)\b/.test(cmd)) return null;
|
|
13238
|
+
if (/(?:^|\s)(?:-u|--user)\b/.test(cmd)) return null;
|
|
13239
|
+
if (/-H\s+['"]?Authorization/i.test(cmd)) return null;
|
|
13240
|
+
const urlMatch = /(https?:\/\/[^\s'"]+)/.exec(cmd);
|
|
13241
|
+
if (!urlMatch?.[1]) return null;
|
|
13242
|
+
return { url: urlMatch[1], outputPath };
|
|
13243
|
+
}
|
|
12634
13244
|
function isTscCommand(cmd) {
|
|
12635
13245
|
return /^\s*tsc(\s|$)/i.test(cmd);
|
|
12636
13246
|
}
|
|
@@ -12648,28 +13258,88 @@ function buildRecallHint(cmd, outputId) {
|
|
|
12648
13258
|
return "Output from a prior `" + cmdPreview + "` run is cached. Use `token-goat bash-output " + outputId + "` (or `--tail 50`, `--grep ERROR`) to re-inspect it without re-running.";
|
|
12649
13259
|
}
|
|
12650
13260
|
function preBashHandler(event) {
|
|
12651
|
-
const
|
|
12652
|
-
if (
|
|
13261
|
+
const rawCmd = extractCommand(event);
|
|
13262
|
+
if (rawCmd === void 0) return passOutput();
|
|
13263
|
+
const cmd = stripCdPrefix(rawCmd);
|
|
13264
|
+
const cdStripped = cmd !== rawCmd;
|
|
13265
|
+
const taskOutput = extractTasksOutput(cmd);
|
|
13266
|
+
if (taskOutput !== null) {
|
|
13267
|
+
const { id } = taskOutput;
|
|
13268
|
+
recordStat("session_hint", 0, 0);
|
|
13269
|
+
return denyOutput(
|
|
13270
|
+
"Use `token-goat bash-output " + id + "` to recall this task output (already cached). Append `--tail <n>` or `--grep PATTERN` to slice it."
|
|
13271
|
+
);
|
|
13272
|
+
}
|
|
13273
|
+
const findResult = extractFindCommand(cmd);
|
|
13274
|
+
if (findResult !== null) {
|
|
13275
|
+
const { extGlob, isXargsGrepL } = findResult;
|
|
13276
|
+
recordStat("session_hint", 0, 0);
|
|
13277
|
+
if (isXargsGrepL) {
|
|
13278
|
+
return denyOutput(
|
|
13279
|
+
"`find | xargs grep -l` is a slow symbol search. Use `token-goat refs <symbol>` or `rg -l <symbol>` for faster symbol-file discovery."
|
|
13280
|
+
);
|
|
13281
|
+
}
|
|
13282
|
+
const fdHint = extGlob ? "Use `fd '" + extGlob + "'` for faster file discovery (respects .gitignore)." : "Use `fd` for faster file discovery (respects .gitignore).";
|
|
13283
|
+
return contextOutput(
|
|
13284
|
+
"`find` is slow and ignores .gitignore. " + fdHint + " For symbol definitions, use `token-goat symbol <Name>`."
|
|
13285
|
+
);
|
|
13286
|
+
}
|
|
13287
|
+
if (extractDirectoryListing(cmd)) {
|
|
13288
|
+
recordStat("session_hint", 0, 0);
|
|
13289
|
+
return contextOutput(
|
|
13290
|
+
"Use `token-goat map --compact` (~300 tokens) for a repo overview, or `token-goat map <dir>` for a subdirectory."
|
|
13291
|
+
);
|
|
13292
|
+
}
|
|
13293
|
+
if (extractForLoopWcL(cmd)) {
|
|
13294
|
+
recordStat("session_hint", 0, 0);
|
|
13295
|
+
return contextOutput(
|
|
13296
|
+
"Use `token-goat outline <file>` to see symbol names and line counts without loading files."
|
|
13297
|
+
);
|
|
13298
|
+
}
|
|
13299
|
+
if (extractSedLineRange(cmd)) {
|
|
13300
|
+
recordStat("session_hint", 0, 0);
|
|
13301
|
+
return contextOutput(
|
|
13302
|
+
'Use `token-goat section "<file>::HeadingName"` to read one section instead of a line range.'
|
|
13303
|
+
);
|
|
13304
|
+
}
|
|
13305
|
+
const catJsonPipe = extractCatJsonPipe(cmd);
|
|
13306
|
+
if (catJsonPipe !== null) {
|
|
13307
|
+
const { filePath } = catJsonPipe;
|
|
13308
|
+
recordStat("session_hint", 0, 0);
|
|
13309
|
+
return contextOutput(
|
|
13310
|
+
'`cat | jq` loads the whole file. Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to slice one value.'
|
|
13311
|
+
);
|
|
13312
|
+
}
|
|
12653
13313
|
const catResult = extractCatFile(cmd);
|
|
12654
13314
|
if (catResult !== null) {
|
|
12655
|
-
const { filePath, isDoc, isEnv, isConfig } = catResult;
|
|
12656
|
-
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13315
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = catResult;
|
|
12657
13316
|
recordStat("session_hint", 0, 0);
|
|
12658
|
-
|
|
13317
|
+
if (isSql) {
|
|
13318
|
+
return contextOutput(
|
|
13319
|
+
'`cat` loads the entire file into context. Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
13320
|
+
);
|
|
13321
|
+
}
|
|
13322
|
+
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13323
|
+
return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
|
|
12659
13324
|
}
|
|
12660
13325
|
const wslCatResult = extractWslCatFile(cmd);
|
|
12661
13326
|
if (wslCatResult !== null) {
|
|
12662
|
-
const { filePath, isDoc, isEnv, isConfig } = wslCatResult;
|
|
12663
|
-
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13327
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = wslCatResult;
|
|
12664
13328
|
recordStat("session_hint", 0, 0);
|
|
12665
|
-
|
|
13329
|
+
if (isSql) {
|
|
13330
|
+
return contextOutput(
|
|
13331
|
+
'`cat` loads the entire file into context. Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
13332
|
+
);
|
|
13333
|
+
}
|
|
13334
|
+
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13335
|
+
return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
|
|
12666
13336
|
}
|
|
12667
13337
|
const pyRead = extractPythonFileRead(cmd);
|
|
12668
13338
|
if (pyRead !== null) {
|
|
12669
13339
|
const { filePath, isDoc } = pyRead;
|
|
12670
13340
|
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
12671
13341
|
recordStat("session_hint", 0, 0);
|
|
12672
|
-
return denyOutput("Python `open()` file reads bypass read hooks. " + hint);
|
|
13342
|
+
return cdStripped ? contextOutput("Python `open()` file reads bypass read hooks. " + hint) : denyOutput("Python `open()` file reads bypass read hooks. " + hint);
|
|
12673
13343
|
}
|
|
12674
13344
|
const tailResult = extractTailFile(cmd);
|
|
12675
13345
|
if (tailResult !== null) {
|
|
@@ -12687,10 +13357,32 @@ function preBashHandler(event) {
|
|
|
12687
13357
|
}
|
|
12688
13358
|
const nodeRead = extractNodeFileRead(cmd);
|
|
12689
13359
|
if (nodeRead !== null) {
|
|
12690
|
-
const { filePath, isDoc } = nodeRead;
|
|
12691
|
-
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
13360
|
+
const { filePath, isDoc, isConfig } = nodeRead;
|
|
13361
|
+
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
12692
13362
|
recordStat("session_hint", 0, 0);
|
|
12693
|
-
return denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
|
|
13363
|
+
return cdStripped ? contextOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint) : denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
|
|
13364
|
+
}
|
|
13365
|
+
if (extractGrepPipeChain(cmd)) {
|
|
13366
|
+
recordStat("session_hint", 0, 0);
|
|
13367
|
+
return contextOutput(
|
|
13368
|
+
"Collapse `grep | grep` into `rg -e PAT1 -e PAT2` (single pass). For symbol discovery: `token-goat refs <symbol>` or `token-goat semantic`."
|
|
13369
|
+
);
|
|
13370
|
+
}
|
|
13371
|
+
const mdHeadingGrep = extractMarkdownHeadingGrep(cmd);
|
|
13372
|
+
if (mdHeadingGrep !== null) {
|
|
13373
|
+
const { filePath } = mdHeadingGrep;
|
|
13374
|
+
recordStat("session_hint", 0, 0);
|
|
13375
|
+
return contextOutput(
|
|
13376
|
+
'Use `token-goat outline "' + filePath + '"` to get all headings with line ranges \u2014 then `token-goat section "' + filePath + '::Heading"` to read one section.'
|
|
13377
|
+
);
|
|
13378
|
+
}
|
|
13379
|
+
const rgSymbol = extractRgSymbolSearch(cmd);
|
|
13380
|
+
if (rgSymbol !== null) {
|
|
13381
|
+
const { identifier } = rgSymbol;
|
|
13382
|
+
recordStat("session_hint", 0, 0);
|
|
13383
|
+
return contextOutput(
|
|
13384
|
+
"Use `token-goat symbol " + identifier + "` to jump directly to the definition without scanning the file."
|
|
13385
|
+
);
|
|
12694
13386
|
}
|
|
12695
13387
|
const rgStructural = extractRgStructuralSearch(cmd);
|
|
12696
13388
|
if (rgStructural !== null) {
|
|
@@ -12702,7 +13394,7 @@ function preBashHandler(event) {
|
|
|
12702
13394
|
}
|
|
12703
13395
|
const monitoringHint = getMonitoringRecallHint(cmd);
|
|
12704
13396
|
if (monitoringHint !== null) {
|
|
12705
|
-
const monCmdHash =
|
|
13397
|
+
const monCmdHash = shortFingerprint(cmd);
|
|
12706
13398
|
const monOutputId = getBashOutputId(monCmdHash);
|
|
12707
13399
|
if (monOutputId !== null) {
|
|
12708
13400
|
const monEntry = getBashOutput(monOutputId);
|
|
@@ -12721,8 +13413,32 @@ function preBashHandler(event) {
|
|
|
12721
13413
|
);
|
|
12722
13414
|
}
|
|
12723
13415
|
}
|
|
13416
|
+
const curlDl = extractCurlDownload(cmd);
|
|
13417
|
+
if (curlDl !== null) {
|
|
13418
|
+
const prevPath = getCurlDownloadPath(curlDl.url);
|
|
13419
|
+
if (prevPath !== null) {
|
|
13420
|
+
recordStat("session_hint", 0, 0);
|
|
13421
|
+
return denyOutput(
|
|
13422
|
+
"Already downloaded to " + prevPath + " earlier this session. Use `rg '<pattern>' " + prevPath + '` to search it, or `token-goat read "' + prevPath + '::SectionName"` to read a part of it.'
|
|
13423
|
+
);
|
|
13424
|
+
}
|
|
13425
|
+
}
|
|
13426
|
+
if (isCurlGetCommand(cmd)) {
|
|
13427
|
+
const curlCacheKey = extractCurlUrl(cmd) ?? cmd;
|
|
13428
|
+
const curlHash = shortFingerprint(curlCacheKey);
|
|
13429
|
+
const curlOutputId = getBashOutputId(curlHash);
|
|
13430
|
+
if (curlOutputId !== null) {
|
|
13431
|
+
const curlEntry = getBashOutput(curlOutputId);
|
|
13432
|
+
const curlBytes = curlEntry?.sizeBytes ?? 0;
|
|
13433
|
+
recordStat("bash_compress:recall", curlBytes, Math.round(curlBytes / 4));
|
|
13434
|
+
const curlPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
13435
|
+
return contextOutput(
|
|
13436
|
+
"curl response cached (`" + curlPreview + "`). Use `token-goat bash-output " + curlOutputId + "` to recall it. Append `--grep PATTERN` to filter or `--section HeadingName` for a markdown section."
|
|
13437
|
+
);
|
|
13438
|
+
}
|
|
13439
|
+
}
|
|
12724
13440
|
if (!isBuildCommand(cmd)) return passOutput();
|
|
12725
|
-
const cmdHash =
|
|
13441
|
+
const cmdHash = shortFingerprint(cmd);
|
|
12726
13442
|
const outputId = getBashOutputId(cmdHash);
|
|
12727
13443
|
if (outputId === null) return passOutput();
|
|
12728
13444
|
const entry = getBashOutput(outputId);
|
|
@@ -12745,14 +13461,20 @@ function extractBashOutput(raw) {
|
|
|
12745
13461
|
}
|
|
12746
13462
|
async function postBashHandler(event) {
|
|
12747
13463
|
try {
|
|
12748
|
-
const
|
|
12749
|
-
if (
|
|
13464
|
+
const rawCmd = extractCommand(event);
|
|
13465
|
+
if (rawCmd === void 0) return passOutput();
|
|
13466
|
+
const cmd = stripCdPrefix(rawCmd);
|
|
13467
|
+
const curlDl = extractCurlDownload(cmd);
|
|
13468
|
+
if (curlDl !== null) {
|
|
13469
|
+
recordCurlDownload(curlDl.url, curlDl.outputPath);
|
|
13470
|
+
}
|
|
12750
13471
|
const isMonitoring = getMonitoringRecallHint(cmd) !== null;
|
|
12751
|
-
if (!isMonitoring && !isBuildCommand(cmd)) return passOutput();
|
|
13472
|
+
if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) return passOutput();
|
|
12752
13473
|
const output = extractBashOutput(event.raw);
|
|
12753
13474
|
if (Buffer.byteLength(output, "utf-8") < MIN_CACHE_BYTES) return passOutput();
|
|
12754
13475
|
const cwd = typeof event.raw["cwd"] === "string" ? event.raw["cwd"] : null;
|
|
12755
|
-
const
|
|
13476
|
+
const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : cmd;
|
|
13477
|
+
const simpleHash = shortFingerprint(cacheKey);
|
|
12756
13478
|
const id = await storeBashOutput(cmd, output, 0, cwd);
|
|
12757
13479
|
recordBashOutput(simpleHash, id, Buffer.byteLength(output, "utf-8"));
|
|
12758
13480
|
} catch {
|
|
@@ -12763,8 +13485,8 @@ registerHook("post_tool_use", postBashHandler, { toolName: "Bash" });
|
|
|
12763
13485
|
|
|
12764
13486
|
// src/image_shrink.ts
|
|
12765
13487
|
init_define_import_meta_env();
|
|
12766
|
-
import * as
|
|
12767
|
-
import * as
|
|
13488
|
+
import * as fs9 from "node:fs";
|
|
13489
|
+
import * as path12 from "node:path";
|
|
12768
13490
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12769
13491
|
".png",
|
|
12770
13492
|
".jpg",
|
|
@@ -12791,7 +13513,7 @@ async function loadSharp() {
|
|
|
12791
13513
|
return _sharpCache;
|
|
12792
13514
|
}
|
|
12793
13515
|
function isImagePath(p) {
|
|
12794
|
-
return IMAGE_EXTENSIONS.has(
|
|
13516
|
+
return IMAGE_EXTENSIONS.has(path12.extname(p).toLowerCase());
|
|
12795
13517
|
}
|
|
12796
13518
|
async function shrinkImage(input, opts) {
|
|
12797
13519
|
const maxDimension = opts?.maxDimension ?? DEFAULT_MAX_DIMENSION;
|
|
@@ -12823,7 +13545,7 @@ async function shrinkImage(input, opts) {
|
|
|
12823
13545
|
}
|
|
12824
13546
|
function statSize2(absPath) {
|
|
12825
13547
|
try {
|
|
12826
|
-
const st =
|
|
13548
|
+
const st = fs9.statSync(absPath);
|
|
12827
13549
|
return st.isFile() ? st.size : null;
|
|
12828
13550
|
} catch {
|
|
12829
13551
|
return null;
|
|
@@ -12837,7 +13559,7 @@ async function preReadImageHandler(event) {
|
|
|
12837
13559
|
if (size === null || size < DEFAULT_SIZE_THRESHOLD_BYTES) return passOutput();
|
|
12838
13560
|
let input;
|
|
12839
13561
|
try {
|
|
12840
|
-
input =
|
|
13562
|
+
input = fs9.readFileSync(filePath);
|
|
12841
13563
|
} catch {
|
|
12842
13564
|
return passOutput();
|
|
12843
13565
|
}
|
|
@@ -12846,7 +13568,7 @@ async function preReadImageHandler(event) {
|
|
|
12846
13568
|
const saved = result.originalBytes - result.shrunkBytes;
|
|
12847
13569
|
const pct = Math.round(saved / result.originalBytes * 100);
|
|
12848
13570
|
const dataUrl = `data:image/${result.format};base64,${result.data.toString("base64")}`;
|
|
12849
|
-
const summary = `token-goat shrank ${
|
|
13571
|
+
const summary = `token-goat shrank ${path12.basename(filePath)}: ${Math.round(result.originalBytes / 1024)}kb -> ${Math.round(result.shrunkBytes / 1024)}kb (${pct}% smaller, ${result.width}x${result.height} ${result.format}).`;
|
|
12850
13572
|
return contextOutput(`${summary}
|
|
12851
13573
|
${dataUrl}`);
|
|
12852
13574
|
}
|
|
@@ -12925,7 +13647,7 @@ async function relay(eventName) {
|
|
|
12925
13647
|
|
|
12926
13648
|
// src/section_reader.ts
|
|
12927
13649
|
init_define_import_meta_env();
|
|
12928
|
-
import { readFileSync as
|
|
13650
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
12929
13651
|
function parseHeadingSpec(spec) {
|
|
12930
13652
|
const m = /^(.*?)#(\d+)$/.exec(spec);
|
|
12931
13653
|
if (m !== null && m[1] !== void 0 && m[2] !== void 0) {
|
|
@@ -12933,6 +13655,18 @@ function parseHeadingSpec(spec) {
|
|
|
12933
13655
|
}
|
|
12934
13656
|
return { base: spec.trim(), ordinal: null };
|
|
12935
13657
|
}
|
|
13658
|
+
function normalizeHeading(s) {
|
|
13659
|
+
let n = s.replace(/[—–]/g, "-");
|
|
13660
|
+
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
13661
|
+
n = n.replace(/^\d+\.\s+/, "");
|
|
13662
|
+
return n.replace(/\s+/g, " ").trim();
|
|
13663
|
+
}
|
|
13664
|
+
function normalizeHeadingStrip(s) {
|
|
13665
|
+
let n = s.replace(/\s*[—–].*$/, "");
|
|
13666
|
+
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
13667
|
+
n = n.replace(/^\d+\.\s+/, "");
|
|
13668
|
+
return n.replace(/\s+/g, " ").trim();
|
|
13669
|
+
}
|
|
12936
13670
|
var MARKDOWN_HEADER_RE = /^(#{1,6})\s+(.+?)\s*#*\s*$/;
|
|
12937
13671
|
var TABLE_HEADER_RE = /^\s*\[+\s*([^\]]+?)\s*\]+\s*$/;
|
|
12938
13672
|
var PYTHON_HEADER_RE = /^(\s*)(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)/;
|
|
@@ -13007,7 +13741,7 @@ function sectionEndIndex(headers, headerPos, totalLines) {
|
|
|
13007
13741
|
function readSection(filePath, headingSpec) {
|
|
13008
13742
|
let text;
|
|
13009
13743
|
try {
|
|
13010
|
-
text =
|
|
13744
|
+
text = readFileSync6(filePath, "utf-8");
|
|
13011
13745
|
} catch {
|
|
13012
13746
|
return null;
|
|
13013
13747
|
}
|
|
@@ -13017,10 +13751,15 @@ function readSection(filePath, headingSpec) {
|
|
|
13017
13751
|
const headers = findHeaders(text, language);
|
|
13018
13752
|
const lines = text.split("\n");
|
|
13019
13753
|
const target = base.toLowerCase();
|
|
13754
|
+
const normalizedTarget = normalizeHeading(base).toLowerCase();
|
|
13755
|
+
const strippedTarget = normalizeHeadingStrip(base).toLowerCase();
|
|
13020
13756
|
const matches = [];
|
|
13021
13757
|
for (let i = 0; i < headers.length; i++) {
|
|
13022
13758
|
const h = headers[i];
|
|
13023
|
-
if (h
|
|
13759
|
+
if (h === void 0) continue;
|
|
13760
|
+
if (h.heading.toLowerCase() === target || normalizeHeading(h.heading).toLowerCase() === normalizedTarget || normalizeHeadingStrip(h.heading).toLowerCase() === strippedTarget) {
|
|
13761
|
+
matches.push(i);
|
|
13762
|
+
}
|
|
13024
13763
|
}
|
|
13025
13764
|
if (matches.length === 0) return null;
|
|
13026
13765
|
const pick = ordinal === null ? 0 : ordinal - 1;
|
|
@@ -13044,9 +13783,9 @@ function readSection(filePath, headingSpec) {
|
|
|
13044
13783
|
|
|
13045
13784
|
// src/install.ts
|
|
13046
13785
|
init_define_import_meta_env();
|
|
13047
|
-
import * as
|
|
13048
|
-
import * as
|
|
13049
|
-
import * as
|
|
13786
|
+
import * as fs10 from "node:fs";
|
|
13787
|
+
import * as os3 from "node:os";
|
|
13788
|
+
import * as path13 from "node:path";
|
|
13050
13789
|
var HOOK_EVENT_MAP = [
|
|
13051
13790
|
["PreToolUse", "pre_tool_use"],
|
|
13052
13791
|
["PostToolUse", "post_tool_use"],
|
|
@@ -13057,13 +13796,13 @@ function hookCommand(eventArg) {
|
|
|
13057
13796
|
return `token-goat hook ${eventArg}`;
|
|
13058
13797
|
}
|
|
13059
13798
|
function settingsPath(scope) {
|
|
13060
|
-
const base = scope === "user" ?
|
|
13061
|
-
return
|
|
13799
|
+
const base = scope === "user" ? path13.join(os3.homedir(), ".claude") : path13.join(process.cwd(), ".claude");
|
|
13800
|
+
return path13.join(base, "settings.json");
|
|
13062
13801
|
}
|
|
13063
13802
|
function readSettings(p) {
|
|
13064
13803
|
let raw;
|
|
13065
13804
|
try {
|
|
13066
|
-
raw =
|
|
13805
|
+
raw = fs10.readFileSync(p, "utf8");
|
|
13067
13806
|
} catch {
|
|
13068
13807
|
return {};
|
|
13069
13808
|
}
|
|
@@ -13103,7 +13842,7 @@ function installHooks(scope = "user") {
|
|
|
13103
13842
|
return { scope, settingsPath: p, alreadyInstalled: true };
|
|
13104
13843
|
}
|
|
13105
13844
|
settings.hooks = hooks;
|
|
13106
|
-
|
|
13845
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
13107
13846
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
13108
13847
|
`);
|
|
13109
13848
|
return { scope, settingsPath: p, alreadyInstalled: false };
|
|
@@ -13142,7 +13881,7 @@ function uninstallHooks(scope = "user") {
|
|
|
13142
13881
|
} else {
|
|
13143
13882
|
settings.hooks = hooks;
|
|
13144
13883
|
}
|
|
13145
|
-
|
|
13884
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
13146
13885
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
13147
13886
|
`);
|
|
13148
13887
|
return true;
|
|
@@ -13151,21 +13890,21 @@ function uninstallHooks(scope = "user") {
|
|
|
13151
13890
|
// src/worker.ts
|
|
13152
13891
|
init_define_import_meta_env();
|
|
13153
13892
|
import { spawn } from "node:child_process";
|
|
13154
|
-
import * as
|
|
13155
|
-
import * as
|
|
13893
|
+
import * as fs11 from "node:fs";
|
|
13894
|
+
import * as path14 from "node:path";
|
|
13156
13895
|
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
|
|
13157
13896
|
import { fileURLToPath } from "node:url";
|
|
13158
13897
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
13159
13898
|
function dirtyQueuePathFor(dir) {
|
|
13160
|
-
return
|
|
13899
|
+
return path14.join(dir, "queue", "dirty.txt");
|
|
13161
13900
|
}
|
|
13162
13901
|
function workerPidPath(dir = dataDir()) {
|
|
13163
|
-
return
|
|
13902
|
+
return path14.join(dir, "worker.pid");
|
|
13164
13903
|
}
|
|
13165
13904
|
function getDirtyPathsFor(dir) {
|
|
13166
13905
|
let raw;
|
|
13167
13906
|
try {
|
|
13168
|
-
raw =
|
|
13907
|
+
raw = fs11.readFileSync(dirtyQueuePathFor(dir), "utf8");
|
|
13169
13908
|
} catch {
|
|
13170
13909
|
return [];
|
|
13171
13910
|
}
|
|
@@ -13181,7 +13920,7 @@ function getDirtyPathsFor(dir) {
|
|
|
13181
13920
|
}
|
|
13182
13921
|
function clearDirtyQueueFor(dir) {
|
|
13183
13922
|
try {
|
|
13184
|
-
|
|
13923
|
+
fs11.rmSync(dirtyQueuePathFor(dir), { force: true });
|
|
13185
13924
|
} catch {
|
|
13186
13925
|
}
|
|
13187
13926
|
}
|
|
@@ -13191,7 +13930,7 @@ function processDirtyBatch(paths, index = (absPath) => {
|
|
|
13191
13930
|
}) {
|
|
13192
13931
|
let indexed = 0;
|
|
13193
13932
|
for (const p of paths) {
|
|
13194
|
-
if (!
|
|
13933
|
+
if (!p || !fs11.existsSync(p)) continue;
|
|
13195
13934
|
const sha = fingerprintFile(p);
|
|
13196
13935
|
if (sha === null) continue;
|
|
13197
13936
|
index(p, sha);
|
|
@@ -13216,7 +13955,7 @@ function pidAlive(pid) {
|
|
|
13216
13955
|
}
|
|
13217
13956
|
function readPidFile(dir) {
|
|
13218
13957
|
try {
|
|
13219
|
-
const raw =
|
|
13958
|
+
const raw = fs11.readFileSync(workerPidPath(dir), "utf8").trim();
|
|
13220
13959
|
if (!/^\d+$/.test(raw)) return null;
|
|
13221
13960
|
return parseInt(raw, 10);
|
|
13222
13961
|
} catch {
|
|
@@ -13239,7 +13978,7 @@ function stopWorker(dir = dataDir()) {
|
|
|
13239
13978
|
}
|
|
13240
13979
|
}
|
|
13241
13980
|
try {
|
|
13242
|
-
|
|
13981
|
+
fs11.rmSync(workerPidPath(dir), { force: true });
|
|
13243
13982
|
} catch {
|
|
13244
13983
|
}
|
|
13245
13984
|
return alive;
|
|
@@ -13247,7 +13986,11 @@ function stopWorker(dir = dataDir()) {
|
|
|
13247
13986
|
function startDetachedWorker(opts) {
|
|
13248
13987
|
const pollIntervalMs = opts?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
13249
13988
|
const dir = opts?.dataDir ?? dataDir();
|
|
13250
|
-
|
|
13989
|
+
try {
|
|
13990
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13991
|
+
} catch (e) {
|
|
13992
|
+
if (e.code !== "EEXIST" || !fs11.existsSync(dir)) throw e;
|
|
13993
|
+
}
|
|
13251
13994
|
const child = spawn(
|
|
13252
13995
|
process.execPath,
|
|
13253
13996
|
[fileURLToPath(import.meta.url), "--worker-daemon"],
|
|
@@ -13266,7 +14009,7 @@ function startDetachedWorker(opts) {
|
|
|
13266
14009
|
if (pid === void 0) {
|
|
13267
14010
|
throw new Error("startDetachedWorker: spawn produced no pid");
|
|
13268
14011
|
}
|
|
13269
|
-
|
|
14012
|
+
fs11.writeFileSync(workerPidPath(dir), `${pid}
|
|
13270
14013
|
`);
|
|
13271
14014
|
child.unref();
|
|
13272
14015
|
return pid;
|
|
@@ -13309,7 +14052,7 @@ workerEntry();
|
|
|
13309
14052
|
|
|
13310
14053
|
// src/skill_cache.ts
|
|
13311
14054
|
init_define_import_meta_env();
|
|
13312
|
-
import * as
|
|
14055
|
+
import * as fs12 from "fs/promises";
|
|
13313
14056
|
import { resolve as resolve4 } from "path";
|
|
13314
14057
|
var COMPACT_END_MARKER = "<!-- COMPACT_END -->";
|
|
13315
14058
|
var _skillOutputsDirOverride = null;
|
|
@@ -13322,7 +14065,7 @@ function skillOutputsDir() {
|
|
|
13322
14065
|
}
|
|
13323
14066
|
async function ensureSkillsDir() {
|
|
13324
14067
|
try {
|
|
13325
|
-
await
|
|
14068
|
+
await fs12.mkdir(skillOutputsDir(), { recursive: true });
|
|
13326
14069
|
} catch {
|
|
13327
14070
|
}
|
|
13328
14071
|
}
|
|
@@ -13349,7 +14092,7 @@ function extractCompactFromMarker(body) {
|
|
|
13349
14092
|
const lines = body.split("\n");
|
|
13350
14093
|
for (let i = 0; i < lines.length; i++) {
|
|
13351
14094
|
const stripped = lines[i].trim();
|
|
13352
|
-
if (
|
|
14095
|
+
if (isCodeFenceDelimiter(stripped)) {
|
|
13353
14096
|
inCodeBlock = !inCodeBlock;
|
|
13354
14097
|
continue;
|
|
13355
14098
|
}
|
|
@@ -13364,14 +14107,14 @@ function extractCompactFromMarker(body) {
|
|
|
13364
14107
|
async function listOutputs() {
|
|
13365
14108
|
try {
|
|
13366
14109
|
const dir = skillOutputsDir();
|
|
13367
|
-
const entries = await
|
|
14110
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
13368
14111
|
const metas = [];
|
|
13369
14112
|
for (const entry of entries) {
|
|
13370
14113
|
if (!entry.isFile() || !entry.name.endsWith(".meta")) {
|
|
13371
14114
|
continue;
|
|
13372
14115
|
}
|
|
13373
14116
|
try {
|
|
13374
|
-
const content = await
|
|
14117
|
+
const content = await fs12.readFile(resolve4(dir, entry.name), "utf-8");
|
|
13375
14118
|
const meta = JSON.parse(content);
|
|
13376
14119
|
metas.push(meta);
|
|
13377
14120
|
} catch {
|
|
@@ -13416,13 +14159,13 @@ async function listSkills(sessionId) {
|
|
|
13416
14159
|
const compactFileId = `${safeSession}-${meta.skillName.replace(":", "_")}-compact`;
|
|
13417
14160
|
let compactLen = 0;
|
|
13418
14161
|
try {
|
|
13419
|
-
const stat3 = await
|
|
14162
|
+
const stat3 = await fs12.stat(resolve4(dir, compactFileId));
|
|
13420
14163
|
compactLen = stat3.size;
|
|
13421
14164
|
} catch {
|
|
13422
14165
|
compactLen = 0;
|
|
13423
14166
|
}
|
|
13424
14167
|
const hasMarker = extractCompactFromMarker(
|
|
13425
|
-
await
|
|
14168
|
+
await fs12.readFile(resolve4(dir, `${meta.outputId}.txt`), "utf-8").catch(() => "")
|
|
13426
14169
|
) !== null;
|
|
13427
14170
|
results.push({
|
|
13428
14171
|
name: meta.skillName,
|
|
@@ -13454,7 +14197,7 @@ async function getSkillFilePath(skillName) {
|
|
|
13454
14197
|
|
|
13455
14198
|
// src/config.ts
|
|
13456
14199
|
init_define_import_meta_env();
|
|
13457
|
-
import * as
|
|
14200
|
+
import * as fs13 from "node:fs";
|
|
13458
14201
|
|
|
13459
14202
|
// node_modules/smol-toml/dist/index.js
|
|
13460
14203
|
init_define_import_meta_env();
|
|
@@ -14186,8 +14929,8 @@ function envInt(key, defaultVal) {
|
|
|
14186
14929
|
}
|
|
14187
14930
|
|
|
14188
14931
|
// src/config.ts
|
|
14189
|
-
|
|
14190
|
-
|
|
14932
|
+
var CONFIG_DEFAULTS = {
|
|
14933
|
+
compact_assist: {
|
|
14191
14934
|
enabled: true,
|
|
14192
14935
|
triggers: ["manual", "auto"],
|
|
14193
14936
|
min_events: 3,
|
|
@@ -14202,10 +14945,8 @@ function defaultCompactAssistConfig() {
|
|
|
14202
14945
|
lazy_skill_injection: true,
|
|
14203
14946
|
max_manifest_chars: 1600,
|
|
14204
14947
|
harness: "auto"
|
|
14205
|
-
}
|
|
14206
|
-
|
|
14207
|
-
function defaultBashCompressConfig() {
|
|
14208
|
-
return {
|
|
14948
|
+
},
|
|
14949
|
+
bash_compress: {
|
|
14209
14950
|
enabled: true,
|
|
14210
14951
|
disabled_filters: [],
|
|
14211
14952
|
max_lines: 1e3,
|
|
@@ -14215,32 +14956,22 @@ function defaultBashCompressConfig() {
|
|
|
14215
14956
|
cache_max_file_count: 4096,
|
|
14216
14957
|
cache_max_bytes: 16 * 1024 * 1024,
|
|
14217
14958
|
cache_max_bytes_per_output: 50 * 1024 * 1024
|
|
14218
|
-
}
|
|
14219
|
-
|
|
14220
|
-
function defaultBashDiffConfig() {
|
|
14221
|
-
return {
|
|
14959
|
+
},
|
|
14960
|
+
bash_diff: {
|
|
14222
14961
|
max_hunks_per_file: 10,
|
|
14223
14962
|
hunk_density_cap: true
|
|
14224
|
-
}
|
|
14225
|
-
|
|
14226
|
-
function defaultSeverityLogConfig() {
|
|
14227
|
-
return {
|
|
14963
|
+
},
|
|
14964
|
+
bash_severity_log: {
|
|
14228
14965
|
context_lines: 3,
|
|
14229
14966
|
score_threshold: 0.5
|
|
14230
|
-
}
|
|
14231
|
-
|
|
14232
|
-
function defaultCodeCompressConfig() {
|
|
14233
|
-
return {
|
|
14967
|
+
},
|
|
14968
|
+
post_read_code_compress: {
|
|
14234
14969
|
min_lines: 200
|
|
14235
|
-
}
|
|
14236
|
-
|
|
14237
|
-
function defaultSessionBriefConfig() {
|
|
14238
|
-
return {
|
|
14970
|
+
},
|
|
14971
|
+
session_brief: {
|
|
14239
14972
|
enabled: true
|
|
14240
|
-
}
|
|
14241
|
-
|
|
14242
|
-
function defaultSkillPreservationConfig() {
|
|
14243
|
-
return {
|
|
14973
|
+
},
|
|
14974
|
+
skill_preservation: {
|
|
14244
14975
|
enabled: true,
|
|
14245
14976
|
max_cache_bytes: 5 * 1024 * 1024,
|
|
14246
14977
|
orphan_sweep_enabled: true,
|
|
@@ -14252,25 +14983,19 @@ function defaultSkillPreservationConfig() {
|
|
|
14252
14983
|
pre_skill_enabled: true,
|
|
14253
14984
|
first_load_compact: false,
|
|
14254
14985
|
post_compact_full_loads: false
|
|
14255
|
-
}
|
|
14256
|
-
|
|
14257
|
-
function defaultCuratorConfig() {
|
|
14258
|
-
return {
|
|
14986
|
+
},
|
|
14987
|
+
curator: {
|
|
14259
14988
|
enabled: true,
|
|
14260
14989
|
min_samples: 10,
|
|
14261
14990
|
threshold_pct: 20
|
|
14262
|
-
}
|
|
14263
|
-
|
|
14264
|
-
function defaultHintBudgetConfig() {
|
|
14265
|
-
return {
|
|
14991
|
+
},
|
|
14992
|
+
hint_budget: {
|
|
14266
14993
|
enabled: true,
|
|
14267
14994
|
max_per_session: 100,
|
|
14268
14995
|
max_structured_per_session: 30,
|
|
14269
14996
|
max_index_only_per_session: 30
|
|
14270
|
-
}
|
|
14271
|
-
|
|
14272
|
-
function defaultImageShrinkConfig() {
|
|
14273
|
-
return {
|
|
14997
|
+
},
|
|
14998
|
+
image_shrink: {
|
|
14274
14999
|
prefer_avif: true,
|
|
14275
15000
|
avif_quality: 60,
|
|
14276
15001
|
jpeg_quality: 75,
|
|
@@ -14278,27 +15003,19 @@ function defaultImageShrinkConfig() {
|
|
|
14278
15003
|
orphan_sweep_enabled: true,
|
|
14279
15004
|
orphan_age_secs: 604800,
|
|
14280
15005
|
screenshot_redirect: true
|
|
14281
|
-
}
|
|
14282
|
-
|
|
14283
|
-
function defaultRepomapConfig() {
|
|
14284
|
-
return {
|
|
15006
|
+
},
|
|
15007
|
+
repomap: {
|
|
14285
15008
|
compact_file_threshold: 50,
|
|
14286
15009
|
exclude_tests: true
|
|
14287
|
-
}
|
|
14288
|
-
|
|
14289
|
-
function defaultOverflowGuardConfig() {
|
|
14290
|
-
return {
|
|
15010
|
+
},
|
|
15011
|
+
overflow_guard: {
|
|
14291
15012
|
enabled: true,
|
|
14292
15013
|
max_tokens: 25e3
|
|
14293
|
-
}
|
|
14294
|
-
|
|
14295
|
-
function defaultStatsConfig() {
|
|
14296
|
-
return {
|
|
15014
|
+
},
|
|
15015
|
+
stats: {
|
|
14297
15016
|
record_zero_savings: false
|
|
14298
|
-
}
|
|
14299
|
-
|
|
14300
|
-
function defaultHintsConfig() {
|
|
14301
|
-
return {
|
|
15017
|
+
},
|
|
15018
|
+
hints: {
|
|
14302
15019
|
suppress_after_ignored: 5,
|
|
14303
15020
|
quiet_hours: "",
|
|
14304
15021
|
json_sidecar: false,
|
|
@@ -14322,51 +15039,40 @@ function defaultHintsConfig() {
|
|
|
14322
15039
|
truncated_read_min_lines: 200,
|
|
14323
15040
|
protect_recent_reads: 4,
|
|
14324
15041
|
prompt_triggers: []
|
|
14325
|
-
}
|
|
14326
|
-
|
|
14327
|
-
function defaultHooksConfig() {
|
|
14328
|
-
return {
|
|
15042
|
+
},
|
|
15043
|
+
hooks: {
|
|
14329
15044
|
watchdog_ms: 700
|
|
14330
|
-
}
|
|
14331
|
-
|
|
14332
|
-
function defaultWebFetchConfig() {
|
|
14333
|
-
return {
|
|
15045
|
+
},
|
|
15046
|
+
webfetch: {
|
|
14334
15047
|
allow: [],
|
|
14335
15048
|
deny: [],
|
|
14336
15049
|
max_file_count: 4096,
|
|
14337
15050
|
max_bytes: 32 * 1024 * 1024,
|
|
14338
15051
|
compress_bodies: true,
|
|
14339
15052
|
compress_min_bytes: 16 * 1024
|
|
14340
|
-
}
|
|
14341
|
-
|
|
14342
|
-
function defaultWorkerConfig() {
|
|
14343
|
-
return {
|
|
15053
|
+
},
|
|
15054
|
+
worker: {
|
|
14344
15055
|
watchdog_enabled: true,
|
|
14345
15056
|
max_pool_workers: 4,
|
|
14346
15057
|
blocked_roots: []
|
|
14347
|
-
}
|
|
14348
|
-
|
|
14349
|
-
function defaultIndexingConfig() {
|
|
14350
|
-
return {
|
|
15058
|
+
},
|
|
15059
|
+
indexing: {
|
|
14351
15060
|
large_file_symbol_only_kb: 500,
|
|
14352
15061
|
large_file_skip_kb: 2048,
|
|
14353
15062
|
skip_dirs: []
|
|
14354
|
-
}
|
|
14355
|
-
|
|
14356
|
-
function defaultCompressionConfig() {
|
|
14357
|
-
return {
|
|
15063
|
+
},
|
|
15064
|
+
compression: {
|
|
14358
15065
|
profile: "auto"
|
|
14359
|
-
}
|
|
14360
|
-
|
|
14361
|
-
function defaultContextConfig() {
|
|
14362
|
-
return {
|
|
15066
|
+
},
|
|
15067
|
+
context: {
|
|
14363
15068
|
model_window_tokens: 2e5
|
|
14364
|
-
}
|
|
14365
|
-
|
|
14366
|
-
function defaultInjectionConfig() {
|
|
14367
|
-
return {
|
|
15069
|
+
},
|
|
15070
|
+
injection: {
|
|
14368
15071
|
enabled: true
|
|
14369
|
-
}
|
|
15072
|
+
}
|
|
15073
|
+
};
|
|
15074
|
+
function getDefaultConfig(section2) {
|
|
15075
|
+
return structuredClone(CONFIG_DEFAULTS[section2] ?? {});
|
|
14370
15076
|
}
|
|
14371
15077
|
function validatedBool(raw, def) {
|
|
14372
15078
|
if (typeof raw === "boolean") return raw;
|
|
@@ -14439,7 +15145,7 @@ function loadConfig() {
|
|
|
14439
15145
|
const p = configPath();
|
|
14440
15146
|
let currentMtime = 0;
|
|
14441
15147
|
try {
|
|
14442
|
-
currentMtime =
|
|
15148
|
+
currentMtime = fs13.statSync(p).mtimeMs;
|
|
14443
15149
|
} catch {
|
|
14444
15150
|
}
|
|
14445
15151
|
const envFp = configEnvFingerprint();
|
|
@@ -14449,7 +15155,7 @@ function loadConfig() {
|
|
|
14449
15155
|
let raw = {};
|
|
14450
15156
|
if (currentMtime !== 0) {
|
|
14451
15157
|
try {
|
|
14452
|
-
const text =
|
|
15158
|
+
const text = fs13.readFileSync(p, "utf8");
|
|
14453
15159
|
raw = parse(text);
|
|
14454
15160
|
} catch {
|
|
14455
15161
|
}
|
|
@@ -14460,7 +15166,7 @@ function loadConfig() {
|
|
|
14460
15166
|
}
|
|
14461
15167
|
function _buildConfig(raw) {
|
|
14462
15168
|
const ca_raw = section(raw, "compact_assist");
|
|
14463
|
-
const ca =
|
|
15169
|
+
const ca = getDefaultConfig("compact_assist");
|
|
14464
15170
|
ca.enabled = validatedBool(ca_raw["enabled"], ca.enabled);
|
|
14465
15171
|
ca.triggers = validatedStrList(ca_raw["triggers"], ca.triggers);
|
|
14466
15172
|
ca.min_events = validatedInt(ca_raw["min_events"], ca.min_events, 0, 1e3);
|
|
@@ -14478,7 +15184,7 @@ function _buildConfig(raw) {
|
|
|
14478
15184
|
ca.enabled = envBool("TOKEN_GOAT_COMPACT_ASSIST", envBool("TOKENWISE_COMPACT_ASSIST", ca.enabled));
|
|
14479
15185
|
ca.lazy_skill_injection = envBool("TOKEN_GOAT_LAZY_SKILL_INJECTION", ca.lazy_skill_injection);
|
|
14480
15186
|
const bc_raw = section(raw, "bash_compress");
|
|
14481
|
-
const bc =
|
|
15187
|
+
const bc = getDefaultConfig("bash_compress");
|
|
14482
15188
|
bc.enabled = validatedBool(bc_raw["enabled"], bc.enabled);
|
|
14483
15189
|
bc.disabled_filters = validatedStrList(bc_raw["disabled_filters"], bc.disabled_filters);
|
|
14484
15190
|
bc.max_lines = validatedInt(bc_raw["max_lines"], bc.max_lines, 50, 1e5);
|
|
@@ -14494,22 +15200,22 @@ function _buildConfig(raw) {
|
|
|
14494
15200
|
bc.cache_max_bytes = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES", bc.cache_max_bytes);
|
|
14495
15201
|
bc.cache_max_bytes_per_output = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT", bc.cache_max_bytes_per_output);
|
|
14496
15202
|
const bd_raw = section(raw, "bash_diff");
|
|
14497
|
-
const bd =
|
|
15203
|
+
const bd = getDefaultConfig("bash_diff");
|
|
14498
15204
|
bd.max_hunks_per_file = validatedInt(bd_raw["max_hunks_per_file"], bd.max_hunks_per_file, 1, 1e4);
|
|
14499
15205
|
bd.hunk_density_cap = validatedBool(bd_raw["hunk_density_cap"], bd.hunk_density_cap);
|
|
14500
15206
|
const sl_raw = section(raw, "bash_severity_log");
|
|
14501
|
-
const sl =
|
|
15207
|
+
const sl = getDefaultConfig("bash_severity_log");
|
|
14502
15208
|
sl.context_lines = validatedInt(sl_raw["context_lines"], sl.context_lines, 0, 100);
|
|
14503
15209
|
sl.score_threshold = validatedFloat(sl_raw["score_threshold"], sl.score_threshold, 0, 1);
|
|
14504
15210
|
const cc_raw = section(raw, "post_read_code_compress");
|
|
14505
|
-
const cc =
|
|
15211
|
+
const cc = getDefaultConfig("post_read_code_compress");
|
|
14506
15212
|
cc.min_lines = validatedInt(cc_raw["min_lines"], cc.min_lines, 0, 1e6);
|
|
14507
15213
|
const sb_raw = section(raw, "session_brief");
|
|
14508
|
-
const sb =
|
|
15214
|
+
const sb = getDefaultConfig("session_brief");
|
|
14509
15215
|
sb.enabled = validatedBool(sb_raw["enabled"], sb.enabled);
|
|
14510
15216
|
sb.enabled = envBool("TOKEN_GOAT_SESSION_BRIEF", sb.enabled);
|
|
14511
15217
|
const sp_raw = section(raw, "skill_preservation");
|
|
14512
|
-
const sp =
|
|
15218
|
+
const sp = getDefaultConfig("skill_preservation");
|
|
14513
15219
|
sp.enabled = validatedBool(sp_raw["enabled"], sp.enabled);
|
|
14514
15220
|
sp.max_cache_bytes = validatedInt(sp_raw["max_cache_bytes"], sp.max_cache_bytes, 64 * 1024, 512 * 1024 * 1024);
|
|
14515
15221
|
sp.orphan_sweep_enabled = validatedBool(sp_raw["orphan_sweep_enabled"], sp.orphan_sweep_enabled);
|
|
@@ -14526,7 +15232,7 @@ function _buildConfig(raw) {
|
|
|
14526
15232
|
sp.pre_skill_enabled = envBool("TOKEN_GOAT_PRE_SKILL", sp.pre_skill_enabled);
|
|
14527
15233
|
sp.orphan_sweep_enabled = envBool("TOKEN_GOAT_ORPHAN_SWEEP", sp.orphan_sweep_enabled);
|
|
14528
15234
|
const is_raw = section(raw, "image_shrink");
|
|
14529
|
-
const is_cfg =
|
|
15235
|
+
const is_cfg = getDefaultConfig("image_shrink");
|
|
14530
15236
|
is_cfg.prefer_avif = validatedBool(is_raw["prefer_avif"], is_cfg.prefer_avif);
|
|
14531
15237
|
is_cfg.avif_quality = validatedInt(is_raw["avif_quality"], is_cfg.avif_quality, 1, 100);
|
|
14532
15238
|
is_cfg.jpeg_quality = validatedInt(is_raw["jpeg_quality"], is_cfg.jpeg_quality, 1, 100);
|
|
@@ -14537,33 +15243,33 @@ function _buildConfig(raw) {
|
|
|
14537
15243
|
is_cfg.prefer_avif = envBool("TOKEN_GOAT_PREFER_AVIF", is_cfg.prefer_avif);
|
|
14538
15244
|
is_cfg.max_image_pixels = envInt("TOKEN_GOAT_MAX_IMAGE_PIXELS", is_cfg.max_image_pixels);
|
|
14539
15245
|
const cur_raw = section(raw, "curator");
|
|
14540
|
-
const cur =
|
|
15246
|
+
const cur = getDefaultConfig("curator");
|
|
14541
15247
|
cur.enabled = validatedBool(cur_raw["enabled"], cur.enabled);
|
|
14542
15248
|
cur.min_samples = validatedInt(cur_raw["min_samples"], cur.min_samples, 0, 1e4);
|
|
14543
15249
|
cur.threshold_pct = validatedInt(cur_raw["threshold_pct"], cur.threshold_pct, 0, 100);
|
|
14544
15250
|
cur.enabled = envBool("TOKEN_GOAT_CURATOR", cur.enabled);
|
|
14545
15251
|
const hb_raw = section(raw, "hint_budget");
|
|
14546
|
-
const hb =
|
|
15252
|
+
const hb = getDefaultConfig("hint_budget");
|
|
14547
15253
|
hb.enabled = validatedBool(hb_raw["enabled"], hb.enabled);
|
|
14548
15254
|
hb.max_per_session = validatedInt(hb_raw["max_per_session"], hb.max_per_session, 0, 1e6);
|
|
14549
15255
|
hb.max_structured_per_session = validatedInt(hb_raw["max_structured_per_session"], hb.max_structured_per_session, 0, 1e6);
|
|
14550
15256
|
hb.max_index_only_per_session = validatedInt(hb_raw["max_index_only_per_session"], hb.max_index_only_per_session, 0, 1e6);
|
|
14551
15257
|
hb.enabled = envBool("TOKEN_GOAT_HINT_BUDGET", hb.enabled);
|
|
14552
15258
|
const rm_raw = section(raw, "repomap");
|
|
14553
|
-
const rm =
|
|
15259
|
+
const rm = getDefaultConfig("repomap");
|
|
14554
15260
|
rm.compact_file_threshold = validatedInt(rm_raw["compact_file_threshold"], rm.compact_file_threshold, 0, 1e5);
|
|
14555
15261
|
rm.exclude_tests = validatedBool(rm_raw["exclude_tests"], rm.exclude_tests);
|
|
14556
15262
|
rm.compact_file_threshold = envInt("TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD", rm.compact_file_threshold);
|
|
14557
15263
|
rm.exclude_tests = envBool("TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS", rm.exclude_tests);
|
|
14558
15264
|
const og_raw = section(raw, "overflow_guard");
|
|
14559
|
-
const og =
|
|
15265
|
+
const og = getDefaultConfig("overflow_guard");
|
|
14560
15266
|
og.enabled = validatedBool(og_raw["enabled"], og.enabled);
|
|
14561
15267
|
og.max_tokens = validatedInt(og_raw["max_tokens"], og.max_tokens, 1e3, 1e6);
|
|
14562
15268
|
const st_raw = section(raw, "stats");
|
|
14563
|
-
const st =
|
|
15269
|
+
const st = getDefaultConfig("stats");
|
|
14564
15270
|
st.record_zero_savings = validatedBool(st_raw["record_zero_savings"], st.record_zero_savings);
|
|
14565
15271
|
const hi_raw = section(raw, "hints");
|
|
14566
|
-
const hi =
|
|
15272
|
+
const hi = getDefaultConfig("hints");
|
|
14567
15273
|
hi.suppress_after_ignored = validatedInt(hi_raw["suppress_after_ignored"], hi.suppress_after_ignored, 0, 1e3);
|
|
14568
15274
|
hi.quiet_hours = validatedStr(hi_raw["quiet_hours"], hi.quiet_hours);
|
|
14569
15275
|
hi.json_sidecar = validatedBool(hi_raw["json_sidecar"], hi.json_sidecar);
|
|
@@ -14596,11 +15302,11 @@ function _buildConfig(raw) {
|
|
|
14596
15302
|
})).filter((t) => t.keywords.length > 0 && t.hint.length > 0);
|
|
14597
15303
|
}
|
|
14598
15304
|
const hk_raw = section(raw, "hooks");
|
|
14599
|
-
const hk =
|
|
15305
|
+
const hk = getDefaultConfig("hooks");
|
|
14600
15306
|
hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, 100, 3e4);
|
|
14601
15307
|
hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms);
|
|
14602
15308
|
const wf_raw = section(raw, "webfetch");
|
|
14603
|
-
const wf =
|
|
15309
|
+
const wf = getDefaultConfig("webfetch");
|
|
14604
15310
|
wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
|
|
14605
15311
|
wf.deny = validatedStrList(wf_raw["deny"], wf.deny);
|
|
14606
15312
|
wf.max_file_count = validatedInt(wf_raw["max_file_count"], wf.max_file_count, 0, 1e7);
|
|
@@ -14609,27 +15315,27 @@ function _buildConfig(raw) {
|
|
|
14609
15315
|
wf.compress_min_bytes = validatedInt(wf_raw["compress_min_bytes"], wf.compress_min_bytes, 1024, 10 * 1024 * 1024);
|
|
14610
15316
|
wf.compress_bodies = envBool("TOKEN_GOAT_WEB_COMPRESS", wf.compress_bodies);
|
|
14611
15317
|
const wk_raw = section(raw, "worker");
|
|
14612
|
-
const wk =
|
|
15318
|
+
const wk = getDefaultConfig("worker");
|
|
14613
15319
|
wk.watchdog_enabled = validatedBool(wk_raw["watchdog_enabled"], wk.watchdog_enabled);
|
|
14614
15320
|
wk.max_pool_workers = validatedInt(wk_raw["max_pool_workers"], wk.max_pool_workers, 1, 8);
|
|
14615
15321
|
wk.blocked_roots = validatedStrList(wk_raw["blocked_roots"], wk.blocked_roots);
|
|
14616
15322
|
wk.watchdog_enabled = envBool("TOKEN_GOAT_WORKER_WATCHDOG", wk.watchdog_enabled);
|
|
14617
15323
|
wk.max_pool_workers = envInt("TOKEN_GOAT_WORKER_MAX_POOL", wk.max_pool_workers);
|
|
14618
15324
|
const ix_raw = section(raw, "indexing");
|
|
14619
|
-
const ix =
|
|
15325
|
+
const ix = getDefaultConfig("indexing");
|
|
14620
15326
|
ix.large_file_symbol_only_kb = validatedInt(ix_raw["large_file_symbol_only_kb"], ix.large_file_symbol_only_kb, 1, 1048576);
|
|
14621
15327
|
ix.large_file_skip_kb = validatedInt(ix_raw["large_file_skip_kb"], ix.large_file_skip_kb, 1, 1048576);
|
|
14622
15328
|
ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
|
|
14623
15329
|
const cpr_raw = section(raw, "compression");
|
|
14624
|
-
const cpr =
|
|
15330
|
+
const cpr = getDefaultConfig("compression");
|
|
14625
15331
|
cpr.profile = validatedStr(cpr_raw["profile"], cpr.profile);
|
|
14626
15332
|
cpr.profile = envStr("TOKEN_GOAT_COMPRESS_PROFILE", cpr.profile);
|
|
14627
15333
|
const ctx_raw = section(raw, "context");
|
|
14628
|
-
const ctx =
|
|
15334
|
+
const ctx = getDefaultConfig("context");
|
|
14629
15335
|
ctx.model_window_tokens = validatedInt(ctx_raw["model_window_tokens"], ctx.model_window_tokens, 1e4, 1e7);
|
|
14630
15336
|
ctx.model_window_tokens = envInt("TOKEN_GOAT_MODEL_WINDOW_TOKENS", ctx.model_window_tokens);
|
|
14631
15337
|
const inj_raw = section(raw, "injection");
|
|
14632
|
-
const inj =
|
|
15338
|
+
const inj = getDefaultConfig("injection");
|
|
14633
15339
|
inj.enabled = validatedBool(inj_raw["enabled"], inj.enabled);
|
|
14634
15340
|
inj.enabled = envBool("TOKEN_GOAT_INJECTION_ENABLED", inj.enabled);
|
|
14635
15341
|
return {
|
|
@@ -14659,9 +15365,9 @@ function _buildConfig(raw) {
|
|
|
14659
15365
|
|
|
14660
15366
|
// src/cli_doctor.ts
|
|
14661
15367
|
init_define_import_meta_env();
|
|
14662
|
-
import * as
|
|
14663
|
-
import * as
|
|
14664
|
-
import { execSync } from "child_process";
|
|
15368
|
+
import * as fs14 from "fs";
|
|
15369
|
+
import * as path15 from "path";
|
|
15370
|
+
import { execSync, spawnSync as spawnSync2 } from "child_process";
|
|
14665
15371
|
function checkWorkerRunning() {
|
|
14666
15372
|
try {
|
|
14667
15373
|
const output = execSync("tasklist", { encoding: "utf-8" });
|
|
@@ -14671,8 +15377,8 @@ function checkWorkerRunning() {
|
|
|
14671
15377
|
}
|
|
14672
15378
|
}
|
|
14673
15379
|
function checkDbExists(dataDir2) {
|
|
14674
|
-
const dbPath =
|
|
14675
|
-
if (!
|
|
15380
|
+
const dbPath = path15.join(dataDir2, "index.db");
|
|
15381
|
+
if (!fs14.existsSync(dbPath)) {
|
|
14676
15382
|
return {
|
|
14677
15383
|
name: "Database",
|
|
14678
15384
|
status: "warn",
|
|
@@ -14682,7 +15388,7 @@ function checkDbExists(dataDir2) {
|
|
|
14682
15388
|
return {
|
|
14683
15389
|
name: "Database",
|
|
14684
15390
|
status: "ok",
|
|
14685
|
-
message: `index.db exists (${Math.round(
|
|
15391
|
+
message: `index.db exists (${Math.round(fs14.statSync(dbPath).size / 1024)} KB)`
|
|
14686
15392
|
};
|
|
14687
15393
|
}
|
|
14688
15394
|
function checkInstall() {
|
|
@@ -14702,7 +15408,7 @@ function checkInstall() {
|
|
|
14702
15408
|
}
|
|
14703
15409
|
}
|
|
14704
15410
|
function checkConfigValid(configPath2) {
|
|
14705
|
-
if (!
|
|
15411
|
+
if (!fs14.existsSync(configPath2)) {
|
|
14706
15412
|
return {
|
|
14707
15413
|
name: "Config",
|
|
14708
15414
|
status: "warn",
|
|
@@ -14710,7 +15416,7 @@ function checkConfigValid(configPath2) {
|
|
|
14710
15416
|
};
|
|
14711
15417
|
}
|
|
14712
15418
|
try {
|
|
14713
|
-
const content =
|
|
15419
|
+
const content = fs14.readFileSync(configPath2, "utf-8");
|
|
14714
15420
|
JSON.parse(content);
|
|
14715
15421
|
return {
|
|
14716
15422
|
name: "Config",
|
|
@@ -14721,18 +15427,22 @@ function checkConfigValid(configPath2) {
|
|
|
14721
15427
|
return {
|
|
14722
15428
|
name: "Config",
|
|
14723
15429
|
status: "fail",
|
|
14724
|
-
message: `config invalid: ${err2
|
|
15430
|
+
message: `config invalid: ${extractErrorMessage(err2, "unknown error")}`
|
|
14725
15431
|
};
|
|
14726
15432
|
}
|
|
14727
15433
|
}
|
|
14728
15434
|
function checkDiskSpace(dataDir2) {
|
|
14729
15435
|
try {
|
|
14730
|
-
const
|
|
14731
|
-
const
|
|
15436
|
+
const result = spawnSync2("df", ["-h", dataDir2], { encoding: "utf-8" });
|
|
15437
|
+
const stdout = typeof result.stdout === "string" ? result.stdout : "";
|
|
15438
|
+
if (result.error !== void 0 || result.status !== 0 || !stdout) {
|
|
15439
|
+
return { name: "Disk Space", status: "warn", message: "could not determine" };
|
|
15440
|
+
}
|
|
15441
|
+
const lines = stdout.trim().split("\n");
|
|
14732
15442
|
if (lines.length < 2) {
|
|
14733
15443
|
return { name: "Disk Space", status: "warn", message: "could not determine" };
|
|
14734
15444
|
}
|
|
14735
|
-
const parts = lines[1].split(/\s+/);
|
|
15445
|
+
const parts = lines[1].trim().split(/\s+/);
|
|
14736
15446
|
const available = parts[3] || "unknown";
|
|
14737
15447
|
return { name: "Disk Space", status: "ok", message: `${available} available` };
|
|
14738
15448
|
} catch {
|
|
@@ -14744,9 +15454,9 @@ function runDoctor(dataDir2, configPath2) {
|
|
|
14744
15454
|
results.push(checkInstall());
|
|
14745
15455
|
results.push(checkWorkerRunning() ? { name: "Worker", status: "ok", message: "running" } : { name: "Worker", status: "warn", message: "not running" });
|
|
14746
15456
|
const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
14747
|
-
const actualDataDir = dataDir2 ||
|
|
15457
|
+
const actualDataDir = dataDir2 || path15.join(homeDir, ".token-goat");
|
|
14748
15458
|
results.push(checkDbExists(actualDataDir));
|
|
14749
|
-
const actualConfigPath = configPath2 ||
|
|
15459
|
+
const actualConfigPath = configPath2 || path15.join(actualDataDir, "config.json");
|
|
14750
15460
|
results.push(checkConfigValid(actualConfigPath));
|
|
14751
15461
|
results.push(checkDiskSpace(actualDataDir));
|
|
14752
15462
|
return results;
|
|
@@ -14785,7 +15495,7 @@ init_define_import_meta_env();
|
|
|
14785
15495
|
var _byId2 = /* @__PURE__ */ new Map();
|
|
14786
15496
|
var _urlIndex = /* @__PURE__ */ new Map();
|
|
14787
15497
|
function cacheIdForUrl(url) {
|
|
14788
|
-
return
|
|
15498
|
+
return shortFingerprint(url);
|
|
14789
15499
|
}
|
|
14790
15500
|
function storeWebOutput(url, content) {
|
|
14791
15501
|
const cacheId = cacheIdForUrl(url);
|
|
@@ -14905,12 +15615,10 @@ async function getSectionContent(fileId, heading) {
|
|
|
14905
15615
|
var CliError = class extends Error {
|
|
14906
15616
|
};
|
|
14907
15617
|
function out(text) {
|
|
14908
|
-
process.stdout.write(text
|
|
14909
|
-
`);
|
|
15618
|
+
process.stdout.write(ensureNewline(text));
|
|
14910
15619
|
}
|
|
14911
15620
|
function err(text) {
|
|
14912
|
-
process.stderr.write(text
|
|
14913
|
-
`);
|
|
15621
|
+
process.stderr.write(ensureNewline(text));
|
|
14914
15622
|
}
|
|
14915
15623
|
function previewLines(body, n) {
|
|
14916
15624
|
return body.split(/\r?\n/).slice(0, n).join("\n");
|
|
@@ -15070,7 +15778,7 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
15070
15778
|
const n = Number.parseInt(opts.tail, 10);
|
|
15071
15779
|
return Number.isFinite(n) && n > 0 ? n : 80;
|
|
15072
15780
|
})() : 80;
|
|
15073
|
-
const applyElision = (lines2, headN2, tailN2) => lines2.length > headN2 + tailN2 ? [...lines2.slice(0, headN2), "...(elided)...", ...lines2.slice(lines2.length - tailN2)] : lines2;
|
|
15781
|
+
const applyElision = (lines2, headN2, tailN2) => lines2.length > headN2 + tailN2 + 1 ? [...lines2.slice(0, headN2), "...(elided)...", ...lines2.slice(lines2.length - tailN2)] : lines2;
|
|
15074
15782
|
let result = lines;
|
|
15075
15783
|
if (opts.head === void 0 && opts.tail === void 0 && opts.grep === void 0) {
|
|
15076
15784
|
result = applyElision(lines, headN, tailN);
|
|
@@ -15085,10 +15793,21 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
15085
15793
|
}
|
|
15086
15794
|
function cmdBashOutput(id, opts) {
|
|
15087
15795
|
if (opts.file !== void 0) {
|
|
15796
|
+
if (opts.file.includes("\0")) {
|
|
15797
|
+
throw new CliError("--file path contains a null byte");
|
|
15798
|
+
}
|
|
15799
|
+
if (!isWindows() && /^\/dev\/(stdin|fd\/0)$|^\/proc\/self\/fd\/0$/.test(opts.file) && process.stdin.isTTY) {
|
|
15800
|
+
throw new CliError("--file /dev/stdin requires piped input; redirect a file instead");
|
|
15801
|
+
}
|
|
15088
15802
|
let content;
|
|
15089
15803
|
try {
|
|
15090
|
-
|
|
15091
|
-
|
|
15804
|
+
const st = fs15.statSync(opts.file);
|
|
15805
|
+
if (st.isFIFO() || st.isSocket()) {
|
|
15806
|
+
throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
15807
|
+
}
|
|
15808
|
+
content = fs15.readFileSync(opts.file, "utf-8");
|
|
15809
|
+
} catch (e) {
|
|
15810
|
+
if (e instanceof CliError) throw e;
|
|
15092
15811
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
15093
15812
|
}
|
|
15094
15813
|
_applyFiltersAndPrint(content, opts);
|
|
@@ -15108,12 +15827,12 @@ async function cmdSkillBody(name, opts) {
|
|
|
15108
15827
|
if (filePath === null) {
|
|
15109
15828
|
throw new CliError(`skill '${name}' not found`);
|
|
15110
15829
|
}
|
|
15111
|
-
const body =
|
|
15830
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
15112
15831
|
if (opts.compact === true) {
|
|
15113
15832
|
const lines = body.split("\n");
|
|
15114
15833
|
const end = lines.findIndex((l) => l.includes("COMPACT_END"));
|
|
15115
15834
|
if (end !== -1) {
|
|
15116
|
-
out(lines.slice(
|
|
15835
|
+
out(lines.slice(end + 1).join("\n"));
|
|
15117
15836
|
} else {
|
|
15118
15837
|
out(body);
|
|
15119
15838
|
}
|
|
@@ -15126,7 +15845,7 @@ async function cmdSkillCompact(name) {
|
|
|
15126
15845
|
if (filePath === null) {
|
|
15127
15846
|
throw new CliError(`skill '${name}' not found`);
|
|
15128
15847
|
}
|
|
15129
|
-
const body =
|
|
15848
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
15130
15849
|
const sessionFiles = getSessionFiles();
|
|
15131
15850
|
const sessionId = Array.from(sessionFiles.keys())[0] ?? "default";
|
|
15132
15851
|
await storeCompact(sessionId, name, body);
|
|
@@ -15213,7 +15932,7 @@ function cmdConfigGet(file, key) {
|
|
|
15213
15932
|
}
|
|
15214
15933
|
function atomicWriteBuffer(dest, data) {
|
|
15215
15934
|
try {
|
|
15216
|
-
if (
|
|
15935
|
+
if (fs15.statSync(dest).isDirectory()) {
|
|
15217
15936
|
const e = Object.assign(new Error(`EISDIR: illegal operation on a directory, open '${dest}'`), { code: "EISDIR", path: dest });
|
|
15218
15937
|
throw e;
|
|
15219
15938
|
}
|
|
@@ -15221,16 +15940,16 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15221
15940
|
if (e.code !== "ENOENT") throw e;
|
|
15222
15941
|
}
|
|
15223
15942
|
const rnd = Math.random().toString(36).slice(2, 8);
|
|
15224
|
-
const tmp =
|
|
15943
|
+
const tmp = path16.join(path16.dirname(path16.resolve(dest)), `.tmp.${process.pid}.${rnd}`);
|
|
15225
15944
|
try {
|
|
15226
|
-
|
|
15945
|
+
fs15.writeFileSync(tmp, data, { mode: 384 });
|
|
15227
15946
|
try {
|
|
15228
|
-
|
|
15947
|
+
fs15.renameSync(tmp, dest);
|
|
15229
15948
|
} catch (e) {
|
|
15230
15949
|
if (e.code === "EXDEV") {
|
|
15231
|
-
|
|
15950
|
+
fs15.copyFileSync(tmp, dest);
|
|
15232
15951
|
try {
|
|
15233
|
-
|
|
15952
|
+
fs15.unlinkSync(tmp);
|
|
15234
15953
|
} catch (ue) {
|
|
15235
15954
|
process.stderr.write(`token-goat write-file: warning: could not remove temp file ${tmp}: ${ue.message}
|
|
15236
15955
|
`);
|
|
@@ -15241,7 +15960,7 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15241
15960
|
}
|
|
15242
15961
|
} catch (e) {
|
|
15243
15962
|
try {
|
|
15244
|
-
|
|
15963
|
+
fs15.unlinkSync(tmp);
|
|
15245
15964
|
} catch {
|
|
15246
15965
|
}
|
|
15247
15966
|
throw e;
|
|
@@ -15251,9 +15970,9 @@ function mapFsError(e, src, dest) {
|
|
|
15251
15970
|
const fe = e;
|
|
15252
15971
|
if (fe.code === "ENOENT") {
|
|
15253
15972
|
const errPath = fe.path ?? "";
|
|
15254
|
-
const isSource = src !== void 0 &&
|
|
15973
|
+
const isSource = src !== void 0 && path16.resolve(errPath) === path16.resolve(src);
|
|
15255
15974
|
if (isSource) throw new CliError(`source file not found: ${src}`);
|
|
15256
|
-
const destDir = dest ?
|
|
15975
|
+
const destDir = dest ? path16.dirname(path16.resolve(dest)) : path16.dirname(path16.resolve(errPath || "."));
|
|
15257
15976
|
throw new CliError(`destination directory does not exist: ${destDir}`);
|
|
15258
15977
|
}
|
|
15259
15978
|
if (fe.code === "ENOTDIR") {
|
|
@@ -15261,7 +15980,7 @@ function mapFsError(e, src, dest) {
|
|
|
15261
15980
|
}
|
|
15262
15981
|
if (fe.code === "EISDIR") {
|
|
15263
15982
|
const errPath = fe.path ?? "";
|
|
15264
|
-
const isSource = src !== void 0 && (errPath === "" ||
|
|
15983
|
+
const isSource = src !== void 0 && (errPath === "" || path16.resolve(errPath) === path16.resolve(src));
|
|
15265
15984
|
if (isSource) throw new CliError(`source is a directory, not a file: ${src}`);
|
|
15266
15985
|
throw new CliError(`destination is a directory, not a file: ${dest ?? (errPath || "(unknown)")}`);
|
|
15267
15986
|
}
|
|
@@ -15326,8 +16045,8 @@ function cmdWriteFile(dest, opts) {
|
|
|
15326
16045
|
if (dest.includes("\0")) {
|
|
15327
16046
|
throw new CliError("destination path contains a null byte");
|
|
15328
16047
|
}
|
|
15329
|
-
if (
|
|
15330
|
-
const base =
|
|
16048
|
+
if (isWindows()) {
|
|
16049
|
+
const base = path16.basename(dest);
|
|
15331
16050
|
const stem = base.replace(/\.[^.]*$/, "").toUpperCase();
|
|
15332
16051
|
if (WIN_RESERVED.has(stem)) {
|
|
15333
16052
|
throw new CliError(`destination '${base}' is a reserved Windows device name`);
|
|
@@ -15346,20 +16065,23 @@ function cmdWriteFile(dest, opts) {
|
|
|
15346
16065
|
if (opts.from.includes("\0")) {
|
|
15347
16066
|
throw new CliError("--from path contains a null byte");
|
|
15348
16067
|
}
|
|
15349
|
-
if (
|
|
16068
|
+
if (!isWindows() && /^\/dev\/(stdin|fd\/0)$|^\/proc\/self\/fd\/0$/.test(opts.from) && process.stdin.isTTY) {
|
|
15350
16069
|
throw new CliError("--from /dev/stdin requires piped input; use piped stdin mode or --b64 for interactive use");
|
|
15351
16070
|
}
|
|
15352
16071
|
try {
|
|
15353
|
-
const st =
|
|
16072
|
+
const st = fs15.statSync(opts.from);
|
|
15354
16073
|
if (st.isFIFO() || st.isSocket()) {
|
|
15355
16074
|
throw new CliError(`--from '${opts.from}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
15356
16075
|
}
|
|
15357
16076
|
const maxFromMB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15358
|
-
|
|
16077
|
+
if (!Number.isFinite(maxFromMB) || maxFromMB <= 0) {
|
|
16078
|
+
throw new CliError(`TOKEN_GOAT_MAX_STDIN_MB must be a positive integer; got '${process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? ""}'`);
|
|
16079
|
+
}
|
|
16080
|
+
const maxFromBytes = maxFromMB * 1024 * 1024;
|
|
15359
16081
|
if (st.size > maxFromBytes) {
|
|
15360
16082
|
throw new CliError(`--from source exceeds size limit (${Math.round(st.size / 1024 / 1024)} MB); set TOKEN_GOAT_MAX_STDIN_MB to override`);
|
|
15361
16083
|
}
|
|
15362
|
-
atomicWriteBuffer(dest,
|
|
16084
|
+
atomicWriteBuffer(dest, fs15.readFileSync(opts.from));
|
|
15363
16085
|
} catch (e) {
|
|
15364
16086
|
if (e instanceof CliError) throw e;
|
|
15365
16087
|
mapFsError(e, opts.from, dest);
|
|
@@ -15372,7 +16094,10 @@ function cmdWriteFile(dest, opts) {
|
|
|
15372
16094
|
throw new CliError("--b64 payload contains only whitespace \u2014 likely a shell expansion error; pass an empty string explicitly for a zero-byte file");
|
|
15373
16095
|
}
|
|
15374
16096
|
const maxB64MB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15375
|
-
|
|
16097
|
+
if (!Number.isFinite(maxB64MB) || maxB64MB <= 0) {
|
|
16098
|
+
throw new CliError(`TOKEN_GOAT_MAX_STDIN_MB must be a positive integer; got '${process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? ""}'`);
|
|
16099
|
+
}
|
|
16100
|
+
const maxB64Bytes = maxB64MB * 1024 * 1024;
|
|
15376
16101
|
const decodedSize = Math.floor(normalized.replace(/=+$/, "").length * 3 / 4);
|
|
15377
16102
|
if (decodedSize > maxB64Bytes) {
|
|
15378
16103
|
throw new CliError(`--b64 payload would decode to ${Math.round(decodedSize / 1024 / 1024)} MB which exceeds size limit; set TOKEN_GOAT_MAX_STDIN_MB to override`);
|
|
@@ -15473,7 +16198,7 @@ function buildProgram() {
|
|
|
15473
16198
|
await fn(...args);
|
|
15474
16199
|
process.exitCode = 0;
|
|
15475
16200
|
} catch (e) {
|
|
15476
|
-
const msg =
|
|
16201
|
+
const msg = extractErrorMessage(e);
|
|
15477
16202
|
err(`token-goat: ${msg}`);
|
|
15478
16203
|
process.exitCode = 1;
|
|
15479
16204
|
}
|
|
@@ -15525,7 +16250,7 @@ async function run(argv = process.argv) {
|
|
|
15525
16250
|
process.exitCode = 1;
|
|
15526
16251
|
return;
|
|
15527
16252
|
}
|
|
15528
|
-
const msg =
|
|
16253
|
+
const msg = extractErrorMessage(e);
|
|
15529
16254
|
err(`token-goat: ${msg}`);
|
|
15530
16255
|
process.exitCode = 1;
|
|
15531
16256
|
}
|