token-goat 2.8.0 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/{token-goat-chunk-VXSYZGBA.mjs → token-goat-chunk-2MWF3OGR.mjs} +226 -20
- package/dist/{token-goat-chunk-AO6MFFTW.mjs → token-goat-chunk-5MLXFSRI.mjs} +6 -6
- package/dist/{token-goat-chunk-FBGBTICM.mjs → token-goat-chunk-AL644JUV.mjs} +3 -3
- package/dist/{token-goat-chunk-2F6TFBZE.mjs → token-goat-chunk-AM23GDIS.mjs} +121 -15
- package/dist/{token-goat-chunk-4KZILRZN.mjs → token-goat-chunk-BTZSUIYA.mjs} +2 -2
- package/dist/{token-goat-chunk-44Y77VHR.mjs → token-goat-chunk-IVCTQPZD.mjs} +129 -7
- package/dist/{token-goat-chunk-A62K4XW2.mjs → token-goat-chunk-JU7QESB3.mjs} +5 -5
- package/dist/{token-goat-chunk-LVCBDJVE.mjs → token-goat-chunk-KBVN4ELV.mjs} +5 -5
- package/dist/{token-goat-chunk-SRAR6DOK.mjs → token-goat-chunk-LILS6TIU.mjs} +97 -13
- package/dist/{token-goat-chunk-J35AKWEQ.mjs → token-goat-chunk-SE6V7LUZ.mjs} +5 -5
- package/dist/{token-goat-chunk-TUPJRK7R.mjs → token-goat-chunk-TF5NT3H5.mjs} +14 -14
- package/dist/token-goat-hook.mjs +5 -5
- package/dist/token-goat.core.mjs +5 -5
- package/package.json +4 -2
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
runSkeleton,
|
|
26
26
|
runSymbol,
|
|
27
27
|
withPinnedReads
|
|
28
|
-
} from "./token-goat-chunk-
|
|
28
|
+
} from "./token-goat-chunk-LILS6TIU.mjs";
|
|
29
29
|
import {
|
|
30
30
|
buildProjectMap,
|
|
31
31
|
embeddingsDepsAvailable,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
getProjectIndexCounts,
|
|
35
35
|
isWorkerRunning,
|
|
36
36
|
mapLookupBytesSaved
|
|
37
|
-
} from "./token-goat-chunk-
|
|
37
|
+
} from "./token-goat-chunk-AM23GDIS.mjs";
|
|
38
38
|
import {
|
|
39
39
|
VERSION,
|
|
40
40
|
dataDir,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
normalizePath,
|
|
46
46
|
recordStat,
|
|
47
47
|
resolveProjectRoot
|
|
48
|
-
} from "./token-goat-chunk-
|
|
48
|
+
} from "./token-goat-chunk-IVCTQPZD.mjs";
|
|
49
49
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
50
50
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
51
51
|
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
propagateEndLinesToSymbols,
|
|
60
60
|
pushAll,
|
|
61
61
|
recordStat,
|
|
62
|
+
recordUnmappedTool,
|
|
62
63
|
redactIfDotenv,
|
|
63
64
|
redactSecrets,
|
|
64
65
|
resolveIndexPath,
|
|
@@ -90,7 +91,7 @@ import {
|
|
|
90
91
|
withFileLock,
|
|
91
92
|
writeIfDifferent,
|
|
92
93
|
writeJsonSettings
|
|
93
|
-
} from "./token-goat-chunk-
|
|
94
|
+
} from "./token-goat-chunk-IVCTQPZD.mjs";
|
|
94
95
|
import {
|
|
95
96
|
registerReset
|
|
96
97
|
} from "./token-goat-chunk-AO2QD2AG.mjs";
|
|
@@ -2331,10 +2332,18 @@ var parse2 = function(data, opts = {}) {
|
|
|
2331
2332
|
function parseRecords(content, opts) {
|
|
2332
2333
|
const delimiter = opts.delimiter ?? ",";
|
|
2333
2334
|
if (opts.noHeader === true) {
|
|
2334
|
-
const rows = parse2(content, { columns: false, skip_empty_lines: true, trim: true, delimiter, bom: true });
|
|
2335
|
+
const rows = parse2(content, { columns: false, skip_empty_lines: true, trim: true, delimiter, bom: true, relax_column_count: true });
|
|
2335
2336
|
return rows.map((row) => Object.fromEntries(row.map((cell, i) => [`col${i + 1}`, cell])));
|
|
2336
2337
|
}
|
|
2337
|
-
|
|
2338
|
+
const header = csvHeader(content, opts);
|
|
2339
|
+
const dupes = header.filter((name, i) => name !== "" && header.indexOf(name) !== i);
|
|
2340
|
+
if (dupes.length > 0) {
|
|
2341
|
+
const unique = [...new Set(dupes)];
|
|
2342
|
+
throw new Error(
|
|
2343
|
+
`duplicate column ${unique.length === 1 ? "name" : "names"} in header: ${unique.join(", ")} \u2014 rename the duplicates or pass --no-header to address columns positionally as col1, col2, \u2026`
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
return parse2(content, { columns: true, skip_empty_lines: true, trim: true, delimiter, bom: true, relax_column_count: true });
|
|
2338
2347
|
}
|
|
2339
2348
|
function csvHeader(content, opts) {
|
|
2340
2349
|
if (opts.noHeader === true) return [];
|
|
@@ -2828,8 +2837,10 @@ function usedRange(ws) {
|
|
|
2828
2837
|
}
|
|
2829
2838
|
const rows = rowCount;
|
|
2830
2839
|
const cols = maxCol;
|
|
2831
|
-
|
|
2832
|
-
|
|
2840
|
+
if (rows === 0 || cols === 0) {
|
|
2841
|
+
return { ref: "(empty)", rows: 0, cols: 0 };
|
|
2842
|
+
}
|
|
2843
|
+
return { ref: `A1:${indexToColLetters(cols)}${rows}`, rows, cols };
|
|
2833
2844
|
}
|
|
2834
2845
|
async function listSheets(filePath) {
|
|
2835
2846
|
const wb = await loadWorkbook(filePath);
|
|
@@ -2993,6 +3004,40 @@ async function extractPdfText(data, pagesSpec, layout = false) {
|
|
|
2993
3004
|
return { text: pages.join("\n\n"), pageCount: doc.numPages, pagesExtracted: end - start + 1 };
|
|
2994
3005
|
});
|
|
2995
3006
|
}
|
|
3007
|
+
async function locatePdfPages(data, pattern, opts) {
|
|
3008
|
+
let re;
|
|
3009
|
+
try {
|
|
3010
|
+
re = new RegExp(pattern, opts.ignoreCase === true ? "i" : "");
|
|
3011
|
+
} catch (e) {
|
|
3012
|
+
throw new Error(`invalid regex pattern: ${pattern} (${e instanceof Error ? e.message : String(e)})`, { cause: e });
|
|
3013
|
+
}
|
|
3014
|
+
const pdfjs = await loadPdfjs();
|
|
3015
|
+
if (!pdfjs) throw new Error("pdfjs-dist is not installed; run `npm install pdfjs-dist` to enable pdf-extract");
|
|
3016
|
+
const maxMatches = opts.maxMatches ?? 50;
|
|
3017
|
+
const context = opts.context ?? 80;
|
|
3018
|
+
return withPdfDocument(pdfjs, data, async (doc) => {
|
|
3019
|
+
const range = parsePageRange(opts.pages, doc.numPages);
|
|
3020
|
+
const start = range ? range.start : 1;
|
|
3021
|
+
const end = range ? range.end : doc.numPages;
|
|
3022
|
+
const matches = [];
|
|
3023
|
+
for (let i = start; i <= end && matches.length < maxMatches; i++) {
|
|
3024
|
+
const page = await doc.getPage(i);
|
|
3025
|
+
const content = await page.getTextContent();
|
|
3026
|
+
const textItems = content.items.filter((item) => "str" in item);
|
|
3027
|
+
const pageText = textItems.map((item) => item.str).join(" ");
|
|
3028
|
+
const m = re.exec(pageText);
|
|
3029
|
+
if (m === null) continue;
|
|
3030
|
+
matches.push({ page: i, snippet: locateSnippet(pageText, m.index, m[0].length, context) });
|
|
3031
|
+
}
|
|
3032
|
+
return matches;
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
function locateSnippet(text, index, matchLen, context) {
|
|
3036
|
+
const pad = Math.max(0, context - matchLen);
|
|
3037
|
+
const from = Math.max(0, index - Math.floor(pad / 2));
|
|
3038
|
+
const to = Math.min(text.length, index + matchLen + Math.ceil(pad / 2));
|
|
3039
|
+
return text.slice(from, to).replace(/\s+/g, " ").trim();
|
|
3040
|
+
}
|
|
2996
3041
|
async function resolveDestPage(doc, dest) {
|
|
2997
3042
|
let explicitDest = dest;
|
|
2998
3043
|
if (typeof explicitDest === "string") {
|
|
@@ -3190,9 +3235,27 @@ function toolMatcherFor(eventName) {
|
|
|
3190
3235
|
if (parts.length === 0) return null;
|
|
3191
3236
|
return parts.join("|");
|
|
3192
3237
|
}
|
|
3238
|
+
function foldToolName(name) {
|
|
3239
|
+
return name.toLowerCase().replace(/[_-]/g, "");
|
|
3240
|
+
}
|
|
3241
|
+
function noteUnrecognizedTool(event, list) {
|
|
3242
|
+
const toolName = event.toolName;
|
|
3243
|
+
if (typeof toolName !== "string" || toolName === "") return;
|
|
3244
|
+
const named = [];
|
|
3245
|
+
for (const { toolName: want } of list) {
|
|
3246
|
+
if (want === void 0) continue;
|
|
3247
|
+
if (want === toolName) return;
|
|
3248
|
+
named.push(want);
|
|
3249
|
+
}
|
|
3250
|
+
if (named.length === 0) return;
|
|
3251
|
+
const folded = foldToolName(toolName);
|
|
3252
|
+
const nearMiss = named.find((n) => foldToolName(n) === folded) ?? null;
|
|
3253
|
+
recordUnmappedTool(toolName, event.eventName, nearMiss);
|
|
3254
|
+
}
|
|
3193
3255
|
async function runHook(event) {
|
|
3194
3256
|
const list = _handlers.get(event.eventName);
|
|
3195
3257
|
if (list === void 0) return { hookType: "pass" };
|
|
3258
|
+
noteUnrecognizedTool(event, list);
|
|
3196
3259
|
let advisoryResult;
|
|
3197
3260
|
for (const { handler, toolName, advisory } of list) {
|
|
3198
3261
|
if (toolName !== void 0 && toolName !== event.toolName) continue;
|
|
@@ -4237,9 +4300,9 @@ function buildGuidanceBody(fallbackToolClause, opts = {}) {
|
|
|
4237
4300
|
"- pulling one value or subtree out of a JSON/YAML/XML file (manifest, lockfile, spec, config) \u2192 `json-query file 'a.b.c'` / `yaml-query file 'a.b.c'` / `xml-query file 'a.b.c'`",
|
|
4238
4301
|
"- opening an image to check its dimensions, format, or size \u2192 `image-meta file`",
|
|
4239
4302
|
"- opening a screenshot, diagram, or scan to read the text in it \u2192 `image-text file`",
|
|
4240
|
-
"- opening a PDF or Office document \u2192 inspect its format first, then read a narrow slice: PDF `pdf-meta`/`pdf-outline` then `pdf-extract
|
|
4303
|
+
"- opening a PDF or Office document \u2192 inspect its format first, then read a narrow slice: PDF `pdf-meta`/`pdf-outline` then `pdf-locate` to find the pages and `pdf-extract` only those; Word `docx-outline` then `docx-text`; PowerPoint `pptx-outline` then `pptx-slide`/`pptx-notes`; Excel `xlsx-sheets` then `xlsx-head`/`xlsx-range`/`xlsx-query`",
|
|
4241
4304
|
"",
|
|
4242
|
-
'Commands: `symbol NAME`, `read "file::symbol"`, `brief "file::symbol"`, `section "file::Heading"`, `semantic "description"`, `outline file`/`skeleton file`, `map --compact`, `refs file::symbol --callers`, `changed --symbol`, `config-get file KEY`, `json-query file \'a.b.c\'`/`yaml-query`/`xml-query`, `json-outline file`/`yaml-outline`/`xml-outline`, `bash-output`/`web-output`/`mcp-output`, ' + (gdrive ? "`gdrive-sections <file-id>`, " : "") + "`image-meta file`/`image-text file`, `pdf-meta`/`pdf-outline`/`pdf-extract`, `docx-outline`/`docx-text`, `pptx-outline`/`pptx-slide`/`pptx-notes`/`pptx-text`, `xlsx-sheets`/`xlsx-head`/`xlsx-range`/`xlsx-query`.",
|
|
4305
|
+
'Commands: `symbol NAME`, `read "file::symbol"`, `brief "file::symbol"`, `section "file::Heading"`, `semantic "description"`, `outline file`/`skeleton file`, `map --compact`, `refs file::symbol --callers`, `changed --symbol`, `config-get file KEY`, `json-query file \'a.b.c\'`/`yaml-query`/`xml-query`, `json-outline file`/`yaml-outline`/`xml-outline`, `bash-output`/`web-output`/`mcp-output`, ' + (gdrive ? "`gdrive-sections <file-id>`, " : "") + "`image-meta file`/`image-text file`, `pdf-meta`/`pdf-outline`/`pdf-locate`/`pdf-extract`, `docx-outline`/`docx-text`, `pptx-outline`/`pptx-slide`/`pptx-notes`/`pptx-text`, `xlsx-sheets`/`xlsx-head`/`xlsx-range`/`xlsx-query`.",
|
|
4243
4306
|
"",
|
|
4244
4307
|
"Sub-agent briefs must carry this gate verbatim: a sub-agent inherits none of this context and its reads spend the same token budget.",
|
|
4245
4308
|
"",
|
|
@@ -5107,7 +5170,14 @@ const POLL_ID_ARG_KEY = {
|
|
|
5107
5170
|
// the same session, since process.pid varies per invocation -- breaking token-goat's
|
|
5108
5171
|
// session-based dedup/state ledger, which never accumulates across calls as a result. Derive a
|
|
5109
5172
|
// stable id instead from the one thing that's actually constant across calls for the same
|
|
5110
|
-
// session: the working directory Copilot reports
|
|
5173
|
+
// session: the working directory Copilot reports. That field is \`workingDirectory\`, declared
|
|
5174
|
+
// required on BaseHookInput in copilot-sdk/types.d.ts since 1.0.76, so it is present on EVERY
|
|
5175
|
+
// hook event. This previously read \`payload.cwd\`, which Copilot has never sent under any name in
|
|
5176
|
+
// any version -- the key simply did not exist, so this derived every fallback id from
|
|
5177
|
+
// process.cwd() instead and \`canonical.cwd\` below was undefined on every single call. It went
|
|
5178
|
+
// unnoticed because process.cwd() happens to be the project directory Copilot spawns the hook in,
|
|
5179
|
+
// so the fallback was accidentally right; nothing about that was by design. \`cwd\` is still read
|
|
5180
|
+
// as a secondary in case a future version adds it under the shorter name.
|
|
5111
5181
|
function stableFallbackSessionId(cwd) {
|
|
5112
5182
|
const key = typeof cwd === 'string' && cwd ? cwd : process.cwd()
|
|
5113
5183
|
const hash = require('node:crypto').createHash('sha256').update(key).digest('hex').slice(0, 16)
|
|
@@ -5177,8 +5247,19 @@ async function main() {
|
|
|
5177
5247
|
|
|
5178
5248
|
const toolName = payload && payload.toolName
|
|
5179
5249
|
const canonical = {
|
|
5180
|
-
session_id:
|
|
5181
|
-
|
|
5250
|
+
session_id:
|
|
5251
|
+
(payload && payload.sessionId) ||
|
|
5252
|
+
stableFallbackSessionId(payload && (payload.workingDirectory || payload.cwd)),
|
|
5253
|
+
cwd: payload && (payload.workingDirectory || payload.cwd),
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5256
|
+
// userPromptSubmitted only: Copilot declares \`prompt\` required on UserPromptSubmittedHookInput.
|
|
5257
|
+
// hooks_session.ts's userPromptSubmitHandler reads it as \`event.raw['prompt']\` and gates every
|
|
5258
|
+
// branch it has on the text, so without this it saw '' on every Copilot prompt and the
|
|
5259
|
+
// embedded-skill dedup hint could never fire. Same shape as the postToolUseFailure \`error\`
|
|
5260
|
+
// drop: a required field the canonical builder simply did not list.
|
|
5261
|
+
if (typeof (payload && payload.prompt) === 'string' && payload.prompt !== '') {
|
|
5262
|
+
canonical.prompt = payload.prompt
|
|
5182
5263
|
}
|
|
5183
5264
|
if (toolName) {
|
|
5184
5265
|
canonical.tool_name = TOOL_TO_TG[toolName] || toolName
|
|
@@ -5193,6 +5274,16 @@ async function main() {
|
|
|
5193
5274
|
// post-read/post-bash stats stay empty no matter how many tool calls happen. Extract the
|
|
5194
5275
|
// LLM-facing text directly rather than forwarding the raw object, since textResultForLlm
|
|
5195
5276
|
// isn't one of those recognized object keys.
|
|
5277
|
+
// postToolUseFailure only: Copilot's PostToolUseFailureHookInput (copilot-sdk/types.d.ts:1042)
|
|
5278
|
+
// carries {toolName, toolArgs, error} and no toolResult at all -- the failure text lives in
|
|
5279
|
+
// \`error\`, a plain string. Without forwarding it, hooks_tool_failure.ts's extractFailureText
|
|
5280
|
+
// finds nothing to key on and the repeat-failure brake returns pass on every single call: wired,
|
|
5281
|
+
// green, and doing nothing. Found by driving the installed shim rather than by a test, because
|
|
5282
|
+
// the handler's own tests hand it a raw payload that already has the field.
|
|
5283
|
+
if (typeof (payload && payload.error) === 'string' && payload.error !== '') {
|
|
5284
|
+
canonical.error = payload.error
|
|
5285
|
+
}
|
|
5286
|
+
|
|
5196
5287
|
const rawResult = payload && payload.toolResult
|
|
5197
5288
|
if (rawResult && typeof rawResult === 'object') {
|
|
5198
5289
|
const tr = rawResult
|
|
@@ -7373,6 +7464,9 @@ function resolveTesseractEntry() {
|
|
|
7373
7464
|
}
|
|
7374
7465
|
return _tesseractEntryPath;
|
|
7375
7466
|
}
|
|
7467
|
+
function isOcrEngineAvailable() {
|
|
7468
|
+
return !_ocrUnavailableThisProcess && resolveTesseractEntry() !== null;
|
|
7469
|
+
}
|
|
7376
7470
|
var _ocrUnavailableThisProcess = false;
|
|
7377
7471
|
function buildChildScript(entryPath, cacheDir) {
|
|
7378
7472
|
return [
|
|
@@ -7487,14 +7581,16 @@ var loadSharp = createLazyModuleLoader(async () => {
|
|
|
7487
7581
|
function isImagePath(p) {
|
|
7488
7582
|
return IMAGE_EXTENSIONS.has(path12.extname(p).toLowerCase());
|
|
7489
7583
|
}
|
|
7584
|
+
var ImageDecodeError = class extends Error {
|
|
7585
|
+
};
|
|
7490
7586
|
async function probeImageMeta(input) {
|
|
7491
7587
|
const sharp = await loadSharp();
|
|
7492
7588
|
if (sharp === null) return null;
|
|
7493
7589
|
try {
|
|
7494
7590
|
const meta = await sharp(input, { limitInputPixels: false }).metadata();
|
|
7495
7591
|
return { width: meta.width ?? 0, height: meta.height ?? 0, format: meta.format ?? null, pages: meta.pages ?? 1 };
|
|
7496
|
-
} catch {
|
|
7497
|
-
|
|
7592
|
+
} catch (e) {
|
|
7593
|
+
throw new ImageDecodeError(e?.message ?? "image could not be decoded");
|
|
7498
7594
|
}
|
|
7499
7595
|
}
|
|
7500
7596
|
async function imageQualifiesForShrink(input) {
|
|
@@ -7640,7 +7736,14 @@ async function preReadImageHandler(event) {
|
|
|
7640
7736
|
} catch {
|
|
7641
7737
|
cachedData = null;
|
|
7642
7738
|
}
|
|
7643
|
-
|
|
7739
|
+
let meta = null;
|
|
7740
|
+
if (cachedData !== null) {
|
|
7741
|
+
try {
|
|
7742
|
+
meta = await probeImageMeta(cachedData);
|
|
7743
|
+
} catch {
|
|
7744
|
+
meta = null;
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7644
7747
|
if (cachedData !== null && meta !== null) {
|
|
7645
7748
|
const result2 = {
|
|
7646
7749
|
data: cachedData,
|
|
@@ -9819,7 +9922,7 @@ function extractMarkdownHeadings(content, limit = MAX_HEADINGS) {
|
|
|
9819
9922
|
const lines2 = content.split("\n");
|
|
9820
9923
|
for (const [i, line] of eachUnfencedLine(lines2)) {
|
|
9821
9924
|
if (!line) continue;
|
|
9822
|
-
const match = /^(#+)\s+(
|
|
9925
|
+
const match = /^(#+)\s+([^\r\n]+?)(?:\s+#+)?\s*$/.exec(line);
|
|
9823
9926
|
if (!match || match.length < 3) continue;
|
|
9824
9927
|
const hashes = match[1];
|
|
9825
9928
|
const headingText = match[2];
|
|
@@ -9949,7 +10052,7 @@ function handleHtml(filePath, content, contentLengthHint) {
|
|
|
9949
10052
|
message: `Large HTML file (${formatBytes(length)}) \u2014 too large to preview (exceeds the in-hook scan cap). Use token-goat section to extract a section by heading, or convert to text: pandoc "${filePath}" -t plain`
|
|
9950
10053
|
};
|
|
9951
10054
|
}
|
|
9952
|
-
const title = content.match(/<title[^>]*>([^<]
|
|
10055
|
+
const title = content.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1]?.trim();
|
|
9953
10056
|
const headings = findHtmlHeadingMatches(content).slice(0, 20).map(({ level, heading }) => {
|
|
9954
10057
|
if (!heading) return "";
|
|
9955
10058
|
return `${" ".repeat(level - 1)}h${level}: ${heading}`;
|
|
@@ -18839,6 +18942,7 @@ function urlPolicyDenialReason(url, policy) {
|
|
|
18839
18942
|
export {
|
|
18840
18943
|
createLazyModuleLoader,
|
|
18841
18944
|
extractPdfText,
|
|
18945
|
+
locatePdfPages,
|
|
18842
18946
|
extractPdfOutline,
|
|
18843
18947
|
extractPdfMeta,
|
|
18844
18948
|
docxOutline,
|
|
@@ -19005,10 +19109,12 @@ export {
|
|
|
19005
19109
|
getSkillFilePath,
|
|
19006
19110
|
installedSkillPath,
|
|
19007
19111
|
pruneSkillOutputs,
|
|
19112
|
+
isOcrEngineAvailable,
|
|
19008
19113
|
ocrImage,
|
|
19009
19114
|
isTextHeavy,
|
|
19010
19115
|
formatShrinkSummary,
|
|
19011
19116
|
isImagePath,
|
|
19117
|
+
ImageDecodeError,
|
|
19012
19118
|
probeImageMeta,
|
|
19013
19119
|
imageQualifiesForShrink,
|
|
19014
19120
|
shrinkImage,
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
selectFilter,
|
|
11
11
|
shlexSplit,
|
|
12
12
|
wrappedShell
|
|
13
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-TF5NT3H5.mjs";
|
|
14
14
|
import {
|
|
15
15
|
loadConfig,
|
|
16
16
|
recordStat
|
|
17
|
-
} from "./token-goat-chunk-
|
|
17
|
+
} from "./token-goat-chunk-IVCTQPZD.mjs";
|
|
18
18
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
19
19
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
20
20
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
function resolveVersion() {
|
|
10
10
|
if (true) {
|
|
11
|
-
return "2.8.
|
|
11
|
+
return "2.8.2";
|
|
12
12
|
}
|
|
13
13
|
const require2 = createRequire(import.meta.url);
|
|
14
14
|
const pkg = require2("../package.json");
|
|
@@ -5801,6 +5801,30 @@ function _renderByCommandSection(stats) {
|
|
|
5801
5801
|
}
|
|
5802
5802
|
return lines;
|
|
5803
5803
|
}
|
|
5804
|
+
function _renderByHarnessSection(stats) {
|
|
5805
|
+
if (!stats.by_harness || stats.by_harness.length < 2) {
|
|
5806
|
+
return [];
|
|
5807
|
+
}
|
|
5808
|
+
const lines = [..._sectionHeader("By harness"), _tableHeader("harness")];
|
|
5809
|
+
const { grossBytes, shareBytesDenom, shareTokensDenom } = _computeShareDenominators(stats.by_harness);
|
|
5810
|
+
function share(h) {
|
|
5811
|
+
return _absShare(h.bytes, h.tokens, shareBytesDenom, shareTokensDenom);
|
|
5812
|
+
}
|
|
5813
|
+
for (const h of [...stats.by_harness].sort((a, b) => share(b) - share(a))) {
|
|
5814
|
+
lines.push(
|
|
5815
|
+
_tableRow({
|
|
5816
|
+
name: h.harness,
|
|
5817
|
+
fraction: _barFraction(h.bytes, grossBytes),
|
|
5818
|
+
bytes: h.bytes,
|
|
5819
|
+
tokens: h.tokens,
|
|
5820
|
+
events: h.events,
|
|
5821
|
+
share: share(h),
|
|
5822
|
+
nameColor: C.TEXT_PRIMARY
|
|
5823
|
+
})
|
|
5824
|
+
);
|
|
5825
|
+
}
|
|
5826
|
+
return lines;
|
|
5827
|
+
}
|
|
5804
5828
|
function _renderByDaySection(stats) {
|
|
5805
5829
|
if (stats.by_day.length === 0) {
|
|
5806
5830
|
return [];
|
|
@@ -5923,6 +5947,7 @@ function renderStats(stats, opts) {
|
|
|
5923
5947
|
_renderByKindSection(stats),
|
|
5924
5948
|
_renderBySourceSection(stats),
|
|
5925
5949
|
_renderByCommandSection(stats),
|
|
5950
|
+
_renderByHarnessSection(stats),
|
|
5926
5951
|
_renderByDaySection(stats),
|
|
5927
5952
|
_renderByProjectSection(stats),
|
|
5928
5953
|
_renderInsightsSection(stats),
|
|
@@ -5932,6 +5957,7 @@ function renderStats(stats, opts) {
|
|
|
5932
5957
|
}
|
|
5933
5958
|
|
|
5934
5959
|
// src/stats.ts
|
|
5960
|
+
var HARNESS_UNRECORDED = "unrecorded (pre-2.8.1)";
|
|
5935
5961
|
var SOURCE_IMAGE = "image";
|
|
5936
5962
|
var SOURCE_HINT = "hint";
|
|
5937
5963
|
var SOURCE_READ = "read";
|
|
@@ -5978,6 +6004,7 @@ var KIND_TO_SOURCE = {
|
|
|
5978
6004
|
csv_query: SOURCE_READ,
|
|
5979
6005
|
csv_profile: SOURCE_READ,
|
|
5980
6006
|
pdf_extract: SOURCE_READ,
|
|
6007
|
+
pdf_locate: SOURCE_READ,
|
|
5981
6008
|
pdf_outline: SOURCE_READ,
|
|
5982
6009
|
pdf_meta: SOURCE_READ,
|
|
5983
6010
|
xlsx_sheets: SOURCE_READ,
|
|
@@ -6067,6 +6094,7 @@ var COMMAND_KINDS = {
|
|
|
6067
6094
|
"csv-query": /* @__PURE__ */ new Set(["csv_query"]),
|
|
6068
6095
|
"csv-profile": /* @__PURE__ */ new Set(["csv_profile"]),
|
|
6069
6096
|
"pdf-extract": /* @__PURE__ */ new Set(["pdf_extract"]),
|
|
6097
|
+
"pdf-locate": /* @__PURE__ */ new Set(["pdf_locate"]),
|
|
6070
6098
|
"pdf-outline": /* @__PURE__ */ new Set(["pdf_outline"]),
|
|
6071
6099
|
"pdf-meta": /* @__PURE__ */ new Set(["pdf_meta"]),
|
|
6072
6100
|
"xlsx-sheets": /* @__PURE__ */ new Set(["xlsx_sheets"]),
|
|
@@ -6161,19 +6189,53 @@ CREATE TABLE IF NOT EXISTS stats (
|
|
|
6161
6189
|
kind TEXT NOT NULL,
|
|
6162
6190
|
tokens_saved INTEGER NOT NULL DEFAULT 0,
|
|
6163
6191
|
bytes_saved INTEGER NOT NULL DEFAULT 0,
|
|
6164
|
-
detail TEXT
|
|
6192
|
+
detail TEXT,
|
|
6193
|
+
harness TEXT
|
|
6165
6194
|
);
|
|
6166
6195
|
CREATE INDEX IF NOT EXISTS idx_stats_ts ON stats(ts);
|
|
6167
6196
|
CREATE INDEX IF NOT EXISTS idx_stats_kind ON stats(kind);
|
|
6197
|
+
CREATE TABLE IF NOT EXISTS unmapped_tools (
|
|
6198
|
+
harness TEXT NOT NULL,
|
|
6199
|
+
tool_name TEXT NOT NULL,
|
|
6200
|
+
event_name TEXT NOT NULL,
|
|
6201
|
+
near_miss TEXT,
|
|
6202
|
+
first_seen INTEGER NOT NULL,
|
|
6203
|
+
last_seen INTEGER NOT NULL,
|
|
6204
|
+
hits INTEGER NOT NULL DEFAULT 0,
|
|
6205
|
+
PRIMARY KEY (harness, tool_name, event_name)
|
|
6206
|
+
);
|
|
6168
6207
|
`;
|
|
6169
6208
|
var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
6170
6209
|
registerReset(() => _globalSchemaApplied.clear());
|
|
6210
|
+
function migrateGlobalSchema(db) {
|
|
6211
|
+
try {
|
|
6212
|
+
db.exec("ALTER TABLE stats ADD COLUMN harness TEXT");
|
|
6213
|
+
} catch (err) {
|
|
6214
|
+
if (!(err instanceof Error) || !/duplicate column/i.test(err.message)) throw err;
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
var _harnessColumnByDb = /* @__PURE__ */ new WeakMap();
|
|
6218
|
+
function statsHasHarnessColumn(db) {
|
|
6219
|
+
const cached = _harnessColumnByDb.get(db);
|
|
6220
|
+
if (cached !== void 0) return cached;
|
|
6221
|
+
let present;
|
|
6222
|
+
try {
|
|
6223
|
+
present = db.prepare("PRAGMA table_info(stats)").all().some(
|
|
6224
|
+
(c) => c.name === "harness"
|
|
6225
|
+
);
|
|
6226
|
+
} catch {
|
|
6227
|
+
present = false;
|
|
6228
|
+
}
|
|
6229
|
+
_harnessColumnByDb.set(db, present);
|
|
6230
|
+
return present;
|
|
6231
|
+
}
|
|
6171
6232
|
function getGlobalDb(homeDir) {
|
|
6172
6233
|
const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
|
|
6173
6234
|
const dbPath = path8.join(basePath, "global.db");
|
|
6174
6235
|
const db = getDb(dbPath);
|
|
6175
6236
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
6176
6237
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
6238
|
+
migrateGlobalSchema(db);
|
|
6177
6239
|
_globalSchemaApplied.add(dbPath);
|
|
6178
6240
|
}
|
|
6179
6241
|
return db;
|
|
@@ -6188,10 +6250,44 @@ function noStatsMessage(windowDays, homeDir) {
|
|
|
6188
6250
|
function recordStat(kind, bytesSaved = 0, tokensSaved = 0, _testDb, detail) {
|
|
6189
6251
|
try {
|
|
6190
6252
|
const db = _testDb ?? getGlobalDb();
|
|
6253
|
+
const ts = Math.floor(Date.now() / 1e3);
|
|
6254
|
+
if (statsHasHarnessColumn(db)) {
|
|
6255
|
+
db.prepare(
|
|
6256
|
+
"INSERT INTO stats (ts, kind, bytes_saved, tokens_saved, detail, harness) VALUES (?, ?, ?, ?, ?, ?)"
|
|
6257
|
+
).run(ts, kind, bytesSaved, tokensSaved, detail ?? null, getHarnessName());
|
|
6258
|
+
} else {
|
|
6259
|
+
db.prepare(
|
|
6260
|
+
"INSERT INTO stats (ts, kind, bytes_saved, tokens_saved, detail) VALUES (?, ?, ?, ?, ?)"
|
|
6261
|
+
).run(ts, kind, bytesSaved, tokensSaved, detail ?? null);
|
|
6262
|
+
}
|
|
6263
|
+
} catch {
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
var MAX_TOOL_NAME_CHARS = 200;
|
|
6267
|
+
function recordUnmappedTool(toolName, eventName, nearMiss, _testDb) {
|
|
6268
|
+
try {
|
|
6269
|
+
if (!toolName) return;
|
|
6270
|
+
const db = _testDb ?? getGlobalDb();
|
|
6271
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
6191
6272
|
db.prepare(
|
|
6192
|
-
|
|
6193
|
-
|
|
6273
|
+
`INSERT INTO unmapped_tools (harness, tool_name, event_name, near_miss, first_seen, last_seen, hits)
|
|
6274
|
+
VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
6275
|
+
ON CONFLICT(harness, tool_name, event_name) DO UPDATE SET
|
|
6276
|
+
hits = hits + 1,
|
|
6277
|
+
last_seen = excluded.last_seen,
|
|
6278
|
+
near_miss = excluded.near_miss`
|
|
6279
|
+
).run(getHarnessName(), toolName.slice(0, MAX_TOOL_NAME_CHARS), eventName, nearMiss, now, now);
|
|
6280
|
+
} catch {
|
|
6281
|
+
}
|
|
6282
|
+
}
|
|
6283
|
+
function readUnmappedTools(dbPath, homeDir) {
|
|
6284
|
+
try {
|
|
6285
|
+
const db = dbPath ? getDb(dbPath) : getGlobalDb(homeDir);
|
|
6286
|
+
return db.prepare(
|
|
6287
|
+
"SELECT harness, tool_name, event_name, near_miss, hits, last_seen FROM unmapped_tools ORDER BY hits DESC, tool_name ASC"
|
|
6288
|
+
).all();
|
|
6194
6289
|
} catch {
|
|
6290
|
+
return [];
|
|
6195
6291
|
}
|
|
6196
6292
|
}
|
|
6197
6293
|
function summarize(windowDays = 30, testDb, homeDir) {
|
|
@@ -6199,11 +6295,14 @@ function summarize(windowDays = 30, testDb, homeDir) {
|
|
|
6199
6295
|
const sinceTs = windowDays > 0 ? Math.floor((Date.now() - windowDays * 24 * 60 * 60 * 1e3) / 1e3) : null;
|
|
6200
6296
|
const byKind = {};
|
|
6201
6297
|
const byDay = {};
|
|
6298
|
+
const byHarness = {};
|
|
6202
6299
|
let totalEvents = 0;
|
|
6203
6300
|
let totalBytes = 0;
|
|
6204
6301
|
let totalTokens = 0;
|
|
6205
6302
|
const db = testDb ?? getGlobalDb(homeDir);
|
|
6206
|
-
const
|
|
6303
|
+
const hasHarness = statsHasHarnessColumn(db);
|
|
6304
|
+
const cols = hasHarness ? "ts, kind, bytes_saved, tokens_saved, harness" : "ts, kind, bytes_saved, tokens_saved";
|
|
6305
|
+
const query = sinceTs !== null ? `SELECT ${cols} FROM stats WHERE ts >= ? ORDER BY ts DESC` : `SELECT ${cols} FROM stats ORDER BY ts DESC`;
|
|
6207
6306
|
const stmt = db.prepare(query);
|
|
6208
6307
|
const rows = sinceTs !== null ? stmt.all(sinceTs) : stmt.all();
|
|
6209
6308
|
const tsToDateCache = {};
|
|
@@ -6227,6 +6326,11 @@ function summarize(windowDays = 30, testDb, homeDir) {
|
|
|
6227
6326
|
byDay[dateKey] = zeroBucket();
|
|
6228
6327
|
}
|
|
6229
6328
|
incBucket(byDay[dateKey], bytesSaved, tokensSaved);
|
|
6329
|
+
const harness = row.harness || HARNESS_UNRECORDED;
|
|
6330
|
+
if (!byHarness[harness]) {
|
|
6331
|
+
byHarness[harness] = zeroBucket();
|
|
6332
|
+
}
|
|
6333
|
+
incBucket(byHarness[harness], bytesSaved, tokensSaved);
|
|
6230
6334
|
}
|
|
6231
6335
|
const bySourceDict = {};
|
|
6232
6336
|
for (const [kind, bucket] of Object.entries(byKind)) {
|
|
@@ -6263,6 +6367,7 @@ function summarize(windowDays = 30, testDb, homeDir) {
|
|
|
6263
6367
|
by_day: byDayList,
|
|
6264
6368
|
by_project: byProjectList,
|
|
6265
6369
|
by_source: bySourceDict,
|
|
6370
|
+
by_harness: byHarness,
|
|
6266
6371
|
by_command: Object.entries(byCommandDict).map(([command, bucket]) => ({ ...bucket, command })).filter((r) => r.events > 0),
|
|
6267
6372
|
window_days: windowDays
|
|
6268
6373
|
};
|
|
@@ -6300,6 +6405,15 @@ function _plainTextStats(summary) {
|
|
|
6300
6405
|
);
|
|
6301
6406
|
}
|
|
6302
6407
|
}
|
|
6408
|
+
const harnesses = Object.entries(summary.by_harness).filter(([, b]) => b.events > 0).sort((a, b) => b[1].tokens_saved - a[1].tokens_saved);
|
|
6409
|
+
if (harnesses.length > 1) {
|
|
6410
|
+
lines.push("", "## By Harness");
|
|
6411
|
+
for (const [harness, bucket] of harnesses) {
|
|
6412
|
+
lines.push(
|
|
6413
|
+
` ${harness.padEnd(22)} ${bucket.events.toString().padStart(6)} events ${fmtBytes(bucket.bytes_saved).padStart(8)} ${bucket.tokens_saved.toString().padStart(8)} tokens`
|
|
6414
|
+
);
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6303
6417
|
if (summary.by_command.length > 0) {
|
|
6304
6418
|
lines.push("", "## By Command");
|
|
6305
6419
|
for (const row of summary.by_command) {
|
|
@@ -6373,7 +6487,13 @@ function _buildStatsData(summary, windowDays) {
|
|
|
6373
6487
|
bytes: c.bytes_saved,
|
|
6374
6488
|
tokens: c.tokens_saved,
|
|
6375
6489
|
events: c.events
|
|
6376
|
-
}))
|
|
6490
|
+
})),
|
|
6491
|
+
by_harness: Object.entries(summary.by_harness).filter(([, b]) => b.events > 0).map(([harness, bucket]) => ({
|
|
6492
|
+
harness,
|
|
6493
|
+
bytes: bucket.bytes_saved,
|
|
6494
|
+
tokens: bucket.tokens_saved,
|
|
6495
|
+
events: bucket.events
|
|
6496
|
+
})).sort((a, b) => b.bytes - a.bytes)
|
|
6377
6497
|
};
|
|
6378
6498
|
}
|
|
6379
6499
|
function renderShortStats(opts) {
|
|
@@ -6537,7 +6657,7 @@ var SECRET_PATTERNS = [
|
|
|
6537
6657
|
// identifier characters only, so prose that merely mentions a keyword still never reaches
|
|
6538
6658
|
// a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
|
|
6539
6659
|
// `& ; # , :` play two incompatible roles. They separate one field from the next (a query
|
|
6540
|
-
// string, a cookie header, an inline env list), and they are also perfectly ordinary
|
|
6660
|
+
// string, a cookie header, an inline env list), and they are also perfectly ordinary credential
|
|
6541
6661
|
// characters. Rejecting them outright got the first role right and the second badly wrong: the
|
|
6542
6662
|
// match stopped at the first one and left everything after it in plain text, so
|
|
6543
6663
|
// `password=corr&horse&battery` redacted four characters and printed the rest, and
|
|
@@ -6770,6 +6890,8 @@ export {
|
|
|
6770
6890
|
SOURCE_HINT,
|
|
6771
6891
|
formatLocalTimestamp,
|
|
6772
6892
|
recordStat,
|
|
6893
|
+
recordUnmappedTool,
|
|
6894
|
+
readUnmappedTools,
|
|
6773
6895
|
summarize,
|
|
6774
6896
|
_useRichStats,
|
|
6775
6897
|
renderShortStats,
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
buildEvent,
|
|
5
5
|
relay,
|
|
6
6
|
relayInProcess
|
|
7
|
-
} from "./token-goat-chunk-
|
|
7
|
+
} from "./token-goat-chunk-KBVN4ELV.mjs";
|
|
8
8
|
import {
|
|
9
9
|
MAX_STDIN_BYTES,
|
|
10
10
|
readStdinJson
|
|
11
|
-
} from "./token-goat-chunk-
|
|
12
|
-
import "./token-goat-chunk-
|
|
13
|
-
import "./token-goat-chunk-
|
|
14
|
-
import "./token-goat-chunk-
|
|
11
|
+
} from "./token-goat-chunk-5MLXFSRI.mjs";
|
|
12
|
+
import "./token-goat-chunk-AM23GDIS.mjs";
|
|
13
|
+
import "./token-goat-chunk-TF5NT3H5.mjs";
|
|
14
|
+
import "./token-goat-chunk-IVCTQPZD.mjs";
|
|
15
15
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
16
16
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
17
17
|
export {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
summarizeOutputDelta,
|
|
24
24
|
summarizeResidentContext,
|
|
25
25
|
taskListPruneHint
|
|
26
|
-
} from "./token-goat-chunk-
|
|
26
|
+
} from "./token-goat-chunk-5MLXFSRI.mjs";
|
|
27
27
|
import {
|
|
28
28
|
BODY_FIRST_TOOL_RESPONSE_KEYS,
|
|
29
29
|
OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
|
|
@@ -118,7 +118,7 @@ import {
|
|
|
118
118
|
wasCliReadThisSession,
|
|
119
119
|
wasFileReadThisSession,
|
|
120
120
|
wasHintShown
|
|
121
|
-
} from "./token-goat-chunk-
|
|
121
|
+
} from "./token-goat-chunk-AM23GDIS.mjs";
|
|
122
122
|
import {
|
|
123
123
|
canRunWrappedShell,
|
|
124
124
|
compressOutput,
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
isRewriteWorthwhile,
|
|
130
130
|
resolveMinNetSavingsBytes,
|
|
131
131
|
shlexSplit
|
|
132
|
-
} from "./token-goat-chunk-
|
|
132
|
+
} from "./token-goat-chunk-TF5NT3H5.mjs";
|
|
133
133
|
import {
|
|
134
134
|
VERSION,
|
|
135
135
|
detectHarness,
|
|
@@ -149,7 +149,7 @@ import {
|
|
|
149
149
|
runGit,
|
|
150
150
|
shortFingerprint,
|
|
151
151
|
toKB
|
|
152
|
-
} from "./token-goat-chunk-
|
|
152
|
+
} from "./token-goat-chunk-IVCTQPZD.mjs";
|
|
153
153
|
|
|
154
154
|
// src/hooks_grep.ts
|
|
155
155
|
function grepIntInput(toolInput, key) {
|
|
@@ -620,7 +620,7 @@ import crypto from "node:crypto";
|
|
|
620
620
|
var TRACKED_SKILL = "token-goat";
|
|
621
621
|
var MAX_COMMANDS_SHOWN = 8;
|
|
622
622
|
async function currentCommandNames() {
|
|
623
|
-
const { buildProgram } = await import("./token-goat-chunk-
|
|
623
|
+
const { buildProgram } = await import("./token-goat-chunk-SE6V7LUZ.mjs");
|
|
624
624
|
return flattenCommandNames(buildCommandManifest(buildProgram()));
|
|
625
625
|
}
|
|
626
626
|
async function recordSkillVersionSnapshot(sessionId, skillName) {
|