token-goat 2.0.3 → 2.2.0
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 +3 -2
- package/dist/token-goat.mjs +1251 -358
- 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.0
|
|
9496
|
+
return "2.2.0";
|
|
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
|
|
@@ -10567,6 +10803,10 @@ var BUILD_COMMAND_PATTERNS = [
|
|
|
10567
10803
|
// Turbo
|
|
10568
10804
|
/^\s*turbo\s+(build|dev)\b/i
|
|
10569
10805
|
];
|
|
10806
|
+
var LOCK_FILE_COUNT = LOCK_FILE_NAMES.size;
|
|
10807
|
+
var MANIFEST_FILE_COUNT = MANIFEST_FILE_NAMES.size + MANIFEST_EXTENSIONS.size + MANIFEST_BASENAME_PATTERNS.length;
|
|
10808
|
+
var BUILD_DIR_COUNT = BUILD_DIR_NAMES.size;
|
|
10809
|
+
var GENERATED_EXT_COUNT = ALWAYS_GENERATED_EXTS.size + CONDITIONALLY_GENERATED_EXTS.size;
|
|
10570
10810
|
function isLockFile(basename7) {
|
|
10571
10811
|
return LOCK_FILE_NAMES.has(basename7.toLowerCase());
|
|
10572
10812
|
}
|
|
@@ -10870,7 +11110,7 @@ function dispatchFileTypeHandler(filePath, content, contentLengthHint) {
|
|
|
10870
11110
|
|
|
10871
11111
|
// src/stats.ts
|
|
10872
11112
|
init_define_import_meta_env();
|
|
10873
|
-
import * as
|
|
11113
|
+
import * as path8 from "node:path";
|
|
10874
11114
|
|
|
10875
11115
|
// src/render/stats_renderer.ts
|
|
10876
11116
|
init_define_import_meta_env();
|
|
@@ -11650,7 +11890,7 @@ CREATE INDEX IF NOT EXISTS idx_stats_kind ON stats(kind);
|
|
|
11650
11890
|
var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
11651
11891
|
registerReset(() => _globalSchemaApplied.clear());
|
|
11652
11892
|
function getGlobalDb() {
|
|
11653
|
-
const dbPath =
|
|
11893
|
+
const dbPath = path8.join(dataDir(), "global.db");
|
|
11654
11894
|
const db = getDb(dbPath);
|
|
11655
11895
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
11656
11896
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
@@ -11684,7 +11924,9 @@ function summarize(windowDays = 30, testDb) {
|
|
|
11684
11924
|
const bytesSaved = row.bytes_saved ?? 0;
|
|
11685
11925
|
const tokensSaved = row.tokens_saved ?? 0;
|
|
11686
11926
|
const kind = row.kind;
|
|
11687
|
-
const
|
|
11927
|
+
const tsRaw = row.ts;
|
|
11928
|
+
if (tsRaw === void 0) continue;
|
|
11929
|
+
const ts = tsRaw;
|
|
11688
11930
|
totalEvents += 1;
|
|
11689
11931
|
totalBytes += bytesSaved;
|
|
11690
11932
|
totalTokens += tokensSaved;
|
|
@@ -11845,22 +12087,61 @@ function isTsConfigFile(basename7) {
|
|
|
11845
12087
|
return /^tsconfig(\..+)?\.json$/i.test(lower) || lower === "jsconfig.json";
|
|
11846
12088
|
}
|
|
11847
12089
|
var LARGE_FILE_BYTES = 100 * 1024;
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
12090
|
+
var REREAD_DENY_BYTES = 50 * 1024;
|
|
12091
|
+
var LARGE_FILE_DENY_BYTES = 500 * 1024;
|
|
12092
|
+
function isNodeModulesPath(p) {
|
|
12093
|
+
const check = isWindows() ? p.toLowerCase() : p;
|
|
11851
12094
|
return check.includes("/node_modules/") || check.includes("\\node_modules\\");
|
|
11852
12095
|
}
|
|
11853
12096
|
function _isDocFile(filePath) {
|
|
11854
12097
|
const lower = filePath.toLowerCase();
|
|
11855
12098
|
return lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".markdown") || lower.endsWith(".rst");
|
|
11856
12099
|
}
|
|
12100
|
+
function isSessionArtifactFile(filePath) {
|
|
12101
|
+
if (/[/\\]tasks[/\\][a-z0-9]+\.output$/i.test(filePath)) return true;
|
|
12102
|
+
if (/[/\\]tool-results[/\\][a-z0-9]+\.txt$/i.test(filePath)) return true;
|
|
12103
|
+
return false;
|
|
12104
|
+
}
|
|
11857
12105
|
function statSize(absPath) {
|
|
11858
12106
|
try {
|
|
11859
|
-
return
|
|
12107
|
+
return fs5.statSync(absPath).size;
|
|
11860
12108
|
} catch {
|
|
11861
12109
|
return null;
|
|
11862
12110
|
}
|
|
11863
12111
|
}
|
|
12112
|
+
function buildLineDiff(oldContent, newContent, label) {
|
|
12113
|
+
const oldLines = oldContent.split("\n");
|
|
12114
|
+
const newLines = newContent.split("\n");
|
|
12115
|
+
let prefix = 0;
|
|
12116
|
+
while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix]) {
|
|
12117
|
+
prefix++;
|
|
12118
|
+
}
|
|
12119
|
+
let oldSuffix = oldLines.length;
|
|
12120
|
+
let newSuffix = newLines.length;
|
|
12121
|
+
while (oldSuffix > prefix && newSuffix > prefix && oldLines[oldSuffix - 1] === newLines[newSuffix - 1]) {
|
|
12122
|
+
oldSuffix--;
|
|
12123
|
+
newSuffix--;
|
|
12124
|
+
}
|
|
12125
|
+
if (prefix === oldLines.length && prefix === newLines.length) return "";
|
|
12126
|
+
const changedOld = oldLines.slice(prefix, oldSuffix);
|
|
12127
|
+
const changedNew = newLines.slice(prefix, newSuffix);
|
|
12128
|
+
const MAX_LINES = 50;
|
|
12129
|
+
const out2 = [
|
|
12130
|
+
`--- ${label} (prev)`,
|
|
12131
|
+
`+++ ${label} (current)`,
|
|
12132
|
+
`@@ -${prefix + 1},${changedOld.length} +${prefix + 1},${changedNew.length} @@`
|
|
12133
|
+
];
|
|
12134
|
+
const removedLines = changedOld.map((l) => `-${l}`);
|
|
12135
|
+
const addedLines = changedNew.map((l) => `+${l}`);
|
|
12136
|
+
const allChanges = [...removedLines, ...addedLines];
|
|
12137
|
+
if (allChanges.length <= MAX_LINES) {
|
|
12138
|
+
out2.push(...allChanges);
|
|
12139
|
+
} else {
|
|
12140
|
+
out2.push(...allChanges.slice(0, MAX_LINES));
|
|
12141
|
+
out2.push(`... (${allChanges.length - MAX_LINES} more changed lines)`);
|
|
12142
|
+
}
|
|
12143
|
+
return out2.join("\n");
|
|
12144
|
+
}
|
|
11864
12145
|
function preReadHandler(event) {
|
|
11865
12146
|
const filePath = getFilePath(event);
|
|
11866
12147
|
if (filePath === void 0) return passOutput();
|
|
@@ -11870,7 +12151,7 @@ function preReadHandler(event) {
|
|
|
11870
12151
|
"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"
|
|
11871
12152
|
);
|
|
11872
12153
|
}
|
|
11873
|
-
const basename7 =
|
|
12154
|
+
const basename7 = path9.basename(normalized);
|
|
11874
12155
|
if (isLockFile(basename7)) {
|
|
11875
12156
|
return denyOutput(
|
|
11876
12157
|
'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.'
|
|
@@ -11909,7 +12190,7 @@ function preReadHandler(event) {
|
|
|
11909
12190
|
try {
|
|
11910
12191
|
const sz = statSize(normalized);
|
|
11911
12192
|
if (sz !== null && sz >= MARKDOWN_SIZE_THRESHOLD) {
|
|
11912
|
-
fileContent =
|
|
12193
|
+
fileContent = fs5.readFileSync(normalized, "utf8");
|
|
11913
12194
|
}
|
|
11914
12195
|
} catch {
|
|
11915
12196
|
}
|
|
@@ -11925,14 +12206,152 @@ function preReadHandler(event) {
|
|
|
11925
12206
|
}
|
|
11926
12207
|
}
|
|
11927
12208
|
}
|
|
12209
|
+
const isMemoryMd = normalized.toLowerCase().includes("memory/memory.md") || /[/\\]memory[/\\][^/\\]+\.md$/i.test(normalized);
|
|
12210
|
+
if (isMemoryMd && wasFileReadThisSession(normalized)) {
|
|
12211
|
+
recordFileRead(normalized);
|
|
12212
|
+
recordStat("session_hint", 0, 0);
|
|
12213
|
+
const isMainMemory = basename7.toLowerCase() === "memory.md";
|
|
12214
|
+
return denyOutput(
|
|
12215
|
+
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.'
|
|
12216
|
+
);
|
|
12217
|
+
}
|
|
12218
|
+
if (/^\.improve-state-.*\.json$/.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
12219
|
+
recordFileRead(normalized);
|
|
12220
|
+
recordStat("session_hint", 0, 0);
|
|
12221
|
+
return denyOutput(
|
|
12222
|
+
"Orchestrator state already read this session. Use `token-goat bash-output <id>` or recall it from the compact manifest."
|
|
12223
|
+
);
|
|
12224
|
+
}
|
|
12225
|
+
if (/^\.env(\.\w+)?$/.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
12226
|
+
recordFileRead(normalized);
|
|
12227
|
+
recordStat("session_hint", 0, 0);
|
|
12228
|
+
return denyOutput(
|
|
12229
|
+
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."
|
|
12230
|
+
);
|
|
12231
|
+
}
|
|
12232
|
+
if (isSessionArtifactFile(normalized)) {
|
|
12233
|
+
if (wasFileReadThisSession(normalized)) {
|
|
12234
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12235
|
+
recordFileRead(normalized);
|
|
12236
|
+
recordStat("session_hint", 0, 0);
|
|
12237
|
+
return denyOutput(
|
|
12238
|
+
"File was truncated on last read. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12239
|
+
);
|
|
12240
|
+
}
|
|
12241
|
+
const artifactSessionId = getSessionId();
|
|
12242
|
+
const oldArtifactSnap = load(artifactSessionId, normalized);
|
|
12243
|
+
if (oldArtifactSnap !== null) {
|
|
12244
|
+
try {
|
|
12245
|
+
const sz = statSize(normalized);
|
|
12246
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12247
|
+
const currentContent = fs5.readFileSync(normalized, "utf8");
|
|
12248
|
+
const TRUNC_MARKER = "\n<snapshot truncated at ";
|
|
12249
|
+
const oldRaw = oldArtifactSnap.toString("utf8");
|
|
12250
|
+
const truncIdx = oldRaw.indexOf(TRUNC_MARKER);
|
|
12251
|
+
const oldContent = truncIdx >= 0 ? oldRaw.slice(0, truncIdx) : oldRaw;
|
|
12252
|
+
if (oldContent === currentContent) {
|
|
12253
|
+
recordFileRead(normalized);
|
|
12254
|
+
recordStat("session_hint", 0, 0);
|
|
12255
|
+
return denyOutput(
|
|
12256
|
+
basename7 + " is unchanged since last read. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12257
|
+
);
|
|
12258
|
+
}
|
|
12259
|
+
const diff = buildLineDiff(oldContent, currentContent, basename7);
|
|
12260
|
+
if (diff !== "") {
|
|
12261
|
+
recordFileRead(normalized);
|
|
12262
|
+
const savedBytes = Math.max(0, currentContent.length - diff.length);
|
|
12263
|
+
recordStat("session_hint", savedBytes, Math.round(savedBytes / 4));
|
|
12264
|
+
return denyOutput(
|
|
12265
|
+
"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."
|
|
12266
|
+
);
|
|
12267
|
+
}
|
|
12268
|
+
}
|
|
12269
|
+
} catch {
|
|
12270
|
+
}
|
|
12271
|
+
}
|
|
12272
|
+
recordFileRead(normalized);
|
|
12273
|
+
recordStat("session_hint", 0, 0);
|
|
12274
|
+
return denyOutput(
|
|
12275
|
+
normalized + " was already read this session. Use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice."
|
|
12276
|
+
);
|
|
12277
|
+
}
|
|
12278
|
+
if (/[/\\]tasks[/\\][a-z0-9]+\.output$/i.test(normalized)) {
|
|
12279
|
+
recordFileRead(normalized);
|
|
12280
|
+
return contextOutput(
|
|
12281
|
+
"Session transcript: use `token-goat bash-output --tail N` or `--grep PATTERN` to read a slice instead of the full file."
|
|
12282
|
+
);
|
|
12283
|
+
}
|
|
12284
|
+
}
|
|
12285
|
+
if (/\.(md|mdx|rst|txt)$/i.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
12286
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12287
|
+
recordFileRead(normalized);
|
|
12288
|
+
recordStat("session_hint", 0, 0);
|
|
12289
|
+
return denyOutput(
|
|
12290
|
+
'File was truncated on last read (>33K tokens). Use `token-goat skeleton "' + normalized + '"` for structure or `token-goat read "' + normalized + '::SymbolName"` for one function.'
|
|
12291
|
+
);
|
|
12292
|
+
}
|
|
12293
|
+
const sessionId = getSessionId();
|
|
12294
|
+
const oldSnap = load(sessionId, normalized);
|
|
12295
|
+
if (oldSnap !== null) {
|
|
12296
|
+
try {
|
|
12297
|
+
const sz = statSize(normalized);
|
|
12298
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12299
|
+
const currentContent = fs5.readFileSync(normalized, "utf8");
|
|
12300
|
+
const TRUNC_MARKER = "\n<snapshot truncated at ";
|
|
12301
|
+
const oldRaw = oldSnap.toString("utf8");
|
|
12302
|
+
const truncIdx = oldRaw.indexOf(TRUNC_MARKER);
|
|
12303
|
+
const oldContent = truncIdx >= 0 ? oldRaw.slice(0, truncIdx) : oldRaw;
|
|
12304
|
+
if (oldContent === currentContent) {
|
|
12305
|
+
recordFileRead(normalized);
|
|
12306
|
+
recordStat("session_hint", 0, 0);
|
|
12307
|
+
return denyOutput(
|
|
12308
|
+
basename7 + ' is unchanged since last read. Use `token-goat section "' + normalized + '::HeadingName"` to extract a part.'
|
|
12309
|
+
);
|
|
12310
|
+
}
|
|
12311
|
+
const diff = buildLineDiff(oldContent, currentContent, basename7);
|
|
12312
|
+
if (diff !== "") {
|
|
12313
|
+
recordFileRead(normalized);
|
|
12314
|
+
const savedBytes = Math.max(0, currentContent.length - diff.length);
|
|
12315
|
+
recordStat("session_hint", savedBytes, Math.round(savedBytes / 4));
|
|
12316
|
+
return denyOutput(
|
|
12317
|
+
"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.'
|
|
12318
|
+
);
|
|
12319
|
+
}
|
|
12320
|
+
}
|
|
12321
|
+
} catch {
|
|
12322
|
+
}
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
11928
12325
|
if (wasFileReadThisSession(normalized)) {
|
|
11929
12326
|
const entry = getSessionFiles().get(normalized);
|
|
11930
12327
|
const reads = entry?.readCount ?? 1;
|
|
11931
12328
|
const plural = reads === 1 ? "read" : "reads";
|
|
11932
12329
|
recordFileRead(normalized);
|
|
11933
|
-
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
11934
12330
|
const rereadBytes = statSize(normalized) ?? 0;
|
|
11935
12331
|
recordStat("session_hint", rereadBytes, Math.round(rereadBytes / 4));
|
|
12332
|
+
if (wasFileTruncatedThisSession(normalized)) {
|
|
12333
|
+
return denyOutput(
|
|
12334
|
+
'File was truncated on last read (>33K tokens). Use `token-goat skeleton "' + normalized + '"` for structure or `token-goat read "' + normalized + '::SymbolName"` for one function.'
|
|
12335
|
+
);
|
|
12336
|
+
}
|
|
12337
|
+
if (/\.(md|mdx)$/i.test(basename7)) {
|
|
12338
|
+
return denyOutput(
|
|
12339
|
+
'Markdown file already read this session. Use `token-goat section "' + normalized + '::HeadingName"` to read one section.'
|
|
12340
|
+
);
|
|
12341
|
+
}
|
|
12342
|
+
const isSourceExt = /\.(ts|tsx|js|jsx|py|go|rs|java|rb|php|swift|kt|cpp|c|h)$/i.test(basename7);
|
|
12343
|
+
if (isSourceExt && reads >= 2) {
|
|
12344
|
+
recordStat("read_count_deny", rereadBytes, Math.round(rereadBytes / 4));
|
|
12345
|
+
return denyOutput(
|
|
12346
|
+
"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."
|
|
12347
|
+
);
|
|
12348
|
+
}
|
|
12349
|
+
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
12350
|
+
if (rereadBytes >= REREAD_DENY_BYTES || reads >= 2) {
|
|
12351
|
+
return denyOutput(
|
|
12352
|
+
normalized + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
12353
|
+
);
|
|
12354
|
+
}
|
|
11936
12355
|
return contextOutput(
|
|
11937
12356
|
"Note: " + normalized + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
11938
12357
|
);
|
|
@@ -11943,11 +12362,16 @@ function preReadHandler(event) {
|
|
|
11943
12362
|
recordFileRead(normalized);
|
|
11944
12363
|
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Consider token-goat skeleton or token-goat section.";
|
|
11945
12364
|
recordStat("session_hint", size, Math.round(size / 4));
|
|
12365
|
+
if (size >= LARGE_FILE_DENY_BYTES) {
|
|
12366
|
+
return denyOutput(
|
|
12367
|
+
normalized + " is very large (" + kb + "KB). " + hint + " Use Read with offset/limit to sample specific sections."
|
|
12368
|
+
);
|
|
12369
|
+
}
|
|
11946
12370
|
return contextOutput(
|
|
11947
|
-
"Note: " + normalized + " is large (" + kb + "
|
|
12371
|
+
"Note: " + normalized + " is large (" + kb + "KB). " + hint
|
|
11948
12372
|
);
|
|
11949
12373
|
}
|
|
11950
|
-
const fileTypeExt =
|
|
12374
|
+
const fileTypeExt = path9.extname(normalized).slice(1).toLowerCase();
|
|
11951
12375
|
const binaryExts = /* @__PURE__ */ new Set(["pdf", "docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"]);
|
|
11952
12376
|
const textTypeExts = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv"]);
|
|
11953
12377
|
const fileStatSize = size ?? statSize(normalized) ?? 0;
|
|
@@ -11956,7 +12380,7 @@ function preReadHandler(event) {
|
|
|
11956
12380
|
let ftContent = "";
|
|
11957
12381
|
if (!binaryExts.has(fileTypeExt)) {
|
|
11958
12382
|
try {
|
|
11959
|
-
ftContent =
|
|
12383
|
+
ftContent = fs5.readFileSync(normalized, "utf8");
|
|
11960
12384
|
} catch {
|
|
11961
12385
|
}
|
|
11962
12386
|
}
|
|
@@ -11971,29 +12395,67 @@ function preReadHandler(event) {
|
|
|
11971
12395
|
}
|
|
11972
12396
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Read" });
|
|
11973
12397
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Grep" });
|
|
12398
|
+
function extractReadOutput(raw) {
|
|
12399
|
+
const resp = raw["tool_response"];
|
|
12400
|
+
if (typeof resp === "string") return resp;
|
|
12401
|
+
if (resp !== null && typeof resp === "object") {
|
|
12402
|
+
const r = resp;
|
|
12403
|
+
for (const key of ["output", "content", "text", "body"]) {
|
|
12404
|
+
if (typeof r[key] === "string") return r[key];
|
|
12405
|
+
}
|
|
12406
|
+
}
|
|
12407
|
+
return "";
|
|
12408
|
+
}
|
|
12409
|
+
function postReadHandler(event) {
|
|
12410
|
+
const filePath = getFilePath(event);
|
|
12411
|
+
if (filePath === void 0) return passOutput();
|
|
12412
|
+
const normalized = normalizePath(filePath);
|
|
12413
|
+
const respText = extractReadOutput(event.raw);
|
|
12414
|
+
if (respText.includes("[Truncated:") || respText.includes("Truncated: PARTIAL view")) {
|
|
12415
|
+
markFileTruncated(normalized);
|
|
12416
|
+
}
|
|
12417
|
+
const postBasename = path9.basename(normalized);
|
|
12418
|
+
if (/\.(md|mdx|rst|txt)$/i.test(postBasename) || isSessionArtifactFile(normalized)) {
|
|
12419
|
+
try {
|
|
12420
|
+
const sz = statSize(normalized);
|
|
12421
|
+
if (sz !== null && sz <= 256 * 1024) {
|
|
12422
|
+
const content = fs5.readFileSync(normalized);
|
|
12423
|
+
store(getSessionId(), normalized, content);
|
|
12424
|
+
}
|
|
12425
|
+
} catch {
|
|
12426
|
+
}
|
|
12427
|
+
}
|
|
12428
|
+
return passOutput();
|
|
12429
|
+
}
|
|
12430
|
+
registerHook("post_tool_use", postReadHandler, { toolName: "Read" });
|
|
11974
12431
|
|
|
11975
12432
|
// src/hooks_edit.ts
|
|
11976
12433
|
init_define_import_meta_env();
|
|
11977
|
-
import * as
|
|
12434
|
+
import * as path11 from "node:path";
|
|
11978
12435
|
|
|
11979
12436
|
// src/hooks_index.ts
|
|
11980
12437
|
init_define_import_meta_env();
|
|
11981
|
-
import * as
|
|
11982
|
-
import * as
|
|
12438
|
+
import * as fs6 from "node:fs";
|
|
12439
|
+
import * as path10 from "node:path";
|
|
11983
12440
|
function dirtyQueuePath() {
|
|
11984
|
-
return
|
|
12441
|
+
return path10.join(dataDir(), "queue", "dirty.txt");
|
|
11985
12442
|
}
|
|
11986
12443
|
function appendDirtyPath(normalizedPath) {
|
|
11987
12444
|
const queuePath = dirtyQueuePath();
|
|
11988
|
-
|
|
11989
|
-
|
|
12445
|
+
const dir = path10.dirname(queuePath);
|
|
12446
|
+
try {
|
|
12447
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
12448
|
+
} catch (e) {
|
|
12449
|
+
if (e.code !== "EEXIST" || !fs6.existsSync(dir)) throw e;
|
|
12450
|
+
}
|
|
12451
|
+
fs6.appendFileSync(queuePath, `${normalizedPath}
|
|
11990
12452
|
`);
|
|
11991
12453
|
}
|
|
11992
12454
|
function getDirtyPaths() {
|
|
11993
12455
|
const queuePath = dirtyQueuePath();
|
|
11994
12456
|
let raw;
|
|
11995
12457
|
try {
|
|
11996
|
-
raw =
|
|
12458
|
+
raw = fs6.readFileSync(queuePath, "utf8");
|
|
11997
12459
|
} catch {
|
|
11998
12460
|
return [];
|
|
11999
12461
|
}
|
|
@@ -12009,21 +12471,21 @@ function getDirtyPaths() {
|
|
|
12009
12471
|
}
|
|
12010
12472
|
function clearDirtyQueue() {
|
|
12011
12473
|
try {
|
|
12012
|
-
|
|
12474
|
+
fs6.rmSync(dirtyQueuePath(), { force: true });
|
|
12013
12475
|
} catch {
|
|
12014
12476
|
}
|
|
12015
12477
|
}
|
|
12016
12478
|
function preCompactIndexHandler(_event) {
|
|
12017
12479
|
const paths = getDirtyPaths();
|
|
12018
12480
|
if (paths.length > 0) {
|
|
12019
|
-
const sidecar =
|
|
12481
|
+
const sidecar = path10.join(dataDir(), "queue", "pending.txt");
|
|
12020
12482
|
try {
|
|
12021
|
-
|
|
12483
|
+
fs6.mkdirSync(path10.dirname(sidecar), { recursive: true });
|
|
12022
12484
|
atomicWriteBytes(sidecar, Buffer.from(`${paths.join("\n")}
|
|
12023
12485
|
`, "utf8"));
|
|
12486
|
+
clearDirtyQueue();
|
|
12024
12487
|
} catch {
|
|
12025
12488
|
}
|
|
12026
|
-
clearDirtyQueue();
|
|
12027
12489
|
}
|
|
12028
12490
|
return passOutput();
|
|
12029
12491
|
}
|
|
@@ -12036,10 +12498,11 @@ function postEditHandler(event) {
|
|
|
12036
12498
|
const normalized = normalizePath(filePath);
|
|
12037
12499
|
recordFileEdit(normalized);
|
|
12038
12500
|
appendDirtyPath(normalized);
|
|
12039
|
-
const editedBasename =
|
|
12501
|
+
const editedBasename = path11.basename(normalized);
|
|
12040
12502
|
if (/\.(md|mdx|markdown|rst)$/i.test(editedBasename)) {
|
|
12503
|
+
const escapedPath = normalized.replace(/`/g, "\\`");
|
|
12041
12504
|
return contextOutput(
|
|
12042
|
-
editedBasename + ' was edited. Use `token-goat section "' +
|
|
12505
|
+
editedBasename + ' was edited. Use `token-goat section "' + escapedPath + '::HeadingName"` to re-read a specific section rather than the full file.'
|
|
12043
12506
|
);
|
|
12044
12507
|
}
|
|
12045
12508
|
return passOutput();
|
|
@@ -12317,17 +12780,20 @@ init_define_import_meta_env();
|
|
|
12317
12780
|
|
|
12318
12781
|
// src/fingerprint.ts
|
|
12319
12782
|
init_define_import_meta_env();
|
|
12320
|
-
import { createHash } from "node:crypto";
|
|
12321
|
-
import * as
|
|
12783
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12784
|
+
import * as fs7 from "node:fs";
|
|
12322
12785
|
function fingerprintContent(content) {
|
|
12323
|
-
const hash =
|
|
12786
|
+
const hash = createHash2("sha256");
|
|
12324
12787
|
hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
|
|
12325
12788
|
return hash.digest("hex");
|
|
12326
12789
|
}
|
|
12790
|
+
function shortFingerprint(content) {
|
|
12791
|
+
return fingerprintContent(content).slice(0, 16);
|
|
12792
|
+
}
|
|
12327
12793
|
function fingerprintFile(filePath) {
|
|
12328
12794
|
let data;
|
|
12329
12795
|
try {
|
|
12330
|
-
data =
|
|
12796
|
+
data = fs7.readFileSync(filePath);
|
|
12331
12797
|
} catch {
|
|
12332
12798
|
return null;
|
|
12333
12799
|
}
|
|
@@ -12336,15 +12802,24 @@ function fingerprintFile(filePath) {
|
|
|
12336
12802
|
|
|
12337
12803
|
// src/bash_output_cache.ts
|
|
12338
12804
|
init_define_import_meta_env();
|
|
12339
|
-
import * as
|
|
12805
|
+
import * as fs8 from "fs/promises";
|
|
12340
12806
|
import { resolve as resolve3 } from "path";
|
|
12341
12807
|
var _byId = /* @__PURE__ */ new Map();
|
|
12342
12808
|
var _globsByKey = /* @__PURE__ */ new Map();
|
|
12343
12809
|
var _grepsByKey = /* @__PURE__ */ new Map();
|
|
12344
|
-
var
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12810
|
+
var COMMAND_PATTERNS = {
|
|
12811
|
+
gitMutable: /^\s*git\s+(diff|status)\b/i,
|
|
12812
|
+
gitImmutable: /^\s*git\s+show\s+[0-9a-f]{40}\b/i,
|
|
12813
|
+
gitDiffUnscoped: /^\s*git\s+diff\b/i,
|
|
12814
|
+
gitDiffScoped: /\s--\s+\S/,
|
|
12815
|
+
dirListing: /^\s*(?:ls|eza|exa|dir|Get-ChildItem|gci)\b/i,
|
|
12816
|
+
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,
|
|
12817
|
+
npmInstall: /^\s*npm\s+(?:-\S+\s+)*(?:install|ci)\b/i,
|
|
12818
|
+
npmAudit: /^\s*npm\s+(?:-\S+\s+)*audit\b(?!.*(?:--fix|fix)\b)/i,
|
|
12819
|
+
npmOutdated: /^\s*npm\s+(?:-\S+\s+)*outdated\b/i,
|
|
12820
|
+
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,
|
|
12821
|
+
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
|
|
12822
|
+
};
|
|
12348
12823
|
var DEP_LOCKFILES = {
|
|
12349
12824
|
npm: ["package-lock.json", "yarn.lock"],
|
|
12350
12825
|
pip: ["requirements.txt"],
|
|
@@ -12355,18 +12830,14 @@ var DEP_LOCKFILES = {
|
|
|
12355
12830
|
bundle: ["Gemfile.lock"],
|
|
12356
12831
|
composer: ["composer.lock"]
|
|
12357
12832
|
};
|
|
12358
|
-
function
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
}
|
|
12367
|
-
function isNpmInstallCommand(cmd) {
|
|
12368
|
-
return NPM_INSTALL_RE.test(cmd);
|
|
12369
|
-
}
|
|
12833
|
+
function isCommandOfType(cmd, type) {
|
|
12834
|
+
const pattern = COMMAND_PATTERNS[type];
|
|
12835
|
+
return pattern?.test(cmd) ?? false;
|
|
12836
|
+
}
|
|
12837
|
+
var isGitMutableCommand = (cmd) => isCommandOfType(cmd, "gitMutable");
|
|
12838
|
+
var isDirListingCommand = (cmd) => isCommandOfType(cmd, "dirListing");
|
|
12839
|
+
var isDepListCommand = (cmd) => isCommandOfType(cmd, "depList");
|
|
12840
|
+
var isNpmInstallCommand = (cmd) => isCommandOfType(cmd, "npmInstall");
|
|
12370
12841
|
async function gitStateFingerprint(cwd) {
|
|
12371
12842
|
try {
|
|
12372
12843
|
const headResult = runGit(["rev-parse", "HEAD"], { cwd });
|
|
@@ -12374,21 +12845,21 @@ async function gitStateFingerprint(cwd) {
|
|
|
12374
12845
|
const headSha = headResult.stdout.trim();
|
|
12375
12846
|
let indexMtime = "";
|
|
12376
12847
|
try {
|
|
12377
|
-
const stat3 = await
|
|
12848
|
+
const stat3 = await fs8.stat(resolve3(cwd, ".git", "index"));
|
|
12378
12849
|
indexMtime = stat3.mtimeMs.toString();
|
|
12379
12850
|
} catch {
|
|
12380
12851
|
}
|
|
12381
12852
|
const key = `${headSha}\0${indexMtime}`;
|
|
12382
|
-
return
|
|
12853
|
+
return shortFingerprint(key);
|
|
12383
12854
|
} catch {
|
|
12384
12855
|
return null;
|
|
12385
12856
|
}
|
|
12386
12857
|
}
|
|
12387
|
-
async function dirStateFingerprint(
|
|
12858
|
+
async function dirStateFingerprint(path17) {
|
|
12388
12859
|
try {
|
|
12389
|
-
const stat3 = await
|
|
12860
|
+
const stat3 = await fs8.stat(path17);
|
|
12390
12861
|
if (!stat3.isDirectory()) return null;
|
|
12391
|
-
return
|
|
12862
|
+
return shortFingerprint(stat3.mtimeMs.toString());
|
|
12392
12863
|
} catch {
|
|
12393
12864
|
return null;
|
|
12394
12865
|
}
|
|
@@ -12402,8 +12873,8 @@ async function depLockfileFingerprint(cmd, cwd) {
|
|
|
12402
12873
|
if (!candidates) return null;
|
|
12403
12874
|
for (const lockfile of candidates) {
|
|
12404
12875
|
try {
|
|
12405
|
-
const content = await
|
|
12406
|
-
return
|
|
12876
|
+
const content = await fs8.readFile(resolve3(cwd, lockfile));
|
|
12877
|
+
return shortFingerprint(content);
|
|
12407
12878
|
} catch {
|
|
12408
12879
|
continue;
|
|
12409
12880
|
}
|
|
@@ -12451,7 +12922,7 @@ async function commandHash(command, cwd = null) {
|
|
|
12451
12922
|
const fp = await depLockfileFingerprint(command, cwd);
|
|
12452
12923
|
if (fp) key = `${key}\0npm-install:${fp}`;
|
|
12453
12924
|
}
|
|
12454
|
-
return
|
|
12925
|
+
return shortFingerprint(key);
|
|
12455
12926
|
}
|
|
12456
12927
|
function extractLsTarget(cmd, cwd) {
|
|
12457
12928
|
const tokens = cmd.trim().split(/\s+/);
|
|
@@ -12489,10 +12960,276 @@ function extractCommand(event) {
|
|
|
12489
12960
|
const cmd = event.toolInput["command"];
|
|
12490
12961
|
return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
|
|
12491
12962
|
}
|
|
12963
|
+
function isTempPath(fp) {
|
|
12964
|
+
const norm = fp.replace(/\\/g, "/");
|
|
12965
|
+
return /^\/tmp\//i.test(norm) || /\/var\/folders\//i.test(norm) || /AppData\/Local\/Temp\//i.test(norm) || norm.startsWith("/c/Users/") && norm.includes("/AppData/Local/Temp/");
|
|
12966
|
+
}
|
|
12967
|
+
function isOrchestratorStateFile(filePath) {
|
|
12968
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12969
|
+
return /^\.improve-state-/.test(basename7);
|
|
12970
|
+
}
|
|
12492
12971
|
function extractCatSourceFile(cmd) {
|
|
12493
|
-
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);
|
|
12972
|
+
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);
|
|
12494
12973
|
return m?.[1] ?? null;
|
|
12495
12974
|
}
|
|
12975
|
+
function extractCatFile(cmd) {
|
|
12976
|
+
const m = /^cat(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
12977
|
+
if (!m) return null;
|
|
12978
|
+
const filePath = m[1] ?? m[2] ?? m[3];
|
|
12979
|
+
if (filePath === void 0) return null;
|
|
12980
|
+
if (isTempPath(filePath)) return null;
|
|
12981
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12982
|
+
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
12983
|
+
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);
|
|
12984
|
+
if (!hasKnownExt && !isEnvFile) return null;
|
|
12985
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
12986
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12987
|
+
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
12988
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
12989
|
+
return { filePath, isDoc, isEnv, isConfig, isSql };
|
|
12990
|
+
}
|
|
12991
|
+
function extractRgSymbolSearch(cmd) {
|
|
12992
|
+
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
12993
|
+
if (!/-n\b/.test(cmd)) return null;
|
|
12994
|
+
const patternMatch = /["']([^"']+)["']/.exec(cmd);
|
|
12995
|
+
const pattern = patternMatch?.[1];
|
|
12996
|
+
if (!pattern) return null;
|
|
12997
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*(\|[A-Za-z_][A-Za-z0-9_]*)*$/.test(pattern)) return null;
|
|
12998
|
+
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);
|
|
12999
|
+
if (!fileMatch) return null;
|
|
13000
|
+
const filePath = fileMatch[1] ?? fileMatch[2] ?? fileMatch[3];
|
|
13001
|
+
if (!filePath) return null;
|
|
13002
|
+
if (isTempPath(filePath)) return null;
|
|
13003
|
+
if (/-[a-zA-Z]*r[a-zA-Z]*\b/.test(cmd) || /--recursive\b/.test(cmd)) return null;
|
|
13004
|
+
return { filePath, identifier: pattern };
|
|
13005
|
+
}
|
|
13006
|
+
function extractCatJsonPipe(cmd) {
|
|
13007
|
+
const m = /^cat\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*\|\s*jq\b/.exec(cmd);
|
|
13008
|
+
if (!m) return null;
|
|
13009
|
+
const filePath = m[1] ?? m[2] ?? m[3];
|
|
13010
|
+
if (!filePath) return null;
|
|
13011
|
+
if (isTempPath(filePath)) return null;
|
|
13012
|
+
if (!/\.(?:json|yaml|yml|toml)$/i.test(filePath)) return null;
|
|
13013
|
+
return { filePath };
|
|
13014
|
+
}
|
|
13015
|
+
function extractWslCatFile(cmd) {
|
|
13016
|
+
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);
|
|
13017
|
+
if (!wslMatch) return null;
|
|
13018
|
+
const drive = wslMatch[1]?.toUpperCase();
|
|
13019
|
+
const pathRest = wslMatch[2];
|
|
13020
|
+
if (!drive || !pathRest) return null;
|
|
13021
|
+
const filePath = drive + ":/" + pathRest;
|
|
13022
|
+
if (isTempPath(filePath)) return null;
|
|
13023
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
13024
|
+
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
13025
|
+
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);
|
|
13026
|
+
if (!hasKnownExt && !isEnvFile) return null;
|
|
13027
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
13028
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13029
|
+
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
13030
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
13031
|
+
return { filePath, isDoc, isEnv, isConfig, isSql };
|
|
13032
|
+
}
|
|
13033
|
+
function extractPythonFileRead(cmd) {
|
|
13034
|
+
if (!/python3?/.test(cmd)) return null;
|
|
13035
|
+
if (/open\s*\([^)]*,\s*['"][wa]/i.test(cmd) || /\.write\s*\(/.test(cmd)) return null;
|
|
13036
|
+
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;
|
|
13037
|
+
const heredocMatch = /^python3?\s+-\s+<<\s*'?(\w+)'?\s*\n([\s\S]*?)\n\1\s*$/.exec(cmd);
|
|
13038
|
+
if (heredocMatch) {
|
|
13039
|
+
const body = heredocMatch[2] ?? "";
|
|
13040
|
+
if (/open\s*\([^)]*,\s*['"][wa]/i.test(body) || /\.write\s*\(/.test(body) || /\.writelines\s*\(/.test(body)) return null;
|
|
13041
|
+
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);
|
|
13042
|
+
if (heredocOpen?.[1]) {
|
|
13043
|
+
const filePath = heredocOpen[1];
|
|
13044
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13045
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13046
|
+
return { filePath, isDoc };
|
|
13047
|
+
}
|
|
13048
|
+
if (/open\s*\(/.test(body)) {
|
|
13049
|
+
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);
|
|
13050
|
+
if (literal?.[1]) {
|
|
13051
|
+
const filePath = literal[1];
|
|
13052
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13053
|
+
if (OPEN_EXT.test(filePath)) {
|
|
13054
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13055
|
+
return { filePath, isDoc };
|
|
13056
|
+
}
|
|
13057
|
+
}
|
|
13058
|
+
}
|
|
13059
|
+
return null;
|
|
13060
|
+
}
|
|
13061
|
+
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);
|
|
13062
|
+
if (direct) {
|
|
13063
|
+
const filePath = direct[1] ?? "";
|
|
13064
|
+
if (!filePath) return null;
|
|
13065
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13066
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13067
|
+
return { filePath, isDoc };
|
|
13068
|
+
}
|
|
13069
|
+
if (/open\s*\(/.test(cmd)) {
|
|
13070
|
+
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(cmd);
|
|
13071
|
+
if (literal) {
|
|
13072
|
+
const filePath = literal[1] ?? "";
|
|
13073
|
+
if (filePath) {
|
|
13074
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13075
|
+
if (OPEN_EXT.test(filePath)) {
|
|
13076
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
13077
|
+
return { filePath, isDoc };
|
|
13078
|
+
}
|
|
13079
|
+
}
|
|
13080
|
+
}
|
|
13081
|
+
}
|
|
13082
|
+
return null;
|
|
13083
|
+
}
|
|
13084
|
+
function extractHeadFile(cmd) {
|
|
13085
|
+
const m = /^head(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13086
|
+
if (!m) return null;
|
|
13087
|
+
const n = parseInt(m[1] ?? m[2] ?? "0", 10);
|
|
13088
|
+
if (n < 10) return null;
|
|
13089
|
+
const filePath = m[3] ?? m[4] ?? m[5];
|
|
13090
|
+
if (filePath === void 0) return null;
|
|
13091
|
+
if (isTempPath(filePath)) return null;
|
|
13092
|
+
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
13093
|
+
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
13094
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
13095
|
+
return { filePath, isDoc, isConfig };
|
|
13096
|
+
}
|
|
13097
|
+
function extractNodeFileRead(cmd) {
|
|
13098
|
+
if (!/^node\s+-e/.test(cmd)) return null;
|
|
13099
|
+
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);
|
|
13100
|
+
if (readSync?.[1]) {
|
|
13101
|
+
const filePath = readSync[1];
|
|
13102
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13103
|
+
if (isTempPath(filePath)) return null;
|
|
13104
|
+
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
13105
|
+
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
13106
|
+
return { filePath, isDoc, isConfig };
|
|
13107
|
+
}
|
|
13108
|
+
const requireM = /require\(['"]([^'"]+\.json)['"]\)/i.exec(cmd);
|
|
13109
|
+
if (requireM?.[1]) {
|
|
13110
|
+
const filePath = requireM[1];
|
|
13111
|
+
if (filePath.includes("node_modules")) return null;
|
|
13112
|
+
if (isOrchestratorStateFile(filePath)) return null;
|
|
13113
|
+
if (isTempPath(filePath)) return null;
|
|
13114
|
+
return { filePath, isDoc: false, isConfig: true };
|
|
13115
|
+
}
|
|
13116
|
+
return null;
|
|
13117
|
+
}
|
|
13118
|
+
function extractTailFile(cmd) {
|
|
13119
|
+
if (/-f\b/.test(cmd)) return null;
|
|
13120
|
+
if (/-c\b/.test(cmd)) return null;
|
|
13121
|
+
if (/-n\s*\+/.test(cmd)) return null;
|
|
13122
|
+
const m = /^tail(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13123
|
+
if (!m) return null;
|
|
13124
|
+
const n = parseInt(m[1] ?? m[2] ?? "0", 10);
|
|
13125
|
+
if (n <= 10) return null;
|
|
13126
|
+
const filePath = m[3] ?? m[4] ?? m[5];
|
|
13127
|
+
if (!filePath) return null;
|
|
13128
|
+
if (isTempPath(filePath)) return null;
|
|
13129
|
+
if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
|
|
13130
|
+
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
13131
|
+
return { filePath, isDoc };
|
|
13132
|
+
}
|
|
13133
|
+
function extractTasksOutput(cmd) {
|
|
13134
|
+
const taskOutputRe = /[/\\]tasks[/\\]([a-z0-9]+)\.output$/;
|
|
13135
|
+
const catM = /^cat(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13136
|
+
if (catM) {
|
|
13137
|
+
const fp = catM[1] ?? catM[2] ?? catM[3];
|
|
13138
|
+
if (fp) {
|
|
13139
|
+
const m = taskOutputRe.exec(fp);
|
|
13140
|
+
if (m) return { id: m[1] };
|
|
13141
|
+
}
|
|
13142
|
+
}
|
|
13143
|
+
if (!/-f\b/.test(cmd) && !/-n\s*\+/.test(cmd)) {
|
|
13144
|
+
const tailM = /^tail(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13145
|
+
if (tailM) {
|
|
13146
|
+
const fp = tailM[3] ?? tailM[4] ?? tailM[5];
|
|
13147
|
+
if (fp) {
|
|
13148
|
+
const m = taskOutputRe.exec(fp);
|
|
13149
|
+
if (m) {
|
|
13150
|
+
const nStr = tailM[1] ?? tailM[2];
|
|
13151
|
+
const n = nStr !== void 0 ? parseInt(nStr, 10) : void 0;
|
|
13152
|
+
return n !== void 0 ? { id: m[1], n } : { id: m[1] };
|
|
13153
|
+
}
|
|
13154
|
+
}
|
|
13155
|
+
}
|
|
13156
|
+
const byteTailM = /^tail\s+-c\s+\d+\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
13157
|
+
if (byteTailM) {
|
|
13158
|
+
const fp = byteTailM[1] ?? byteTailM[2] ?? byteTailM[3];
|
|
13159
|
+
if (fp) {
|
|
13160
|
+
const m = taskOutputRe.exec(fp);
|
|
13161
|
+
if (m) return { id: m[1] };
|
|
13162
|
+
}
|
|
13163
|
+
}
|
|
13164
|
+
}
|
|
13165
|
+
return null;
|
|
13166
|
+
}
|
|
13167
|
+
function extractSedLineRange(cmd) {
|
|
13168
|
+
return /^sed\s+-n\s+['"]?\d+,\d+p['"]?/.test(cmd);
|
|
13169
|
+
}
|
|
13170
|
+
function extractDirectoryListing(cmd) {
|
|
13171
|
+
return /^eza\s+.*--long\s+\S+/.test(cmd) || /^eza\s+.*--tree/.test(cmd) || /^tree(\s|$)/.test(cmd) || /^ls\s+.*-[a-zA-Z]*R/.test(cmd) || /^ls\s+(?:-[la]+\s+)?(\S+)\s*[|]\s*head/.test(cmd);
|
|
13172
|
+
}
|
|
13173
|
+
function extractFindCommand(cmd) {
|
|
13174
|
+
if (!/^find\b/.test(cmd)) return null;
|
|
13175
|
+
const isXargsGrepL = /[|]\s*xargs\s+(?:grep|rg)\s+.*-l\b/.test(cmd) || /[|]\s*xargs\s+grep\s+-l\b/.test(cmd);
|
|
13176
|
+
const nameMatch = /-name\s+['"]([^'"]+)['"]/i.exec(cmd);
|
|
13177
|
+
const extGlob = nameMatch ? nameMatch[1] ?? null : null;
|
|
13178
|
+
return { extGlob, isXargsGrepL };
|
|
13179
|
+
}
|
|
13180
|
+
function extractMarkdownHeadingGrep(cmd) {
|
|
13181
|
+
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
13182
|
+
if (!/-n\b/.test(cmd)) return null;
|
|
13183
|
+
const hasHeadingPattern = /["']?\^#{1,6}["']?/.test(cmd) || /["']?\^#\+["']?/.test(cmd) || /["']?\^#\\+["']?/.test(cmd);
|
|
13184
|
+
if (!hasHeadingPattern) return null;
|
|
13185
|
+
const fileMatch = /(?:^|\s)(?:"([^"]+\.(?:md|markdown))"|'([^']+\.(?:md|markdown))'|([^\s"'|<>]+\.(?:md|markdown)))\s*(?:\||$)/.exec(cmd);
|
|
13186
|
+
if (!fileMatch) return null;
|
|
13187
|
+
const filePath = fileMatch[1] ?? fileMatch[2] ?? fileMatch[3];
|
|
13188
|
+
if (!filePath) return null;
|
|
13189
|
+
return { filePath };
|
|
13190
|
+
}
|
|
13191
|
+
function extractRgStructuralSearch(cmd) {
|
|
13192
|
+
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
13193
|
+
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);
|
|
13194
|
+
if (!hasStructural) return null;
|
|
13195
|
+
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);
|
|
13196
|
+
if (!fileMatch) return null;
|
|
13197
|
+
const filePath = fileMatch[1] ?? fileMatch[3] ?? fileMatch[4];
|
|
13198
|
+
if (!filePath) return null;
|
|
13199
|
+
if (isTempPath(filePath)) return null;
|
|
13200
|
+
return { filePath };
|
|
13201
|
+
}
|
|
13202
|
+
function extractGrepPipeChain(cmd) {
|
|
13203
|
+
return /^(?:rg|grep)\b.*\|\s*(?:rg|grep)\b/.test(cmd);
|
|
13204
|
+
}
|
|
13205
|
+
function extractCurlUrl(cmd) {
|
|
13206
|
+
const m = /(https?:\/\/[^\s'"]+)/.exec(cmd);
|
|
13207
|
+
return m?.[1] ?? null;
|
|
13208
|
+
}
|
|
13209
|
+
function isCurlGetCommand(cmd) {
|
|
13210
|
+
if (!/^curl\b/.test(cmd)) return false;
|
|
13211
|
+
if (/-X\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return false;
|
|
13212
|
+
if (/--request\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return false;
|
|
13213
|
+
if (/\s(?:-d|--data(?:-raw|-binary|-urlencode)?|-F|--form)\b/.test(cmd)) return false;
|
|
13214
|
+
if (/\s(?:-u|--user)\b/.test(cmd)) return false;
|
|
13215
|
+
if (/-H\s+['"]?Authorization/i.test(cmd)) return false;
|
|
13216
|
+
return true;
|
|
13217
|
+
}
|
|
13218
|
+
function extractCurlDownload(cmd) {
|
|
13219
|
+
if (!/^curl\b/.test(cmd)) return null;
|
|
13220
|
+
const outputMatch = /(?:^|\s)(?:-o|--output)\s+(?:"([^"]+)"|'([^']+)'|(\S+))/.exec(cmd);
|
|
13221
|
+
if (!outputMatch) return null;
|
|
13222
|
+
const outputPath = outputMatch[1] ?? outputMatch[2] ?? outputMatch[3];
|
|
13223
|
+
if (!outputPath) return null;
|
|
13224
|
+
if (/-X\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return null;
|
|
13225
|
+
if (/--request\s+(?:POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i.test(cmd)) return null;
|
|
13226
|
+
if (/(?:^|\s)(?:-d|--data(?:-raw|-binary|-urlencode)?|-F|--form)\b/.test(cmd)) return null;
|
|
13227
|
+
if (/(?:^|\s)(?:-u|--user)\b/.test(cmd)) return null;
|
|
13228
|
+
if (/-H\s+['"]?Authorization/i.test(cmd)) return null;
|
|
13229
|
+
const urlMatch = /(https?:\/\/[^\s'"]+)/.exec(cmd);
|
|
13230
|
+
if (!urlMatch?.[1]) return null;
|
|
13231
|
+
return { url: urlMatch[1], outputPath };
|
|
13232
|
+
}
|
|
12496
13233
|
function isTscCommand(cmd) {
|
|
12497
13234
|
return /^\s*tsc(\s|$)/i.test(cmd);
|
|
12498
13235
|
}
|
|
@@ -12512,9 +13249,133 @@ function buildRecallHint(cmd, outputId) {
|
|
|
12512
13249
|
function preBashHandler(event) {
|
|
12513
13250
|
const cmd = extractCommand(event);
|
|
12514
13251
|
if (cmd === void 0) return passOutput();
|
|
13252
|
+
const taskOutput = extractTasksOutput(cmd);
|
|
13253
|
+
if (taskOutput !== null) {
|
|
13254
|
+
const { id } = taskOutput;
|
|
13255
|
+
recordStat("session_hint", 0, 0);
|
|
13256
|
+
return denyOutput(
|
|
13257
|
+
"Use `token-goat bash-output " + id + "` to recall this task output (already cached). Append `--tail <n>` or `--grep PATTERN` to slice it."
|
|
13258
|
+
);
|
|
13259
|
+
}
|
|
13260
|
+
const findResult = extractFindCommand(cmd);
|
|
13261
|
+
if (findResult !== null) {
|
|
13262
|
+
const { extGlob, isXargsGrepL } = findResult;
|
|
13263
|
+
recordStat("session_hint", 0, 0);
|
|
13264
|
+
if (isXargsGrepL) {
|
|
13265
|
+
return denyOutput(
|
|
13266
|
+
"`find | xargs grep -l` is a slow symbol search. Use `token-goat refs <symbol>` or `rg -l <symbol>` for faster symbol-file discovery."
|
|
13267
|
+
);
|
|
13268
|
+
}
|
|
13269
|
+
const fdHint = extGlob ? "Use `fd '" + extGlob + "'` for faster file discovery (respects .gitignore)." : "Use `fd` for faster file discovery (respects .gitignore).";
|
|
13270
|
+
return contextOutput(
|
|
13271
|
+
"`find` is slow and ignores .gitignore. " + fdHint + " For symbol definitions, use `token-goat symbol <Name>`."
|
|
13272
|
+
);
|
|
13273
|
+
}
|
|
13274
|
+
if (extractDirectoryListing(cmd)) {
|
|
13275
|
+
recordStat("session_hint", 0, 0);
|
|
13276
|
+
return contextOutput(
|
|
13277
|
+
"Use `token-goat map --compact` (~300 tokens) for a repo overview, or `token-goat map <dir>` for a subdirectory."
|
|
13278
|
+
);
|
|
13279
|
+
}
|
|
13280
|
+
if (extractSedLineRange(cmd)) {
|
|
13281
|
+
recordStat("session_hint", 0, 0);
|
|
13282
|
+
return contextOutput(
|
|
13283
|
+
'Use `token-goat section "<file>::HeadingName"` to read one section instead of a line range.'
|
|
13284
|
+
);
|
|
13285
|
+
}
|
|
13286
|
+
const catJsonPipe = extractCatJsonPipe(cmd);
|
|
13287
|
+
if (catJsonPipe !== null) {
|
|
13288
|
+
const { filePath } = catJsonPipe;
|
|
13289
|
+
recordStat("session_hint", 0, 0);
|
|
13290
|
+
return contextOutput(
|
|
13291
|
+
'`cat | jq` loads the whole file. Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to slice one value.'
|
|
13292
|
+
);
|
|
13293
|
+
}
|
|
13294
|
+
const catResult = extractCatFile(cmd);
|
|
13295
|
+
if (catResult !== null) {
|
|
13296
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = catResult;
|
|
13297
|
+
recordStat("session_hint", 0, 0);
|
|
13298
|
+
if (isSql) {
|
|
13299
|
+
return contextOutput(
|
|
13300
|
+
'`cat` loads the entire file into context. Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
13301
|
+
);
|
|
13302
|
+
}
|
|
13303
|
+
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13304
|
+
return denyOutput("`cat` loads the entire file into context. " + hint);
|
|
13305
|
+
}
|
|
13306
|
+
const wslCatResult = extractWslCatFile(cmd);
|
|
13307
|
+
if (wslCatResult !== null) {
|
|
13308
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = wslCatResult;
|
|
13309
|
+
recordStat("session_hint", 0, 0);
|
|
13310
|
+
if (isSql) {
|
|
13311
|
+
return contextOutput(
|
|
13312
|
+
'`cat` loads the entire file into context. Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
|
|
13313
|
+
);
|
|
13314
|
+
}
|
|
13315
|
+
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13316
|
+
return denyOutput("`cat` loads the entire file into context. " + hint);
|
|
13317
|
+
}
|
|
13318
|
+
const pyRead = extractPythonFileRead(cmd);
|
|
13319
|
+
if (pyRead !== null) {
|
|
13320
|
+
const { filePath, isDoc } = pyRead;
|
|
13321
|
+
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
13322
|
+
recordStat("session_hint", 0, 0);
|
|
13323
|
+
return denyOutput("Python `open()` file reads bypass read hooks. " + hint);
|
|
13324
|
+
}
|
|
13325
|
+
const tailResult = extractTailFile(cmd);
|
|
13326
|
+
if (tailResult !== null) {
|
|
13327
|
+
const { filePath, isDoc } = tailResult;
|
|
13328
|
+
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
13329
|
+
recordStat("session_hint", 0, 0);
|
|
13330
|
+
return contextOutput("`tail` bypasses read hooks. " + hint);
|
|
13331
|
+
}
|
|
13332
|
+
const headResult = extractHeadFile(cmd);
|
|
13333
|
+
if (headResult !== null) {
|
|
13334
|
+
const { filePath, isDoc, isConfig } = headResult;
|
|
13335
|
+
const hint = 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"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
|
|
13336
|
+
recordStat("session_hint", 0, 0);
|
|
13337
|
+
return contextOutput("`head` bypasses read hooks. " + hint);
|
|
13338
|
+
}
|
|
13339
|
+
const nodeRead = extractNodeFileRead(cmd);
|
|
13340
|
+
if (nodeRead !== null) {
|
|
13341
|
+
const { filePath, isDoc, isConfig } = nodeRead;
|
|
13342
|
+
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
13343
|
+
recordStat("session_hint", 0, 0);
|
|
13344
|
+
return denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
|
|
13345
|
+
}
|
|
13346
|
+
if (extractGrepPipeChain(cmd)) {
|
|
13347
|
+
recordStat("session_hint", 0, 0);
|
|
13348
|
+
return contextOutput(
|
|
13349
|
+
"Collapse `grep | grep` into `rg -e PAT1 -e PAT2` (single pass). For symbol discovery: `token-goat refs <symbol>` or `token-goat semantic`."
|
|
13350
|
+
);
|
|
13351
|
+
}
|
|
13352
|
+
const mdHeadingGrep = extractMarkdownHeadingGrep(cmd);
|
|
13353
|
+
if (mdHeadingGrep !== null) {
|
|
13354
|
+
const { filePath } = mdHeadingGrep;
|
|
13355
|
+
recordStat("session_hint", 0, 0);
|
|
13356
|
+
return contextOutput(
|
|
13357
|
+
'Use `token-goat outline "' + filePath + '"` to get all headings with line ranges \u2014 then `token-goat section "' + filePath + '::Heading"` to read one section.'
|
|
13358
|
+
);
|
|
13359
|
+
}
|
|
13360
|
+
const rgSymbol = extractRgSymbolSearch(cmd);
|
|
13361
|
+
if (rgSymbol !== null) {
|
|
13362
|
+
const { identifier } = rgSymbol;
|
|
13363
|
+
recordStat("session_hint", 0, 0);
|
|
13364
|
+
return contextOutput(
|
|
13365
|
+
"Use `token-goat symbol " + identifier + "` to jump directly to the definition without scanning the file."
|
|
13366
|
+
);
|
|
13367
|
+
}
|
|
13368
|
+
const rgStructural = extractRgStructuralSearch(cmd);
|
|
13369
|
+
if (rgStructural !== null) {
|
|
13370
|
+
const { filePath } = rgStructural;
|
|
13371
|
+
recordStat("session_hint", 0, 0);
|
|
13372
|
+
return contextOutput(
|
|
13373
|
+
'Searching for code definitions with `rg`/`grep` is slower than surgical reads. Use `token-goat skeleton "' + filePath + '"` to see all symbols with line numbers, or `token-goat outline "' + filePath + '"` for symbols with docstrings and line ranges.'
|
|
13374
|
+
);
|
|
13375
|
+
}
|
|
12515
13376
|
const monitoringHint = getMonitoringRecallHint(cmd);
|
|
12516
13377
|
if (monitoringHint !== null) {
|
|
12517
|
-
const monCmdHash =
|
|
13378
|
+
const monCmdHash = shortFingerprint(cmd);
|
|
12518
13379
|
const monOutputId = getBashOutputId(monCmdHash);
|
|
12519
13380
|
if (monOutputId !== null) {
|
|
12520
13381
|
const monEntry = getBashOutput(monOutputId);
|
|
@@ -12533,8 +13394,32 @@ function preBashHandler(event) {
|
|
|
12533
13394
|
);
|
|
12534
13395
|
}
|
|
12535
13396
|
}
|
|
13397
|
+
const curlDl = extractCurlDownload(cmd);
|
|
13398
|
+
if (curlDl !== null) {
|
|
13399
|
+
const prevPath = getCurlDownloadPath(curlDl.url);
|
|
13400
|
+
if (prevPath !== null) {
|
|
13401
|
+
recordStat("session_hint", 0, 0);
|
|
13402
|
+
return denyOutput(
|
|
13403
|
+
"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.'
|
|
13404
|
+
);
|
|
13405
|
+
}
|
|
13406
|
+
}
|
|
13407
|
+
if (isCurlGetCommand(cmd)) {
|
|
13408
|
+
const curlCacheKey = extractCurlUrl(cmd) ?? cmd;
|
|
13409
|
+
const curlHash = shortFingerprint(curlCacheKey);
|
|
13410
|
+
const curlOutputId = getBashOutputId(curlHash);
|
|
13411
|
+
if (curlOutputId !== null) {
|
|
13412
|
+
const curlEntry = getBashOutput(curlOutputId);
|
|
13413
|
+
const curlBytes = curlEntry?.sizeBytes ?? 0;
|
|
13414
|
+
recordStat("bash_compress:recall", curlBytes, Math.round(curlBytes / 4));
|
|
13415
|
+
const curlPreview = cmd.length > 60 ? cmd.slice(0, 57) + "..." : cmd;
|
|
13416
|
+
return contextOutput(
|
|
13417
|
+
"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."
|
|
13418
|
+
);
|
|
13419
|
+
}
|
|
13420
|
+
}
|
|
12536
13421
|
if (!isBuildCommand(cmd)) return passOutput();
|
|
12537
|
-
const cmdHash =
|
|
13422
|
+
const cmdHash = shortFingerprint(cmd);
|
|
12538
13423
|
const outputId = getBashOutputId(cmdHash);
|
|
12539
13424
|
if (outputId === null) return passOutput();
|
|
12540
13425
|
const entry = getBashOutput(outputId);
|
|
@@ -12559,12 +13444,17 @@ async function postBashHandler(event) {
|
|
|
12559
13444
|
try {
|
|
12560
13445
|
const cmd = extractCommand(event);
|
|
12561
13446
|
if (cmd === void 0) return passOutput();
|
|
13447
|
+
const curlDl = extractCurlDownload(cmd);
|
|
13448
|
+
if (curlDl !== null) {
|
|
13449
|
+
recordCurlDownload(curlDl.url, curlDl.outputPath);
|
|
13450
|
+
}
|
|
12562
13451
|
const isMonitoring = getMonitoringRecallHint(cmd) !== null;
|
|
12563
|
-
if (!isMonitoring && !isBuildCommand(cmd)) return passOutput();
|
|
13452
|
+
if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) return passOutput();
|
|
12564
13453
|
const output = extractBashOutput(event.raw);
|
|
12565
13454
|
if (Buffer.byteLength(output, "utf-8") < MIN_CACHE_BYTES) return passOutput();
|
|
12566
13455
|
const cwd = typeof event.raw["cwd"] === "string" ? event.raw["cwd"] : null;
|
|
12567
|
-
const
|
|
13456
|
+
const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : cmd;
|
|
13457
|
+
const simpleHash = shortFingerprint(cacheKey);
|
|
12568
13458
|
const id = await storeBashOutput(cmd, output, 0, cwd);
|
|
12569
13459
|
recordBashOutput(simpleHash, id, Buffer.byteLength(output, "utf-8"));
|
|
12570
13460
|
} catch {
|
|
@@ -12575,8 +13465,8 @@ registerHook("post_tool_use", postBashHandler, { toolName: "Bash" });
|
|
|
12575
13465
|
|
|
12576
13466
|
// src/image_shrink.ts
|
|
12577
13467
|
init_define_import_meta_env();
|
|
12578
|
-
import * as
|
|
12579
|
-
import * as
|
|
13468
|
+
import * as fs9 from "node:fs";
|
|
13469
|
+
import * as path12 from "node:path";
|
|
12580
13470
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12581
13471
|
".png",
|
|
12582
13472
|
".jpg",
|
|
@@ -12603,7 +13493,7 @@ async function loadSharp() {
|
|
|
12603
13493
|
return _sharpCache;
|
|
12604
13494
|
}
|
|
12605
13495
|
function isImagePath(p) {
|
|
12606
|
-
return IMAGE_EXTENSIONS.has(
|
|
13496
|
+
return IMAGE_EXTENSIONS.has(path12.extname(p).toLowerCase());
|
|
12607
13497
|
}
|
|
12608
13498
|
async function shrinkImage(input, opts) {
|
|
12609
13499
|
const maxDimension = opts?.maxDimension ?? DEFAULT_MAX_DIMENSION;
|
|
@@ -12635,7 +13525,7 @@ async function shrinkImage(input, opts) {
|
|
|
12635
13525
|
}
|
|
12636
13526
|
function statSize2(absPath) {
|
|
12637
13527
|
try {
|
|
12638
|
-
const st =
|
|
13528
|
+
const st = fs9.statSync(absPath);
|
|
12639
13529
|
return st.isFile() ? st.size : null;
|
|
12640
13530
|
} catch {
|
|
12641
13531
|
return null;
|
|
@@ -12649,7 +13539,7 @@ async function preReadImageHandler(event) {
|
|
|
12649
13539
|
if (size === null || size < DEFAULT_SIZE_THRESHOLD_BYTES) return passOutput();
|
|
12650
13540
|
let input;
|
|
12651
13541
|
try {
|
|
12652
|
-
input =
|
|
13542
|
+
input = fs9.readFileSync(filePath);
|
|
12653
13543
|
} catch {
|
|
12654
13544
|
return passOutput();
|
|
12655
13545
|
}
|
|
@@ -12658,7 +13548,7 @@ async function preReadImageHandler(event) {
|
|
|
12658
13548
|
const saved = result.originalBytes - result.shrunkBytes;
|
|
12659
13549
|
const pct = Math.round(saved / result.originalBytes * 100);
|
|
12660
13550
|
const dataUrl = `data:image/${result.format};base64,${result.data.toString("base64")}`;
|
|
12661
|
-
const summary = `token-goat shrank ${
|
|
13551
|
+
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}).`;
|
|
12662
13552
|
return contextOutput(`${summary}
|
|
12663
13553
|
${dataUrl}`);
|
|
12664
13554
|
}
|
|
@@ -12737,7 +13627,7 @@ async function relay(eventName) {
|
|
|
12737
13627
|
|
|
12738
13628
|
// src/section_reader.ts
|
|
12739
13629
|
init_define_import_meta_env();
|
|
12740
|
-
import { readFileSync as
|
|
13630
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
12741
13631
|
function parseHeadingSpec(spec) {
|
|
12742
13632
|
const m = /^(.*?)#(\d+)$/.exec(spec);
|
|
12743
13633
|
if (m !== null && m[1] !== void 0 && m[2] !== void 0) {
|
|
@@ -12745,6 +13635,18 @@ function parseHeadingSpec(spec) {
|
|
|
12745
13635
|
}
|
|
12746
13636
|
return { base: spec.trim(), ordinal: null };
|
|
12747
13637
|
}
|
|
13638
|
+
function normalizeHeading(s) {
|
|
13639
|
+
let n = s.replace(/[—–]/g, "-");
|
|
13640
|
+
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
13641
|
+
n = n.replace(/^\d+\.\s+/, "");
|
|
13642
|
+
return n.replace(/\s+/g, " ").trim();
|
|
13643
|
+
}
|
|
13644
|
+
function normalizeHeadingStrip(s) {
|
|
13645
|
+
let n = s.replace(/\s*[—–].*$/, "");
|
|
13646
|
+
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
13647
|
+
n = n.replace(/^\d+\.\s+/, "");
|
|
13648
|
+
return n.replace(/\s+/g, " ").trim();
|
|
13649
|
+
}
|
|
12748
13650
|
var MARKDOWN_HEADER_RE = /^(#{1,6})\s+(.+?)\s*#*\s*$/;
|
|
12749
13651
|
var TABLE_HEADER_RE = /^\s*\[+\s*([^\]]+?)\s*\]+\s*$/;
|
|
12750
13652
|
var PYTHON_HEADER_RE = /^(\s*)(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)/;
|
|
@@ -12819,7 +13721,7 @@ function sectionEndIndex(headers, headerPos, totalLines) {
|
|
|
12819
13721
|
function readSection(filePath, headingSpec) {
|
|
12820
13722
|
let text;
|
|
12821
13723
|
try {
|
|
12822
|
-
text =
|
|
13724
|
+
text = readFileSync6(filePath, "utf-8");
|
|
12823
13725
|
} catch {
|
|
12824
13726
|
return null;
|
|
12825
13727
|
}
|
|
@@ -12829,10 +13731,15 @@ function readSection(filePath, headingSpec) {
|
|
|
12829
13731
|
const headers = findHeaders(text, language);
|
|
12830
13732
|
const lines = text.split("\n");
|
|
12831
13733
|
const target = base.toLowerCase();
|
|
13734
|
+
const normalizedTarget = normalizeHeading(base).toLowerCase();
|
|
13735
|
+
const strippedTarget = normalizeHeadingStrip(base).toLowerCase();
|
|
12832
13736
|
const matches = [];
|
|
12833
13737
|
for (let i = 0; i < headers.length; i++) {
|
|
12834
13738
|
const h = headers[i];
|
|
12835
|
-
if (h
|
|
13739
|
+
if (h === void 0) continue;
|
|
13740
|
+
if (h.heading.toLowerCase() === target || normalizeHeading(h.heading).toLowerCase() === normalizedTarget || normalizeHeadingStrip(h.heading).toLowerCase() === strippedTarget) {
|
|
13741
|
+
matches.push(i);
|
|
13742
|
+
}
|
|
12836
13743
|
}
|
|
12837
13744
|
if (matches.length === 0) return null;
|
|
12838
13745
|
const pick = ordinal === null ? 0 : ordinal - 1;
|
|
@@ -12856,9 +13763,9 @@ function readSection(filePath, headingSpec) {
|
|
|
12856
13763
|
|
|
12857
13764
|
// src/install.ts
|
|
12858
13765
|
init_define_import_meta_env();
|
|
12859
|
-
import * as
|
|
12860
|
-
import * as
|
|
12861
|
-
import * as
|
|
13766
|
+
import * as fs10 from "node:fs";
|
|
13767
|
+
import * as os3 from "node:os";
|
|
13768
|
+
import * as path13 from "node:path";
|
|
12862
13769
|
var HOOK_EVENT_MAP = [
|
|
12863
13770
|
["PreToolUse", "pre_tool_use"],
|
|
12864
13771
|
["PostToolUse", "post_tool_use"],
|
|
@@ -12869,13 +13776,13 @@ function hookCommand(eventArg) {
|
|
|
12869
13776
|
return `token-goat hook ${eventArg}`;
|
|
12870
13777
|
}
|
|
12871
13778
|
function settingsPath(scope) {
|
|
12872
|
-
const base = scope === "user" ?
|
|
12873
|
-
return
|
|
13779
|
+
const base = scope === "user" ? path13.join(os3.homedir(), ".claude") : path13.join(process.cwd(), ".claude");
|
|
13780
|
+
return path13.join(base, "settings.json");
|
|
12874
13781
|
}
|
|
12875
13782
|
function readSettings(p) {
|
|
12876
13783
|
let raw;
|
|
12877
13784
|
try {
|
|
12878
|
-
raw =
|
|
13785
|
+
raw = fs10.readFileSync(p, "utf8");
|
|
12879
13786
|
} catch {
|
|
12880
13787
|
return {};
|
|
12881
13788
|
}
|
|
@@ -12915,7 +13822,7 @@ function installHooks(scope = "user") {
|
|
|
12915
13822
|
return { scope, settingsPath: p, alreadyInstalled: true };
|
|
12916
13823
|
}
|
|
12917
13824
|
settings.hooks = hooks;
|
|
12918
|
-
|
|
13825
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
12919
13826
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
12920
13827
|
`);
|
|
12921
13828
|
return { scope, settingsPath: p, alreadyInstalled: false };
|
|
@@ -12954,7 +13861,7 @@ function uninstallHooks(scope = "user") {
|
|
|
12954
13861
|
} else {
|
|
12955
13862
|
settings.hooks = hooks;
|
|
12956
13863
|
}
|
|
12957
|
-
|
|
13864
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
12958
13865
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
12959
13866
|
`);
|
|
12960
13867
|
return true;
|
|
@@ -12963,21 +13870,21 @@ function uninstallHooks(scope = "user") {
|
|
|
12963
13870
|
// src/worker.ts
|
|
12964
13871
|
init_define_import_meta_env();
|
|
12965
13872
|
import { spawn } from "node:child_process";
|
|
12966
|
-
import * as
|
|
12967
|
-
import * as
|
|
13873
|
+
import * as fs11 from "node:fs";
|
|
13874
|
+
import * as path14 from "node:path";
|
|
12968
13875
|
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
|
|
12969
13876
|
import { fileURLToPath } from "node:url";
|
|
12970
13877
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
12971
13878
|
function dirtyQueuePathFor(dir) {
|
|
12972
|
-
return
|
|
13879
|
+
return path14.join(dir, "queue", "dirty.txt");
|
|
12973
13880
|
}
|
|
12974
13881
|
function workerPidPath(dir = dataDir()) {
|
|
12975
|
-
return
|
|
13882
|
+
return path14.join(dir, "worker.pid");
|
|
12976
13883
|
}
|
|
12977
13884
|
function getDirtyPathsFor(dir) {
|
|
12978
13885
|
let raw;
|
|
12979
13886
|
try {
|
|
12980
|
-
raw =
|
|
13887
|
+
raw = fs11.readFileSync(dirtyQueuePathFor(dir), "utf8");
|
|
12981
13888
|
} catch {
|
|
12982
13889
|
return [];
|
|
12983
13890
|
}
|
|
@@ -12993,7 +13900,7 @@ function getDirtyPathsFor(dir) {
|
|
|
12993
13900
|
}
|
|
12994
13901
|
function clearDirtyQueueFor(dir) {
|
|
12995
13902
|
try {
|
|
12996
|
-
|
|
13903
|
+
fs11.rmSync(dirtyQueuePathFor(dir), { force: true });
|
|
12997
13904
|
} catch {
|
|
12998
13905
|
}
|
|
12999
13906
|
}
|
|
@@ -13003,7 +13910,7 @@ function processDirtyBatch(paths, index = (absPath) => {
|
|
|
13003
13910
|
}) {
|
|
13004
13911
|
let indexed = 0;
|
|
13005
13912
|
for (const p of paths) {
|
|
13006
|
-
if (!
|
|
13913
|
+
if (!p || !fs11.existsSync(p)) continue;
|
|
13007
13914
|
const sha = fingerprintFile(p);
|
|
13008
13915
|
if (sha === null) continue;
|
|
13009
13916
|
index(p, sha);
|
|
@@ -13028,7 +13935,7 @@ function pidAlive(pid) {
|
|
|
13028
13935
|
}
|
|
13029
13936
|
function readPidFile(dir) {
|
|
13030
13937
|
try {
|
|
13031
|
-
const raw =
|
|
13938
|
+
const raw = fs11.readFileSync(workerPidPath(dir), "utf8").trim();
|
|
13032
13939
|
if (!/^\d+$/.test(raw)) return null;
|
|
13033
13940
|
return parseInt(raw, 10);
|
|
13034
13941
|
} catch {
|
|
@@ -13051,7 +13958,7 @@ function stopWorker(dir = dataDir()) {
|
|
|
13051
13958
|
}
|
|
13052
13959
|
}
|
|
13053
13960
|
try {
|
|
13054
|
-
|
|
13961
|
+
fs11.rmSync(workerPidPath(dir), { force: true });
|
|
13055
13962
|
} catch {
|
|
13056
13963
|
}
|
|
13057
13964
|
return alive;
|
|
@@ -13059,7 +13966,11 @@ function stopWorker(dir = dataDir()) {
|
|
|
13059
13966
|
function startDetachedWorker(opts) {
|
|
13060
13967
|
const pollIntervalMs = opts?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
13061
13968
|
const dir = opts?.dataDir ?? dataDir();
|
|
13062
|
-
|
|
13969
|
+
try {
|
|
13970
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13971
|
+
} catch (e) {
|
|
13972
|
+
if (e.code !== "EEXIST" || !fs11.existsSync(dir)) throw e;
|
|
13973
|
+
}
|
|
13063
13974
|
const child = spawn(
|
|
13064
13975
|
process.execPath,
|
|
13065
13976
|
[fileURLToPath(import.meta.url), "--worker-daemon"],
|
|
@@ -13078,7 +13989,7 @@ function startDetachedWorker(opts) {
|
|
|
13078
13989
|
if (pid === void 0) {
|
|
13079
13990
|
throw new Error("startDetachedWorker: spawn produced no pid");
|
|
13080
13991
|
}
|
|
13081
|
-
|
|
13992
|
+
fs11.writeFileSync(workerPidPath(dir), `${pid}
|
|
13082
13993
|
`);
|
|
13083
13994
|
child.unref();
|
|
13084
13995
|
return pid;
|
|
@@ -13121,7 +14032,7 @@ workerEntry();
|
|
|
13121
14032
|
|
|
13122
14033
|
// src/skill_cache.ts
|
|
13123
14034
|
init_define_import_meta_env();
|
|
13124
|
-
import * as
|
|
14035
|
+
import * as fs12 from "fs/promises";
|
|
13125
14036
|
import { resolve as resolve4 } from "path";
|
|
13126
14037
|
var COMPACT_END_MARKER = "<!-- COMPACT_END -->";
|
|
13127
14038
|
var _skillOutputsDirOverride = null;
|
|
@@ -13134,7 +14045,7 @@ function skillOutputsDir() {
|
|
|
13134
14045
|
}
|
|
13135
14046
|
async function ensureSkillsDir() {
|
|
13136
14047
|
try {
|
|
13137
|
-
await
|
|
14048
|
+
await fs12.mkdir(skillOutputsDir(), { recursive: true });
|
|
13138
14049
|
} catch {
|
|
13139
14050
|
}
|
|
13140
14051
|
}
|
|
@@ -13161,7 +14072,7 @@ function extractCompactFromMarker(body) {
|
|
|
13161
14072
|
const lines = body.split("\n");
|
|
13162
14073
|
for (let i = 0; i < lines.length; i++) {
|
|
13163
14074
|
const stripped = lines[i].trim();
|
|
13164
|
-
if (
|
|
14075
|
+
if (isCodeFenceDelimiter(stripped)) {
|
|
13165
14076
|
inCodeBlock = !inCodeBlock;
|
|
13166
14077
|
continue;
|
|
13167
14078
|
}
|
|
@@ -13176,14 +14087,14 @@ function extractCompactFromMarker(body) {
|
|
|
13176
14087
|
async function listOutputs() {
|
|
13177
14088
|
try {
|
|
13178
14089
|
const dir = skillOutputsDir();
|
|
13179
|
-
const entries = await
|
|
14090
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
13180
14091
|
const metas = [];
|
|
13181
14092
|
for (const entry of entries) {
|
|
13182
14093
|
if (!entry.isFile() || !entry.name.endsWith(".meta")) {
|
|
13183
14094
|
continue;
|
|
13184
14095
|
}
|
|
13185
14096
|
try {
|
|
13186
|
-
const content = await
|
|
14097
|
+
const content = await fs12.readFile(resolve4(dir, entry.name), "utf-8");
|
|
13187
14098
|
const meta = JSON.parse(content);
|
|
13188
14099
|
metas.push(meta);
|
|
13189
14100
|
} catch {
|
|
@@ -13228,13 +14139,13 @@ async function listSkills(sessionId) {
|
|
|
13228
14139
|
const compactFileId = `${safeSession}-${meta.skillName.replace(":", "_")}-compact`;
|
|
13229
14140
|
let compactLen = 0;
|
|
13230
14141
|
try {
|
|
13231
|
-
const stat3 = await
|
|
14142
|
+
const stat3 = await fs12.stat(resolve4(dir, compactFileId));
|
|
13232
14143
|
compactLen = stat3.size;
|
|
13233
14144
|
} catch {
|
|
13234
14145
|
compactLen = 0;
|
|
13235
14146
|
}
|
|
13236
14147
|
const hasMarker = extractCompactFromMarker(
|
|
13237
|
-
await
|
|
14148
|
+
await fs12.readFile(resolve4(dir, `${meta.outputId}.txt`), "utf-8").catch(() => "")
|
|
13238
14149
|
) !== null;
|
|
13239
14150
|
results.push({
|
|
13240
14151
|
name: meta.skillName,
|
|
@@ -13266,7 +14177,7 @@ async function getSkillFilePath(skillName) {
|
|
|
13266
14177
|
|
|
13267
14178
|
// src/config.ts
|
|
13268
14179
|
init_define_import_meta_env();
|
|
13269
|
-
import * as
|
|
14180
|
+
import * as fs13 from "node:fs";
|
|
13270
14181
|
|
|
13271
14182
|
// node_modules/smol-toml/dist/index.js
|
|
13272
14183
|
init_define_import_meta_env();
|
|
@@ -13998,8 +14909,8 @@ function envInt(key, defaultVal) {
|
|
|
13998
14909
|
}
|
|
13999
14910
|
|
|
14000
14911
|
// src/config.ts
|
|
14001
|
-
|
|
14002
|
-
|
|
14912
|
+
var CONFIG_DEFAULTS = {
|
|
14913
|
+
compact_assist: {
|
|
14003
14914
|
enabled: true,
|
|
14004
14915
|
triggers: ["manual", "auto"],
|
|
14005
14916
|
min_events: 3,
|
|
@@ -14014,10 +14925,8 @@ function defaultCompactAssistConfig() {
|
|
|
14014
14925
|
lazy_skill_injection: true,
|
|
14015
14926
|
max_manifest_chars: 1600,
|
|
14016
14927
|
harness: "auto"
|
|
14017
|
-
}
|
|
14018
|
-
|
|
14019
|
-
function defaultBashCompressConfig() {
|
|
14020
|
-
return {
|
|
14928
|
+
},
|
|
14929
|
+
bash_compress: {
|
|
14021
14930
|
enabled: true,
|
|
14022
14931
|
disabled_filters: [],
|
|
14023
14932
|
max_lines: 1e3,
|
|
@@ -14027,32 +14936,22 @@ function defaultBashCompressConfig() {
|
|
|
14027
14936
|
cache_max_file_count: 4096,
|
|
14028
14937
|
cache_max_bytes: 16 * 1024 * 1024,
|
|
14029
14938
|
cache_max_bytes_per_output: 50 * 1024 * 1024
|
|
14030
|
-
}
|
|
14031
|
-
|
|
14032
|
-
function defaultBashDiffConfig() {
|
|
14033
|
-
return {
|
|
14939
|
+
},
|
|
14940
|
+
bash_diff: {
|
|
14034
14941
|
max_hunks_per_file: 10,
|
|
14035
14942
|
hunk_density_cap: true
|
|
14036
|
-
}
|
|
14037
|
-
|
|
14038
|
-
function defaultSeverityLogConfig() {
|
|
14039
|
-
return {
|
|
14943
|
+
},
|
|
14944
|
+
bash_severity_log: {
|
|
14040
14945
|
context_lines: 3,
|
|
14041
14946
|
score_threshold: 0.5
|
|
14042
|
-
}
|
|
14043
|
-
|
|
14044
|
-
function defaultCodeCompressConfig() {
|
|
14045
|
-
return {
|
|
14947
|
+
},
|
|
14948
|
+
post_read_code_compress: {
|
|
14046
14949
|
min_lines: 200
|
|
14047
|
-
}
|
|
14048
|
-
|
|
14049
|
-
function defaultSessionBriefConfig() {
|
|
14050
|
-
return {
|
|
14950
|
+
},
|
|
14951
|
+
session_brief: {
|
|
14051
14952
|
enabled: true
|
|
14052
|
-
}
|
|
14053
|
-
|
|
14054
|
-
function defaultSkillPreservationConfig() {
|
|
14055
|
-
return {
|
|
14953
|
+
},
|
|
14954
|
+
skill_preservation: {
|
|
14056
14955
|
enabled: true,
|
|
14057
14956
|
max_cache_bytes: 5 * 1024 * 1024,
|
|
14058
14957
|
orphan_sweep_enabled: true,
|
|
@@ -14064,25 +14963,19 @@ function defaultSkillPreservationConfig() {
|
|
|
14064
14963
|
pre_skill_enabled: true,
|
|
14065
14964
|
first_load_compact: false,
|
|
14066
14965
|
post_compact_full_loads: false
|
|
14067
|
-
}
|
|
14068
|
-
|
|
14069
|
-
function defaultCuratorConfig() {
|
|
14070
|
-
return {
|
|
14966
|
+
},
|
|
14967
|
+
curator: {
|
|
14071
14968
|
enabled: true,
|
|
14072
14969
|
min_samples: 10,
|
|
14073
14970
|
threshold_pct: 20
|
|
14074
|
-
}
|
|
14075
|
-
|
|
14076
|
-
function defaultHintBudgetConfig() {
|
|
14077
|
-
return {
|
|
14971
|
+
},
|
|
14972
|
+
hint_budget: {
|
|
14078
14973
|
enabled: true,
|
|
14079
14974
|
max_per_session: 100,
|
|
14080
14975
|
max_structured_per_session: 30,
|
|
14081
14976
|
max_index_only_per_session: 30
|
|
14082
|
-
}
|
|
14083
|
-
|
|
14084
|
-
function defaultImageShrinkConfig() {
|
|
14085
|
-
return {
|
|
14977
|
+
},
|
|
14978
|
+
image_shrink: {
|
|
14086
14979
|
prefer_avif: true,
|
|
14087
14980
|
avif_quality: 60,
|
|
14088
14981
|
jpeg_quality: 75,
|
|
@@ -14090,27 +14983,19 @@ function defaultImageShrinkConfig() {
|
|
|
14090
14983
|
orphan_sweep_enabled: true,
|
|
14091
14984
|
orphan_age_secs: 604800,
|
|
14092
14985
|
screenshot_redirect: true
|
|
14093
|
-
}
|
|
14094
|
-
|
|
14095
|
-
function defaultRepomapConfig() {
|
|
14096
|
-
return {
|
|
14986
|
+
},
|
|
14987
|
+
repomap: {
|
|
14097
14988
|
compact_file_threshold: 50,
|
|
14098
14989
|
exclude_tests: true
|
|
14099
|
-
}
|
|
14100
|
-
|
|
14101
|
-
function defaultOverflowGuardConfig() {
|
|
14102
|
-
return {
|
|
14990
|
+
},
|
|
14991
|
+
overflow_guard: {
|
|
14103
14992
|
enabled: true,
|
|
14104
14993
|
max_tokens: 25e3
|
|
14105
|
-
}
|
|
14106
|
-
|
|
14107
|
-
function defaultStatsConfig() {
|
|
14108
|
-
return {
|
|
14994
|
+
},
|
|
14995
|
+
stats: {
|
|
14109
14996
|
record_zero_savings: false
|
|
14110
|
-
}
|
|
14111
|
-
|
|
14112
|
-
function defaultHintsConfig() {
|
|
14113
|
-
return {
|
|
14997
|
+
},
|
|
14998
|
+
hints: {
|
|
14114
14999
|
suppress_after_ignored: 5,
|
|
14115
15000
|
quiet_hours: "",
|
|
14116
15001
|
json_sidecar: false,
|
|
@@ -14134,51 +15019,40 @@ function defaultHintsConfig() {
|
|
|
14134
15019
|
truncated_read_min_lines: 200,
|
|
14135
15020
|
protect_recent_reads: 4,
|
|
14136
15021
|
prompt_triggers: []
|
|
14137
|
-
}
|
|
14138
|
-
|
|
14139
|
-
function defaultHooksConfig() {
|
|
14140
|
-
return {
|
|
15022
|
+
},
|
|
15023
|
+
hooks: {
|
|
14141
15024
|
watchdog_ms: 700
|
|
14142
|
-
}
|
|
14143
|
-
|
|
14144
|
-
function defaultWebFetchConfig() {
|
|
14145
|
-
return {
|
|
15025
|
+
},
|
|
15026
|
+
webfetch: {
|
|
14146
15027
|
allow: [],
|
|
14147
15028
|
deny: [],
|
|
14148
15029
|
max_file_count: 4096,
|
|
14149
15030
|
max_bytes: 32 * 1024 * 1024,
|
|
14150
15031
|
compress_bodies: true,
|
|
14151
15032
|
compress_min_bytes: 16 * 1024
|
|
14152
|
-
}
|
|
14153
|
-
|
|
14154
|
-
function defaultWorkerConfig() {
|
|
14155
|
-
return {
|
|
15033
|
+
},
|
|
15034
|
+
worker: {
|
|
14156
15035
|
watchdog_enabled: true,
|
|
14157
15036
|
max_pool_workers: 4,
|
|
14158
15037
|
blocked_roots: []
|
|
14159
|
-
}
|
|
14160
|
-
|
|
14161
|
-
function defaultIndexingConfig() {
|
|
14162
|
-
return {
|
|
15038
|
+
},
|
|
15039
|
+
indexing: {
|
|
14163
15040
|
large_file_symbol_only_kb: 500,
|
|
14164
15041
|
large_file_skip_kb: 2048,
|
|
14165
15042
|
skip_dirs: []
|
|
14166
|
-
}
|
|
14167
|
-
|
|
14168
|
-
function defaultCompressionConfig() {
|
|
14169
|
-
return {
|
|
15043
|
+
},
|
|
15044
|
+
compression: {
|
|
14170
15045
|
profile: "auto"
|
|
14171
|
-
}
|
|
14172
|
-
|
|
14173
|
-
function defaultContextConfig() {
|
|
14174
|
-
return {
|
|
15046
|
+
},
|
|
15047
|
+
context: {
|
|
14175
15048
|
model_window_tokens: 2e5
|
|
14176
|
-
}
|
|
14177
|
-
|
|
14178
|
-
function defaultInjectionConfig() {
|
|
14179
|
-
return {
|
|
15049
|
+
},
|
|
15050
|
+
injection: {
|
|
14180
15051
|
enabled: true
|
|
14181
|
-
}
|
|
15052
|
+
}
|
|
15053
|
+
};
|
|
15054
|
+
function getDefaultConfig(section2) {
|
|
15055
|
+
return structuredClone(CONFIG_DEFAULTS[section2] ?? {});
|
|
14182
15056
|
}
|
|
14183
15057
|
function validatedBool(raw, def) {
|
|
14184
15058
|
if (typeof raw === "boolean") return raw;
|
|
@@ -14251,7 +15125,7 @@ function loadConfig() {
|
|
|
14251
15125
|
const p = configPath();
|
|
14252
15126
|
let currentMtime = 0;
|
|
14253
15127
|
try {
|
|
14254
|
-
currentMtime =
|
|
15128
|
+
currentMtime = fs13.statSync(p).mtimeMs;
|
|
14255
15129
|
} catch {
|
|
14256
15130
|
}
|
|
14257
15131
|
const envFp = configEnvFingerprint();
|
|
@@ -14261,7 +15135,7 @@ function loadConfig() {
|
|
|
14261
15135
|
let raw = {};
|
|
14262
15136
|
if (currentMtime !== 0) {
|
|
14263
15137
|
try {
|
|
14264
|
-
const text =
|
|
15138
|
+
const text = fs13.readFileSync(p, "utf8");
|
|
14265
15139
|
raw = parse(text);
|
|
14266
15140
|
} catch {
|
|
14267
15141
|
}
|
|
@@ -14272,7 +15146,7 @@ function loadConfig() {
|
|
|
14272
15146
|
}
|
|
14273
15147
|
function _buildConfig(raw) {
|
|
14274
15148
|
const ca_raw = section(raw, "compact_assist");
|
|
14275
|
-
const ca =
|
|
15149
|
+
const ca = getDefaultConfig("compact_assist");
|
|
14276
15150
|
ca.enabled = validatedBool(ca_raw["enabled"], ca.enabled);
|
|
14277
15151
|
ca.triggers = validatedStrList(ca_raw["triggers"], ca.triggers);
|
|
14278
15152
|
ca.min_events = validatedInt(ca_raw["min_events"], ca.min_events, 0, 1e3);
|
|
@@ -14290,7 +15164,7 @@ function _buildConfig(raw) {
|
|
|
14290
15164
|
ca.enabled = envBool("TOKEN_GOAT_COMPACT_ASSIST", envBool("TOKENWISE_COMPACT_ASSIST", ca.enabled));
|
|
14291
15165
|
ca.lazy_skill_injection = envBool("TOKEN_GOAT_LAZY_SKILL_INJECTION", ca.lazy_skill_injection);
|
|
14292
15166
|
const bc_raw = section(raw, "bash_compress");
|
|
14293
|
-
const bc =
|
|
15167
|
+
const bc = getDefaultConfig("bash_compress");
|
|
14294
15168
|
bc.enabled = validatedBool(bc_raw["enabled"], bc.enabled);
|
|
14295
15169
|
bc.disabled_filters = validatedStrList(bc_raw["disabled_filters"], bc.disabled_filters);
|
|
14296
15170
|
bc.max_lines = validatedInt(bc_raw["max_lines"], bc.max_lines, 50, 1e5);
|
|
@@ -14306,22 +15180,22 @@ function _buildConfig(raw) {
|
|
|
14306
15180
|
bc.cache_max_bytes = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES", bc.cache_max_bytes);
|
|
14307
15181
|
bc.cache_max_bytes_per_output = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT", bc.cache_max_bytes_per_output);
|
|
14308
15182
|
const bd_raw = section(raw, "bash_diff");
|
|
14309
|
-
const bd =
|
|
15183
|
+
const bd = getDefaultConfig("bash_diff");
|
|
14310
15184
|
bd.max_hunks_per_file = validatedInt(bd_raw["max_hunks_per_file"], bd.max_hunks_per_file, 1, 1e4);
|
|
14311
15185
|
bd.hunk_density_cap = validatedBool(bd_raw["hunk_density_cap"], bd.hunk_density_cap);
|
|
14312
15186
|
const sl_raw = section(raw, "bash_severity_log");
|
|
14313
|
-
const sl =
|
|
15187
|
+
const sl = getDefaultConfig("bash_severity_log");
|
|
14314
15188
|
sl.context_lines = validatedInt(sl_raw["context_lines"], sl.context_lines, 0, 100);
|
|
14315
15189
|
sl.score_threshold = validatedFloat(sl_raw["score_threshold"], sl.score_threshold, 0, 1);
|
|
14316
15190
|
const cc_raw = section(raw, "post_read_code_compress");
|
|
14317
|
-
const cc =
|
|
15191
|
+
const cc = getDefaultConfig("post_read_code_compress");
|
|
14318
15192
|
cc.min_lines = validatedInt(cc_raw["min_lines"], cc.min_lines, 0, 1e6);
|
|
14319
15193
|
const sb_raw = section(raw, "session_brief");
|
|
14320
|
-
const sb =
|
|
15194
|
+
const sb = getDefaultConfig("session_brief");
|
|
14321
15195
|
sb.enabled = validatedBool(sb_raw["enabled"], sb.enabled);
|
|
14322
15196
|
sb.enabled = envBool("TOKEN_GOAT_SESSION_BRIEF", sb.enabled);
|
|
14323
15197
|
const sp_raw = section(raw, "skill_preservation");
|
|
14324
|
-
const sp =
|
|
15198
|
+
const sp = getDefaultConfig("skill_preservation");
|
|
14325
15199
|
sp.enabled = validatedBool(sp_raw["enabled"], sp.enabled);
|
|
14326
15200
|
sp.max_cache_bytes = validatedInt(sp_raw["max_cache_bytes"], sp.max_cache_bytes, 64 * 1024, 512 * 1024 * 1024);
|
|
14327
15201
|
sp.orphan_sweep_enabled = validatedBool(sp_raw["orphan_sweep_enabled"], sp.orphan_sweep_enabled);
|
|
@@ -14338,7 +15212,7 @@ function _buildConfig(raw) {
|
|
|
14338
15212
|
sp.pre_skill_enabled = envBool("TOKEN_GOAT_PRE_SKILL", sp.pre_skill_enabled);
|
|
14339
15213
|
sp.orphan_sweep_enabled = envBool("TOKEN_GOAT_ORPHAN_SWEEP", sp.orphan_sweep_enabled);
|
|
14340
15214
|
const is_raw = section(raw, "image_shrink");
|
|
14341
|
-
const is_cfg =
|
|
15215
|
+
const is_cfg = getDefaultConfig("image_shrink");
|
|
14342
15216
|
is_cfg.prefer_avif = validatedBool(is_raw["prefer_avif"], is_cfg.prefer_avif);
|
|
14343
15217
|
is_cfg.avif_quality = validatedInt(is_raw["avif_quality"], is_cfg.avif_quality, 1, 100);
|
|
14344
15218
|
is_cfg.jpeg_quality = validatedInt(is_raw["jpeg_quality"], is_cfg.jpeg_quality, 1, 100);
|
|
@@ -14349,33 +15223,33 @@ function _buildConfig(raw) {
|
|
|
14349
15223
|
is_cfg.prefer_avif = envBool("TOKEN_GOAT_PREFER_AVIF", is_cfg.prefer_avif);
|
|
14350
15224
|
is_cfg.max_image_pixels = envInt("TOKEN_GOAT_MAX_IMAGE_PIXELS", is_cfg.max_image_pixels);
|
|
14351
15225
|
const cur_raw = section(raw, "curator");
|
|
14352
|
-
const cur =
|
|
15226
|
+
const cur = getDefaultConfig("curator");
|
|
14353
15227
|
cur.enabled = validatedBool(cur_raw["enabled"], cur.enabled);
|
|
14354
15228
|
cur.min_samples = validatedInt(cur_raw["min_samples"], cur.min_samples, 0, 1e4);
|
|
14355
15229
|
cur.threshold_pct = validatedInt(cur_raw["threshold_pct"], cur.threshold_pct, 0, 100);
|
|
14356
15230
|
cur.enabled = envBool("TOKEN_GOAT_CURATOR", cur.enabled);
|
|
14357
15231
|
const hb_raw = section(raw, "hint_budget");
|
|
14358
|
-
const hb =
|
|
15232
|
+
const hb = getDefaultConfig("hint_budget");
|
|
14359
15233
|
hb.enabled = validatedBool(hb_raw["enabled"], hb.enabled);
|
|
14360
15234
|
hb.max_per_session = validatedInt(hb_raw["max_per_session"], hb.max_per_session, 0, 1e6);
|
|
14361
15235
|
hb.max_structured_per_session = validatedInt(hb_raw["max_structured_per_session"], hb.max_structured_per_session, 0, 1e6);
|
|
14362
15236
|
hb.max_index_only_per_session = validatedInt(hb_raw["max_index_only_per_session"], hb.max_index_only_per_session, 0, 1e6);
|
|
14363
15237
|
hb.enabled = envBool("TOKEN_GOAT_HINT_BUDGET", hb.enabled);
|
|
14364
15238
|
const rm_raw = section(raw, "repomap");
|
|
14365
|
-
const rm =
|
|
15239
|
+
const rm = getDefaultConfig("repomap");
|
|
14366
15240
|
rm.compact_file_threshold = validatedInt(rm_raw["compact_file_threshold"], rm.compact_file_threshold, 0, 1e5);
|
|
14367
15241
|
rm.exclude_tests = validatedBool(rm_raw["exclude_tests"], rm.exclude_tests);
|
|
14368
15242
|
rm.compact_file_threshold = envInt("TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD", rm.compact_file_threshold);
|
|
14369
15243
|
rm.exclude_tests = envBool("TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS", rm.exclude_tests);
|
|
14370
15244
|
const og_raw = section(raw, "overflow_guard");
|
|
14371
|
-
const og =
|
|
15245
|
+
const og = getDefaultConfig("overflow_guard");
|
|
14372
15246
|
og.enabled = validatedBool(og_raw["enabled"], og.enabled);
|
|
14373
15247
|
og.max_tokens = validatedInt(og_raw["max_tokens"], og.max_tokens, 1e3, 1e6);
|
|
14374
15248
|
const st_raw = section(raw, "stats");
|
|
14375
|
-
const st =
|
|
15249
|
+
const st = getDefaultConfig("stats");
|
|
14376
15250
|
st.record_zero_savings = validatedBool(st_raw["record_zero_savings"], st.record_zero_savings);
|
|
14377
15251
|
const hi_raw = section(raw, "hints");
|
|
14378
|
-
const hi =
|
|
15252
|
+
const hi = getDefaultConfig("hints");
|
|
14379
15253
|
hi.suppress_after_ignored = validatedInt(hi_raw["suppress_after_ignored"], hi.suppress_after_ignored, 0, 1e3);
|
|
14380
15254
|
hi.quiet_hours = validatedStr(hi_raw["quiet_hours"], hi.quiet_hours);
|
|
14381
15255
|
hi.json_sidecar = validatedBool(hi_raw["json_sidecar"], hi.json_sidecar);
|
|
@@ -14408,11 +15282,11 @@ function _buildConfig(raw) {
|
|
|
14408
15282
|
})).filter((t) => t.keywords.length > 0 && t.hint.length > 0);
|
|
14409
15283
|
}
|
|
14410
15284
|
const hk_raw = section(raw, "hooks");
|
|
14411
|
-
const hk =
|
|
15285
|
+
const hk = getDefaultConfig("hooks");
|
|
14412
15286
|
hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, 100, 3e4);
|
|
14413
15287
|
hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms);
|
|
14414
15288
|
const wf_raw = section(raw, "webfetch");
|
|
14415
|
-
const wf =
|
|
15289
|
+
const wf = getDefaultConfig("webfetch");
|
|
14416
15290
|
wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
|
|
14417
15291
|
wf.deny = validatedStrList(wf_raw["deny"], wf.deny);
|
|
14418
15292
|
wf.max_file_count = validatedInt(wf_raw["max_file_count"], wf.max_file_count, 0, 1e7);
|
|
@@ -14421,27 +15295,27 @@ function _buildConfig(raw) {
|
|
|
14421
15295
|
wf.compress_min_bytes = validatedInt(wf_raw["compress_min_bytes"], wf.compress_min_bytes, 1024, 10 * 1024 * 1024);
|
|
14422
15296
|
wf.compress_bodies = envBool("TOKEN_GOAT_WEB_COMPRESS", wf.compress_bodies);
|
|
14423
15297
|
const wk_raw = section(raw, "worker");
|
|
14424
|
-
const wk =
|
|
15298
|
+
const wk = getDefaultConfig("worker");
|
|
14425
15299
|
wk.watchdog_enabled = validatedBool(wk_raw["watchdog_enabled"], wk.watchdog_enabled);
|
|
14426
15300
|
wk.max_pool_workers = validatedInt(wk_raw["max_pool_workers"], wk.max_pool_workers, 1, 8);
|
|
14427
15301
|
wk.blocked_roots = validatedStrList(wk_raw["blocked_roots"], wk.blocked_roots);
|
|
14428
15302
|
wk.watchdog_enabled = envBool("TOKEN_GOAT_WORKER_WATCHDOG", wk.watchdog_enabled);
|
|
14429
15303
|
wk.max_pool_workers = envInt("TOKEN_GOAT_WORKER_MAX_POOL", wk.max_pool_workers);
|
|
14430
15304
|
const ix_raw = section(raw, "indexing");
|
|
14431
|
-
const ix =
|
|
15305
|
+
const ix = getDefaultConfig("indexing");
|
|
14432
15306
|
ix.large_file_symbol_only_kb = validatedInt(ix_raw["large_file_symbol_only_kb"], ix.large_file_symbol_only_kb, 1, 1048576);
|
|
14433
15307
|
ix.large_file_skip_kb = validatedInt(ix_raw["large_file_skip_kb"], ix.large_file_skip_kb, 1, 1048576);
|
|
14434
15308
|
ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
|
|
14435
15309
|
const cpr_raw = section(raw, "compression");
|
|
14436
|
-
const cpr =
|
|
15310
|
+
const cpr = getDefaultConfig("compression");
|
|
14437
15311
|
cpr.profile = validatedStr(cpr_raw["profile"], cpr.profile);
|
|
14438
15312
|
cpr.profile = envStr("TOKEN_GOAT_COMPRESS_PROFILE", cpr.profile);
|
|
14439
15313
|
const ctx_raw = section(raw, "context");
|
|
14440
|
-
const ctx =
|
|
15314
|
+
const ctx = getDefaultConfig("context");
|
|
14441
15315
|
ctx.model_window_tokens = validatedInt(ctx_raw["model_window_tokens"], ctx.model_window_tokens, 1e4, 1e7);
|
|
14442
15316
|
ctx.model_window_tokens = envInt("TOKEN_GOAT_MODEL_WINDOW_TOKENS", ctx.model_window_tokens);
|
|
14443
15317
|
const inj_raw = section(raw, "injection");
|
|
14444
|
-
const inj =
|
|
15318
|
+
const inj = getDefaultConfig("injection");
|
|
14445
15319
|
inj.enabled = validatedBool(inj_raw["enabled"], inj.enabled);
|
|
14446
15320
|
inj.enabled = envBool("TOKEN_GOAT_INJECTION_ENABLED", inj.enabled);
|
|
14447
15321
|
return {
|
|
@@ -14471,9 +15345,9 @@ function _buildConfig(raw) {
|
|
|
14471
15345
|
|
|
14472
15346
|
// src/cli_doctor.ts
|
|
14473
15347
|
init_define_import_meta_env();
|
|
14474
|
-
import * as
|
|
14475
|
-
import * as
|
|
14476
|
-
import { execSync } from "child_process";
|
|
15348
|
+
import * as fs14 from "fs";
|
|
15349
|
+
import * as path15 from "path";
|
|
15350
|
+
import { execSync, spawnSync as spawnSync2 } from "child_process";
|
|
14477
15351
|
function checkWorkerRunning() {
|
|
14478
15352
|
try {
|
|
14479
15353
|
const output = execSync("tasklist", { encoding: "utf-8" });
|
|
@@ -14483,8 +15357,8 @@ function checkWorkerRunning() {
|
|
|
14483
15357
|
}
|
|
14484
15358
|
}
|
|
14485
15359
|
function checkDbExists(dataDir2) {
|
|
14486
|
-
const dbPath =
|
|
14487
|
-
if (!
|
|
15360
|
+
const dbPath = path15.join(dataDir2, "index.db");
|
|
15361
|
+
if (!fs14.existsSync(dbPath)) {
|
|
14488
15362
|
return {
|
|
14489
15363
|
name: "Database",
|
|
14490
15364
|
status: "warn",
|
|
@@ -14494,7 +15368,7 @@ function checkDbExists(dataDir2) {
|
|
|
14494
15368
|
return {
|
|
14495
15369
|
name: "Database",
|
|
14496
15370
|
status: "ok",
|
|
14497
|
-
message: `index.db exists (${Math.round(
|
|
15371
|
+
message: `index.db exists (${Math.round(fs14.statSync(dbPath).size / 1024)} KB)`
|
|
14498
15372
|
};
|
|
14499
15373
|
}
|
|
14500
15374
|
function checkInstall() {
|
|
@@ -14514,7 +15388,7 @@ function checkInstall() {
|
|
|
14514
15388
|
}
|
|
14515
15389
|
}
|
|
14516
15390
|
function checkConfigValid(configPath2) {
|
|
14517
|
-
if (!
|
|
15391
|
+
if (!fs14.existsSync(configPath2)) {
|
|
14518
15392
|
return {
|
|
14519
15393
|
name: "Config",
|
|
14520
15394
|
status: "warn",
|
|
@@ -14522,7 +15396,7 @@ function checkConfigValid(configPath2) {
|
|
|
14522
15396
|
};
|
|
14523
15397
|
}
|
|
14524
15398
|
try {
|
|
14525
|
-
const content =
|
|
15399
|
+
const content = fs14.readFileSync(configPath2, "utf-8");
|
|
14526
15400
|
JSON.parse(content);
|
|
14527
15401
|
return {
|
|
14528
15402
|
name: "Config",
|
|
@@ -14533,18 +15407,22 @@ function checkConfigValid(configPath2) {
|
|
|
14533
15407
|
return {
|
|
14534
15408
|
name: "Config",
|
|
14535
15409
|
status: "fail",
|
|
14536
|
-
message: `config invalid: ${err2
|
|
15410
|
+
message: `config invalid: ${extractErrorMessage(err2, "unknown error")}`
|
|
14537
15411
|
};
|
|
14538
15412
|
}
|
|
14539
15413
|
}
|
|
14540
15414
|
function checkDiskSpace(dataDir2) {
|
|
14541
15415
|
try {
|
|
14542
|
-
const
|
|
14543
|
-
const
|
|
15416
|
+
const result = spawnSync2("df", ["-h", dataDir2], { encoding: "utf-8" });
|
|
15417
|
+
const stdout = typeof result.stdout === "string" ? result.stdout : "";
|
|
15418
|
+
if (result.error !== void 0 || result.status !== 0 || !stdout) {
|
|
15419
|
+
return { name: "Disk Space", status: "warn", message: "could not determine" };
|
|
15420
|
+
}
|
|
15421
|
+
const lines = stdout.trim().split("\n");
|
|
14544
15422
|
if (lines.length < 2) {
|
|
14545
15423
|
return { name: "Disk Space", status: "warn", message: "could not determine" };
|
|
14546
15424
|
}
|
|
14547
|
-
const parts = lines[1].split(/\s+/);
|
|
15425
|
+
const parts = lines[1].trim().split(/\s+/);
|
|
14548
15426
|
const available = parts[3] || "unknown";
|
|
14549
15427
|
return { name: "Disk Space", status: "ok", message: `${available} available` };
|
|
14550
15428
|
} catch {
|
|
@@ -14556,9 +15434,9 @@ function runDoctor(dataDir2, configPath2) {
|
|
|
14556
15434
|
results.push(checkInstall());
|
|
14557
15435
|
results.push(checkWorkerRunning() ? { name: "Worker", status: "ok", message: "running" } : { name: "Worker", status: "warn", message: "not running" });
|
|
14558
15436
|
const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
14559
|
-
const actualDataDir = dataDir2 ||
|
|
15437
|
+
const actualDataDir = dataDir2 || path15.join(homeDir, ".token-goat");
|
|
14560
15438
|
results.push(checkDbExists(actualDataDir));
|
|
14561
|
-
const actualConfigPath = configPath2 ||
|
|
15439
|
+
const actualConfigPath = configPath2 || path15.join(actualDataDir, "config.json");
|
|
14562
15440
|
results.push(checkConfigValid(actualConfigPath));
|
|
14563
15441
|
results.push(checkDiskSpace(actualDataDir));
|
|
14564
15442
|
return results;
|
|
@@ -14597,7 +15475,7 @@ init_define_import_meta_env();
|
|
|
14597
15475
|
var _byId2 = /* @__PURE__ */ new Map();
|
|
14598
15476
|
var _urlIndex = /* @__PURE__ */ new Map();
|
|
14599
15477
|
function cacheIdForUrl(url) {
|
|
14600
|
-
return
|
|
15478
|
+
return shortFingerprint(url);
|
|
14601
15479
|
}
|
|
14602
15480
|
function storeWebOutput(url, content) {
|
|
14603
15481
|
const cacheId = cacheIdForUrl(url);
|
|
@@ -14717,12 +15595,10 @@ async function getSectionContent(fileId, heading) {
|
|
|
14717
15595
|
var CliError = class extends Error {
|
|
14718
15596
|
};
|
|
14719
15597
|
function out(text) {
|
|
14720
|
-
process.stdout.write(text
|
|
14721
|
-
`);
|
|
15598
|
+
process.stdout.write(ensureNewline(text));
|
|
14722
15599
|
}
|
|
14723
15600
|
function err(text) {
|
|
14724
|
-
process.stderr.write(text
|
|
14725
|
-
`);
|
|
15601
|
+
process.stderr.write(ensureNewline(text));
|
|
14726
15602
|
}
|
|
14727
15603
|
function previewLines(body, n) {
|
|
14728
15604
|
return body.split(/\r?\n/).slice(0, n).join("\n");
|
|
@@ -14882,7 +15758,7 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
14882
15758
|
const n = Number.parseInt(opts.tail, 10);
|
|
14883
15759
|
return Number.isFinite(n) && n > 0 ? n : 80;
|
|
14884
15760
|
})() : 80;
|
|
14885
|
-
const applyElision = (lines2, headN2, tailN2) => lines2.length > headN2 + tailN2 ? [...lines2.slice(0, headN2), "...(elided)...", ...lines2.slice(lines2.length - tailN2)] : lines2;
|
|
15761
|
+
const applyElision = (lines2, headN2, tailN2) => lines2.length > headN2 + tailN2 + 1 ? [...lines2.slice(0, headN2), "...(elided)...", ...lines2.slice(lines2.length - tailN2)] : lines2;
|
|
14886
15762
|
let result = lines;
|
|
14887
15763
|
if (opts.head === void 0 && opts.tail === void 0 && opts.grep === void 0) {
|
|
14888
15764
|
result = applyElision(lines, headN, tailN);
|
|
@@ -14897,10 +15773,21 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
14897
15773
|
}
|
|
14898
15774
|
function cmdBashOutput(id, opts) {
|
|
14899
15775
|
if (opts.file !== void 0) {
|
|
15776
|
+
if (opts.file.includes("\0")) {
|
|
15777
|
+
throw new CliError("--file path contains a null byte");
|
|
15778
|
+
}
|
|
15779
|
+
if (!isWindows() && /^\/dev\/(stdin|fd\/0)$|^\/proc\/self\/fd\/0$/.test(opts.file) && process.stdin.isTTY) {
|
|
15780
|
+
throw new CliError("--file /dev/stdin requires piped input; redirect a file instead");
|
|
15781
|
+
}
|
|
14900
15782
|
let content;
|
|
14901
15783
|
try {
|
|
14902
|
-
|
|
14903
|
-
|
|
15784
|
+
const st = fs15.statSync(opts.file);
|
|
15785
|
+
if (st.isFIFO() || st.isSocket()) {
|
|
15786
|
+
throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
15787
|
+
}
|
|
15788
|
+
content = fs15.readFileSync(opts.file, "utf-8");
|
|
15789
|
+
} catch (e) {
|
|
15790
|
+
if (e instanceof CliError) throw e;
|
|
14904
15791
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
14905
15792
|
}
|
|
14906
15793
|
_applyFiltersAndPrint(content, opts);
|
|
@@ -14920,12 +15807,12 @@ async function cmdSkillBody(name, opts) {
|
|
|
14920
15807
|
if (filePath === null) {
|
|
14921
15808
|
throw new CliError(`skill '${name}' not found`);
|
|
14922
15809
|
}
|
|
14923
|
-
const body =
|
|
15810
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
14924
15811
|
if (opts.compact === true) {
|
|
14925
15812
|
const lines = body.split("\n");
|
|
14926
15813
|
const end = lines.findIndex((l) => l.includes("COMPACT_END"));
|
|
14927
15814
|
if (end !== -1) {
|
|
14928
|
-
out(lines.slice(
|
|
15815
|
+
out(lines.slice(end + 1).join("\n"));
|
|
14929
15816
|
} else {
|
|
14930
15817
|
out(body);
|
|
14931
15818
|
}
|
|
@@ -14938,7 +15825,7 @@ async function cmdSkillCompact(name) {
|
|
|
14938
15825
|
if (filePath === null) {
|
|
14939
15826
|
throw new CliError(`skill '${name}' not found`);
|
|
14940
15827
|
}
|
|
14941
|
-
const body =
|
|
15828
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
14942
15829
|
const sessionFiles = getSessionFiles();
|
|
14943
15830
|
const sessionId = Array.from(sessionFiles.keys())[0] ?? "default";
|
|
14944
15831
|
await storeCompact(sessionId, name, body);
|
|
@@ -15025,7 +15912,7 @@ function cmdConfigGet(file, key) {
|
|
|
15025
15912
|
}
|
|
15026
15913
|
function atomicWriteBuffer(dest, data) {
|
|
15027
15914
|
try {
|
|
15028
|
-
if (
|
|
15915
|
+
if (fs15.statSync(dest).isDirectory()) {
|
|
15029
15916
|
const e = Object.assign(new Error(`EISDIR: illegal operation on a directory, open '${dest}'`), { code: "EISDIR", path: dest });
|
|
15030
15917
|
throw e;
|
|
15031
15918
|
}
|
|
@@ -15033,16 +15920,16 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15033
15920
|
if (e.code !== "ENOENT") throw e;
|
|
15034
15921
|
}
|
|
15035
15922
|
const rnd = Math.random().toString(36).slice(2, 8);
|
|
15036
|
-
const tmp =
|
|
15923
|
+
const tmp = path16.join(path16.dirname(path16.resolve(dest)), `.tmp.${process.pid}.${rnd}`);
|
|
15037
15924
|
try {
|
|
15038
|
-
|
|
15925
|
+
fs15.writeFileSync(tmp, data, { mode: 384 });
|
|
15039
15926
|
try {
|
|
15040
|
-
|
|
15927
|
+
fs15.renameSync(tmp, dest);
|
|
15041
15928
|
} catch (e) {
|
|
15042
15929
|
if (e.code === "EXDEV") {
|
|
15043
|
-
|
|
15930
|
+
fs15.copyFileSync(tmp, dest);
|
|
15044
15931
|
try {
|
|
15045
|
-
|
|
15932
|
+
fs15.unlinkSync(tmp);
|
|
15046
15933
|
} catch (ue) {
|
|
15047
15934
|
process.stderr.write(`token-goat write-file: warning: could not remove temp file ${tmp}: ${ue.message}
|
|
15048
15935
|
`);
|
|
@@ -15053,7 +15940,7 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15053
15940
|
}
|
|
15054
15941
|
} catch (e) {
|
|
15055
15942
|
try {
|
|
15056
|
-
|
|
15943
|
+
fs15.unlinkSync(tmp);
|
|
15057
15944
|
} catch {
|
|
15058
15945
|
}
|
|
15059
15946
|
throw e;
|
|
@@ -15063,9 +15950,9 @@ function mapFsError(e, src, dest) {
|
|
|
15063
15950
|
const fe = e;
|
|
15064
15951
|
if (fe.code === "ENOENT") {
|
|
15065
15952
|
const errPath = fe.path ?? "";
|
|
15066
|
-
const isSource = src !== void 0 &&
|
|
15953
|
+
const isSource = src !== void 0 && path16.resolve(errPath) === path16.resolve(src);
|
|
15067
15954
|
if (isSource) throw new CliError(`source file not found: ${src}`);
|
|
15068
|
-
const destDir = dest ?
|
|
15955
|
+
const destDir = dest ? path16.dirname(path16.resolve(dest)) : path16.dirname(path16.resolve(errPath || "."));
|
|
15069
15956
|
throw new CliError(`destination directory does not exist: ${destDir}`);
|
|
15070
15957
|
}
|
|
15071
15958
|
if (fe.code === "ENOTDIR") {
|
|
@@ -15073,7 +15960,7 @@ function mapFsError(e, src, dest) {
|
|
|
15073
15960
|
}
|
|
15074
15961
|
if (fe.code === "EISDIR") {
|
|
15075
15962
|
const errPath = fe.path ?? "";
|
|
15076
|
-
const isSource = src !== void 0 && (errPath === "" ||
|
|
15963
|
+
const isSource = src !== void 0 && (errPath === "" || path16.resolve(errPath) === path16.resolve(src));
|
|
15077
15964
|
if (isSource) throw new CliError(`source is a directory, not a file: ${src}`);
|
|
15078
15965
|
throw new CliError(`destination is a directory, not a file: ${dest ?? (errPath || "(unknown)")}`);
|
|
15079
15966
|
}
|
|
@@ -15138,8 +16025,8 @@ function cmdWriteFile(dest, opts) {
|
|
|
15138
16025
|
if (dest.includes("\0")) {
|
|
15139
16026
|
throw new CliError("destination path contains a null byte");
|
|
15140
16027
|
}
|
|
15141
|
-
if (
|
|
15142
|
-
const base =
|
|
16028
|
+
if (isWindows()) {
|
|
16029
|
+
const base = path16.basename(dest);
|
|
15143
16030
|
const stem = base.replace(/\.[^.]*$/, "").toUpperCase();
|
|
15144
16031
|
if (WIN_RESERVED.has(stem)) {
|
|
15145
16032
|
throw new CliError(`destination '${base}' is a reserved Windows device name`);
|
|
@@ -15158,20 +16045,23 @@ function cmdWriteFile(dest, opts) {
|
|
|
15158
16045
|
if (opts.from.includes("\0")) {
|
|
15159
16046
|
throw new CliError("--from path contains a null byte");
|
|
15160
16047
|
}
|
|
15161
|
-
if (
|
|
16048
|
+
if (!isWindows() && /^\/dev\/(stdin|fd\/0)$|^\/proc\/self\/fd\/0$/.test(opts.from) && process.stdin.isTTY) {
|
|
15162
16049
|
throw new CliError("--from /dev/stdin requires piped input; use piped stdin mode or --b64 for interactive use");
|
|
15163
16050
|
}
|
|
15164
16051
|
try {
|
|
15165
|
-
const st =
|
|
16052
|
+
const st = fs15.statSync(opts.from);
|
|
15166
16053
|
if (st.isFIFO() || st.isSocket()) {
|
|
15167
16054
|
throw new CliError(`--from '${opts.from}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
15168
16055
|
}
|
|
15169
16056
|
const maxFromMB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15170
|
-
|
|
16057
|
+
if (!Number.isFinite(maxFromMB) || maxFromMB <= 0) {
|
|
16058
|
+
throw new CliError(`TOKEN_GOAT_MAX_STDIN_MB must be a positive integer; got '${process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? ""}'`);
|
|
16059
|
+
}
|
|
16060
|
+
const maxFromBytes = maxFromMB * 1024 * 1024;
|
|
15171
16061
|
if (st.size > maxFromBytes) {
|
|
15172
16062
|
throw new CliError(`--from source exceeds size limit (${Math.round(st.size / 1024 / 1024)} MB); set TOKEN_GOAT_MAX_STDIN_MB to override`);
|
|
15173
16063
|
}
|
|
15174
|
-
atomicWriteBuffer(dest,
|
|
16064
|
+
atomicWriteBuffer(dest, fs15.readFileSync(opts.from));
|
|
15175
16065
|
} catch (e) {
|
|
15176
16066
|
if (e instanceof CliError) throw e;
|
|
15177
16067
|
mapFsError(e, opts.from, dest);
|
|
@@ -15184,7 +16074,10 @@ function cmdWriteFile(dest, opts) {
|
|
|
15184
16074
|
throw new CliError("--b64 payload contains only whitespace \u2014 likely a shell expansion error; pass an empty string explicitly for a zero-byte file");
|
|
15185
16075
|
}
|
|
15186
16076
|
const maxB64MB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15187
|
-
|
|
16077
|
+
if (!Number.isFinite(maxB64MB) || maxB64MB <= 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 maxB64Bytes = maxB64MB * 1024 * 1024;
|
|
15188
16081
|
const decodedSize = Math.floor(normalized.replace(/=+$/, "").length * 3 / 4);
|
|
15189
16082
|
if (decodedSize > maxB64Bytes) {
|
|
15190
16083
|
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`);
|
|
@@ -15285,7 +16178,7 @@ function buildProgram() {
|
|
|
15285
16178
|
await fn(...args);
|
|
15286
16179
|
process.exitCode = 0;
|
|
15287
16180
|
} catch (e) {
|
|
15288
|
-
const msg =
|
|
16181
|
+
const msg = extractErrorMessage(e);
|
|
15289
16182
|
err(`token-goat: ${msg}`);
|
|
15290
16183
|
process.exitCode = 1;
|
|
15291
16184
|
}
|
|
@@ -15337,7 +16230,7 @@ async function run(argv = process.argv) {
|
|
|
15337
16230
|
process.exitCode = 1;
|
|
15338
16231
|
return;
|
|
15339
16232
|
}
|
|
15340
|
-
const msg =
|
|
16233
|
+
const msg = extractErrorMessage(e);
|
|
15341
16234
|
err(`token-goat: ${msg}`);
|
|
15342
16235
|
process.exitCode = 1;
|
|
15343
16236
|
}
|