token-goat 2.1.0 → 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 +1 -1
- package/dist/token-goat.mjs +1088 -383
- 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.
|
|
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
|
|
@@ -10874,7 +11110,7 @@ function dispatchFileTypeHandler(filePath, content, contentLengthHint) {
|
|
|
10874
11110
|
|
|
10875
11111
|
// src/stats.ts
|
|
10876
11112
|
init_define_import_meta_env();
|
|
10877
|
-
import * as
|
|
11113
|
+
import * as path8 from "node:path";
|
|
10878
11114
|
|
|
10879
11115
|
// src/render/stats_renderer.ts
|
|
10880
11116
|
init_define_import_meta_env();
|
|
@@ -11654,7 +11890,7 @@ CREATE INDEX IF NOT EXISTS idx_stats_kind ON stats(kind);
|
|
|
11654
11890
|
var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
11655
11891
|
registerReset(() => _globalSchemaApplied.clear());
|
|
11656
11892
|
function getGlobalDb() {
|
|
11657
|
-
const dbPath =
|
|
11893
|
+
const dbPath = path8.join(dataDir(), "global.db");
|
|
11658
11894
|
const db = getDb(dbPath);
|
|
11659
11895
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
11660
11896
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
@@ -11688,7 +11924,9 @@ function summarize(windowDays = 30, testDb) {
|
|
|
11688
11924
|
const bytesSaved = row.bytes_saved ?? 0;
|
|
11689
11925
|
const tokensSaved = row.tokens_saved ?? 0;
|
|
11690
11926
|
const kind = row.kind;
|
|
11691
|
-
const
|
|
11927
|
+
const tsRaw = row.ts;
|
|
11928
|
+
if (tsRaw === void 0) continue;
|
|
11929
|
+
const ts = tsRaw;
|
|
11692
11930
|
totalEvents += 1;
|
|
11693
11931
|
totalBytes += bytesSaved;
|
|
11694
11932
|
totalTokens += tokensSaved;
|
|
@@ -11851,22 +12089,59 @@ function isTsConfigFile(basename7) {
|
|
|
11851
12089
|
var LARGE_FILE_BYTES = 100 * 1024;
|
|
11852
12090
|
var REREAD_DENY_BYTES = 50 * 1024;
|
|
11853
12091
|
var LARGE_FILE_DENY_BYTES = 500 * 1024;
|
|
11854
|
-
function isNodeModulesPath(
|
|
11855
|
-
const
|
|
11856
|
-
const check = isWindows ? path15.toLowerCase() : path15;
|
|
12092
|
+
function isNodeModulesPath(p) {
|
|
12093
|
+
const check = isWindows() ? p.toLowerCase() : p;
|
|
11857
12094
|
return check.includes("/node_modules/") || check.includes("\\node_modules\\");
|
|
11858
12095
|
}
|
|
11859
12096
|
function _isDocFile(filePath) {
|
|
11860
12097
|
const lower = filePath.toLowerCase();
|
|
11861
12098
|
return lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".markdown") || lower.endsWith(".rst");
|
|
11862
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
|
+
}
|
|
11863
12105
|
function statSize(absPath) {
|
|
11864
12106
|
try {
|
|
11865
|
-
return
|
|
12107
|
+
return fs5.statSync(absPath).size;
|
|
11866
12108
|
} catch {
|
|
11867
12109
|
return null;
|
|
11868
12110
|
}
|
|
11869
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
|
+
}
|
|
11870
12145
|
function preReadHandler(event) {
|
|
11871
12146
|
const filePath = getFilePath(event);
|
|
11872
12147
|
if (filePath === void 0) return passOutput();
|
|
@@ -11876,7 +12151,7 @@ function preReadHandler(event) {
|
|
|
11876
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"
|
|
11877
12152
|
);
|
|
11878
12153
|
}
|
|
11879
|
-
const basename7 =
|
|
12154
|
+
const basename7 = path9.basename(normalized);
|
|
11880
12155
|
if (isLockFile(basename7)) {
|
|
11881
12156
|
return denyOutput(
|
|
11882
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.'
|
|
@@ -11915,7 +12190,7 @@ function preReadHandler(event) {
|
|
|
11915
12190
|
try {
|
|
11916
12191
|
const sz = statSize(normalized);
|
|
11917
12192
|
if (sz !== null && sz >= MARKDOWN_SIZE_THRESHOLD) {
|
|
11918
|
-
fileContent =
|
|
12193
|
+
fileContent = fs5.readFileSync(normalized, "utf8");
|
|
11919
12194
|
}
|
|
11920
12195
|
} catch {
|
|
11921
12196
|
}
|
|
@@ -11931,6 +12206,22 @@ function preReadHandler(event) {
|
|
|
11931
12206
|
}
|
|
11932
12207
|
}
|
|
11933
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
|
+
}
|
|
11934
12225
|
if (/^\.env(\.\w+)?$/.test(basename7) && wasFileReadThisSession(normalized)) {
|
|
11935
12226
|
recordFileRead(normalized);
|
|
11936
12227
|
recordStat("session_hint", 0, 0);
|
|
@@ -11938,14 +12229,124 @@ function preReadHandler(event) {
|
|
|
11938
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."
|
|
11939
12230
|
);
|
|
11940
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
|
+
}
|
|
11941
12325
|
if (wasFileReadThisSession(normalized)) {
|
|
11942
12326
|
const entry = getSessionFiles().get(normalized);
|
|
11943
12327
|
const reads = entry?.readCount ?? 1;
|
|
11944
12328
|
const plural = reads === 1 ? "read" : "reads";
|
|
11945
12329
|
recordFileRead(normalized);
|
|
11946
|
-
const hint = _isDocFile(normalized) ? 'Use `token-goat section "' + normalized + '::SectionName"` to read one section.' : "Use token-goat read/section/symbol to re-read surgically.";
|
|
11947
12330
|
const rereadBytes = statSize(normalized) ?? 0;
|
|
11948
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.";
|
|
11949
12350
|
if (rereadBytes >= REREAD_DENY_BYTES || reads >= 2) {
|
|
11950
12351
|
return denyOutput(
|
|
11951
12352
|
normalized + " was already read this session (" + reads + " " + plural + "). " + hint
|
|
@@ -11967,10 +12368,10 @@ function preReadHandler(event) {
|
|
|
11967
12368
|
);
|
|
11968
12369
|
}
|
|
11969
12370
|
return contextOutput(
|
|
11970
|
-
"Note: " + normalized + " is large (" + kb + "
|
|
12371
|
+
"Note: " + normalized + " is large (" + kb + "KB). " + hint
|
|
11971
12372
|
);
|
|
11972
12373
|
}
|
|
11973
|
-
const fileTypeExt =
|
|
12374
|
+
const fileTypeExt = path9.extname(normalized).slice(1).toLowerCase();
|
|
11974
12375
|
const binaryExts = /* @__PURE__ */ new Set(["pdf", "docx", "xlsx", "pptx", "odt", "ods", "ott", "odp"]);
|
|
11975
12376
|
const textTypeExts = /* @__PURE__ */ new Set(["html", "htm", "xhtml", "txt", "log", "out", "err", "trace", "csv", "tsv"]);
|
|
11976
12377
|
const fileStatSize = size ?? statSize(normalized) ?? 0;
|
|
@@ -11979,7 +12380,7 @@ function preReadHandler(event) {
|
|
|
11979
12380
|
let ftContent = "";
|
|
11980
12381
|
if (!binaryExts.has(fileTypeExt)) {
|
|
11981
12382
|
try {
|
|
11982
|
-
ftContent =
|
|
12383
|
+
ftContent = fs5.readFileSync(normalized, "utf8");
|
|
11983
12384
|
} catch {
|
|
11984
12385
|
}
|
|
11985
12386
|
}
|
|
@@ -11994,29 +12395,67 @@ function preReadHandler(event) {
|
|
|
11994
12395
|
}
|
|
11995
12396
|
registerHook("pre_tool_use", preReadHandler, { toolName: "Read" });
|
|
11996
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" });
|
|
11997
12431
|
|
|
11998
12432
|
// src/hooks_edit.ts
|
|
11999
12433
|
init_define_import_meta_env();
|
|
12000
|
-
import * as
|
|
12434
|
+
import * as path11 from "node:path";
|
|
12001
12435
|
|
|
12002
12436
|
// src/hooks_index.ts
|
|
12003
12437
|
init_define_import_meta_env();
|
|
12004
|
-
import * as
|
|
12005
|
-
import * as
|
|
12438
|
+
import * as fs6 from "node:fs";
|
|
12439
|
+
import * as path10 from "node:path";
|
|
12006
12440
|
function dirtyQueuePath() {
|
|
12007
|
-
return
|
|
12441
|
+
return path10.join(dataDir(), "queue", "dirty.txt");
|
|
12008
12442
|
}
|
|
12009
12443
|
function appendDirtyPath(normalizedPath) {
|
|
12010
12444
|
const queuePath = dirtyQueuePath();
|
|
12011
|
-
|
|
12012
|
-
|
|
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}
|
|
12013
12452
|
`);
|
|
12014
12453
|
}
|
|
12015
12454
|
function getDirtyPaths() {
|
|
12016
12455
|
const queuePath = dirtyQueuePath();
|
|
12017
12456
|
let raw;
|
|
12018
12457
|
try {
|
|
12019
|
-
raw =
|
|
12458
|
+
raw = fs6.readFileSync(queuePath, "utf8");
|
|
12020
12459
|
} catch {
|
|
12021
12460
|
return [];
|
|
12022
12461
|
}
|
|
@@ -12032,21 +12471,21 @@ function getDirtyPaths() {
|
|
|
12032
12471
|
}
|
|
12033
12472
|
function clearDirtyQueue() {
|
|
12034
12473
|
try {
|
|
12035
|
-
|
|
12474
|
+
fs6.rmSync(dirtyQueuePath(), { force: true });
|
|
12036
12475
|
} catch {
|
|
12037
12476
|
}
|
|
12038
12477
|
}
|
|
12039
12478
|
function preCompactIndexHandler(_event) {
|
|
12040
12479
|
const paths = getDirtyPaths();
|
|
12041
12480
|
if (paths.length > 0) {
|
|
12042
|
-
const sidecar =
|
|
12481
|
+
const sidecar = path10.join(dataDir(), "queue", "pending.txt");
|
|
12043
12482
|
try {
|
|
12044
|
-
|
|
12483
|
+
fs6.mkdirSync(path10.dirname(sidecar), { recursive: true });
|
|
12045
12484
|
atomicWriteBytes(sidecar, Buffer.from(`${paths.join("\n")}
|
|
12046
12485
|
`, "utf8"));
|
|
12486
|
+
clearDirtyQueue();
|
|
12047
12487
|
} catch {
|
|
12048
12488
|
}
|
|
12049
|
-
clearDirtyQueue();
|
|
12050
12489
|
}
|
|
12051
12490
|
return passOutput();
|
|
12052
12491
|
}
|
|
@@ -12059,10 +12498,11 @@ function postEditHandler(event) {
|
|
|
12059
12498
|
const normalized = normalizePath(filePath);
|
|
12060
12499
|
recordFileEdit(normalized);
|
|
12061
12500
|
appendDirtyPath(normalized);
|
|
12062
|
-
const editedBasename =
|
|
12501
|
+
const editedBasename = path11.basename(normalized);
|
|
12063
12502
|
if (/\.(md|mdx|markdown|rst)$/i.test(editedBasename)) {
|
|
12503
|
+
const escapedPath = normalized.replace(/`/g, "\\`");
|
|
12064
12504
|
return contextOutput(
|
|
12065
|
-
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.'
|
|
12066
12506
|
);
|
|
12067
12507
|
}
|
|
12068
12508
|
return passOutput();
|
|
@@ -12340,17 +12780,20 @@ init_define_import_meta_env();
|
|
|
12340
12780
|
|
|
12341
12781
|
// src/fingerprint.ts
|
|
12342
12782
|
init_define_import_meta_env();
|
|
12343
|
-
import { createHash } from "node:crypto";
|
|
12344
|
-
import * as
|
|
12783
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12784
|
+
import * as fs7 from "node:fs";
|
|
12345
12785
|
function fingerprintContent(content) {
|
|
12346
|
-
const hash =
|
|
12786
|
+
const hash = createHash2("sha256");
|
|
12347
12787
|
hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
|
|
12348
12788
|
return hash.digest("hex");
|
|
12349
12789
|
}
|
|
12790
|
+
function shortFingerprint(content) {
|
|
12791
|
+
return fingerprintContent(content).slice(0, 16);
|
|
12792
|
+
}
|
|
12350
12793
|
function fingerprintFile(filePath) {
|
|
12351
12794
|
let data;
|
|
12352
12795
|
try {
|
|
12353
|
-
data =
|
|
12796
|
+
data = fs7.readFileSync(filePath);
|
|
12354
12797
|
} catch {
|
|
12355
12798
|
return null;
|
|
12356
12799
|
}
|
|
@@ -12359,15 +12802,24 @@ function fingerprintFile(filePath) {
|
|
|
12359
12802
|
|
|
12360
12803
|
// src/bash_output_cache.ts
|
|
12361
12804
|
init_define_import_meta_env();
|
|
12362
|
-
import * as
|
|
12805
|
+
import * as fs8 from "fs/promises";
|
|
12363
12806
|
import { resolve as resolve3 } from "path";
|
|
12364
12807
|
var _byId = /* @__PURE__ */ new Map();
|
|
12365
12808
|
var _globsByKey = /* @__PURE__ */ new Map();
|
|
12366
12809
|
var _grepsByKey = /* @__PURE__ */ new Map();
|
|
12367
|
-
var
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
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
|
+
};
|
|
12371
12823
|
var DEP_LOCKFILES = {
|
|
12372
12824
|
npm: ["package-lock.json", "yarn.lock"],
|
|
12373
12825
|
pip: ["requirements.txt"],
|
|
@@ -12378,18 +12830,14 @@ var DEP_LOCKFILES = {
|
|
|
12378
12830
|
bundle: ["Gemfile.lock"],
|
|
12379
12831
|
composer: ["composer.lock"]
|
|
12380
12832
|
};
|
|
12381
|
-
function
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
}
|
|
12390
|
-
function isNpmInstallCommand(cmd) {
|
|
12391
|
-
return NPM_INSTALL_RE.test(cmd);
|
|
12392
|
-
}
|
|
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");
|
|
12393
12841
|
async function gitStateFingerprint(cwd) {
|
|
12394
12842
|
try {
|
|
12395
12843
|
const headResult = runGit(["rev-parse", "HEAD"], { cwd });
|
|
@@ -12397,21 +12845,21 @@ async function gitStateFingerprint(cwd) {
|
|
|
12397
12845
|
const headSha = headResult.stdout.trim();
|
|
12398
12846
|
let indexMtime = "";
|
|
12399
12847
|
try {
|
|
12400
|
-
const stat3 = await
|
|
12848
|
+
const stat3 = await fs8.stat(resolve3(cwd, ".git", "index"));
|
|
12401
12849
|
indexMtime = stat3.mtimeMs.toString();
|
|
12402
12850
|
} catch {
|
|
12403
12851
|
}
|
|
12404
12852
|
const key = `${headSha}\0${indexMtime}`;
|
|
12405
|
-
return
|
|
12853
|
+
return shortFingerprint(key);
|
|
12406
12854
|
} catch {
|
|
12407
12855
|
return null;
|
|
12408
12856
|
}
|
|
12409
12857
|
}
|
|
12410
|
-
async function dirStateFingerprint(
|
|
12858
|
+
async function dirStateFingerprint(path17) {
|
|
12411
12859
|
try {
|
|
12412
|
-
const stat3 = await
|
|
12860
|
+
const stat3 = await fs8.stat(path17);
|
|
12413
12861
|
if (!stat3.isDirectory()) return null;
|
|
12414
|
-
return
|
|
12862
|
+
return shortFingerprint(stat3.mtimeMs.toString());
|
|
12415
12863
|
} catch {
|
|
12416
12864
|
return null;
|
|
12417
12865
|
}
|
|
@@ -12425,8 +12873,8 @@ async function depLockfileFingerprint(cmd, cwd) {
|
|
|
12425
12873
|
if (!candidates) return null;
|
|
12426
12874
|
for (const lockfile of candidates) {
|
|
12427
12875
|
try {
|
|
12428
|
-
const content = await
|
|
12429
|
-
return
|
|
12876
|
+
const content = await fs8.readFile(resolve3(cwd, lockfile));
|
|
12877
|
+
return shortFingerprint(content);
|
|
12430
12878
|
} catch {
|
|
12431
12879
|
continue;
|
|
12432
12880
|
}
|
|
@@ -12474,7 +12922,7 @@ async function commandHash(command, cwd = null) {
|
|
|
12474
12922
|
const fp = await depLockfileFingerprint(command, cwd);
|
|
12475
12923
|
if (fp) key = `${key}\0npm-install:${fp}`;
|
|
12476
12924
|
}
|
|
12477
|
-
return
|
|
12925
|
+
return shortFingerprint(key);
|
|
12478
12926
|
}
|
|
12479
12927
|
function extractLsTarget(cmd, cwd) {
|
|
12480
12928
|
const tokens = cmd.trim().split(/\s+/);
|
|
@@ -12521,7 +12969,7 @@ function isOrchestratorStateFile(filePath) {
|
|
|
12521
12969
|
return /^\.improve-state-/.test(basename7);
|
|
12522
12970
|
}
|
|
12523
12971
|
function extractCatSourceFile(cmd) {
|
|
12524
|
-
const m = /^cat\s+(\S+\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj))\s*$/.exec(cmd);
|
|
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);
|
|
12525
12973
|
return m?.[1] ?? null;
|
|
12526
12974
|
}
|
|
12527
12975
|
function extractCatFile(cmd) {
|
|
@@ -12530,14 +12978,39 @@ function extractCatFile(cmd) {
|
|
|
12530
12978
|
const filePath = m[1] ?? m[2] ?? m[3];
|
|
12531
12979
|
if (filePath === void 0) return null;
|
|
12532
12980
|
if (isTempPath(filePath)) return null;
|
|
12533
|
-
const basename7 = filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1) ?? filePath;
|
|
12981
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12534
12982
|
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
12535
|
-
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
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);
|
|
12536
12984
|
if (!hasKnownExt && !isEnvFile) return null;
|
|
12537
|
-
const
|
|
12985
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
12986
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12538
12987
|
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
12539
12988
|
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
12540
|
-
return { filePath, isDoc, isEnv, isConfig };
|
|
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 };
|
|
12541
13014
|
}
|
|
12542
13015
|
function extractWslCatFile(cmd) {
|
|
12543
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);
|
|
@@ -12547,18 +13020,44 @@ function extractWslCatFile(cmd) {
|
|
|
12547
13020
|
if (!drive || !pathRest) return null;
|
|
12548
13021
|
const filePath = drive + ":/" + pathRest;
|
|
12549
13022
|
if (isTempPath(filePath)) return null;
|
|
12550
|
-
const basename7 = filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1) ?? filePath;
|
|
13023
|
+
const basename7 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
|
|
12551
13024
|
const isEnvFile = /^\.env(\.\w+)?$/i.test(basename7);
|
|
12552
|
-
const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|env)$/i.test(filePath);
|
|
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);
|
|
12553
13026
|
if (!hasKnownExt && !isEnvFile) return null;
|
|
12554
|
-
const
|
|
13027
|
+
const isSql = /\.sql$/i.test(filePath);
|
|
13028
|
+
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12555
13029
|
const isEnv = isEnvFile || /\.env$/i.test(filePath);
|
|
12556
13030
|
const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
|
|
12557
|
-
return { filePath, isDoc, isEnv, isConfig };
|
|
13031
|
+
return { filePath, isDoc, isEnv, isConfig, isSql };
|
|
12558
13032
|
}
|
|
12559
13033
|
function extractPythonFileRead(cmd) {
|
|
12560
13034
|
if (!/python3?/.test(cmd)) return null;
|
|
12561
|
-
|
|
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
|
+
}
|
|
12562
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);
|
|
12563
13062
|
if (direct) {
|
|
12564
13063
|
const filePath = direct[1] ?? "";
|
|
@@ -12573,7 +13072,7 @@ function extractPythonFileRead(cmd) {
|
|
|
12573
13072
|
const filePath = literal[1] ?? "";
|
|
12574
13073
|
if (filePath) {
|
|
12575
13074
|
if (isOrchestratorStateFile(filePath)) return null;
|
|
12576
|
-
if (
|
|
13075
|
+
if (OPEN_EXT.test(filePath)) {
|
|
12577
13076
|
const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
|
|
12578
13077
|
return { filePath, isDoc };
|
|
12579
13078
|
}
|
|
@@ -12586,7 +13085,7 @@ function extractHeadFile(cmd) {
|
|
|
12586
13085
|
const m = /^head(?:\s+-n\s+(\d+)|\s+-(\d+))?\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
|
|
12587
13086
|
if (!m) return null;
|
|
12588
13087
|
const n = parseInt(m[1] ?? m[2] ?? "0", 10);
|
|
12589
|
-
if (n
|
|
13088
|
+
if (n < 10) return null;
|
|
12590
13089
|
const filePath = m[3] ?? m[4] ?? m[5];
|
|
12591
13090
|
if (filePath === void 0) return null;
|
|
12592
13091
|
if (isTempPath(filePath)) return null;
|
|
@@ -12597,13 +13096,24 @@ function extractHeadFile(cmd) {
|
|
|
12597
13096
|
}
|
|
12598
13097
|
function extractNodeFileRead(cmd) {
|
|
12599
13098
|
if (!/^node\s+-e/.test(cmd)) return null;
|
|
12600
|
-
const
|
|
12601
|
-
if (
|
|
12602
|
-
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
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;
|
|
12607
13117
|
}
|
|
12608
13118
|
function extractTailFile(cmd) {
|
|
12609
13119
|
if (/-f\b/.test(cmd)) return null;
|
|
@@ -12620,9 +13130,67 @@ function extractTailFile(cmd) {
|
|
|
12620
13130
|
const isDoc = /\.(?:md|mdx|rst|txt|sql)$/i.test(filePath);
|
|
12621
13131
|
return { filePath, isDoc };
|
|
12622
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
|
+
}
|
|
12623
13191
|
function extractRgStructuralSearch(cmd) {
|
|
12624
13192
|
if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
|
|
12625
|
-
const hasStructural = /["']?\^?(?:def\s|class\s|function\s|func\s|fn\s|pub fn\s|import\s|from\s)/.test(cmd) || /["']\^(?:def|class|function|func|import|from)["']/.test(cmd) || /\\bdef\\b|\\bclass\\b/.test(cmd);
|
|
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);
|
|
12626
13194
|
if (!hasStructural) return null;
|
|
12627
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);
|
|
12628
13196
|
if (!fileMatch) return null;
|
|
@@ -12631,6 +13199,37 @@ function extractRgStructuralSearch(cmd) {
|
|
|
12631
13199
|
if (isTempPath(filePath)) return null;
|
|
12632
13200
|
return { filePath };
|
|
12633
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
|
+
}
|
|
12634
13233
|
function isTscCommand(cmd) {
|
|
12635
13234
|
return /^\s*tsc(\s|$)/i.test(cmd);
|
|
12636
13235
|
}
|
|
@@ -12650,18 +13249,70 @@ function buildRecallHint(cmd, outputId) {
|
|
|
12650
13249
|
function preBashHandler(event) {
|
|
12651
13250
|
const cmd = extractCommand(event);
|
|
12652
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
|
+
}
|
|
12653
13294
|
const catResult = extractCatFile(cmd);
|
|
12654
13295
|
if (catResult !== null) {
|
|
12655
|
-
const { filePath, isDoc, isEnv, isConfig } = catResult;
|
|
12656
|
-
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13296
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = catResult;
|
|
12657
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.';
|
|
12658
13304
|
return denyOutput("`cat` loads the entire file into context. " + hint);
|
|
12659
13305
|
}
|
|
12660
13306
|
const wslCatResult = extractWslCatFile(cmd);
|
|
12661
13307
|
if (wslCatResult !== null) {
|
|
12662
|
-
const { filePath, isDoc, isEnv, isConfig } = wslCatResult;
|
|
12663
|
-
const hint = isEnv ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to read one function or class.';
|
|
13308
|
+
const { filePath, isDoc, isEnv, isConfig, isSql } = wslCatResult;
|
|
12664
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.';
|
|
12665
13316
|
return denyOutput("`cat` loads the entire file into context. " + hint);
|
|
12666
13317
|
}
|
|
12667
13318
|
const pyRead = extractPythonFileRead(cmd);
|
|
@@ -12687,11 +13338,33 @@ function preBashHandler(event) {
|
|
|
12687
13338
|
}
|
|
12688
13339
|
const nodeRead = extractNodeFileRead(cmd);
|
|
12689
13340
|
if (nodeRead !== null) {
|
|
12690
|
-
const { filePath, isDoc } = nodeRead;
|
|
12691
|
-
const hint = isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` to extract a specific symbol.';
|
|
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.';
|
|
12692
13343
|
recordStat("session_hint", 0, 0);
|
|
12693
13344
|
return denyOutput("Node.js `fs.readFileSync()` bypasses read hooks. " + hint);
|
|
12694
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
|
+
}
|
|
12695
13368
|
const rgStructural = extractRgStructuralSearch(cmd);
|
|
12696
13369
|
if (rgStructural !== null) {
|
|
12697
13370
|
const { filePath } = rgStructural;
|
|
@@ -12702,7 +13375,7 @@ function preBashHandler(event) {
|
|
|
12702
13375
|
}
|
|
12703
13376
|
const monitoringHint = getMonitoringRecallHint(cmd);
|
|
12704
13377
|
if (monitoringHint !== null) {
|
|
12705
|
-
const monCmdHash =
|
|
13378
|
+
const monCmdHash = shortFingerprint(cmd);
|
|
12706
13379
|
const monOutputId = getBashOutputId(monCmdHash);
|
|
12707
13380
|
if (monOutputId !== null) {
|
|
12708
13381
|
const monEntry = getBashOutput(monOutputId);
|
|
@@ -12721,8 +13394,32 @@ function preBashHandler(event) {
|
|
|
12721
13394
|
);
|
|
12722
13395
|
}
|
|
12723
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
|
+
}
|
|
12724
13421
|
if (!isBuildCommand(cmd)) return passOutput();
|
|
12725
|
-
const cmdHash =
|
|
13422
|
+
const cmdHash = shortFingerprint(cmd);
|
|
12726
13423
|
const outputId = getBashOutputId(cmdHash);
|
|
12727
13424
|
if (outputId === null) return passOutput();
|
|
12728
13425
|
const entry = getBashOutput(outputId);
|
|
@@ -12747,12 +13444,17 @@ async function postBashHandler(event) {
|
|
|
12747
13444
|
try {
|
|
12748
13445
|
const cmd = extractCommand(event);
|
|
12749
13446
|
if (cmd === void 0) return passOutput();
|
|
13447
|
+
const curlDl = extractCurlDownload(cmd);
|
|
13448
|
+
if (curlDl !== null) {
|
|
13449
|
+
recordCurlDownload(curlDl.url, curlDl.outputPath);
|
|
13450
|
+
}
|
|
12750
13451
|
const isMonitoring = getMonitoringRecallHint(cmd) !== null;
|
|
12751
|
-
if (!isMonitoring && !isBuildCommand(cmd)) return passOutput();
|
|
13452
|
+
if (!isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) return passOutput();
|
|
12752
13453
|
const output = extractBashOutput(event.raw);
|
|
12753
13454
|
if (Buffer.byteLength(output, "utf-8") < MIN_CACHE_BYTES) return passOutput();
|
|
12754
13455
|
const cwd = typeof event.raw["cwd"] === "string" ? event.raw["cwd"] : null;
|
|
12755
|
-
const
|
|
13456
|
+
const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : cmd;
|
|
13457
|
+
const simpleHash = shortFingerprint(cacheKey);
|
|
12756
13458
|
const id = await storeBashOutput(cmd, output, 0, cwd);
|
|
12757
13459
|
recordBashOutput(simpleHash, id, Buffer.byteLength(output, "utf-8"));
|
|
12758
13460
|
} catch {
|
|
@@ -12763,8 +13465,8 @@ registerHook("post_tool_use", postBashHandler, { toolName: "Bash" });
|
|
|
12763
13465
|
|
|
12764
13466
|
// src/image_shrink.ts
|
|
12765
13467
|
init_define_import_meta_env();
|
|
12766
|
-
import * as
|
|
12767
|
-
import * as
|
|
13468
|
+
import * as fs9 from "node:fs";
|
|
13469
|
+
import * as path12 from "node:path";
|
|
12768
13470
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12769
13471
|
".png",
|
|
12770
13472
|
".jpg",
|
|
@@ -12791,7 +13493,7 @@ async function loadSharp() {
|
|
|
12791
13493
|
return _sharpCache;
|
|
12792
13494
|
}
|
|
12793
13495
|
function isImagePath(p) {
|
|
12794
|
-
return IMAGE_EXTENSIONS.has(
|
|
13496
|
+
return IMAGE_EXTENSIONS.has(path12.extname(p).toLowerCase());
|
|
12795
13497
|
}
|
|
12796
13498
|
async function shrinkImage(input, opts) {
|
|
12797
13499
|
const maxDimension = opts?.maxDimension ?? DEFAULT_MAX_DIMENSION;
|
|
@@ -12823,7 +13525,7 @@ async function shrinkImage(input, opts) {
|
|
|
12823
13525
|
}
|
|
12824
13526
|
function statSize2(absPath) {
|
|
12825
13527
|
try {
|
|
12826
|
-
const st =
|
|
13528
|
+
const st = fs9.statSync(absPath);
|
|
12827
13529
|
return st.isFile() ? st.size : null;
|
|
12828
13530
|
} catch {
|
|
12829
13531
|
return null;
|
|
@@ -12837,7 +13539,7 @@ async function preReadImageHandler(event) {
|
|
|
12837
13539
|
if (size === null || size < DEFAULT_SIZE_THRESHOLD_BYTES) return passOutput();
|
|
12838
13540
|
let input;
|
|
12839
13541
|
try {
|
|
12840
|
-
input =
|
|
13542
|
+
input = fs9.readFileSync(filePath);
|
|
12841
13543
|
} catch {
|
|
12842
13544
|
return passOutput();
|
|
12843
13545
|
}
|
|
@@ -12846,7 +13548,7 @@ async function preReadImageHandler(event) {
|
|
|
12846
13548
|
const saved = result.originalBytes - result.shrunkBytes;
|
|
12847
13549
|
const pct = Math.round(saved / result.originalBytes * 100);
|
|
12848
13550
|
const dataUrl = `data:image/${result.format};base64,${result.data.toString("base64")}`;
|
|
12849
|
-
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}).`;
|
|
12850
13552
|
return contextOutput(`${summary}
|
|
12851
13553
|
${dataUrl}`);
|
|
12852
13554
|
}
|
|
@@ -12925,7 +13627,7 @@ async function relay(eventName) {
|
|
|
12925
13627
|
|
|
12926
13628
|
// src/section_reader.ts
|
|
12927
13629
|
init_define_import_meta_env();
|
|
12928
|
-
import { readFileSync as
|
|
13630
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
12929
13631
|
function parseHeadingSpec(spec) {
|
|
12930
13632
|
const m = /^(.*?)#(\d+)$/.exec(spec);
|
|
12931
13633
|
if (m !== null && m[1] !== void 0 && m[2] !== void 0) {
|
|
@@ -12933,6 +13635,18 @@ function parseHeadingSpec(spec) {
|
|
|
12933
13635
|
}
|
|
12934
13636
|
return { base: spec.trim(), ordinal: null };
|
|
12935
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
|
+
}
|
|
12936
13650
|
var MARKDOWN_HEADER_RE = /^(#{1,6})\s+(.+?)\s*#*\s*$/;
|
|
12937
13651
|
var TABLE_HEADER_RE = /^\s*\[+\s*([^\]]+?)\s*\]+\s*$/;
|
|
12938
13652
|
var PYTHON_HEADER_RE = /^(\s*)(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)/;
|
|
@@ -13007,7 +13721,7 @@ function sectionEndIndex(headers, headerPos, totalLines) {
|
|
|
13007
13721
|
function readSection(filePath, headingSpec) {
|
|
13008
13722
|
let text;
|
|
13009
13723
|
try {
|
|
13010
|
-
text =
|
|
13724
|
+
text = readFileSync6(filePath, "utf-8");
|
|
13011
13725
|
} catch {
|
|
13012
13726
|
return null;
|
|
13013
13727
|
}
|
|
@@ -13017,10 +13731,15 @@ function readSection(filePath, headingSpec) {
|
|
|
13017
13731
|
const headers = findHeaders(text, language);
|
|
13018
13732
|
const lines = text.split("\n");
|
|
13019
13733
|
const target = base.toLowerCase();
|
|
13734
|
+
const normalizedTarget = normalizeHeading(base).toLowerCase();
|
|
13735
|
+
const strippedTarget = normalizeHeadingStrip(base).toLowerCase();
|
|
13020
13736
|
const matches = [];
|
|
13021
13737
|
for (let i = 0; i < headers.length; i++) {
|
|
13022
13738
|
const h = headers[i];
|
|
13023
|
-
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
|
+
}
|
|
13024
13743
|
}
|
|
13025
13744
|
if (matches.length === 0) return null;
|
|
13026
13745
|
const pick = ordinal === null ? 0 : ordinal - 1;
|
|
@@ -13044,9 +13763,9 @@ function readSection(filePath, headingSpec) {
|
|
|
13044
13763
|
|
|
13045
13764
|
// src/install.ts
|
|
13046
13765
|
init_define_import_meta_env();
|
|
13047
|
-
import * as
|
|
13048
|
-
import * as
|
|
13049
|
-
import * as
|
|
13766
|
+
import * as fs10 from "node:fs";
|
|
13767
|
+
import * as os3 from "node:os";
|
|
13768
|
+
import * as path13 from "node:path";
|
|
13050
13769
|
var HOOK_EVENT_MAP = [
|
|
13051
13770
|
["PreToolUse", "pre_tool_use"],
|
|
13052
13771
|
["PostToolUse", "post_tool_use"],
|
|
@@ -13057,13 +13776,13 @@ function hookCommand(eventArg) {
|
|
|
13057
13776
|
return `token-goat hook ${eventArg}`;
|
|
13058
13777
|
}
|
|
13059
13778
|
function settingsPath(scope) {
|
|
13060
|
-
const base = scope === "user" ?
|
|
13061
|
-
return
|
|
13779
|
+
const base = scope === "user" ? path13.join(os3.homedir(), ".claude") : path13.join(process.cwd(), ".claude");
|
|
13780
|
+
return path13.join(base, "settings.json");
|
|
13062
13781
|
}
|
|
13063
13782
|
function readSettings(p) {
|
|
13064
13783
|
let raw;
|
|
13065
13784
|
try {
|
|
13066
|
-
raw =
|
|
13785
|
+
raw = fs10.readFileSync(p, "utf8");
|
|
13067
13786
|
} catch {
|
|
13068
13787
|
return {};
|
|
13069
13788
|
}
|
|
@@ -13103,7 +13822,7 @@ function installHooks(scope = "user") {
|
|
|
13103
13822
|
return { scope, settingsPath: p, alreadyInstalled: true };
|
|
13104
13823
|
}
|
|
13105
13824
|
settings.hooks = hooks;
|
|
13106
|
-
|
|
13825
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
13107
13826
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
13108
13827
|
`);
|
|
13109
13828
|
return { scope, settingsPath: p, alreadyInstalled: false };
|
|
@@ -13142,7 +13861,7 @@ function uninstallHooks(scope = "user") {
|
|
|
13142
13861
|
} else {
|
|
13143
13862
|
settings.hooks = hooks;
|
|
13144
13863
|
}
|
|
13145
|
-
|
|
13864
|
+
fs10.mkdirSync(path13.dirname(p), { recursive: true });
|
|
13146
13865
|
atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
|
|
13147
13866
|
`);
|
|
13148
13867
|
return true;
|
|
@@ -13151,21 +13870,21 @@ function uninstallHooks(scope = "user") {
|
|
|
13151
13870
|
// src/worker.ts
|
|
13152
13871
|
init_define_import_meta_env();
|
|
13153
13872
|
import { spawn } from "node:child_process";
|
|
13154
|
-
import * as
|
|
13155
|
-
import * as
|
|
13873
|
+
import * as fs11 from "node:fs";
|
|
13874
|
+
import * as path14 from "node:path";
|
|
13156
13875
|
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
|
|
13157
13876
|
import { fileURLToPath } from "node:url";
|
|
13158
13877
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
13159
13878
|
function dirtyQueuePathFor(dir) {
|
|
13160
|
-
return
|
|
13879
|
+
return path14.join(dir, "queue", "dirty.txt");
|
|
13161
13880
|
}
|
|
13162
13881
|
function workerPidPath(dir = dataDir()) {
|
|
13163
|
-
return
|
|
13882
|
+
return path14.join(dir, "worker.pid");
|
|
13164
13883
|
}
|
|
13165
13884
|
function getDirtyPathsFor(dir) {
|
|
13166
13885
|
let raw;
|
|
13167
13886
|
try {
|
|
13168
|
-
raw =
|
|
13887
|
+
raw = fs11.readFileSync(dirtyQueuePathFor(dir), "utf8");
|
|
13169
13888
|
} catch {
|
|
13170
13889
|
return [];
|
|
13171
13890
|
}
|
|
@@ -13181,7 +13900,7 @@ function getDirtyPathsFor(dir) {
|
|
|
13181
13900
|
}
|
|
13182
13901
|
function clearDirtyQueueFor(dir) {
|
|
13183
13902
|
try {
|
|
13184
|
-
|
|
13903
|
+
fs11.rmSync(dirtyQueuePathFor(dir), { force: true });
|
|
13185
13904
|
} catch {
|
|
13186
13905
|
}
|
|
13187
13906
|
}
|
|
@@ -13191,7 +13910,7 @@ function processDirtyBatch(paths, index = (absPath) => {
|
|
|
13191
13910
|
}) {
|
|
13192
13911
|
let indexed = 0;
|
|
13193
13912
|
for (const p of paths) {
|
|
13194
|
-
if (!
|
|
13913
|
+
if (!p || !fs11.existsSync(p)) continue;
|
|
13195
13914
|
const sha = fingerprintFile(p);
|
|
13196
13915
|
if (sha === null) continue;
|
|
13197
13916
|
index(p, sha);
|
|
@@ -13216,7 +13935,7 @@ function pidAlive(pid) {
|
|
|
13216
13935
|
}
|
|
13217
13936
|
function readPidFile(dir) {
|
|
13218
13937
|
try {
|
|
13219
|
-
const raw =
|
|
13938
|
+
const raw = fs11.readFileSync(workerPidPath(dir), "utf8").trim();
|
|
13220
13939
|
if (!/^\d+$/.test(raw)) return null;
|
|
13221
13940
|
return parseInt(raw, 10);
|
|
13222
13941
|
} catch {
|
|
@@ -13239,7 +13958,7 @@ function stopWorker(dir = dataDir()) {
|
|
|
13239
13958
|
}
|
|
13240
13959
|
}
|
|
13241
13960
|
try {
|
|
13242
|
-
|
|
13961
|
+
fs11.rmSync(workerPidPath(dir), { force: true });
|
|
13243
13962
|
} catch {
|
|
13244
13963
|
}
|
|
13245
13964
|
return alive;
|
|
@@ -13247,7 +13966,11 @@ function stopWorker(dir = dataDir()) {
|
|
|
13247
13966
|
function startDetachedWorker(opts) {
|
|
13248
13967
|
const pollIntervalMs = opts?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
13249
13968
|
const dir = opts?.dataDir ?? dataDir();
|
|
13250
|
-
|
|
13969
|
+
try {
|
|
13970
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13971
|
+
} catch (e) {
|
|
13972
|
+
if (e.code !== "EEXIST" || !fs11.existsSync(dir)) throw e;
|
|
13973
|
+
}
|
|
13251
13974
|
const child = spawn(
|
|
13252
13975
|
process.execPath,
|
|
13253
13976
|
[fileURLToPath(import.meta.url), "--worker-daemon"],
|
|
@@ -13266,7 +13989,7 @@ function startDetachedWorker(opts) {
|
|
|
13266
13989
|
if (pid === void 0) {
|
|
13267
13990
|
throw new Error("startDetachedWorker: spawn produced no pid");
|
|
13268
13991
|
}
|
|
13269
|
-
|
|
13992
|
+
fs11.writeFileSync(workerPidPath(dir), `${pid}
|
|
13270
13993
|
`);
|
|
13271
13994
|
child.unref();
|
|
13272
13995
|
return pid;
|
|
@@ -13309,7 +14032,7 @@ workerEntry();
|
|
|
13309
14032
|
|
|
13310
14033
|
// src/skill_cache.ts
|
|
13311
14034
|
init_define_import_meta_env();
|
|
13312
|
-
import * as
|
|
14035
|
+
import * as fs12 from "fs/promises";
|
|
13313
14036
|
import { resolve as resolve4 } from "path";
|
|
13314
14037
|
var COMPACT_END_MARKER = "<!-- COMPACT_END -->";
|
|
13315
14038
|
var _skillOutputsDirOverride = null;
|
|
@@ -13322,7 +14045,7 @@ function skillOutputsDir() {
|
|
|
13322
14045
|
}
|
|
13323
14046
|
async function ensureSkillsDir() {
|
|
13324
14047
|
try {
|
|
13325
|
-
await
|
|
14048
|
+
await fs12.mkdir(skillOutputsDir(), { recursive: true });
|
|
13326
14049
|
} catch {
|
|
13327
14050
|
}
|
|
13328
14051
|
}
|
|
@@ -13349,7 +14072,7 @@ function extractCompactFromMarker(body) {
|
|
|
13349
14072
|
const lines = body.split("\n");
|
|
13350
14073
|
for (let i = 0; i < lines.length; i++) {
|
|
13351
14074
|
const stripped = lines[i].trim();
|
|
13352
|
-
if (
|
|
14075
|
+
if (isCodeFenceDelimiter(stripped)) {
|
|
13353
14076
|
inCodeBlock = !inCodeBlock;
|
|
13354
14077
|
continue;
|
|
13355
14078
|
}
|
|
@@ -13364,14 +14087,14 @@ function extractCompactFromMarker(body) {
|
|
|
13364
14087
|
async function listOutputs() {
|
|
13365
14088
|
try {
|
|
13366
14089
|
const dir = skillOutputsDir();
|
|
13367
|
-
const entries = await
|
|
14090
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
13368
14091
|
const metas = [];
|
|
13369
14092
|
for (const entry of entries) {
|
|
13370
14093
|
if (!entry.isFile() || !entry.name.endsWith(".meta")) {
|
|
13371
14094
|
continue;
|
|
13372
14095
|
}
|
|
13373
14096
|
try {
|
|
13374
|
-
const content = await
|
|
14097
|
+
const content = await fs12.readFile(resolve4(dir, entry.name), "utf-8");
|
|
13375
14098
|
const meta = JSON.parse(content);
|
|
13376
14099
|
metas.push(meta);
|
|
13377
14100
|
} catch {
|
|
@@ -13416,13 +14139,13 @@ async function listSkills(sessionId) {
|
|
|
13416
14139
|
const compactFileId = `${safeSession}-${meta.skillName.replace(":", "_")}-compact`;
|
|
13417
14140
|
let compactLen = 0;
|
|
13418
14141
|
try {
|
|
13419
|
-
const stat3 = await
|
|
14142
|
+
const stat3 = await fs12.stat(resolve4(dir, compactFileId));
|
|
13420
14143
|
compactLen = stat3.size;
|
|
13421
14144
|
} catch {
|
|
13422
14145
|
compactLen = 0;
|
|
13423
14146
|
}
|
|
13424
14147
|
const hasMarker = extractCompactFromMarker(
|
|
13425
|
-
await
|
|
14148
|
+
await fs12.readFile(resolve4(dir, `${meta.outputId}.txt`), "utf-8").catch(() => "")
|
|
13426
14149
|
) !== null;
|
|
13427
14150
|
results.push({
|
|
13428
14151
|
name: meta.skillName,
|
|
@@ -13454,7 +14177,7 @@ async function getSkillFilePath(skillName) {
|
|
|
13454
14177
|
|
|
13455
14178
|
// src/config.ts
|
|
13456
14179
|
init_define_import_meta_env();
|
|
13457
|
-
import * as
|
|
14180
|
+
import * as fs13 from "node:fs";
|
|
13458
14181
|
|
|
13459
14182
|
// node_modules/smol-toml/dist/index.js
|
|
13460
14183
|
init_define_import_meta_env();
|
|
@@ -14186,8 +14909,8 @@ function envInt(key, defaultVal) {
|
|
|
14186
14909
|
}
|
|
14187
14910
|
|
|
14188
14911
|
// src/config.ts
|
|
14189
|
-
|
|
14190
|
-
|
|
14912
|
+
var CONFIG_DEFAULTS = {
|
|
14913
|
+
compact_assist: {
|
|
14191
14914
|
enabled: true,
|
|
14192
14915
|
triggers: ["manual", "auto"],
|
|
14193
14916
|
min_events: 3,
|
|
@@ -14202,10 +14925,8 @@ function defaultCompactAssistConfig() {
|
|
|
14202
14925
|
lazy_skill_injection: true,
|
|
14203
14926
|
max_manifest_chars: 1600,
|
|
14204
14927
|
harness: "auto"
|
|
14205
|
-
}
|
|
14206
|
-
|
|
14207
|
-
function defaultBashCompressConfig() {
|
|
14208
|
-
return {
|
|
14928
|
+
},
|
|
14929
|
+
bash_compress: {
|
|
14209
14930
|
enabled: true,
|
|
14210
14931
|
disabled_filters: [],
|
|
14211
14932
|
max_lines: 1e3,
|
|
@@ -14215,32 +14936,22 @@ function defaultBashCompressConfig() {
|
|
|
14215
14936
|
cache_max_file_count: 4096,
|
|
14216
14937
|
cache_max_bytes: 16 * 1024 * 1024,
|
|
14217
14938
|
cache_max_bytes_per_output: 50 * 1024 * 1024
|
|
14218
|
-
}
|
|
14219
|
-
|
|
14220
|
-
function defaultBashDiffConfig() {
|
|
14221
|
-
return {
|
|
14939
|
+
},
|
|
14940
|
+
bash_diff: {
|
|
14222
14941
|
max_hunks_per_file: 10,
|
|
14223
14942
|
hunk_density_cap: true
|
|
14224
|
-
}
|
|
14225
|
-
|
|
14226
|
-
function defaultSeverityLogConfig() {
|
|
14227
|
-
return {
|
|
14943
|
+
},
|
|
14944
|
+
bash_severity_log: {
|
|
14228
14945
|
context_lines: 3,
|
|
14229
14946
|
score_threshold: 0.5
|
|
14230
|
-
}
|
|
14231
|
-
|
|
14232
|
-
function defaultCodeCompressConfig() {
|
|
14233
|
-
return {
|
|
14947
|
+
},
|
|
14948
|
+
post_read_code_compress: {
|
|
14234
14949
|
min_lines: 200
|
|
14235
|
-
}
|
|
14236
|
-
|
|
14237
|
-
function defaultSessionBriefConfig() {
|
|
14238
|
-
return {
|
|
14950
|
+
},
|
|
14951
|
+
session_brief: {
|
|
14239
14952
|
enabled: true
|
|
14240
|
-
}
|
|
14241
|
-
|
|
14242
|
-
function defaultSkillPreservationConfig() {
|
|
14243
|
-
return {
|
|
14953
|
+
},
|
|
14954
|
+
skill_preservation: {
|
|
14244
14955
|
enabled: true,
|
|
14245
14956
|
max_cache_bytes: 5 * 1024 * 1024,
|
|
14246
14957
|
orphan_sweep_enabled: true,
|
|
@@ -14252,25 +14963,19 @@ function defaultSkillPreservationConfig() {
|
|
|
14252
14963
|
pre_skill_enabled: true,
|
|
14253
14964
|
first_load_compact: false,
|
|
14254
14965
|
post_compact_full_loads: false
|
|
14255
|
-
}
|
|
14256
|
-
|
|
14257
|
-
function defaultCuratorConfig() {
|
|
14258
|
-
return {
|
|
14966
|
+
},
|
|
14967
|
+
curator: {
|
|
14259
14968
|
enabled: true,
|
|
14260
14969
|
min_samples: 10,
|
|
14261
14970
|
threshold_pct: 20
|
|
14262
|
-
}
|
|
14263
|
-
|
|
14264
|
-
function defaultHintBudgetConfig() {
|
|
14265
|
-
return {
|
|
14971
|
+
},
|
|
14972
|
+
hint_budget: {
|
|
14266
14973
|
enabled: true,
|
|
14267
14974
|
max_per_session: 100,
|
|
14268
14975
|
max_structured_per_session: 30,
|
|
14269
14976
|
max_index_only_per_session: 30
|
|
14270
|
-
}
|
|
14271
|
-
|
|
14272
|
-
function defaultImageShrinkConfig() {
|
|
14273
|
-
return {
|
|
14977
|
+
},
|
|
14978
|
+
image_shrink: {
|
|
14274
14979
|
prefer_avif: true,
|
|
14275
14980
|
avif_quality: 60,
|
|
14276
14981
|
jpeg_quality: 75,
|
|
@@ -14278,27 +14983,19 @@ function defaultImageShrinkConfig() {
|
|
|
14278
14983
|
orphan_sweep_enabled: true,
|
|
14279
14984
|
orphan_age_secs: 604800,
|
|
14280
14985
|
screenshot_redirect: true
|
|
14281
|
-
}
|
|
14282
|
-
|
|
14283
|
-
function defaultRepomapConfig() {
|
|
14284
|
-
return {
|
|
14986
|
+
},
|
|
14987
|
+
repomap: {
|
|
14285
14988
|
compact_file_threshold: 50,
|
|
14286
14989
|
exclude_tests: true
|
|
14287
|
-
}
|
|
14288
|
-
|
|
14289
|
-
function defaultOverflowGuardConfig() {
|
|
14290
|
-
return {
|
|
14990
|
+
},
|
|
14991
|
+
overflow_guard: {
|
|
14291
14992
|
enabled: true,
|
|
14292
14993
|
max_tokens: 25e3
|
|
14293
|
-
}
|
|
14294
|
-
|
|
14295
|
-
function defaultStatsConfig() {
|
|
14296
|
-
return {
|
|
14994
|
+
},
|
|
14995
|
+
stats: {
|
|
14297
14996
|
record_zero_savings: false
|
|
14298
|
-
}
|
|
14299
|
-
|
|
14300
|
-
function defaultHintsConfig() {
|
|
14301
|
-
return {
|
|
14997
|
+
},
|
|
14998
|
+
hints: {
|
|
14302
14999
|
suppress_after_ignored: 5,
|
|
14303
15000
|
quiet_hours: "",
|
|
14304
15001
|
json_sidecar: false,
|
|
@@ -14322,51 +15019,40 @@ function defaultHintsConfig() {
|
|
|
14322
15019
|
truncated_read_min_lines: 200,
|
|
14323
15020
|
protect_recent_reads: 4,
|
|
14324
15021
|
prompt_triggers: []
|
|
14325
|
-
}
|
|
14326
|
-
|
|
14327
|
-
function defaultHooksConfig() {
|
|
14328
|
-
return {
|
|
15022
|
+
},
|
|
15023
|
+
hooks: {
|
|
14329
15024
|
watchdog_ms: 700
|
|
14330
|
-
}
|
|
14331
|
-
|
|
14332
|
-
function defaultWebFetchConfig() {
|
|
14333
|
-
return {
|
|
15025
|
+
},
|
|
15026
|
+
webfetch: {
|
|
14334
15027
|
allow: [],
|
|
14335
15028
|
deny: [],
|
|
14336
15029
|
max_file_count: 4096,
|
|
14337
15030
|
max_bytes: 32 * 1024 * 1024,
|
|
14338
15031
|
compress_bodies: true,
|
|
14339
15032
|
compress_min_bytes: 16 * 1024
|
|
14340
|
-
}
|
|
14341
|
-
|
|
14342
|
-
function defaultWorkerConfig() {
|
|
14343
|
-
return {
|
|
15033
|
+
},
|
|
15034
|
+
worker: {
|
|
14344
15035
|
watchdog_enabled: true,
|
|
14345
15036
|
max_pool_workers: 4,
|
|
14346
15037
|
blocked_roots: []
|
|
14347
|
-
}
|
|
14348
|
-
|
|
14349
|
-
function defaultIndexingConfig() {
|
|
14350
|
-
return {
|
|
15038
|
+
},
|
|
15039
|
+
indexing: {
|
|
14351
15040
|
large_file_symbol_only_kb: 500,
|
|
14352
15041
|
large_file_skip_kb: 2048,
|
|
14353
15042
|
skip_dirs: []
|
|
14354
|
-
}
|
|
14355
|
-
|
|
14356
|
-
function defaultCompressionConfig() {
|
|
14357
|
-
return {
|
|
15043
|
+
},
|
|
15044
|
+
compression: {
|
|
14358
15045
|
profile: "auto"
|
|
14359
|
-
}
|
|
14360
|
-
|
|
14361
|
-
function defaultContextConfig() {
|
|
14362
|
-
return {
|
|
15046
|
+
},
|
|
15047
|
+
context: {
|
|
14363
15048
|
model_window_tokens: 2e5
|
|
14364
|
-
}
|
|
14365
|
-
|
|
14366
|
-
function defaultInjectionConfig() {
|
|
14367
|
-
return {
|
|
15049
|
+
},
|
|
15050
|
+
injection: {
|
|
14368
15051
|
enabled: true
|
|
14369
|
-
}
|
|
15052
|
+
}
|
|
15053
|
+
};
|
|
15054
|
+
function getDefaultConfig(section2) {
|
|
15055
|
+
return structuredClone(CONFIG_DEFAULTS[section2] ?? {});
|
|
14370
15056
|
}
|
|
14371
15057
|
function validatedBool(raw, def) {
|
|
14372
15058
|
if (typeof raw === "boolean") return raw;
|
|
@@ -14439,7 +15125,7 @@ function loadConfig() {
|
|
|
14439
15125
|
const p = configPath();
|
|
14440
15126
|
let currentMtime = 0;
|
|
14441
15127
|
try {
|
|
14442
|
-
currentMtime =
|
|
15128
|
+
currentMtime = fs13.statSync(p).mtimeMs;
|
|
14443
15129
|
} catch {
|
|
14444
15130
|
}
|
|
14445
15131
|
const envFp = configEnvFingerprint();
|
|
@@ -14449,7 +15135,7 @@ function loadConfig() {
|
|
|
14449
15135
|
let raw = {};
|
|
14450
15136
|
if (currentMtime !== 0) {
|
|
14451
15137
|
try {
|
|
14452
|
-
const text =
|
|
15138
|
+
const text = fs13.readFileSync(p, "utf8");
|
|
14453
15139
|
raw = parse(text);
|
|
14454
15140
|
} catch {
|
|
14455
15141
|
}
|
|
@@ -14460,7 +15146,7 @@ function loadConfig() {
|
|
|
14460
15146
|
}
|
|
14461
15147
|
function _buildConfig(raw) {
|
|
14462
15148
|
const ca_raw = section(raw, "compact_assist");
|
|
14463
|
-
const ca =
|
|
15149
|
+
const ca = getDefaultConfig("compact_assist");
|
|
14464
15150
|
ca.enabled = validatedBool(ca_raw["enabled"], ca.enabled);
|
|
14465
15151
|
ca.triggers = validatedStrList(ca_raw["triggers"], ca.triggers);
|
|
14466
15152
|
ca.min_events = validatedInt(ca_raw["min_events"], ca.min_events, 0, 1e3);
|
|
@@ -14478,7 +15164,7 @@ function _buildConfig(raw) {
|
|
|
14478
15164
|
ca.enabled = envBool("TOKEN_GOAT_COMPACT_ASSIST", envBool("TOKENWISE_COMPACT_ASSIST", ca.enabled));
|
|
14479
15165
|
ca.lazy_skill_injection = envBool("TOKEN_GOAT_LAZY_SKILL_INJECTION", ca.lazy_skill_injection);
|
|
14480
15166
|
const bc_raw = section(raw, "bash_compress");
|
|
14481
|
-
const bc =
|
|
15167
|
+
const bc = getDefaultConfig("bash_compress");
|
|
14482
15168
|
bc.enabled = validatedBool(bc_raw["enabled"], bc.enabled);
|
|
14483
15169
|
bc.disabled_filters = validatedStrList(bc_raw["disabled_filters"], bc.disabled_filters);
|
|
14484
15170
|
bc.max_lines = validatedInt(bc_raw["max_lines"], bc.max_lines, 50, 1e5);
|
|
@@ -14494,22 +15180,22 @@ function _buildConfig(raw) {
|
|
|
14494
15180
|
bc.cache_max_bytes = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES", bc.cache_max_bytes);
|
|
14495
15181
|
bc.cache_max_bytes_per_output = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT", bc.cache_max_bytes_per_output);
|
|
14496
15182
|
const bd_raw = section(raw, "bash_diff");
|
|
14497
|
-
const bd =
|
|
15183
|
+
const bd = getDefaultConfig("bash_diff");
|
|
14498
15184
|
bd.max_hunks_per_file = validatedInt(bd_raw["max_hunks_per_file"], bd.max_hunks_per_file, 1, 1e4);
|
|
14499
15185
|
bd.hunk_density_cap = validatedBool(bd_raw["hunk_density_cap"], bd.hunk_density_cap);
|
|
14500
15186
|
const sl_raw = section(raw, "bash_severity_log");
|
|
14501
|
-
const sl =
|
|
15187
|
+
const sl = getDefaultConfig("bash_severity_log");
|
|
14502
15188
|
sl.context_lines = validatedInt(sl_raw["context_lines"], sl.context_lines, 0, 100);
|
|
14503
15189
|
sl.score_threshold = validatedFloat(sl_raw["score_threshold"], sl.score_threshold, 0, 1);
|
|
14504
15190
|
const cc_raw = section(raw, "post_read_code_compress");
|
|
14505
|
-
const cc =
|
|
15191
|
+
const cc = getDefaultConfig("post_read_code_compress");
|
|
14506
15192
|
cc.min_lines = validatedInt(cc_raw["min_lines"], cc.min_lines, 0, 1e6);
|
|
14507
15193
|
const sb_raw = section(raw, "session_brief");
|
|
14508
|
-
const sb =
|
|
15194
|
+
const sb = getDefaultConfig("session_brief");
|
|
14509
15195
|
sb.enabled = validatedBool(sb_raw["enabled"], sb.enabled);
|
|
14510
15196
|
sb.enabled = envBool("TOKEN_GOAT_SESSION_BRIEF", sb.enabled);
|
|
14511
15197
|
const sp_raw = section(raw, "skill_preservation");
|
|
14512
|
-
const sp =
|
|
15198
|
+
const sp = getDefaultConfig("skill_preservation");
|
|
14513
15199
|
sp.enabled = validatedBool(sp_raw["enabled"], sp.enabled);
|
|
14514
15200
|
sp.max_cache_bytes = validatedInt(sp_raw["max_cache_bytes"], sp.max_cache_bytes, 64 * 1024, 512 * 1024 * 1024);
|
|
14515
15201
|
sp.orphan_sweep_enabled = validatedBool(sp_raw["orphan_sweep_enabled"], sp.orphan_sweep_enabled);
|
|
@@ -14526,7 +15212,7 @@ function _buildConfig(raw) {
|
|
|
14526
15212
|
sp.pre_skill_enabled = envBool("TOKEN_GOAT_PRE_SKILL", sp.pre_skill_enabled);
|
|
14527
15213
|
sp.orphan_sweep_enabled = envBool("TOKEN_GOAT_ORPHAN_SWEEP", sp.orphan_sweep_enabled);
|
|
14528
15214
|
const is_raw = section(raw, "image_shrink");
|
|
14529
|
-
const is_cfg =
|
|
15215
|
+
const is_cfg = getDefaultConfig("image_shrink");
|
|
14530
15216
|
is_cfg.prefer_avif = validatedBool(is_raw["prefer_avif"], is_cfg.prefer_avif);
|
|
14531
15217
|
is_cfg.avif_quality = validatedInt(is_raw["avif_quality"], is_cfg.avif_quality, 1, 100);
|
|
14532
15218
|
is_cfg.jpeg_quality = validatedInt(is_raw["jpeg_quality"], is_cfg.jpeg_quality, 1, 100);
|
|
@@ -14537,33 +15223,33 @@ function _buildConfig(raw) {
|
|
|
14537
15223
|
is_cfg.prefer_avif = envBool("TOKEN_GOAT_PREFER_AVIF", is_cfg.prefer_avif);
|
|
14538
15224
|
is_cfg.max_image_pixels = envInt("TOKEN_GOAT_MAX_IMAGE_PIXELS", is_cfg.max_image_pixels);
|
|
14539
15225
|
const cur_raw = section(raw, "curator");
|
|
14540
|
-
const cur =
|
|
15226
|
+
const cur = getDefaultConfig("curator");
|
|
14541
15227
|
cur.enabled = validatedBool(cur_raw["enabled"], cur.enabled);
|
|
14542
15228
|
cur.min_samples = validatedInt(cur_raw["min_samples"], cur.min_samples, 0, 1e4);
|
|
14543
15229
|
cur.threshold_pct = validatedInt(cur_raw["threshold_pct"], cur.threshold_pct, 0, 100);
|
|
14544
15230
|
cur.enabled = envBool("TOKEN_GOAT_CURATOR", cur.enabled);
|
|
14545
15231
|
const hb_raw = section(raw, "hint_budget");
|
|
14546
|
-
const hb =
|
|
15232
|
+
const hb = getDefaultConfig("hint_budget");
|
|
14547
15233
|
hb.enabled = validatedBool(hb_raw["enabled"], hb.enabled);
|
|
14548
15234
|
hb.max_per_session = validatedInt(hb_raw["max_per_session"], hb.max_per_session, 0, 1e6);
|
|
14549
15235
|
hb.max_structured_per_session = validatedInt(hb_raw["max_structured_per_session"], hb.max_structured_per_session, 0, 1e6);
|
|
14550
15236
|
hb.max_index_only_per_session = validatedInt(hb_raw["max_index_only_per_session"], hb.max_index_only_per_session, 0, 1e6);
|
|
14551
15237
|
hb.enabled = envBool("TOKEN_GOAT_HINT_BUDGET", hb.enabled);
|
|
14552
15238
|
const rm_raw = section(raw, "repomap");
|
|
14553
|
-
const rm =
|
|
15239
|
+
const rm = getDefaultConfig("repomap");
|
|
14554
15240
|
rm.compact_file_threshold = validatedInt(rm_raw["compact_file_threshold"], rm.compact_file_threshold, 0, 1e5);
|
|
14555
15241
|
rm.exclude_tests = validatedBool(rm_raw["exclude_tests"], rm.exclude_tests);
|
|
14556
15242
|
rm.compact_file_threshold = envInt("TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD", rm.compact_file_threshold);
|
|
14557
15243
|
rm.exclude_tests = envBool("TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS", rm.exclude_tests);
|
|
14558
15244
|
const og_raw = section(raw, "overflow_guard");
|
|
14559
|
-
const og =
|
|
15245
|
+
const og = getDefaultConfig("overflow_guard");
|
|
14560
15246
|
og.enabled = validatedBool(og_raw["enabled"], og.enabled);
|
|
14561
15247
|
og.max_tokens = validatedInt(og_raw["max_tokens"], og.max_tokens, 1e3, 1e6);
|
|
14562
15248
|
const st_raw = section(raw, "stats");
|
|
14563
|
-
const st =
|
|
15249
|
+
const st = getDefaultConfig("stats");
|
|
14564
15250
|
st.record_zero_savings = validatedBool(st_raw["record_zero_savings"], st.record_zero_savings);
|
|
14565
15251
|
const hi_raw = section(raw, "hints");
|
|
14566
|
-
const hi =
|
|
15252
|
+
const hi = getDefaultConfig("hints");
|
|
14567
15253
|
hi.suppress_after_ignored = validatedInt(hi_raw["suppress_after_ignored"], hi.suppress_after_ignored, 0, 1e3);
|
|
14568
15254
|
hi.quiet_hours = validatedStr(hi_raw["quiet_hours"], hi.quiet_hours);
|
|
14569
15255
|
hi.json_sidecar = validatedBool(hi_raw["json_sidecar"], hi.json_sidecar);
|
|
@@ -14596,11 +15282,11 @@ function _buildConfig(raw) {
|
|
|
14596
15282
|
})).filter((t) => t.keywords.length > 0 && t.hint.length > 0);
|
|
14597
15283
|
}
|
|
14598
15284
|
const hk_raw = section(raw, "hooks");
|
|
14599
|
-
const hk =
|
|
15285
|
+
const hk = getDefaultConfig("hooks");
|
|
14600
15286
|
hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, 100, 3e4);
|
|
14601
15287
|
hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms);
|
|
14602
15288
|
const wf_raw = section(raw, "webfetch");
|
|
14603
|
-
const wf =
|
|
15289
|
+
const wf = getDefaultConfig("webfetch");
|
|
14604
15290
|
wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
|
|
14605
15291
|
wf.deny = validatedStrList(wf_raw["deny"], wf.deny);
|
|
14606
15292
|
wf.max_file_count = validatedInt(wf_raw["max_file_count"], wf.max_file_count, 0, 1e7);
|
|
@@ -14609,27 +15295,27 @@ function _buildConfig(raw) {
|
|
|
14609
15295
|
wf.compress_min_bytes = validatedInt(wf_raw["compress_min_bytes"], wf.compress_min_bytes, 1024, 10 * 1024 * 1024);
|
|
14610
15296
|
wf.compress_bodies = envBool("TOKEN_GOAT_WEB_COMPRESS", wf.compress_bodies);
|
|
14611
15297
|
const wk_raw = section(raw, "worker");
|
|
14612
|
-
const wk =
|
|
15298
|
+
const wk = getDefaultConfig("worker");
|
|
14613
15299
|
wk.watchdog_enabled = validatedBool(wk_raw["watchdog_enabled"], wk.watchdog_enabled);
|
|
14614
15300
|
wk.max_pool_workers = validatedInt(wk_raw["max_pool_workers"], wk.max_pool_workers, 1, 8);
|
|
14615
15301
|
wk.blocked_roots = validatedStrList(wk_raw["blocked_roots"], wk.blocked_roots);
|
|
14616
15302
|
wk.watchdog_enabled = envBool("TOKEN_GOAT_WORKER_WATCHDOG", wk.watchdog_enabled);
|
|
14617
15303
|
wk.max_pool_workers = envInt("TOKEN_GOAT_WORKER_MAX_POOL", wk.max_pool_workers);
|
|
14618
15304
|
const ix_raw = section(raw, "indexing");
|
|
14619
|
-
const ix =
|
|
15305
|
+
const ix = getDefaultConfig("indexing");
|
|
14620
15306
|
ix.large_file_symbol_only_kb = validatedInt(ix_raw["large_file_symbol_only_kb"], ix.large_file_symbol_only_kb, 1, 1048576);
|
|
14621
15307
|
ix.large_file_skip_kb = validatedInt(ix_raw["large_file_skip_kb"], ix.large_file_skip_kb, 1, 1048576);
|
|
14622
15308
|
ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
|
|
14623
15309
|
const cpr_raw = section(raw, "compression");
|
|
14624
|
-
const cpr =
|
|
15310
|
+
const cpr = getDefaultConfig("compression");
|
|
14625
15311
|
cpr.profile = validatedStr(cpr_raw["profile"], cpr.profile);
|
|
14626
15312
|
cpr.profile = envStr("TOKEN_GOAT_COMPRESS_PROFILE", cpr.profile);
|
|
14627
15313
|
const ctx_raw = section(raw, "context");
|
|
14628
|
-
const ctx =
|
|
15314
|
+
const ctx = getDefaultConfig("context");
|
|
14629
15315
|
ctx.model_window_tokens = validatedInt(ctx_raw["model_window_tokens"], ctx.model_window_tokens, 1e4, 1e7);
|
|
14630
15316
|
ctx.model_window_tokens = envInt("TOKEN_GOAT_MODEL_WINDOW_TOKENS", ctx.model_window_tokens);
|
|
14631
15317
|
const inj_raw = section(raw, "injection");
|
|
14632
|
-
const inj =
|
|
15318
|
+
const inj = getDefaultConfig("injection");
|
|
14633
15319
|
inj.enabled = validatedBool(inj_raw["enabled"], inj.enabled);
|
|
14634
15320
|
inj.enabled = envBool("TOKEN_GOAT_INJECTION_ENABLED", inj.enabled);
|
|
14635
15321
|
return {
|
|
@@ -14659,9 +15345,9 @@ function _buildConfig(raw) {
|
|
|
14659
15345
|
|
|
14660
15346
|
// src/cli_doctor.ts
|
|
14661
15347
|
init_define_import_meta_env();
|
|
14662
|
-
import * as
|
|
14663
|
-
import * as
|
|
14664
|
-
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";
|
|
14665
15351
|
function checkWorkerRunning() {
|
|
14666
15352
|
try {
|
|
14667
15353
|
const output = execSync("tasklist", { encoding: "utf-8" });
|
|
@@ -14671,8 +15357,8 @@ function checkWorkerRunning() {
|
|
|
14671
15357
|
}
|
|
14672
15358
|
}
|
|
14673
15359
|
function checkDbExists(dataDir2) {
|
|
14674
|
-
const dbPath =
|
|
14675
|
-
if (!
|
|
15360
|
+
const dbPath = path15.join(dataDir2, "index.db");
|
|
15361
|
+
if (!fs14.existsSync(dbPath)) {
|
|
14676
15362
|
return {
|
|
14677
15363
|
name: "Database",
|
|
14678
15364
|
status: "warn",
|
|
@@ -14682,7 +15368,7 @@ function checkDbExists(dataDir2) {
|
|
|
14682
15368
|
return {
|
|
14683
15369
|
name: "Database",
|
|
14684
15370
|
status: "ok",
|
|
14685
|
-
message: `index.db exists (${Math.round(
|
|
15371
|
+
message: `index.db exists (${Math.round(fs14.statSync(dbPath).size / 1024)} KB)`
|
|
14686
15372
|
};
|
|
14687
15373
|
}
|
|
14688
15374
|
function checkInstall() {
|
|
@@ -14702,7 +15388,7 @@ function checkInstall() {
|
|
|
14702
15388
|
}
|
|
14703
15389
|
}
|
|
14704
15390
|
function checkConfigValid(configPath2) {
|
|
14705
|
-
if (!
|
|
15391
|
+
if (!fs14.existsSync(configPath2)) {
|
|
14706
15392
|
return {
|
|
14707
15393
|
name: "Config",
|
|
14708
15394
|
status: "warn",
|
|
@@ -14710,7 +15396,7 @@ function checkConfigValid(configPath2) {
|
|
|
14710
15396
|
};
|
|
14711
15397
|
}
|
|
14712
15398
|
try {
|
|
14713
|
-
const content =
|
|
15399
|
+
const content = fs14.readFileSync(configPath2, "utf-8");
|
|
14714
15400
|
JSON.parse(content);
|
|
14715
15401
|
return {
|
|
14716
15402
|
name: "Config",
|
|
@@ -14721,18 +15407,22 @@ function checkConfigValid(configPath2) {
|
|
|
14721
15407
|
return {
|
|
14722
15408
|
name: "Config",
|
|
14723
15409
|
status: "fail",
|
|
14724
|
-
message: `config invalid: ${err2
|
|
15410
|
+
message: `config invalid: ${extractErrorMessage(err2, "unknown error")}`
|
|
14725
15411
|
};
|
|
14726
15412
|
}
|
|
14727
15413
|
}
|
|
14728
15414
|
function checkDiskSpace(dataDir2) {
|
|
14729
15415
|
try {
|
|
14730
|
-
const
|
|
14731
|
-
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");
|
|
14732
15422
|
if (lines.length < 2) {
|
|
14733
15423
|
return { name: "Disk Space", status: "warn", message: "could not determine" };
|
|
14734
15424
|
}
|
|
14735
|
-
const parts = lines[1].split(/\s+/);
|
|
15425
|
+
const parts = lines[1].trim().split(/\s+/);
|
|
14736
15426
|
const available = parts[3] || "unknown";
|
|
14737
15427
|
return { name: "Disk Space", status: "ok", message: `${available} available` };
|
|
14738
15428
|
} catch {
|
|
@@ -14744,9 +15434,9 @@ function runDoctor(dataDir2, configPath2) {
|
|
|
14744
15434
|
results.push(checkInstall());
|
|
14745
15435
|
results.push(checkWorkerRunning() ? { name: "Worker", status: "ok", message: "running" } : { name: "Worker", status: "warn", message: "not running" });
|
|
14746
15436
|
const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
14747
|
-
const actualDataDir = dataDir2 ||
|
|
15437
|
+
const actualDataDir = dataDir2 || path15.join(homeDir, ".token-goat");
|
|
14748
15438
|
results.push(checkDbExists(actualDataDir));
|
|
14749
|
-
const actualConfigPath = configPath2 ||
|
|
15439
|
+
const actualConfigPath = configPath2 || path15.join(actualDataDir, "config.json");
|
|
14750
15440
|
results.push(checkConfigValid(actualConfigPath));
|
|
14751
15441
|
results.push(checkDiskSpace(actualDataDir));
|
|
14752
15442
|
return results;
|
|
@@ -14785,7 +15475,7 @@ init_define_import_meta_env();
|
|
|
14785
15475
|
var _byId2 = /* @__PURE__ */ new Map();
|
|
14786
15476
|
var _urlIndex = /* @__PURE__ */ new Map();
|
|
14787
15477
|
function cacheIdForUrl(url) {
|
|
14788
|
-
return
|
|
15478
|
+
return shortFingerprint(url);
|
|
14789
15479
|
}
|
|
14790
15480
|
function storeWebOutput(url, content) {
|
|
14791
15481
|
const cacheId = cacheIdForUrl(url);
|
|
@@ -14905,12 +15595,10 @@ async function getSectionContent(fileId, heading) {
|
|
|
14905
15595
|
var CliError = class extends Error {
|
|
14906
15596
|
};
|
|
14907
15597
|
function out(text) {
|
|
14908
|
-
process.stdout.write(text
|
|
14909
|
-
`);
|
|
15598
|
+
process.stdout.write(ensureNewline(text));
|
|
14910
15599
|
}
|
|
14911
15600
|
function err(text) {
|
|
14912
|
-
process.stderr.write(text
|
|
14913
|
-
`);
|
|
15601
|
+
process.stderr.write(ensureNewline(text));
|
|
14914
15602
|
}
|
|
14915
15603
|
function previewLines(body, n) {
|
|
14916
15604
|
return body.split(/\r?\n/).slice(0, n).join("\n");
|
|
@@ -15070,7 +15758,7 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
15070
15758
|
const n = Number.parseInt(opts.tail, 10);
|
|
15071
15759
|
return Number.isFinite(n) && n > 0 ? n : 80;
|
|
15072
15760
|
})() : 80;
|
|
15073
|
-
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;
|
|
15074
15762
|
let result = lines;
|
|
15075
15763
|
if (opts.head === void 0 && opts.tail === void 0 && opts.grep === void 0) {
|
|
15076
15764
|
result = applyElision(lines, headN, tailN);
|
|
@@ -15085,10 +15773,21 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
15085
15773
|
}
|
|
15086
15774
|
function cmdBashOutput(id, opts) {
|
|
15087
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
|
+
}
|
|
15088
15782
|
let content;
|
|
15089
15783
|
try {
|
|
15090
|
-
|
|
15091
|
-
|
|
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;
|
|
15092
15791
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
15093
15792
|
}
|
|
15094
15793
|
_applyFiltersAndPrint(content, opts);
|
|
@@ -15108,12 +15807,12 @@ async function cmdSkillBody(name, opts) {
|
|
|
15108
15807
|
if (filePath === null) {
|
|
15109
15808
|
throw new CliError(`skill '${name}' not found`);
|
|
15110
15809
|
}
|
|
15111
|
-
const body =
|
|
15810
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
15112
15811
|
if (opts.compact === true) {
|
|
15113
15812
|
const lines = body.split("\n");
|
|
15114
15813
|
const end = lines.findIndex((l) => l.includes("COMPACT_END"));
|
|
15115
15814
|
if (end !== -1) {
|
|
15116
|
-
out(lines.slice(
|
|
15815
|
+
out(lines.slice(end + 1).join("\n"));
|
|
15117
15816
|
} else {
|
|
15118
15817
|
out(body);
|
|
15119
15818
|
}
|
|
@@ -15126,7 +15825,7 @@ async function cmdSkillCompact(name) {
|
|
|
15126
15825
|
if (filePath === null) {
|
|
15127
15826
|
throw new CliError(`skill '${name}' not found`);
|
|
15128
15827
|
}
|
|
15129
|
-
const body =
|
|
15828
|
+
const body = fs15.readFileSync(filePath, "utf-8");
|
|
15130
15829
|
const sessionFiles = getSessionFiles();
|
|
15131
15830
|
const sessionId = Array.from(sessionFiles.keys())[0] ?? "default";
|
|
15132
15831
|
await storeCompact(sessionId, name, body);
|
|
@@ -15213,7 +15912,7 @@ function cmdConfigGet(file, key) {
|
|
|
15213
15912
|
}
|
|
15214
15913
|
function atomicWriteBuffer(dest, data) {
|
|
15215
15914
|
try {
|
|
15216
|
-
if (
|
|
15915
|
+
if (fs15.statSync(dest).isDirectory()) {
|
|
15217
15916
|
const e = Object.assign(new Error(`EISDIR: illegal operation on a directory, open '${dest}'`), { code: "EISDIR", path: dest });
|
|
15218
15917
|
throw e;
|
|
15219
15918
|
}
|
|
@@ -15221,16 +15920,16 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15221
15920
|
if (e.code !== "ENOENT") throw e;
|
|
15222
15921
|
}
|
|
15223
15922
|
const rnd = Math.random().toString(36).slice(2, 8);
|
|
15224
|
-
const tmp =
|
|
15923
|
+
const tmp = path16.join(path16.dirname(path16.resolve(dest)), `.tmp.${process.pid}.${rnd}`);
|
|
15225
15924
|
try {
|
|
15226
|
-
|
|
15925
|
+
fs15.writeFileSync(tmp, data, { mode: 384 });
|
|
15227
15926
|
try {
|
|
15228
|
-
|
|
15927
|
+
fs15.renameSync(tmp, dest);
|
|
15229
15928
|
} catch (e) {
|
|
15230
15929
|
if (e.code === "EXDEV") {
|
|
15231
|
-
|
|
15930
|
+
fs15.copyFileSync(tmp, dest);
|
|
15232
15931
|
try {
|
|
15233
|
-
|
|
15932
|
+
fs15.unlinkSync(tmp);
|
|
15234
15933
|
} catch (ue) {
|
|
15235
15934
|
process.stderr.write(`token-goat write-file: warning: could not remove temp file ${tmp}: ${ue.message}
|
|
15236
15935
|
`);
|
|
@@ -15241,7 +15940,7 @@ function atomicWriteBuffer(dest, data) {
|
|
|
15241
15940
|
}
|
|
15242
15941
|
} catch (e) {
|
|
15243
15942
|
try {
|
|
15244
|
-
|
|
15943
|
+
fs15.unlinkSync(tmp);
|
|
15245
15944
|
} catch {
|
|
15246
15945
|
}
|
|
15247
15946
|
throw e;
|
|
@@ -15251,9 +15950,9 @@ function mapFsError(e, src, dest) {
|
|
|
15251
15950
|
const fe = e;
|
|
15252
15951
|
if (fe.code === "ENOENT") {
|
|
15253
15952
|
const errPath = fe.path ?? "";
|
|
15254
|
-
const isSource = src !== void 0 &&
|
|
15953
|
+
const isSource = src !== void 0 && path16.resolve(errPath) === path16.resolve(src);
|
|
15255
15954
|
if (isSource) throw new CliError(`source file not found: ${src}`);
|
|
15256
|
-
const destDir = dest ?
|
|
15955
|
+
const destDir = dest ? path16.dirname(path16.resolve(dest)) : path16.dirname(path16.resolve(errPath || "."));
|
|
15257
15956
|
throw new CliError(`destination directory does not exist: ${destDir}`);
|
|
15258
15957
|
}
|
|
15259
15958
|
if (fe.code === "ENOTDIR") {
|
|
@@ -15261,7 +15960,7 @@ function mapFsError(e, src, dest) {
|
|
|
15261
15960
|
}
|
|
15262
15961
|
if (fe.code === "EISDIR") {
|
|
15263
15962
|
const errPath = fe.path ?? "";
|
|
15264
|
-
const isSource = src !== void 0 && (errPath === "" ||
|
|
15963
|
+
const isSource = src !== void 0 && (errPath === "" || path16.resolve(errPath) === path16.resolve(src));
|
|
15265
15964
|
if (isSource) throw new CliError(`source is a directory, not a file: ${src}`);
|
|
15266
15965
|
throw new CliError(`destination is a directory, not a file: ${dest ?? (errPath || "(unknown)")}`);
|
|
15267
15966
|
}
|
|
@@ -15326,8 +16025,8 @@ function cmdWriteFile(dest, opts) {
|
|
|
15326
16025
|
if (dest.includes("\0")) {
|
|
15327
16026
|
throw new CliError("destination path contains a null byte");
|
|
15328
16027
|
}
|
|
15329
|
-
if (
|
|
15330
|
-
const base =
|
|
16028
|
+
if (isWindows()) {
|
|
16029
|
+
const base = path16.basename(dest);
|
|
15331
16030
|
const stem = base.replace(/\.[^.]*$/, "").toUpperCase();
|
|
15332
16031
|
if (WIN_RESERVED.has(stem)) {
|
|
15333
16032
|
throw new CliError(`destination '${base}' is a reserved Windows device name`);
|
|
@@ -15346,20 +16045,23 @@ function cmdWriteFile(dest, opts) {
|
|
|
15346
16045
|
if (opts.from.includes("\0")) {
|
|
15347
16046
|
throw new CliError("--from path contains a null byte");
|
|
15348
16047
|
}
|
|
15349
|
-
if (
|
|
16048
|
+
if (!isWindows() && /^\/dev\/(stdin|fd\/0)$|^\/proc\/self\/fd\/0$/.test(opts.from) && process.stdin.isTTY) {
|
|
15350
16049
|
throw new CliError("--from /dev/stdin requires piped input; use piped stdin mode or --b64 for interactive use");
|
|
15351
16050
|
}
|
|
15352
16051
|
try {
|
|
15353
|
-
const st =
|
|
16052
|
+
const st = fs15.statSync(opts.from);
|
|
15354
16053
|
if (st.isFIFO() || st.isSocket()) {
|
|
15355
16054
|
throw new CliError(`--from '${opts.from}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
15356
16055
|
}
|
|
15357
16056
|
const maxFromMB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15358
|
-
|
|
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;
|
|
15359
16061
|
if (st.size > maxFromBytes) {
|
|
15360
16062
|
throw new CliError(`--from source exceeds size limit (${Math.round(st.size / 1024 / 1024)} MB); set TOKEN_GOAT_MAX_STDIN_MB to override`);
|
|
15361
16063
|
}
|
|
15362
|
-
atomicWriteBuffer(dest,
|
|
16064
|
+
atomicWriteBuffer(dest, fs15.readFileSync(opts.from));
|
|
15363
16065
|
} catch (e) {
|
|
15364
16066
|
if (e instanceof CliError) throw e;
|
|
15365
16067
|
mapFsError(e, opts.from, dest);
|
|
@@ -15372,7 +16074,10 @@ function cmdWriteFile(dest, opts) {
|
|
|
15372
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");
|
|
15373
16075
|
}
|
|
15374
16076
|
const maxB64MB = parseInt(process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? "512", 10);
|
|
15375
|
-
|
|
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;
|
|
15376
16081
|
const decodedSize = Math.floor(normalized.replace(/=+$/, "").length * 3 / 4);
|
|
15377
16082
|
if (decodedSize > maxB64Bytes) {
|
|
15378
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`);
|
|
@@ -15473,7 +16178,7 @@ function buildProgram() {
|
|
|
15473
16178
|
await fn(...args);
|
|
15474
16179
|
process.exitCode = 0;
|
|
15475
16180
|
} catch (e) {
|
|
15476
|
-
const msg =
|
|
16181
|
+
const msg = extractErrorMessage(e);
|
|
15477
16182
|
err(`token-goat: ${msg}`);
|
|
15478
16183
|
process.exitCode = 1;
|
|
15479
16184
|
}
|
|
@@ -15525,7 +16230,7 @@ async function run(argv = process.argv) {
|
|
|
15525
16230
|
process.exitCode = 1;
|
|
15526
16231
|
return;
|
|
15527
16232
|
}
|
|
15528
|
-
const msg =
|
|
16233
|
+
const msg = extractErrorMessage(e);
|
|
15529
16234
|
err(`token-goat: ${msg}`);
|
|
15530
16235
|
process.exitCode = 1;
|
|
15531
16236
|
}
|