token-goat 2.9.26 → 2.9.29
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 +30 -88
- package/SECURITY.md +14 -0
- package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-2AWQ2R5X.mjs} +2 -2
- package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-2NNUA2LR.mjs} +4 -4
- package/dist/token-goat-chunk-2WOUYWLM.mjs +955 -0
- package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-435UQTKD.mjs} +5 -3
- package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-44BM7DDQ.mjs} +5 -3
- package/dist/token-goat-chunk-52NSDWYY.mjs +96 -0
- package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-67BNIKKO.mjs} +32 -18
- package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-6AK46ZT7.mjs} +2 -3
- package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-7CPMDFGB.mjs} +166 -40
- package/dist/token-goat-chunk-ASLWOQ3I.mjs +14 -0
- package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-BGYOZ6DO.mjs} +6 -4
- package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-C5YPNZKQ.mjs} +22 -8
- package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-CIQ2FTY3.mjs} +23 -242
- package/dist/token-goat-chunk-D4ETHJD6.mjs +246 -0
- package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-DNRPXHYH.mjs} +25 -17
- package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-DNSPXQXQ.mjs} +2 -2
- package/dist/token-goat-chunk-DPNLUJWB.mjs +220 -0
- package/dist/token-goat-chunk-E4ZOJIZK.mjs +1382 -0
- package/dist/token-goat-chunk-E5TK5DNO.mjs +718 -0
- package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-EUSDXRXU.mjs} +62 -12
- package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-FTP4U4QA.mjs} +12 -8
- package/dist/token-goat-chunk-G23DWHV4.mjs +142 -0
- package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-G7IWXCFF.mjs} +223 -15
- package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-GLXRTTLE.mjs} +7 -5
- package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-H5J3C56Q.mjs} +95 -573
- package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-HNFZZHFW.mjs} +2 -2
- package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-HUYUHODZ.mjs} +1036 -759
- package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
- package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-IVWI2OCK.mjs} +72 -45
- package/dist/{token-goat-chunk-GMOUBOX4.mjs → token-goat-chunk-JTKCQMQA.mjs} +37 -5
- package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-KOPIR3KZ.mjs} +46 -23
- package/dist/token-goat-chunk-L7H3U27L.mjs +35 -0
- package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-LZNBQTDK.mjs} +6 -4
- package/dist/token-goat-chunk-MELOKFDJ.mjs +199 -0
- package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-NMBWLRHW.mjs} +164 -50
- package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-O6I2XU4P.mjs} +27 -967
- package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-ONXH6NZ5.mjs} +2 -87
- package/dist/token-goat-chunk-ORNFMIER.mjs +295 -0
- package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-PGTH2U4C.mjs} +1 -1
- package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-PKRWMHVP.mjs} +76 -59
- package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-PQ53BSCF.mjs} +1 -1
- package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-PYSUADX4.mjs} +2 -2
- package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-QO3LXVVR.mjs} +4247 -5005
- package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-RLP6J7WR.mjs} +6 -6
- package/dist/token-goat-chunk-RQGGMPCR.mjs +205 -0
- package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-RTMVLHWX.mjs} +3708 -4003
- package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-S4VSXURL.mjs} +8 -6
- package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-SE6E4BKJ.mjs} +1 -1
- package/dist/token-goat-chunk-TCQANXYC.mjs +351 -0
- package/dist/token-goat-chunk-TDUT2CL6.mjs +564 -0
- package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-TGOXNAHW.mjs} +54 -111
- package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-UA5BKWWQ.mjs} +1 -1
- package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UXSXQQIY.mjs} +1 -1
- package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-VMFWNHGR.mjs} +84 -73
- package/dist/token-goat-chunk-VQ6F6T7X.mjs +36 -0
- package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-VZQEWRVH.mjs} +6 -4
- package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
- package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-XYWPOSCN.mjs} +57 -615
- package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-YAGLESS3.mjs} +8 -5
- package/dist/token-goat-chunk-YKSRAWUU.mjs +33 -0
- package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-YOOVFPTP.mjs} +2 -2
- package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
- package/dist/token-goat-chunk-Z6KBMOBI.mjs +53 -0
- package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-ZER6EAXZ.mjs} +81 -70
- package/dist/token-goat-hook-client.cjs +475 -0
- package/dist/token-goat-hook-client.mjs +26 -0
- package/dist/token-goat-hook.mjs +31 -21
- package/dist/token-goat.core.mjs +9 -39
- package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
- package/docs/cli.md +35 -23
- package/docs/install.md +18 -14
- package/package.json +1 -1
- package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
- package/dist/token-goat-chunk-E6B2UFDF.mjs +0 -30
- package/dist/token-goat-chunk-GKZ2US5B.mjs +0 -187
- package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
|
-
import {
|
|
4
|
-
compareSemver
|
|
5
|
-
} from "./token-goat-chunk-BH4ZVRB2.mjs";
|
|
6
|
-
import {
|
|
7
|
-
buildCopilotWasteReport,
|
|
8
|
-
findLatestCopilotSession,
|
|
9
|
-
findProjectSession,
|
|
10
|
-
isCopilotTranscript
|
|
11
|
-
} from "./token-goat-chunk-PAV6NNY7.mjs";
|
|
12
|
-
import {
|
|
13
|
-
buildResumePacket
|
|
14
|
-
} from "./token-goat-chunk-L45IWWMC.mjs";
|
|
15
3
|
import {
|
|
16
4
|
ALL_SYMBOLS_IN_FILE_LIMIT,
|
|
17
5
|
AMBIGUOUS_HEADING_LIMIT,
|
|
@@ -21,7 +9,7 @@ import {
|
|
|
21
9
|
compressText,
|
|
22
10
|
computeFileFingerprint,
|
|
23
11
|
createHandoff,
|
|
24
|
-
|
|
12
|
+
didYouMeanLines,
|
|
25
13
|
emit,
|
|
26
14
|
emitErr,
|
|
27
15
|
enclosingSymbol,
|
|
@@ -90,6 +78,7 @@ import {
|
|
|
90
78
|
runScreenshot,
|
|
91
79
|
runSection,
|
|
92
80
|
runSemantic,
|
|
81
|
+
runSemanticMulti,
|
|
93
82
|
runSimilar,
|
|
94
83
|
runSkeleton,
|
|
95
84
|
runSqliteQuery,
|
|
@@ -104,10 +93,27 @@ import {
|
|
|
104
93
|
runYamlQuery,
|
|
105
94
|
runZipList,
|
|
106
95
|
runZipRead,
|
|
96
|
+
statThroughHandle,
|
|
107
97
|
symbolNamesInFile,
|
|
108
98
|
upsertNote,
|
|
109
99
|
warnIfFilesStale
|
|
110
|
-
} from "./token-goat-chunk-
|
|
100
|
+
} from "./token-goat-chunk-NMBWLRHW.mjs";
|
|
101
|
+
import "./token-goat-chunk-VZQEWRVH.mjs";
|
|
102
|
+
import {
|
|
103
|
+
compareSemver
|
|
104
|
+
} from "./token-goat-chunk-2NNUA2LR.mjs";
|
|
105
|
+
import "./token-goat-chunk-PQ53BSCF.mjs";
|
|
106
|
+
import {
|
|
107
|
+
MCP_DISABLE_NOTE,
|
|
108
|
+
buildCopilotWasteReport,
|
|
109
|
+
findLatestCopilotSession,
|
|
110
|
+
findProjectSession,
|
|
111
|
+
isCopilotTranscript,
|
|
112
|
+
unusedMcpServers
|
|
113
|
+
} from "./token-goat-chunk-C5YPNZKQ.mjs";
|
|
114
|
+
import {
|
|
115
|
+
buildResumePacket
|
|
116
|
+
} from "./token-goat-chunk-RLP6J7WR.mjs";
|
|
111
117
|
import {
|
|
112
118
|
DEFAULT_RECONCILE_BUDGET_MS,
|
|
113
119
|
HOOK_EVENTS,
|
|
@@ -126,19 +132,9 @@ import {
|
|
|
126
132
|
runRecallCommand,
|
|
127
133
|
runReconcile,
|
|
128
134
|
storeWebOutput
|
|
129
|
-
} from "./token-goat-chunk-
|
|
135
|
+
} from "./token-goat-chunk-DNRPXHYH.mjs";
|
|
130
136
|
import {
|
|
131
|
-
|
|
132
|
-
extractResultText,
|
|
133
|
-
findLatestTranscript,
|
|
134
|
-
projectTranscriptsDir,
|
|
135
|
-
safeStringify
|
|
136
|
-
} from "./token-goat-chunk-62IHOU6L.mjs";
|
|
137
|
-
import {
|
|
138
|
-
buildManifest
|
|
139
|
-
} from "./token-goat-chunk-MDV5VWF4.mjs";
|
|
140
|
-
import {
|
|
141
|
-
GEMINI_TOOL_NAME_MAP,
|
|
137
|
+
HINT_CATEGORIES,
|
|
142
138
|
MAX_FILES_SCANNED,
|
|
143
139
|
SKIP_DIRS,
|
|
144
140
|
WORKER_HEARTBEAT_STALE_MS,
|
|
@@ -153,6 +149,7 @@ import {
|
|
|
153
149
|
compactDoc,
|
|
154
150
|
compactPathFor,
|
|
155
151
|
confirmAndApply,
|
|
152
|
+
dataDirWriteRefusal,
|
|
156
153
|
detectWalkMode,
|
|
157
154
|
dirtyQueuePathFor,
|
|
158
155
|
drainHeartbeatPathFor,
|
|
@@ -170,6 +167,7 @@ import {
|
|
|
170
167
|
formatSymbolLocation,
|
|
171
168
|
getDirtyPathsFor,
|
|
172
169
|
getEmbeddingCoverage,
|
|
170
|
+
getHintSpendTotals,
|
|
173
171
|
getHintStatsSummary,
|
|
174
172
|
getHintStatsTotals,
|
|
175
173
|
getParserFreshness,
|
|
@@ -208,17 +206,32 @@ import {
|
|
|
208
206
|
visionTokensSavedByText,
|
|
209
207
|
walkProject,
|
|
210
208
|
writeCompact
|
|
211
|
-
} from "./token-goat-chunk-
|
|
209
|
+
} from "./token-goat-chunk-RTMVLHWX.mjs";
|
|
210
|
+
import "./token-goat-chunk-L7H3U27L.mjs";
|
|
211
|
+
import "./token-goat-chunk-RRNZMM3A.mjs";
|
|
212
|
+
import {
|
|
213
|
+
GEMINI_TOOL_NAME_MAP
|
|
214
|
+
} from "./token-goat-chunk-E5TK5DNO.mjs";
|
|
212
215
|
import {
|
|
213
216
|
CompressedOutput,
|
|
214
217
|
TOOL_FILTERS,
|
|
215
218
|
ToolFilter,
|
|
216
219
|
deliverCompressed,
|
|
217
220
|
detectFromCommand
|
|
218
|
-
} from "./token-goat-chunk-
|
|
221
|
+
} from "./token-goat-chunk-ZER6EAXZ.mjs";
|
|
219
222
|
import {
|
|
223
|
+
buildWasteReport,
|
|
224
|
+
extractResultText,
|
|
225
|
+
findLatestTranscript,
|
|
226
|
+
projectTranscriptsDir,
|
|
227
|
+
safeStringify
|
|
228
|
+
} from "./token-goat-chunk-44BM7DDQ.mjs";
|
|
229
|
+
import {
|
|
230
|
+
COPILOT_CLI_HOOK_SCRIPT,
|
|
220
231
|
HOOKS_SCRIPT_FILE,
|
|
232
|
+
LEGACY_HOOKS_SCRIPT_FILE,
|
|
221
233
|
MATERIALIZE_SHRUNK_IMAGE_JS,
|
|
234
|
+
SHIM_TRY_SERVER,
|
|
222
235
|
buildGuidanceBlock,
|
|
223
236
|
buildGuidanceBody,
|
|
224
237
|
bundledCliPath,
|
|
@@ -253,7 +266,14 @@ import {
|
|
|
253
266
|
visualStudioProjectMcpPath,
|
|
254
267
|
visualStudioSolutionVscodeMcpPath,
|
|
255
268
|
visualStudioUserMcpPath
|
|
256
|
-
} from "./token-goat-chunk-
|
|
269
|
+
} from "./token-goat-chunk-EUSDXRXU.mjs";
|
|
270
|
+
import {
|
|
271
|
+
buildManifest,
|
|
272
|
+
clearAll,
|
|
273
|
+
loadEntries,
|
|
274
|
+
setEntry,
|
|
275
|
+
unsetEntry
|
|
276
|
+
} from "./token-goat-chunk-G7IWXCFF.mjs";
|
|
257
277
|
import {
|
|
258
278
|
AGENT_SALT_MARKER,
|
|
259
279
|
CONTEXT_AUTOCOMPACT_TOKENS,
|
|
@@ -266,8 +286,6 @@ import {
|
|
|
266
286
|
findLatestSessionId,
|
|
267
287
|
formatAge,
|
|
268
288
|
getContextPressure,
|
|
269
|
-
getSessionFiles,
|
|
270
|
-
getSessionId,
|
|
271
289
|
getSkillFilePath,
|
|
272
290
|
incrementSkillHit,
|
|
273
291
|
listOutputs,
|
|
@@ -279,27 +297,39 @@ import {
|
|
|
279
297
|
skillOutputsDir,
|
|
280
298
|
storeCompact,
|
|
281
299
|
storeOutput
|
|
282
|
-
} from "./token-goat-chunk-
|
|
300
|
+
} from "./token-goat-chunk-H5J3C56Q.mjs";
|
|
301
|
+
import {
|
|
302
|
+
getSessionFiles,
|
|
303
|
+
getSessionId
|
|
304
|
+
} from "./token-goat-chunk-TDUT2CL6.mjs";
|
|
283
305
|
import {
|
|
284
|
-
capJsonRows,
|
|
285
306
|
claudeConfigDir,
|
|
286
|
-
estimateTokens,
|
|
287
|
-
estimateTokensFromLength,
|
|
288
307
|
formatBytes,
|
|
289
|
-
formatTokenEstimate
|
|
290
|
-
|
|
291
|
-
} from "./token-goat-chunk-G6EYO5CD.mjs";
|
|
308
|
+
formatTokenEstimate
|
|
309
|
+
} from "./token-goat-chunk-ONXH6NZ5.mjs";
|
|
292
310
|
import {
|
|
293
311
|
BASH_OUTPUT_SUBDIR,
|
|
294
|
-
clipLongMatchLine,
|
|
295
|
-
combineStreams,
|
|
296
312
|
getBashOutput,
|
|
297
313
|
isRecallCacheType
|
|
298
|
-
} from "./token-goat-chunk-
|
|
314
|
+
} from "./token-goat-chunk-O6I2XU4P.mjs";
|
|
299
315
|
import {
|
|
300
|
-
C,
|
|
301
316
|
DEFAULT_MAX_AGE_MS,
|
|
302
317
|
DEFAULT_MAX_COUNT,
|
|
318
|
+
listBlobs,
|
|
319
|
+
pruneBlobs
|
|
320
|
+
} from "./token-goat-chunk-D4ETHJD6.mjs";
|
|
321
|
+
import {
|
|
322
|
+
capJsonRows,
|
|
323
|
+
estimateTokens,
|
|
324
|
+
estimateTokensFromLength,
|
|
325
|
+
trimToBudget
|
|
326
|
+
} from "./token-goat-chunk-52NSDWYY.mjs";
|
|
327
|
+
import {
|
|
328
|
+
clipLongMatchLine,
|
|
329
|
+
combineStreams
|
|
330
|
+
} from "./token-goat-chunk-2WOUYWLM.mjs";
|
|
331
|
+
import {
|
|
332
|
+
C,
|
|
303
333
|
HOOK_STATS_RETENTION_DAYS,
|
|
304
334
|
RESET,
|
|
305
335
|
_useRichStats,
|
|
@@ -308,8 +338,6 @@ import {
|
|
|
308
338
|
fg,
|
|
309
339
|
formatLocalTimestamp,
|
|
310
340
|
getGlobalDb,
|
|
311
|
-
listBlobs,
|
|
312
|
-
pruneBlobs,
|
|
313
341
|
pruneStalePatternCoveredUnmappedTools,
|
|
314
342
|
readUnmappedTools,
|
|
315
343
|
recordStat,
|
|
@@ -321,19 +349,28 @@ import {
|
|
|
321
349
|
statsHasHarnessColumn,
|
|
322
350
|
stripAnsiEscapes,
|
|
323
351
|
summarize
|
|
324
|
-
} from "./token-goat-chunk-
|
|
352
|
+
} from "./token-goat-chunk-CIQ2FTY3.mjs";
|
|
353
|
+
import {
|
|
354
|
+
queryServers,
|
|
355
|
+
serverStatuses
|
|
356
|
+
} from "./token-goat-chunk-RQGGMPCR.mjs";
|
|
357
|
+
import {
|
|
358
|
+
readMarker,
|
|
359
|
+
touchMarker
|
|
360
|
+
} from "./token-goat-chunk-DPNLUJWB.mjs";
|
|
361
|
+
import "./token-goat-chunk-SE6E4BKJ.mjs";
|
|
325
362
|
import {
|
|
326
363
|
docxOutline,
|
|
327
364
|
docxTables,
|
|
328
365
|
docxText,
|
|
329
366
|
formatDocxTables
|
|
330
|
-
} from "./token-goat-chunk-
|
|
367
|
+
} from "./token-goat-chunk-UA5BKWWQ.mjs";
|
|
331
368
|
import {
|
|
332
369
|
pptxNotesText,
|
|
333
370
|
pptxOutline,
|
|
334
371
|
pptxSlideText,
|
|
335
372
|
pptxTextGrep
|
|
336
|
-
} from "./token-goat-chunk-
|
|
373
|
+
} from "./token-goat-chunk-HNFZZHFW.mjs";
|
|
337
374
|
import {
|
|
338
375
|
formatXlsxColumns,
|
|
339
376
|
formatXlsxRange,
|
|
@@ -342,11 +379,16 @@ import {
|
|
|
342
379
|
querySheet,
|
|
343
380
|
rangeSheet,
|
|
344
381
|
xlsxColumns
|
|
345
|
-
} from "./token-goat-chunk-
|
|
382
|
+
} from "./token-goat-chunk-PYSUADX4.mjs";
|
|
346
383
|
import {
|
|
347
384
|
formatCsvTable,
|
|
348
385
|
parseWhereSpecs
|
|
349
|
-
} from "./token-goat-chunk-
|
|
386
|
+
} from "./token-goat-chunk-DNSPXQXQ.mjs";
|
|
387
|
+
import "./token-goat-chunk-3BTK54F3.mjs";
|
|
388
|
+
import "./token-goat-chunk-UXSXQQIY.mjs";
|
|
389
|
+
import "./token-goat-chunk-XTQAOTSO.mjs";
|
|
390
|
+
import "./token-goat-chunk-AH6QILZM.mjs";
|
|
391
|
+
import "./token-goat-chunk-PGTH2U4C.mjs";
|
|
350
392
|
import {
|
|
351
393
|
assetEmbedSha,
|
|
352
394
|
deleteFileEmbeddings,
|
|
@@ -368,18 +410,21 @@ import {
|
|
|
368
410
|
maxChunksEmbedSha,
|
|
369
411
|
missingTreeSitterGrammarPackages,
|
|
370
412
|
modelFilesPresent,
|
|
413
|
+
oversizeEmbedSha,
|
|
371
414
|
parserFingerprintForLanguage,
|
|
372
415
|
readSection,
|
|
373
416
|
treeSitterCoreAvailable,
|
|
374
417
|
treeSitterCoreLoadError
|
|
375
|
-
} from "./token-goat-chunk-
|
|
418
|
+
} from "./token-goat-chunk-VMFWNHGR.mjs";
|
|
376
419
|
import {
|
|
377
420
|
getFileEntry,
|
|
378
421
|
getProjectFileEntries,
|
|
422
|
+
projectScopeClause,
|
|
379
423
|
querySymbols
|
|
380
|
-
} from "./token-goat-chunk-
|
|
424
|
+
} from "./token-goat-chunk-435UQTKD.mjs";
|
|
381
425
|
import {
|
|
382
426
|
TREE_SITTER_LANGUAGES,
|
|
427
|
+
allowReadOnlyIndex,
|
|
383
428
|
detectLanguage,
|
|
384
429
|
detectLanguageOfFile,
|
|
385
430
|
fenceFor,
|
|
@@ -388,14 +433,13 @@ import {
|
|
|
388
433
|
matchGroovySlashy,
|
|
389
434
|
nonTreeSitterLanguageCount,
|
|
390
435
|
redactIfDotenv
|
|
391
|
-
} from "./token-goat-chunk-
|
|
436
|
+
} from "./token-goat-chunk-7CPMDFGB.mjs";
|
|
392
437
|
import {
|
|
393
438
|
CONFIG_KEY_ENV_OVERRIDES,
|
|
394
439
|
PROJECT_LOCKED_KEYS,
|
|
395
440
|
PROJECT_LOCKED_SECTIONS,
|
|
396
441
|
SUPPORTED_OCR_LANG_CODES,
|
|
397
442
|
defaultConfig,
|
|
398
|
-
envBool,
|
|
399
443
|
fileIsAbsent,
|
|
400
444
|
findProject,
|
|
401
445
|
fingerprintContent,
|
|
@@ -404,8 +448,10 @@ import {
|
|
|
404
448
|
getLastConfigParseError,
|
|
405
449
|
getLastProjectConfigParseError,
|
|
406
450
|
getProjectConfigInfo,
|
|
451
|
+
hookServerEnabled,
|
|
407
452
|
invalidateConfigCache,
|
|
408
453
|
isSupportedOcrLang,
|
|
454
|
+
isUnderSystemTemp,
|
|
409
455
|
lastProjectConfigLockedKeys,
|
|
410
456
|
loadConfig,
|
|
411
457
|
loadPersistedConfig,
|
|
@@ -417,22 +463,21 @@ import {
|
|
|
417
463
|
stringify,
|
|
418
464
|
validateEnumField,
|
|
419
465
|
validateNumericField
|
|
420
|
-
} from "./token-goat-chunk-
|
|
466
|
+
} from "./token-goat-chunk-TGOXNAHW.mjs";
|
|
467
|
+
import "./token-goat-chunk-XB5KKOCG.mjs";
|
|
468
|
+
import "./token-goat-chunk-YZAAZU2S.mjs";
|
|
469
|
+
import {
|
|
470
|
+
envBool
|
|
471
|
+
} from "./token-goat-chunk-IVE6U7KV.mjs";
|
|
421
472
|
import {
|
|
422
|
-
ENV_KEYS,
|
|
423
473
|
LOCK_WAIT_MS_HARDENED,
|
|
424
|
-
PACKAGE_NAME,
|
|
425
|
-
VERSION,
|
|
426
474
|
assertProjectScopeTarget,
|
|
427
475
|
assertWriteInScope,
|
|
428
476
|
atomicWriteBytes,
|
|
429
477
|
atomicWriteText,
|
|
430
478
|
backupFile,
|
|
431
|
-
canonicalize,
|
|
432
479
|
cappedSourceBytesSaved,
|
|
433
|
-
configPath,
|
|
434
480
|
countNoun,
|
|
435
|
-
dataDir,
|
|
436
481
|
decodeSource,
|
|
437
482
|
detectSourceEncoding,
|
|
438
483
|
encodeSource,
|
|
@@ -440,19 +485,16 @@ import {
|
|
|
440
485
|
ensureNewline,
|
|
441
486
|
escapeRegExp,
|
|
442
487
|
extractErrorMessage,
|
|
443
|
-
|
|
444
|
-
globalDbPath,
|
|
488
|
+
hasCreatedConfig,
|
|
445
489
|
hookCommandFor,
|
|
446
490
|
hookExecPartsFor,
|
|
447
491
|
installSingleFilePlugin,
|
|
448
492
|
isTestFile,
|
|
449
493
|
isUnderBlockedRoot,
|
|
450
|
-
isWindows,
|
|
451
494
|
pad,
|
|
452
495
|
projectPathIsConsultable,
|
|
453
496
|
projectScopeRoot,
|
|
454
497
|
pushAll,
|
|
455
|
-
quoteShellPath,
|
|
456
498
|
recordCreatedConfig,
|
|
457
499
|
redactUrlQuery,
|
|
458
500
|
removeCreatedBackups,
|
|
@@ -460,16 +502,13 @@ import {
|
|
|
460
502
|
removeFileInScope,
|
|
461
503
|
requireNonNegativeStrictInt,
|
|
462
504
|
requirePositiveStrictInt,
|
|
463
|
-
resolveOnPath,
|
|
464
505
|
runGit,
|
|
465
|
-
sleepSync,
|
|
466
506
|
stripDelimitedBlock,
|
|
467
507
|
stripLower,
|
|
468
508
|
stripOwnHooksFromMap,
|
|
469
509
|
stripStaleGroupHooks,
|
|
470
510
|
takeCreatedConfig,
|
|
471
511
|
toKB,
|
|
472
|
-
tokenGoatHome,
|
|
473
512
|
uninstallSingleFilePlugin,
|
|
474
513
|
upsertDelimitedBlock,
|
|
475
514
|
withExtension,
|
|
@@ -478,7 +517,15 @@ import {
|
|
|
478
517
|
withRetryOnLock,
|
|
479
518
|
writeIfDifferent,
|
|
480
519
|
writeJsonSettings
|
|
481
|
-
} from "./token-goat-chunk-
|
|
520
|
+
} from "./token-goat-chunk-XYWPOSCN.mjs";
|
|
521
|
+
import {
|
|
522
|
+
canonicalize,
|
|
523
|
+
foldPath,
|
|
524
|
+
isWindows,
|
|
525
|
+
quoteShellPath,
|
|
526
|
+
resolveOnPath,
|
|
527
|
+
sleepSync
|
|
528
|
+
} from "./token-goat-chunk-TCQANXYC.mjs";
|
|
482
529
|
import {
|
|
483
530
|
UNTRUSTED_FILE_TAG,
|
|
484
531
|
UNTRUSTED_TOOL_TAG,
|
|
@@ -493,9 +540,19 @@ import {
|
|
|
493
540
|
resolveIndexPath,
|
|
494
541
|
toDisplayPath
|
|
495
542
|
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
543
|
+
import {
|
|
544
|
+
ENV_KEYS,
|
|
545
|
+
PACKAGE_NAME,
|
|
546
|
+
VERSION,
|
|
547
|
+
configPath,
|
|
548
|
+
dataDir,
|
|
549
|
+
globalDbPath,
|
|
550
|
+
tokenGoatHome
|
|
551
|
+
} from "./token-goat-chunk-MELOKFDJ.mjs";
|
|
552
|
+
import "./token-goat-chunk-Y4AFKTHK.mjs";
|
|
496
553
|
import {
|
|
497
554
|
compileGuardedRegex
|
|
498
|
-
} from "./token-goat-chunk-
|
|
555
|
+
} from "./token-goat-chunk-JTKCQMQA.mjs";
|
|
499
556
|
import {
|
|
500
557
|
__export,
|
|
501
558
|
init_define_import_meta_env
|
|
@@ -3626,9 +3683,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3626
3683
|
* @param {string} [path]
|
|
3627
3684
|
* @return {(string|null|Command)}
|
|
3628
3685
|
*/
|
|
3629
|
-
executableDir(
|
|
3630
|
-
if (
|
|
3631
|
-
this._executableDir =
|
|
3686
|
+
executableDir(path41) {
|
|
3687
|
+
if (path41 === void 0) return this._executableDir;
|
|
3688
|
+
this._executableDir = path41;
|
|
3632
3689
|
return this;
|
|
3633
3690
|
}
|
|
3634
3691
|
/**
|
|
@@ -3928,8 +3985,8 @@ function attemptedCommandName(argv) {
|
|
|
3928
3985
|
}
|
|
3929
3986
|
|
|
3930
3987
|
// src/cli.ts
|
|
3931
|
-
import * as
|
|
3932
|
-
import * as
|
|
3988
|
+
import * as fs44 from "fs";
|
|
3989
|
+
import * as path40 from "path";
|
|
3933
3990
|
|
|
3934
3991
|
// src/walk_index.ts
|
|
3935
3992
|
init_define_import_meta_env();
|
|
@@ -3991,6 +4048,18 @@ init_define_import_meta_env();
|
|
|
3991
4048
|
|
|
3992
4049
|
// src/bridges/shim_common.ts
|
|
3993
4050
|
init_define_import_meta_env();
|
|
4051
|
+
var SHIM_FILE = "token-goat-shim.cjs";
|
|
4052
|
+
var LEGACY_SHIM_FILE = "token-goat-shim.js";
|
|
4053
|
+
function legacyShimForwarder(noOp) {
|
|
4054
|
+
const answer = noOp === "" ? "" : `
|
|
4055
|
+
try { process.stdout.write('${noOp}') } catch {}`;
|
|
4056
|
+
return `#!/usr/bin/env node
|
|
4057
|
+
// Forwards to token-goat-shim.cjs for hook commands wired before the shim was renamed.
|
|
4058
|
+
import('./token-goat-shim.cjs').catch(() => {${answer}
|
|
4059
|
+
process.exitCode = 0
|
|
4060
|
+
});
|
|
4061
|
+
`;
|
|
4062
|
+
}
|
|
3994
4063
|
var SHIM_REQUIRES = `const { spawnSync } = require('node:child_process')
|
|
3995
4064
|
const path = require('node:path')
|
|
3996
4065
|
const { pathToFileURL } = require('node:url')`;
|
|
@@ -4022,10 +4091,12 @@ var SHIM_TRY_IN_PROCESS = `// Attempts the in-process hook call: import()s dist/
|
|
|
4022
4091
|
async function tryInProcess(entryPath, eventName, input, harnessWaitMs) {
|
|
4023
4092
|
if (!entryPath) return undefined
|
|
4024
4093
|
try {
|
|
4094
|
+
const payload = JSON.parse(input)
|
|
4095
|
+
const served = await tryServer(entryPath, eventName, input, harnessWaitMs)
|
|
4096
|
+
if (served !== undefined) return served
|
|
4025
4097
|
const hookLibPath = path.join(path.dirname(entryPath), 'token-goat-hook.mjs')
|
|
4026
4098
|
if (!require('node:fs').existsSync(hookLibPath)) return undefined
|
|
4027
4099
|
const mod = await import(pathToFileURL(hookLibPath).href)
|
|
4028
|
-
const payload = JSON.parse(input)
|
|
4029
4100
|
return await mod.relayInProcess(eventName, payload, harnessWaitMs)
|
|
4030
4101
|
} catch {
|
|
4031
4102
|
return undefined
|
|
@@ -4111,6 +4182,8 @@ ${SHIM_REQUIRES}
|
|
|
4111
4182
|
|
|
4112
4183
|
${SHIM_VALID_HOOK_EVENTS}
|
|
4113
4184
|
|
|
4185
|
+
${SHIM_TRY_SERVER}
|
|
4186
|
+
|
|
4114
4187
|
${SHIM_TRY_IN_PROCESS}
|
|
4115
4188
|
|
|
4116
4189
|
${SHIM_MAX_BUFFER_CONST}
|
|
@@ -4210,6 +4283,8 @@ var CANONICAL_SKILL_MD = gunzipSync(Buffer.from(CANONICAL_SKILL_GZIP_BASE64, "ba
|
|
|
4210
4283
|
var HOOK_EVENT_MAP = [
|
|
4211
4284
|
["PreToolUse", "pre_tool_use"],
|
|
4212
4285
|
["PostToolUse", "post_tool_use"],
|
|
4286
|
+
// A failed call never reaches PostToolUse: Claude Code 2.1.281 sends a missing-file Read and a non-zero Bash exit here instead, carrying `error`, `is_interrupt` and `duration_ms` (captured, 2026-09-24).
|
|
4287
|
+
["PostToolUseFailure", "post_tool_use_failure"],
|
|
4213
4288
|
["PreCompact", "pre_compact"],
|
|
4214
4289
|
["PostCompact", "post_compact"],
|
|
4215
4290
|
["UserPromptSubmit", "user_prompt_submit"],
|
|
@@ -4259,21 +4334,46 @@ function execFormSupportedForVersionOutput(stdout) {
|
|
|
4259
4334
|
function expectedHookEntryFor(scriptPath, event) {
|
|
4260
4335
|
return claudeExecFormHooksSupported() ? hookExecPartsFor(scriptPath, event) : { command: hookCommandFor(scriptPath, event) };
|
|
4261
4336
|
}
|
|
4337
|
+
function realPathOrNull(p) {
|
|
4338
|
+
if (!path3.isAbsolute(p)) return null;
|
|
4339
|
+
try {
|
|
4340
|
+
return fs3.realpathSync.native(p);
|
|
4341
|
+
} catch {
|
|
4342
|
+
return null;
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
function sameHookWord(a, b) {
|
|
4346
|
+
if (a === b) return true;
|
|
4347
|
+
const realA = realPathOrNull(a);
|
|
4348
|
+
return realA !== null && realA === realPathOrNull(b);
|
|
4349
|
+
}
|
|
4350
|
+
function stringFormHookWords(command) {
|
|
4351
|
+
const words = [];
|
|
4352
|
+
for (const m of command.matchAll(/"((?:\\.|[^"\\])*)"|(\S+)/g)) {
|
|
4353
|
+
const quoted = m[1];
|
|
4354
|
+
words.push(quoted === void 0 ? m[2] : process.platform === "win32" ? quoted : quoted.replace(/\\(.)/g, "$1"));
|
|
4355
|
+
}
|
|
4356
|
+
return words;
|
|
4357
|
+
}
|
|
4262
4358
|
function hookEntryMatches(command, args, expected) {
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
const
|
|
4266
|
-
|
|
4359
|
+
const execForm = expected.args !== void 0;
|
|
4360
|
+
if (!execForm && args !== void 0 && args.length > 0) return false;
|
|
4361
|
+
const a = execForm ? [command, ...args ?? []] : stringFormHookWords(command);
|
|
4362
|
+
const b = execForm ? [expected.command, ...expected.args] : stringFormHookWords(expected.command);
|
|
4363
|
+
return a.length === b.length && a.every((v, i) => sameHookWord(v, b[i]));
|
|
4267
4364
|
}
|
|
4268
4365
|
function claudeHookScriptPath() {
|
|
4269
|
-
return path3.join(claudeConfigDir(), "hooks",
|
|
4366
|
+
return path3.join(claudeConfigDir(), "hooks", SHIM_FILE);
|
|
4270
4367
|
}
|
|
4271
|
-
function
|
|
4368
|
+
function claudeLegacyHookScriptPath() {
|
|
4369
|
+
return path3.join(claudeConfigDir(), "hooks", LEGACY_SHIM_FILE);
|
|
4370
|
+
}
|
|
4371
|
+
function anyScopeReferencesShim(scriptPaths, currentScope, alreadyStripped) {
|
|
4272
4372
|
const referencesIn = (map) => {
|
|
4273
4373
|
for (const groups of Object.values(map ?? {})) {
|
|
4274
4374
|
for (const group of groups) {
|
|
4275
4375
|
for (const h of group.hooks ?? []) {
|
|
4276
|
-
if (h.command.includes(
|
|
4376
|
+
if (scriptPaths.some((p) => h.command.includes(p) || (h.args ?? []).some((a) => a.includes(p)))) return true;
|
|
4277
4377
|
}
|
|
4278
4378
|
}
|
|
4279
4379
|
}
|
|
@@ -4342,7 +4442,9 @@ function installHooksScoped(scope) {
|
|
|
4342
4442
|
const scriptPath = claudeHookScriptPath();
|
|
4343
4443
|
const scriptChanged = withInstallScope(void 0, () => {
|
|
4344
4444
|
ensureDirSync(path3.dirname(scriptPath));
|
|
4345
|
-
|
|
4445
|
+
const forwarderChanged = writeIfDifferent(claudeLegacyHookScriptPath(), legacyShimForwarder("{}"));
|
|
4446
|
+
const scriptChanged2 = writeIfDifferent(scriptPath, CLAUDECODE_HOOK_SCRIPT);
|
|
4447
|
+
return scriptChanged2 || forwarderChanged;
|
|
4346
4448
|
});
|
|
4347
4449
|
let settingsChanged = false;
|
|
4348
4450
|
for (const [eventKey, eventArg] of HOOK_EVENT_MAP) {
|
|
@@ -4409,8 +4511,8 @@ function uninstallHooksScoped(scope) {
|
|
|
4409
4511
|
const removed = stripOwnHooksFromMap(hooks, isTokenGoatHookCommand);
|
|
4410
4512
|
const scriptPath = claudeHookScriptPath();
|
|
4411
4513
|
let removedScript = false;
|
|
4412
|
-
if (!anyScopeReferencesShim(scriptPath, scope, hooks)) {
|
|
4413
|
-
removedScript = withInstallScope(void 0, () => removeFileInScope(
|
|
4514
|
+
if (!anyScopeReferencesShim([scriptPath, claudeLegacyHookScriptPath()], scope, hooks)) {
|
|
4515
|
+
removedScript = withInstallScope(void 0, () => [scriptPath, claudeLegacyHookScriptPath()].map((p2) => removeFileInScope(p2)).some(Boolean));
|
|
4414
4516
|
}
|
|
4415
4517
|
if (!removed) return removedScript;
|
|
4416
4518
|
if (Object.keys(hooks).length === 0) {
|
|
@@ -4423,16 +4525,19 @@ function uninstallHooksScoped(scope) {
|
|
|
4423
4525
|
return true;
|
|
4424
4526
|
}
|
|
4425
4527
|
function isInstalled(scope = "user") {
|
|
4426
|
-
|
|
4427
|
-
const
|
|
4428
|
-
|
|
4528
|
+
if (!fs3.existsSync(claudeHookScriptPath())) return false;
|
|
4529
|
+
const missing = missingHookEvents(scope);
|
|
4530
|
+
return missing !== null && missing.length === 0;
|
|
4531
|
+
}
|
|
4532
|
+
function missingHookEvents(scope = "user") {
|
|
4533
|
+
const hooks = readSettings(settingsPath(scope)).hooks;
|
|
4534
|
+
if (hooks === void 0) return null;
|
|
4535
|
+
if (!HOOK_EVENT_MAP.some(([eventKey]) => groupHasTokenGoat(hooks[eventKey], isTokenGoatHookCommand))) return null;
|
|
4429
4536
|
const scriptPath = claudeHookScriptPath();
|
|
4430
|
-
|
|
4431
|
-
for (const [eventKey, eventArg] of HOOK_EVENT_MAP) {
|
|
4537
|
+
return HOOK_EVENT_MAP.filter(([eventKey, eventArg]) => {
|
|
4432
4538
|
const expected = expectedHookEntryFor(scriptPath, eventArg);
|
|
4433
|
-
|
|
4434
|
-
}
|
|
4435
|
-
return true;
|
|
4539
|
+
return !groupHasTokenGoat(hooks[eventKey], (c, a) => hookEntryMatches(c, a, expected));
|
|
4540
|
+
}).map(([eventKey]) => eventKey);
|
|
4436
4541
|
}
|
|
4437
4542
|
var CLAUDE_MD_BEGIN = "<!-- token-goat-begin -->";
|
|
4438
4543
|
var CLAUDE_MD_END = "<!-- token-goat-end -->";
|
|
@@ -4586,6 +4691,8 @@ function stripTg(value) {
|
|
|
4586
4691
|
return value
|
|
4587
4692
|
}
|
|
4588
4693
|
|
|
4694
|
+
${SHIM_TRY_SERVER}
|
|
4695
|
+
|
|
4589
4696
|
${SHIM_TRY_IN_PROCESS}
|
|
4590
4697
|
|
|
4591
4698
|
${SHIM_MAX_BUFFER_CONST}
|
|
@@ -4705,7 +4812,10 @@ function codexAgentsPath() {
|
|
|
4705
4812
|
return path4.join(os2.homedir(), ".codex", "AGENTS.md");
|
|
4706
4813
|
}
|
|
4707
4814
|
function codexHookScriptPath() {
|
|
4708
|
-
return path4.join(os2.homedir(), ".codex", "hooks",
|
|
4815
|
+
return path4.join(os2.homedir(), ".codex", "hooks", SHIM_FILE);
|
|
4816
|
+
}
|
|
4817
|
+
function codexLegacyHookScriptPath() {
|
|
4818
|
+
return path4.join(os2.homedir(), ".codex", "hooks", LEGACY_SHIM_FILE);
|
|
4709
4819
|
}
|
|
4710
4820
|
function readCodexConfig(p, opts = {}) {
|
|
4711
4821
|
let raw;
|
|
@@ -4762,6 +4872,7 @@ function installCodex() {
|
|
|
4762
4872
|
const scriptPath = codexHookScriptPath();
|
|
4763
4873
|
ensureDirSync(path4.dirname(scriptPath));
|
|
4764
4874
|
atomicWriteText(scriptPath, CODEX_HOOK_SCRIPT);
|
|
4875
|
+
atomicWriteText(codexLegacyHookScriptPath(), legacyShimForwarder("{}"));
|
|
4765
4876
|
const config = readCodexConfig(configPath2, { strict: true });
|
|
4766
4877
|
const hooks = config.hooks ?? {};
|
|
4767
4878
|
let hooksChanged = false;
|
|
@@ -4915,10 +5026,12 @@ function uninstallCodex() {
|
|
|
4915
5026
|
if (stripAgentsBlock(agentsPath)) {
|
|
4916
5027
|
removedAny = true;
|
|
4917
5028
|
}
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
5029
|
+
for (const p of [scriptPath, codexLegacyHookScriptPath()]) {
|
|
5030
|
+
try {
|
|
5031
|
+
fs4.unlinkSync(p);
|
|
5032
|
+
removedAny = true;
|
|
5033
|
+
} catch {
|
|
5034
|
+
}
|
|
4922
5035
|
}
|
|
4923
5036
|
removeCreatedBackups(configPath2);
|
|
4924
5037
|
return removedAny;
|
|
@@ -5296,6 +5409,8 @@ function toKimi(parsed) {
|
|
|
5296
5409
|
return ''
|
|
5297
5410
|
}
|
|
5298
5411
|
|
|
5412
|
+
${SHIM_TRY_SERVER}
|
|
5413
|
+
|
|
5299
5414
|
${SHIM_TRY_IN_PROCESS}
|
|
5300
5415
|
|
|
5301
5416
|
${SHIM_MAX_BUFFER_CONST}
|
|
@@ -5369,7 +5484,10 @@ function kimiAgentsPath() {
|
|
|
5369
5484
|
return path7.join(kimiHome(), "AGENTS.md");
|
|
5370
5485
|
}
|
|
5371
5486
|
function kimiHookScriptPath() {
|
|
5372
|
-
return path7.join(kimiHome(), "hooks",
|
|
5487
|
+
return path7.join(kimiHome(), "hooks", SHIM_FILE);
|
|
5488
|
+
}
|
|
5489
|
+
function kimiLegacyHookScriptPath() {
|
|
5490
|
+
return path7.join(kimiHome(), "hooks", LEGACY_SHIM_FILE);
|
|
5373
5491
|
}
|
|
5374
5492
|
function kimiSkillDir() {
|
|
5375
5493
|
return path7.join(kimiHome(), "skills", "token-goat");
|
|
@@ -5439,6 +5557,7 @@ function installKimi() {
|
|
|
5439
5557
|
const scriptPath = kimiHookScriptPath();
|
|
5440
5558
|
ensureDirSync(path7.dirname(scriptPath));
|
|
5441
5559
|
atomicWriteText(scriptPath, KIMI_HOOK_SCRIPT);
|
|
5560
|
+
atomicWriteText(kimiLegacyHookScriptPath(), legacyShimForwarder(""));
|
|
5442
5561
|
const config = readKimiConfig(configPath2, { strict: true });
|
|
5443
5562
|
const existing = Array.isArray(config.hooks) ? config.hooks : [];
|
|
5444
5563
|
const desired = KIMI_HOOK_EVENTS.map((event) => ({
|
|
@@ -5490,12 +5609,14 @@ function uninstallKimi() {
|
|
|
5490
5609
|
}
|
|
5491
5610
|
} catch {
|
|
5492
5611
|
}
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
fs7.
|
|
5496
|
-
|
|
5612
|
+
for (const p of [kimiHookScriptPath(), kimiLegacyHookScriptPath()]) {
|
|
5613
|
+
try {
|
|
5614
|
+
if (fs7.existsSync(p)) {
|
|
5615
|
+
fs7.rmSync(p, { force: true });
|
|
5616
|
+
removed = true;
|
|
5617
|
+
}
|
|
5618
|
+
} catch {
|
|
5497
5619
|
}
|
|
5498
|
-
} catch {
|
|
5499
5620
|
}
|
|
5500
5621
|
removeCreatedBackups(configPath2);
|
|
5501
5622
|
return removed;
|
|
@@ -5589,7 +5710,7 @@ function resolveEntryPath(): string | undefined {
|
|
|
5589
5710
|
// undefined (triggering the spawnSync fallback below) when entryPath is absent, the
|
|
5590
5711
|
// sibling file doesn't exist (an install predating this file), or anything else goes
|
|
5591
5712
|
// wrong -- this must never throw.
|
|
5592
|
-
type RelayInProcessFn = (event: string, payload: unknown) => Promise<string>;
|
|
5713
|
+
type RelayInProcessFn = (event: string, payload: unknown, harnessWaitMs?: number, opts?: { elapsedMs?: () => number }) => Promise<string>;
|
|
5593
5714
|
let cachedRelayInProcess: RelayInProcessFn | undefined;
|
|
5594
5715
|
async function resolveRelayInProcess(): Promise<RelayInProcessFn | undefined> {
|
|
5595
5716
|
if (cachedRelayInProcess) return cachedRelayInProcess;
|
|
@@ -5657,11 +5778,13 @@ function callHookViaSpawn(event: string, payload: Record<string, unknown>): Reco
|
|
|
5657
5778
|
// its own fail-open null rather than being force-killed by pi's own hook timeout
|
|
5658
5779
|
// budget, ~5000ms) when the in-process path is unavailable or throws.
|
|
5659
5780
|
async function callHook(event: string, payload: Record<string, unknown>): Promise<Record<string, unknown> | null> {
|
|
5781
|
+
// Timed from here, not from process start: this host lives far longer than one call, so the hook library's default clock (process age) would record the host's uptime as this call's duration.
|
|
5782
|
+
const start = performance.now();
|
|
5660
5783
|
const relay = await resolveRelayInProcess();
|
|
5661
5784
|
if (relay) {
|
|
5662
5785
|
try {
|
|
5663
5786
|
process.env.TOKEN_GOAT_HARNESS_OVERRIDE = "pi";
|
|
5664
|
-
const out = await relay(event, payload);
|
|
5787
|
+
const out = await relay(event, payload, undefined, { elapsedMs: () => performance.now() - start });
|
|
5665
5788
|
const trimmed = out?.trim();
|
|
5666
5789
|
if (!trimmed) return null;
|
|
5667
5790
|
return JSON.parse(trimmed) as Record<string, unknown>;
|
|
@@ -6023,10 +6146,12 @@ function callHookViaSpawn(event, payload) {
|
|
|
6023
6146
|
// its own fail-open null rather than being force-killed by the host's own hook timeout
|
|
6024
6147
|
// budget, ~5000ms) when the in-process path is unavailable or throws.
|
|
6025
6148
|
async function callHook(event, payload) {
|
|
6149
|
+
// Timed from here, not from process start: this host lives far longer than one call, so the hook library's default clock (process age) would record the host's uptime as this call's duration.
|
|
6150
|
+
const start = performance.now();
|
|
6026
6151
|
const relay = await resolveRelayInProcess();
|
|
6027
6152
|
if (relay) {
|
|
6028
6153
|
try {
|
|
6029
|
-
const out = await relay(event, payload);
|
|
6154
|
+
const out = await relay(event, payload, undefined, { elapsedMs: () => performance.now() - start });
|
|
6030
6155
|
const trimmed = out ? out.trim() : "";
|
|
6031
6156
|
if (!trimmed) return null;
|
|
6032
6157
|
return JSON.parse(trimmed);
|
|
@@ -6556,6 +6681,8 @@ function allowResponse(eventName) {
|
|
|
6556
6681
|
return eventName === 'pre_tool_use' ? '{"decision":"allow"}' : '{}'
|
|
6557
6682
|
}
|
|
6558
6683
|
|
|
6684
|
+
${SHIM_TRY_SERVER}
|
|
6685
|
+
|
|
6559
6686
|
${SHIM_TRY_IN_PROCESS}
|
|
6560
6687
|
|
|
6561
6688
|
${SHIM_MAX_BUFFER_CONST}
|
|
@@ -6649,7 +6776,10 @@ function grokConfigPath() {
|
|
|
6649
6776
|
return path11.join(grokHooksDir(), "token-goat.json");
|
|
6650
6777
|
}
|
|
6651
6778
|
function grokHookScriptPath() {
|
|
6652
|
-
return path11.join(grokHooksDir(),
|
|
6779
|
+
return path11.join(grokHooksDir(), SHIM_FILE);
|
|
6780
|
+
}
|
|
6781
|
+
function grokLegacyHookScriptPath() {
|
|
6782
|
+
return path11.join(grokHooksDir(), LEGACY_SHIM_FILE);
|
|
6653
6783
|
}
|
|
6654
6784
|
function buildConfig(scriptPath) {
|
|
6655
6785
|
const hooks = {};
|
|
@@ -6663,11 +6793,12 @@ function buildConfig(scriptPath) {
|
|
|
6663
6793
|
function installGrok() {
|
|
6664
6794
|
const configPath2 = grokConfigPath();
|
|
6665
6795
|
const scriptPath = grokHookScriptPath();
|
|
6796
|
+
const forwarderChanged = writeIfDifferent(grokLegacyHookScriptPath(), legacyShimForwarder("{}"));
|
|
6666
6797
|
const scriptChanged = writeIfDifferent(scriptPath, GROK_HOOK_SCRIPT);
|
|
6667
6798
|
const desiredText = `${JSON.stringify(buildConfig(scriptPath), null, 2)}
|
|
6668
6799
|
`;
|
|
6669
6800
|
const configChanged = writeIfDifferent(configPath2, desiredText, true);
|
|
6670
|
-
return { configPath: configPath2, hookScriptPath: scriptPath, alreadyInstalled: !scriptChanged && !configChanged };
|
|
6801
|
+
return { configPath: configPath2, hookScriptPath: scriptPath, alreadyInstalled: !scriptChanged && !forwarderChanged && !configChanged };
|
|
6671
6802
|
}
|
|
6672
6803
|
function uninstallGrok() {
|
|
6673
6804
|
const configPath2 = grokConfigPath();
|
|
@@ -6678,10 +6809,12 @@ function uninstallGrok() {
|
|
|
6678
6809
|
removedAny = true;
|
|
6679
6810
|
} catch {
|
|
6680
6811
|
}
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6812
|
+
for (const p of [scriptPath, grokLegacyHookScriptPath()]) {
|
|
6813
|
+
try {
|
|
6814
|
+
fs11.unlinkSync(p);
|
|
6815
|
+
removedAny = true;
|
|
6816
|
+
} catch {
|
|
6817
|
+
}
|
|
6685
6818
|
}
|
|
6686
6819
|
removeCreatedBackups(configPath2);
|
|
6687
6820
|
return removedAny;
|
|
@@ -7169,6 +7302,9 @@ init_define_import_meta_env();
|
|
|
7169
7302
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7170
7303
|
import * as fs15 from "node:fs";
|
|
7171
7304
|
import * as path15 from "node:path";
|
|
7305
|
+
var ProcessListTimeout = class extends Error {
|
|
7306
|
+
};
|
|
7307
|
+
var PROCESS_LIST_TIMEOUT_MS = 2e4;
|
|
7172
7308
|
var INTERPRETER_BASENAMES = /* @__PURE__ */ new Set(["node.exe", "python.exe", "python3.exe", "pwsh.exe", "powershell.exe", "cmd.exe"]);
|
|
7173
7309
|
function describeProcess(commandLine) {
|
|
7174
7310
|
for (const m of commandLine.matchAll(/[^\s"]+\.(?:js|mjs|cjs|ts|py|exe)\b/gi)) {
|
|
@@ -7179,11 +7315,14 @@ function describeProcess(commandLine) {
|
|
|
7179
7315
|
return trimmed.length > 0 ? trimmed.length > 60 ? trimmed.slice(0, 60) + "\u2026" : trimmed : "(no command line)";
|
|
7180
7316
|
}
|
|
7181
7317
|
function checkMcpProcessHealth(processes) {
|
|
7182
|
-
if (processes
|
|
7318
|
+
if (!Array.isArray(processes)) {
|
|
7319
|
+
const failure = processes;
|
|
7320
|
+
const query = `Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Select-Object ProcessId,ParentProcessId,CommandLine`;
|
|
7321
|
+
const advice = failure.transient === true ? `Run doctor again once the machine is less busy, or list them yourself with: ${query}` : `List them yourself with: ${query}`;
|
|
7183
7322
|
return {
|
|
7184
7323
|
name: "MCP process health",
|
|
7185
7324
|
status: "warn",
|
|
7186
|
-
message:
|
|
7325
|
+
message: `could not read the process list (${displaySafeText(failure.reason)}), so duplicate MCP launchers and orphaned Node processes were not checked. ${advice}`
|
|
7187
7326
|
};
|
|
7188
7327
|
}
|
|
7189
7328
|
const byPid = new Set(processes.map((process3) => process3.processId));
|
|
@@ -7216,19 +7355,37 @@ function runProcessListCommand() {
|
|
|
7216
7355
|
const shell = path15.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
7217
7356
|
const result = spawnSync2(fs15.existsSync(shell) ? shell : "powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", command], {
|
|
7218
7357
|
encoding: "utf8",
|
|
7219
|
-
timeout:
|
|
7358
|
+
timeout: PROCESS_LIST_TIMEOUT_MS,
|
|
7220
7359
|
maxBuffer: 10 * 1024 * 1024,
|
|
7221
7360
|
windowsHide: true
|
|
7222
7361
|
});
|
|
7223
|
-
|
|
7224
|
-
|
|
7362
|
+
return processListOutput(result);
|
|
7363
|
+
}
|
|
7364
|
+
function processListOutput(result) {
|
|
7365
|
+
if (result.error !== void 0) {
|
|
7366
|
+
const code = result.error.code;
|
|
7367
|
+
if (code === "ETIMEDOUT") throw new ProcessListTimeout(`PowerShell did not finish within ${PROCESS_LIST_TIMEOUT_MS / 1e3}s`);
|
|
7368
|
+
if (code === "ENOENT") throw new Error("powershell.exe was not found");
|
|
7369
|
+
throw result.error;
|
|
7370
|
+
}
|
|
7371
|
+
const stdout = result.stdout ?? "";
|
|
7372
|
+
if (result.status !== 0 && stdout.trim() === "") {
|
|
7373
|
+
const firstLine2 = (result.stderr ?? "").split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "");
|
|
7374
|
+
throw new Error(`PowerShell exited with code ${String(result.status)}${firstLine2 !== void 0 ? `: ${firstLine2}` : ""}`);
|
|
7375
|
+
}
|
|
7376
|
+
return stdout;
|
|
7225
7377
|
}
|
|
7226
7378
|
function readWindowsProcesses(runCommand = runProcessListCommand) {
|
|
7227
7379
|
if (process.platform !== "win32") return [];
|
|
7228
7380
|
try {
|
|
7229
7381
|
const output = runCommand().trim();
|
|
7230
7382
|
if (output === "") return [];
|
|
7231
|
-
|
|
7383
|
+
let parsed;
|
|
7384
|
+
try {
|
|
7385
|
+
parsed = JSON.parse(output);
|
|
7386
|
+
} catch {
|
|
7387
|
+
return { reason: "PowerShell printed something other than the JSON process list" };
|
|
7388
|
+
}
|
|
7232
7389
|
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
7233
7390
|
return rows.flatMap((row) => {
|
|
7234
7391
|
if (typeof row !== "object" || row === null) return [];
|
|
@@ -7241,8 +7398,9 @@ function readWindowsProcesses(runCommand = runProcessListCommand) {
|
|
|
7241
7398
|
commandLine: typeof value["CommandLine"] === "string" ? value["CommandLine"] : ""
|
|
7242
7399
|
}];
|
|
7243
7400
|
});
|
|
7244
|
-
} catch {
|
|
7245
|
-
|
|
7401
|
+
} catch (e) {
|
|
7402
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
7403
|
+
return e instanceof ProcessListTimeout ? { reason, transient: true } : { reason };
|
|
7246
7404
|
}
|
|
7247
7405
|
}
|
|
7248
7406
|
function checkWorkerRunning(dataDir2) {
|
|
@@ -7329,6 +7487,15 @@ function checkVscodeClaudeHooks(useClaudeHooks, claudeHooksInstalled, vscodeHook
|
|
|
7329
7487
|
message: vscodeHooksInstalled2 ? "VS Code has chat.useClaudeHooks on and token-goat hooks are in both ~/.claude/settings.json and the Copilot hooks file, so each hook fires twice in VS Code. Turn chat.useClaudeHooks off in VS Code settings." : 'VS Code has chat.useClaudeHooks on, so it runs the token-goat hooks from ~/.claude/settings.json in Claude Code wire format, which VS Code reads only in part. Run "token-goat install --vscode" and turn chat.useClaudeHooks off in VS Code settings.'
|
|
7330
7488
|
};
|
|
7331
7489
|
}
|
|
7490
|
+
function checkClaudeHookEvents(missing) {
|
|
7491
|
+
const name = "Claude Code hook events";
|
|
7492
|
+
if (missing.user === null && missing.project === null) return null;
|
|
7493
|
+
const gaps = [];
|
|
7494
|
+
if (missing.user !== null && missing.user.length > 0) gaps.push(`user scope lacks ${missing.user.join(", ")}; run: token-goat install`);
|
|
7495
|
+
if (missing.project !== null && missing.project.length > 0) gaps.push(`project scope lacks ${missing.project.join(", ")}; run: token-goat install --project`);
|
|
7496
|
+
if (gaps.length === 0) return { name, status: "ok", message: "every event this build handles is wired" };
|
|
7497
|
+
return { name, status: "warn", message: `${gaps.join(". ")}. Those events never reach token-goat until then; restart any running session afterwards.` };
|
|
7498
|
+
}
|
|
7332
7499
|
function dedupeByResolvedPath(paths) {
|
|
7333
7500
|
const seen = /* @__PURE__ */ new Set();
|
|
7334
7501
|
return paths.filter((p) => {
|
|
@@ -7565,35 +7732,31 @@ function freelistBytes(header) {
|
|
|
7565
7732
|
const rawPageSize = header.readUInt16BE(16);
|
|
7566
7733
|
return (rawPageSize === 1 ? 65536 : rawPageSize) * header.readUInt32BE(36);
|
|
7567
7734
|
}
|
|
7568
|
-
var
|
|
7569
|
-
{ name: "
|
|
7570
|
-
{ name: "
|
|
7571
|
-
{
|
|
7572
|
-
|
|
7735
|
+
var STORAGE_GROUPS = [
|
|
7736
|
+
{ name: "refs", owns: /^refs$/, command: "grows with the files indexed, so it shrinks only when files leave the index" },
|
|
7737
|
+
{ name: "symbols and their search index", owns: /^symbols(_fts\w*)?$/, command: "grows with the files indexed, so it shrinks only when files leave the index" },
|
|
7738
|
+
{
|
|
7739
|
+
name: "embeddings",
|
|
7740
|
+
owns: /^(chunks|chunk_vectors\w*)$/,
|
|
7741
|
+
command: "these back 'semantic'; to drop them, set indexing.embeddings_enabled = false and indexing.auto_reclaim_embeddings = true, then run 'token-goat doctor --repair'"
|
|
7742
|
+
},
|
|
7743
|
+
{ name: "usage stats", owns: /^(stats\w*|hint_\w+|unmapped_tools)$/, command: "ages out on its own (180-day retention)" },
|
|
7744
|
+
{ name: "recall cache", owns: /^cache_recall\w*$/, command: "ages out on its own" }
|
|
7573
7745
|
];
|
|
7574
|
-
var
|
|
7746
|
+
var OWNER_BYTES_SQL = `SELECT COALESCE(m.tbl_name, s.name) AS owner, SUM(s.pgsize) AS bytes FROM dbstat AS s LEFT JOIN sqlite_master AS m ON m.name = s.name WHERE s.aggregate = 1 GROUP BY owner`;
|
|
7575
7747
|
function dbCategoryBreakdown(dbPath) {
|
|
7576
|
-
|
|
7577
|
-
const shares = [];
|
|
7578
|
-
for (const cat of CATEGORY_COLUMNS) {
|
|
7579
|
-
try {
|
|
7580
|
-
const row = db.prepare(`SELECT COALESCE(SUM(LENGTH(${cat.column})), 0) as bytes FROM ${cat.table}`).get();
|
|
7581
|
-
if (row.bytes > 0) shares.push({ name: cat.name, bytes: row.bytes, command: cat.command });
|
|
7582
|
-
} catch {
|
|
7583
|
-
}
|
|
7584
|
-
}
|
|
7748
|
+
let rows;
|
|
7585
7749
|
try {
|
|
7586
|
-
|
|
7587
|
-
if (row.n > 0) {
|
|
7588
|
-
shares.push({
|
|
7589
|
-
name: "embedding vectors",
|
|
7590
|
-
bytes: row.n * VECTOR_BYTES_PER_ROW,
|
|
7591
|
-
command: "'token-goat reclaim-index --rebuild' drops them (set indexing.embeddings_enabled = false first so they don't regrow)"
|
|
7592
|
-
});
|
|
7593
|
-
}
|
|
7750
|
+
rows = getDb(dbPath).prepare(OWNER_BYTES_SQL).all();
|
|
7594
7751
|
} catch {
|
|
7752
|
+
return [];
|
|
7595
7753
|
}
|
|
7596
|
-
|
|
7754
|
+
const shares = STORAGE_GROUPS.map((group) => ({
|
|
7755
|
+
name: group.name,
|
|
7756
|
+
bytes: rows.filter((r) => group.owns.test(r.owner)).reduce((sum, r) => sum + r.bytes, 0),
|
|
7757
|
+
command: group.command
|
|
7758
|
+
}));
|
|
7759
|
+
return shares.filter((share) => share.bytes > 0).sort((a, b) => b.bytes - a.bytes);
|
|
7597
7760
|
}
|
|
7598
7761
|
function oversizeDbMessage(dbPath, sizeBytes, freeBytes, tempRows, categories = [], topConsumers = [], thresholdMb = 1500, autoReclaimEmbeddings = false) {
|
|
7599
7762
|
const mb = (bytes) => Math.round(bytes / (1024 * 1024));
|
|
@@ -7604,15 +7767,18 @@ function oversizeDbMessage(dbPath, sizeBytes, freeBytes, tempRows, categories =
|
|
|
7604
7767
|
advice.push(`'token-goat doctor --repair' will automatically reclaim embedding vectors and compact global.db`);
|
|
7605
7768
|
}
|
|
7606
7769
|
const head = `global.db is ${mb(sizeBytes)} MB at ${displaySafeText(dbPath)} (larger than threshold of ${thresholdMb} MB). `;
|
|
7607
|
-
const
|
|
7770
|
+
const listed = categories.slice(0, 3);
|
|
7771
|
+
const totalCategoryBytes = listed.reduce((sum, c) => sum + c.bytes, 0);
|
|
7608
7772
|
const unmeasuredBytes = sizeBytes - totalCategoryBytes;
|
|
7609
|
-
const breakdown = totalCategoryBytes > 0 && sizeBytes > 0 ? ` Where it went: ${
|
|
7773
|
+
const breakdown = totalCategoryBytes > 0 && sizeBytes > 0 ? ` Where it went: ${listed.map((c) => `${c.name} ${mb(c.bytes)} MB (${Math.round(c.bytes / sizeBytes * 100)}%) -- ${c.command}`).join("; ")}.${unmeasuredBytes >= sizeBytes / 20 ? ` The other ${mb(unmeasuredBytes)} MB is smaller tables and free pages.` : ""}` : "";
|
|
7610
7774
|
let base = advice.length > 0 ? `${head}${advice.join("; ")}.${breakdown}` : `${head}Only ${mb(freeBytes)} MB of it is free pages and none of it is temp-dir scratch, so it is live index data that neither 'reclaim-index' nor 'project prune' will shrink.${breakdown}`;
|
|
7611
|
-
|
|
7775
|
+
const [top] = topConsumers;
|
|
7776
|
+
if (top !== void 0) {
|
|
7612
7777
|
const list = topConsumers.map((c) => `${path17.basename(c.root) || c.root} (${countNoun(c.fileCount, "file")})`).join(", ");
|
|
7613
7778
|
base += ` Top index consumers: ${list}.`;
|
|
7779
|
+
base += ` To shrink it, take out a project you do not need surgical reads in: 'token-goat project exclude "${displaySafeText(top.root)}"' removes its rows, then 'token-goat reclaim-index' returns the space.`;
|
|
7614
7780
|
}
|
|
7615
|
-
return base
|
|
7781
|
+
return `${base} If this size is expected, raise indexing.max_db_size_mb above ${Math.ceil(sizeBytes / (1024 * 1024))}.`;
|
|
7616
7782
|
}
|
|
7617
7783
|
function checkDbExists(dataDir2, maxDbSizeMb) {
|
|
7618
7784
|
const dbPath = path17.join(dataDir2, "global.db");
|
|
@@ -7716,6 +7882,29 @@ function checkSymbolCount(dbPath, rootDir) {
|
|
|
7716
7882
|
}
|
|
7717
7883
|
}
|
|
7718
7884
|
var EMBED_COVERAGE_WARN_FRACTION = 0.25;
|
|
7885
|
+
function unembeddedReasons(dbPath, rootDir, symbolOnlyKb, maxChunks) {
|
|
7886
|
+
const db = getDb(dbPath);
|
|
7887
|
+
const scope = rootDir === void 0 ? null : projectScopeClause("path");
|
|
7888
|
+
const rows = db.prepare(`SELECT path, sha, embed_sha FROM files${scope === null ? "" : ` WHERE ${scope.clause}`}`).all(...scope === null || rootDir === void 0 ? [] : scope.params(rootDir));
|
|
7889
|
+
let owed = 0;
|
|
7890
|
+
let overSizeCap = 0;
|
|
7891
|
+
for (const row of rows) {
|
|
7892
|
+
if (isUnderSystemTemp(row.path)) continue;
|
|
7893
|
+
if (row.embed_sha === oversizeEmbedSha(row.sha, symbolOnlyKb)) overSizeCap += 1;
|
|
7894
|
+
else if (!isEmbedFresh(row.embed_sha ?? void 0, row.sha, true, true, symbolOnlyKb, maxChunks)) owed += 1;
|
|
7895
|
+
}
|
|
7896
|
+
return { owed, overSizeCap };
|
|
7897
|
+
}
|
|
7898
|
+
function unembeddedReasonText(reasons, sizeKb) {
|
|
7899
|
+
let text = "";
|
|
7900
|
+
if (reasons.owed > 0) {
|
|
7901
|
+
text += ` ${countNoun(reasons.owed, "file")} ${reasons.owed === 1 ? "is" : "are"} still owed an embed: the worker embeds them while it is idle, or run 'token-goat index' in the project to embed them now.`;
|
|
7902
|
+
}
|
|
7903
|
+
if (reasons.overSizeCap > 0) {
|
|
7904
|
+
text += ` ${countNoun(reasons.overSizeCap, "file")} ${reasons.overSizeCap === 1 ? "is" : "are"} over indexing.large_file_symbol_only_kb (currently ${sizeKb} KB) and indexed for symbols only; raise it with 'token-goat config set indexing.large_file_symbol_only_kb <KB>' and the next 'token-goat index' embeds them.`;
|
|
7905
|
+
}
|
|
7906
|
+
return text;
|
|
7907
|
+
}
|
|
7719
7908
|
function checkEmbeddingCoverage(dbPath, rootDir) {
|
|
7720
7909
|
if (!fs18.existsSync(dbPath)) {
|
|
7721
7910
|
return { name: "Embedding coverage", status: "ok", message: "no database yet" };
|
|
@@ -7735,7 +7924,7 @@ function checkEmbeddingCoverage(dbPath, rootDir) {
|
|
|
7735
7924
|
return {
|
|
7736
7925
|
name: "Embedding coverage",
|
|
7737
7926
|
status: "warn",
|
|
7738
|
-
message: `only ${embeddedFiles} of ${indexedFiles} indexed file(s) (${pct3}%) have embeddings
|
|
7927
|
+
message: `only ${embeddedFiles} of ${indexedFiles} indexed file(s) (${pct3}%) have embeddings, so 'semantic' searches those files only, and reports finding nothing in the same words it uses after searching everything.` + unembeddedReasonText(unembeddedReasons(dbPath, rootDir, sizeKb, cfg.indexing.max_chunks_per_file), sizeKb) + ` Exact symbol lookups are unaffected`
|
|
7739
7928
|
};
|
|
7740
7929
|
}
|
|
7741
7930
|
return {
|
|
@@ -7989,16 +8178,33 @@ function checkDiskSpace(dataDir2) {
|
|
|
7989
8178
|
}
|
|
7990
8179
|
return { name: "Disk Space", status: "warn", message: "disk space check unavailable on this platform" };
|
|
7991
8180
|
}
|
|
7992
|
-
function checkCopilotCli(configPath2, scriptPath) {
|
|
7993
|
-
if (!fs18.existsSync(configPath2)
|
|
8181
|
+
function checkCopilotCli(configPath2, scriptPath, scope = "user") {
|
|
8182
|
+
if (!fs18.existsSync(configPath2)) {
|
|
7994
8183
|
return null;
|
|
7995
8184
|
}
|
|
8185
|
+
const name = scope === "project" ? "Copilot CLI (project)" : "Copilot CLI";
|
|
8186
|
+
const { install, harness } = copilotHooksRecovery(path17.dirname(configPath2), scope);
|
|
8187
|
+
if (scope === "project" && !hasCreatedConfig(configPath2)) {
|
|
8188
|
+
return {
|
|
8189
|
+
name,
|
|
8190
|
+
status: "warn",
|
|
8191
|
+
message: `hook config at ${configPath2} was not written by token-goat on this machine, so doctor does not run the command it names. If these hooks are yours, run "${install}" to rewrite them here.`
|
|
8192
|
+
};
|
|
8193
|
+
}
|
|
8194
|
+
if (!fs18.existsSync(scriptPath)) {
|
|
8195
|
+
if (!fs18.existsSync(path17.join(path17.dirname(scriptPath), LEGACY_HOOKS_SCRIPT_FILE))) return null;
|
|
8196
|
+
return {
|
|
8197
|
+
name,
|
|
8198
|
+
status: "warn",
|
|
8199
|
+
message: `hooks at ${path17.dirname(scriptPath)} still run ${LEGACY_HOOKS_SCRIPT_FILE} from an older token-goat build, which Node loads as an ES module under any package.json that says "type": "module" and then fails every tool call. Recovery: run "${install}", then fully restart ${harness}.`
|
|
8200
|
+
};
|
|
8201
|
+
}
|
|
7996
8202
|
let config;
|
|
7997
8203
|
try {
|
|
7998
8204
|
config = JSON.parse(fs18.readFileSync(configPath2, "utf-8"));
|
|
7999
8205
|
} catch (err2) {
|
|
8000
8206
|
return {
|
|
8001
|
-
name
|
|
8207
|
+
name,
|
|
8002
8208
|
status: "fail",
|
|
8003
8209
|
message: `hook config at ${configPath2} is not valid JSON: ${extractErrorMessage(err2, "unknown error")}`
|
|
8004
8210
|
};
|
|
@@ -8006,17 +8212,17 @@ function checkCopilotCli(configPath2, scriptPath) {
|
|
|
8006
8212
|
const preToolUseCommand = config.hooks?.["preToolUse"]?.[0]?.command;
|
|
8007
8213
|
if (typeof preToolUseCommand !== "string" || preToolUseCommand === "") {
|
|
8008
8214
|
return {
|
|
8009
|
-
name
|
|
8215
|
+
name,
|
|
8010
8216
|
status: "fail",
|
|
8011
|
-
message: `hook config at ${configPath2} has no preToolUse entry; run:
|
|
8217
|
+
message: `hook config at ${configPath2} has no preToolUse entry; run: ${install}`
|
|
8012
8218
|
};
|
|
8013
8219
|
}
|
|
8014
8220
|
const bakedExecPath = /^"([^"]+)"/.exec(preToolUseCommand)?.[1];
|
|
8015
8221
|
if (bakedExecPath !== void 0 && !fs18.existsSync(bakedExecPath)) {
|
|
8016
8222
|
return {
|
|
8017
|
-
name
|
|
8223
|
+
name,
|
|
8018
8224
|
status: "fail",
|
|
8019
|
-
message: `hook points at a node binary that no longer exists (${bakedExecPath}) -- likely stale after an nvm/fnm/volta node upgrade. Recovery: run "
|
|
8225
|
+
message: `hook points at a node binary that no longer exists (${bakedExecPath}) -- likely stale after an nvm/fnm/volta node upgrade. Recovery: run "${install}", then fully restart ${harness} (renaming/reinstalling the hook has no effect on an already-running session -- hook configs are cached at startup).`
|
|
8020
8226
|
};
|
|
8021
8227
|
}
|
|
8022
8228
|
const synthetic = JSON.stringify({
|
|
@@ -8034,28 +8240,56 @@ function checkCopilotCli(configPath2, scriptPath) {
|
|
|
8034
8240
|
});
|
|
8035
8241
|
if (res.error) {
|
|
8036
8242
|
return {
|
|
8037
|
-
name
|
|
8243
|
+
name,
|
|
8038
8244
|
status: "fail",
|
|
8039
|
-
message: `hook failed to launch: ${extractErrorMessage(res.error, "unknown error")}. Recovery: run "
|
|
8245
|
+
message: `hook failed to launch: ${extractErrorMessage(res.error, "unknown error")}. Recovery: run "${install}", then fully restart ${harness}.`
|
|
8040
8246
|
};
|
|
8041
8247
|
}
|
|
8042
8248
|
if (res.status !== 0) {
|
|
8043
8249
|
return {
|
|
8044
|
-
name
|
|
8250
|
+
name,
|
|
8045
8251
|
status: "fail",
|
|
8046
|
-
message: `hook exited with status ${res.status} -- Copilot's preToolUse fails closed on a non-zero exit and denies every tool call for the rest of the session. Recovery: run "
|
|
8252
|
+
message: `hook exited with status ${res.status} -- Copilot's preToolUse fails closed on a non-zero exit and denies every tool call for the rest of the session. Recovery: run "${install}", then fully restart ${harness} (a live session won't pick up the fix).`
|
|
8047
8253
|
};
|
|
8048
8254
|
}
|
|
8049
8255
|
try {
|
|
8050
8256
|
JSON.parse(res.stdout ?? "");
|
|
8051
8257
|
} catch {
|
|
8052
8258
|
return {
|
|
8053
|
-
name
|
|
8259
|
+
name,
|
|
8054
8260
|
status: "fail",
|
|
8055
|
-
message:
|
|
8261
|
+
message: `hook did not return valid JSON -- Copilot treats this as a hook error and denies every tool call. Recovery: run "${install}", then fully restart ${harness}.`
|
|
8262
|
+
};
|
|
8263
|
+
}
|
|
8264
|
+
if (!shimIsCurrent(scriptPath, COPILOT_CLI_HOOK_SCRIPT)) {
|
|
8265
|
+
return { name, status: "warn", message: staleShimMessage(scriptPath, "Copilot", install) + `, then fully restart ${harness}.` };
|
|
8266
|
+
}
|
|
8267
|
+
return { name, status: "ok", message: "preToolUse hook invokes cleanly and returns valid JSON" };
|
|
8268
|
+
}
|
|
8269
|
+
function copilotHooksRecovery(hooksDir, scope) {
|
|
8270
|
+
const owners = readCopilotHooksOwners(hooksDir);
|
|
8271
|
+
if (!owners.has("copilot") && owners.has("vscode")) {
|
|
8272
|
+
return { install: scope === "project" ? "token-goat install --vscode" : "token-goat install --vscode --user", harness: "VS Code" };
|
|
8273
|
+
}
|
|
8274
|
+
return { install: scope === "project" ? "token-goat install --copilot --local" : "token-goat install --copilot", harness: "Copilot CLI" };
|
|
8275
|
+
}
|
|
8276
|
+
function shimIsCurrent(scriptPath, expected) {
|
|
8277
|
+
return fs18.readFileSync(scriptPath, "utf-8").replace(/\r\n/g, "\n") === expected.replace(/\r\n/g, "\n");
|
|
8278
|
+
}
|
|
8279
|
+
function staleShimMessage(scriptPath, harness, reinstall) {
|
|
8280
|
+
return `hook shim at ${scriptPath} was written by an older token-goat build, so fixes to it since then are not reaching ${harness}. Recovery: run "${reinstall}"`;
|
|
8281
|
+
}
|
|
8282
|
+
function checkHookShim(name, scriptPath, expected, reinstall) {
|
|
8283
|
+
if (!fs18.existsSync(scriptPath)) {
|
|
8284
|
+
if (!fs18.existsSync(path17.join(path17.dirname(scriptPath), LEGACY_SHIM_FILE))) return null;
|
|
8285
|
+
return {
|
|
8286
|
+
name,
|
|
8287
|
+
status: "warn",
|
|
8288
|
+
message: `hooks at ${path17.dirname(scriptPath)} still run ${LEGACY_SHIM_FILE} from an older token-goat build, which Node loads as an ES module under any package.json that says "type": "module" and then fails every tool call. Recovery: run "${reinstall}", then restart any running session.`
|
|
8056
8289
|
};
|
|
8057
8290
|
}
|
|
8058
|
-
return { name
|
|
8291
|
+
if (shimIsCurrent(scriptPath, expected)) return { name, status: "ok", message: `hook shim at ${scriptPath} matches this build` };
|
|
8292
|
+
return { name, status: "warn", message: staleShimMessage(scriptPath, name, reinstall) + ", then restart any running session." };
|
|
8059
8293
|
}
|
|
8060
8294
|
var COMPACTION_CHANNEL_WINDOW = 5;
|
|
8061
8295
|
var COMPACTION_STATS_BATCH_SIZE = 50;
|
|
@@ -8192,6 +8426,28 @@ function checkUnmappedTools(dbPath, options) {
|
|
|
8192
8426
|
return { name, status: "warn", message: `could not read the tool-name histogram: ${extractErrorMessage(e)}` };
|
|
8193
8427
|
}
|
|
8194
8428
|
}
|
|
8429
|
+
function checkWorker(dir) {
|
|
8430
|
+
if (checkWorkerRunning(dir)) return { name: "Worker", status: "ok", message: "running" };
|
|
8431
|
+
const refusal2 = fs18.existsSync(dir) ? dataDirWriteRefusal(dir) : void 0;
|
|
8432
|
+
if (refusal2 !== void 0) {
|
|
8433
|
+
return { name: "Worker", status: "fail", message: `not running, and cannot start: ${displaySafeText(dir)} cannot be written (${displaySafeText(extractErrorMessage(refusal2))}); make it writable, then run 'token-goat worker start'` };
|
|
8434
|
+
}
|
|
8435
|
+
return { name: "Worker", status: "warn", message: "not running" };
|
|
8436
|
+
}
|
|
8437
|
+
function checkHookServer(state) {
|
|
8438
|
+
const name = "Hook server";
|
|
8439
|
+
if (!state.enabled) return { name, status: "ok", message: "off (hooks.server or TOKEN_GOAT_HOOK_SERVER); every hook call starts its own process" };
|
|
8440
|
+
if (state.statuses.length > 0) return { name, status: "ok", message: `${state.statuses.length} running (${state.statuses.map((s) => `slot ${s.slot}, pid ${s.pid}, ${s.served} served`).join("; ")})` };
|
|
8441
|
+
if (state.failure !== void 0) return { name, status: "warn", message: `not running, and the last start failed: ${state.failure}. Run 'token-goat hook-server run' to see it in the foreground` };
|
|
8442
|
+
return { name, status: "ok", message: "not running; the next hook call starts one" };
|
|
8443
|
+
}
|
|
8444
|
+
async function runDoctorChecks(dataDir2, configPath2, rootDir, processes) {
|
|
8445
|
+
const results = runDoctor(dataDir2, configPath2, rootDir, processes);
|
|
8446
|
+
const enabled = hookServerEnabled();
|
|
8447
|
+
const dir = dataDir2 || dataDir();
|
|
8448
|
+
results.push(checkHookServer({ enabled, statuses: enabled ? await serverStatuses(dir) : [], failure: readMarker("failed", dir) }));
|
|
8449
|
+
return results;
|
|
8450
|
+
}
|
|
8195
8451
|
function runDoctor(dataDir2, configPath2, rootDir, processes) {
|
|
8196
8452
|
const results = [];
|
|
8197
8453
|
const actualDataDir = dataDir2 || dataDir();
|
|
@@ -8199,7 +8455,7 @@ function runDoctor(dataDir2, configPath2, rootDir, processes) {
|
|
|
8199
8455
|
results.push(checkTsCompiler());
|
|
8200
8456
|
results.push(checkTreeSitter());
|
|
8201
8457
|
results.push(checkStrayClaudeMdBlocks());
|
|
8202
|
-
results.push(
|
|
8458
|
+
results.push(checkWorker(actualDataDir));
|
|
8203
8459
|
const cfg = loadConfig(rootDir);
|
|
8204
8460
|
results.push(checkDbExists(actualDataDir, cfg.indexing.max_db_size_mb));
|
|
8205
8461
|
results.push(checkSymbolBodySize(path17.join(actualDataDir, "global.db")));
|
|
@@ -8218,6 +8474,14 @@ function runDoctor(dataDir2, configPath2, rootDir, processes) {
|
|
|
8218
8474
|
results.push(checkDiskSpace(actualDataDir));
|
|
8219
8475
|
const copilotResult = checkCopilotCli(copilotCliConfigPath(), copilotCliScriptPath());
|
|
8220
8476
|
if (copilotResult) results.push(copilotResult);
|
|
8477
|
+
const copilotProjectResult = checkCopilotCli(copilotCliConfigPath({ local: true }), copilotCliScriptPath({ local: true }), "project");
|
|
8478
|
+
if (copilotProjectResult) results.push(copilotProjectResult);
|
|
8479
|
+
const claudeShimResult = checkHookShim("Claude Code", claudeHookScriptPath(), CLAUDECODE_HOOK_SCRIPT, isInstalled("user") || !isInstalled("project") ? "token-goat install" : "token-goat install --project");
|
|
8480
|
+
if (claudeShimResult) results.push(claudeShimResult);
|
|
8481
|
+
const claudeEventsResult = checkClaudeHookEvents({ user: missingHookEvents("user"), project: missingHookEvents("project") });
|
|
8482
|
+
if (claudeEventsResult) results.push(claudeEventsResult);
|
|
8483
|
+
const codexShimResult = checkHookShim("Codex", codexHookScriptPath(), CODEX_HOOK_SCRIPT, "token-goat install --codex");
|
|
8484
|
+
if (codexShimResult) results.push(codexShimResult);
|
|
8221
8485
|
const vscodeHooksResult = checkVscodeClaudeHooks(
|
|
8222
8486
|
vscodeUsesClaudeHooks(),
|
|
8223
8487
|
isInstalled("user") || isInstalled("project"),
|
|
@@ -8432,7 +8696,7 @@ async function runDoctorAndExit(opts) {
|
|
|
8432
8696
|
console.log();
|
|
8433
8697
|
}
|
|
8434
8698
|
}
|
|
8435
|
-
const results =
|
|
8699
|
+
const results = await runDoctorChecks(options.dataDir, options.configPath, options.rootDir, options.processes);
|
|
8436
8700
|
printDoctorResults(results);
|
|
8437
8701
|
if (options.context === true) {
|
|
8438
8702
|
console.log("\n## Context footprint\n");
|
|
@@ -8470,7 +8734,7 @@ async function runDoctorAndExit(opts) {
|
|
|
8470
8734
|
}
|
|
8471
8735
|
}
|
|
8472
8736
|
try {
|
|
8473
|
-
const { checkUpdateStatus } = await import("./token-goat-chunk-
|
|
8737
|
+
const { checkUpdateStatus } = await import("./token-goat-chunk-YAGLESS3.mjs");
|
|
8474
8738
|
const update = await checkUpdateStatus(1500);
|
|
8475
8739
|
if (update.updateAvailable && update.latest) {
|
|
8476
8740
|
console.log(`
|
|
@@ -8566,7 +8830,7 @@ function generateCompactHelp() {
|
|
|
8566
8830
|
" -h, --help display help for command",
|
|
8567
8831
|
"",
|
|
8568
8832
|
"Reads: symbol, read, brief, section, semantic, skeleton, outline, refs, scope,",
|
|
8569
|
-
" similar, context-for, call-chain, impact, callers, dead, test-for",
|
|
8833
|
+
" similar, context-for, call-chain, impact, callers, dead, test-for, locate",
|
|
8570
8834
|
"",
|
|
8571
8835
|
"Analysis: arch, affected, blame, deps, types, coverage-gaps, changed, diff, log,",
|
|
8572
8836
|
" exports, imports, find, grep",
|
|
@@ -8579,30 +8843,29 @@ function generateCompactHelp() {
|
|
|
8579
8843
|
"",
|
|
8580
8844
|
"Index & Search: index, map, reconcile, doctor, commands, ask, answer, pack, tokens,",
|
|
8581
8845
|
" budget, failures, todo, trace, logfold, lockdeps, dep-docs, recent, hot,",
|
|
8582
|
-
"
|
|
8846
|
+
" baseline, cost, coverage-report-gaps, clean-cache,",
|
|
8583
8847
|
" cache-audit, reclaim-index, project",
|
|
8584
8848
|
"",
|
|
8585
8849
|
"Session: stats, waste, session-outline, session-audit, session-slice,",
|
|
8586
8850
|
" session-summary, context-stats, bootstrap-audit, memory, hint-stats,",
|
|
8587
|
-
" session-schema, mcp-audit",
|
|
8851
|
+
" session-schema, mcp-audit, audit",
|
|
8588
8852
|
"",
|
|
8589
8853
|
"Skills: skill-body, skill-compact, skill-list, skill-size, skill-history,",
|
|
8590
8854
|
" skill-diff, skill-section",
|
|
8591
8855
|
"",
|
|
8592
8856
|
"Compression: compress-text, retrieve, handoff-create, handoff-resolve,",
|
|
8593
|
-
" compress, recall, bash-output, web-output, mcp-output,
|
|
8594
|
-
" compress, bench",
|
|
8857
|
+
" compress, recall, bash-output, web-output, mcp-output, bench",
|
|
8595
8858
|
"",
|
|
8596
8859
|
"Config & Integration: install, uninstall, upgrade, mcp-serve, mcp-status, hook,",
|
|
8597
|
-
" bridges-status, worker, statusline, version, config, config-get,",
|
|
8860
|
+
" bridges-status, worker, hook-server, statusline, version, config, config-get,",
|
|
8598
8861
|
" capabilities, help",
|
|
8599
8862
|
"",
|
|
8600
8863
|
"Data: note, note-add, note-get, note-list, describe, sqlite-query,",
|
|
8601
8864
|
" sqlite-tables, sqlite-schema, csv-profile, csv-query",
|
|
8602
8865
|
"",
|
|
8603
|
-
"Utils: ignores, bash-history, web-history, openapi-op, openapi-outline,",
|
|
8604
|
-
" gdrive-sections, screenshot,
|
|
8605
|
-
" image-text,
|
|
8866
|
+
"Utils: ignores, bash-history, web-history, history, openapi-op, openapi-outline,",
|
|
8867
|
+
" gdrive-sections, screenshot, fetch-image, image-meta,",
|
|
8868
|
+
" image-text, resume, replace, insert-section, pr-slice,",
|
|
8606
8869
|
" sharepoint-resolve, transcript, transcript-outline, video-chapters,",
|
|
8607
8870
|
" write-file, zip-list, zip-read, mcp-history, compact-doc, compact-hint,",
|
|
8608
8871
|
" conflicts, prune-cache",
|
|
@@ -8904,12 +9167,9 @@ function performHttpFetch(targetUrl, opts) {
|
|
|
8904
9167
|
});
|
|
8905
9168
|
}
|
|
8906
9169
|
|
|
8907
|
-
// src/
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
saveConfig(cfg);
|
|
8911
|
-
}
|
|
8912
|
-
function levenshtein(a, b, cap = 3) {
|
|
9170
|
+
// src/util_suggest.ts
|
|
9171
|
+
init_define_import_meta_env();
|
|
9172
|
+
function levenshteinDistance(a, b, cap = 3) {
|
|
8913
9173
|
if (Math.abs(a.length - b.length) > cap) return cap + 1;
|
|
8914
9174
|
const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
8915
9175
|
for (let i = 1; i <= a.length; i++) {
|
|
@@ -8922,8 +9182,17 @@ function levenshtein(a, b, cap = 3) {
|
|
|
8922
9182
|
}
|
|
8923
9183
|
return prev[b.length] ?? cap + 1;
|
|
8924
9184
|
}
|
|
9185
|
+
function suggestPackageNames(query, names) {
|
|
9186
|
+
return [...new Set(names)].map((n) => ({ n, d: levenshteinDistance(query.toLowerCase(), n.toLowerCase()) })).filter((x) => x.d <= 3).sort((a, b) => a.d - b.d).slice(0, 5).map((x) => x.n);
|
|
9187
|
+
}
|
|
9188
|
+
|
|
9189
|
+
// src/config_commands.ts
|
|
9190
|
+
function saveConfigSafe(cfg) {
|
|
9191
|
+
ensureDirSync(path18.dirname(configPath()));
|
|
9192
|
+
saveConfig(cfg);
|
|
9193
|
+
}
|
|
8925
9194
|
function closestKeys(unknown, known) {
|
|
8926
|
-
return known.map((k) => ({ k, d:
|
|
9195
|
+
return known.map((k) => ({ k, d: levenshteinDistance(unknown, k) })).filter((x) => x.d <= 3).sort((a, b) => a.d - b.d).slice(0, 3).map((x) => x.k);
|
|
8927
9196
|
}
|
|
8928
9197
|
function didYouMeanKeySuffix(unknownKey) {
|
|
8929
9198
|
const knownKeys = flattenConfig(defaultConfig()).map(([k]) => k);
|
|
@@ -11511,11 +11780,12 @@ function openWithinRoot(rootReal, p) {
|
|
|
11511
11780
|
if (!isPathWithinRoot(rootReal, realPath)) return "outside-root";
|
|
11512
11781
|
let realStat;
|
|
11513
11782
|
try {
|
|
11514
|
-
realStat =
|
|
11783
|
+
realStat = statThroughHandle(realPath);
|
|
11515
11784
|
} catch {
|
|
11516
11785
|
return "outside-root";
|
|
11517
11786
|
}
|
|
11518
|
-
|
|
11787
|
+
const fdStat = fs21.fstatSync(fd, { bigint: true });
|
|
11788
|
+
if (realStat.dev !== fdStat.dev || realStat.ino !== fdStat.ino) return "outside-root";
|
|
11519
11789
|
ownershipTransferred = true;
|
|
11520
11790
|
return { fd, stat };
|
|
11521
11791
|
} finally {
|
|
@@ -13522,9 +13792,9 @@ function cmdNoteAdd(file, opts) {
|
|
|
13522
13792
|
const messages = [`No symbol named '${opts.symbol}' is indexed in '${file}'`];
|
|
13523
13793
|
const allNames = symbolNamesInFile(resolvedPath);
|
|
13524
13794
|
const available = rankSimilarNames(allNames, opts.symbol);
|
|
13525
|
-
if (available.length > 0) messages.push(
|
|
13795
|
+
if (available.length > 0) messages.push(...didYouMeanLines(available));
|
|
13526
13796
|
else if (allNames.length > 0) messages.push(`Try: token-goat outline ${file}`);
|
|
13527
|
-
throw new CliError(messages
|
|
13797
|
+
throw new CliError(messages);
|
|
13528
13798
|
}
|
|
13529
13799
|
symbol = opts.symbol;
|
|
13530
13800
|
fingerprint = fingerprintContent(match2.body);
|
|
@@ -13853,9 +14123,9 @@ function cmdInsertSection(file, opts) {
|
|
|
13853
14123
|
const allHeadings = listSections(file);
|
|
13854
14124
|
const messages = [`Section '${opts.after}' not found in '${file}'`];
|
|
13855
14125
|
const available = filterSimilarHeadings(allHeadings, opts.after);
|
|
13856
|
-
if (available.length > 0) messages.push(
|
|
14126
|
+
if (available.length > 0) messages.push(...didYouMeanLines(available));
|
|
13857
14127
|
else if (allHeadings.length > 0) messages.push(`Try: token-goat outline ${file}`);
|
|
13858
|
-
throw new CliError(messages
|
|
14128
|
+
throw new CliError(messages);
|
|
13859
14129
|
}
|
|
13860
14130
|
if (result.occurrences !== void 0) {
|
|
13861
14131
|
const lines = [
|
|
@@ -13867,7 +14137,7 @@ function cmdInsertSection(file, opts) {
|
|
|
13867
14137
|
if (result.occurrences.length > AMBIGUOUS_HEADING_LIMIT) {
|
|
13868
14138
|
lines.push(` (${result.occurrences.length - AMBIGUOUS_HEADING_LIMIT} more not shown)`);
|
|
13869
14139
|
}
|
|
13870
|
-
throw new CliError(lines
|
|
14140
|
+
throw new CliError(lines);
|
|
13871
14141
|
}
|
|
13872
14142
|
let rawBytes;
|
|
13873
14143
|
try {
|
|
@@ -14012,13 +14282,13 @@ function registerFormatCommands(program2, guard) {
|
|
|
14012
14282
|
[]
|
|
14013
14283
|
).option("--head <n>", "limit to the first N matching rows").option("--json", "emit rows as a JSON array of objects instead of CSV").option("--delimiter <char>", "field delimiter (default: ,)").option("--no-header", "treat the first row as data, not a header (columns become col1, col2, ...)").action(guard(cmdCsvQuery));
|
|
14014
14284
|
program2.command("csv-profile <file>").description("per-column type/null/distinct/range summary of a CSV instead of a raw Read").option("--delimiter <char>", "field delimiter (default: ,)").option("--no-header", "treat the first row as data, not a header (columns become col1, col2, ...)").action(guard(cmdCsvProfile));
|
|
14015
|
-
program2.command("json-outline <file>").description("structural summary of a JSON document (array shape / object key types) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").action(guard(cmdJsonOutline));
|
|
14285
|
+
program2.command("json-outline <file>").description("structural summary of a JSON document (array shape / object key types) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").option("--filter <text>", "list only the top-level keys containing TEXT (case-insensitive), with a count of how many matched").action(guard(cmdJsonOutline));
|
|
14016
14286
|
program2.command("json-query <file> <path>").description(
|
|
14017
|
-
|
|
14287
|
+
'extract one value or a projected/filtered subset from a JSON document by dot-path instead of a raw Read\n\npath grammar: dot-separated keys with optional bracket segments -- [n] index, [*] wildcard (projects every element/value), [field=value] filter (keeps array elements whose field stringifies to value), ["key"] for a key holding a dot or space. Examples: data.items[3].name, items[*].id, items[status=active], ["a.b"].c'
|
|
14018
14288
|
).option("--head <n>", "limit a projected/filtered result to the first N items").option("--json", "emit the result as JSON instead of text").action(guard(cmdJsonQuery));
|
|
14019
|
-
program2.command("yaml-outline <file>").description("structural summary of a YAML document (array shape / object key types) instead of a raw Read -- multi-document streams (---separated) outline as an array of documents").option("--json", "emit the outline as JSON instead of text").action(guard(cmdYamlOutline));
|
|
14289
|
+
program2.command("yaml-outline <file>").description("structural summary of a YAML document (array shape / object key types) instead of a raw Read -- multi-document streams (---separated) outline as an array of documents").option("--json", "emit the outline as JSON instead of text").option("--filter <text>", "list only the top-level keys containing TEXT (case-insensitive), with a count of how many matched").action(guard(cmdYamlOutline));
|
|
14020
14290
|
program2.command("yaml-query <file> <path>").description(
|
|
14021
|
-
|
|
14291
|
+
'extract one value or a projected/filtered subset from a YAML document by dot-path instead of a raw Read (same grammar as json-query)\n\npath grammar: dot-separated keys with optional bracket segments -- [n] index, [*] wildcard (projects every element/value), [field=value] filter (keeps array elements whose field stringifies to value), ["key"] for a key holding a dot or space. Examples: spec.containers[0].image, items[*].name, items[kind=Service]'
|
|
14022
14292
|
).option("--head <n>", "limit a projected/filtered result to the first N items").option("--json", "emit the result as JSON instead of text").action(guard(cmdYamlQuery));
|
|
14023
14293
|
program2.command("xml-outline <file>").description("structural summary of an XML document (element hierarchy / attribute names / child counts) instead of a raw Read").option("--json", "emit the outline as JSON instead of text").option("--max-depth <n>", "max depth of element hierarchy to show").option("--depth <n>", "alias for --max-depth").action(guard(cmdXmlOutline));
|
|
14024
14294
|
program2.command("xml-query <file> [path]").description(
|
|
@@ -14383,184 +14653,44 @@ function runAffected(opts) {
|
|
|
14383
14653
|
|
|
14384
14654
|
// src/text_commands.ts
|
|
14385
14655
|
init_define_import_meta_env();
|
|
14386
|
-
import * as
|
|
14387
|
-
import * as
|
|
14656
|
+
import * as fs31 from "fs";
|
|
14657
|
+
import * as path28 from "path";
|
|
14388
14658
|
|
|
14389
|
-
// src/
|
|
14659
|
+
// src/text_todo.ts
|
|
14390
14660
|
init_define_import_meta_env();
|
|
14391
|
-
import * as fs28 from "
|
|
14392
|
-
import * as path26 from "
|
|
14393
|
-
var
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
14397
|
-
}
|
|
14398
|
-
function memoryPath(projectHash) {
|
|
14399
|
-
return path26.join(dataDir(), "projects", `${projectHash}_memory.toml`);
|
|
14400
|
-
}
|
|
14401
|
-
function validateKey2(key) {
|
|
14402
|
-
if (!KEY_RE2.test(key)) {
|
|
14403
|
-
throw new Error(
|
|
14404
|
-
`Invalid memory key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
|
|
14405
|
-
);
|
|
14406
|
-
}
|
|
14661
|
+
import * as fs28 from "fs";
|
|
14662
|
+
import * as path26 from "path";
|
|
14663
|
+
var DEFAULT_KINDS = ["TODO", "FIXME", "HACK", "XXX", "NOTE"];
|
|
14664
|
+
function splitLines(text) {
|
|
14665
|
+
return text.split(/\r?\n/);
|
|
14407
14666
|
}
|
|
14408
|
-
function
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
if (
|
|
14667
|
+
function countUnescapedQuotes(text, quoteChar) {
|
|
14668
|
+
let count = 0;
|
|
14669
|
+
let backslashes = 0;
|
|
14670
|
+
for (const ch of text) {
|
|
14671
|
+
if (ch === "\\") {
|
|
14672
|
+
backslashes++;
|
|
14413
14673
|
continue;
|
|
14414
14674
|
}
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
const [, key, value] = match2;
|
|
14418
|
-
if (key && value !== void 0) {
|
|
14419
|
-
const unescaped = value.replace(/\\([\\nrt"])/g, (_, c) => {
|
|
14420
|
-
switch (c) {
|
|
14421
|
-
case "\\":
|
|
14422
|
-
return "\\";
|
|
14423
|
-
case "n":
|
|
14424
|
-
return "\n";
|
|
14425
|
-
case "r":
|
|
14426
|
-
return "\r";
|
|
14427
|
-
case '"':
|
|
14428
|
-
return '"';
|
|
14429
|
-
default:
|
|
14430
|
-
return _;
|
|
14431
|
-
}
|
|
14432
|
-
});
|
|
14433
|
-
result[key] = unescaped;
|
|
14434
|
-
}
|
|
14435
|
-
}
|
|
14675
|
+
if (ch === quoteChar && backslashes % 2 === 0) count++;
|
|
14676
|
+
backslashes = 0;
|
|
14436
14677
|
}
|
|
14437
|
-
return
|
|
14678
|
+
return count;
|
|
14679
|
+
}
|
|
14680
|
+
function isInsideStringLiteral2(line, markerIndex) {
|
|
14681
|
+
const before = line.slice(0, markerIndex);
|
|
14682
|
+
const dqCount = countUnescapedQuotes(before, '"');
|
|
14683
|
+
return dqCount % 2 !== 0;
|
|
14438
14684
|
}
|
|
14439
|
-
function
|
|
14685
|
+
function isMarkerOccurrence(matched, hasColon) {
|
|
14686
|
+
return hasColon || matched === matched.toUpperCase();
|
|
14687
|
+
}
|
|
14688
|
+
function scanFileForTodos(filePath, kindSet) {
|
|
14689
|
+
let text;
|
|
14440
14690
|
try {
|
|
14441
|
-
|
|
14442
|
-
return {};
|
|
14443
|
-
}
|
|
14444
|
-
const content = fs28.readFileSync(filePath, "utf-8");
|
|
14445
|
-
return parseTOML(content);
|
|
14691
|
+
text = decodeSource(fs28.readFileSync(filePath));
|
|
14446
14692
|
} catch {
|
|
14447
|
-
return
|
|
14448
|
-
}
|
|
14449
|
-
}
|
|
14450
|
-
function save(filePath, entries) {
|
|
14451
|
-
const lines = [];
|
|
14452
|
-
const sorted = Object.entries(entries).sort(([a], [b]) => ordinal(a, b));
|
|
14453
|
-
for (const [k, v] of sorted) {
|
|
14454
|
-
const escaped = v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
14455
|
-
lines.push(`${k} = "${escaped}"`);
|
|
14456
|
-
}
|
|
14457
|
-
const content = lines.length > 0 ? lines.join("\n") + "\n" : "";
|
|
14458
|
-
const dir = path26.dirname(filePath);
|
|
14459
|
-
ensureDirSync(dir);
|
|
14460
|
-
atomicWriteText(filePath, content);
|
|
14461
|
-
}
|
|
14462
|
-
function loadEntries(projectHash) {
|
|
14463
|
-
return loadRaw(memoryPath(projectHash));
|
|
14464
|
-
}
|
|
14465
|
-
function setEntry(projectHash, key, value) {
|
|
14466
|
-
validateKey2(key);
|
|
14467
|
-
const p = memoryPath(projectHash);
|
|
14468
|
-
const dir = path26.dirname(p);
|
|
14469
|
-
ensureDirSync(dir);
|
|
14470
|
-
const doSet = () => {
|
|
14471
|
-
const entries = loadRaw(p);
|
|
14472
|
-
const isNewKey = !(key in entries);
|
|
14473
|
-
if (isNewKey && Object.keys(entries).length >= MAX_ENTRIES) {
|
|
14474
|
-
const keysToKeep = MAX_ENTRIES - 1;
|
|
14475
|
-
const allKeys = Object.keys(entries).sort((a, b) => ordinal(a, b));
|
|
14476
|
-
for (const k of allKeys.slice(keysToKeep)) {
|
|
14477
|
-
delete entries[k];
|
|
14478
|
-
}
|
|
14479
|
-
}
|
|
14480
|
-
entries[key] = value;
|
|
14481
|
-
save(p, entries);
|
|
14482
|
-
return true;
|
|
14483
|
-
};
|
|
14484
|
-
if (withFileLock(`${p}.lock`, doSet) === void 0) doSet();
|
|
14485
|
-
}
|
|
14486
|
-
function unsetEntry(projectHash, key) {
|
|
14487
|
-
validateKey2(key);
|
|
14488
|
-
const p = memoryPath(projectHash);
|
|
14489
|
-
const doUnset = () => {
|
|
14490
|
-
const entries = loadRaw(p);
|
|
14491
|
-
if (key in entries) {
|
|
14492
|
-
delete entries[key];
|
|
14493
|
-
save(p, entries);
|
|
14494
|
-
}
|
|
14495
|
-
return true;
|
|
14496
|
-
};
|
|
14497
|
-
if (withFileLock(`${p}.lock`, doUnset) === void 0) doUnset();
|
|
14498
|
-
}
|
|
14499
|
-
function clearAll(projectHash) {
|
|
14500
|
-
const p = memoryPath(projectHash);
|
|
14501
|
-
const doClear = () => {
|
|
14502
|
-
if (fs28.existsSync(p)) {
|
|
14503
|
-
save(p, {});
|
|
14504
|
-
}
|
|
14505
|
-
return true;
|
|
14506
|
-
};
|
|
14507
|
-
if (withFileLock(`${p}.lock`, doClear) === void 0) doClear();
|
|
14508
|
-
}
|
|
14509
|
-
|
|
14510
|
-
// src/util_suggest.ts
|
|
14511
|
-
init_define_import_meta_env();
|
|
14512
|
-
function packageNameDistance(a, b, cap = 3) {
|
|
14513
|
-
if (Math.abs(a.length - b.length) > cap) return cap + 1;
|
|
14514
|
-
const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
14515
|
-
for (let i = 1; i <= a.length; i++) {
|
|
14516
|
-
const curr = [i];
|
|
14517
|
-
for (let j = 1; j <= b.length; j++) {
|
|
14518
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
14519
|
-
curr.push(Math.min((curr[j - 1] ?? 0) + 1, (prev[j] ?? 0) + 1, (prev[j - 1] ?? 0) + cost));
|
|
14520
|
-
}
|
|
14521
|
-
prev.splice(0, prev.length, ...curr);
|
|
14522
|
-
}
|
|
14523
|
-
return prev[b.length] ?? cap + 1;
|
|
14524
|
-
}
|
|
14525
|
-
function suggestPackageNames(query, names) {
|
|
14526
|
-
return [...new Set(names)].map((n) => ({ n, d: packageNameDistance(query.toLowerCase(), n.toLowerCase()) })).filter((x) => x.d <= 3).sort((a, b) => a.d - b.d).slice(0, 5).map((x) => x.n);
|
|
14527
|
-
}
|
|
14528
|
-
|
|
14529
|
-
// src/text_todo.ts
|
|
14530
|
-
init_define_import_meta_env();
|
|
14531
|
-
import * as fs29 from "fs";
|
|
14532
|
-
import * as path27 from "path";
|
|
14533
|
-
var DEFAULT_KINDS = ["TODO", "FIXME", "HACK", "XXX", "NOTE"];
|
|
14534
|
-
function splitLines(text) {
|
|
14535
|
-
return text.split(/\r?\n/);
|
|
14536
|
-
}
|
|
14537
|
-
function countUnescapedQuotes(text, quoteChar) {
|
|
14538
|
-
let count = 0;
|
|
14539
|
-
let backslashes = 0;
|
|
14540
|
-
for (const ch of text) {
|
|
14541
|
-
if (ch === "\\") {
|
|
14542
|
-
backslashes++;
|
|
14543
|
-
continue;
|
|
14544
|
-
}
|
|
14545
|
-
if (ch === quoteChar && backslashes % 2 === 0) count++;
|
|
14546
|
-
backslashes = 0;
|
|
14547
|
-
}
|
|
14548
|
-
return count;
|
|
14549
|
-
}
|
|
14550
|
-
function isInsideStringLiteral2(line, markerIndex) {
|
|
14551
|
-
const before = line.slice(0, markerIndex);
|
|
14552
|
-
const dqCount = countUnescapedQuotes(before, '"');
|
|
14553
|
-
return dqCount % 2 !== 0;
|
|
14554
|
-
}
|
|
14555
|
-
function isMarkerOccurrence(matched, hasColon) {
|
|
14556
|
-
return hasColon || matched === matched.toUpperCase();
|
|
14557
|
-
}
|
|
14558
|
-
function scanFileForTodos(filePath, kindSet) {
|
|
14559
|
-
let text;
|
|
14560
|
-
try {
|
|
14561
|
-
text = decodeSource(fs29.readFileSync(filePath));
|
|
14562
|
-
} catch {
|
|
14563
|
-
return [];
|
|
14693
|
+
return [];
|
|
14564
14694
|
}
|
|
14565
14695
|
const kindPattern = [...kindSet].map(escapeRegExp).join("|");
|
|
14566
14696
|
const re = new RegExp(`\\b(${kindPattern})\\b(\\s*:)?\\s*(.*)`, "gi");
|
|
@@ -14586,9 +14716,9 @@ function collectTodoFiles(patterns) {
|
|
|
14586
14716
|
if (patterns.length > 0) {
|
|
14587
14717
|
const results = [];
|
|
14588
14718
|
for (const p of patterns) {
|
|
14589
|
-
const abs =
|
|
14719
|
+
const abs = path26.resolve(p);
|
|
14590
14720
|
try {
|
|
14591
|
-
const stat =
|
|
14721
|
+
const stat = fs28.statSync(abs);
|
|
14592
14722
|
if (stat.isDirectory()) {
|
|
14593
14723
|
pushAll(results, walkProject(abs).files);
|
|
14594
14724
|
} else {
|
|
@@ -14653,11 +14783,11 @@ function cmdTodo(patterns, opts) {
|
|
|
14653
14783
|
|
|
14654
14784
|
// src/text_trace.ts
|
|
14655
14785
|
init_define_import_meta_env();
|
|
14656
|
-
import * as
|
|
14657
|
-
import * as
|
|
14786
|
+
import * as fs29 from "fs";
|
|
14787
|
+
import * as path27 from "path";
|
|
14658
14788
|
function readInput(src) {
|
|
14659
|
-
if (src !== void 0) return
|
|
14660
|
-
return
|
|
14789
|
+
if (src !== void 0) return fs29.readFileSync(src, "utf8");
|
|
14790
|
+
return fs29.readFileSync(0, "utf8");
|
|
14661
14791
|
}
|
|
14662
14792
|
function splitLines2(text) {
|
|
14663
14793
|
return text.split(/\r?\n/);
|
|
@@ -14869,7 +14999,7 @@ function isProjectFrame(framePath, cwd) {
|
|
|
14869
14999
|
if (framePath.includes("/rustc/")) return false;
|
|
14870
15000
|
if (framePath.includes(".cargo/registry") || framePath.includes(".cargo\\registry")) return false;
|
|
14871
15001
|
if (/^<.+>$/.test(framePath)) return false;
|
|
14872
|
-
if (!
|
|
15002
|
+
if (!path27.isAbsolute(framePath) && !framePath.startsWith("..")) return true;
|
|
14873
15003
|
return false;
|
|
14874
15004
|
}
|
|
14875
15005
|
function resolveFrameSymbol(frame, projectRoot) {
|
|
@@ -14977,7 +15107,7 @@ function cmdTrace(src, opts) {
|
|
|
14977
15107
|
|
|
14978
15108
|
// src/text_logfold.ts
|
|
14979
15109
|
init_define_import_meta_env();
|
|
14980
|
-
import * as
|
|
15110
|
+
import * as fs30 from "fs";
|
|
14981
15111
|
|
|
14982
15112
|
// src/filters.ts
|
|
14983
15113
|
init_define_import_meta_env();
|
|
@@ -15107,8 +15237,8 @@ function applyFiltersAndFold(lines, noNormalize, foldRepeats) {
|
|
|
15107
15237
|
return folded;
|
|
15108
15238
|
}
|
|
15109
15239
|
function readInput2(src) {
|
|
15110
|
-
if (src !== void 0) return
|
|
15111
|
-
return
|
|
15240
|
+
if (src !== void 0) return fs30.readFileSync(src, "utf8");
|
|
15241
|
+
return fs30.readFileSync(0, "utf8");
|
|
15112
15242
|
}
|
|
15113
15243
|
function splitLines3(text) {
|
|
15114
15244
|
return text.split(/\r?\n/);
|
|
@@ -15159,21 +15289,21 @@ var LOCK_PRIORITY = [
|
|
|
15159
15289
|
"Cargo.lock"
|
|
15160
15290
|
];
|
|
15161
15291
|
function findLockfile(startPath) {
|
|
15162
|
-
const stat =
|
|
15292
|
+
const stat = fs31.statSync(startPath, { throwIfNoEntry: false });
|
|
15163
15293
|
if (stat !== void 0 && stat.isFile()) {
|
|
15164
15294
|
return { file: startPath, others: [] };
|
|
15165
15295
|
}
|
|
15166
|
-
const dir = stat !== void 0 && stat.isDirectory() ? startPath :
|
|
15296
|
+
const dir = stat !== void 0 && stat.isDirectory() ? startPath : path28.dirname(startPath);
|
|
15167
15297
|
const found = [];
|
|
15168
15298
|
for (const name of LOCK_PRIORITY) {
|
|
15169
|
-
const candidate =
|
|
15170
|
-
if (
|
|
15299
|
+
const candidate = path28.join(dir, name);
|
|
15300
|
+
if (fs31.existsSync(candidate)) found.push(candidate);
|
|
15171
15301
|
}
|
|
15172
15302
|
try {
|
|
15173
|
-
const entries =
|
|
15303
|
+
const entries = fs31.readdirSync(dir);
|
|
15174
15304
|
for (const e of entries) {
|
|
15175
15305
|
if (/^requirements.*\.txt$/.test(e)) {
|
|
15176
|
-
const p =
|
|
15306
|
+
const p = path28.join(dir, e);
|
|
15177
15307
|
if (!found.includes(p)) found.push(p);
|
|
15178
15308
|
}
|
|
15179
15309
|
}
|
|
@@ -15370,8 +15500,8 @@ function parsePnpmLock(content) {
|
|
|
15370
15500
|
return deps;
|
|
15371
15501
|
}
|
|
15372
15502
|
function parseLockFile(filePath) {
|
|
15373
|
-
const base =
|
|
15374
|
-
const content =
|
|
15503
|
+
const base = path28.basename(filePath);
|
|
15504
|
+
const content = fs31.readFileSync(filePath, "utf8");
|
|
15375
15505
|
if (base === "package-lock.json") return { format: "npm", deps: parsePackageLockJson(content) };
|
|
15376
15506
|
if (base === "yarn.lock") return { format: "yarn", deps: parseYarnLock(content) };
|
|
15377
15507
|
if (base === "pnpm-lock.yaml") return { format: "pnpm", deps: parsePnpmLock(content) };
|
|
@@ -15444,7 +15574,7 @@ function cmdLockdepsPackage(lockfile, format, deps, query, json) {
|
|
|
15444
15574
|
}
|
|
15445
15575
|
const primary = matches2.find((d) => d.kind === "direct") ?? matches2[0];
|
|
15446
15576
|
const otherVersions = [...new Set(matches2.filter((d) => d.version !== primary.version).map((d) => d.version))];
|
|
15447
|
-
const graph = format === "npm" ? buildNpmEdges(
|
|
15577
|
+
const graph = format === "npm" ? buildNpmEdges(fs31.readFileSync(lockfile, "utf8")) : null;
|
|
15448
15578
|
const graphAvailable = graph !== null;
|
|
15449
15579
|
const dependsOn = graph !== null ? [...graph.edges.get(query) ?? []].sort() : [];
|
|
15450
15580
|
const dependedOnBy = graph !== null ? findReverseDirectDeps(query, graph.edges, graph.directNames) : [];
|
|
@@ -15484,7 +15614,7 @@ Depended on by direct/top-level deps (${dependedOnBy.length}):
|
|
|
15484
15614
|
`);
|
|
15485
15615
|
}
|
|
15486
15616
|
function cmdLockdeps(filePath, opts) {
|
|
15487
|
-
const target = filePath !== void 0 ?
|
|
15617
|
+
const target = filePath !== void 0 ? path28.resolve(filePath) : process.cwd();
|
|
15488
15618
|
const found = findLockfile(target);
|
|
15489
15619
|
if (found === null) {
|
|
15490
15620
|
throw new Error("No lockfile found. Expected one of: " + LOCK_PRIORITY.join(", ") + ", requirements*.txt");
|
|
@@ -15572,20 +15702,20 @@ function cmdNote(action, key, value, opts) {
|
|
|
15572
15702
|
throw new Error(`Unknown note action: ${action}. Use: set, get, unset, list, clear`);
|
|
15573
15703
|
}
|
|
15574
15704
|
function loadAllSessionReadCounts() {
|
|
15575
|
-
const sessionsDir2 =
|
|
15705
|
+
const sessionsDir2 = path28.join(tokenGoatHome(), "sessions");
|
|
15576
15706
|
const totals = /* @__PURE__ */ new Map();
|
|
15577
15707
|
let entries;
|
|
15578
15708
|
try {
|
|
15579
|
-
entries =
|
|
15709
|
+
entries = fs31.readdirSync(sessionsDir2, { withFileTypes: true });
|
|
15580
15710
|
} catch {
|
|
15581
15711
|
return totals;
|
|
15582
15712
|
}
|
|
15583
15713
|
for (const entry of entries) {
|
|
15584
15714
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
15585
|
-
const filePath =
|
|
15715
|
+
const filePath = path28.join(sessionsDir2, entry.name);
|
|
15586
15716
|
let raw;
|
|
15587
15717
|
try {
|
|
15588
|
-
raw = JSON.parse(
|
|
15718
|
+
raw = JSON.parse(fs31.readFileSync(filePath, "utf8"));
|
|
15589
15719
|
} catch {
|
|
15590
15720
|
continue;
|
|
15591
15721
|
}
|
|
@@ -15718,7 +15848,7 @@ function cmdIgnores(opts) {
|
|
|
15718
15848
|
}
|
|
15719
15849
|
function countPackIgnorePatterns(root) {
|
|
15720
15850
|
try {
|
|
15721
|
-
return
|
|
15851
|
+
return fs31.readFileSync(path28.join(root, ".tokengoatignore"), "utf8").split("\n").map((ln) => ln.trim()).filter((ln) => ln.length > 0 && !ln.startsWith("#")).length;
|
|
15722
15852
|
} catch {
|
|
15723
15853
|
return 0;
|
|
15724
15854
|
}
|
|
@@ -15727,8 +15857,8 @@ function countPackIgnorePatterns(root) {
|
|
|
15727
15857
|
// src/dep_docs.ts
|
|
15728
15858
|
init_define_import_meta_env();
|
|
15729
15859
|
import { createRequire } from "node:module";
|
|
15730
|
-
import * as
|
|
15731
|
-
import * as
|
|
15860
|
+
import * as fs32 from "node:fs";
|
|
15861
|
+
import * as path29 from "node:path";
|
|
15732
15862
|
var _require = createRequire(import.meta.url);
|
|
15733
15863
|
var _ts = null;
|
|
15734
15864
|
var _tsLoadAttempted = false;
|
|
@@ -15747,21 +15877,21 @@ function loadTs() {
|
|
|
15747
15877
|
}
|
|
15748
15878
|
function dirExists(p) {
|
|
15749
15879
|
try {
|
|
15750
|
-
return
|
|
15880
|
+
return fs32.statSync(p).isDirectory();
|
|
15751
15881
|
} catch {
|
|
15752
15882
|
return false;
|
|
15753
15883
|
}
|
|
15754
15884
|
}
|
|
15755
15885
|
function fileExists(p) {
|
|
15756
15886
|
try {
|
|
15757
|
-
return
|
|
15887
|
+
return fs32.statSync(p).isFile();
|
|
15758
15888
|
} catch {
|
|
15759
15889
|
return false;
|
|
15760
15890
|
}
|
|
15761
15891
|
}
|
|
15762
15892
|
function readFileTextOrNull(p) {
|
|
15763
15893
|
try {
|
|
15764
|
-
return
|
|
15894
|
+
return fs32.readFileSync(p, "utf8");
|
|
15765
15895
|
} catch {
|
|
15766
15896
|
return null;
|
|
15767
15897
|
}
|
|
@@ -15769,7 +15899,7 @@ function readFileTextOrNull(p) {
|
|
|
15769
15899
|
function listInstalledPackageNames(nodeModulesDir) {
|
|
15770
15900
|
let entries;
|
|
15771
15901
|
try {
|
|
15772
|
-
entries =
|
|
15902
|
+
entries = fs32.readdirSync(nodeModulesDir, { withFileTypes: true });
|
|
15773
15903
|
} catch {
|
|
15774
15904
|
return [];
|
|
15775
15905
|
}
|
|
@@ -15779,7 +15909,7 @@ function listInstalledPackageNames(nodeModulesDir) {
|
|
|
15779
15909
|
if (entry.name.startsWith("@")) {
|
|
15780
15910
|
let scoped;
|
|
15781
15911
|
try {
|
|
15782
|
-
scoped =
|
|
15912
|
+
scoped = fs32.readdirSync(path29.join(nodeModulesDir, entry.name), { withFileTypes: true });
|
|
15783
15913
|
} catch {
|
|
15784
15914
|
continue;
|
|
15785
15915
|
}
|
|
@@ -15796,12 +15926,12 @@ var README_NAME_RE = /^readme(\.(md|markdown|txt))?$/i;
|
|
|
15796
15926
|
function findReadmeFile(pkgDir) {
|
|
15797
15927
|
const direct = findReadmeIn(pkgDir);
|
|
15798
15928
|
if (direct !== null) return direct;
|
|
15799
|
-
return findReadmeIn(
|
|
15929
|
+
return findReadmeIn(path29.join(pkgDir, "docs"));
|
|
15800
15930
|
}
|
|
15801
15931
|
function findReadmeIn(dir) {
|
|
15802
15932
|
let entries;
|
|
15803
15933
|
try {
|
|
15804
|
-
entries =
|
|
15934
|
+
entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
15805
15935
|
} catch {
|
|
15806
15936
|
return null;
|
|
15807
15937
|
}
|
|
@@ -15813,7 +15943,7 @@ function findReadmeIn(dir) {
|
|
|
15813
15943
|
return 1;
|
|
15814
15944
|
};
|
|
15815
15945
|
matches2.sort((a, b) => rank(a.name) - rank(b.name));
|
|
15816
|
-
return
|
|
15946
|
+
return path29.join(dir, matches2[0].name);
|
|
15817
15947
|
}
|
|
15818
15948
|
function typesPackageDirName(pkgName) {
|
|
15819
15949
|
if (pkgName.startsWith("@")) {
|
|
@@ -15840,30 +15970,30 @@ function resolveTypesLocation(pkgDir, pkgJson, nodeModulesDir, pkgName) {
|
|
|
15840
15970
|
if (declared !== void 0) {
|
|
15841
15971
|
const candidates = [declared, declared.endsWith(".d.ts") ? declared : `${declared}.d.ts`, declared.replace(/\.[cm]?[jt]s$/, ".d.ts")];
|
|
15842
15972
|
for (const c of candidates) {
|
|
15843
|
-
const p =
|
|
15973
|
+
const p = path29.join(pkgDir, c);
|
|
15844
15974
|
if (fileExists(p)) return { path: p, source: "bundled" };
|
|
15845
15975
|
}
|
|
15846
15976
|
}
|
|
15847
15977
|
const main = typeof pkgJson["main"] === "string" ? pkgJson["main"] : "index.js";
|
|
15848
|
-
const mainDts =
|
|
15978
|
+
const mainDts = path29.join(pkgDir, main.replace(/\.[cm]?js$/, ".d.ts"));
|
|
15849
15979
|
if (fileExists(mainDts)) return { path: mainDts, source: "bundled" };
|
|
15850
|
-
const indexDts =
|
|
15980
|
+
const indexDts = path29.join(pkgDir, "index.d.ts");
|
|
15851
15981
|
if (fileExists(indexDts)) return { path: indexDts, source: "bundled" };
|
|
15852
15982
|
const typesDirName = typesPackageDirName(pkgName);
|
|
15853
|
-
const typesPkgDir =
|
|
15854
|
-
const typesPkgJsonRaw = readFileTextOrNull(
|
|
15983
|
+
const typesPkgDir = path29.join(nodeModulesDir, "@types", typesDirName);
|
|
15984
|
+
const typesPkgJsonRaw = readFileTextOrNull(path29.join(typesPkgDir, "package.json"));
|
|
15855
15985
|
if (typesPkgJsonRaw !== null) {
|
|
15856
15986
|
try {
|
|
15857
15987
|
const typesPkgJson = JSON.parse(typesPkgJsonRaw);
|
|
15858
15988
|
const entry = (typeof typesPkgJson["types"] === "string" ? typesPkgJson["types"] : void 0) ?? (typeof typesPkgJson["main"] === "string" ? typesPkgJson["main"] : void 0) ?? "index.d.ts";
|
|
15859
15989
|
const entryCandidates = [entry, entry.endsWith(".d.ts") ? entry : `${entry}.d.ts`, entry.replace(/\.[cm]?[jt]s$/, ".d.ts")];
|
|
15860
15990
|
for (const c of entryCandidates) {
|
|
15861
|
-
const entryPath =
|
|
15991
|
+
const entryPath = path29.join(typesPkgDir, c);
|
|
15862
15992
|
if (fileExists(entryPath)) return { path: entryPath, source: "@types" };
|
|
15863
15993
|
}
|
|
15864
15994
|
} catch {
|
|
15865
15995
|
}
|
|
15866
|
-
const fallback =
|
|
15996
|
+
const fallback = path29.join(typesPkgDir, "index.d.ts");
|
|
15867
15997
|
if (fileExists(fallback)) return { path: fallback, source: "@types" };
|
|
15868
15998
|
}
|
|
15869
15999
|
return null;
|
|
@@ -15930,16 +16060,16 @@ function recordDepDocsStat(fullSourceBytes, emittedText, packageName) {
|
|
|
15930
16060
|
}
|
|
15931
16061
|
function runDepDocs(opts) {
|
|
15932
16062
|
const root = resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() });
|
|
15933
|
-
const nodeModulesDir =
|
|
15934
|
-
const pkgDir =
|
|
15935
|
-
const pkgJsonPath =
|
|
16063
|
+
const nodeModulesDir = path29.join(root, "node_modules");
|
|
16064
|
+
const pkgDir = path29.join(nodeModulesDir, opts.packageName);
|
|
16065
|
+
const pkgJsonPath = path29.join(pkgDir, "package.json");
|
|
15936
16066
|
if (!dirExists(pkgDir) || !fileExists(pkgJsonPath)) {
|
|
15937
16067
|
const known = listInstalledPackageNames(nodeModulesDir);
|
|
15938
16068
|
const suggestions = suggestPackageNames(opts.packageName, known);
|
|
15939
16069
|
const hint = suggestions.length > 0 ? ` (did you mean: ${suggestions.map(displaySafeText).join(", ")}?)` : "";
|
|
15940
16070
|
return { text: `Package '${displaySafeText(opts.packageName)}' not found under ${displaySafeText(nodeModulesDir)}${hint}`, code: 1 };
|
|
15941
16071
|
}
|
|
15942
|
-
const pkgJsonRaw =
|
|
16072
|
+
const pkgJsonRaw = fs32.readFileSync(pkgJsonPath, "utf8");
|
|
15943
16073
|
let pkgJson;
|
|
15944
16074
|
try {
|
|
15945
16075
|
pkgJson = JSON.parse(pkgJsonRaw);
|
|
@@ -16315,8 +16445,7 @@ function collectCapabilities(config = loadConfig()) {
|
|
|
16315
16445
|
id: "at_rest.symbol_index",
|
|
16316
16446
|
kind: "at-rest",
|
|
16317
16447
|
what: "Stores the text of indexed source files in a local database, so a symbol can be returned without re-reading the file.",
|
|
16318
|
-
// Always on: it is the product. Reported anyway, because a reviewer deciding about data at
|
|
16319
|
-
// rest needs the always-on items more than the optional ones.
|
|
16448
|
+
// Always on: it is the product. Reported anyway, because a reviewer deciding about data at rest needs the always-on items more than the optional ones.
|
|
16320
16449
|
enabled: true,
|
|
16321
16450
|
controlledBy: "always on (this is what the tool does)",
|
|
16322
16451
|
enforcedAt: "src/db.ts"
|
|
@@ -16328,15 +16457,24 @@ function collectCapabilities(config = loadConfig()) {
|
|
|
16328
16457
|
enabled: true,
|
|
16329
16458
|
controlledBy: "always on, 24-hour expiry",
|
|
16330
16459
|
enforcedAt: "src/disk_cache.ts"
|
|
16460
|
+
},
|
|
16461
|
+
{
|
|
16462
|
+
id: "ipc.hook_server",
|
|
16463
|
+
kind: "local-ipc",
|
|
16464
|
+
what: "Keeps up to three hook servers running between hook calls, each on a named pipe (Windows) or Unix socket (elsewhere) that answers only a caller holding the key file in the data directory.",
|
|
16465
|
+
// Read the way the server reads it, which a project's config cannot change.
|
|
16466
|
+
enabled: hookServerEnabled(),
|
|
16467
|
+
controlledBy: "hooks.server (global config only), TOKEN_GOAT_HOOK_SERVER",
|
|
16468
|
+
enforcedAt: "src/hook_server.ts::runHookServer"
|
|
16331
16469
|
}
|
|
16332
16470
|
];
|
|
16333
16471
|
}
|
|
16334
16472
|
function renderCapabilities(caps) {
|
|
16335
16473
|
const lines = [];
|
|
16336
|
-
for (const kind of ["egress", "at-rest"]) {
|
|
16474
|
+
for (const [kind, heading] of [["egress", "Can send data off this machine:"], ["at-rest", "Leaves data on this machine:"], ["local-ipc", "Listens for other processes on this machine:"]]) {
|
|
16337
16475
|
const group = caps.filter((c) => c.kind === kind);
|
|
16338
16476
|
if (group.length === 0) continue;
|
|
16339
|
-
lines.push(
|
|
16477
|
+
lines.push(heading);
|
|
16340
16478
|
for (const c of group) {
|
|
16341
16479
|
lines.push(` [${c.enabled ? "ON " : "OFF"}] ${displaySafeText(c.id)}`);
|
|
16342
16480
|
lines.push(` ${c.what}`);
|
|
@@ -16352,13 +16490,13 @@ function renderCapabilities(caps) {
|
|
|
16352
16490
|
|
|
16353
16491
|
// src/cli_session.ts
|
|
16354
16492
|
init_define_import_meta_env();
|
|
16355
|
-
import * as
|
|
16493
|
+
import * as fs39 from "node:fs";
|
|
16356
16494
|
|
|
16357
16495
|
// src/session_audit.ts
|
|
16358
16496
|
init_define_import_meta_env();
|
|
16359
|
-
import * as
|
|
16497
|
+
import * as fs33 from "node:fs";
|
|
16360
16498
|
import * as os16 from "node:os";
|
|
16361
|
-
import * as
|
|
16499
|
+
import * as path30 from "node:path";
|
|
16362
16500
|
import * as readline from "node:readline";
|
|
16363
16501
|
var MODEL_VISIBLE_CATEGORIES = ["toolResults", "assistantText", "assistantThinking", "toolUseInputs", "attachments", "userTurns", "harnessMeta", "system"];
|
|
16364
16502
|
function computeCalibration(estimated, measured) {
|
|
@@ -16419,10 +16557,13 @@ var ATTACHMENT_VISIBLE_FIELDS = {
|
|
|
16419
16557
|
};
|
|
16420
16558
|
var CACHE_WRITE_MULTIPLIER = 1.25;
|
|
16421
16559
|
var CACHE_READ_MULTIPLIER = 0.1;
|
|
16422
|
-
var READ_DIVERT_MARKER_RE = /(?:was already read this session|Already read |You've already read|Use `token-goat (?:section|read|bash-output|config-get|skeleton)|token-goat bash-output --file)/;
|
|
16560
|
+
var READ_DIVERT_MARKER_RE = /(?:was already read this session|Already read |You've already read|(?:Use|Run) `token-goat (?:section|read|bash-output|config-get|skeleton|json-query|yaml-query)|token-goat bash-output --file)/;
|
|
16423
16561
|
var READ_DIVERT_MAX_BYTES = 2500;
|
|
16424
16562
|
var READ_FULL_SERVE_MIN_BYTES = 10240;
|
|
16425
16563
|
var DENY_TEMPLATES = [
|
|
16564
|
+
// hint_target.ts's sharpenRepeatedDeny replaces a verbatim repeat of any deny with this one line, so the kind the first copy had is not recoverable from the second.
|
|
16565
|
+
{ kind: "repeat_refusal_deny", re: /Repeat refusal of this exact call/, tool: "Read" },
|
|
16566
|
+
{ kind: "skill_repeat_refusal_deny", re: /Repeat refusal of this exact call/, tool: "Skill" },
|
|
16426
16567
|
{ kind: "node_modules_deny", re: /node_modules is typically noise/, tool: "Read" },
|
|
16427
16568
|
{ kind: "lock_file_deny", re: /Lock files are rarely useful to read in full/, tool: "Read" },
|
|
16428
16569
|
{ kind: "tsbuildinfo_deny", re: /TypeScript incremental build cache file/, tool: "Read" },
|
|
@@ -16432,13 +16573,7 @@ var DENY_TEMPLATES = [
|
|
|
16432
16573
|
// Must stay ABOVE markdown_heading_tree_deny: this deny's message embeds the same "Large markdown file (N headings)" guidance block, so the generic alternative would swallow it and the new intervention would be uncountable. DENY_TEMPLATES is scanned with `.find`, so the more specific wording has to come first.
|
|
16433
16574
|
{ kind: "subagent_markdown_first_read_deny", re: /Subagent first read of a large markdown file/, tool: "Read" },
|
|
16434
16575
|
{ kind: "markdown_heading_tree_deny", re: /Large markdown file \(\d+ headings\)/, tool: "Read" },
|
|
16435
|
-
// The first alternative is a wording hooks_read.ts no longer emits (it claimed a compact-manifest
|
|
16436
|
-
// section that never existed, reworded in 3d044feb). It stays because this table classifies a
|
|
16437
|
-
// historical corpus, not just today's output: transcripts written before the rewording still
|
|
16438
|
-
// carry the old text, and dropping the alternative silently shrank this kind from 51 events to
|
|
16439
|
-
// 30 -- 41% of its history -- with a green suite. A superseded alternative is only removable
|
|
16440
|
-
// once no transcript contains it, which source code cannot tell you. See the superseded-wording
|
|
16441
|
-
// test in tests/deny_outcomes.test.ts.
|
|
16576
|
+
// The first alternative is a wording hooks_read.ts no longer emits (it claimed a compact-manifest section that never existed, reworded in 3d044feb). It stays because this table classifies a historical corpus, not just today's output: transcripts written before the rewording still carry the old text, and dropping the alternative silently shrank this kind from 51 events to 30 -- 41% of its history -- with a green suite. A superseded alternative is only removable once no transcript contains it, which source code cannot tell you. See the superseded-wording test in tests/deny_outcomes.test.ts.
|
|
16442
16577
|
{ kind: "memory_md_reread_deny", re: /MEMORY\.md was read this session\. Its content is in the compact manifest|already read this session\. Memory files rarely change mid-session/, tool: "Read" },
|
|
16443
16578
|
{ kind: "improve_state_reread_deny", re: /Orchestrator state already read this session/, tool: "Read" },
|
|
16444
16579
|
{ kind: "env_reread_deny", re: /Environment files rarely change mid-session/, tool: "Read" },
|
|
@@ -16448,12 +16583,12 @@ var DENY_TEMPLATES = [
|
|
|
16448
16583
|
{ kind: "session_artifact_large_deny", re: /(?:Session transcript|Tool-result file) is large \(/, tool: "Read" },
|
|
16449
16584
|
{ kind: "session_artifact_generic_reread_deny", re: /already read this session\. Use `token-goat bash-output --file/, tool: "Read" },
|
|
16450
16585
|
{ kind: "truncated_read_deny", re: /File was truncated on last read \(>33K tokens\)/, tool: "Read" },
|
|
16451
|
-
{ kind: "doc_unchanged_deny", re: /is unchanged since last read\. Use `token-goat (?:section|read)/, tool: "Read" },
|
|
16452
|
-
{ kind: "doc_diff_deny", re: /Content changed since last read of [\s\S]*?Use `token-goat (?:section|read)/, tool: "Read" },
|
|
16586
|
+
{ kind: "doc_unchanged_deny", re: /is unchanged since last read\. (?:Use|Run) `token-goat (?:section|read|skeleton|json-query|yaml-query)/, tool: "Read" },
|
|
16587
|
+
{ kind: "doc_diff_deny", re: /Content changed since last read of [\s\S]*?(?:Use|Run) `token-goat (?:section|read|skeleton|json-query|yaml-query)/, tool: "Read" },
|
|
16453
16588
|
{ kind: "read_served_deny", re: /was already served in this session, byte for byte/, tool: "Read" },
|
|
16454
16589
|
// Its own kind rather than folded into read_served_deny above, whose stat name this branch shares: the wording is disjoint (a span, not a byte-for-byte whole serve) and so is the follow-up it invites, since the model still needs part of that span and has to choose a narrower call rather than recall the whole result.
|
|
16455
16590
|
{ kind: "range_reread_deny", re: /Lines \d+\.\.\d+ of [\s\S]*?was already read this session/, tool: "Read" },
|
|
16456
|
-
{ kind: "markdown_already_read_deny", re: /Markdown file already read this session
|
|
16591
|
+
{ kind: "markdown_already_read_deny", re: /Markdown file already read this session\./, tool: "Read" },
|
|
16457
16592
|
{ kind: "read_count_deny", re: /(?:Read|Tried to read) this file \d+ times already/, tool: "Read" },
|
|
16458
16593
|
// Shares read_count_deny's stat name and matches none of its wording: this branch fires on the SHAPE of the reads (consecutive line windows walking one file) rather than on their count, and says so.
|
|
16459
16594
|
{ kind: "sequential_paging_deny", re: /Sequential line-range paging detected on /, tool: "Read" },
|
|
@@ -16543,9 +16678,9 @@ function toolResultText(content) {
|
|
|
16543
16678
|
return "";
|
|
16544
16679
|
}
|
|
16545
16680
|
function listCorpusTranscripts(corpusDir) {
|
|
16546
|
-
if (!
|
|
16681
|
+
if (!fs33.existsSync(corpusDir)) return [];
|
|
16547
16682
|
try {
|
|
16548
|
-
const stat =
|
|
16683
|
+
const stat = fs33.statSync(corpusDir);
|
|
16549
16684
|
if (stat.isFile()) {
|
|
16550
16685
|
return corpusDir.endsWith(".jsonl") ? [corpusDir] : [];
|
|
16551
16686
|
}
|
|
@@ -16555,13 +16690,13 @@ function listCorpusTranscripts(corpusDir) {
|
|
|
16555
16690
|
const found = [];
|
|
16556
16691
|
const walk = (dir, entries) => {
|
|
16557
16692
|
for (const entry of entries) {
|
|
16558
|
-
const full =
|
|
16693
|
+
const full = path30.join(dir, entry.name);
|
|
16559
16694
|
if (entry.name.endsWith(".jsonl")) {
|
|
16560
16695
|
found.push(full);
|
|
16561
16696
|
} else if (entry.isDirectory()) {
|
|
16562
16697
|
let inner;
|
|
16563
16698
|
try {
|
|
16564
|
-
inner =
|
|
16699
|
+
inner = fs33.readdirSync(full, { withFileTypes: true });
|
|
16565
16700
|
} catch {
|
|
16566
16701
|
continue;
|
|
16567
16702
|
}
|
|
@@ -16570,31 +16705,41 @@ function listCorpusTranscripts(corpusDir) {
|
|
|
16570
16705
|
}
|
|
16571
16706
|
};
|
|
16572
16707
|
try {
|
|
16573
|
-
walk(corpusDir,
|
|
16708
|
+
walk(corpusDir, fs33.readdirSync(corpusDir, { withFileTypes: true }));
|
|
16574
16709
|
} catch {
|
|
16575
16710
|
}
|
|
16576
16711
|
return found.sort();
|
|
16577
16712
|
}
|
|
16713
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
16714
|
+
function modifiedSince(files, sinceMs) {
|
|
16715
|
+
return files.filter((file) => {
|
|
16716
|
+
try {
|
|
16717
|
+
return fs33.statSync(file).mtimeMs >= sinceMs;
|
|
16718
|
+
} catch {
|
|
16719
|
+
return false;
|
|
16720
|
+
}
|
|
16721
|
+
});
|
|
16722
|
+
}
|
|
16578
16723
|
function defaultCorpusDir() {
|
|
16579
|
-
const claudeDir =
|
|
16580
|
-
if (
|
|
16724
|
+
const claudeDir = path30.join(claudeConfigDir(), "projects");
|
|
16725
|
+
if (fs33.existsSync(claudeDir) && listCorpusTranscripts(claudeDir).length > 0) {
|
|
16581
16726
|
return claudeDir;
|
|
16582
16727
|
}
|
|
16583
16728
|
const home = os16.homedir();
|
|
16584
|
-
const appData = process.env["APPDATA"] ||
|
|
16729
|
+
const appData = process.env["APPDATA"] || path30.join(home, "AppData", "Roaming");
|
|
16585
16730
|
const candidates = [
|
|
16586
16731
|
claudeDir,
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16732
|
+
path30.join(appData, "Code", "User", "workspaceStorage"),
|
|
16733
|
+
path30.join(appData, "Code - Insiders", "User", "workspaceStorage"),
|
|
16734
|
+
path30.join(home, "Library", "Application Support", "Code", "User", "workspaceStorage"),
|
|
16735
|
+
path30.join(home, "Library", "Application Support", "Code - Insiders", "User", "workspaceStorage"),
|
|
16736
|
+
path30.join(home, ".config", "Code", "User", "workspaceStorage"),
|
|
16737
|
+
path30.join(home, ".config", "Code - Insiders", "User", "workspaceStorage"),
|
|
16738
|
+
path30.join(home, ".copilot", "session-state")
|
|
16594
16739
|
];
|
|
16595
16740
|
for (const cand of candidates) {
|
|
16596
16741
|
try {
|
|
16597
|
-
if (
|
|
16742
|
+
if (fs33.existsSync(cand) && listCorpusTranscripts(cand).length > 0) {
|
|
16598
16743
|
return cand;
|
|
16599
16744
|
}
|
|
16600
16745
|
} catch {
|
|
@@ -16602,11 +16747,13 @@ function defaultCorpusDir() {
|
|
|
16602
16747
|
}
|
|
16603
16748
|
return claudeDir;
|
|
16604
16749
|
}
|
|
16605
|
-
async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneObservations, bashHeadMap, denyRows) {
|
|
16750
|
+
async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneObservations, bashHeadMap, denyRows, toolErrorAcc) {
|
|
16606
16751
|
const isLane = filePath.split(/[\\/]/).includes("subagents");
|
|
16607
16752
|
let laneFirstPrefix = null;
|
|
16608
16753
|
let laneBriefBytes = -1;
|
|
16609
16754
|
const toolNameById = /* @__PURE__ */ new Map();
|
|
16755
|
+
const modelById = /* @__PURE__ */ new Map();
|
|
16756
|
+
const bashCommandById = /* @__PURE__ */ new Map();
|
|
16610
16757
|
const bashHeadById = /* @__PURE__ */ new Map();
|
|
16611
16758
|
let pendingBashReread = [];
|
|
16612
16759
|
const readCallById = /* @__PURE__ */ new Map();
|
|
@@ -16645,7 +16792,7 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
|
|
|
16645
16792
|
}
|
|
16646
16793
|
pendingBashReread = keptBash;
|
|
16647
16794
|
};
|
|
16648
|
-
const stream =
|
|
16795
|
+
const stream = fs33.createReadStream(filePath);
|
|
16649
16796
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
16650
16797
|
const streamFailure = new Promise((_, reject) => stream.on("error", reject));
|
|
16651
16798
|
const consume = (async () => {
|
|
@@ -16709,11 +16856,15 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
|
|
|
16709
16856
|
if (!toolNameById.has(block["id"])) {
|
|
16710
16857
|
toolNameById.set(block["id"], name);
|
|
16711
16858
|
toolRollup(toolMap, name).calls += 1;
|
|
16859
|
+
const model = typeof message.model === "string" && message.model !== "" ? message.model : void 0;
|
|
16860
|
+
if (model !== void 0) modelById.set(block["id"], model);
|
|
16861
|
+
toolErrorAcc.countCall(name, model);
|
|
16712
16862
|
const input = block["input"] !== null && typeof block["input"] === "object" ? block["input"] : {};
|
|
16713
16863
|
let readNorm;
|
|
16714
16864
|
let editNorm;
|
|
16715
16865
|
if (name === "Bash" && typeof input["command"] === "string") {
|
|
16716
16866
|
bashHeadById.set(block["id"], commandHead(input["command"]));
|
|
16867
|
+
bashCommandById.set(block["id"], input["command"]);
|
|
16717
16868
|
} else if (name === "Read" && typeof input["file_path"] === "string") {
|
|
16718
16869
|
readNorm = normalizeReadPath(input["file_path"]);
|
|
16719
16870
|
const priorEpoch = readPathEpoch.get(readNorm);
|
|
@@ -16767,9 +16918,17 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
|
|
|
16767
16918
|
const name = toolNameById.get(id) ?? "(unknown)";
|
|
16768
16919
|
addCategory(s.estimated.toolResults, bytes);
|
|
16769
16920
|
const roll = toolRollup(toolMap, name);
|
|
16770
|
-
if (!toolNameById.has(id))
|
|
16921
|
+
if (!toolNameById.has(id)) {
|
|
16922
|
+
roll.calls += 1;
|
|
16923
|
+
toolErrorAcc.countCall(name, void 0);
|
|
16924
|
+
}
|
|
16771
16925
|
roll.resultBytes += bytes;
|
|
16772
16926
|
roll.resultEstTokens += estimateTokensFromLength(bytes);
|
|
16927
|
+
if (block["is_error"] === true) {
|
|
16928
|
+
const denialKind = obj["toolDenialKind"];
|
|
16929
|
+
const command = bashCommandById.get(id);
|
|
16930
|
+
toolErrorAcc.countError(name, modelById.get(id), text, { ...typeof denialKind === "string" ? { denialKind } : {}, ...command !== void 0 ? { command } : {} });
|
|
16931
|
+
}
|
|
16773
16932
|
if (name === "Edit" && block["is_error"] === true) {
|
|
16774
16933
|
s.editErrorBaseline.totalErrors += 1;
|
|
16775
16934
|
editErrorById.set(id, true);
|
|
@@ -16777,13 +16936,13 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
|
|
|
16777
16936
|
if (name === "Read" || name === "Skill") {
|
|
16778
16937
|
const denyTemplate = DENY_TEMPLATES.find((t) => t.tool === name && t.re.test(text));
|
|
16779
16938
|
if (denyTemplate !== void 0) {
|
|
16780
|
-
const
|
|
16781
|
-
const lastSlash =
|
|
16939
|
+
const path41 = readPathById.get(id) ?? "";
|
|
16940
|
+
const lastSlash = path41.lastIndexOf("/");
|
|
16782
16941
|
openDenies.push({
|
|
16783
16942
|
kind: denyTemplate.kind,
|
|
16784
16943
|
withheldBytes: parseWithheldBytes(denyTemplate.kind, text),
|
|
16785
|
-
path:
|
|
16786
|
-
basename: lastSlash === -1 ?
|
|
16944
|
+
path: path41,
|
|
16945
|
+
basename: lastSlash === -1 ? path41 : path41.slice(lastSlash + 1),
|
|
16787
16946
|
callIndexAtDeny: perCall.length,
|
|
16788
16947
|
compactEpochAtOpen: compactEpoch,
|
|
16789
16948
|
compactEpochAtWindow: null,
|
|
@@ -16973,7 +17132,7 @@ async function auditOneFile(filePath, s, toolMap, attachmentMap, hookMap, laneOb
|
|
|
16973
17132
|
if (isLane) {
|
|
16974
17133
|
let agentType = "(none)";
|
|
16975
17134
|
try {
|
|
16976
|
-
const meta = JSON.parse(
|
|
17135
|
+
const meta = JSON.parse(fs33.readFileSync(filePath.replace(/\.jsonl$/i, ".meta.json"), "utf8"));
|
|
16977
17136
|
if (typeof meta["agentType"] === "string" && meta["agentType"] !== "") agentType = meta["agentType"];
|
|
16978
17137
|
} catch {
|
|
16979
17138
|
}
|
|
@@ -17054,14 +17213,19 @@ function aggregateDenyOutcomes(rows) {
|
|
|
17054
17213
|
return result.sort((a, b) => b.count - a.count || a.kind.localeCompare(b.kind));
|
|
17055
17214
|
}
|
|
17056
17215
|
async function auditSessionCorpus(opts = {}) {
|
|
17057
|
-
const corpusDir =
|
|
17058
|
-
if (!
|
|
17216
|
+
const corpusDir = path30.resolve(opts.dir ?? defaultCorpusDir());
|
|
17217
|
+
if (!fs33.existsSync(corpusDir)) {
|
|
17059
17218
|
throw new Error(`session corpus directory not found: ${corpusDir}`);
|
|
17060
17219
|
}
|
|
17061
|
-
const
|
|
17062
|
-
|
|
17220
|
+
const windowDays = opts.windowDays ?? 0;
|
|
17221
|
+
const allFiles = listCorpusTranscripts(corpusDir);
|
|
17222
|
+
if (allFiles.length === 0) {
|
|
17063
17223
|
throw new Error(`no .jsonl session transcripts found under ${corpusDir}`);
|
|
17064
17224
|
}
|
|
17225
|
+
const files = windowDays === 0 ? allFiles : modifiedSince(allFiles, Date.now() - windowDays * MS_PER_DAY);
|
|
17226
|
+
if (files.length === 0) {
|
|
17227
|
+
throw new Error(`no .jsonl session transcripts under ${corpusDir} were modified in the last ${windowDays} days`);
|
|
17228
|
+
}
|
|
17065
17229
|
const started = Date.now();
|
|
17066
17230
|
const summary = {
|
|
17067
17231
|
corpusDir,
|
|
@@ -17096,8 +17260,11 @@ async function auditSessionCorpus(opts = {}) {
|
|
|
17096
17260
|
denyOutcomes: [],
|
|
17097
17261
|
editErrorBaseline: { totalEdits: 0, totalErrors: 0, rate: 0 },
|
|
17098
17262
|
lineTypes: {},
|
|
17099
|
-
omissionMarkers: { fires: 0, linesOmitted: 0 }
|
|
17263
|
+
omissionMarkers: { fires: 0, linesOmitted: 0 },
|
|
17264
|
+
windowDays,
|
|
17265
|
+
toolErrors: { byTool: [], byModel: [], unknownPrefixes: [] }
|
|
17100
17266
|
};
|
|
17267
|
+
const toolErrorAcc = (await import("./token-goat-chunk-G23DWHV4.mjs")).newToolErrorAccumulator();
|
|
17101
17268
|
const toolMap = /* @__PURE__ */ new Map();
|
|
17102
17269
|
const attachmentMap = /* @__PURE__ */ new Map();
|
|
17103
17270
|
const hookMap = /* @__PURE__ */ new Map();
|
|
@@ -17106,7 +17273,7 @@ async function auditSessionCorpus(opts = {}) {
|
|
|
17106
17273
|
const denyRows = [];
|
|
17107
17274
|
for (const file of files) {
|
|
17108
17275
|
try {
|
|
17109
|
-
await auditOneFile(file, summary, toolMap, attachmentMap, hookMap, laneObservations, bashHeadMap, denyRows);
|
|
17276
|
+
await auditOneFile(file, summary, toolMap, attachmentMap, hookMap, laneObservations, bashHeadMap, denyRows, toolErrorAcc);
|
|
17110
17277
|
summary.filesScanned += 1;
|
|
17111
17278
|
} catch {
|
|
17112
17279
|
summary.filesFailed += 1;
|
|
@@ -17146,6 +17313,7 @@ async function auditSessionCorpus(opts = {}) {
|
|
|
17146
17313
|
summary.denyOutcomes = aggregateDenyOutcomes(denyRows);
|
|
17147
17314
|
summary.editErrorBaseline.rate = summary.editErrorBaseline.totalEdits === 0 ? 0 : summary.editErrorBaseline.totalErrors / summary.editErrorBaseline.totalEdits;
|
|
17148
17315
|
summary.calibration = computeCalibration(summary.estimated, summary.measured);
|
|
17316
|
+
summary.toolErrors = toolErrorAcc.finish();
|
|
17149
17317
|
summary.runtimeMs = Date.now() - started;
|
|
17150
17318
|
return summary;
|
|
17151
17319
|
}
|
|
@@ -17266,17 +17434,17 @@ function formatSessionAudit(s) {
|
|
|
17266
17434
|
|
|
17267
17435
|
// src/session_read.ts
|
|
17268
17436
|
init_define_import_meta_env();
|
|
17269
|
-
import * as
|
|
17270
|
-
import * as
|
|
17437
|
+
import * as fs34 from "node:fs";
|
|
17438
|
+
import * as path31 from "node:path";
|
|
17271
17439
|
import * as readline2 from "node:readline";
|
|
17272
17440
|
function resolveSessionTranscript(arg, opts = {}) {
|
|
17273
17441
|
if (arg !== void 0 && arg !== "") {
|
|
17274
|
-
if (
|
|
17442
|
+
if (fs34.existsSync(arg) && fs34.statSync(arg).isFile()) return arg;
|
|
17275
17443
|
const projectRoot2 = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
17276
17444
|
const dir = projectTranscriptsDir(projectRoot2);
|
|
17277
17445
|
const byId = arg.endsWith(".jsonl") ? arg : `${arg}.jsonl`;
|
|
17278
|
-
const candidate =
|
|
17279
|
-
if (
|
|
17446
|
+
const candidate = path31.join(dir, byId);
|
|
17447
|
+
if (fs34.existsSync(candidate) && fs34.statSync(candidate).isFile()) return candidate;
|
|
17280
17448
|
return null;
|
|
17281
17449
|
}
|
|
17282
17450
|
const projectRoot = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
@@ -17334,7 +17502,7 @@ function toolCallsForBlocks(blocks) {
|
|
|
17334
17502
|
return blocks.filter((b) => b.type === "tool_use" && b.name !== void 0).map((b) => b.name);
|
|
17335
17503
|
}
|
|
17336
17504
|
async function* streamTurns(transcriptPath) {
|
|
17337
|
-
const input =
|
|
17505
|
+
const input = fs34.createReadStream(transcriptPath, { encoding: "utf8" });
|
|
17338
17506
|
const rl = readline2.createInterface({ input, crlfDelay: Infinity });
|
|
17339
17507
|
try {
|
|
17340
17508
|
let lineNumber = 0;
|
|
@@ -17433,9 +17601,9 @@ function formatSessionSlice(turns) {
|
|
|
17433
17601
|
|
|
17434
17602
|
// src/cli_bootstrap_audit.ts
|
|
17435
17603
|
init_define_import_meta_env();
|
|
17436
|
-
import * as
|
|
17604
|
+
import * as fs35 from "node:fs";
|
|
17437
17605
|
import * as os17 from "node:os";
|
|
17438
|
-
import * as
|
|
17606
|
+
import * as path32 from "node:path";
|
|
17439
17607
|
import * as readline3 from "node:readline";
|
|
17440
17608
|
var FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["description", "tools", "allowed-tools", "allowed_tools"]);
|
|
17441
17609
|
function parseBudget(name, value) {
|
|
@@ -17444,7 +17612,7 @@ function parseBudget(name, value) {
|
|
|
17444
17612
|
return value;
|
|
17445
17613
|
}
|
|
17446
17614
|
async function readFrontmatter(filePath) {
|
|
17447
|
-
const stream =
|
|
17615
|
+
const stream = fs35.createReadStream(filePath, { encoding: "utf8" });
|
|
17448
17616
|
const lines = readline3.createInterface({ input: stream, crlfDelay: Infinity });
|
|
17449
17617
|
let first = true;
|
|
17450
17618
|
let inFrontmatter = false;
|
|
@@ -17490,44 +17658,44 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
17490
17658
|
let logicalRoot;
|
|
17491
17659
|
let rootIsLink;
|
|
17492
17660
|
try {
|
|
17493
|
-
rootIsLink = (await
|
|
17494
|
-
logicalRoot = await
|
|
17661
|
+
rootIsLink = (await fs35.promises.lstat(root)).isSymbolicLink();
|
|
17662
|
+
logicalRoot = await fs35.promises.realpath(root);
|
|
17495
17663
|
} catch (error) {
|
|
17496
17664
|
if (error.code === "ENOENT") return entries;
|
|
17497
|
-
diagnostics.push({ path:
|
|
17665
|
+
diagnostics.push({ path: path32.resolve(root), reason: "unreadable root" });
|
|
17498
17666
|
return entries;
|
|
17499
17667
|
}
|
|
17500
17668
|
if (rootIsLink && !followLinks) {
|
|
17501
|
-
diagnostics.push({ path:
|
|
17669
|
+
diagnostics.push({ path: path32.resolve(root), reason: "external root link skipped (use --follow-links)" });
|
|
17502
17670
|
return entries;
|
|
17503
17671
|
}
|
|
17504
17672
|
const canonicalKey = (candidate) => process.platform === "win32" ? candidate.toLocaleLowerCase() : candidate;
|
|
17505
17673
|
const isContained = (candidate, allowedRoot) => {
|
|
17506
|
-
const relative3 =
|
|
17507
|
-
return relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${
|
|
17674
|
+
const relative3 = path32.relative(canonicalKey(allowedRoot), canonicalKey(candidate));
|
|
17675
|
+
return relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${path32.sep}`) && !path32.isAbsolute(relative3);
|
|
17508
17676
|
};
|
|
17509
17677
|
async function visit(candidate, allowedRoot, topLevel = false) {
|
|
17510
17678
|
let real;
|
|
17511
17679
|
let candidateIsLink;
|
|
17512
17680
|
try {
|
|
17513
|
-
candidateIsLink = (await
|
|
17514
|
-
real = await
|
|
17681
|
+
candidateIsLink = (await fs35.promises.lstat(candidate)).isSymbolicLink();
|
|
17682
|
+
real = await fs35.promises.realpath(candidate);
|
|
17515
17683
|
} catch {
|
|
17516
|
-
diagnostics.push({ path:
|
|
17684
|
+
diagnostics.push({ path: path32.resolve(candidate), reason: "broken or unreadable link" });
|
|
17517
17685
|
return;
|
|
17518
17686
|
}
|
|
17519
17687
|
const withinAllowedRoot = allowedRoot === void 0 ? isContained(real, logicalRoot) : isContained(real, allowedRoot);
|
|
17520
17688
|
const canFollowExternal = followLinks && topLevel;
|
|
17521
17689
|
if (!withinAllowedRoot && !canFollowExternal) {
|
|
17522
|
-
diagnostics.push({ path:
|
|
17690
|
+
diagnostics.push({ path: path32.resolve(candidate), reason: candidateIsLink ? "external link skipped (use --follow-links)" : "canonical target outside scan root" });
|
|
17523
17691
|
return;
|
|
17524
17692
|
}
|
|
17525
17693
|
const trustedRoot = !withinAllowedRoot && canFollowExternal ? real : allowedRoot ?? real;
|
|
17526
17694
|
let stat;
|
|
17527
17695
|
try {
|
|
17528
|
-
stat = await
|
|
17696
|
+
stat = await fs35.promises.stat(real);
|
|
17529
17697
|
} catch {
|
|
17530
|
-
diagnostics.push({ path:
|
|
17698
|
+
diagnostics.push({ path: path32.resolve(candidate), reason: "unreadable" });
|
|
17531
17699
|
return;
|
|
17532
17700
|
}
|
|
17533
17701
|
const canonical = process.platform === "win32" ? real.toLocaleLowerCase() : real;
|
|
@@ -17536,16 +17704,16 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
17536
17704
|
visitedDirs.add(canonical);
|
|
17537
17705
|
let children;
|
|
17538
17706
|
try {
|
|
17539
|
-
children = await
|
|
17707
|
+
children = await fs35.promises.readdir(real, { withFileTypes: true });
|
|
17540
17708
|
} catch {
|
|
17541
|
-
diagnostics.push({ path:
|
|
17709
|
+
diagnostics.push({ path: path32.resolve(candidate), reason: "unreadable directory" });
|
|
17542
17710
|
return;
|
|
17543
17711
|
}
|
|
17544
17712
|
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
17545
|
-
for (const child of children) await visit(
|
|
17713
|
+
for (const child of children) await visit(path32.join(real, child.name), trustedRoot);
|
|
17546
17714
|
return;
|
|
17547
17715
|
}
|
|
17548
|
-
if (!stat.isFile() ||
|
|
17716
|
+
if (!stat.isFile() || path32.extname(real).toLowerCase() !== ".md") return;
|
|
17549
17717
|
if (seenFiles.has(canonical)) return;
|
|
17550
17718
|
seenFiles.add(canonical);
|
|
17551
17719
|
try {
|
|
@@ -17555,35 +17723,35 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
17555
17723
|
const toolsBytes = Buffer.byteLength(metadata.tools, "utf8");
|
|
17556
17724
|
entries.push({
|
|
17557
17725
|
kind,
|
|
17558
|
-
path:
|
|
17726
|
+
path: path32.resolve(real),
|
|
17559
17727
|
description_bytes: descriptionBytes,
|
|
17560
17728
|
tools_bytes: toolsBytes,
|
|
17561
17729
|
metadata_bytes: descriptionBytes + toolsBytes,
|
|
17562
17730
|
estimated_tokens: Math.floor((descriptionBytes + toolsBytes) / 4)
|
|
17563
17731
|
});
|
|
17564
17732
|
} catch {
|
|
17565
|
-
diagnostics.push({ path:
|
|
17733
|
+
diagnostics.push({ path: path32.resolve(candidate), reason: "unreadable file" });
|
|
17566
17734
|
}
|
|
17567
17735
|
}
|
|
17568
17736
|
try {
|
|
17569
|
-
const children = await
|
|
17737
|
+
const children = await fs35.promises.readdir(logicalRoot, { withFileTypes: true });
|
|
17570
17738
|
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
17571
|
-
for (const child of children) await visit(
|
|
17739
|
+
for (const child of children) await visit(path32.join(logicalRoot, child.name), void 0, true);
|
|
17572
17740
|
} catch {
|
|
17573
|
-
diagnostics.push({ path:
|
|
17741
|
+
diagnostics.push({ path: path32.resolve(root), reason: "unreadable root" });
|
|
17574
17742
|
}
|
|
17575
17743
|
return entries;
|
|
17576
17744
|
}
|
|
17577
17745
|
async function buildBootstrapAudit(opts = {}) {
|
|
17578
17746
|
const project = resolveProjectRoot(opts.project === void 0 ? {} : { project: opts.project });
|
|
17579
|
-
const home =
|
|
17747
|
+
const home = path32.resolve(opts.home ?? os17.homedir());
|
|
17580
17748
|
const context = buildStats(project, home, opts.project === void 0 ? [] : [opts.project]);
|
|
17581
17749
|
const diagnostics = [];
|
|
17582
17750
|
const top = opts.top === void 0 ? 10 : parseBudget("--top", opts.top) ?? 10;
|
|
17583
17751
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
17584
17752
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
17585
|
-
const agents = await scanMetadataRoot(
|
|
17586
|
-
const skills = await scanMetadataRoot(
|
|
17753
|
+
const agents = await scanMetadataRoot(path32.join(claudeConfigDir(home), "agents"), "agent", diagnostics, visitedDirs, seenFiles, opts.followLinks === true);
|
|
17754
|
+
const skills = await scanMetadataRoot(path32.join(claudeConfigDir(home), "skills"), "skill", diagnostics, visitedDirs, seenFiles, opts.followLinks === true);
|
|
17587
17755
|
const rankedEntries = [...agents, ...skills].sort((a, b) => b.metadata_bytes - a.metadata_bytes || a.path.localeCompare(b.path));
|
|
17588
17756
|
const largestTotal = rankedEntries.length;
|
|
17589
17757
|
const largest = rankedEntries.slice(0, top);
|
|
@@ -17650,8 +17818,8 @@ async function runBootstrapAudit(opts = {}) {
|
|
|
17650
17818
|
|
|
17651
17819
|
// src/cli_memory.ts
|
|
17652
17820
|
init_define_import_meta_env();
|
|
17653
|
-
import * as
|
|
17654
|
-
import * as
|
|
17821
|
+
import * as fs36 from "node:fs";
|
|
17822
|
+
import * as path33 from "node:path";
|
|
17655
17823
|
function removeExactDupLines(text, report) {
|
|
17656
17824
|
if (report.exactDupLines.length === 0) return text;
|
|
17657
17825
|
const toRemove = new Set(report.exactDupLines.map(([, dupIdx]) => dupIdx));
|
|
@@ -17709,7 +17877,7 @@ function printReport(reports, clusters) {
|
|
|
17709
17877
|
} else {
|
|
17710
17878
|
for (const cluster of clusters) {
|
|
17711
17879
|
w(
|
|
17712
|
-
` [${cluster.method}, similarity ${cluster.similarity}, ~${cluster.tokens} tok] ${cluster.members.map((m) => displaySafeText(
|
|
17880
|
+
` [${cluster.method}, similarity ${cluster.similarity}, ~${cluster.tokens} tok] ${cluster.members.map((m) => displaySafeText(path33.basename(m))).join(", ")}
|
|
17713
17881
|
`
|
|
17714
17882
|
);
|
|
17715
17883
|
}
|
|
@@ -17724,7 +17892,7 @@ async function runMemoryCommand(opts = {}) {
|
|
|
17724
17892
|
const claudeMds = findClaudeMdFiles(projectRoot);
|
|
17725
17893
|
const reports = auditClaudeMd(claudeMds);
|
|
17726
17894
|
const memoryMdPath = findMemoryMd(projectRoot);
|
|
17727
|
-
const clusters = memoryMdPath !== null ? await findContentDuplicates(
|
|
17895
|
+
const clusters = memoryMdPath !== null ? await findContentDuplicates(path33.dirname(memoryMdPath)) : [];
|
|
17728
17896
|
printReport(reports, clusters);
|
|
17729
17897
|
if (opts.fix !== true) return;
|
|
17730
17898
|
const changes = [];
|
|
@@ -17732,7 +17900,7 @@ async function runMemoryCommand(opts = {}) {
|
|
|
17732
17900
|
if (report.exactDupLines.length === 0) continue;
|
|
17733
17901
|
let before;
|
|
17734
17902
|
try {
|
|
17735
|
-
before =
|
|
17903
|
+
before = fs36.readFileSync(report.path, "utf-8");
|
|
17736
17904
|
} catch {
|
|
17737
17905
|
continue;
|
|
17738
17906
|
}
|
|
@@ -17770,8 +17938,8 @@ async function runMemoryCommand(opts = {}) {
|
|
|
17770
17938
|
|
|
17771
17939
|
// src/cli_waste.ts
|
|
17772
17940
|
init_define_import_meta_env();
|
|
17773
|
-
import * as
|
|
17774
|
-
import * as
|
|
17941
|
+
import * as fs37 from "node:fs";
|
|
17942
|
+
import * as path34 from "node:path";
|
|
17775
17943
|
function printCopilotReport(report) {
|
|
17776
17944
|
const w = (text) => {
|
|
17777
17945
|
process.stdout.write(text);
|
|
@@ -17825,8 +17993,9 @@ function printCopilotReport(report) {
|
|
|
17825
17993
|
} else {
|
|
17826
17994
|
for (const server of mcp.servers) {
|
|
17827
17995
|
const tokens = server.estimatedTokens.toLocaleString();
|
|
17996
|
+
const calls = report.mcpCalls === null ? "" : `, ${countNoun(report.mcpCalls[server.serverName] ?? 0, "call")} this session`;
|
|
17828
17997
|
w(` ${server.serverName}: ${countNoun(server.toolCount, "tool")}, `);
|
|
17829
|
-
w(`${formatBytes(server.definitionBytes)}, ~${tokens} tok
|
|
17998
|
+
w(`${formatBytes(server.definitionBytes)}, ~${tokens} tok${calls}
|
|
17830
17999
|
`);
|
|
17831
18000
|
}
|
|
17832
18001
|
const mcpTokens = mcp.servers.reduce((sum, server) => sum + server.estimatedTokens, 0);
|
|
@@ -17846,6 +18015,15 @@ function printCopilotReport(report) {
|
|
|
17846
18015
|
w(" tool-filter flags above still can.\n");
|
|
17847
18016
|
}
|
|
17848
18017
|
w(" Dropping a server saves its line above on every request for the rest of the session.\n");
|
|
18018
|
+
const unused = unusedMcpServers(report);
|
|
18019
|
+
if (unused === null) {
|
|
18020
|
+
w(" This log records no tool calls, so it cannot say which servers went unused.\n");
|
|
18021
|
+
} else {
|
|
18022
|
+
for (const server of unused) w(` Never called this session: \`copilot mcp disable ${server.serverName}\` drops it from future sessions.
|
|
18023
|
+
`);
|
|
18024
|
+
if (unused.length > 0) w(` ${MCP_DISABLE_NOTE}
|
|
18025
|
+
`);
|
|
18026
|
+
}
|
|
17849
18027
|
}
|
|
17850
18028
|
if (mcp.unreadable > 0) {
|
|
17851
18029
|
const verb = mcp.unreadable === 1 ? "is" : "are";
|
|
@@ -17972,8 +18150,8 @@ function printResidentContext(resident, w) {
|
|
|
17972
18150
|
async function runWasteCommand(opts = {}) {
|
|
17973
18151
|
const projectRoot = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
17974
18152
|
if (opts.transcript !== void 0) {
|
|
17975
|
-
const resolvedPath =
|
|
17976
|
-
if (!
|
|
18153
|
+
const resolvedPath = path34.resolve(opts.transcript);
|
|
18154
|
+
if (!fs37.existsSync(resolvedPath)) {
|
|
17977
18155
|
if (opts.copilot === true) {
|
|
17978
18156
|
const detail = `Copilot session event log not found: ${resolvedPath}`;
|
|
17979
18157
|
if (opts.json === true) {
|
|
@@ -18013,7 +18191,7 @@ async function runWasteCommand(opts = {}) {
|
|
|
18013
18191
|
}
|
|
18014
18192
|
if (opts.copilot === true) {
|
|
18015
18193
|
const eventsPath = opts.project !== void 0 ? findLatestCopilotSession({ projectRoot }) : findLatestCopilotSession({ projectRoot }) ?? findLatestCopilotSession();
|
|
18016
|
-
if (eventsPath === null || !
|
|
18194
|
+
if (eventsPath === null || !fs37.existsSync(eventsPath)) {
|
|
18017
18195
|
const detail = eventsPath === null ? "no Copilot CLI session found under <copilot-home>/session-state" : `Copilot session event log not found: ${eventsPath}`;
|
|
18018
18196
|
if (opts.json === true) {
|
|
18019
18197
|
process.stdout.write(`${displaySafeJson({ error: detail }, 0)}
|
|
@@ -18070,13 +18248,13 @@ async function runWasteCommand(opts = {}) {
|
|
|
18070
18248
|
|
|
18071
18249
|
// src/cli_mcp_audit.ts
|
|
18072
18250
|
init_define_import_meta_env();
|
|
18073
|
-
import * as
|
|
18251
|
+
import * as fs38 from "node:fs";
|
|
18074
18252
|
import * as os18 from "node:os";
|
|
18075
|
-
import * as
|
|
18253
|
+
import * as path35 from "node:path";
|
|
18076
18254
|
function readMcpJsonFile(configPath2) {
|
|
18077
18255
|
try {
|
|
18078
|
-
if (!
|
|
18079
|
-
const content =
|
|
18256
|
+
if (!fs38.existsSync(configPath2)) return null;
|
|
18257
|
+
const content = fs38.readFileSync(configPath2, "utf-8");
|
|
18080
18258
|
const parsed = JSON.parse(content);
|
|
18081
18259
|
const servers = parsed && typeof parsed === "object" ? parsed.mcpServers ?? ("servers" in parsed ? null : parsed) : null;
|
|
18082
18260
|
return servers && typeof servers === "object" ? servers : null;
|
|
@@ -18092,8 +18270,8 @@ function driveLetterCaseVariants(p) {
|
|
|
18092
18270
|
}
|
|
18093
18271
|
function readClaudeJsonConfig(claudeJsonPath, projectRoot) {
|
|
18094
18272
|
try {
|
|
18095
|
-
if (!
|
|
18096
|
-
const parsed = JSON.parse(
|
|
18273
|
+
if (!fs38.existsSync(claudeJsonPath)) return null;
|
|
18274
|
+
const parsed = JSON.parse(fs38.readFileSync(claudeJsonPath, "utf-8"));
|
|
18097
18275
|
const projects = parsed && typeof parsed === "object" ? parsed.projects : null;
|
|
18098
18276
|
if (!projects || typeof projects !== "object") return null;
|
|
18099
18277
|
const slashForms = [projectRoot, projectRoot.replace(/\\/g, "/"), projectRoot.replace(/\//g, "\\")];
|
|
@@ -18111,9 +18289,9 @@ function readClaudeJsonConfig(claudeJsonPath, projectRoot) {
|
|
|
18111
18289
|
}
|
|
18112
18290
|
}
|
|
18113
18291
|
function discoverMcpConfig(projectRoot, home) {
|
|
18114
|
-
const mcpJsonPath =
|
|
18115
|
-
const claudeJsonPath =
|
|
18116
|
-
const copilotJsonPath =
|
|
18292
|
+
const mcpJsonPath = path35.join(projectRoot, ".mcp.json");
|
|
18293
|
+
const claudeJsonPath = path35.join(home, ".claude.json");
|
|
18294
|
+
const copilotJsonPath = path35.join(home, ".copilot", "mcp-config.json");
|
|
18117
18295
|
const sourcesChecked = [mcpJsonPath, claudeJsonPath, copilotJsonPath];
|
|
18118
18296
|
const fromMcpJson = readMcpJsonFile(mcpJsonPath);
|
|
18119
18297
|
if (fromMcpJson !== null) return { servers: fromMcpJson, sourcePath: mcpJsonPath, sourcesChecked };
|
|
@@ -18312,6 +18490,11 @@ async function runStatuslineCommand(opts = {}) {
|
|
|
18312
18490
|
|
|
18313
18491
|
// src/cli_hint_stats.ts
|
|
18314
18492
|
init_define_import_meta_env();
|
|
18493
|
+
var SESSION_JSON_SCOPE = {
|
|
18494
|
+
session: ["emitted", "actedOn", "efficacyPct", "unobservable", "detected", "bytesEmitted", "legacyEmissions", "totals.spentBytes", "totals.legacyEmissions"],
|
|
18495
|
+
allTime: ["suppressed", "suppressionPermanent", "manualEffective", "manualIneffective"],
|
|
18496
|
+
unavailable: ["totals.savedBytes"]
|
|
18497
|
+
};
|
|
18315
18498
|
function formatSpentCell(row) {
|
|
18316
18499
|
if (row.emitted === 0) return "n/a";
|
|
18317
18500
|
if (row.bytesEmitted === null) return "n/a (legacy)";
|
|
@@ -18351,6 +18534,16 @@ TOTAL saved-bytes=${totals.savedBytes} (all-time, every hint kind) spent-byt
|
|
|
18351
18534
|
`
|
|
18352
18535
|
);
|
|
18353
18536
|
}
|
|
18537
|
+
function printSessionTotals(totals) {
|
|
18538
|
+
const spent = totals.spentBytes === null ? "n/a" : String(totals.spentBytes);
|
|
18539
|
+
const legacyNote = totals.legacyEmissions > 0 ? ` (excludes ${totals.legacyEmissions} legacy emission(s) recorded before spend tracking)` : "";
|
|
18540
|
+
process.stdout.write(
|
|
18541
|
+
`
|
|
18542
|
+
TOTAL (this session) spent-bytes=${spent} (hint_emissions ledger only)${legacyNote}
|
|
18543
|
+
saved-bytes: not available per session, because the stats ledger it comes from records no session id. Run \`token-goat hint-stats\` without --session-id for the all-time figure.
|
|
18544
|
+
`
|
|
18545
|
+
);
|
|
18546
|
+
}
|
|
18354
18547
|
function runHintStatsCommand(opts = {}) {
|
|
18355
18548
|
if (opts.reset === true) {
|
|
18356
18549
|
resetHintStats();
|
|
@@ -18369,13 +18562,24 @@ function runHintStatsCommand(opts = {}) {
|
|
|
18369
18562
|
`);
|
|
18370
18563
|
return;
|
|
18371
18564
|
}
|
|
18372
|
-
const
|
|
18565
|
+
const session = opts.sessionId;
|
|
18566
|
+
const rows = getHintStatsSummary(session);
|
|
18373
18567
|
if (opts.json === true) {
|
|
18374
|
-
|
|
18568
|
+
const payload = session === void 0 ? rows : { session, scope: SESSION_JSON_SCOPE, rows, totals: { savedBytes: null, ...getHintSpendTotals(session) } };
|
|
18569
|
+
process.stdout.write(`${displaySafeJson(payload, 0)}
|
|
18375
18570
|
`);
|
|
18376
18571
|
return;
|
|
18377
18572
|
}
|
|
18378
|
-
|
|
18573
|
+
const noEmissions = rows.every((r) => r.emitted === 0 && r.actedOn === 0 && r.unobservable === 0 && r.detected === 0);
|
|
18574
|
+
if (session !== void 0) {
|
|
18575
|
+
process.stdout.write(
|
|
18576
|
+
`Session: ${displaySafeText(session)}
|
|
18577
|
+
emitted, undisplayed, acted-on, efficacy and spent-bytes count this session only. suppressed, manual+ and manual- are all-time, across every session: suppression is decided on the whole history, and manual marks carry no session.
|
|
18578
|
+
`
|
|
18579
|
+
);
|
|
18580
|
+
if (noEmissions) process.stdout.write("No hint emissions were recorded for this session, so every per-session figure below is 0.\n");
|
|
18581
|
+
}
|
|
18582
|
+
if (session === void 0 && noEmissions) {
|
|
18379
18583
|
process.stdout.write("No hint emissions recorded yet \u2014 the zeros below are absence of data, not measured ineffectiveness.\n");
|
|
18380
18584
|
}
|
|
18381
18585
|
printSummary(rows);
|
|
@@ -18401,7 +18605,8 @@ function runHintStatsCommand(opts = {}) {
|
|
|
18401
18605
|
hints.backoff_thresholds is empty, so suppression here is permanent rather than a self-healing throttle: ${names} will not emit again on any occasion. Set backoff_thresholds to re-enable probe emissions, or run \`token-goat hint-stats --reset\` to clear the ledger.
|
|
18402
18606
|
`);
|
|
18403
18607
|
}
|
|
18404
|
-
printTotals(getHintStatsTotals());
|
|
18608
|
+
if (session === void 0) printTotals(getHintStatsTotals());
|
|
18609
|
+
else printSessionTotals(getHintSpendTotals(session));
|
|
18405
18610
|
}
|
|
18406
18611
|
|
|
18407
18612
|
// src/cli_session.ts
|
|
@@ -18434,7 +18639,7 @@ function cmdWaste(opts = {}) {
|
|
|
18434
18639
|
});
|
|
18435
18640
|
}
|
|
18436
18641
|
async function cmdAudit(opts = {}) {
|
|
18437
|
-
const { runAuditCommand } = await import("./token-goat-chunk-
|
|
18642
|
+
const { runAuditCommand } = await import("./token-goat-chunk-67BNIKKO.mjs");
|
|
18438
18643
|
return runAuditCommand({
|
|
18439
18644
|
...opts.project !== void 0 ? { project: opts.project } : {},
|
|
18440
18645
|
...opts.transcript !== void 0 ? { transcript: opts.transcript } : {},
|
|
@@ -18444,10 +18649,15 @@ async function cmdAudit(opts = {}) {
|
|
|
18444
18649
|
async function cmdSessionAudit(opts = {}) {
|
|
18445
18650
|
let summary;
|
|
18446
18651
|
try {
|
|
18447
|
-
summary = await auditSessionCorpus({ ...opts.dir !== void 0 ? { dir: opts.dir } : {} });
|
|
18652
|
+
summary = await auditSessionCorpus({ ...opts.dir !== void 0 ? { dir: opts.dir } : {}, ...opts.windowDays !== void 0 ? { windowDays: opts.windowDays } : {} });
|
|
18448
18653
|
} catch (err2) {
|
|
18449
18654
|
throw new CliError(err2 instanceof Error ? err2.message : String(err2));
|
|
18450
18655
|
}
|
|
18656
|
+
if (opts.toolErrors === true) {
|
|
18657
|
+
const { formatToolErrorCensus } = await import("./token-goat-chunk-G23DWHV4.mjs");
|
|
18658
|
+
out(opts.json === true ? displaySafeJson({ filesScanned: summary.filesScanned, windowDays: summary.windowDays, ...summary.toolErrors }, 0) : formatToolErrorCensus(summary.toolErrors, summary));
|
|
18659
|
+
return;
|
|
18660
|
+
}
|
|
18451
18661
|
out(opts.json === true ? displaySafeJson(summary, 0) : formatSessionAudit(summary));
|
|
18452
18662
|
}
|
|
18453
18663
|
async function cmdSessionOutline(sessionIdOrPath, opts = {}) {
|
|
@@ -18467,7 +18677,7 @@ ${formatSessionOutline(turns)}`;
|
|
|
18467
18677
|
}
|
|
18468
18678
|
function sessionTranscriptSize(transcriptPath) {
|
|
18469
18679
|
try {
|
|
18470
|
-
return
|
|
18680
|
+
return fs39.statSync(transcriptPath).size;
|
|
18471
18681
|
} catch {
|
|
18472
18682
|
return 0;
|
|
18473
18683
|
}
|
|
@@ -18511,30 +18721,46 @@ function cmdStatusline(opts = {}) {
|
|
|
18511
18721
|
return runStatuslineCommand({ ...opts.json === true ? { json: true } : {} });
|
|
18512
18722
|
}
|
|
18513
18723
|
function cmdHintStats(opts = {}) {
|
|
18724
|
+
if (opts.sessionId !== void 0) {
|
|
18725
|
+
const mutating = [opts.reset === true ? "--reset" : null, opts.markEffective !== void 0 ? "--mark-effective" : null, opts.markIneffective !== void 0 ? "--mark-ineffective" : null].filter((f) => f !== null);
|
|
18726
|
+
if (mutating.length > 0) {
|
|
18727
|
+
throw new CliError(`--session-id cannot be combined with ${mutating.join(", ")}: those change cross-session state (every session's emissions and marks), not one session's view`);
|
|
18728
|
+
}
|
|
18729
|
+
}
|
|
18730
|
+
const session = opts.sessionId === void 0 ? void 0 : resolveHintStatsSession(opts.sessionId);
|
|
18514
18731
|
if (opts.markEffective !== void 0 && !isHintCategory(opts.markEffective)) {
|
|
18515
|
-
throw new CliError(`--mark-effective must be one of:
|
|
18732
|
+
throw new CliError(`--mark-effective must be one of: ${HINT_CATEGORIES.join(", ")} (got: ${opts.markEffective})`);
|
|
18516
18733
|
}
|
|
18517
18734
|
if (opts.markIneffective !== void 0 && !isHintCategory(opts.markIneffective)) {
|
|
18518
|
-
throw new CliError(`--mark-ineffective must be one of:
|
|
18735
|
+
throw new CliError(`--mark-ineffective must be one of: ${HINT_CATEGORIES.join(", ")} (got: ${opts.markIneffective})`);
|
|
18519
18736
|
}
|
|
18520
18737
|
runHintStatsCommand({
|
|
18521
18738
|
...opts.json === true ? { json: true } : {},
|
|
18522
18739
|
...opts.reset === true ? { reset: true } : {},
|
|
18523
18740
|
...opts.markEffective !== void 0 && isHintCategory(opts.markEffective) ? { markEffective: opts.markEffective } : {},
|
|
18524
|
-
...opts.markIneffective !== void 0 && isHintCategory(opts.markIneffective) ? { markIneffective: opts.markIneffective } : {}
|
|
18741
|
+
...opts.markIneffective !== void 0 && isHintCategory(opts.markIneffective) ? { markIneffective: opts.markIneffective } : {},
|
|
18742
|
+
...session !== void 0 ? { sessionId: session } : {}
|
|
18525
18743
|
});
|
|
18526
18744
|
}
|
|
18745
|
+
function resolveHintStatsSession(arg) {
|
|
18746
|
+
const trimmed = arg.trim();
|
|
18747
|
+
if (trimmed === "") throw new CliError("--session-id needs a session id, or `latest` for the most recent session");
|
|
18748
|
+
if (trimmed !== "latest") return trimmed;
|
|
18749
|
+
const latest = findLatestSessionId();
|
|
18750
|
+
if (latest === null) throw new CliError("--session-id latest: no session state found on disk; pass a session id explicitly");
|
|
18751
|
+
return latest;
|
|
18752
|
+
}
|
|
18527
18753
|
|
|
18528
18754
|
// src/cli_skills.ts
|
|
18529
18755
|
init_define_import_meta_env();
|
|
18530
|
-
import * as
|
|
18531
|
-
import * as
|
|
18756
|
+
import * as fs40 from "node:fs";
|
|
18757
|
+
import * as path36 from "node:path";
|
|
18532
18758
|
async function cmdSkillBody(name, opts) {
|
|
18533
18759
|
const filePath = await getSkillFilePath(name);
|
|
18534
18760
|
if (filePath === null) {
|
|
18535
18761
|
throw new CliError(`skill '${name}' not found`);
|
|
18536
18762
|
}
|
|
18537
|
-
const body = decodeSource(
|
|
18763
|
+
const body = decodeSource(fs40.readFileSync(filePath));
|
|
18538
18764
|
if (opts.compact === true) {
|
|
18539
18765
|
const emitted = extractCompactFromMarker(body) ?? body;
|
|
18540
18766
|
out(emitted);
|
|
@@ -18561,7 +18787,7 @@ async function cmdSkillCompact(name, opts) {
|
|
|
18561
18787
|
}
|
|
18562
18788
|
let body2;
|
|
18563
18789
|
try {
|
|
18564
|
-
body2 = decodeSource(
|
|
18790
|
+
body2 = decodeSource(fs40.readFileSync(filePath));
|
|
18565
18791
|
} catch {
|
|
18566
18792
|
unresolvable++;
|
|
18567
18793
|
continue;
|
|
@@ -18595,19 +18821,19 @@ async function cmdSkillCompact(name, opts) {
|
|
|
18595
18821
|
if (!opts.path.trim()) {
|
|
18596
18822
|
throw new CliError("--path cannot be empty");
|
|
18597
18823
|
}
|
|
18598
|
-
if (!
|
|
18824
|
+
if (!fs40.existsSync(opts.path)) {
|
|
18599
18825
|
throw new CliError(`skill file not found: ${opts.path}`);
|
|
18600
18826
|
}
|
|
18601
18827
|
try {
|
|
18602
|
-
body =
|
|
18828
|
+
body = fs40.readFileSync(opts.path, "utf-8");
|
|
18603
18829
|
} catch (e) {
|
|
18604
18830
|
if (e.code === "ENOENT") {
|
|
18605
18831
|
throw new CliError(`skill file not found: ${opts.path}`);
|
|
18606
18832
|
}
|
|
18607
18833
|
throw new CliError(`failed to read skill file '${opts.path}': ${extractErrorMessage(e)}`);
|
|
18608
18834
|
}
|
|
18609
|
-
cacheName = name ??
|
|
18610
|
-
sourcePath =
|
|
18835
|
+
cacheName = name ?? path36.basename(path36.dirname(path36.resolve(opts.path)));
|
|
18836
|
+
sourcePath = path36.resolve(opts.path);
|
|
18611
18837
|
} else {
|
|
18612
18838
|
if (name === void 0 || !name.trim()) {
|
|
18613
18839
|
throw new CliError("skill-compact requires a <name> or --path <file>");
|
|
@@ -18616,7 +18842,7 @@ async function cmdSkillCompact(name, opts) {
|
|
|
18616
18842
|
if (filePath === null) {
|
|
18617
18843
|
throw new CliError(`skill '${name}' not found`);
|
|
18618
18844
|
}
|
|
18619
|
-
body =
|
|
18845
|
+
body = fs40.readFileSync(filePath, "utf-8");
|
|
18620
18846
|
cacheName = name;
|
|
18621
18847
|
sourcePath = filePath;
|
|
18622
18848
|
}
|
|
@@ -18748,8 +18974,8 @@ async function cmdSkillDiff(name) {
|
|
|
18748
18974
|
}
|
|
18749
18975
|
const newer = versions[0];
|
|
18750
18976
|
const older = versions[1];
|
|
18751
|
-
const newerBody = await
|
|
18752
|
-
const olderBody = await
|
|
18977
|
+
const newerBody = await fs40.promises.readFile(path36.resolve(dir, `${newer.outputId}.txt`), "utf-8").catch(() => null);
|
|
18978
|
+
const olderBody = await fs40.promises.readFile(path36.resolve(dir, `${older.outputId}.txt`), "utf-8").catch(() => null);
|
|
18753
18979
|
if (newerBody === null || olderBody === null) {
|
|
18754
18980
|
out(`a cached version of '${name}' was evicted while diffing -- try again`);
|
|
18755
18981
|
return;
|
|
@@ -18778,7 +19004,7 @@ async function cmdSkillSection(nameHeading, headingArg) {
|
|
|
18778
19004
|
if (!filePath) {
|
|
18779
19005
|
throw new CliError(`skill '${skillName}' not found`);
|
|
18780
19006
|
}
|
|
18781
|
-
const body = decodeSource(
|
|
19007
|
+
const body = decodeSource(fs40.readFileSync(filePath));
|
|
18782
19008
|
const extracted = extractNamedSection(body, heading);
|
|
18783
19009
|
if (!extracted) {
|
|
18784
19010
|
const allHeadings = listSections(filePath);
|
|
@@ -18788,10 +19014,10 @@ async function cmdSkillSection(nameHeading, headingArg) {
|
|
|
18788
19014
|
}
|
|
18789
19015
|
const messages = [`Section '${heading}' not found in skill '${skillName}'`];
|
|
18790
19016
|
const available = filterSimilarHeadings(allHeadings, heading);
|
|
18791
|
-
if (available.length > 0) messages.push(
|
|
19017
|
+
if (available.length > 0) messages.push(...didYouMeanLines(available));
|
|
18792
19018
|
else if (allHeadings.length === 0) messages.push(`skill '${skillName}' has no headings`);
|
|
18793
19019
|
else messages.push(`Try: token-goat outline ${filePath}`);
|
|
18794
|
-
throw new CliError(messages
|
|
19020
|
+
throw new CliError(messages);
|
|
18795
19021
|
}
|
|
18796
19022
|
out(extracted);
|
|
18797
19023
|
}
|
|
@@ -18801,8 +19027,8 @@ init_define_import_meta_env();
|
|
|
18801
19027
|
|
|
18802
19028
|
// src/cli_stats.ts
|
|
18803
19029
|
init_define_import_meta_env();
|
|
18804
|
-
import * as
|
|
18805
|
-
import * as
|
|
19030
|
+
import * as fs41 from "node:fs";
|
|
19031
|
+
import * as path37 from "node:path";
|
|
18806
19032
|
function writeRaw(text) {
|
|
18807
19033
|
const payload = colorStdout() ? text : stripAnsiEscapes(text);
|
|
18808
19034
|
process.stdout.write(ensureNewline(payload));
|
|
@@ -18814,7 +19040,7 @@ function formatTopFiles(ranked) {
|
|
|
18814
19040
|
if (ranked.length === 0) return "";
|
|
18815
19041
|
const lines = ["Top files this session:"];
|
|
18816
19042
|
for (const { path: filePath, count } of ranked) {
|
|
18817
|
-
const basename10 =
|
|
19043
|
+
const basename10 = path37.basename(filePath);
|
|
18818
19044
|
lines.push(` ${count.toString().padStart(3)}x ${basename10} (${filePath})`);
|
|
18819
19045
|
}
|
|
18820
19046
|
return lines.join("\n");
|
|
@@ -18832,11 +19058,11 @@ function renderTopSessionFiles(topN = 5) {
|
|
|
18832
19058
|
function renderTopSessionFilesFromDisk(topN = 5, overrideSessionsDir) {
|
|
18833
19059
|
try {
|
|
18834
19060
|
const dir = overrideSessionsDir ?? sessionsDir();
|
|
18835
|
-
if (!
|
|
18836
|
-
const files =
|
|
19061
|
+
if (!fs41.existsSync(dir)) return "";
|
|
19062
|
+
const files = fs41.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, mtime: fs41.statSync(path37.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).slice(0, 3);
|
|
18837
19063
|
for (const { name } of files) {
|
|
18838
19064
|
try {
|
|
18839
|
-
const raw =
|
|
19065
|
+
const raw = fs41.readFileSync(path37.join(dir, name), "utf-8");
|
|
18840
19066
|
const data = JSON.parse(raw);
|
|
18841
19067
|
const filesList = data["files"];
|
|
18842
19068
|
if (!Array.isArray(filesList)) continue;
|
|
@@ -18858,6 +19084,7 @@ var METHODOLOGY = {
|
|
|
18858
19084
|
billing: "They are not GitHub Copilot usage, provider-reported token consumption, or billing data.",
|
|
18859
19085
|
byte_derived_formula: "Most read, hook, and command entries go through savedTokensFromBytes in src/stats.ts, which is Math.round(bytes_saved / 4). Image entries are the exception: they are priced in visual tokens, not bytes.",
|
|
18860
19086
|
filter_estimates: "Output compressors record their filter-calculated delta, measured against what the harness would actually have delivered rather than the full command output. Image entries are priced in visual tokens (28x28-pixel patches, capped at the configured vision tier), because an image is not billed by its byte size; where the pixel dimensions are unavailable the tier ceiling is used.",
|
|
19087
|
+
read_command_baselines: "A read command is credited the bytes of what it replaced, less what it printed. Naming a file (read, section, outline and the rest) replaces reading that file whole, capped at 100,000 bytes per file, about what one Read returns before it truncates. A search over files the caller did not name (symbol NAME, semantic) replaces a search plus a read of the one file wanted, so it is credited the largest matched file under the same cap, not every match. refs is credited the one line per reference a plain text search prints, and changed the diff it stands in for; both are shell output, so both are first cut to what the harness would have delivered of it.",
|
|
18861
19088
|
advisory_events: "Zero-byte, zero-token advisory events show that guidance fired, not that an agent followed it.",
|
|
18862
19089
|
audit: "Use stats --full or stats --json for source and command breakdowns; reconcile billing with provider-exported usage data."
|
|
18863
19090
|
};
|
|
@@ -18873,6 +19100,7 @@ function renderMethodology(json = false) {
|
|
|
18873
19100
|
`\`tokens saved\` is a ${METHODOLOGY.estimate_scope.toLowerCase()} ${METHODOLOGY.billing}`,
|
|
18874
19101
|
"",
|
|
18875
19102
|
`- ${METHODOLOGY.byte_derived_formula}`,
|
|
19103
|
+
`- ${METHODOLOGY.read_command_baselines}`,
|
|
18876
19104
|
`- ${METHODOLOGY.filter_estimates}`,
|
|
18877
19105
|
`- ${METHODOLOGY.advisory_events}`,
|
|
18878
19106
|
`- ${METHODOLOGY.audit}`,
|
|
@@ -18971,6 +19199,19 @@ function getNewestSessionFiles() {
|
|
|
18971
19199
|
const filesArr = Array.isArray(raw["files"]) ? raw["files"] : [];
|
|
18972
19200
|
return { id: newest.id, sessionCount: blobs.length, filesArr };
|
|
18973
19201
|
}
|
|
19202
|
+
function emitHistoryOutput(allItems, limit, json, emptyMessage, printTable) {
|
|
19203
|
+
const sorted = allItems.sort((a, b) => b.storedAt - a.storedAt);
|
|
19204
|
+
const items = capAndNote(sorted, limit);
|
|
19205
|
+
if (json === true) {
|
|
19206
|
+
process.stdout.write(displaySafeJson(items) + "\n");
|
|
19207
|
+
return;
|
|
19208
|
+
}
|
|
19209
|
+
if (items.length === 0) {
|
|
19210
|
+
process.stdout.write(emptyMessage);
|
|
19211
|
+
return;
|
|
19212
|
+
}
|
|
19213
|
+
printTable(items);
|
|
19214
|
+
}
|
|
18974
19215
|
function cmdBashHistory(opts) {
|
|
18975
19216
|
const limit = parseLimitOpt("bash-history", opts.limit);
|
|
18976
19217
|
const blobs = listBlobs(BASH_OUTPUT_SUBDIR);
|
|
@@ -18985,24 +19226,17 @@ function cmdBashHistory(opts) {
|
|
|
18985
19226
|
exitCode: typeof v["exitCode"] === "number" ? v["exitCode"] : -1,
|
|
18986
19227
|
sizeBytes: typeof v["sizeBytes"] === "number" ? v["sizeBytes"] : 0
|
|
18987
19228
|
};
|
|
18988
|
-
}).filter((x) => x !== null)
|
|
18989
|
-
|
|
18990
|
-
|
|
18991
|
-
process.stdout.write(displaySafeJson(items) + "\n");
|
|
18992
|
-
return;
|
|
18993
|
-
}
|
|
18994
|
-
if (items.length === 0) {
|
|
18995
|
-
process.stdout.write("No bash output entries cached.\n");
|
|
18996
|
-
return;
|
|
18997
|
-
}
|
|
18998
|
-
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} ${pad("exit", 4)} command
|
|
19229
|
+
}).filter((x) => x !== null);
|
|
19230
|
+
emitHistoryOutput(allItems, limit, opts.json, "No bash output entries cached.\n", (items) => {
|
|
19231
|
+
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} ${pad("exit", 4)} command
|
|
18999
19232
|
`);
|
|
19000
|
-
|
|
19001
|
-
|
|
19002
|
-
|
|
19003
|
-
|
|
19233
|
+
for (const item of items) {
|
|
19234
|
+
const flatCommand = displaySafeText(item.command);
|
|
19235
|
+
const preview = flatCommand.length > 80 ? flatCommand.slice(0, 77) + "..." : flatCommand;
|
|
19236
|
+
process.stdout.write(`${pad(displaySafeText(item.id), 18)} ${pad(String(item.sizeBytes), 8)} ${pad(String(item.exitCode), 4)} ${preview}
|
|
19004
19237
|
`);
|
|
19005
|
-
|
|
19238
|
+
}
|
|
19239
|
+
});
|
|
19006
19240
|
}
|
|
19007
19241
|
function cmdWebHistory(opts) {
|
|
19008
19242
|
const limit = parseLimitOpt("web-history", opts.limit);
|
|
@@ -19016,22 +19250,15 @@ function cmdWebHistory(opts) {
|
|
|
19016
19250
|
bytes: typeof v["content"] === "string" ? Buffer.byteLength(v["content"], "utf8") : 0,
|
|
19017
19251
|
storedAt: mtime
|
|
19018
19252
|
};
|
|
19019
|
-
}).filter((x) => x !== null)
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
process.stdout.write(displaySafeJson(items) + "\n");
|
|
19023
|
-
return;
|
|
19024
|
-
}
|
|
19025
|
-
if (items.length === 0) {
|
|
19026
|
-
process.stdout.write("No web output entries cached.\n");
|
|
19027
|
-
return;
|
|
19028
|
-
}
|
|
19029
|
-
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} url
|
|
19253
|
+
}).filter((x) => x !== null);
|
|
19254
|
+
emitHistoryOutput(allItems, limit, opts.json, "No web output entries cached.\n", (items) => {
|
|
19255
|
+
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} url
|
|
19030
19256
|
`);
|
|
19031
|
-
|
|
19032
|
-
|
|
19257
|
+
for (const item of items) {
|
|
19258
|
+
process.stdout.write(`${pad(displaySafeText(item.id), 18)} ${pad(String(item.bytes), 8)} ${displaySafeText(item.url)}
|
|
19033
19259
|
`);
|
|
19034
|
-
|
|
19260
|
+
}
|
|
19261
|
+
});
|
|
19035
19262
|
}
|
|
19036
19263
|
function cmdMcpHistory(opts) {
|
|
19037
19264
|
const limit = parseLimitOpt("mcp-history", opts.limit);
|
|
@@ -19047,22 +19274,15 @@ function cmdMcpHistory(opts) {
|
|
|
19047
19274
|
storedAt: typeof v["storedAt"] === "number" ? v["storedAt"] : mtime,
|
|
19048
19275
|
sizeBytes: typeof v["sizeBytes"] === "number" ? v["sizeBytes"] : 0
|
|
19049
19276
|
};
|
|
19050
|
-
}).filter((x) => x !== null)
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
process.stdout.write(displaySafeJson(items) + "\n");
|
|
19054
|
-
return;
|
|
19055
|
-
}
|
|
19056
|
-
if (items.length === 0) {
|
|
19057
|
-
process.stdout.write("No mcp output entries cached.\n");
|
|
19058
|
-
return;
|
|
19059
|
-
}
|
|
19060
|
-
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} tool
|
|
19277
|
+
}).filter((x) => x !== null);
|
|
19278
|
+
emitHistoryOutput(allItems, limit, opts.json, "No mcp output entries cached.\n", (items) => {
|
|
19279
|
+
process.stdout.write(`${pad("id", 18)} ${pad("bytes", 8)} tool
|
|
19061
19280
|
`);
|
|
19062
|
-
|
|
19063
|
-
|
|
19281
|
+
for (const item of items) {
|
|
19282
|
+
process.stdout.write(`${pad(displaySafeText(item.id), 18)} ${pad(String(item.sizeBytes), 8)} ${displaySafeText(item.toolName)}
|
|
19064
19283
|
`);
|
|
19065
|
-
|
|
19284
|
+
}
|
|
19285
|
+
});
|
|
19066
19286
|
}
|
|
19067
19287
|
function cmdCleanCache(opts) {
|
|
19068
19288
|
const removed = {};
|
|
@@ -19296,7 +19516,7 @@ function registerSessionCommands(program2, guard) {
|
|
|
19296
19516
|
})
|
|
19297
19517
|
)
|
|
19298
19518
|
);
|
|
19299
|
-
program2.command("capabilities").description("report every capability that can send data off this machine, and its current state").option("-j, --json", "emit as JSON, for asserting on in a pipeline").action(
|
|
19519
|
+
program2.command("capabilities").description("report every capability that can send data off this machine, leave data on it, or listen for other processes on it, and its current state").option("-j, --json", "emit as JSON, for asserting on in a pipeline").action(
|
|
19300
19520
|
guard((opts) => {
|
|
19301
19521
|
const caps = collectCapabilities();
|
|
19302
19522
|
console.log(opts.json ? displaySafeJson({ version: VERSION, capabilities: caps }) : renderCapabilities(caps));
|
|
@@ -19309,10 +19529,17 @@ function registerSessionCommands(program2, guard) {
|
|
|
19309
19529
|
program2.command("audit").description("session retrospective: analyze the current session transcript (Copilot CLI or Claude Code) and emit a Maintainer Feedback Card").option("--project <path>", "project root to analyze").option("--transcript <path>", "explicit transcript path (default: active or newest session for this project)").option("-j, --json", "output as JSON").action(guard(cmdAudit));
|
|
19310
19530
|
program2.command("session-outline [session-id-or-path]").description("turn-by-turn structure (role, preview, tool calls, approx size) of a Claude Code session JSONL transcript, instead of a raw Read; defaults to the current project's most recent session").option("--project <path>", "project root to resolve the session transcript against").option("--json", "output JSON").action(guard(cmdSessionOutline));
|
|
19311
19531
|
program2.command("session-slice [session-id-or-path]").description("full content of one turn range from a Claude Code session JSONL transcript (see session-outline for turn numbers), instead of a raw Read").requiredOption("--range <spec>", "turn range, e.g. 5-9 or 12 (see session-outline for turn numbers)").option("--project <path>", "project root to resolve the session transcript against").option("--json", "output JSON").action(guard(cmdSessionSlice));
|
|
19312
|
-
program2.command("session-audit").alias("audit-session").description("corpus-wide token attribution across every local Claude Code session transcript: measured billed usage, estimated content size by source and by tool, and billed cost by session position (aggregate counts only, never transcript content)").option("--dir <path>", "transcript corpus root to scan (default: ~/.claude/projects)").option("--json", "output JSON").action(guard(
|
|
19532
|
+
program2.command("session-audit").alias("audit-session").description("corpus-wide token attribution across every local Claude Code session transcript: measured billed usage, estimated content size by source and by tool, and billed cost by session position (aggregate counts only, never transcript content)").option("--dir <path>", "transcript corpus root to scan (default: ~/.claude/projects)").option("--window-days <days>", "only transcripts whose file was modified in the last N days (0 = all time)", "0").option("--tool-errors", "print only the failed-tool-call report: calls, errors, expected failures by reason and unknown ones, per tool and per model, with the top unknown error prefixes").option("--json", "output JSON").action(guard(
|
|
19533
|
+
(opts) => cmdSessionAudit({
|
|
19534
|
+
...opts.dir !== void 0 ? { dir: opts.dir } : {},
|
|
19535
|
+
...opts.json === true ? { json: true } : {},
|
|
19536
|
+
...opts.toolErrors === true ? { toolErrors: true } : {},
|
|
19537
|
+
windowDays: requireNonNegativeInt("--window-days", opts.windowDays)
|
|
19538
|
+
})
|
|
19539
|
+
));
|
|
19313
19540
|
program2.command("mcp-audit").description("MCP server schema cost-vs-usage report: estimate per-server token cost from cached tool calls").option("--project <path>", "project root to analyze").option("--json", "output JSON").action(guard(cmdMcpAudit));
|
|
19314
19541
|
program2.command("recall [query]").description("search across every cached bash-output, web-output, and mcp-output entry (full-text); with no query, list them newest-first").option("--type <type>", "filter to one cache type: bash, web, or mcp").option("--limit <n>", "max results to return (default: 10)").option("--json", "output JSON").action(guard(cmdRecall));
|
|
19315
|
-
program2.command("hint-stats").description("per-category efficacy report for token-goat's discretionary hint hooks (emitted/acted-on/suppression)").option("--json", "output JSON").option("--reset", "clear all tracked emissions and manual marks").option("--mark-effective <category>", 'record a manual "effective" vote for a hint category').option("--mark-ineffective <category>", 'record a manual "ineffective" vote for a hint category').action(guard(cmdHintStats));
|
|
19542
|
+
program2.command("hint-stats").description("per-category efficacy report for token-goat's discretionary hint hooks (emitted/acted-on/suppression); all-time unless --session-id narrows it").option("--json", "output JSON").option("--session-id <id>", "scope emission counts, efficacy and spend to one session id (or `latest`); suppression and manual marks stay all-time, and saved-bytes has no per-session figure").option("--reset", "clear all tracked emissions and manual marks").option("--mark-effective <category>", 'record a manual "effective" vote for a hint category').option("--mark-ineffective <category>", 'record a manual "ineffective" vote for a hint category').action(guard(cmdHintStats));
|
|
19316
19543
|
program2.command("statusline").description("render one line of terminal status text from a harness statusline payload on stdin (Claude Code statusLine.command)").option("--json", "emit the underlying data as JSON instead of a rendered line (debug)").action(guard(cmdStatusline));
|
|
19317
19544
|
program2.command("skill-body <name>").description("retrieve a skill's cached body").option("-c, --compact", "print compact slice instead of full body").action(guard(cmdSkillBody));
|
|
19318
19545
|
program2.command("skill-compact [name]").description("regenerate and cache compact slice for a skill").option("--path <file>", "read the skill body from this file instead of resolving by name").option("--all", "regenerate compacts for all skills, skipping fresh ones").action(guard(cmdSkillCompact));
|
|
@@ -19388,11 +19615,44 @@ function registerSessionCommands(program2, guard) {
|
|
|
19388
19615
|
program2.command("describe [target] [table]").description("describe columns and structure of a session store table or SQLite database file instead of querying SELECT *").option("-j, --json", "output as JSON").action(guard(cmdDescribe));
|
|
19389
19616
|
}
|
|
19390
19617
|
|
|
19618
|
+
// src/cli_hook_server.ts
|
|
19619
|
+
init_define_import_meta_env();
|
|
19620
|
+
async function cmdHookServerRun(opts) {
|
|
19621
|
+
const slot = Number(opts.slot ?? "0");
|
|
19622
|
+
const { runHookServer } = await import("./token-goat-chunk-ORNFMIER.mjs");
|
|
19623
|
+
try {
|
|
19624
|
+
await runHookServer(slot, (argv) => run(argv));
|
|
19625
|
+
} catch (e) {
|
|
19626
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
19627
|
+
touchMarker("failed", `slot ${slot}: ${message}`);
|
|
19628
|
+
throw new CliError(message);
|
|
19629
|
+
}
|
|
19630
|
+
}
|
|
19631
|
+
function formatHookServerStatus(s, now = Date.now()) {
|
|
19632
|
+
return `slot ${s.slot}: pid ${s.pid}, v${s.version}, up ${formatAge(now - s.startedAt)}, served ${s.served}, errors ${s.errors}, idle ${formatAge(now - s.lastUsedAt)}`;
|
|
19633
|
+
}
|
|
19634
|
+
async function cmdHookServerStatus(opts) {
|
|
19635
|
+
const statuses = await serverStatuses();
|
|
19636
|
+
if (opts.json === true) {
|
|
19637
|
+
out(displaySafeJson(statuses));
|
|
19638
|
+
return;
|
|
19639
|
+
}
|
|
19640
|
+
if (statuses.length === 0) {
|
|
19641
|
+
out("No hook server is running. The next hook call starts one.");
|
|
19642
|
+
return;
|
|
19643
|
+
}
|
|
19644
|
+
for (const s of statuses) out(formatHookServerStatus(s));
|
|
19645
|
+
}
|
|
19646
|
+
async function cmdHookServerStop() {
|
|
19647
|
+
const stopped = await queryServers("stop");
|
|
19648
|
+
out(stopped.length === 0 ? "No hook server is running." : `Stopped ${stopped.length} hook server${stopped.length === 1 ? "" : "s"}.`);
|
|
19649
|
+
}
|
|
19650
|
+
|
|
19391
19651
|
// src/bridges_status.ts
|
|
19392
19652
|
init_define_import_meta_env();
|
|
19393
19653
|
var NO_SERVER_HANDLER_REASON = "token-goat has no registered server-side handler for this event (zero registerHook('notification'|'stop', ...) call sites in src/) -- wiring it client-side would currently be a no-op";
|
|
19394
19654
|
var NO_POST_COMPACT_EVENT_REASON = "post_compact is a Claude Code event (hook_event_name PostCompact, carrying compact_summary); no equivalent has been confirmed for this harness, so it is left unwired rather than guessed at";
|
|
19395
|
-
var NO_SEPARATE_FAILURE_EVENT_REASON = "post_tool_use_failure exists because Copilot CLI
|
|
19655
|
+
var NO_SEPARATE_FAILURE_EVENT_REASON = "post_tool_use_failure exists because Copilot CLI (postToolUseFailure) and Claude Code (PostToolUseFailure) route a failed tool result to a separate event instead of their post-tool one. No separate failure event is wired for this harness, so a failed tool call either arrives on post_tool_use like any other result or is not seen; which of the two has not been checked here";
|
|
19396
19656
|
var COPILOT_NO_POST_COMPACT_REASON = "Copilot CLI has no post-compaction hook: its HookType enum (schemas/api.schema.json, 1.0.79 and 1.0.80) declares preCompact and no postCompact, and both preCompact call sites in app.js await the hook and never assign its result. Whether the summary is reachable another way is open. app.js does emit session.compaction_complete carrying summaryContent, and the session event writer subscribes to '*' -- but emit() vs emitEphemeral() does NOT gate that writer: dispatchEventHandlers runs outside the ephemeral branch in emitInternal, on('*') early-returns past every filter, and the writer's callback applies no filter of its own before handing the JSON to native recordEventJson. The durable-vs-ephemeral decision is in Rust (api_session_event_writer.rs) and was not readable. Nor is the event uniformly summary-bearing: two of the four emit sites are the branches taken when no summary exists, summaryContent is optional in the schema, and the relay session class emits the same event via emitEphemeral. No compaction has ever been observed on the machines checked, so nothing empirical anchors any of it. Context can be written back on the next turn through userPromptSubmitted additionalContext";
|
|
19397
19657
|
var VERIFICATION_RANK = {
|
|
19398
19658
|
dogfooded: 0,
|
|
@@ -19411,9 +19671,8 @@ var BRIDGE_CAPABILITY_MATRIX = [
|
|
|
19411
19671
|
sourceFile: "src/install.ts (HOOK_EVENT_MAP)",
|
|
19412
19672
|
verification: "dogfooded",
|
|
19413
19673
|
verificationNote: "The harness this repo is developed and released under; CLAUDE.md requires every CLI/hook change be run against the built binary here before it ships.",
|
|
19414
|
-
implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "pre_compact", "post_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
|
|
19674
|
+
implemented: /* @__PURE__ */ new Set(["pre_tool_use", "post_tool_use", "post_tool_use_failure", "pre_compact", "post_compact", "user_prompt_submit", "subagent_stop", "session_start"]),
|
|
19415
19675
|
reasons: [
|
|
19416
|
-
{ events: ["post_tool_use_failure"], reason: NO_SEPARATE_FAILURE_EVENT_REASON },
|
|
19417
19676
|
{ events: ["notification", "stop"], reason: NO_SERVER_HANDLER_REASON }
|
|
19418
19677
|
]
|
|
19419
19678
|
},
|
|
@@ -19450,55 +19709,7 @@ var BRIDGE_CAPABILITY_MATRIX = [
|
|
|
19450
19709
|
}
|
|
19451
19710
|
]
|
|
19452
19711
|
},
|
|
19453
|
-
/**
|
|
19454
|
-
* What Copilot CLI's wired events can actually carry, read from the shipping 1.0.80 bundle
|
|
19455
|
-
* rather than from its hooks reference page. A row's `implemented` set says an event is wired;
|
|
19456
|
-
* it deliberately says nothing about how much of that event's response the harness honors, and
|
|
19457
|
-
* for Copilot the difference matters:
|
|
19458
|
-
*
|
|
19459
|
-
* - `pre_tool_use` deny is real, and the reason text reaches the model. The native string table
|
|
19460
|
-
* (runtime.node offset 98057208) carries `permissionDecision`, `permissionDecisionReason`, the
|
|
19461
|
-
* default "No reason provided." and the formatter "Denied by preToolUse hook: " as distinct
|
|
19462
|
-
* literals, and app.js sets `{textResultForLlm: reason, resultType: "denied"}` per denial and
|
|
19463
|
-
* filters that call out of execution. This was previously only an inference drawn from an
|
|
19464
|
-
* incident comment; it is now confirmed. The fail-closed "(hook errored)" deny-all strings sit
|
|
19465
|
-
* beside these, so that incident was behavior layered on top of a working deny handler, not a
|
|
19466
|
-
* substitute for one.
|
|
19467
|
-
* - `post_tool_use` honors `modifiedResult`, so compression, injection fencing and image shrink
|
|
19468
|
-
* do reach the model: `postToolExecution` (app.js offset 2043150) assigns the returned
|
|
19469
|
-
* `toolResultJson` onto the tool result in place.
|
|
19470
|
-
* - `post_tool_use` drops `additionalContext` on the JS path -- no supplier for the
|
|
19471
|
-
* `onAdditionalContext` callback anywhere in the bundle, and no `additional_contexts` key in
|
|
19472
|
-
* that event's native return payload, unlike its pre-tool sibling. Whether native folds it
|
|
19473
|
-
* into the returned result instead was not verified.
|
|
19474
|
-
* - Failed tool calls never reach `post_tool_use` at all. Copilot routes them to a separate
|
|
19475
|
-
* `postToolUseFailure` event, which is handed only a stringified error and honors only
|
|
19476
|
-
* `additionalContext`; `modifiedResult` is documented as not honored there. So on Copilot the
|
|
19477
|
-
* output of a failed tool call reaches the model unfenced, uncompressed and unshrunk, and no
|
|
19478
|
-
* response shape token-goat's shim can emit changes that. Known gap, deliberately recorded.
|
|
19479
|
-
* What `additionalContext` does on that event is no longer doc-derived: app.js offset 2043380
|
|
19480
|
-
* reads the native processor's return and, when it carries `additionalContext`, either folds
|
|
19481
|
-
* it into `textResultForLlm` (if `appendFailureContextToToolResult` is set) or formats it and
|
|
19482
|
-
* pushes `{content, source: "system"}` onto `toolResult.newMessages`. So the channel is real
|
|
19483
|
-
* and model-visible -- it just carries advice alongside the failure, never a replacement for
|
|
19484
|
-
* it. It is wired now, as its own `post_tool_use_failure` event rather than a reuse of
|
|
19485
|
-
* `post_tool_use`: routing failures through the success event would let success-path handlers
|
|
19486
|
-
* mark a file as successfully read when the read failed. Because the channel spends tokens
|
|
19487
|
-
* instead of saving them, its handler (`src/hooks_tool_failure.ts`) stays silent on a first
|
|
19488
|
-
* failure and speaks only on an exact repeat.
|
|
19489
|
-
* - `pre_compact` is wired and fires, but nothing it returns can reach the model. Both dispatch
|
|
19490
|
-
* sites call it in statement position and drop the result: app.js offset 2467452 (the manual
|
|
19491
|
-
* `/compact` path) and offset 2571216 (`case "execute_pre_compact_hook"`). The contrast is
|
|
19492
|
-
* what makes this conclusive rather than an absence of evidence -- the same `event()` runner's
|
|
19493
|
-
* return IS read for other events, e.g. `notification` at offset 2296123 assigns it and
|
|
19494
|
-
* forwards `additionalContext` as a prepended system prompt. The compaction prompt is then
|
|
19495
|
-
* built from session history and the user's own focus text, with no hook channel into it.
|
|
19496
|
-
* So token-goat's `pre_compact` registration here is observe-only by construction, not merely
|
|
19497
|
-
* unused: a future attempt to inject a session manifest through it would silently do nothing.
|
|
19498
|
-
* Not verified: whether the native declarative runner applies `additionalContext` itself. The
|
|
19499
|
-
* trail ends in stripped Rust. That it would make the explicit JS handling for `notification`
|
|
19500
|
-
* and `userPromptSubmitted` redundant is an argument, not a proof.
|
|
19501
|
-
*/
|
|
19712
|
+
/** What Copilot CLI's wired events can actually carry, read from the shipping 1.0.80 bundle rather than from its hooks reference page. A row's `implemented` set says an event is wired; it deliberately says nothing about how much of that event's response the harness honors, and for Copilot the difference matters: - `pre_tool_use` deny is real, and the reason text reaches the model. The native string table (runtime.node offset 98057208) carries `permissionDecision`, `permissionDecisionReason`, the default "No reason provided." and the formatter "Denied by preToolUse hook: " as distinct literals, and app.js sets `{textResultForLlm: reason, resultType: "denied"}` per denial and filters that call out of execution. This was previously only an inference drawn from an incident comment; it is now confirmed. The fail-closed "(hook errored)" deny-all strings sit beside these, so that incident was behavior layered on top of a working deny handler, not a substitute for one. - `post_tool_use` honors `modifiedResult`, so compression, injection fencing and image shrink do reach the model: `postToolExecution` (app.js offset 2043150) assigns the returned `toolResultJson` onto the tool result in place. - `post_tool_use` drops `additionalContext` on the JS path -- no supplier for the `onAdditionalContext` callback anywhere in the bundle, and no `additional_contexts` key in that event's native return payload, unlike its pre-tool sibling. Whether native folds it into the returned result instead was not verified. - Failed tool calls never reach `post_tool_use` at all. Copilot routes them to a separate `postToolUseFailure` event, which is handed only a stringified error and honors only `additionalContext`; `modifiedResult` is documented as not honored there. So on Copilot the output of a failed tool call reaches the model unfenced, uncompressed and unshrunk, and no response shape token-goat's shim can emit changes that. Known gap, deliberately recorded. What `additionalContext` does on that event is no longer doc-derived: app.js offset 2043380 reads the native processor's return and, when it carries `additionalContext`, either folds it into `textResultForLlm` (if `appendFailureContextToToolResult` is set) or formats it and pushes `{content, source: "system"}` onto `toolResult.newMessages`. So the channel is real and model-visible -- it just carries advice alongside the failure, never a replacement for it. It is wired now, as its own `post_tool_use_failure` event rather than a reuse of `post_tool_use`: routing failures through the success event would let success-path handlers mark a file as successfully read when the read failed. Because the channel spends tokens instead of saving them, its handler (`src/hooks_tool_failure.ts`) stays silent on a first failure and speaks only on an exact repeat. - `pre_compact` is wired and fires, but nothing it returns can reach the model. Both dispatch sites call it in statement position and drop the result: app.js offset 2467452 (the manual `/compact` path) and offset 2571216 (`case "execute_pre_compact_hook"`). The contrast is what makes this conclusive rather than an absence of evidence -- the same `event()` runner's return IS read for other events, e.g. `notification` at offset 2296123 assigns it and forwards `additionalContext` as a prepended system prompt. The compaction prompt is then built from session history and the user's own focus text, with no hook channel into it. So token-goat's `pre_compact` registration here is observe-only by construction, not merely unused: a future attempt to inject a session manifest through it would silently do nothing. Not verified: whether the native declarative runner applies `additionalContext` itself. The trail ends in stripped Rust. That it would make the explicit JS handling for `notification` and `userPromptSubmitted` redundant is an argument, not a proof. */
|
|
19502
19713
|
{
|
|
19503
19714
|
harness: "copilot_cli",
|
|
19504
19715
|
label: "Copilot CLI",
|
|
@@ -19723,25 +19934,25 @@ function installVerificationNotice(harness) {
|
|
|
19723
19934
|
|
|
19724
19935
|
// src/purge.ts
|
|
19725
19936
|
init_define_import_meta_env();
|
|
19726
|
-
import * as
|
|
19727
|
-
import * as
|
|
19937
|
+
import * as fs42 from "node:fs";
|
|
19938
|
+
import * as path38 from "node:path";
|
|
19728
19939
|
function directorySize(root) {
|
|
19729
19940
|
let total = 0;
|
|
19730
19941
|
let entries;
|
|
19731
19942
|
try {
|
|
19732
|
-
entries =
|
|
19943
|
+
entries = fs42.readdirSync(root, { withFileTypes: true });
|
|
19733
19944
|
} catch {
|
|
19734
19945
|
return 0;
|
|
19735
19946
|
}
|
|
19736
19947
|
for (const entry of entries) {
|
|
19737
|
-
const full =
|
|
19948
|
+
const full = path38.join(root, entry.name);
|
|
19738
19949
|
if (entry.isDirectory()) {
|
|
19739
19950
|
total += directorySize(full);
|
|
19740
19951
|
continue;
|
|
19741
19952
|
}
|
|
19742
19953
|
if (!entry.isFile()) continue;
|
|
19743
19954
|
try {
|
|
19744
|
-
total +=
|
|
19955
|
+
total += fs42.statSync(full).size;
|
|
19745
19956
|
} catch {
|
|
19746
19957
|
}
|
|
19747
19958
|
}
|
|
@@ -19760,7 +19971,7 @@ function purgeDataDirectories() {
|
|
|
19760
19971
|
}
|
|
19761
19972
|
const bytes = directorySize(root);
|
|
19762
19973
|
try {
|
|
19763
|
-
|
|
19974
|
+
fs42.rmSync(root, { recursive: true, force: true });
|
|
19764
19975
|
result.removed.push({ path: root, bytes });
|
|
19765
19976
|
} catch (e) {
|
|
19766
19977
|
result.failed.push({ path: root, reason: e instanceof Error ? e.message : String(e) });
|
|
@@ -19907,8 +20118,8 @@ async function getSectionContent(fileId, heading, opts = {}) {
|
|
|
19907
20118
|
|
|
19908
20119
|
// src/cli_bench.ts
|
|
19909
20120
|
init_define_import_meta_env();
|
|
19910
|
-
import * as
|
|
19911
|
-
import * as
|
|
20121
|
+
import * as fs43 from "node:fs";
|
|
20122
|
+
import * as path39 from "node:path";
|
|
19912
20123
|
var ControlFilter = class extends ToolFilter {
|
|
19913
20124
|
constructor(name, transform) {
|
|
19914
20125
|
super();
|
|
@@ -19929,13 +20140,13 @@ var CONTROL_FILTERS = {
|
|
|
19929
20140
|
};
|
|
19930
20141
|
var MAX_BENCH_FILE_BYTES = 5 * 1024 * 1024;
|
|
19931
20142
|
function readCaseFile(id, filePath, what) {
|
|
19932
|
-
const bytes =
|
|
20143
|
+
const bytes = fs43.statSync(filePath).size;
|
|
19933
20144
|
if (bytes > MAX_BENCH_FILE_BYTES) {
|
|
19934
20145
|
throw new Error(
|
|
19935
20146
|
`bench case ${id}: ${what} is ${bytes} bytes, over the ${MAX_BENCH_FILE_BYTES}-byte limit for a corpus file (${filePath})`
|
|
19936
20147
|
);
|
|
19937
20148
|
}
|
|
19938
|
-
return
|
|
20149
|
+
return fs43.readFileSync(filePath, "utf8");
|
|
19939
20150
|
}
|
|
19940
20151
|
function parseCase(id, metaPath, outputPath) {
|
|
19941
20152
|
const metaText = readCaseFile(id, metaPath, "metadata");
|
|
@@ -19970,7 +20181,7 @@ function parseCase(id, metaPath, outputPath) {
|
|
|
19970
20181
|
function loadCorpus(dir) {
|
|
19971
20182
|
let entries;
|
|
19972
20183
|
try {
|
|
19973
|
-
entries =
|
|
20184
|
+
entries = fs43.readdirSync(dir);
|
|
19974
20185
|
} catch {
|
|
19975
20186
|
throw new Error(`bench corpus not found: ${dir}`);
|
|
19976
20187
|
}
|
|
@@ -19978,9 +20189,9 @@ function loadCorpus(dir) {
|
|
|
19978
20189
|
for (const entry of entries.sort()) {
|
|
19979
20190
|
if (!entry.endsWith(".json")) continue;
|
|
19980
20191
|
const id = entry.slice(0, -".json".length);
|
|
19981
|
-
const outputPath =
|
|
19982
|
-
if (!
|
|
19983
|
-
cases.push(parseCase(id,
|
|
20192
|
+
const outputPath = path39.join(dir, `${id}.txt`);
|
|
20193
|
+
if (!fs43.existsSync(outputPath)) throw new Error(`bench case ${id}: missing output file ${outputPath}`);
|
|
20194
|
+
cases.push(parseCase(id, path39.join(dir, entry), outputPath));
|
|
19984
20195
|
}
|
|
19985
20196
|
if (cases.length === 0) throw new Error(`bench corpus is empty: ${dir}`);
|
|
19986
20197
|
return cases;
|
|
@@ -20100,10 +20311,10 @@ function appendTsv(file, report, commit) {
|
|
|
20100
20311
|
report.mustKeepTotal,
|
|
20101
20312
|
report.coveredFilters
|
|
20102
20313
|
].join(" ");
|
|
20103
|
-
const dir =
|
|
20104
|
-
|
|
20105
|
-
const header =
|
|
20106
|
-
|
|
20314
|
+
const dir = path39.dirname(path39.resolve(file));
|
|
20315
|
+
fs43.mkdirSync(dir, { recursive: true });
|
|
20316
|
+
const header = fs43.existsSync(file) ? "" : TSV_HEADER;
|
|
20317
|
+
fs43.appendFileSync(file, header + row + "\n", "utf8");
|
|
20107
20318
|
}
|
|
20108
20319
|
function currentCommit(cwd) {
|
|
20109
20320
|
const opts = cwd === void 0 ? {} : { cwd };
|
|
@@ -20130,7 +20341,16 @@ function runBenchCommand(opts) {
|
|
|
20130
20341
|
|
|
20131
20342
|
// src/cli.ts
|
|
20132
20343
|
var CliError = class extends Error {
|
|
20344
|
+
lines;
|
|
20345
|
+
constructor(message) {
|
|
20346
|
+
super(typeof message === "string" ? message : message.join("\n"));
|
|
20347
|
+
this.lines = typeof message === "string" ? void 0 : message;
|
|
20348
|
+
}
|
|
20133
20349
|
};
|
|
20350
|
+
function formatCommandError(e) {
|
|
20351
|
+
if (e instanceof CliError && e.lines !== void 0) return "token-goat: " + e.lines.map(displaySafeText).join("\n");
|
|
20352
|
+
return "token-goat: " + displaySafeText(extractErrorMessage(e));
|
|
20353
|
+
}
|
|
20134
20354
|
function out(text) {
|
|
20135
20355
|
const payload = colorStdout() ? text : stripAnsiEscapes(text);
|
|
20136
20356
|
process.stdout.write(ensureNewline(payload));
|
|
@@ -20143,10 +20363,10 @@ function readBoundedText(text, file) {
|
|
|
20143
20363
|
if (text === void 0 && file === void 0) throw new CliError("provide text or --file");
|
|
20144
20364
|
let value;
|
|
20145
20365
|
if (file !== void 0) {
|
|
20146
|
-
if (
|
|
20366
|
+
if (fs44.statSync(file).size > CONTENT_MAX_INPUT_CHARS) {
|
|
20147
20367
|
throw new CliError(`file exceeds the ${CONTENT_MAX_INPUT_CHARS}-byte safety limit`);
|
|
20148
20368
|
}
|
|
20149
|
-
value =
|
|
20369
|
+
value = fs44.readFileSync(file, "utf8");
|
|
20150
20370
|
} else {
|
|
20151
20371
|
if (text === void 0) throw new CliError("provide text or --file");
|
|
20152
20372
|
value = text;
|
|
@@ -20191,19 +20411,23 @@ function cmdHandoffResolve(name, opts) {
|
|
|
20191
20411
|
if (result === null) throw new CliError(`no local handoff named "${name}" in this project`);
|
|
20192
20412
|
out(typeof result === "string" ? result : formatCompression(result, false, "payload withheld: inlining it would cost more tokens than the original text; pass --full to get the original text back outright"));
|
|
20193
20413
|
}
|
|
20194
|
-
async function cmdSemantic(query, opts) {
|
|
20414
|
+
async function cmdSemantic(query, more, opts) {
|
|
20195
20415
|
if (!query && !opts.preflight && !opts.warm) {
|
|
20196
20416
|
throw new CliError("missing required argument: query");
|
|
20197
20417
|
}
|
|
20418
|
+
if (opts.preflight === true && more.length > 0) {
|
|
20419
|
+
throw new CliError("--preflight checks the embedding setup and runs no query; drop the queries, or drop --preflight to search");
|
|
20420
|
+
}
|
|
20198
20421
|
const limit = opts.limit !== void 0 ? requireNonNegativeInt("--limit", opts.limit) : 20;
|
|
20199
|
-
const
|
|
20422
|
+
const semanticOpts = {
|
|
20200
20423
|
limit,
|
|
20201
20424
|
...opts.json === true ? { json: true } : {},
|
|
20202
20425
|
...opts.grep !== void 0 ? { grep: opts.grep } : {},
|
|
20203
20426
|
...opts.excludeTests === true ? { excludeTests: true } : {},
|
|
20204
20427
|
...opts.preflight === true ? { preflight: true } : {},
|
|
20205
20428
|
...opts.warm === true ? { warm: true } : {}
|
|
20206
|
-
}
|
|
20429
|
+
};
|
|
20430
|
+
const { text, code } = more.length > 0 ? await runSemanticMulti([query ?? "", ...more], semanticOpts) : await runSemantic(query ?? "", semanticOpts);
|
|
20207
20431
|
(opts.json === true || code === 0 ? out : err)(text);
|
|
20208
20432
|
process.exitCode = code;
|
|
20209
20433
|
}
|
|
@@ -20269,7 +20493,7 @@ async function cmdIndex(pathArg, opts = {}) {
|
|
|
20269
20493
|
continue;
|
|
20270
20494
|
}
|
|
20271
20495
|
const sha = fingerprintFile(key);
|
|
20272
|
-
if (sha === null && !
|
|
20496
|
+
if (sha === null && !fs44.existsSync(key)) continue;
|
|
20273
20497
|
recordKnownRootThrottled(key, dataDir(), dbPath);
|
|
20274
20498
|
const entry = sha !== null ? getFileEntry(key, dbPath) : null;
|
|
20275
20499
|
const spellingStale = entry !== null && indexedPathSpellingIsStale(entry.filePath, key);
|
|
@@ -20306,7 +20530,7 @@ async function cmdIndex(pathArg, opts = {}) {
|
|
|
20306
20530
|
}
|
|
20307
20531
|
continue;
|
|
20308
20532
|
}
|
|
20309
|
-
if (!
|
|
20533
|
+
if (!fs44.existsSync(key)) continue;
|
|
20310
20534
|
}
|
|
20311
20535
|
const embedFresh = parseUnchanged ? embedUnchanged : embedFreshFor(getFileEntry(key, dbPath)?.embedSha);
|
|
20312
20536
|
if (!embedFresh) {
|
|
@@ -20367,7 +20591,7 @@ async function cmdMcpServe() {
|
|
|
20367
20591
|
let StdioServerTransport;
|
|
20368
20592
|
try {
|
|
20369
20593
|
;
|
|
20370
|
-
({ createMcpServer } = await import("./token-goat-chunk-
|
|
20594
|
+
({ createMcpServer } = await import("./token-goat-chunk-PKRWMHVP.mjs"));
|
|
20371
20595
|
({ StdioServerTransport } = await import("./token-goat-chunk-EVC4TOLE.mjs"));
|
|
20372
20596
|
} catch (err2) {
|
|
20373
20597
|
process.stderr.write(
|
|
@@ -20392,11 +20616,11 @@ async function cmdHook(event, opts) {
|
|
|
20392
20616
|
if (typeof opts.harness === "string" && opts.harness.length > 0) {
|
|
20393
20617
|
process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
|
|
20394
20618
|
}
|
|
20395
|
-
const { relay } = await import("./token-goat-chunk-
|
|
20619
|
+
const { relay } = await import("./token-goat-chunk-Z6KBMOBI.mjs");
|
|
20396
20620
|
await relay(event);
|
|
20397
20621
|
}
|
|
20398
20622
|
function projectHooksCommitNote(pathFiles, hooksConfigPath) {
|
|
20399
|
-
const shim = hooksConfigPath === void 0 ? "" : ` (${displaySafePath(
|
|
20623
|
+
const shim = hooksConfigPath === void 0 ? "" : ` (${displaySafePath(path40.join(path40.dirname(hooksConfigPath), HOOKS_SCRIPT_FILE))} is generated with them)`;
|
|
20400
20624
|
return `Note: ${pathFiles.map((p) => displaySafePath(p)).join(", ")} ${pathFiles.length === 1 ? "holds" : "hold"} absolute paths to node and token-goat on this machine${shim}, so do not commit them: list them in .git/info/exclude or .gitignore.`;
|
|
20401
20625
|
}
|
|
20402
20626
|
function visualStudioManualSteps(scope) {
|
|
@@ -20429,7 +20653,7 @@ async function cmdInstall(opts) {
|
|
|
20429
20653
|
if (opts.project === true && opts.user === true) {
|
|
20430
20654
|
throw new Error("install takes either -p/--project or --user, not both.");
|
|
20431
20655
|
}
|
|
20432
|
-
await import("./token-goat-chunk-
|
|
20656
|
+
await import("./token-goat-chunk-Z6KBMOBI.mjs");
|
|
20433
20657
|
const scope = opts.project === true ? "project" : "user";
|
|
20434
20658
|
if (wantsClaudeCodeBase(opts)) {
|
|
20435
20659
|
const result = installHooks(scope);
|
|
@@ -20575,16 +20799,16 @@ async function cmdInstall(opts) {
|
|
|
20575
20799
|
);
|
|
20576
20800
|
}
|
|
20577
20801
|
try {
|
|
20578
|
-
const skillDir2 =
|
|
20579
|
-
if (
|
|
20580
|
-
const entries =
|
|
20802
|
+
const skillDir2 = path40.join(claudeConfigDir(), "skills");
|
|
20803
|
+
if (fs44.existsSync(skillDir2)) {
|
|
20804
|
+
const entries = fs44.readdirSync(skillDir2, { withFileTypes: true });
|
|
20581
20805
|
const skillNames = [];
|
|
20582
20806
|
const sessionId = getSessionId();
|
|
20583
20807
|
for (const entry of entries) {
|
|
20584
20808
|
if (!entry.isDirectory()) continue;
|
|
20585
|
-
const skillFile =
|
|
20586
|
-
if (
|
|
20587
|
-
const body =
|
|
20809
|
+
const skillFile = path40.join(skillDir2, entry.name, "SKILL.md");
|
|
20810
|
+
if (fs44.existsSync(skillFile)) {
|
|
20811
|
+
const body = fs44.readFileSync(skillFile, "utf-8");
|
|
20588
20812
|
const compact = extractCompactFromMarker(body);
|
|
20589
20813
|
if (compact === null) continue;
|
|
20590
20814
|
const sourceSha = contentHash(body);
|
|
@@ -20595,9 +20819,9 @@ async function cmdInstall(opts) {
|
|
|
20595
20819
|
if (skillNames.length > 0) {
|
|
20596
20820
|
const dir = skillOutputsDir();
|
|
20597
20821
|
ensureDirSync(dir);
|
|
20598
|
-
const pregenPath =
|
|
20822
|
+
const pregenPath = path40.join(dir, "pregen.json");
|
|
20599
20823
|
const pregenData = { ts: Date.now(), names: skillNames };
|
|
20600
|
-
await
|
|
20824
|
+
await fs44.promises.writeFile(pregenPath, JSON.stringify(pregenData, null, 2));
|
|
20601
20825
|
out(`Pre-generated ${skillNames.length} skill compacts.`);
|
|
20602
20826
|
}
|
|
20603
20827
|
}
|
|
@@ -20611,7 +20835,7 @@ function cmdMcpStatus(opts) {
|
|
|
20611
20835
|
const scope = opts.project === true ? { projectRoot: process.cwd() } : {};
|
|
20612
20836
|
out(displaySafeJson(opts.vscode === true ? vscodeDecoderConfigured(scope) : visualStudioMcpStatus(scope), 0));
|
|
20613
20837
|
}
|
|
20614
|
-
function cmdUninstall(opts) {
|
|
20838
|
+
async function cmdUninstall(opts) {
|
|
20615
20839
|
if (opts.project === true && opts.user === true) {
|
|
20616
20840
|
throw new Error("uninstall takes either -p/--project or --user, not both.");
|
|
20617
20841
|
}
|
|
@@ -20661,7 +20885,7 @@ function cmdUninstall(opts) {
|
|
|
20661
20885
|
if (opts.hermes === true) {
|
|
20662
20886
|
out("No separate Hermes integration to remove (it shares the Claude Code hook entries).");
|
|
20663
20887
|
}
|
|
20664
|
-
if (opts.purge === true) runPurge();
|
|
20888
|
+
if (opts.purge === true) await runPurge();
|
|
20665
20889
|
}
|
|
20666
20890
|
function leftoverIntegrations(opts) {
|
|
20667
20891
|
const candidates = [
|
|
@@ -20703,7 +20927,8 @@ function leftoverIntegrations(opts) {
|
|
|
20703
20927
|
}
|
|
20704
20928
|
return found;
|
|
20705
20929
|
}
|
|
20706
|
-
function runPurge() {
|
|
20930
|
+
async function runPurge() {
|
|
20931
|
+
await queryServers("stop");
|
|
20707
20932
|
if (isWorkerRunning()) {
|
|
20708
20933
|
err('token-goat: the background worker is running, so --purge would delete files it is about to rewrite. Run "token-goat worker stop" first.');
|
|
20709
20934
|
return;
|
|
@@ -20764,7 +20989,7 @@ async function cmdDoctor(opts) {
|
|
|
20764
20989
|
doctorOpts.rootDir = project.root;
|
|
20765
20990
|
}
|
|
20766
20991
|
if (opts.json === true) {
|
|
20767
|
-
const results =
|
|
20992
|
+
const results = await runDoctorChecks(doctorOpts.dataDir, doctorOpts.configPath, doctorOpts.rootDir);
|
|
20768
20993
|
out(displaySafeJson(results, 0));
|
|
20769
20994
|
if (results.some((r) => r.status === "fail")) {
|
|
20770
20995
|
throw new CliError("doctor checks failed");
|
|
@@ -20860,7 +21085,7 @@ function cmdBashOutput(id, opts) {
|
|
|
20860
21085
|
}
|
|
20861
21086
|
let content;
|
|
20862
21087
|
try {
|
|
20863
|
-
const st =
|
|
21088
|
+
const st = fs44.statSync(opts.file);
|
|
20864
21089
|
if (st.isFIFO() || st.isSocket()) {
|
|
20865
21090
|
throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
20866
21091
|
}
|
|
@@ -20875,7 +21100,7 @@ function cmdBashOutput(id, opts) {
|
|
|
20875
21100
|
`);
|
|
20876
21101
|
}
|
|
20877
21102
|
}
|
|
20878
|
-
content = redactIfDotenv(opts.file, decodeSource(
|
|
21103
|
+
content = redactIfDotenv(opts.file, decodeSource(fs44.readFileSync(opts.file)));
|
|
20879
21104
|
} catch (e) {
|
|
20880
21105
|
if (e instanceof CliError) throw e;
|
|
20881
21106
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
@@ -20939,15 +21164,15 @@ function cmdMcpOutput(id, opts) {
|
|
|
20939
21164
|
if (opts.file.includes("\0")) {
|
|
20940
21165
|
throw new CliError("--file path contains a null byte");
|
|
20941
21166
|
}
|
|
20942
|
-
if (!
|
|
21167
|
+
if (!fs44.existsSync(opts.file)) {
|
|
20943
21168
|
throw new CliError(`file not found: ${opts.file}`);
|
|
20944
21169
|
}
|
|
20945
21170
|
try {
|
|
20946
|
-
const st =
|
|
21171
|
+
const st = fs44.statSync(opts.file);
|
|
20947
21172
|
if (st.isFIFO() || st.isSocket()) {
|
|
20948
21173
|
throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
20949
21174
|
}
|
|
20950
|
-
content = decodeSource(
|
|
21175
|
+
content = decodeSource(fs44.readFileSync(opts.file));
|
|
20951
21176
|
} catch (e) {
|
|
20952
21177
|
if (e instanceof CliError) throw e;
|
|
20953
21178
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
@@ -21020,9 +21245,14 @@ async function cmdCompress(commandArgs, opts = {}) {
|
|
|
21020
21245
|
process.exitCode = 1;
|
|
21021
21246
|
return;
|
|
21022
21247
|
}
|
|
21023
|
-
const bashRunner = await import("./token-goat-chunk-
|
|
21248
|
+
const bashRunner = await import("./token-goat-chunk-VQ6F6T7X.mjs");
|
|
21024
21249
|
if (opts.compress === false) {
|
|
21025
|
-
process.exitCode = bashRunner.runRaw(
|
|
21250
|
+
process.exitCode = bashRunner.runRaw(
|
|
21251
|
+
command,
|
|
21252
|
+
parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS),
|
|
21253
|
+
opts.native,
|
|
21254
|
+
opts.shell
|
|
21255
|
+
);
|
|
21026
21256
|
return;
|
|
21027
21257
|
}
|
|
21028
21258
|
const maxTokens = opts.maxTokens !== void 0 ? requireNonNegativeInt("--max-tokens", opts.maxTokens) : 0;
|
|
@@ -21030,12 +21260,14 @@ async function cmdCompress(commandArgs, opts = {}) {
|
|
|
21030
21260
|
filterName: opts.filter,
|
|
21031
21261
|
timeout: parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS),
|
|
21032
21262
|
maxTokens,
|
|
21263
|
+
...opts.capHintB64 !== void 0 ? { capHint: Buffer.from(opts.capHintB64, "base64").toString("utf8") } : {},
|
|
21033
21264
|
...opts.profile !== void 0 ? { compressionProfile: opts.profile } : {},
|
|
21034
21265
|
...opts.quietSuccess === true ? { quietSuccess: true } : {},
|
|
21035
|
-
...opts.native === true ? { nativeShell: true } : {}
|
|
21266
|
+
...opts.native === true ? { nativeShell: true } : {},
|
|
21267
|
+
...opts.shell !== void 0 ? { shellType: opts.shell } : {}
|
|
21036
21268
|
});
|
|
21037
21269
|
} catch (e) {
|
|
21038
|
-
err(
|
|
21270
|
+
err(formatCommandError(e));
|
|
21039
21271
|
process.exitCode = 1;
|
|
21040
21272
|
}
|
|
21041
21273
|
}
|
|
@@ -21067,11 +21299,41 @@ ${content}`;
|
|
|
21067
21299
|
const bytesSaved = cappedSourceBytesSaved(fullSourceBytes, Buffer.byteLength(toEmit, "utf8"));
|
|
21068
21300
|
recordStat("gdrive_sections", bytesSaved, savedTokensFromBytes(bytesSaved));
|
|
21069
21301
|
}
|
|
21302
|
+
var READ_ONLY_INDEX_COMMANDS = /* @__PURE__ */ new Set([
|
|
21303
|
+
"symbol",
|
|
21304
|
+
"read",
|
|
21305
|
+
"brief",
|
|
21306
|
+
"section",
|
|
21307
|
+
"semantic",
|
|
21308
|
+
"skeleton",
|
|
21309
|
+
"outline",
|
|
21310
|
+
"refs",
|
|
21311
|
+
"answer",
|
|
21312
|
+
"ask",
|
|
21313
|
+
"map",
|
|
21314
|
+
"exports",
|
|
21315
|
+
"imports",
|
|
21316
|
+
"find",
|
|
21317
|
+
"locate",
|
|
21318
|
+
"callers",
|
|
21319
|
+
"call-chain",
|
|
21320
|
+
"impact",
|
|
21321
|
+
"dead",
|
|
21322
|
+
"deps",
|
|
21323
|
+
"types",
|
|
21324
|
+
"scope",
|
|
21325
|
+
"similar",
|
|
21326
|
+
"context-for",
|
|
21327
|
+
"test-for"
|
|
21328
|
+
]);
|
|
21070
21329
|
var originalHelpInformation = null;
|
|
21071
21330
|
function buildProgram() {
|
|
21072
21331
|
const program2 = new Command();
|
|
21073
21332
|
program2.name("token-goat").description("Surgical token-reduction companion for AI coding agents").version(VERSION, "-v, --version", "print the token-goat version").option("--cwd <path>", "run as if invoked from this directory (overrides the real working directory)").option("--notice <text>", "print this line to stdout before the command's own output");
|
|
21074
|
-
program2.hook("preAction", (thisCommand) => {
|
|
21333
|
+
program2.hook("preAction", (thisCommand, actionCommand) => {
|
|
21334
|
+
if (actionCommand.parent === program2 && READ_ONLY_INDEX_COMMANDS.has(actionCommand.name())) {
|
|
21335
|
+
allowReadOnlyIndex(() => err("token-goat: the index database cannot be written here, so this run reads it without writing: no stats are recorded and changed files are not reindexed."));
|
|
21336
|
+
}
|
|
21075
21337
|
const opts = thisCommand.opts();
|
|
21076
21338
|
const cwdOverride = opts.cwd;
|
|
21077
21339
|
if (cwdOverride !== void 0) {
|
|
@@ -21106,8 +21368,7 @@ function buildProgram() {
|
|
|
21106
21368
|
process.exitCode = 0;
|
|
21107
21369
|
}
|
|
21108
21370
|
} catch (e) {
|
|
21109
|
-
|
|
21110
|
-
err(`token-goat: ${displaySafeText(msg)}`);
|
|
21371
|
+
err(formatCommandError(e));
|
|
21111
21372
|
process.exitCode = 1;
|
|
21112
21373
|
}
|
|
21113
21374
|
};
|
|
@@ -21196,7 +21457,7 @@ function buildProgram() {
|
|
|
21196
21457
|
)
|
|
21197
21458
|
);
|
|
21198
21459
|
});
|
|
21199
|
-
program2.command("semantic [query]").description("semantic search (falls back to full-text search)").option("-l, --limit <n>", "max results").option("-j, --json", "output as JSON").option("--grep <pattern>", "filter to hits whose file path matches this regex (literal substring if it is not valid regex); matched against the path as rendered").option("--exclude-tests", "hide hits whose file is a test file (opt-in; default output is unchanged)").option("--preflight", "run semantic embedding preflight check and exit").option("--warm", "warm up the embedding model session in memory").action(guard(cmdSemantic));
|
|
21460
|
+
program2.command("semantic [query] [more...]").description("semantic search (falls back to full-text search); several queries run in one call, one headed block per query").option("-l, --limit <n>", "max results").option("-j, --json", "output as JSON").option("--grep <pattern>", "filter to hits whose file path matches this regex (literal substring if it is not valid regex); matched against the path as rendered").option("--exclude-tests", "hide hits whose file is a test file (opt-in; default output is unchanged)").option("--preflight", "run semantic embedding preflight check and exit").option("--warm", "warm up the embedding model session in memory").action(guard(cmdSemantic));
|
|
21200
21461
|
const registerSymbolListing = (name, description, run2) => {
|
|
21201
21462
|
program2.command(`${name} <file> [more...]`).description(description).option("-j, --json", "output as JSON").option("--min-lines <n>", "only show symbols at least N lines long").option("--grep <pattern>", "only show symbols whose name matches this regex (literal substring if it is not valid regex)").option("--force-refresh", "reparse file from disk before querying (ignore stale index)").option("--stats", "add per-symbol reference count and doc-coverage flag").action(
|
|
21202
21463
|
(file, more, opts) => runExitText(
|
|
@@ -21252,7 +21513,7 @@ function buildProgram() {
|
|
|
21252
21513
|
program2.command("bench").description("replay a corpus of captured command output through the compressors; prints the byte savings ratio and a fidelity check, and exits 1 when a must-keep line was dropped").option("--corpus <dir>", "corpus directory (default: tests/fixtures/bench, relative to the working directory)").option("--tsv <path>", "append one result row, keyed by the current commit, creating the file and its header if absent").option("--validate", "score the corpus with control filters instead: proves the ratio has a floor and the fidelity guard can actually fail").option("-j, --json", "output as JSON").action(
|
|
21253
21514
|
(opts) => runExitText(
|
|
21254
21515
|
() => runBenchCommand({
|
|
21255
|
-
corpus: opts.corpus ??
|
|
21516
|
+
corpus: opts.corpus ?? path40.join("tests", "fixtures", "bench"),
|
|
21256
21517
|
...opts.tsv !== void 0 ? { tsv: opts.tsv } : {},
|
|
21257
21518
|
...opts.validate === true ? { validate: true } : {},
|
|
21258
21519
|
...opts.json === true ? { json: true } : {}
|
|
@@ -21264,13 +21525,17 @@ function buildProgram() {
|
|
|
21264
21525
|
program2.command("handoff-create <name> [text]").description("create a project-local named compressed handoff").option("--file <path>", "read handoff text from a local file instead of the argument").action(guard(cmdHandoffCreate));
|
|
21265
21526
|
program2.command("handoff-resolve <name>").description("resolve a project-local handoff compactly, or return it in full").option("--full", "return the full handoff text").action(guard(cmdHandoffResolve));
|
|
21266
21527
|
program2.command("hook <event>").description("hook relay entrypoint (reads JSON on stdin)").option("--harness <name>", "override harness detection for this invocation (sets TOKEN_GOAT_HARNESS_OVERRIDE)").action(guard(cmdHook));
|
|
21267
|
-
program2.command("install").description("install hooks into Claude Code settings").option("-p, --project", "install into project scope instead of user scope").option("--user", "with --vscode, install into user scope instead of this project (every project at once, but nothing past the first folder of a multi-root workspace)").option("--codex", "
|
|
21268
|
-
program2.command("uninstall").description("remove token-goat hooks from Claude Code settings").option("-p, --project", "uninstall from project scope instead of user scope").option("--user", "with --vscode, remove the user-scope install instead of this project one").option("--codex", "
|
|
21528
|
+
program2.command("install").description("install hooks into Claude Code settings, or with harness flags into those harnesses instead").option("-p, --project", "install into project scope instead of user scope").option("--user", "with --vscode, install into user scope instead of this project (every project at once, but nothing past the first folder of a multi-root workspace)").option("--codex", "patch Codex CLI (~/.codex/config.toml, ~/.codex/AGENTS.md)").option("--gemini", "patch Gemini CLI (~/.gemini/settings.json)").option("--qwen", "patch Qwen Code (~/.qwen/settings.json)").option("--kimi", "register a Kimi Code hook config, shim, instructions block and skill ($KIMI_CODE_HOME or ~/.kimi-code: config.toml, hooks/token-goat-shim.cjs, AGENTS.md, skills/token-goat/SKILL.md)").option("--pi", "drop a pi (pi-coding-agent) extension (~/.pi/agent/extensions/token-goat.ts)").option("--opencode", "drop an opencode plugin (~/.config/opencode/plugins/token-goat.ts, %APPDATA%\\opencode\\plugins\\token-goat.ts on Windows)").option("--hermes", "verify token-goat hooks are present for Hermes Agent (writes nothing new)").option("--openclaw", "register an OpenClaw plugin (~/.openclaw/openclaw.json, ~/.openclaw/plugins/token-goat.ts)").option("--copilot", "register a Copilot CLI hook config and routing block (~/.copilot/hooks/token-goat.json, ~/.copilot/hooks/token-goat-shim.cjs, ~/.copilot/copilot-instructions.md; with --local, <project>/.github/hooks/token-goat.json, <project>/.github/hooks/token-goat-shim.cjs, <project>/.github/copilot-instructions.md)").option("--grok", "register a Grok CLI (xAI Grok Build) hook config (~/.grok/hooks/token-goat.json, ~/.grok/hooks/token-goat-shim.cjs)").option("--vscode", "configure a VS Code MCP server (the workspace .vscode/mcp.json by default; --user for the user-profile mcp.json) and Copilot routing guidance").option("--visualstudio", "configure a Visual Studio (2022 17.14+ / 2026) Copilot MCP server and routing guidance, no hooks (%USERPROFILE%\\.mcp.json and %USERPROFILE%\\copilot-instructions.md; -p/--project for <project>/.mcp.json and <project>/.github/copilot-instructions.md)").option("--zed", "register token-goat as a Zed MCP context server (%APPDATA%\\Zed\\settings.json on Windows, ~/.config/zed/settings.json elsewhere, plus a generated shim script); Zed has no hooks API, so this is user scope only, no -p/--project support").option("--cursor", 'register a Cursor MCP server (~/.cursor/mcp.json by default; -p/--project for <project>/.cursor/mcp.json); writes no Cursor hooks config -- Cursor already imports the Claude Code hooks "token-goat install" writes to ~/.claude/settings.json').option("--local", "with --pi, install the project-local extension (<project>/.pi/extensions/token-goat.ts) instead of the global one").action(guard(cmdInstall));
|
|
21529
|
+
program2.command("uninstall").description("remove token-goat hooks from Claude Code settings, or with harness flags from those harnesses instead").option("-p, --project", "uninstall from project scope instead of user scope").option("--user", "with --vscode, remove the user-scope install instead of this project one").option("--codex", "strip the Codex CLI integration (~/.codex/config.toml, ~/.codex/AGENTS.md)").option("--gemini", "strip the Gemini CLI integration (~/.gemini/settings.json)").option("--qwen", "strip the Qwen Code integration (~/.qwen/settings.json)").option("--kimi", "strip the Kimi Code integration (config.toml hooks, hooks/token-goat-shim.cjs, the AGENTS.md block and skills/token-goat under $KIMI_CODE_HOME or ~/.kimi-code)").option("--pi", "remove the pi (pi-coding-agent) extension").option("--opencode", "remove the opencode plugin").option("--hermes", "no-op verification flag for symmetry with install (removes no files)").option("--openclaw", "remove the OpenClaw plugin and config entry").option("--copilot", "remove the Copilot CLI hook config and shim script, and strip the token-goat block from ~/.copilot/copilot-instructions.md (or <project>/.github/copilot-instructions.md with --local)").option("--grok", "remove the Grok CLI hook config and shim script").option("--vscode", "remove the VS Code MCP server (project scope by default; --user for the user-profile one) and routing guidance").option("--visualstudio", "remove the Visual Studio MCP server entry and routing guidance (user scope by default; -p/--project for the project one)").option("--zed", "remove the Zed MCP context server entry and its generated shim script").option("--cursor", "remove the Cursor MCP server entry (user scope by default; -p/--project for the project one)").option("--local", "with --pi, remove the project-local extension instead of the global one").option("--purge", "also delete the data directories (index, caches, session state, logs); refuses while the worker is running").action(guard(cmdUninstall));
|
|
21269
21530
|
program2.command("mcp-status").description("check whether an MCP integration is already configured (used by the VS Code extension)").option("--vscode", "check VS Code mcp.json (user scope, plus workspace scope with --project)").option("--visualstudio", "check the Visual Studio %USERPROFILE%\\.mcp.json (plus the project .mcp.json with --project)").option("-p, --project", "also check the project file: .vscode/mcp.json for --vscode, .mcp.json for --visualstudio (relative to --cwd or the real cwd)").action(guard(cmdMcpStatus));
|
|
21270
21531
|
const worker = program2.command("worker").description("background indexer lifecycle");
|
|
21271
21532
|
worker.command("start").description("start the background indexer").action(guard(cmdWorkerStart));
|
|
21272
21533
|
worker.command("stop").description("stop the background indexer").action(guard(cmdWorkerStop));
|
|
21273
21534
|
worker.command("status").description("check if the indexer is running").action(guard(cmdWorkerStatus));
|
|
21535
|
+
const hookServer = program2.command("hook-server").description("resident processes that answer hook calls and read-only commands without starting Node for each one");
|
|
21536
|
+
hookServer.command("run", { hidden: true }).description("serve one slot (started automatically by the first hook call)").option("--slot <n>", "which slot to serve", "0").action(guard(cmdHookServerRun));
|
|
21537
|
+
hookServer.command("status").description("list the running hook servers").option("-j, --json", "output as JSON").action(guard(cmdHookServerStatus));
|
|
21538
|
+
hookServer.command("stop").description("stop every running hook server (the next hook call starts a fresh one)").action(guard(cmdHookServerStop));
|
|
21274
21539
|
program2.command("stats").description("show session statistics (bare = totals only; --full for the breakdown)").option("-j, --json", "output as JSON").option("--full", "show the full breakdown (by source, by command, by day)").option("--short", "force the rich short KPI view even when stdout is not a TTY (e.g. piped)").option("--methodology", "explain local savings estimates and their billing limits").option("--hooks", "show the per-event/per-harness hook latency breakdown (median/p95/slowest/last-seen)").option("--window-days <days>", "days to include (0 = all time)", "30").option("--home-dir <path>", "home directory (for testing)").action(guard(cmdStats));
|
|
21275
21540
|
program2.command("doctor").description("diagnose token-goat health").option("--context", "include context footprint analysis").option("--json", "emit check results as JSON instead of text").option("--repair", "automatically repair fixable issues (permissive settings, missing semantics models)").option("--fix", "alias for --repair").action(guard(cmdDoctor));
|
|
21276
21541
|
program2.command("bash-output [id]").description("retrieve cached bash output by ID or file").option("--head <n>", "show first N lines").option("--tail <n>", "show last N lines").option("--grep <pattern>", "filter lines matching regex").option("--max-matches <n>", "cap --grep output to the first N matching lines").option("--section <heading>", "extract a specific section from the output").option("--full", "print the entire cached entry with no head/tail elision").option("--file <path>", "read from raw output file instead of cache").option("--transcript", "parse the --file as a JSONL agent transcript: keep assistant text blocks in order before filtering").option("--verify-last-write [seconds]", "verify the file or cache entry was written within [seconds] (default: 60s) to catch stale/no-op terminal output").option("--strict", "exit non-zero when --verify-last-write detects stale output").action(guard(cmdBashOutput));
|
|
@@ -21283,10 +21548,10 @@ function buildProgram() {
|
|
|
21283
21548
|
registerAnalysisCommands(program2, guard);
|
|
21284
21549
|
registerSessionCommands(program2, guard);
|
|
21285
21550
|
program2.command("gdrive-sections <file-id>").description("fetch and list sections from a public Google Doc").option("--heading <name>", "get content of one named section").option("--fresh", "skip the on-disk cache and force a live fetch").action(guard(cmdGdriveSections));
|
|
21286
|
-
program2.command("compress [command...]").alias("bash").alias("run").description("run a shell command (under a POSIX shell / bash) and emit a compressed view of its output").allowUnknownOption(true).option("-c, --cmd <command>", "the shell command to run, as one string (use / for paths across platforms)").option("--cmd-b64 <payload>", "the shell command as a base64-encoded string (preserves quotes, backslashes, and symbols across platforms)").option("-f, --filter <name>", "filter name (auto-detected from the command when omitted)").option("--timeout <seconds>", "wall-clock timeout in seconds (0 = built-in default)").option("--no-compress", "stream output raw without compression (debug the wrapper)").option("--profile <name>", "compression profile: aggressive | balanced | minimal").option("--max-tokens <n>", "post-compress token cap (0 = no cap)").option("-q, --quiet-success", "on exit code 0, emit only [tg: ok] summary and store full output for recall via bash-output").option("--native", "use native platform shell (e.g. cmd.exe on Windows) instead of bash, preserving Windows path backslashes").action(cmdCompress);
|
|
21551
|
+
program2.command("compress [command...]").alias("bash").alias("run").description("run a shell command (under a POSIX shell / bash) and emit a compressed view of its output").allowUnknownOption(true).option("-c, --cmd <command>", "the shell command to run, as one string (use / for paths across platforms)").option("--cmd-b64 <payload>", "the shell command as a base64-encoded string (preserves quotes, backslashes, and symbols across platforms)").option("--shell <type>", "shell interpreter to run under: bash | pwsh | powershell | native").option("-f, --filter <name>", "filter name (auto-detected from the command when omitted)").option("--timeout <seconds>", "wall-clock timeout in seconds (0 = built-in default)").option("--no-compress", "stream output raw without compression (debug the wrapper)").option("--profile <name>", "compression profile: aggressive | balanced | minimal").option("--max-tokens <n>", "post-compress token cap (0 = no cap)").option("--cap-hint-b64 <payload>", "base64 text printed after the output when --max-tokens cut it (the Bash hook sets it to the narrower read command)").option("-q, --quiet-success", "on exit code 0, emit only [tg: ok] summary and store full output for recall via bash-output").option("--native", "use native platform shell (e.g. cmd.exe on Windows) instead of bash, preserving Windows path backslashes").action(cmdCompress);
|
|
21287
21552
|
program2.command("upgrade").alias("update").description("check for updates and upgrade token-goat to the latest version").option("--check", "check whether an update is available without installing").option("-j, --json", "emit version check status as JSON").action(
|
|
21288
21553
|
(opts) => guard(async () => {
|
|
21289
|
-
const { cmdUpgrade } = await import("./token-goat-chunk-
|
|
21554
|
+
const { cmdUpgrade } = await import("./token-goat-chunk-YAGLESS3.mjs");
|
|
21290
21555
|
await cmdUpgrade(opts, () => cmdInstall({}));
|
|
21291
21556
|
})()
|
|
21292
21557
|
);
|
|
@@ -21303,8 +21568,19 @@ function buildProgram() {
|
|
|
21303
21568
|
return;
|
|
21304
21569
|
}
|
|
21305
21570
|
if (cmd) {
|
|
21571
|
+
const known = program2.commands.some((sub) => sub.name() === cmd || sub.aliases().includes(cmd));
|
|
21572
|
+
if (!known) {
|
|
21573
|
+
err(`token-goat: unknown command '${displaySafeText(cmd)}'. Run 'token-goat commands --grep <pattern>' to search the list.`);
|
|
21574
|
+
process.exitCode = 1;
|
|
21575
|
+
return;
|
|
21576
|
+
}
|
|
21306
21577
|
const argv = [process.argv[0] ?? "node", process.argv[1] ?? "token-goat", cmd, "--help"];
|
|
21307
|
-
|
|
21578
|
+
try {
|
|
21579
|
+
program2.parse(argv);
|
|
21580
|
+
} catch (e) {
|
|
21581
|
+
const code = e.code;
|
|
21582
|
+
if (code !== "commander.help" && code !== "commander.helpDisplayed") throw e;
|
|
21583
|
+
}
|
|
21308
21584
|
} else {
|
|
21309
21585
|
out(generateCompactHelp());
|
|
21310
21586
|
}
|
|
@@ -21325,7 +21601,7 @@ async function run(argv = process.argv) {
|
|
|
21325
21601
|
return;
|
|
21326
21602
|
}
|
|
21327
21603
|
if (argv[2] === "--batch-serve" && typeof argv[3] === "string") {
|
|
21328
|
-
const { serveBatch } = await import("./token-goat-chunk-
|
|
21604
|
+
const { serveBatch } = await import("./token-goat-chunk-ASLWOQ3I.mjs");
|
|
21329
21605
|
serveBatch(argv[3], (a) => run(a));
|
|
21330
21606
|
return;
|
|
21331
21607
|
}
|
|
@@ -21349,80 +21625,81 @@ async function run(argv = process.argv) {
|
|
|
21349
21625
|
process.exitCode = 1;
|
|
21350
21626
|
return;
|
|
21351
21627
|
}
|
|
21352
|
-
|
|
21353
|
-
err(`token-goat: ${displaySafeText(msg)}`);
|
|
21628
|
+
err(formatCommandError(e));
|
|
21354
21629
|
process.exitCode = 1;
|
|
21355
21630
|
}
|
|
21356
21631
|
}
|
|
21357
|
-
|
|
21358
21632
|
export {
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
|
|
21362
|
-
|
|
21363
|
-
|
|
21364
|
-
|
|
21365
|
-
|
|
21366
|
-
cmdPdfExtract,
|
|
21367
|
-
cmdPdfLocate,
|
|
21368
|
-
cmdPdfOutline,
|
|
21369
|
-
cmdPdfMeta,
|
|
21370
|
-
cmdVideoChapters,
|
|
21371
|
-
cmdSharepointResolve,
|
|
21372
|
-
cmdXlsxSheets,
|
|
21373
|
-
cmdXlsxHead,
|
|
21374
|
-
cmdXlsxColumns,
|
|
21375
|
-
cmdXlsxRange,
|
|
21376
|
-
cmdXlsxQuery,
|
|
21377
|
-
cmdPptxOutline,
|
|
21378
|
-
cmdPptxSlide,
|
|
21379
|
-
cmdPptxNotes,
|
|
21380
|
-
cmdPptxText,
|
|
21633
|
+
CliError,
|
|
21634
|
+
_applyFiltersAndPrint,
|
|
21635
|
+
applyExitOverride,
|
|
21636
|
+
buildProgram,
|
|
21637
|
+
cmdCsvProfile,
|
|
21638
|
+
cmdCsvQuery,
|
|
21639
|
+
cmdDescribe,
|
|
21381
21640
|
cmdDocxOutline,
|
|
21382
21641
|
cmdDocxTables,
|
|
21383
21642
|
cmdDocxText,
|
|
21384
|
-
|
|
21385
|
-
cmdTranscript,
|
|
21386
|
-
cmdCsvQuery,
|
|
21387
|
-
cmdCsvProfile,
|
|
21388
|
-
cmdJsonOutline,
|
|
21389
|
-
cmdJsonQuery,
|
|
21390
|
-
cmdYamlOutline,
|
|
21391
|
-
cmdYamlQuery,
|
|
21392
|
-
cmdXmlOutline,
|
|
21393
|
-
cmdXmlQuery,
|
|
21643
|
+
cmdHtmlLint,
|
|
21394
21644
|
cmdHtmlOutline,
|
|
21395
21645
|
cmdHtmlQuery,
|
|
21396
|
-
cmdHtmlLint,
|
|
21397
|
-
cmdOpenApiOutline,
|
|
21398
|
-
cmdOpenApiOp,
|
|
21399
|
-
cmdZipList,
|
|
21400
|
-
cmdZipRead,
|
|
21401
|
-
cmdNoteAdd,
|
|
21402
|
-
cmdWriteFile,
|
|
21403
|
-
cmdReplace,
|
|
21404
|
-
cmdInsertSection,
|
|
21405
|
-
fenceOcrText,
|
|
21406
21646
|
cmdImageMeta,
|
|
21407
21647
|
cmdImageText,
|
|
21408
|
-
|
|
21409
|
-
|
|
21410
|
-
|
|
21648
|
+
cmdIndex,
|
|
21649
|
+
cmdInsertSection,
|
|
21650
|
+
cmdJsonOutline,
|
|
21651
|
+
cmdJsonQuery,
|
|
21652
|
+
cmdNoteAdd,
|
|
21653
|
+
cmdOpenApiOp,
|
|
21654
|
+
cmdOpenApiOutline,
|
|
21655
|
+
cmdPdfExtract,
|
|
21656
|
+
cmdPdfLocate,
|
|
21657
|
+
cmdPdfMeta,
|
|
21658
|
+
cmdPdfOutline,
|
|
21659
|
+
cmdPptxNotes,
|
|
21660
|
+
cmdPptxOutline,
|
|
21661
|
+
cmdPptxSlide,
|
|
21662
|
+
cmdPptxText,
|
|
21663
|
+
cmdReplace,
|
|
21664
|
+
cmdSessionSchema,
|
|
21665
|
+
cmdSharepointResolve,
|
|
21411
21666
|
cmdSkillBody,
|
|
21412
21667
|
cmdSkillCompact,
|
|
21413
|
-
cmdSkillList,
|
|
21414
|
-
cmdSkillSize,
|
|
21415
|
-
cmdSkillHistory,
|
|
21416
21668
|
cmdSkillDiff,
|
|
21669
|
+
cmdSkillHistory,
|
|
21670
|
+
cmdSkillList,
|
|
21417
21671
|
cmdSkillSection,
|
|
21418
|
-
|
|
21419
|
-
|
|
21672
|
+
cmdSkillSize,
|
|
21673
|
+
cmdSqliteQuery,
|
|
21674
|
+
cmdSqliteSchema,
|
|
21675
|
+
cmdSqliteTables,
|
|
21676
|
+
cmdTranscript,
|
|
21677
|
+
cmdTranscriptOutline,
|
|
21678
|
+
cmdVideoChapters,
|
|
21679
|
+
cmdWriteFile,
|
|
21680
|
+
cmdXlsxColumns,
|
|
21681
|
+
cmdXlsxHead,
|
|
21682
|
+
cmdXlsxQuery,
|
|
21683
|
+
cmdXlsxRange,
|
|
21684
|
+
cmdXlsxSheets,
|
|
21685
|
+
cmdXmlOutline,
|
|
21686
|
+
cmdXmlQuery,
|
|
21687
|
+
cmdYamlOutline,
|
|
21688
|
+
cmdYamlQuery,
|
|
21689
|
+
cmdZipList,
|
|
21690
|
+
cmdZipRead,
|
|
21420
21691
|
err,
|
|
21421
|
-
|
|
21422
|
-
|
|
21692
|
+
expandGlobs,
|
|
21693
|
+
fenceFileFieldIfMatched,
|
|
21694
|
+
fenceFileText,
|
|
21695
|
+
fenceOcrText,
|
|
21696
|
+
fileSizeOrZero,
|
|
21697
|
+
formatCommandError,
|
|
21423
21698
|
leftoverIntegrations,
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21699
|
+
out,
|
|
21700
|
+
requireInt,
|
|
21701
|
+
requireNonNegativeInt,
|
|
21702
|
+
requirePositiveInt,
|
|
21703
|
+
run,
|
|
21704
|
+
visualStudioManualSteps
|
|
21428
21705
|
};
|