token-goat 2.9.26 → 2.9.28
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 +28 -88
- package/SECURITY.md +14 -0
- package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-4JJBFT7V.mjs} +3 -3
- package/dist/token-goat-chunk-4JMWPWCS.mjs +96 -0
- package/dist/token-goat-chunk-4RN64ZND.mjs +954 -0
- package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-4STDIGYC.mjs} +2 -2
- package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-5NNYIUGV.mjs} +2 -2
- package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-66LODAUT.mjs} +1 -1
- package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-6CCQDAYY.mjs} +69 -566
- package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-6DQNNFJ6.mjs} +5 -3
- package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-6SGLIPQB.mjs} +40 -20
- package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-6Z5ULNE5.mjs} +3570 -3970
- package/dist/token-goat-chunk-7MAFDRVR.mjs +47 -0
- package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-7R2XYKC5.mjs} +6 -5
- package/dist/{token-goat-chunk-E6B2UFDF.mjs → token-goat-chunk-BCN2YQC6.mjs} +10 -8
- package/dist/token-goat-chunk-BJBRGPBX.mjs +244 -0
- package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-CBMY2FGI.mjs} +479 -544
- package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-CC2PYJM7.mjs} +2 -1
- package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-D5ICEPSB.mjs} +14 -14
- package/dist/token-goat-chunk-D7GHQKQD.mjs +30 -0
- package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-EL7M26WP.mjs} +7623 -8462
- package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-F7QZRIWM.mjs} +69 -20
- package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-FSTWAOW6.mjs} +3 -3
- package/dist/token-goat-chunk-GGLEE35R.mjs +564 -0
- package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-HUDC5GS5.mjs} +2 -2
- package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-HXNAC4ZF.mjs} +22 -964
- package/dist/token-goat-chunk-I7CB3X4K.mjs +1379 -0
- package/dist/{token-goat-chunk-GKZ2US5B.mjs → token-goat-chunk-IFORDBGC.mjs} +32 -27
- package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-IHKZ3QNA.mjs} +26 -15
- package/dist/token-goat-chunk-IZXKVT4A.mjs +711 -0
- package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-JXK2HQXS.mjs} +22 -8
- package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-L45ZQRT7.mjs} +1 -1
- package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-L7SDVGBT.mjs} +196 -14
- package/dist/token-goat-chunk-LEG3JNJ6.mjs +139 -0
- package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-M56BWPBN.mjs} +1 -1
- package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-MAMQPC43.mjs} +2 -87
- package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-MMLMALWK.mjs} +5 -3
- package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-MVSWBNMD.mjs} +7 -231
- package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-NILVK7XM.mjs} +4 -4
- package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-Q4S3UQGO.mjs} +1 -1
- package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-QM76S6YS.mjs} +3 -3
- package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-RJH64KQH.mjs} +81 -70
- package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-RSS3TLXU.mjs} +2 -2
- package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-SJEKA7Y2.mjs} +21 -16
- package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UBUKHVYW.mjs} +1 -1
- package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-VE27HPIF.mjs} +14 -10
- package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-VWZKZPSR.mjs} +100 -23
- package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-XI2VFAV6.mjs} +6 -6
- package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-XKY4VKJ4.mjs} +1 -1
- package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-YWSP6IU7.mjs} +1 -1
- package/dist/token-goat-hook.mjs +23 -17
- package/dist/token-goat.core.mjs +32 -27
- package/docs/cli.md +32 -21
- package/docs/install.md +2 -0
- package/package.json +1 -1
- package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
- package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
|
@@ -3,14 +3,14 @@ const require = __cjsRequire(import.meta.url);
|
|
|
3
3
|
import {
|
|
4
4
|
findLatestTranscript,
|
|
5
5
|
readFileLines
|
|
6
|
-
} from "./token-goat-chunk-
|
|
6
|
+
} from "./token-goat-chunk-6DQNNFJ6.mjs";
|
|
7
7
|
import {
|
|
8
8
|
copilotCliUserRoot,
|
|
9
9
|
readCopilotMcpTools
|
|
10
|
-
} from "./token-goat-chunk-
|
|
10
|
+
} from "./token-goat-chunk-MMLMALWK.mjs";
|
|
11
11
|
import {
|
|
12
12
|
canonicalize
|
|
13
|
-
} from "./token-goat-chunk-
|
|
13
|
+
} from "./token-goat-chunk-L45ZQRT7.mjs";
|
|
14
14
|
import {
|
|
15
15
|
init_define_import_meta_env
|
|
16
16
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -213,6 +213,11 @@ function readNumber(source, key) {
|
|
|
213
213
|
const value = source[key];
|
|
214
214
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
215
215
|
}
|
|
216
|
+
function unusedMcpServers(report) {
|
|
217
|
+
const calls = report.mcpCalls;
|
|
218
|
+
return calls === null ? null : report.mcpTools.servers.filter((server) => (calls[server.serverName] ?? 0) === 0);
|
|
219
|
+
}
|
|
220
|
+
var MCP_DISABLE_NOTE = "'copilot mcp enable <name>' restores one, and '--disable-mcp-server <name>' drops one for a single run instead.";
|
|
216
221
|
function buildCopilotWasteReport(eventsPath) {
|
|
217
222
|
const report = {
|
|
218
223
|
sessionPath: eventsPath,
|
|
@@ -224,14 +229,14 @@ function buildCopilotWasteReport(eventsPath) {
|
|
|
224
229
|
hookRecordBytes: 0,
|
|
225
230
|
// Measured off the file rather than off a string of its contents: an event log large enough for this number to matter is exactly the one readFileSync cannot return, since V8 caps a string at about 512 MB.
|
|
226
231
|
totalEventBytes: fs.statSync(eventsPath).size,
|
|
227
|
-
// Read through the real resolution chain rather than passed in. Copilot's
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// test ever supplies.
|
|
231
|
-
mcpTools: readCopilotMcpTools()
|
|
232
|
+
// Read through the real resolution chain rather than passed in. Copilot's own COPILOT_CACHE_HOME override is what tests point at a fixture, so the shipping path is the tested path and there is no seam here that only a test ever supplies.
|
|
233
|
+
mcpTools: readCopilotMcpTools(),
|
|
234
|
+
mcpCalls: null
|
|
232
235
|
};
|
|
233
236
|
const classes = /* @__PURE__ */ new Map();
|
|
234
237
|
const seen = /* @__PURE__ */ new Map();
|
|
238
|
+
const mcpCalls = /* @__PURE__ */ new Map();
|
|
239
|
+
let toolExecutions = 0;
|
|
235
240
|
for (const line of readFileLines(eventsPath)) {
|
|
236
241
|
const trimmed = line.trim();
|
|
237
242
|
if (trimmed === "") continue;
|
|
@@ -266,6 +271,12 @@ function buildCopilotWasteReport(eventsPath) {
|
|
|
266
271
|
});
|
|
267
272
|
continue;
|
|
268
273
|
}
|
|
274
|
+
if (type === "tool.execution_start") {
|
|
275
|
+
toolExecutions += 1;
|
|
276
|
+
const server = data["mcpServerName"];
|
|
277
|
+
if (typeof server === "string") mcpCalls.set(server, (mcpCalls.get(server) ?? 0) + 1);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
269
280
|
if (type !== "user.message") continue;
|
|
270
281
|
const transformed = typeof data["transformedContent"] === "string" ? data["transformedContent"] : "";
|
|
271
282
|
if (transformed === "") continue;
|
|
@@ -293,6 +304,7 @@ function buildCopilotWasteReport(eventsPath) {
|
|
|
293
304
|
}
|
|
294
305
|
}
|
|
295
306
|
report.blocks = [...classes.values()].sort((a, b) => b.bytes - a.bytes);
|
|
307
|
+
report.mcpCalls = toolExecutions === 0 ? null : Object.fromEntries(mcpCalls);
|
|
296
308
|
return report;
|
|
297
309
|
}
|
|
298
310
|
|
|
@@ -300,5 +312,7 @@ export {
|
|
|
300
312
|
isCopilotTranscript,
|
|
301
313
|
findLatestCopilotSession,
|
|
302
314
|
findProjectSession,
|
|
315
|
+
unusedMcpServers,
|
|
316
|
+
MCP_DISABLE_NOTE,
|
|
303
317
|
buildCopilotWasteReport
|
|
304
318
|
};
|
|
@@ -21,7 +21,7 @@ init_define_import_meta_env();
|
|
|
21
21
|
import { createRequire } from "node:module";
|
|
22
22
|
function resolveVersion() {
|
|
23
23
|
if (true) {
|
|
24
|
-
return "2.9.
|
|
24
|
+
return "2.9.28";
|
|
25
25
|
}
|
|
26
26
|
const require2 = createRequire(import.meta.url);
|
|
27
27
|
const pkg = require2("../package.json");
|
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
-
WEB_FETCH_KEY_SEP,
|
|
5
4
|
computeAdaptiveBudget,
|
|
6
5
|
getContextPressure,
|
|
7
|
-
getSessionBashOutputs,
|
|
8
|
-
getSessionBashReruns,
|
|
9
|
-
getSessionFiles,
|
|
10
|
-
getSessionWebFetches,
|
|
11
6
|
isNoisePath,
|
|
12
7
|
listSiblingSessionStates,
|
|
13
8
|
loadSessionCache
|
|
14
|
-
} from "./token-goat-chunk-
|
|
9
|
+
} from "./token-goat-chunk-6CCQDAYY.mjs";
|
|
10
|
+
import {
|
|
11
|
+
WEB_FETCH_KEY_SEP,
|
|
12
|
+
getSessionBashOutputs,
|
|
13
|
+
getSessionBashReruns,
|
|
14
|
+
getSessionFiles,
|
|
15
|
+
getSessionWebFetches
|
|
16
|
+
} from "./token-goat-chunk-GGLEE35R.mjs";
|
|
15
17
|
import {
|
|
16
18
|
getBashOutput
|
|
17
|
-
} from "./token-goat-chunk-
|
|
19
|
+
} from "./token-goat-chunk-HXNAC4ZF.mjs";
|
|
18
20
|
import {
|
|
21
|
+
findProject,
|
|
19
22
|
loadConfig
|
|
20
|
-
} from "./token-goat-chunk-
|
|
23
|
+
} from "./token-goat-chunk-CC2PYJM7.mjs";
|
|
21
24
|
import {
|
|
25
|
+
atomicWriteText,
|
|
26
|
+
dataDir,
|
|
27
|
+
ensureDirSync,
|
|
22
28
|
foldPath,
|
|
23
29
|
runGit,
|
|
24
|
-
toKB
|
|
25
|
-
|
|
30
|
+
toKB,
|
|
31
|
+
withFileLock
|
|
32
|
+
} from "./token-goat-chunk-L45ZQRT7.mjs";
|
|
26
33
|
import {
|
|
27
34
|
displaySafePath,
|
|
28
35
|
displaySafeText,
|
|
@@ -35,6 +42,174 @@ import {
|
|
|
35
42
|
// src/manifest.ts
|
|
36
43
|
init_define_import_meta_env();
|
|
37
44
|
import { spawnSync } from "node:child_process";
|
|
45
|
+
|
|
46
|
+
// src/project_memory.ts
|
|
47
|
+
init_define_import_meta_env();
|
|
48
|
+
import * as fs from "node:fs";
|
|
49
|
+
import * as path from "node:path";
|
|
50
|
+
var MAX_ENTRIES = 30;
|
|
51
|
+
var MAX_VALUE_LEN = 300;
|
|
52
|
+
var MAX_TOTAL_CHARS = 4e3;
|
|
53
|
+
var KEY_RE = /^[A-Za-z0-9_-]{1,80}$/;
|
|
54
|
+
function ordinal(a, b) {
|
|
55
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
56
|
+
}
|
|
57
|
+
function memoryPath(projectHash) {
|
|
58
|
+
return path.join(dataDir(), "projects", `${projectHash}_memory.toml`);
|
|
59
|
+
}
|
|
60
|
+
function validateKey(key) {
|
|
61
|
+
if (!KEY_RE.test(key)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Invalid memory key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseTOML(content) {
|
|
68
|
+
const result = {};
|
|
69
|
+
for (const line of content.split("\n")) {
|
|
70
|
+
const trimmed = line.trim();
|
|
71
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const match = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*"(.*)"\s*$/);
|
|
75
|
+
if (match) {
|
|
76
|
+
const [, key, value] = match;
|
|
77
|
+
if (key && value !== void 0) {
|
|
78
|
+
const unescaped = value.replace(/\\([\\nrt"])/g, (_, c) => {
|
|
79
|
+
switch (c) {
|
|
80
|
+
case "\\":
|
|
81
|
+
return "\\";
|
|
82
|
+
case "n":
|
|
83
|
+
return "\n";
|
|
84
|
+
case "r":
|
|
85
|
+
return "\r";
|
|
86
|
+
case '"':
|
|
87
|
+
return '"';
|
|
88
|
+
default:
|
|
89
|
+
return _;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
result[key] = unescaped;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
function loadRaw(filePath) {
|
|
99
|
+
try {
|
|
100
|
+
if (!fs.existsSync(filePath)) {
|
|
101
|
+
return {};
|
|
102
|
+
}
|
|
103
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
104
|
+
return parseTOML(content);
|
|
105
|
+
} catch {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function save(filePath, entries) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
const sorted = Object.entries(entries).sort(([a], [b]) => ordinal(a, b));
|
|
112
|
+
for (const [k, v] of sorted) {
|
|
113
|
+
const escaped = v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
114
|
+
lines.push(`${k} = "${escaped}"`);
|
|
115
|
+
}
|
|
116
|
+
const content = lines.length > 0 ? lines.join("\n") + "\n" : "";
|
|
117
|
+
const dir = path.dirname(filePath);
|
|
118
|
+
ensureDirSync(dir);
|
|
119
|
+
atomicWriteText(filePath, content);
|
|
120
|
+
}
|
|
121
|
+
function loadEntries(projectHash) {
|
|
122
|
+
return loadRaw(memoryPath(projectHash));
|
|
123
|
+
}
|
|
124
|
+
function setEntry(projectHash, key, value) {
|
|
125
|
+
validateKey(key);
|
|
126
|
+
const p = memoryPath(projectHash);
|
|
127
|
+
const dir = path.dirname(p);
|
|
128
|
+
ensureDirSync(dir);
|
|
129
|
+
const doSet = () => {
|
|
130
|
+
const entries = loadRaw(p);
|
|
131
|
+
const isNewKey = !(key in entries);
|
|
132
|
+
if (isNewKey && Object.keys(entries).length >= MAX_ENTRIES) {
|
|
133
|
+
const keysToKeep = MAX_ENTRIES - 1;
|
|
134
|
+
const allKeys = Object.keys(entries).sort((a, b) => ordinal(a, b));
|
|
135
|
+
for (const k of allKeys.slice(keysToKeep)) {
|
|
136
|
+
delete entries[k];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
entries[key] = value;
|
|
140
|
+
save(p, entries);
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
143
|
+
if (withFileLock(`${p}.lock`, doSet) === void 0) doSet();
|
|
144
|
+
}
|
|
145
|
+
function unsetEntry(projectHash, key) {
|
|
146
|
+
validateKey(key);
|
|
147
|
+
const p = memoryPath(projectHash);
|
|
148
|
+
const doUnset = () => {
|
|
149
|
+
const entries = loadRaw(p);
|
|
150
|
+
if (key in entries) {
|
|
151
|
+
delete entries[key];
|
|
152
|
+
save(p, entries);
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
};
|
|
156
|
+
if (withFileLock(`${p}.lock`, doUnset) === void 0) doUnset();
|
|
157
|
+
}
|
|
158
|
+
function clearAll(projectHash) {
|
|
159
|
+
const p = memoryPath(projectHash);
|
|
160
|
+
const doClear = () => {
|
|
161
|
+
if (fs.existsSync(p)) {
|
|
162
|
+
save(p, {});
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
};
|
|
166
|
+
if (withFileLock(`${p}.lock`, doClear) === void 0) doClear();
|
|
167
|
+
}
|
|
168
|
+
function buildInjection(projectHash) {
|
|
169
|
+
try {
|
|
170
|
+
const entries = loadEntries(projectHash);
|
|
171
|
+
if (Object.keys(entries).length === 0) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const header = '### Project notes (`token-goat note set <key> "<finding>"`)';
|
|
175
|
+
const lines = [header];
|
|
176
|
+
let total = header.length;
|
|
177
|
+
let skipped = 0;
|
|
178
|
+
const entries_list = Object.entries(entries).sort(([a], [b]) => ordinal(a, b)).slice(0, MAX_ENTRIES);
|
|
179
|
+
for (const [key, val] of entries_list) {
|
|
180
|
+
const display = val.length <= MAX_VALUE_LEN ? val : val.slice(0, MAX_VALUE_LEN) + "\u2026";
|
|
181
|
+
const line = `- **${key}**: ${display}`;
|
|
182
|
+
if (total + line.length + 1 > MAX_TOTAL_CHARS) {
|
|
183
|
+
skipped++;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
lines.push(line);
|
|
187
|
+
total += line.length + 1;
|
|
188
|
+
}
|
|
189
|
+
if (skipped > 0) {
|
|
190
|
+
while (lines.length > 1 && total + `- (+${skipped} more memory entries omitted -- total size limit reached)`.length + 1 > MAX_TOTAL_CHARS) {
|
|
191
|
+
const popped = lines.pop();
|
|
192
|
+
total -= popped.length + 1;
|
|
193
|
+
skipped++;
|
|
194
|
+
}
|
|
195
|
+
lines.push(`- (+${skipped} more memory entries omitted -- total size limit reached)`);
|
|
196
|
+
}
|
|
197
|
+
return lines.join("\n");
|
|
198
|
+
} catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function projectNotesFor(cwd) {
|
|
203
|
+
if (cwd === void 0) return null;
|
|
204
|
+
try {
|
|
205
|
+
const project = findProject(cwd);
|
|
206
|
+
return project === null ? null : buildInjection(project.hash);
|
|
207
|
+
} catch {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/manifest.ts
|
|
38
213
|
var MEM_EPOCH_TIMEOUT_MS = 800;
|
|
39
214
|
var MAX_ROWS = 40;
|
|
40
215
|
function appendCappedSection(lines, header, rows, cap) {
|
|
@@ -115,6 +290,8 @@ function buildManifestParts(sessionId, cwd, transcriptPath) {
|
|
|
115
290
|
for (let i = 0; i < Math.min(rows.length, MAX_ROWS); i++) fileRows.push({ path: displaySafePath(entries[i].path), row: rows[i] });
|
|
116
291
|
};
|
|
117
292
|
appendFileSection("### Edited files", editedFiles, (entry) => `- ${displaySafePath(entry.path)}`);
|
|
293
|
+
const notes = projectNotesFor(cwd);
|
|
294
|
+
if (notes !== null) lines.push("", notes);
|
|
118
295
|
appendFileSection("### Surgically read files (symbol/section reads, never read whole)", symbolOnlyFiles, renderSymbolReadRow);
|
|
119
296
|
appendFileSection("### Read files", readFiles, renderReadRow);
|
|
120
297
|
appendCappedSection(lines, "### Web URLs fetched", webFetches.map(([key, cacheId]) => renderWebFetchRow(key, cacheId)), MAX_ROWS);
|
|
@@ -123,10 +300,10 @@ function buildManifestParts(sessionId, cwd, transcriptPath) {
|
|
|
123
300
|
const text = capManifestChars(lines.join("\n"), sessionId, cwd, transcriptPath);
|
|
124
301
|
const seen = /* @__PURE__ */ new Set();
|
|
125
302
|
const printed = [];
|
|
126
|
-
for (const { path, row } of fileRows) {
|
|
127
|
-
if (seen.has(
|
|
128
|
-
seen.add(
|
|
129
|
-
printed.push(
|
|
303
|
+
for (const { path: path2, row } of fileRows) {
|
|
304
|
+
if (seen.has(path2) || !(text.includes(row + "\n") || text.endsWith(row))) continue;
|
|
305
|
+
seen.add(path2);
|
|
306
|
+
printed.push(path2);
|
|
130
307
|
}
|
|
131
308
|
return { text, printed };
|
|
132
309
|
}
|
|
@@ -238,6 +415,11 @@ function summaryBudgetDirective(budgetChars) {
|
|
|
238
415
|
}
|
|
239
416
|
|
|
240
417
|
export {
|
|
418
|
+
loadEntries,
|
|
419
|
+
setEntry,
|
|
420
|
+
unsetEntry,
|
|
421
|
+
clearAll,
|
|
422
|
+
projectNotesFor,
|
|
241
423
|
renderWebFetchRow,
|
|
242
424
|
manifestPrintedPaths,
|
|
243
425
|
buildManifest,
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
CONTENT_DELIVERED_REASON,
|
|
5
|
+
classifyToolError,
|
|
6
|
+
errorPrefix
|
|
7
|
+
} from "./token-goat-chunk-I7CB3X4K.mjs";
|
|
8
|
+
import "./token-goat-chunk-IZXKVT4A.mjs";
|
|
9
|
+
import "./token-goat-chunk-RJH64KQH.mjs";
|
|
10
|
+
import "./token-goat-chunk-MMLMALWK.mjs";
|
|
11
|
+
import "./token-goat-chunk-GGLEE35R.mjs";
|
|
12
|
+
import "./token-goat-chunk-4JMWPWCS.mjs";
|
|
13
|
+
import "./token-goat-chunk-4RN64ZND.mjs";
|
|
14
|
+
import "./token-goat-chunk-MVSWBNMD.mjs";
|
|
15
|
+
import "./token-goat-chunk-M56BWPBN.mjs";
|
|
16
|
+
import "./token-goat-chunk-CC2PYJM7.mjs";
|
|
17
|
+
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
18
|
+
import "./token-goat-chunk-OSUFN2FV.mjs";
|
|
19
|
+
import "./token-goat-chunk-L45ZQRT7.mjs";
|
|
20
|
+
import {
|
|
21
|
+
displaySafeText
|
|
22
|
+
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
23
|
+
import "./token-goat-chunk-GMOUBOX4.mjs";
|
|
24
|
+
import {
|
|
25
|
+
init_define_import_meta_env
|
|
26
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
27
|
+
|
|
28
|
+
// src/tool_error_census.ts
|
|
29
|
+
init_define_import_meta_env();
|
|
30
|
+
var UNKNOWN_PREFIX_LIMIT = 20;
|
|
31
|
+
var REASONS_PER_ROW = 4;
|
|
32
|
+
var UNKNOWN_MODEL = "(unknown)";
|
|
33
|
+
function tally(map, name) {
|
|
34
|
+
let row = map.get(name);
|
|
35
|
+
if (row === void 0) {
|
|
36
|
+
row = { name, calls: 0, errors: 0, unknown: 0, delivered: 0, expected: {} };
|
|
37
|
+
map.set(name, row);
|
|
38
|
+
}
|
|
39
|
+
return row;
|
|
40
|
+
}
|
|
41
|
+
function byCodeUnit(a, b) {
|
|
42
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
43
|
+
}
|
|
44
|
+
function sortTallies(map) {
|
|
45
|
+
return [...map.values()].sort((a, b) => b.errors - a.errors || b.calls - a.calls || byCodeUnit(a.name, b.name));
|
|
46
|
+
}
|
|
47
|
+
function newToolErrorAccumulator() {
|
|
48
|
+
const tools = /* @__PURE__ */ new Map();
|
|
49
|
+
const models = /* @__PURE__ */ new Map();
|
|
50
|
+
const unknownPrefixes = /* @__PURE__ */ new Map();
|
|
51
|
+
return {
|
|
52
|
+
countCall(tool, model) {
|
|
53
|
+
tally(tools, tool).calls += 1;
|
|
54
|
+
tally(models, model ?? UNKNOWN_MODEL).calls += 1;
|
|
55
|
+
},
|
|
56
|
+
countError(tool, model, errorText, flags) {
|
|
57
|
+
const verdict = classifyToolError(tool, errorText, flags);
|
|
58
|
+
const rows = [tally(tools, tool), tally(models, model ?? UNKNOWN_MODEL)];
|
|
59
|
+
if (verdict.reason === CONTENT_DELIVERED_REASON) {
|
|
60
|
+
for (const row of rows) row.delivered += 1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (const row of rows) {
|
|
64
|
+
row.errors += 1;
|
|
65
|
+
if (verdict.kind === "unknown") row.unknown += 1;
|
|
66
|
+
else row.expected[verdict.reason] = (row.expected[verdict.reason] ?? 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
if (verdict.kind !== "unknown") return;
|
|
69
|
+
const prefix = errorPrefix(errorText);
|
|
70
|
+
const key = `${tool}\0${prefix}`;
|
|
71
|
+
const hit = unknownPrefixes.get(key);
|
|
72
|
+
if (hit === void 0) unknownPrefixes.set(key, { tool, prefix, count: 1 });
|
|
73
|
+
else hit.count += 1;
|
|
74
|
+
},
|
|
75
|
+
finish() {
|
|
76
|
+
const topUnknown = [...unknownPrefixes.values()].sort((a, b) => b.count - a.count || byCodeUnit(a.tool, b.tool) || byCodeUnit(a.prefix, b.prefix)).slice(0, UNKNOWN_PREFIX_LIMIT);
|
|
77
|
+
return { byTool: sortTallies(tools), byModel: sortTallies(models), unknownPrefixes: topUnknown };
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function fmt(n) {
|
|
82
|
+
return n.toLocaleString("en-US");
|
|
83
|
+
}
|
|
84
|
+
function rate(errors, calls) {
|
|
85
|
+
return calls === 0 ? "-" : `${(errors / calls * 100).toFixed(1)}%`;
|
|
86
|
+
}
|
|
87
|
+
function reasonsCell(expected) {
|
|
88
|
+
const ranked = Object.entries(expected).sort((a, b) => b[1] - a[1] || byCodeUnit(a[0], b[0]));
|
|
89
|
+
const shown = ranked.slice(0, REASONS_PER_ROW).map(([reason, n]) => `${reason} ${fmt(n)}`);
|
|
90
|
+
const rest = ranked.slice(REASONS_PER_ROW).reduce((sum, [, n]) => sum + n, 0);
|
|
91
|
+
if (rest > 0) shown.push(`+${fmt(rest)} more`);
|
|
92
|
+
return shown.join(", ");
|
|
93
|
+
}
|
|
94
|
+
function columnWidth(names, header) {
|
|
95
|
+
return names.reduce((w, n) => Math.max(w, n.length), header.length);
|
|
96
|
+
}
|
|
97
|
+
function tableLines(rows) {
|
|
98
|
+
const failing = rows.filter((r) => r.errors > 0);
|
|
99
|
+
const names = failing.map((r) => displaySafeText(r.name));
|
|
100
|
+
const width = columnWidth(names, "name");
|
|
101
|
+
const out = [`${"name".padEnd(width)} ${"calls".padStart(9)} ${"errors".padStart(7)} ${"rate".padStart(6)} ${"unknown".padStart(7)} expected, by reason`];
|
|
102
|
+
failing.forEach((r, i) => out.push(`${names[i].padEnd(width)} ${fmt(r.calls).padStart(9)} ${fmt(r.errors).padStart(7)} ${rate(r.errors, r.calls).padStart(6)} ${fmt(r.unknown).padStart(7)} ${reasonsCell(r.expected)}`.trimEnd()));
|
|
103
|
+
if (failing.length < rows.length) out.push(`(${fmt(rows.length - failing.length)} more ran without an error)`);
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
function deliveredLines(rows) {
|
|
107
|
+
const delivering = rows.filter((r) => r.delivered > 0).sort((a, b) => b.delivered - a.delivered || byCodeUnit(a.name, b.name));
|
|
108
|
+
if (delivering.length === 0) return [];
|
|
109
|
+
const total = delivering.reduce((sum, r) => sum + r.delivered, 0);
|
|
110
|
+
return [`Content delivered by a token-goat deny, not counted as errors: ${fmt(total)} (${delivering.map((r) => `${displaySafeText(r.name)} ${fmt(r.delivered)}`).join(", ")}).`];
|
|
111
|
+
}
|
|
112
|
+
function formatToolErrorCensus(census, scope) {
|
|
113
|
+
const calls = census.byTool.reduce((sum, r) => sum + r.calls, 0);
|
|
114
|
+
const errors = census.byTool.reduce((sum, r) => sum + r.errors, 0);
|
|
115
|
+
const unknown = census.byTool.reduce((sum, r) => sum + r.unknown, 0);
|
|
116
|
+
const toolWidth = columnWidth(census.unknownPrefixes.map((p) => displaySafeText(p.tool)), "");
|
|
117
|
+
const window = scope.windowDays === 0 ? "all time" : `transcripts modified in the last ${fmt(scope.windowDays)} days`;
|
|
118
|
+
const lines = [
|
|
119
|
+
`# Tool errors (${fmt(scope.filesScanned)} transcripts, ${window})`,
|
|
120
|
+
`Calls ${fmt(calls)}, errors ${fmt(errors)} (${rate(errors, calls)}), unknown ${fmt(unknown)}. Expected means a named failure shape in tool_error_class.ts; unknown is everything else.`,
|
|
121
|
+
...deliveredLines(census.byTool),
|
|
122
|
+
"",
|
|
123
|
+
"## By tool",
|
|
124
|
+
...tableLines(census.byTool),
|
|
125
|
+
"",
|
|
126
|
+
"## By model",
|
|
127
|
+
...tableLines(census.byModel),
|
|
128
|
+
"",
|
|
129
|
+
"## Top unknown error prefixes (paths, quoted text and digits masked)",
|
|
130
|
+
...census.unknownPrefixes.map((p) => `${fmt(p.count).padStart(7)} ${displaySafeText(p.tool).padEnd(toolWidth)} ${displaySafeText(p.prefix)}`)
|
|
131
|
+
];
|
|
132
|
+
if (census.unknownPrefixes.length === 0) lines.push("(none)");
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
UNKNOWN_PREFIX_LIMIT,
|
|
137
|
+
formatToolErrorCensus,
|
|
138
|
+
newToolErrorAccumulator
|
|
139
|
+
};
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
stripAnsiEscapes
|
|
7
|
-
} from "./token-goat-chunk-D2X7XN5M.mjs";
|
|
8
|
-
import {
|
|
9
|
-
safeSlice
|
|
10
|
-
} from "./token-goat-chunk-6E2IDLHF.mjs";
|
|
4
|
+
estimateTokensFromLength
|
|
5
|
+
} from "./token-goat-chunk-4JMWPWCS.mjs";
|
|
11
6
|
import {
|
|
12
7
|
displaySafeText
|
|
13
8
|
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
@@ -25,82 +20,6 @@ function claudeConfigDir(homeDir = os.homedir()) {
|
|
|
25
20
|
return path.join(homeDir, ".claude");
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
// src/overflow_guard.ts
|
|
29
|
-
init_define_import_meta_env();
|
|
30
|
-
function estimateTokensFromLength(length, cls = "text") {
|
|
31
|
-
return Math.max(1, Math.floor(Math.max(0, length) / guardDivisor(cls)) + 1);
|
|
32
|
-
}
|
|
33
|
-
function estimateTokens(text) {
|
|
34
|
-
const stripped = stripAnsiEscapes(text);
|
|
35
|
-
return estimateTokensFromLength(stripped.length, classifyContent(stripped));
|
|
36
|
-
}
|
|
37
|
-
function trimToBudget(text, budgetTokens, command) {
|
|
38
|
-
const markerMarginTokens = 64;
|
|
39
|
-
const strippedAll = stripAnsiEscapes(text);
|
|
40
|
-
const contentClass = classifyContent(strippedAll);
|
|
41
|
-
const totalTokens = estimateTokensFromLength(strippedAll.length, contentClass);
|
|
42
|
-
if (totalTokens <= budgetTokens) {
|
|
43
|
-
return text;
|
|
44
|
-
}
|
|
45
|
-
const lines = text.split("\n");
|
|
46
|
-
if (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
|
|
47
|
-
const totalLines = lines.length;
|
|
48
|
-
const bodyBudget = Math.max(1, budgetTokens - markerMarginTokens);
|
|
49
|
-
const charBudget = bodyBudget * guardDivisor(contentClass);
|
|
50
|
-
const kept = [];
|
|
51
|
-
let used = 0;
|
|
52
|
-
for (const ln of lines) {
|
|
53
|
-
const stripped = stripAnsiEscapes(ln);
|
|
54
|
-
const cost = ln.length + 1;
|
|
55
|
-
if (kept.length === 0 && cost > charBudget) {
|
|
56
|
-
const truncated = safeSlice(stripped, charBudget);
|
|
57
|
-
kept.push(truncated);
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
if (kept.length > 0 && used + cost > charBudget) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
kept.push(ln);
|
|
64
|
-
used += cost;
|
|
65
|
-
}
|
|
66
|
-
const shown = kept.length;
|
|
67
|
-
const hint = getHintFor(command);
|
|
68
|
-
const marker = `[token-goat: output capped at ~${budgetTokens} tokens to protect context \u2014 showing ${shown} of ${totalLines} lines. ${hint}]`;
|
|
69
|
-
return kept.join("\n") + "\n" + marker;
|
|
70
|
-
}
|
|
71
|
-
function capJsonRows(items, budgetTokens) {
|
|
72
|
-
const totalCount = items.length;
|
|
73
|
-
const charBudget = Math.max(1, budgetTokens * guardDivisor());
|
|
74
|
-
const kept = [];
|
|
75
|
-
let used = 0;
|
|
76
|
-
for (const item of items) {
|
|
77
|
-
const cost = JSON.stringify(item).length + 2;
|
|
78
|
-
if (kept.length > 0 && used + cost > charBudget) break;
|
|
79
|
-
kept.push(item);
|
|
80
|
-
used += cost;
|
|
81
|
-
}
|
|
82
|
-
return { items: kept, truncated: kept.length < totalCount, totalCount };
|
|
83
|
-
}
|
|
84
|
-
function getHintFor(command) {
|
|
85
|
-
const cmd = (command || "").toLowerCase().trim();
|
|
86
|
-
if (cmd === "symbol") {
|
|
87
|
-
return "Request a specific method (file.py::Class.method) or use --json for structured access.";
|
|
88
|
-
}
|
|
89
|
-
if (cmd === "heading" || cmd === "section") {
|
|
90
|
-
return "Request a narrower sub-heading, e.g. 'doc.md::Section#2'.";
|
|
91
|
-
}
|
|
92
|
-
if (cmd === "lines") {
|
|
93
|
-
return "Request a smaller line range, e.g. 'file.py@100-150'.";
|
|
94
|
-
}
|
|
95
|
-
if (cmd === "bash-output" || cmd === "web-output") {
|
|
96
|
-
return "Use --grep PATTERN, --section HEADING, or --tail N to narrow the cached output.";
|
|
97
|
-
}
|
|
98
|
-
if (cmd === "semantic") {
|
|
99
|
-
return "Narrow your query text or pass --limit to reduce the number of matches returned.";
|
|
100
|
-
}
|
|
101
|
-
return "Narrow your query or raise overflow_guard max_tokens in config.";
|
|
102
|
-
}
|
|
103
|
-
|
|
104
23
|
// src/resident_context.ts
|
|
105
24
|
init_define_import_meta_env();
|
|
106
25
|
import * as fs from "node:fs";
|
|
@@ -307,10 +226,6 @@ function accumulateResidentLines(lines) {
|
|
|
307
226
|
|
|
308
227
|
export {
|
|
309
228
|
claudeConfigDir,
|
|
310
|
-
estimateTokensFromLength,
|
|
311
|
-
estimateTokens,
|
|
312
|
-
trimToBudget,
|
|
313
|
-
capJsonRows,
|
|
314
229
|
createResidentContextStats,
|
|
315
230
|
accumulateResidentLine,
|
|
316
231
|
summarizeResidentContext,
|
|
@@ -2,10 +2,10 @@ import { createRequire as __cjsRequire } from 'node:module';
|
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
estimateTokensFromLength
|
|
5
|
-
} from "./token-goat-chunk-
|
|
5
|
+
} from "./token-goat-chunk-4JMWPWCS.mjs";
|
|
6
6
|
import {
|
|
7
7
|
loadConfig
|
|
8
|
-
} from "./token-goat-chunk-
|
|
8
|
+
} from "./token-goat-chunk-CC2PYJM7.mjs";
|
|
9
9
|
import {
|
|
10
10
|
atomicWriteText,
|
|
11
11
|
backupFile,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
upsertDelimitedBlock,
|
|
22
22
|
withInstallScope,
|
|
23
23
|
writeIfDifferent
|
|
24
|
-
} from "./token-goat-chunk-
|
|
24
|
+
} from "./token-goat-chunk-L45ZQRT7.mjs";
|
|
25
25
|
import {
|
|
26
26
|
init_define_import_meta_env
|
|
27
27
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
@@ -51,6 +51,7 @@ function buildGuidanceBody(fallbackToolClause, opts = {}) {
|
|
|
51
51
|
'- not knowing which command answers a question you can already state in words \u2192 `answer "<question>"`, which resolves the subject in the index, runs the right command, prints `via: <command>`, and refuses rather than guess',
|
|
52
52
|
'- a shell text search with context flags to find a function body \u2192 `read "file::symbol"`',
|
|
53
53
|
'- paging one function with view/view_range \u2192 `read "file::symbol"`',
|
|
54
|
+
"- a read refused by a `[tg]` deny, retried with a shifted range or a different read tool \u2192 the command the deny names",
|
|
54
55
|
'- reading a symbol plus chasing its callers and containing doc section as separate reads \u2192 `brief "file::symbol"`',
|
|
55
56
|
'- reading one heading of a large doc \u2192 `section "file::Heading"`',
|
|
56
57
|
"- searching for a symbol's callers \u2192 `refs file::symbol --callers`",
|
|
@@ -1339,6 +1340,7 @@ export {
|
|
|
1339
1340
|
foldToolName,
|
|
1340
1341
|
COPILOT_CLI_TOOL_NAME_MAP,
|
|
1341
1342
|
MATERIALIZE_SHRUNK_IMAGE_JS,
|
|
1343
|
+
COPILOT_CLI_HOOK_SCRIPT,
|
|
1342
1344
|
buildGuidanceBody,
|
|
1343
1345
|
skillDescriptionLine,
|
|
1344
1346
|
buildGuidanceBlock,
|