token-goat 2.6.30 → 2.6.31
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 +54 -15
- package/SECURITY.md +72 -0
- package/dist/token-goat-chunk-4WGVGN6W.mjs +54 -0
- package/dist/token-goat-chunk-56C3XUQY.mjs +156 -0
- package/dist/token-goat-chunk-DCGBS2YZ.mjs +112 -0
- package/dist/token-goat-chunk-HPY7XE77.mjs +18311 -0
- package/dist/token-goat-chunk-J6JTYE2B.mjs +24 -0
- package/dist/token-goat-chunk-N2S7UAVU.mjs +13674 -0
- package/dist/token-goat-chunk-OIBTYBVR.mjs +901 -0
- package/dist/token-goat-chunk-P7I6LS5H.mjs +9643 -0
- package/dist/token-goat-chunk-PWD5XZ6C.mjs +9441 -0
- package/dist/token-goat-chunk-Q4N6SQWR.mjs +14860 -0
- package/dist/token-goat-chunk-QL2743EW.mjs +707 -0
- package/dist/token-goat-chunk-VYC34TBW.mjs +33 -0
- package/dist/token-goat-chunk-X7PIWZMB.mjs +5337 -0
- package/dist/token-goat-chunk-XEJBPPD7.mjs +15545 -0
- package/dist/token-goat-hook-chunk-2K7FV2ME.mjs +9438 -0
- package/dist/token-goat-hook-chunk-3OJELLK5.mjs +156 -0
- package/dist/{token-goat-hook-chunk-ZRJUZZQE.mjs → token-goat-hook-chunk-5AQYD2SZ.mjs} +1 -2
- package/dist/token-goat-hook-chunk-66W63A4Y.mjs +9643 -0
- package/dist/token-goat-hook-chunk-JT5RMRIY.mjs +901 -0
- package/dist/token-goat-hook-chunk-JVJUBWKT.mjs +13674 -0
- package/dist/{token-goat-hook-chunk-FMQ37OQD.mjs → token-goat-hook-chunk-K6HLYRRI.mjs} +25 -23
- package/dist/token-goat-hook-chunk-NIVRFAJ4.mjs +5323 -0
- package/dist/token-goat-hook-chunk-SJM4BUZQ.mjs +18309 -0
- package/dist/token-goat-hook-chunk-ULGSXGZK.mjs +23 -0
- package/dist/{token-goat-hook-chunk-XNZLMFQ2.mjs → token-goat-hook-chunk-YHRJMMEF.mjs} +2629 -801
- package/dist/token-goat-hook.mjs +5 -2
- package/dist/token-goat.core.mjs +14 -89574
- package/package.json +5 -4
- package/dist/token-goat-hook-chunk-4SM2PAR6.mjs +0 -33590
- package/dist/token-goat-hook-chunk-5B3OWRNC.mjs +0 -145
- package/dist/token-goat-hook-chunk-VKAQNN2R.mjs +0 -24416
|
@@ -1,17 +1,96 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
ALL_SYMBOLS_IN_FILE_LIMIT,
|
|
5
|
+
CONTENT_MAX_INPUT_CHARS,
|
|
6
|
+
WHOLE_FILE_NOTE_SYMBOL,
|
|
7
|
+
compressText,
|
|
8
|
+
computeFileFingerprint,
|
|
9
|
+
createHandoff,
|
|
10
|
+
didYouMean,
|
|
11
|
+
enclosingSymbol,
|
|
12
|
+
extraFileArgsNote,
|
|
13
|
+
extractSection,
|
|
14
|
+
extractTranscriptText,
|
|
15
|
+
filterSimilarHeadings,
|
|
16
|
+
findSpecSeparator,
|
|
17
|
+
getTrackedFiles,
|
|
18
|
+
healStaleIndex,
|
|
19
|
+
isAvailable,
|
|
20
|
+
listSections,
|
|
21
|
+
load,
|
|
22
|
+
loadError,
|
|
23
|
+
rankSimilarNames,
|
|
24
|
+
readSection,
|
|
25
|
+
resolveBody,
|
|
26
|
+
resolveHandoff,
|
|
27
|
+
resolveSymbolMatch,
|
|
28
|
+
retrieveText,
|
|
29
|
+
runArch,
|
|
30
|
+
runAsk,
|
|
31
|
+
runBlame,
|
|
32
|
+
runBrief,
|
|
33
|
+
runCallChain,
|
|
34
|
+
runCallers,
|
|
35
|
+
runChanged,
|
|
36
|
+
runConfigGet,
|
|
37
|
+
runConflicts,
|
|
38
|
+
runContextFor,
|
|
39
|
+
runCoverageGaps,
|
|
40
|
+
runCoverageReportGaps,
|
|
41
|
+
runCsvProfile,
|
|
42
|
+
runCsvQuery,
|
|
43
|
+
runDead,
|
|
44
|
+
runDeps,
|
|
45
|
+
runDiff,
|
|
46
|
+
runExports,
|
|
47
|
+
runFind,
|
|
48
|
+
runGrep,
|
|
49
|
+
runImageMeta,
|
|
50
|
+
runImageText,
|
|
51
|
+
runImpact,
|
|
52
|
+
runImports,
|
|
53
|
+
runJsonOutline,
|
|
54
|
+
runJsonQuery,
|
|
55
|
+
runListSections,
|
|
56
|
+
runLog,
|
|
57
|
+
runNoteGet,
|
|
58
|
+
runNoteList,
|
|
59
|
+
runOpenApiOp,
|
|
60
|
+
runOpenApiOutline,
|
|
61
|
+
runOutline,
|
|
62
|
+
runPdfExtractText,
|
|
63
|
+
runPdfMeta,
|
|
64
|
+
runPdfOutline,
|
|
65
|
+
runPrSlice,
|
|
66
|
+
runRead,
|
|
67
|
+
runRefs,
|
|
68
|
+
runScope,
|
|
69
|
+
runScreenshot,
|
|
70
|
+
runSection,
|
|
71
|
+
runSemantic,
|
|
72
|
+
runSimilar,
|
|
73
|
+
runSkeleton,
|
|
74
|
+
runSqliteQuery,
|
|
75
|
+
runSqliteSchema,
|
|
76
|
+
runSymbol,
|
|
77
|
+
runTestFor,
|
|
78
|
+
runTypes,
|
|
79
|
+
runYamlOutline,
|
|
80
|
+
runYamlQuery,
|
|
81
|
+
runZipList,
|
|
82
|
+
runZipRead,
|
|
83
|
+
symbolNamesInFile,
|
|
84
|
+
upsertNote
|
|
85
|
+
} from "./token-goat-hook-chunk-66W63A4Y.mjs";
|
|
3
86
|
import {
|
|
4
87
|
BASH_OUTPUT_SUBDIR,
|
|
5
88
|
GEMINI_TOOL_NAME_MAP,
|
|
6
89
|
HOOK_EVENTS,
|
|
7
|
-
ToolFilter,
|
|
8
90
|
WEB_OUTPUT_SUBDIR,
|
|
9
91
|
buildCommandManifest,
|
|
10
|
-
|
|
11
|
-
combineStreams,
|
|
92
|
+
checkSymbolBodySize,
|
|
12
93
|
commandHash,
|
|
13
|
-
compressOutput,
|
|
14
|
-
filterByName,
|
|
15
94
|
filterCommandManifest,
|
|
16
95
|
formatCommandManifest,
|
|
17
96
|
getBashOutput,
|
|
@@ -22,43 +101,23 @@ import {
|
|
|
22
101
|
listRecentRecall,
|
|
23
102
|
normalizeCommandForCacheKey,
|
|
24
103
|
readStdinJson,
|
|
25
|
-
relay,
|
|
26
|
-
resolveMinNetSavingsBytes,
|
|
27
|
-
runDoctor,
|
|
28
|
-
runDoctorAndExit,
|
|
29
104
|
searchRecall,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
storeWebOutput,
|
|
33
|
-
wrappedShell
|
|
34
|
-
} from "./token-goat-hook-chunk-VKAQNN2R.mjs";
|
|
35
|
-
import {
|
|
36
|
-
CONTENT_MAX_INPUT_CHARS,
|
|
37
|
-
compressText,
|
|
38
|
-
createHandoff,
|
|
39
|
-
resolveHandoff,
|
|
40
|
-
retrieveText
|
|
41
|
-
} from "./token-goat-hook-chunk-5B3OWRNC.mjs";
|
|
105
|
+
storeWebOutput
|
|
106
|
+
} from "./token-goat-hook-chunk-JT5RMRIY.mjs";
|
|
42
107
|
import {
|
|
43
108
|
AGENT_SALT_MARKER,
|
|
44
|
-
C,
|
|
45
|
-
CONFIG_KEY_ENV_OVERRIDES,
|
|
46
109
|
CONTEXT_AUTOCOMPACT_TOKENS,
|
|
47
110
|
DEFAULT_MAX_AGE_MS,
|
|
48
111
|
DEFAULT_MAX_COUNT,
|
|
49
|
-
ENV_KEYS,
|
|
50
|
-
LOCK_WAIT_MS_HARDENED,
|
|
51
112
|
MAX_FILES_SCANNED,
|
|
52
|
-
RESET,
|
|
53
113
|
SESSIONS_SUBDIR,
|
|
54
114
|
SKILLS_OUTPUT_SUBDIR,
|
|
55
|
-
|
|
56
|
-
|
|
115
|
+
SKIP_DIRS,
|
|
116
|
+
UNTRUSTED_TOOL_TAG,
|
|
117
|
+
UNTRUSTED_WEB_TAG,
|
|
118
|
+
WORKER_HEARTBEAT_STALE_MS,
|
|
57
119
|
WorkerAlreadyRunningError,
|
|
58
|
-
_useRichStats,
|
|
59
120
|
anchoredMarkerPattern,
|
|
60
|
-
atomicWriteBytes,
|
|
61
|
-
atomicWriteText,
|
|
62
121
|
auditClaudeMd,
|
|
63
122
|
buildExtractiveCompact,
|
|
64
123
|
buildLineDiff,
|
|
@@ -66,77 +125,49 @@ import {
|
|
|
66
125
|
buildProjectMap,
|
|
67
126
|
buildStats,
|
|
68
127
|
capJsonRows,
|
|
69
|
-
cmdHot,
|
|
70
|
-
cmdIgnores,
|
|
71
|
-
cmdLockdeps,
|
|
72
|
-
cmdLogfold,
|
|
73
|
-
cmdNote,
|
|
74
|
-
cmdRecent,
|
|
75
|
-
cmdTodo,
|
|
76
|
-
cmdTrace,
|
|
77
|
-
colorStdout,
|
|
78
128
|
compactDoc,
|
|
79
129
|
compactPathFor,
|
|
80
|
-
computeFileFingerprint,
|
|
81
|
-
configPath,
|
|
82
130
|
confirmAndApply,
|
|
83
131
|
contentHash,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
defaultConfig,
|
|
132
|
+
copilotCliConfigPath,
|
|
133
|
+
copilotCliScriptPath,
|
|
87
134
|
detectLanguage,
|
|
88
|
-
|
|
135
|
+
detectWalkMode,
|
|
136
|
+
dirtyQueuePathFor,
|
|
89
137
|
docxOutline,
|
|
90
138
|
docxText,
|
|
139
|
+
drainHeartbeatPathFor,
|
|
91
140
|
embeddingsDepsAvailable,
|
|
141
|
+
emptyIndexMessage,
|
|
92
142
|
enqueueDirtyPathSafe,
|
|
93
|
-
ensureDirSync,
|
|
94
|
-
ensureNewline,
|
|
95
143
|
estimateTokens,
|
|
96
|
-
extraFileArgsNote,
|
|
97
144
|
extractChecklistSection,
|
|
98
145
|
extractCompactFromMarker,
|
|
99
|
-
extractErrorMessage,
|
|
100
146
|
extractNamedSection,
|
|
101
|
-
|
|
102
|
-
extractTranscriptText,
|
|
103
|
-
fg,
|
|
104
|
-
filterSimilarHeadings,
|
|
147
|
+
fenceUntrustedContent,
|
|
105
148
|
findClaudeMdFiles,
|
|
106
149
|
findContentDuplicates,
|
|
107
150
|
findLatestSessionId,
|
|
108
151
|
findMemSuggestionCandidates,
|
|
109
152
|
findMemoryMd,
|
|
110
|
-
findProject,
|
|
111
|
-
findSpecSeparator,
|
|
112
153
|
findStrayClaudeMdBlocks,
|
|
113
154
|
findSystemTempFiles,
|
|
114
|
-
fingerprintContent,
|
|
115
|
-
fingerprintFile,
|
|
116
|
-
foldPath,
|
|
117
155
|
formatAge,
|
|
118
156
|
formatCsvTable,
|
|
119
|
-
formatLocalTimestamp,
|
|
120
157
|
formatMemSuggestions,
|
|
121
158
|
formatProjectMap,
|
|
122
159
|
formatXlsxRange,
|
|
123
160
|
getContextPressure,
|
|
124
|
-
getDb,
|
|
125
161
|
getDirtyPathsFor,
|
|
126
162
|
getFileEntry,
|
|
127
163
|
getHintStatsSummary,
|
|
128
164
|
getHintStatsTotals,
|
|
129
|
-
|
|
130
|
-
getLastProjectConfigParseError,
|
|
131
|
-
getProjectConfigInfo,
|
|
165
|
+
getProjectIndexCounts,
|
|
132
166
|
getSessionFiles,
|
|
133
167
|
getSessionId,
|
|
134
168
|
getSkillFilePath,
|
|
135
|
-
getTrackedFiles,
|
|
136
|
-
globalDbPath,
|
|
137
169
|
groupHasTokenGoat,
|
|
138
170
|
headSheet,
|
|
139
|
-
healStaleIndex,
|
|
140
171
|
incrementSkillHit,
|
|
141
172
|
indexFileEmbeddings,
|
|
142
173
|
indexFileSync,
|
|
@@ -145,35 +176,28 @@ import {
|
|
|
145
176
|
installCopilotCli,
|
|
146
177
|
installGrok,
|
|
147
178
|
installHooks,
|
|
148
|
-
installSingleFilePlugin,
|
|
149
179
|
installSkill,
|
|
150
180
|
installVscode,
|
|
151
|
-
|
|
181
|
+
isCodexInstalled,
|
|
152
182
|
isCompactFresh,
|
|
183
|
+
isCopilotCliInstalled,
|
|
153
184
|
isEmbedFresh,
|
|
154
185
|
isEmbeddableDocument,
|
|
186
|
+
isGrokInstalled,
|
|
155
187
|
isHintCategory,
|
|
156
188
|
isInstalled,
|
|
157
189
|
isParseSkipEligible,
|
|
158
|
-
isUnderBlockedRoot,
|
|
159
|
-
isWindows,
|
|
160
190
|
isWorkerRunning,
|
|
161
191
|
listBlobs,
|
|
162
192
|
listOutputs,
|
|
163
|
-
listSections,
|
|
164
193
|
listSheets,
|
|
165
194
|
listSkills,
|
|
166
195
|
loadBlob,
|
|
167
|
-
loadConfig,
|
|
168
|
-
loadPersistedConfig,
|
|
169
196
|
loadSessionCache,
|
|
170
197
|
mapLookupBytesSaved,
|
|
171
198
|
markCategoryEffective,
|
|
172
199
|
markCategoryIneffective,
|
|
173
|
-
normalizePath,
|
|
174
200
|
otherScopeHasManagedServer,
|
|
175
|
-
pad,
|
|
176
|
-
parse,
|
|
177
201
|
parseWhereSpecs,
|
|
178
202
|
pptxNotesText,
|
|
179
203
|
pptxOutline,
|
|
@@ -184,161 +208,153 @@ import {
|
|
|
184
208
|
pruneSkillOutputs,
|
|
185
209
|
pruneSystemTempFiles,
|
|
186
210
|
querySheet,
|
|
211
|
+
querySymbols,
|
|
187
212
|
rangeSheet,
|
|
188
|
-
rankSimilarNames,
|
|
189
213
|
readCompactBody,
|
|
190
|
-
readSection,
|
|
191
|
-
recordStat,
|
|
192
|
-
redactUrlQuery,
|
|
193
214
|
removeFileFromIndex,
|
|
194
|
-
renderShortStats,
|
|
195
|
-
renderStats,
|
|
196
|
-
requireNonNegativeStrictInt,
|
|
197
|
-
requirePositiveStrictInt,
|
|
198
215
|
resetHintStats,
|
|
199
|
-
resolveConfigKeyLayer,
|
|
200
|
-
resolveIndexPath,
|
|
201
|
-
resolveProjectRoot,
|
|
202
|
-
resolveSymbolMatch,
|
|
203
|
-
runArch,
|
|
204
|
-
runAsk,
|
|
205
|
-
runBlame,
|
|
206
|
-
runBrief,
|
|
207
|
-
runCallChain,
|
|
208
|
-
runCallers,
|
|
209
|
-
runChanged,
|
|
210
|
-
runConfigGet,
|
|
211
|
-
runConflicts,
|
|
212
|
-
runContextFor,
|
|
213
216
|
runContextStats,
|
|
214
|
-
runCoverageGaps,
|
|
215
|
-
runCoverageReportGaps,
|
|
216
|
-
runCsvProfile,
|
|
217
|
-
runCsvQuery,
|
|
218
|
-
runDead,
|
|
219
|
-
runDeps,
|
|
220
217
|
runDetachedWorkerDaemon,
|
|
221
|
-
|
|
222
|
-
runExports,
|
|
223
|
-
runFind,
|
|
224
|
-
runGit,
|
|
225
|
-
runGrep,
|
|
226
|
-
runImageMeta,
|
|
227
|
-
runImageText,
|
|
228
|
-
runImpact,
|
|
229
|
-
runImports,
|
|
230
|
-
runJsonOutline,
|
|
231
|
-
runJsonQuery,
|
|
232
|
-
runListSections,
|
|
233
|
-
runLog,
|
|
234
|
-
runNoteGet,
|
|
235
|
-
runNoteList,
|
|
236
|
-
runOpenApiOp,
|
|
237
|
-
runOpenApiOutline,
|
|
238
|
-
runOutline,
|
|
239
|
-
runPdfExtractText,
|
|
240
|
-
runPdfMeta,
|
|
241
|
-
runPdfOutline,
|
|
242
|
-
runPrSlice,
|
|
243
|
-
runRead,
|
|
244
|
-
runRefs,
|
|
245
|
-
runScope,
|
|
246
|
-
runScreenshot,
|
|
247
|
-
runSection,
|
|
248
|
-
runSemantic,
|
|
249
|
-
runSimilar,
|
|
250
|
-
runSkeleton,
|
|
251
|
-
runSqliteQuery,
|
|
252
|
-
runSqliteSchema,
|
|
253
|
-
runSymbol,
|
|
254
|
-
runTestFor,
|
|
255
|
-
runTypes,
|
|
256
|
-
runYamlOutline,
|
|
257
|
-
runYamlQuery,
|
|
258
|
-
runZipList,
|
|
259
|
-
runZipRead,
|
|
260
|
-
safeSlice,
|
|
261
|
-
saveConfig,
|
|
218
|
+
scanForInjectionPatterns,
|
|
262
219
|
shrinkImage,
|
|
263
220
|
skillOutputsDir,
|
|
264
|
-
sleepSync,
|
|
265
221
|
startDetachedWorker,
|
|
266
222
|
stopWorker,
|
|
267
223
|
storeCompact,
|
|
268
224
|
storeOutput,
|
|
269
|
-
|
|
270
|
-
stripOwnHooksFromMap,
|
|
271
|
-
stripStaleGroupHooks,
|
|
272
|
-
suggestPackageNames,
|
|
273
|
-
summarize,
|
|
274
|
-
symbolNamesInFile,
|
|
225
|
+
tokenGoatHome,
|
|
275
226
|
trimToBudget,
|
|
276
227
|
uninstallClaudeMd,
|
|
277
228
|
uninstallCodex,
|
|
278
229
|
uninstallCopilotCli,
|
|
279
230
|
uninstallGrok,
|
|
280
231
|
uninstallHooks,
|
|
281
|
-
uninstallSingleFilePlugin,
|
|
282
232
|
uninstallSkill,
|
|
283
233
|
uninstallVscode,
|
|
284
|
-
|
|
285
|
-
validateEnumField,
|
|
286
|
-
validateNumericField,
|
|
234
|
+
urlPolicyDenialReason,
|
|
287
235
|
vscodeDecoderConfigured,
|
|
288
236
|
walkProject,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
withRetryOnLock,
|
|
292
|
-
writeCompact,
|
|
293
|
-
writeJsonSettings
|
|
294
|
-
} from "./token-goat-hook-chunk-4SM2PAR6.mjs";
|
|
295
|
-
import "./token-goat-hook-chunk-KNVHTGEX.mjs";
|
|
237
|
+
writeCompact
|
|
238
|
+
} from "./token-goat-hook-chunk-SJM4BUZQ.mjs";
|
|
296
239
|
import {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
240
|
+
C,
|
|
241
|
+
CONFIG_KEY_ENV_OVERRIDES,
|
|
242
|
+
ENV_KEYS,
|
|
243
|
+
FILTERS,
|
|
244
|
+
LOCK_WAIT_MS_HARDENED,
|
|
245
|
+
RESET,
|
|
246
|
+
VERSION,
|
|
247
|
+
_useRichStats,
|
|
248
|
+
atomicWriteBytes,
|
|
249
|
+
atomicWriteText,
|
|
250
|
+
canonicalize,
|
|
251
|
+
colorStdout,
|
|
252
|
+
configPath,
|
|
253
|
+
countNoun,
|
|
254
|
+
dataDir,
|
|
255
|
+
defaultConfig,
|
|
256
|
+
ensureDirSync,
|
|
257
|
+
ensureNewline,
|
|
258
|
+
escapeRegExp,
|
|
259
|
+
extractErrorMessage,
|
|
260
|
+
fg,
|
|
261
|
+
findProject,
|
|
262
|
+
fingerprintContent,
|
|
263
|
+
fingerprintFile,
|
|
264
|
+
foldPath,
|
|
265
|
+
formatLocalTimestamp,
|
|
266
|
+
getDb,
|
|
267
|
+
getDisplayRoot,
|
|
268
|
+
getLastConfigParseError,
|
|
269
|
+
getLastProjectConfigParseError,
|
|
270
|
+
getProjectConfigInfo,
|
|
271
|
+
globalDbPath,
|
|
272
|
+
installSingleFilePlugin,
|
|
273
|
+
invalidateConfigCache,
|
|
274
|
+
isUnderBlockedRoot,
|
|
275
|
+
isWindows,
|
|
276
|
+
lastProjectConfigLockedKeys,
|
|
277
|
+
loadConfig,
|
|
278
|
+
loadPersistedConfig,
|
|
279
|
+
normalizeDarwinSystemAlias,
|
|
280
|
+
normalizePath,
|
|
281
|
+
pad,
|
|
282
|
+
parse,
|
|
283
|
+
recordStat,
|
|
284
|
+
redactUrlQuery,
|
|
285
|
+
renderShortStats,
|
|
286
|
+
renderStats,
|
|
287
|
+
requireNonNegativeStrictInt,
|
|
288
|
+
requirePositiveStrictInt,
|
|
289
|
+
resolveConfigKeyLayer,
|
|
290
|
+
resolveIndexPath,
|
|
291
|
+
resolveProjectRoot,
|
|
292
|
+
runGit,
|
|
293
|
+
safeSlice,
|
|
294
|
+
saveConfig,
|
|
295
|
+
sleepSync,
|
|
296
|
+
stripAnsi,
|
|
297
|
+
stripOwnHooksFromMap,
|
|
298
|
+
stripStaleGroupHooks,
|
|
299
|
+
suggestPackageNames,
|
|
300
|
+
summarize,
|
|
301
|
+
toDisplayPath,
|
|
302
|
+
toKB,
|
|
303
|
+
uninstallSingleFilePlugin,
|
|
304
|
+
validateEnumField,
|
|
305
|
+
validateNumericField,
|
|
306
|
+
withExtension,
|
|
307
|
+
withFileLock,
|
|
308
|
+
withRetryOnLock,
|
|
309
|
+
writeJsonSettings
|
|
310
|
+
} from "./token-goat-hook-chunk-NIVRFAJ4.mjs";
|
|
311
|
+
import "./token-goat-hook-chunk-KNVHTGEX.mjs";
|
|
312
|
+
import {
|
|
313
|
+
__commonJS,
|
|
314
|
+
__export,
|
|
315
|
+
__require,
|
|
316
|
+
__toESM,
|
|
317
|
+
init_define_import_meta_env
|
|
318
|
+
} from "./token-goat-hook-chunk-7WC2H3EW.mjs";
|
|
319
|
+
|
|
320
|
+
// node_modules/commander/lib/error.js
|
|
321
|
+
var require_error = __commonJS({
|
|
322
|
+
"node_modules/commander/lib/error.js"(exports) {
|
|
323
|
+
init_define_import_meta_env();
|
|
324
|
+
var CommanderError2 = class extends Error {
|
|
325
|
+
/**
|
|
326
|
+
* Constructs the CommanderError class
|
|
327
|
+
* @param {number} exitCode suggested exit code which could be used with process.exit
|
|
328
|
+
* @param {string} code an id string representing the error
|
|
329
|
+
* @param {string} message human-readable description of the error
|
|
330
|
+
*/
|
|
331
|
+
constructor(exitCode, code, message) {
|
|
332
|
+
super(message);
|
|
333
|
+
Error.captureStackTrace(this, this.constructor);
|
|
334
|
+
this.name = this.constructor.name;
|
|
335
|
+
this.code = code;
|
|
336
|
+
this.exitCode = exitCode;
|
|
337
|
+
this.nestedError = void 0;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
var InvalidArgumentError2 = class extends CommanderError2 {
|
|
341
|
+
/**
|
|
342
|
+
* Constructs the InvalidArgumentError class
|
|
343
|
+
* @param {string} [message] explanation of why argument is invalid
|
|
344
|
+
*/
|
|
345
|
+
constructor(message) {
|
|
346
|
+
super(1, "commander.invalidArgument", message);
|
|
347
|
+
Error.captureStackTrace(this, this.constructor);
|
|
348
|
+
this.name = this.constructor.name;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
exports.CommanderError = CommanderError2;
|
|
352
|
+
exports.InvalidArgumentError = InvalidArgumentError2;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// node_modules/commander/lib/argument.js
|
|
357
|
+
var require_argument = __commonJS({
|
|
342
358
|
"node_modules/commander/lib/argument.js"(exports) {
|
|
343
359
|
init_define_import_meta_env();
|
|
344
360
|
var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
|
|
@@ -1240,8 +1256,8 @@ var require_command = __commonJS({
|
|
|
1240
1256
|
init_define_import_meta_env();
|
|
1241
1257
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
1242
1258
|
var childProcess = __require("node:child_process");
|
|
1243
|
-
var
|
|
1244
|
-
var
|
|
1259
|
+
var path26 = __require("node:path");
|
|
1260
|
+
var fs26 = __require("node:fs");
|
|
1245
1261
|
var process2 = __require("node:process");
|
|
1246
1262
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1247
1263
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -2173,11 +2189,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2173
2189
|
let launchWithNode = false;
|
|
2174
2190
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2175
2191
|
function findFile(baseDir, baseName) {
|
|
2176
|
-
const localBin =
|
|
2177
|
-
if (
|
|
2178
|
-
if (sourceExt.includes(
|
|
2192
|
+
const localBin = path26.resolve(baseDir, baseName);
|
|
2193
|
+
if (fs26.existsSync(localBin)) return localBin;
|
|
2194
|
+
if (sourceExt.includes(path26.extname(baseName))) return void 0;
|
|
2179
2195
|
const foundExt = sourceExt.find(
|
|
2180
|
-
(ext2) =>
|
|
2196
|
+
(ext2) => fs26.existsSync(`${localBin}${ext2}`)
|
|
2181
2197
|
);
|
|
2182
2198
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
2183
2199
|
return void 0;
|
|
@@ -2189,21 +2205,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2189
2205
|
if (this._scriptPath) {
|
|
2190
2206
|
let resolvedScriptPath;
|
|
2191
2207
|
try {
|
|
2192
|
-
resolvedScriptPath =
|
|
2208
|
+
resolvedScriptPath = fs26.realpathSync(this._scriptPath);
|
|
2193
2209
|
} catch (err2) {
|
|
2194
2210
|
resolvedScriptPath = this._scriptPath;
|
|
2195
2211
|
}
|
|
2196
|
-
executableDir =
|
|
2197
|
-
|
|
2212
|
+
executableDir = path26.resolve(
|
|
2213
|
+
path26.dirname(resolvedScriptPath),
|
|
2198
2214
|
executableDir
|
|
2199
2215
|
);
|
|
2200
2216
|
}
|
|
2201
2217
|
if (executableDir) {
|
|
2202
2218
|
let localFile = findFile(executableDir, executableFile);
|
|
2203
2219
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2204
|
-
const legacyName =
|
|
2220
|
+
const legacyName = path26.basename(
|
|
2205
2221
|
this._scriptPath,
|
|
2206
|
-
|
|
2222
|
+
path26.extname(this._scriptPath)
|
|
2207
2223
|
);
|
|
2208
2224
|
if (legacyName !== this._name) {
|
|
2209
2225
|
localFile = findFile(
|
|
@@ -2214,7 +2230,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2214
2230
|
}
|
|
2215
2231
|
executableFile = localFile || executableFile;
|
|
2216
2232
|
}
|
|
2217
|
-
launchWithNode = sourceExt.includes(
|
|
2233
|
+
launchWithNode = sourceExt.includes(path26.extname(executableFile));
|
|
2218
2234
|
let proc;
|
|
2219
2235
|
if (process2.platform !== "win32") {
|
|
2220
2236
|
if (launchWithNode) {
|
|
@@ -3054,7 +3070,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3054
3070
|
* @return {Command}
|
|
3055
3071
|
*/
|
|
3056
3072
|
nameFromFilename(filename) {
|
|
3057
|
-
this._name =
|
|
3073
|
+
this._name = path26.basename(filename, path26.extname(filename));
|
|
3058
3074
|
return this;
|
|
3059
3075
|
}
|
|
3060
3076
|
/**
|
|
@@ -3068,9 +3084,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3068
3084
|
* @param {string} [path]
|
|
3069
3085
|
* @return {(string|null|Command)}
|
|
3070
3086
|
*/
|
|
3071
|
-
executableDir(
|
|
3072
|
-
if (
|
|
3073
|
-
this._executableDir =
|
|
3087
|
+
executableDir(path27) {
|
|
3088
|
+
if (path27 === void 0) return this._executableDir;
|
|
3089
|
+
this._executableDir = path27;
|
|
3074
3090
|
return this;
|
|
3075
3091
|
}
|
|
3076
3092
|
/**
|
|
@@ -3367,9 +3383,9 @@ function attemptedCommandName(argv) {
|
|
|
3367
3383
|
}
|
|
3368
3384
|
|
|
3369
3385
|
// src/cli.ts
|
|
3370
|
-
import * as
|
|
3371
|
-
import * as
|
|
3372
|
-
import { homedir as
|
|
3386
|
+
import * as fs25 from "fs";
|
|
3387
|
+
import * as path25 from "path";
|
|
3388
|
+
import { homedir as homedir11 } from "os";
|
|
3373
3389
|
|
|
3374
3390
|
// src/walk_index.ts
|
|
3375
3391
|
init_define_import_meta_env();
|
|
@@ -3551,6 +3567,18 @@ function uninstallGemini() {
|
|
|
3551
3567
|
writeJsonSettings(p, settings);
|
|
3552
3568
|
return true;
|
|
3553
3569
|
}
|
|
3570
|
+
function isGeminiInstalled() {
|
|
3571
|
+
const settings = readGeminiSettings(geminiSettingsPath());
|
|
3572
|
+
const hooks = settings.hooks;
|
|
3573
|
+
if (hooks === void 0) return false;
|
|
3574
|
+
for (const event of GEMINI_HOOK_EVENTS) {
|
|
3575
|
+
const command = geminiHookCommand(GEMINI_EVENT_ARG[event]);
|
|
3576
|
+
for (const matcher of desiredMatchersFor(event)) {
|
|
3577
|
+
if (!groupHasTokenGoat(hooks[event], matcher, (c) => isCurrentGeminiTokenGoatCommand(c, command))) return false;
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
return true;
|
|
3581
|
+
}
|
|
3554
3582
|
|
|
3555
3583
|
// src/bridges/qwen_install.ts
|
|
3556
3584
|
init_define_import_meta_env();
|
|
@@ -3666,9 +3694,20 @@ function uninstallQwen() {
|
|
|
3666
3694
|
writeJsonSettings(p, settings);
|
|
3667
3695
|
return true;
|
|
3668
3696
|
}
|
|
3697
|
+
function isQwenInstalled() {
|
|
3698
|
+
const settings = readQwenSettings(qwenSettingsPath());
|
|
3699
|
+
const hooks = settings.hooks;
|
|
3700
|
+
if (hooks === void 0) return false;
|
|
3701
|
+
for (const event of QWEN_HOOK_EVENTS) {
|
|
3702
|
+
const command = qwenHookCommand(QWEN_EVENT_ARG[event]);
|
|
3703
|
+
if (!groupHasTokenGoat2(hooks[event], (c) => isCurrentQwenTokenGoatCommand(c, command))) return false;
|
|
3704
|
+
}
|
|
3705
|
+
return true;
|
|
3706
|
+
}
|
|
3669
3707
|
|
|
3670
3708
|
// src/bridges/pi_install.ts
|
|
3671
3709
|
init_define_import_meta_env();
|
|
3710
|
+
import * as fs4 from "node:fs";
|
|
3672
3711
|
import * as os4 from "node:os";
|
|
3673
3712
|
import * as path4 from "node:path";
|
|
3674
3713
|
|
|
@@ -4011,9 +4050,13 @@ function uninstallPi(opts = {}) {
|
|
|
4011
4050
|
const localRemoved = uninstallPiScope({ local: true });
|
|
4012
4051
|
return globalRemoved || localRemoved;
|
|
4013
4052
|
}
|
|
4053
|
+
function isPiInstalled(opts = {}) {
|
|
4054
|
+
return fs4.existsSync(piExtensionPath(opts));
|
|
4055
|
+
}
|
|
4014
4056
|
|
|
4015
4057
|
// src/bridges/opencode_install.ts
|
|
4016
4058
|
init_define_import_meta_env();
|
|
4059
|
+
import * as fs5 from "node:fs";
|
|
4017
4060
|
import * as os5 from "node:os";
|
|
4018
4061
|
import * as path5 from "node:path";
|
|
4019
4062
|
|
|
@@ -4315,10 +4358,13 @@ function installOpencode() {
|
|
|
4315
4358
|
function uninstallOpencode() {
|
|
4316
4359
|
return uninstallSingleFilePlugin(opencodePluginPath(), opencodeEntrySidecarPath());
|
|
4317
4360
|
}
|
|
4361
|
+
function isOpencodeInstalled() {
|
|
4362
|
+
return fs5.existsSync(opencodePluginPath());
|
|
4363
|
+
}
|
|
4318
4364
|
|
|
4319
4365
|
// src/bridges/openclaw_install.ts
|
|
4320
4366
|
init_define_import_meta_env();
|
|
4321
|
-
import * as
|
|
4367
|
+
import * as fs6 from "node:fs";
|
|
4322
4368
|
import * as os6 from "node:os";
|
|
4323
4369
|
import * as path6 from "node:path";
|
|
4324
4370
|
|
|
@@ -4470,7 +4516,7 @@ function openclawEntrySidecarPath() {
|
|
|
4470
4516
|
function readOpenclawConfig(p, opts = {}) {
|
|
4471
4517
|
let raw;
|
|
4472
4518
|
try {
|
|
4473
|
-
raw =
|
|
4519
|
+
raw = fs6.readFileSync(p, "utf8");
|
|
4474
4520
|
} catch {
|
|
4475
4521
|
return {};
|
|
4476
4522
|
}
|
|
@@ -4510,7 +4556,7 @@ function installOpenclaw() {
|
|
|
4510
4556
|
const pluginPath = openclawPluginPath();
|
|
4511
4557
|
let existingPlugin;
|
|
4512
4558
|
try {
|
|
4513
|
-
existingPlugin =
|
|
4559
|
+
existingPlugin = fs6.readFileSync(pluginPath, "utf8");
|
|
4514
4560
|
} catch {
|
|
4515
4561
|
existingPlugin = void 0;
|
|
4516
4562
|
}
|
|
@@ -4551,12 +4597,12 @@ function uninstallOpenclaw() {
|
|
|
4551
4597
|
const pluginPath = openclawPluginPath();
|
|
4552
4598
|
let removed = false;
|
|
4553
4599
|
try {
|
|
4554
|
-
|
|
4600
|
+
fs6.unlinkSync(pluginPath);
|
|
4555
4601
|
removed = true;
|
|
4556
4602
|
} catch {
|
|
4557
4603
|
}
|
|
4558
4604
|
try {
|
|
4559
|
-
|
|
4605
|
+
fs6.unlinkSync(openclawEntrySidecarPath());
|
|
4560
4606
|
} catch {
|
|
4561
4607
|
}
|
|
4562
4608
|
const settings = readOpenclawConfig(configPath2);
|
|
@@ -4593,134 +4639,15 @@ function uninstallOpenclaw() {
|
|
|
4593
4639
|
}
|
|
4594
4640
|
return removed;
|
|
4595
4641
|
}
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
var MAX_CAPTURE_BYTES = 32 * 1024 * 1024;
|
|
4606
|
-
var MIN_RECORD_STAT_BYTES = 32;
|
|
4607
|
-
function resolveFilter(command, filterName, cwd) {
|
|
4608
|
-
if (filterName) {
|
|
4609
|
-
const named = filterByName(filterName);
|
|
4610
|
-
if (named !== null) return named;
|
|
4611
|
-
}
|
|
4612
|
-
let argv;
|
|
4613
|
-
try {
|
|
4614
|
-
argv = shlexSplit(command);
|
|
4615
|
-
} catch {
|
|
4616
|
-
return null;
|
|
4617
|
-
}
|
|
4618
|
-
return selectFilter(argv, cwd);
|
|
4619
|
-
}
|
|
4620
|
-
function baseSpawnOptions(timeout, cwd, env) {
|
|
4621
|
-
return { shell: wrappedShell(), timeout: timeout * 1e3, cwd, env };
|
|
4622
|
-
}
|
|
4623
|
-
function signalExitCode(signal) {
|
|
4624
|
-
const num = os7.constants.signals[signal];
|
|
4625
|
-
return 128 + (num ?? 0);
|
|
4626
|
-
}
|
|
4627
|
-
function resolveProfile(explicit) {
|
|
4628
|
-
if (explicit) return explicit;
|
|
4629
|
-
try {
|
|
4630
|
-
const p = loadConfig().compression.profile;
|
|
4631
|
-
return p && p !== "auto" ? p : "balanced";
|
|
4632
|
-
} catch {
|
|
4633
|
-
return "balanced";
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
function resolveCompressLimits() {
|
|
4637
|
-
try {
|
|
4638
|
-
const bc = loadConfig().bash_compress;
|
|
4639
|
-
return { maxLines: bc.max_lines, maxBytes: bc.max_bytes };
|
|
4640
|
-
} catch {
|
|
4641
|
-
return { maxLines: 1e3, maxBytes: 64 * 1024 };
|
|
4642
|
-
}
|
|
4643
|
-
}
|
|
4644
|
-
function run(command, opts = {}) {
|
|
4645
|
-
const timeout = opts.timeout ?? DEFAULT_TIMEOUT_SECONDS;
|
|
4646
|
-
const filter2 = resolveFilter(command, opts.filterName, opts.cwd);
|
|
4647
|
-
if (filter2 === null) {
|
|
4648
|
-
if ((opts.maxTokens ?? 0) > 0) {
|
|
4649
|
-
return wrapAndCompress(command, new IdentityFilter(), timeout, resolveProfile(opts.compressionProfile), opts);
|
|
4650
|
-
}
|
|
4651
|
-
return passthrough(command, timeout, opts.cwd, opts.env);
|
|
4652
|
-
}
|
|
4653
|
-
return wrapAndCompress(command, filter2, timeout, resolveProfile(opts.compressionProfile), opts);
|
|
4654
|
-
}
|
|
4655
|
-
function runRaw(command, timeout = DEFAULT_TIMEOUT_SECONDS) {
|
|
4656
|
-
return passthrough(command, timeout, void 0, void 0);
|
|
4657
|
-
}
|
|
4658
|
-
function passthrough(command, timeout, cwd, env) {
|
|
4659
|
-
const result = spawnSync(command, { ...baseSpawnOptions(timeout, cwd, env), stdio: "inherit" });
|
|
4660
|
-
if (isTimeout(result.error)) return 124;
|
|
4661
|
-
if (result.status !== null) return result.status;
|
|
4662
|
-
if (result.signal) return signalExitCode(result.signal);
|
|
4663
|
-
return 0;
|
|
4664
|
-
}
|
|
4665
|
-
function isTimeout(error) {
|
|
4666
|
-
return !!error && error.code === "ETIMEDOUT";
|
|
4667
|
-
}
|
|
4668
|
-
function decode(buf) {
|
|
4669
|
-
if (buf == null) return "";
|
|
4670
|
-
return typeof buf === "string" ? buf : buf.toString("utf8");
|
|
4671
|
-
}
|
|
4672
|
-
function wrapAndCompress(command, filter2, timeout, profile, opts) {
|
|
4673
|
-
const writeStdout = opts.writeStdout ?? ((s) => process.stdout.write(s));
|
|
4674
|
-
const result = spawnSync(command, {
|
|
4675
|
-
...baseSpawnOptions(timeout, opts.cwd, opts.env),
|
|
4676
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
4677
|
-
maxBuffer: MAX_CAPTURE_BYTES
|
|
4678
|
-
});
|
|
4679
|
-
const timedOut = isTimeout(result.error);
|
|
4680
|
-
const overflowed = !!result.error && result.error.code === "ENOBUFS";
|
|
4681
|
-
let stdoutText = decode(result.stdout);
|
|
4682
|
-
let stderrText = decode(result.stderr);
|
|
4683
|
-
if (overflowed) {
|
|
4684
|
-
stdoutText += `
|
|
4685
|
-
[token-goat: capture capped at ${MAX_CAPTURE_BYTES / (1024 * 1024)} MiB]`;
|
|
4686
|
-
}
|
|
4687
|
-
let exitCode;
|
|
4688
|
-
if (timedOut) {
|
|
4689
|
-
exitCode = 124;
|
|
4690
|
-
stderrText = (stderrText ? stderrText + "\n" : "") + `[token-goat: command exceeded ${timeout}s timeout and was killed]`;
|
|
4691
|
-
} else if (result.status !== null) {
|
|
4692
|
-
exitCode = result.status;
|
|
4693
|
-
} else if (result.signal) {
|
|
4694
|
-
exitCode = signalExitCode(result.signal);
|
|
4695
|
-
} else {
|
|
4696
|
-
exitCode = 0;
|
|
4697
|
-
}
|
|
4698
|
-
let argv;
|
|
4699
|
-
try {
|
|
4700
|
-
argv = shlexSplit(command);
|
|
4701
|
-
} catch {
|
|
4702
|
-
argv = [command];
|
|
4703
|
-
}
|
|
4704
|
-
const limits = resolveCompressLimits();
|
|
4705
|
-
const compressed = compressOutput(filter2, stdoutText, stderrText, exitCode, argv, {
|
|
4706
|
-
compressionProfile: profile,
|
|
4707
|
-
maxLines: limits.maxLines,
|
|
4708
|
-
maxBytes: limits.maxBytes
|
|
4709
|
-
});
|
|
4710
|
-
const minNetSavingsBytes = resolveMinNetSavingsBytes();
|
|
4711
|
-
const applied = compressed.worthApplying(minNetSavingsBytes);
|
|
4712
|
-
let text = applied ? compressed.text : combineStreams(stdoutText, stderrText);
|
|
4713
|
-
const maxTokens = opts.maxTokens ?? 0;
|
|
4714
|
-
if (maxTokens > 0) text = capTokens(text, maxTokens);
|
|
4715
|
-
const marker = applied ? compressed.withMarker(minNetSavingsBytes).slice(compressed.text.length) : "";
|
|
4716
|
-
const body = text + marker;
|
|
4717
|
-
writeStdout(body.endsWith("\n") ? body : body + "\n");
|
|
4718
|
-
if (applied) recordSavings(compressed);
|
|
4719
|
-
return exitCode;
|
|
4720
|
-
}
|
|
4721
|
-
function recordSavings(result) {
|
|
4722
|
-
if (result.bytesSaved < MIN_RECORD_STAT_BYTES) return;
|
|
4723
|
-
recordStat(`bash_compress:${result.filterName}`, result.bytesSaved, result.tokensSaved);
|
|
4642
|
+
function isOpenclawInstalled() {
|
|
4643
|
+
if (!fs6.existsSync(openclawPluginPath())) return false;
|
|
4644
|
+
const settings = readOpenclawConfig(openclawConfigPath());
|
|
4645
|
+
const plugins = settings.plugins;
|
|
4646
|
+
if (plugins === void 0) return false;
|
|
4647
|
+
const targetFolded = foldPath(openclawPluginPath());
|
|
4648
|
+
const hasPath = (plugins.load?.paths ?? []).some((p) => foldPath(p) === targetFolded);
|
|
4649
|
+
const hasEntry = plugins.entries?.[OPENCLAW_PLUGIN_ID] !== void 0;
|
|
4650
|
+
return hasPath && hasEntry;
|
|
4724
4651
|
}
|
|
4725
4652
|
|
|
4726
4653
|
// src/bridges_status.ts
|
|
@@ -4894,8 +4821,8 @@ function formatBridgesStatus(matrix = BRIDGE_CAPABILITY_MATRIX) {
|
|
|
4894
4821
|
|
|
4895
4822
|
// src/sharepoint_resolve.ts
|
|
4896
4823
|
init_define_import_meta_env();
|
|
4897
|
-
import * as
|
|
4898
|
-
import * as
|
|
4824
|
+
import * as fs7 from "node:fs";
|
|
4825
|
+
import * as os7 from "node:os";
|
|
4899
4826
|
import * as path7 from "node:path";
|
|
4900
4827
|
var TENANT_HOST_RE = /^([a-z0-9-]+?)(-my)?\.sharepoint\.com$/i;
|
|
4901
4828
|
function parseShareUrl(url) {
|
|
@@ -4944,7 +4871,7 @@ function candidateRoots(env, home) {
|
|
|
4944
4871
|
if (commercial !== void 0) roots.push(commercial);
|
|
4945
4872
|
if (personal !== void 0 && personal !== commercial) roots.push(personal);
|
|
4946
4873
|
try {
|
|
4947
|
-
for (const entry of
|
|
4874
|
+
for (const entry of fs7.readdirSync(home, { withFileTypes: true })) {
|
|
4948
4875
|
if (entry.isDirectory() && /onedrive/i.test(entry.name)) {
|
|
4949
4876
|
const full = path7.join(home, entry.name);
|
|
4950
4877
|
if (!roots.includes(full)) roots.push(full);
|
|
@@ -4957,18 +4884,18 @@ function candidateRoots(env, home) {
|
|
|
4957
4884
|
function tryLibraryPaths(root, libSegments, triedPaths) {
|
|
4958
4885
|
const rawJoined = path7.join(root, ...libSegments);
|
|
4959
4886
|
triedPaths.push(rawJoined);
|
|
4960
|
-
if (
|
|
4887
|
+
if (fs7.existsSync(rawJoined)) return rawJoined;
|
|
4961
4888
|
if (libSegments.length > 0) {
|
|
4962
4889
|
const aliasedFirst = normalizeLibrarySegment(libSegments[0]);
|
|
4963
4890
|
if (aliasedFirst !== libSegments[0]) {
|
|
4964
4891
|
const aliasedJoined = path7.join(root, aliasedFirst, ...libSegments.slice(1));
|
|
4965
4892
|
triedPaths.push(aliasedJoined);
|
|
4966
|
-
if (
|
|
4893
|
+
if (fs7.existsSync(aliasedJoined)) return aliasedJoined;
|
|
4967
4894
|
}
|
|
4968
4895
|
}
|
|
4969
4896
|
return null;
|
|
4970
4897
|
}
|
|
4971
|
-
function resolveLocalPath(parsed, env = process.env, home =
|
|
4898
|
+
function resolveLocalPath(parsed, env = process.env, home = os7.homedir()) {
|
|
4972
4899
|
const roots = candidateRoots(env, home);
|
|
4973
4900
|
const libSegments = parsed.libraryPath.split(/[/\\]+/).filter((s) => s.length > 0 && s !== "." && s !== "..");
|
|
4974
4901
|
const triedPaths = [];
|
|
@@ -4987,7 +4914,7 @@ function resolveLocalPath(parsed, env = process.env, home = os8.homedir()) {
|
|
|
4987
4914
|
if (found !== null) return { resolvedPath: found, triedPaths };
|
|
4988
4915
|
if (parsed.siteType === "site" && parsed.siteName.length > 0) {
|
|
4989
4916
|
try {
|
|
4990
|
-
for (const entry of
|
|
4917
|
+
for (const entry of fs7.readdirSync(root, { withFileTypes: true })) {
|
|
4991
4918
|
if (!entry.isDirectory() || !entry.name.toLowerCase().includes(parsed.siteName.toLowerCase())) continue;
|
|
4992
4919
|
const siteRoot = path7.join(root, entry.name);
|
|
4993
4920
|
const siteFound = safeTryLibraryPaths(siteRoot, libSegments, triedPaths);
|
|
@@ -5002,12 +4929,12 @@ function resolveLocalPath(parsed, env = process.env, home = os8.homedir()) {
|
|
|
5002
4929
|
|
|
5003
4930
|
// src/video_chapters.ts
|
|
5004
4931
|
init_define_import_meta_env();
|
|
5005
|
-
import { spawnSync
|
|
4932
|
+
import { spawnSync } from "node:child_process";
|
|
5006
4933
|
var _ffprobeAvailable;
|
|
5007
4934
|
function isFfprobeAvailable() {
|
|
5008
4935
|
if (_ffprobeAvailable !== void 0) return _ffprobeAvailable;
|
|
5009
4936
|
try {
|
|
5010
|
-
const res =
|
|
4937
|
+
const res = spawnSync("ffprobe", ["-version"], { stdio: "ignore" });
|
|
5011
4938
|
_ffprobeAvailable = res.status === 0;
|
|
5012
4939
|
} catch {
|
|
5013
4940
|
_ffprobeAvailable = false;
|
|
@@ -5018,7 +4945,7 @@ function extractVideoChapters(file) {
|
|
|
5018
4945
|
if (!isFfprobeAvailable()) {
|
|
5019
4946
|
throw new Error("ffprobe not found on PATH; video-chapters requires ffmpeg (install ffmpeg and ensure ffprobe is on PATH)");
|
|
5020
4947
|
}
|
|
5021
|
-
const res =
|
|
4948
|
+
const res = spawnSync(
|
|
5022
4949
|
"ffprobe",
|
|
5023
4950
|
["-v", "error", "-print_format", "json", "-show_chapters", "-show_streams", file],
|
|
5024
4951
|
{ encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
|
|
@@ -5050,7 +4977,7 @@ function extractVideoChapters(file) {
|
|
|
5050
4977
|
|
|
5051
4978
|
// src/transcript_extract.ts
|
|
5052
4979
|
init_define_import_meta_env();
|
|
5053
|
-
import * as
|
|
4980
|
+
import * as fs8 from "node:fs";
|
|
5054
4981
|
var TIMESTAMP_RE = /(\d{1,2}:)?(\d{2}):(\d{2})[.,](\d{1,3})/;
|
|
5055
4982
|
var CUE_LINE_RE = new RegExp(`^\\s*${TIMESTAMP_RE.source}\\s*-->\\s*${TIMESTAMP_RE.source}`);
|
|
5056
4983
|
var V_TAG_RE = /^<v(?:\.\w+)?\s+([^>]+)>\s*(.*)$/;
|
|
@@ -5102,7 +5029,7 @@ function parseTranscript(content) {
|
|
|
5102
5029
|
return cues;
|
|
5103
5030
|
}
|
|
5104
5031
|
function readTranscript(filePath) {
|
|
5105
|
-
const content =
|
|
5032
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
5106
5033
|
return parseTranscript(content);
|
|
5107
5034
|
}
|
|
5108
5035
|
function formatTimestamp(seconds) {
|
|
@@ -5162,10 +5089,64 @@ function formatCues(cues) {
|
|
|
5162
5089
|
return cues.map((cue) => `[${formatTimestamp(cue.startSeconds)}]${cue.speaker !== null ? ` ${cue.speaker}:` : ""} ${cue.text}`).join("\n");
|
|
5163
5090
|
}
|
|
5164
5091
|
|
|
5165
|
-
// src/
|
|
5092
|
+
// src/purge.ts
|
|
5166
5093
|
init_define_import_meta_env();
|
|
5167
|
-
import * as
|
|
5094
|
+
import * as fs9 from "node:fs";
|
|
5168
5095
|
import * as path8 from "node:path";
|
|
5096
|
+
function directorySize(root) {
|
|
5097
|
+
let total = 0;
|
|
5098
|
+
let entries;
|
|
5099
|
+
try {
|
|
5100
|
+
entries = fs9.readdirSync(root, { withFileTypes: true });
|
|
5101
|
+
} catch {
|
|
5102
|
+
return 0;
|
|
5103
|
+
}
|
|
5104
|
+
for (const entry of entries) {
|
|
5105
|
+
const full = path8.join(root, entry.name);
|
|
5106
|
+
if (entry.isDirectory()) {
|
|
5107
|
+
total += directorySize(full);
|
|
5108
|
+
continue;
|
|
5109
|
+
}
|
|
5110
|
+
if (!entry.isFile()) continue;
|
|
5111
|
+
try {
|
|
5112
|
+
total += fs9.statSync(full).size;
|
|
5113
|
+
} catch {
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
return total;
|
|
5117
|
+
}
|
|
5118
|
+
function purgeRoots() {
|
|
5119
|
+
const roots = [dataDir(), tokenGoatHome()];
|
|
5120
|
+
return roots.filter((root, index) => roots.indexOf(root) === index);
|
|
5121
|
+
}
|
|
5122
|
+
function purgeDataDirectories() {
|
|
5123
|
+
const result = { removed: [], absent: [], failed: [] };
|
|
5124
|
+
for (const root of purgeRoots()) {
|
|
5125
|
+
if (!fs9.existsSync(root)) {
|
|
5126
|
+
result.absent.push(root);
|
|
5127
|
+
continue;
|
|
5128
|
+
}
|
|
5129
|
+
const bytes = directorySize(root);
|
|
5130
|
+
try {
|
|
5131
|
+
fs9.rmSync(root, { recursive: true, force: true });
|
|
5132
|
+
result.removed.push({ path: root, bytes });
|
|
5133
|
+
} catch (e) {
|
|
5134
|
+
result.failed.push({ path: root, reason: e instanceof Error ? e.message : String(e) });
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
return result;
|
|
5138
|
+
}
|
|
5139
|
+
function formatBytes(bytes) {
|
|
5140
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
5141
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
5142
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
5143
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
5144
|
+
}
|
|
5145
|
+
|
|
5146
|
+
// src/cli_stats.ts
|
|
5147
|
+
init_define_import_meta_env();
|
|
5148
|
+
import * as fs10 from "node:fs";
|
|
5149
|
+
import * as path9 from "node:path";
|
|
5169
5150
|
function writeRaw(text) {
|
|
5170
5151
|
const payload = colorStdout() ? text : stripAnsi(text);
|
|
5171
5152
|
process.stdout.write(ensureNewline(payload));
|
|
@@ -5177,8 +5158,8 @@ function formatTopFiles(ranked) {
|
|
|
5177
5158
|
if (ranked.length === 0) return "";
|
|
5178
5159
|
const lines = ["Top files this session:"];
|
|
5179
5160
|
for (const { path: filePath, count } of ranked) {
|
|
5180
|
-
const
|
|
5181
|
-
lines.push(` ${count.toString().padStart(3)}x ${
|
|
5161
|
+
const basename7 = path9.basename(filePath);
|
|
5162
|
+
lines.push(` ${count.toString().padStart(3)}x ${basename7} (${filePath})`);
|
|
5182
5163
|
}
|
|
5183
5164
|
return lines.join("\n");
|
|
5184
5165
|
}
|
|
@@ -5194,12 +5175,12 @@ function renderTopSessionFiles(topN = 5) {
|
|
|
5194
5175
|
}
|
|
5195
5176
|
function renderTopSessionFilesFromDisk(topN = 5, overrideSessionsDir) {
|
|
5196
5177
|
try {
|
|
5197
|
-
const sessionsDir = overrideSessionsDir ??
|
|
5198
|
-
if (!
|
|
5199
|
-
const files =
|
|
5178
|
+
const sessionsDir = overrideSessionsDir ?? path9.join(dataDir(), "sessions");
|
|
5179
|
+
if (!fs10.existsSync(sessionsDir)) return "";
|
|
5180
|
+
const files = fs10.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, mtime: fs10.statSync(path9.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).slice(0, 3);
|
|
5200
5181
|
for (const { name } of files) {
|
|
5201
5182
|
try {
|
|
5202
|
-
const raw =
|
|
5183
|
+
const raw = fs10.readFileSync(path9.join(sessionsDir, name), "utf-8");
|
|
5203
5184
|
const data = JSON.parse(raw);
|
|
5204
5185
|
const filesList = data["files"];
|
|
5205
5186
|
if (!Array.isArray(filesList)) continue;
|
|
@@ -5281,58 +5262,596 @@ function runStats(opts = {}) {
|
|
|
5281
5262
|
}
|
|
5282
5263
|
}
|
|
5283
5264
|
|
|
5284
|
-
// src/
|
|
5285
|
-
init_define_import_meta_env();
|
|
5286
|
-
|
|
5287
|
-
// src/webfetch.ts
|
|
5265
|
+
// src/cli_doctor.ts
|
|
5288
5266
|
init_define_import_meta_env();
|
|
5289
|
-
import
|
|
5290
|
-
import * as
|
|
5291
|
-
import * as
|
|
5292
|
-
import {
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
5304
|
-
"localhost",
|
|
5305
|
-
"ip6-localhost",
|
|
5306
|
-
"ip6-loopback",
|
|
5307
|
-
"metadata.google.internal",
|
|
5308
|
-
"169.254.169.254"
|
|
5309
|
-
]);
|
|
5310
|
-
function truncateUrl(url, maxLen = MAX_URL_IN_ERROR) {
|
|
5311
|
-
const sanitized = url.replace(/[\r\n]/g, "");
|
|
5312
|
-
return sanitized.length > maxLen ? sanitized.slice(0, maxLen) + "\u2026" : sanitized;
|
|
5313
|
-
}
|
|
5314
|
-
async function resolveSsrfSafeAddress(hostname) {
|
|
5315
|
-
const hostnameLower = hostname.toLowerCase().replace(/\.$/, "");
|
|
5316
|
-
if (BLOCKED_HOSTNAMES.has(hostnameLower)) return { kind: "blocked" };
|
|
5317
|
-
let results;
|
|
5267
|
+
import * as fs11 from "fs";
|
|
5268
|
+
import * as os8 from "os";
|
|
5269
|
+
import * as path10 from "path";
|
|
5270
|
+
import { execSync, spawnSync as spawnSync2 } from "child_process";
|
|
5271
|
+
function globalMcpConfigPath() {
|
|
5272
|
+
const copilotHome = process.env["COPILOT_HOME"];
|
|
5273
|
+
const root = copilotHome !== void 0 && copilotHome.trim() !== "" ? path10.resolve(copilotHome) : path10.join(os8.homedir(), ".copilot");
|
|
5274
|
+
return path10.join(root, "mcp-config.json");
|
|
5275
|
+
}
|
|
5276
|
+
function checkGlobalMcpConfig(configPath2 = globalMcpConfigPath()) {
|
|
5277
|
+
if (!fs11.existsSync(configPath2)) {
|
|
5278
|
+
return { name: "Global MCP configuration", status: "ok", message: `no global Copilot MCP configuration found at ${configPath2}` };
|
|
5279
|
+
}
|
|
5280
|
+
let parsed;
|
|
5318
5281
|
try {
|
|
5319
|
-
|
|
5320
|
-
if (!Array.isArray(r) || r.length === 0) return { kind: "unresolved" };
|
|
5321
|
-
results = r;
|
|
5282
|
+
parsed = JSON.parse(fs11.readFileSync(configPath2, "utf8"));
|
|
5322
5283
|
} catch {
|
|
5323
|
-
return {
|
|
5284
|
+
return {
|
|
5285
|
+
name: "Global MCP configuration",
|
|
5286
|
+
status: "warn",
|
|
5287
|
+
message: `could not read global Copilot MCP configuration at ${configPath2}; unable to audit heavy launchers.`
|
|
5288
|
+
};
|
|
5324
5289
|
}
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5290
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
5291
|
+
return {
|
|
5292
|
+
name: "Global MCP configuration",
|
|
5293
|
+
status: "warn",
|
|
5294
|
+
message: `global Copilot MCP configuration at ${configPath2} has an unsupported format; unable to audit heavy launchers.`
|
|
5295
|
+
};
|
|
5329
5296
|
}
|
|
5330
|
-
const
|
|
5331
|
-
if (
|
|
5332
|
-
|
|
5297
|
+
const configuredServers = parsed["mcpServers"];
|
|
5298
|
+
if (typeof configuredServers !== "object" || configuredServers === null || Array.isArray(configuredServers)) {
|
|
5299
|
+
return { name: "Global MCP configuration", status: "ok", message: `no global stdio MCP servers configured at ${configPath2}` };
|
|
5300
|
+
}
|
|
5301
|
+
let chromeDevTools = 0;
|
|
5302
|
+
let playwright = 0;
|
|
5303
|
+
for (const server of Object.values(configuredServers)) {
|
|
5304
|
+
if (typeof server !== "object" || server === null || Array.isArray(server)) continue;
|
|
5305
|
+
const entry = server;
|
|
5306
|
+
const rawCommand = entry["command"];
|
|
5307
|
+
const command = typeof rawCommand === "string" ? rawCommand : "";
|
|
5308
|
+
const args = entry["args"];
|
|
5309
|
+
if (!/\bnpx(?:\.cmd)?\b/i.test(command) || !Array.isArray(args)) continue;
|
|
5310
|
+
const invocation = args.filter((arg) => typeof arg === "string").join(" ");
|
|
5311
|
+
if (/\bchrome-devtools-mcp\b/i.test(invocation)) chromeDevTools += 1;
|
|
5312
|
+
if (/@playwright[\\/]mcp\b/i.test(invocation)) playwright += 1;
|
|
5313
|
+
}
|
|
5314
|
+
if (chromeDevTools > 0 || playwright > 0) {
|
|
5315
|
+
const launchers = [];
|
|
5316
|
+
if (chromeDevTools > 0) launchers.push(`${chromeDevTools} Chrome DevTools MCP launcher${chromeDevTools === 1 ? "" : "s"}`);
|
|
5317
|
+
if (playwright > 0) launchers.push(`${playwright} Playwright MCP launcher${playwright === 1 ? "" : "s"}`);
|
|
5318
|
+
return {
|
|
5319
|
+
name: "Global MCP configuration",
|
|
5320
|
+
status: "warn",
|
|
5321
|
+
message: `${launchers.join(" and ")} configured at ${configPath2}. Move heavy launchers to project scope or remove them when not actively needed.`
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5324
|
+
return { name: "Global MCP configuration", status: "ok", message: `no known heavy global MCP launchers configured at ${configPath2}` };
|
|
5333
5325
|
}
|
|
5334
|
-
function
|
|
5335
|
-
|
|
5326
|
+
function checkMcpProcessHealth(processes) {
|
|
5327
|
+
if (processes === null) {
|
|
5328
|
+
return {
|
|
5329
|
+
name: "MCP process health",
|
|
5330
|
+
status: "warn",
|
|
5331
|
+
message: "could not read the process list (PowerShell did not answer), so duplicate MCP launchers and orphaned Node processes were not checked"
|
|
5332
|
+
};
|
|
5333
|
+
}
|
|
5334
|
+
const byPid = new Set(processes.map((process2) => process2.processId));
|
|
5335
|
+
const nodeProcesses = processes.filter((process2) => process2.name.toLowerCase() === "node.exe");
|
|
5336
|
+
const chromeLaunchers = nodeProcesses.filter((process2) => /npx-cli\.js.*chrome-devtools-mcp/i.test(process2.commandLine));
|
|
5337
|
+
const playwrightLaunchers = nodeProcesses.filter((process2) => /npx-cli\.js.*@playwright[\\/]mcp/i.test(process2.commandLine));
|
|
5338
|
+
const orphanedNodeProcesses = nodeProcesses.filter((process2) => !byPid.has(process2.parentProcessId));
|
|
5339
|
+
const launchers = chromeLaunchers.length + playwrightLaunchers.length;
|
|
5340
|
+
if (launchers > 2 || orphanedNodeProcesses.length > 0) {
|
|
5341
|
+
const details = [];
|
|
5342
|
+
if (chromeLaunchers.length > 1) details.push(`${chromeLaunchers.length} Chrome DevTools MCP launchers`);
|
|
5343
|
+
if (playwrightLaunchers.length > 1) details.push(`${playwrightLaunchers.length} Playwright MCP launchers`);
|
|
5344
|
+
if (orphanedNodeProcesses.length > 0) details.push(`${orphanedNodeProcesses.length} orphaned Node process${orphanedNodeProcesses.length === 1 ? "" : "es"}`);
|
|
5345
|
+
return {
|
|
5346
|
+
name: "MCP process health",
|
|
5347
|
+
status: "warn",
|
|
5348
|
+
message: `${details.join("; ")} detected. These are host-managed processes; close stale Copilot sessions before terminating a specific confirmed orphan.`
|
|
5349
|
+
};
|
|
5350
|
+
}
|
|
5351
|
+
return { name: "MCP process health", status: "ok", message: "no duplicate MCP launchers or orphaned Node processes detected" };
|
|
5352
|
+
}
|
|
5353
|
+
function runProcessListCommand() {
|
|
5354
|
+
const command = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name,CommandLine | ConvertTo-Json -Compress";
|
|
5355
|
+
return execSync(`powershell.exe -NoProfile -NonInteractive -Command "${command}"`, {
|
|
5356
|
+
encoding: "utf8",
|
|
5357
|
+
timeout: 2e4,
|
|
5358
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
5359
|
+
windowsHide: true
|
|
5360
|
+
});
|
|
5361
|
+
}
|
|
5362
|
+
function readWindowsProcesses(runCommand = runProcessListCommand) {
|
|
5363
|
+
if (process.platform !== "win32") return [];
|
|
5364
|
+
try {
|
|
5365
|
+
const output = runCommand().trim();
|
|
5366
|
+
if (output === "") return [];
|
|
5367
|
+
const parsed = JSON.parse(output);
|
|
5368
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
5369
|
+
return rows.flatMap((row) => {
|
|
5370
|
+
if (typeof row !== "object" || row === null) return [];
|
|
5371
|
+
const value = row;
|
|
5372
|
+
if (typeof value["ProcessId"] !== "number" || typeof value["ParentProcessId"] !== "number" || typeof value["Name"] !== "string") return [];
|
|
5373
|
+
return [{
|
|
5374
|
+
processId: value["ProcessId"],
|
|
5375
|
+
parentProcessId: value["ParentProcessId"],
|
|
5376
|
+
name: value["Name"],
|
|
5377
|
+
commandLine: typeof value["CommandLine"] === "string" ? value["CommandLine"] : ""
|
|
5378
|
+
}];
|
|
5379
|
+
});
|
|
5380
|
+
} catch {
|
|
5381
|
+
return null;
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
function checkWorkerRunning(dataDir2) {
|
|
5385
|
+
return dataDir2 !== void 0 ? isWorkerRunning(dataDir2) : isWorkerRunning();
|
|
5386
|
+
}
|
|
5387
|
+
var DB_SIZE_WARN_BYTES = 1024 * 1024 * 1024;
|
|
5388
|
+
function checkDbExists(dataDir2) {
|
|
5389
|
+
const dbPath = path10.join(dataDir2, "global.db");
|
|
5390
|
+
if (!fs11.existsSync(dbPath)) {
|
|
5391
|
+
return {
|
|
5392
|
+
name: "Database",
|
|
5393
|
+
status: "warn",
|
|
5394
|
+
message: `global.db not found at ${dbPath}`
|
|
5395
|
+
};
|
|
5396
|
+
}
|
|
5397
|
+
const sizeBytes = fs11.statSync(dbPath).size;
|
|
5398
|
+
const SQLITE_HEADER = "SQLite format 3\0";
|
|
5399
|
+
let header = "";
|
|
5400
|
+
try {
|
|
5401
|
+
const fd = fs11.openSync(dbPath, "r");
|
|
5402
|
+
try {
|
|
5403
|
+
const buf = Buffer.alloc(SQLITE_HEADER.length);
|
|
5404
|
+
const bytesRead = fs11.readSync(fd, buf, 0, buf.length, 0);
|
|
5405
|
+
header = buf.toString("latin1", 0, bytesRead);
|
|
5406
|
+
} finally {
|
|
5407
|
+
fs11.closeSync(fd);
|
|
5408
|
+
}
|
|
5409
|
+
} catch {
|
|
5410
|
+
}
|
|
5411
|
+
if (header !== SQLITE_HEADER) {
|
|
5412
|
+
return {
|
|
5413
|
+
name: "Database",
|
|
5414
|
+
status: "fail",
|
|
5415
|
+
message: `global.db at ${dbPath} is not a valid SQLite file (${sizeBytes} bytes) \u2014 likely truncated or corrupt`
|
|
5416
|
+
};
|
|
5417
|
+
}
|
|
5418
|
+
if (sizeBytes > DB_SIZE_WARN_BYTES) {
|
|
5419
|
+
return {
|
|
5420
|
+
name: "Database",
|
|
5421
|
+
status: "warn",
|
|
5422
|
+
message: `global.db is ${Math.round(sizeBytes / (1024 * 1024))} MB at ${dbPath} \u2014 far larger than a healthy index. Large writes against it can exceed the 15s busy_timeout and appear as "database is locked". Try 'token-goat reclaim-index' first (a plain VACUUM, cheap, can recover a useful amount on its own); only reach for 'token-goat reclaim-index --rebuild' if that isn't enough, since --rebuild reparses and re-embeds every indexed file across every project and can take a long time on a large multi-project index`
|
|
5423
|
+
};
|
|
5424
|
+
}
|
|
5425
|
+
return {
|
|
5426
|
+
name: "Database",
|
|
5427
|
+
status: "ok",
|
|
5428
|
+
message: `global.db exists (${toKB(sizeBytes)} KB) at ${dbPath}`
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5431
|
+
function checkSymbolCount(dbPath, rootDir) {
|
|
5432
|
+
if (!fs11.existsSync(dbPath)) {
|
|
5433
|
+
return { name: "Symbols", status: "ok", message: "no database yet" };
|
|
5434
|
+
}
|
|
5435
|
+
try {
|
|
5436
|
+
const { fileCount, symbolCount } = getProjectIndexCounts(dbPath, rootDir);
|
|
5437
|
+
if (fileCount > 0 && symbolCount === 0) {
|
|
5438
|
+
return {
|
|
5439
|
+
name: "Symbols",
|
|
5440
|
+
status: "warn",
|
|
5441
|
+
message: `${fileCount} file(s) indexed but 0 symbols extracted \u2014 the parser may not be running (check the worker log); try 'token-goat index --force'`
|
|
5442
|
+
};
|
|
5443
|
+
}
|
|
5444
|
+
if (fileCount === 0 && symbolCount === 0) {
|
|
5445
|
+
return {
|
|
5446
|
+
name: "Symbols",
|
|
5447
|
+
status: "warn",
|
|
5448
|
+
message: emptyIndexMessage(rootDir ?? process.cwd())
|
|
5449
|
+
};
|
|
5450
|
+
}
|
|
5451
|
+
return {
|
|
5452
|
+
name: "Symbols",
|
|
5453
|
+
status: "ok",
|
|
5454
|
+
message: `${symbolCount} symbol(s) across ${fileCount} indexed file(s)`
|
|
5455
|
+
};
|
|
5456
|
+
} catch (err2) {
|
|
5457
|
+
return {
|
|
5458
|
+
name: "Symbols",
|
|
5459
|
+
status: "warn",
|
|
5460
|
+
message: `could not query symbol count: ${extractErrorMessage(err2)}`
|
|
5461
|
+
};
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
var DIRTY_QUEUE_BACKLOG_WARN_THRESHOLD = 500;
|
|
5465
|
+
function checkDirtyQueueHealth(dataDir2) {
|
|
5466
|
+
let pendingCount = 0;
|
|
5467
|
+
try {
|
|
5468
|
+
const raw = fs11.readFileSync(dirtyQueuePathFor(dataDir2), "utf8");
|
|
5469
|
+
pendingCount = raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).length;
|
|
5470
|
+
} catch {
|
|
5471
|
+
}
|
|
5472
|
+
if (pendingCount > DIRTY_QUEUE_BACKLOG_WARN_THRESHOLD) {
|
|
5473
|
+
return {
|
|
5474
|
+
name: "Dirty queue",
|
|
5475
|
+
status: "warn",
|
|
5476
|
+
message: `${pendingCount} file(s) pending reindex -- the worker may be falling behind or stalled; check 'token-goat worker status'`
|
|
5477
|
+
};
|
|
5478
|
+
}
|
|
5479
|
+
if (!isWorkerRunning(dataDir2)) {
|
|
5480
|
+
return { name: "Dirty queue", status: "ok", message: `${pendingCount} file(s) pending (worker not running)` };
|
|
5481
|
+
}
|
|
5482
|
+
let heartbeatAgeMs = null;
|
|
5483
|
+
try {
|
|
5484
|
+
heartbeatAgeMs = Date.now() - fs11.statSync(drainHeartbeatPathFor(dataDir2)).mtimeMs;
|
|
5485
|
+
} catch {
|
|
5486
|
+
}
|
|
5487
|
+
if (heartbeatAgeMs !== null && heartbeatAgeMs > WORKER_HEARTBEAT_STALE_MS) {
|
|
5488
|
+
return {
|
|
5489
|
+
name: "Dirty queue",
|
|
5490
|
+
status: "warn",
|
|
5491
|
+
message: `worker process is running but hasn't completed a drain cycle in ${Math.round(heartbeatAgeMs / 1e3)}s -- possibly deadlocked or stuck; check the worker error log`
|
|
5492
|
+
};
|
|
5493
|
+
}
|
|
5494
|
+
return { name: "Dirty queue", status: "ok", message: `${pendingCount} file(s) pending, worker actively draining` };
|
|
5495
|
+
}
|
|
5496
|
+
function checkInstall() {
|
|
5497
|
+
try {
|
|
5498
|
+
const output = execSync("token-goat --version", { encoding: "utf-8" });
|
|
5499
|
+
return {
|
|
5500
|
+
name: "Installation",
|
|
5501
|
+
status: "ok",
|
|
5502
|
+
message: output.trim()
|
|
5503
|
+
};
|
|
5504
|
+
} catch {
|
|
5505
|
+
return {
|
|
5506
|
+
name: "Installation",
|
|
5507
|
+
status: "fail",
|
|
5508
|
+
message: "token-goat command not found; run: npm install -g token-goat-ts"
|
|
5509
|
+
};
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
function checkTsCompiler() {
|
|
5513
|
+
if (isAvailable()) {
|
|
5514
|
+
return { name: "TypeScript compiler", status: "ok", message: "available" };
|
|
5515
|
+
}
|
|
5516
|
+
const err2 = loadError();
|
|
5517
|
+
return {
|
|
5518
|
+
name: "TypeScript compiler",
|
|
5519
|
+
status: "warn",
|
|
5520
|
+
message: err2 !== null ? `unavailable: ${extractErrorMessage(err2)}` : "unavailable (not attempted)"
|
|
5521
|
+
};
|
|
5522
|
+
}
|
|
5523
|
+
function checkConfigValid(configPath2) {
|
|
5524
|
+
if (!fs11.existsSync(configPath2)) {
|
|
5525
|
+
return {
|
|
5526
|
+
name: "Config",
|
|
5527
|
+
status: "warn",
|
|
5528
|
+
message: `config file not found at ${configPath2}`
|
|
5529
|
+
};
|
|
5530
|
+
}
|
|
5531
|
+
try {
|
|
5532
|
+
const content = fs11.readFileSync(configPath2, "utf-8");
|
|
5533
|
+
parse(content);
|
|
5534
|
+
return {
|
|
5535
|
+
name: "Config",
|
|
5536
|
+
status: "ok",
|
|
5537
|
+
message: `config file valid (${content.length} bytes)`
|
|
5538
|
+
};
|
|
5539
|
+
} catch (err2) {
|
|
5540
|
+
return {
|
|
5541
|
+
name: "Config",
|
|
5542
|
+
status: "fail",
|
|
5543
|
+
message: `config invalid: ${extractErrorMessage(err2, "unknown error")}`
|
|
5544
|
+
};
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
function formatDiskSpace(bytes) {
|
|
5548
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
5549
|
+
let value = bytes;
|
|
5550
|
+
let unitIndex = 0;
|
|
5551
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
5552
|
+
value /= 1024;
|
|
5553
|
+
unitIndex++;
|
|
5554
|
+
}
|
|
5555
|
+
return `${value.toFixed(1)} ${units[unitIndex]}`;
|
|
5556
|
+
}
|
|
5557
|
+
var LOW_DISK_WARN_BYTES = 1024 * 1024 * 1024;
|
|
5558
|
+
function checkDiskSpace(dataDir2) {
|
|
5559
|
+
if (typeof fs11.statfsSync === "function") {
|
|
5560
|
+
try {
|
|
5561
|
+
const stats = fs11.statfsSync(dataDir2);
|
|
5562
|
+
const availableBytes = stats.bavail * stats.bsize;
|
|
5563
|
+
const status = availableBytes < LOW_DISK_WARN_BYTES ? "warn" : "ok";
|
|
5564
|
+
const suffix = status === "warn" ? " \u2014 running low, indexing/embeddings writes may start failing" : "";
|
|
5565
|
+
return { name: "Disk Space", status, message: `${formatDiskSpace(availableBytes)} available${suffix}` };
|
|
5566
|
+
} catch {
|
|
5567
|
+
}
|
|
5568
|
+
}
|
|
5569
|
+
if (process.platform !== "win32") {
|
|
5570
|
+
try {
|
|
5571
|
+
const result = spawnSync2("df", ["-Pk", dataDir2], { encoding: "utf-8" });
|
|
5572
|
+
const stdout = typeof result.stdout === "string" ? result.stdout : "";
|
|
5573
|
+
if (result.error === void 0 && result.status === 0 && stdout) {
|
|
5574
|
+
const lines = stdout.trim().split("\n");
|
|
5575
|
+
if (lines.length >= 2) {
|
|
5576
|
+
const parts = lines[1].trim().split(/\s+/);
|
|
5577
|
+
const availableKb = Number.parseInt(parts[3] ?? "", 10);
|
|
5578
|
+
if (Number.isFinite(availableKb)) {
|
|
5579
|
+
const availableBytes = availableKb * 1024;
|
|
5580
|
+
const status = availableBytes < LOW_DISK_WARN_BYTES ? "warn" : "ok";
|
|
5581
|
+
const suffix = status === "warn" ? " \u2014 running low, indexing/embeddings writes may start failing" : "";
|
|
5582
|
+
return { name: "Disk Space", status, message: `${formatDiskSpace(availableBytes)} available${suffix}` };
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
} catch {
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
return { name: "Disk Space", status: "warn", message: "disk space check unavailable on this platform" };
|
|
5590
|
+
}
|
|
5591
|
+
function checkCopilotCli(configPath2, scriptPath) {
|
|
5592
|
+
if (!fs11.existsSync(configPath2) || !fs11.existsSync(scriptPath)) {
|
|
5593
|
+
return null;
|
|
5594
|
+
}
|
|
5595
|
+
let config;
|
|
5596
|
+
try {
|
|
5597
|
+
config = JSON.parse(fs11.readFileSync(configPath2, "utf-8"));
|
|
5598
|
+
} catch (err2) {
|
|
5599
|
+
return {
|
|
5600
|
+
name: "Copilot CLI",
|
|
5601
|
+
status: "fail",
|
|
5602
|
+
message: `hook config at ${configPath2} is not valid JSON: ${extractErrorMessage(err2, "unknown error")}`
|
|
5603
|
+
};
|
|
5604
|
+
}
|
|
5605
|
+
const preToolUseCommand = config.hooks?.["preToolUse"]?.[0]?.command;
|
|
5606
|
+
if (typeof preToolUseCommand !== "string" || preToolUseCommand === "") {
|
|
5607
|
+
return {
|
|
5608
|
+
name: "Copilot CLI",
|
|
5609
|
+
status: "fail",
|
|
5610
|
+
message: `hook config at ${configPath2} has no preToolUse entry; run: token-goat install --copilot`
|
|
5611
|
+
};
|
|
5612
|
+
}
|
|
5613
|
+
const bakedExecPath = /^"([^"]+)"/.exec(preToolUseCommand)?.[1];
|
|
5614
|
+
if (bakedExecPath !== void 0 && !fs11.existsSync(bakedExecPath)) {
|
|
5615
|
+
return {
|
|
5616
|
+
name: "Copilot CLI",
|
|
5617
|
+
status: "fail",
|
|
5618
|
+
message: `hook points at a node binary that no longer exists (${bakedExecPath}) -- likely stale after an nvm/fnm/volta node upgrade. Recovery: run "token-goat install --copilot", then fully restart Copilot CLI (renaming/reinstalling the hook has no effect on an already-running session -- Copilot caches hook configs at startup).`
|
|
5619
|
+
};
|
|
5620
|
+
}
|
|
5621
|
+
const synthetic = JSON.stringify({
|
|
5622
|
+
sessionId: "doctor-check",
|
|
5623
|
+
cwd: process.cwd(),
|
|
5624
|
+
toolName: "view",
|
|
5625
|
+
toolArgs: { path: "doctor-check.txt" }
|
|
5626
|
+
});
|
|
5627
|
+
const res = spawnSync2(preToolUseCommand, {
|
|
5628
|
+
input: synthetic,
|
|
5629
|
+
encoding: "utf-8",
|
|
5630
|
+
shell: true,
|
|
5631
|
+
windowsHide: true,
|
|
5632
|
+
timeout: 15e3
|
|
5633
|
+
});
|
|
5634
|
+
if (res.error) {
|
|
5635
|
+
return {
|
|
5636
|
+
name: "Copilot CLI",
|
|
5637
|
+
status: "fail",
|
|
5638
|
+
message: `hook failed to launch: ${extractErrorMessage(res.error, "unknown error")}. Recovery: run "token-goat install --copilot", then fully restart Copilot CLI.`
|
|
5639
|
+
};
|
|
5640
|
+
}
|
|
5641
|
+
if (res.status !== 0) {
|
|
5642
|
+
return {
|
|
5643
|
+
name: "Copilot CLI",
|
|
5644
|
+
status: "fail",
|
|
5645
|
+
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 "token-goat install --copilot", then fully restart Copilot CLI (a live session won't pick up the fix).`
|
|
5646
|
+
};
|
|
5647
|
+
}
|
|
5648
|
+
try {
|
|
5649
|
+
JSON.parse(res.stdout ?? "");
|
|
5650
|
+
} catch {
|
|
5651
|
+
return {
|
|
5652
|
+
name: "Copilot CLI",
|
|
5653
|
+
status: "fail",
|
|
5654
|
+
message: 'hook did not return valid JSON -- Copilot treats this as a hook error and denies every tool call. Recovery: run "token-goat install --copilot", then fully restart Copilot CLI.'
|
|
5655
|
+
};
|
|
5656
|
+
}
|
|
5657
|
+
return { name: "Copilot CLI", status: "ok", message: "preToolUse hook invokes cleanly and returns valid JSON" };
|
|
5658
|
+
}
|
|
5659
|
+
function checkStrayClaudeMdBlocks(searchRoot) {
|
|
5660
|
+
const strays = findStrayClaudeMdBlocks(searchRoot);
|
|
5661
|
+
if (strays.length === 0) {
|
|
5662
|
+
return { name: "CLAUDE.md block", status: "ok", message: "no stray copies outside CLAUDE.md" };
|
|
5663
|
+
}
|
|
5664
|
+
return {
|
|
5665
|
+
name: "CLAUDE.md block",
|
|
5666
|
+
status: "warn",
|
|
5667
|
+
message: `${strays.length} stray cop${strays.length === 1 ? "y" : "ies"} outside CLAUDE.md (never refreshed by install, never removed by uninstall, will go stale): ${strays.join(", ")}`
|
|
5668
|
+
};
|
|
5669
|
+
}
|
|
5670
|
+
function checkSecurityPosture(cfg, dataDirPath) {
|
|
5671
|
+
const results = [];
|
|
5672
|
+
results.push({
|
|
5673
|
+
name: "Security network",
|
|
5674
|
+
status: "ok",
|
|
5675
|
+
message: cfg.network.offline ? "offline mode is on: no fetch, model download, OCR data, screenshot, or Drive call" : "offline mode is off (network.offline)"
|
|
5676
|
+
});
|
|
5677
|
+
results.push(
|
|
5678
|
+
cfg.injection.enabled ? { name: "Security injection", status: "ok", message: "fetched and MCP content is scanned and fenced" } : { name: "Security injection", status: "warn", message: "scanning is off (injection.enabled): fetched and MCP content reaches the model unfenced" }
|
|
5679
|
+
);
|
|
5680
|
+
results.push({
|
|
5681
|
+
name: "Security gdrive",
|
|
5682
|
+
status: "ok",
|
|
5683
|
+
message: cfg.gdrive.enabled ? "enabled (gdrive.enabled = false turns it off)" : "disabled"
|
|
5684
|
+
});
|
|
5685
|
+
const allow = cfg.webfetch.allow.length;
|
|
5686
|
+
const deny = cfg.webfetch.deny.length;
|
|
5687
|
+
results.push({
|
|
5688
|
+
name: "Security fetch policy",
|
|
5689
|
+
status: "ok",
|
|
5690
|
+
message: allow > 0 ? `${allow} allowed host pattern${allow === 1 ? "" : "s"}, ${deny} denied: nothing outside the allow list is fetched` : `no allow list, ${deny} denied pattern${deny === 1 ? "" : "s"}: any host not denied can be fetched`
|
|
5691
|
+
});
|
|
5692
|
+
const extraRoots = cfg.mcp.allowed_roots.length;
|
|
5693
|
+
results.push(
|
|
5694
|
+
cfg.mcp.confine_reads_to_project_root ? {
|
|
5695
|
+
name: "Security mcp roots",
|
|
5696
|
+
status: "ok",
|
|
5697
|
+
message: extraRoots === 0 ? "reads are confined to the project root" : `reads are confined to the project root plus ${extraRoots} configured root${extraRoots === 1 ? "" : "s"}`
|
|
5698
|
+
} : { name: "Security mcp roots", status: "warn", message: "confinement is off (mcp.confine_reads_to_project_root): a read can leave the project" }
|
|
5699
|
+
);
|
|
5700
|
+
results.push(dataDirPermissionResult(dataDirPath));
|
|
5701
|
+
return results;
|
|
5702
|
+
}
|
|
5703
|
+
function dataDirPermissionResult(dataDirPath) {
|
|
5704
|
+
if (process.platform === "win32") {
|
|
5705
|
+
return { name: "Security data dir", status: "ok", message: "inherits the parent ACL (POSIX modes do not apply on Windows)" };
|
|
5706
|
+
}
|
|
5707
|
+
try {
|
|
5708
|
+
const mode = fs11.statSync(dataDirPath).mode & 511;
|
|
5709
|
+
if ((mode & 63) !== 0) {
|
|
5710
|
+
return {
|
|
5711
|
+
name: "Security data dir",
|
|
5712
|
+
status: "warn",
|
|
5713
|
+
message: `mode ${mode.toString(8).padStart(3, "0")}: other local users can read the indexed source text`
|
|
5714
|
+
};
|
|
5715
|
+
}
|
|
5716
|
+
return { name: "Security data dir", status: "ok", message: `mode ${mode.toString(8).padStart(3, "0")}: owner only` };
|
|
5717
|
+
} catch {
|
|
5718
|
+
return { name: "Security data dir", status: "warn", message: "could not be read, so its permissions are unknown" };
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
function runDoctor(dataDir2, configPath2, rootDir, processes) {
|
|
5722
|
+
const results = [];
|
|
5723
|
+
const actualDataDir = dataDir2 || dataDir();
|
|
5724
|
+
results.push(checkInstall());
|
|
5725
|
+
results.push(checkTsCompiler());
|
|
5726
|
+
results.push(checkStrayClaudeMdBlocks());
|
|
5727
|
+
results.push(checkWorkerRunning(actualDataDir) ? { name: "Worker", status: "ok", message: "running" } : { name: "Worker", status: "warn", message: "not running" });
|
|
5728
|
+
results.push(checkDbExists(actualDataDir));
|
|
5729
|
+
results.push(checkSymbolBodySize(path10.join(actualDataDir, "global.db")));
|
|
5730
|
+
results.push(checkSymbolCount(path10.join(actualDataDir, "global.db"), rootDir));
|
|
5731
|
+
results.push(checkDirtyQueueHealth(actualDataDir));
|
|
5732
|
+
const actualConfigPath = configPath2 || configPath();
|
|
5733
|
+
results.push(checkConfigValid(actualConfigPath));
|
|
5734
|
+
for (const result of checkSecurityPosture(loadConfig(rootDir), actualDataDir)) results.push(result);
|
|
5735
|
+
results.push(checkDiskSpace(actualDataDir));
|
|
5736
|
+
const copilotResult = checkCopilotCli(copilotCliConfigPath(), copilotCliScriptPath());
|
|
5737
|
+
if (copilotResult) results.push(copilotResult);
|
|
5738
|
+
results.push(checkGlobalMcpConfig());
|
|
5739
|
+
if (process.platform === "win32") results.push(checkMcpProcessHealth(processes ?? readWindowsProcesses()));
|
|
5740
|
+
return results;
|
|
5741
|
+
}
|
|
5742
|
+
function printDoctorResults(results) {
|
|
5743
|
+
console.log("\ntoken-goat doctor\n");
|
|
5744
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5745
|
+
for (const result of results) {
|
|
5746
|
+
const key = result.name.split(" ")[0];
|
|
5747
|
+
if (!grouped.has(key)) {
|
|
5748
|
+
grouped.set(key, []);
|
|
5749
|
+
}
|
|
5750
|
+
grouped.get(key).push(result);
|
|
5751
|
+
}
|
|
5752
|
+
for (const [, items] of grouped) {
|
|
5753
|
+
for (const item of items) {
|
|
5754
|
+
const prefix = item.status === "ok" ? " " : ` [${item.status.toUpperCase()}] `;
|
|
5755
|
+
console.log(`${prefix}${item.name}: ${item.message}`);
|
|
5756
|
+
}
|
|
5757
|
+
}
|
|
5758
|
+
const hasFailures = results.some((r) => r.status === "fail");
|
|
5759
|
+
console.log(hasFailures ? "\nFAILURES DETECTED" : "\nAll checks passed");
|
|
5760
|
+
console.log();
|
|
5761
|
+
}
|
|
5762
|
+
async function runDoctorAndExit(opts) {
|
|
5763
|
+
const results = runDoctor(opts?.dataDir, opts?.configPath, opts?.rootDir, opts?.processes);
|
|
5764
|
+
printDoctorResults(results);
|
|
5765
|
+
if (opts?.context === true) {
|
|
5766
|
+
console.log("\n## Context footprint\n");
|
|
5767
|
+
await runContextStats({});
|
|
5768
|
+
console.log();
|
|
5769
|
+
try {
|
|
5770
|
+
const dir = skillOutputsDir();
|
|
5771
|
+
const pregenPath = path10.join(dir, "pregen.json");
|
|
5772
|
+
if (fs11.existsSync(pregenPath)) {
|
|
5773
|
+
const content = JSON.parse(fs11.readFileSync(pregenPath, "utf-8"));
|
|
5774
|
+
const pregenNames = new Set(content.names || []);
|
|
5775
|
+
const skillsSeen = /* @__PURE__ */ new Set();
|
|
5776
|
+
try {
|
|
5777
|
+
const entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
5778
|
+
for (const entry of entries) {
|
|
5779
|
+
if (!entry.isFile() || !entry.name.endsWith(".meta")) continue;
|
|
5780
|
+
try {
|
|
5781
|
+
const meta = JSON.parse(fs11.readFileSync(path10.join(dir, entry.name), "utf-8"));
|
|
5782
|
+
if (meta.skillName && !pregenNames.has(meta.skillName)) {
|
|
5783
|
+
skillsSeen.add(meta.skillName);
|
|
5784
|
+
}
|
|
5785
|
+
} catch {
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
} catch {
|
|
5789
|
+
}
|
|
5790
|
+
const skills = [...skillsSeen];
|
|
5791
|
+
if (skills.length > 0) {
|
|
5792
|
+
console.log(`Missing from pregen.json: ${skills.join(", ")}`);
|
|
5793
|
+
console.log(`Remediation: token-goat skill-compact --all
|
|
5794
|
+
`);
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5797
|
+
} catch {
|
|
5798
|
+
}
|
|
5799
|
+
}
|
|
5800
|
+
return results.some((r) => r.status === "fail") ? 1 : 0;
|
|
5801
|
+
}
|
|
5802
|
+
|
|
5803
|
+
// src/gdrive.ts
|
|
5804
|
+
init_define_import_meta_env();
|
|
5805
|
+
|
|
5806
|
+
// src/webfetch.ts
|
|
5807
|
+
init_define_import_meta_env();
|
|
5808
|
+
import { existsSync as existsSync8, readdirSync as readdirSync5, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
5809
|
+
import * as http from "http";
|
|
5810
|
+
import * as https from "https";
|
|
5811
|
+
import { isIPv4, isIPv6 } from "net";
|
|
5812
|
+
import { resolve as resolve4, join as join10 } from "path";
|
|
5813
|
+
import { URL as URL2 } from "url";
|
|
5814
|
+
import { promisify } from "util";
|
|
5815
|
+
import { lookup as dnsLookup } from "dns";
|
|
5816
|
+
var dnsLookupAsync = promisify(dnsLookup);
|
|
5817
|
+
var MAX_URL_IN_ERROR = 200;
|
|
5818
|
+
var ALLOW_UNRESOLVED = (process.env["TOKEN_GOAT_WEBFETCH_ALLOW_UNRESOLVED"] ?? "").toLowerCase() === "true";
|
|
5819
|
+
function webCacheDir() {
|
|
5820
|
+
return join10(dataDir(), "web_cache");
|
|
5821
|
+
}
|
|
5822
|
+
var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
5823
|
+
"localhost",
|
|
5824
|
+
"ip6-localhost",
|
|
5825
|
+
"ip6-loopback",
|
|
5826
|
+
"metadata.google.internal",
|
|
5827
|
+
"169.254.169.254"
|
|
5828
|
+
]);
|
|
5829
|
+
function truncateUrl(url, maxLen = MAX_URL_IN_ERROR) {
|
|
5830
|
+
const sanitized = url.replace(/[\r\n]/g, "");
|
|
5831
|
+
return sanitized.length > maxLen ? sanitized.slice(0, maxLen) + "\u2026" : sanitized;
|
|
5832
|
+
}
|
|
5833
|
+
async function resolveSsrfSafeAddress(hostname) {
|
|
5834
|
+
const hostnameLower = hostname.toLowerCase().replace(/\.$/, "");
|
|
5835
|
+
if (BLOCKED_HOSTNAMES.has(hostnameLower)) return { kind: "blocked" };
|
|
5836
|
+
let results;
|
|
5837
|
+
try {
|
|
5838
|
+
const r = await dnsLookupAsync(hostnameLower, { all: true });
|
|
5839
|
+
if (!Array.isArray(r) || r.length === 0) return { kind: "unresolved" };
|
|
5840
|
+
results = r;
|
|
5841
|
+
} catch {
|
|
5842
|
+
return { kind: "unresolved" };
|
|
5843
|
+
}
|
|
5844
|
+
for (const addr of results) {
|
|
5845
|
+
const ip = addr.address || "";
|
|
5846
|
+
const isPrivate = isIPv4(ip) ? isPrivateIPv4(ip) : isIPv6(ip) ? isPrivateIPv6(ip) : true;
|
|
5847
|
+
if (isPrivate) return { kind: "blocked" };
|
|
5848
|
+
}
|
|
5849
|
+
const first = results[0];
|
|
5850
|
+
if (!first) return { kind: "unresolved" };
|
|
5851
|
+
return { kind: "safe", address: first.address, family: first.family, addresses: results };
|
|
5852
|
+
}
|
|
5853
|
+
function ssrfPinnedLookup(hostname, options, callback) {
|
|
5854
|
+
resolveSsrfSafeAddress(hostname).then((result) => {
|
|
5336
5855
|
if (result.kind === "safe") {
|
|
5337
5856
|
if (options.all) {
|
|
5338
5857
|
callback(null, result.addresses);
|
|
@@ -5380,13 +5899,18 @@ function isPrivateIPv4(ip) {
|
|
|
5380
5899
|
if (octets.length !== 4 || octets.some((o) => !Number.isFinite(o))) return false;
|
|
5381
5900
|
const a = octets[0];
|
|
5382
5901
|
const b = octets[1];
|
|
5902
|
+
const c = octets[2];
|
|
5383
5903
|
return a === 0 || // 0.0.0.0/8 ("this network" / unspecified-source range)
|
|
5384
5904
|
a === 127 || // 127.x.x.x
|
|
5385
5905
|
a === 10 || // 10.x.x.x
|
|
5386
5906
|
a === 100 && b >= 64 && b <= 127 || // 100.64.0.0/10 (carrier-grade NAT, RFC 6598)
|
|
5387
5907
|
a === 172 && b >= 16 && b <= 31 || // 172.16-31.x.x
|
|
5388
5908
|
a === 192 && b === 168 || // 192.168.x.x
|
|
5389
|
-
a === 169 && b === 254
|
|
5909
|
+
a === 169 && b === 254 || // 169.254.x.x
|
|
5910
|
+
a === 192 && b === 0 && c === 0 || // 192.0.0.0/24 (IETF protocol assignments, RFC 6890)
|
|
5911
|
+
a === 198 && (b === 18 || b === 19) || // 198.18.0.0/15 (benchmarking, RFC 2544)
|
|
5912
|
+
a >= 224 && a <= 239 || // 224.0.0.0/4 multicast, including the all-hosts group
|
|
5913
|
+
a >= 240;
|
|
5390
5914
|
}
|
|
5391
5915
|
function parseIPv6Groups(ip) {
|
|
5392
5916
|
if (!isIPv6(ip)) return null;
|
|
@@ -5435,6 +5959,13 @@ function matchesIPv6Prefix(groups, prefixGroups, prefixBits) {
|
|
|
5435
5959
|
}
|
|
5436
5960
|
var FC00_PREFIX = [64512, 0, 0, 0, 0, 0, 0, 0];
|
|
5437
5961
|
var FE80_PREFIX = [65152, 0, 0, 0, 0, 0, 0, 0];
|
|
5962
|
+
var FEC0_PREFIX = [65216, 0, 0, 0, 0, 0, 0, 0];
|
|
5963
|
+
var FF00_PREFIX = [65280, 0, 0, 0, 0, 0, 0, 0];
|
|
5964
|
+
var SIXTOFOUR_PREFIX = [8194, 0, 0, 0, 0, 0, 0, 0];
|
|
5965
|
+
var NAT64_PREFIX = [100, 65435, 0, 0, 0, 0, 0, 0];
|
|
5966
|
+
function embeddedIPv4(hi, lo) {
|
|
5967
|
+
return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
|
|
5968
|
+
}
|
|
5438
5969
|
function isPrivateIPv6(ip) {
|
|
5439
5970
|
const lower = ip.toLowerCase();
|
|
5440
5971
|
if (lower === "::1") return true;
|
|
@@ -5444,27 +5975,32 @@ function isPrivateIPv6(ip) {
|
|
|
5444
5975
|
const isIPv4Translated = groups[0] === 0 && groups[1] === 0 && groups[2] === 0 && groups[3] === 0 && groups[4] === 65535 && groups[5] === 0;
|
|
5445
5976
|
const isIPv4Compatible = groups[0] === 0 && groups[1] === 0 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 0;
|
|
5446
5977
|
if (isIPv4Mapped || isIPv4Translated || isIPv4Compatible) {
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
return isPrivateIPv4(
|
|
5978
|
+
return isPrivateIPv4(embeddedIPv4(groups[6] ?? 0, groups[7] ?? 0));
|
|
5979
|
+
}
|
|
5980
|
+
if (matchesIPv6Prefix(groups, SIXTOFOUR_PREFIX, 16)) {
|
|
5981
|
+
return isPrivateIPv4(embeddedIPv4(groups[1] ?? 0, groups[2] ?? 0));
|
|
5982
|
+
}
|
|
5983
|
+
if (matchesIPv6Prefix(groups, NAT64_PREFIX, 96)) {
|
|
5984
|
+
return isPrivateIPv4(embeddedIPv4(groups[6] ?? 0, groups[7] ?? 0));
|
|
5451
5985
|
}
|
|
5452
5986
|
if (matchesIPv6Prefix(groups, FC00_PREFIX, 7)) return true;
|
|
5453
5987
|
if (matchesIPv6Prefix(groups, FE80_PREFIX, 10)) return true;
|
|
5988
|
+
if (matchesIPv6Prefix(groups, FEC0_PREFIX, 10)) return true;
|
|
5989
|
+
if (matchesIPv6Prefix(groups, FF00_PREFIX, 8)) return true;
|
|
5454
5990
|
return false;
|
|
5455
5991
|
}
|
|
5456
5992
|
var STALE_DOWNLOAD_AGE_MS = 10 * 60 * 1e3;
|
|
5457
5993
|
function cleanupStaleDownloads() {
|
|
5458
5994
|
const cacheDir = webCacheDir();
|
|
5459
|
-
if (!
|
|
5995
|
+
if (!existsSync8(cacheDir)) return 0;
|
|
5460
5996
|
let removed = 0;
|
|
5461
5997
|
try {
|
|
5462
|
-
const files =
|
|
5998
|
+
const files = readdirSync5(cacheDir);
|
|
5463
5999
|
for (const file of files) {
|
|
5464
6000
|
if (file.endsWith(".tmp")) {
|
|
5465
|
-
const filePath =
|
|
6001
|
+
const filePath = resolve4(cacheDir, file);
|
|
5466
6002
|
try {
|
|
5467
|
-
const stat =
|
|
6003
|
+
const stat = statSync4(filePath);
|
|
5468
6004
|
if (Date.now() - stat.mtimeMs < STALE_DOWNLOAD_AGE_MS) continue;
|
|
5469
6005
|
unlinkSync2(filePath);
|
|
5470
6006
|
removed++;
|
|
@@ -5489,6 +6025,15 @@ function performHttpFetch(targetUrl, opts) {
|
|
|
5489
6025
|
rejectPromise(new Error(`URL blocked by SSRF safety check: ${truncateUrl(targetUrl)}`));
|
|
5490
6026
|
return;
|
|
5491
6027
|
}
|
|
6028
|
+
if (loadConfig().network.offline) {
|
|
6029
|
+
rejectPromise(new Error(`Offline mode is on (network.offline): refusing to fetch ${truncateUrl(targetUrl)}`));
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
6032
|
+
const policyDenial = urlPolicyDenialReason(targetUrl, loadConfig().webfetch);
|
|
6033
|
+
if (policyDenial !== null) {
|
|
6034
|
+
rejectPromise(new Error(`${policyDenial}: ${truncateUrl(targetUrl)}`));
|
|
6035
|
+
return;
|
|
6036
|
+
}
|
|
5492
6037
|
const literalIp = parsed.hostname.startsWith("[") && parsed.hostname.endsWith("]") ? parsed.hostname.slice(1, -1) : parsed.hostname;
|
|
5493
6038
|
const isLiteralPrivate = isIPv4(literalIp) ? isPrivateIPv4(literalIp) : isIPv6(literalIp) ? isPrivateIPv6(literalIp) : false;
|
|
5494
6039
|
if (isLiteralPrivate) {
|
|
@@ -5537,7 +6082,7 @@ function performHttpFetch(targetUrl, opts) {
|
|
|
5537
6082
|
rejectPromise(new Error(`Invalid redirect location fetching ${truncateUrl(targetUrl)}`));
|
|
5538
6083
|
return;
|
|
5539
6084
|
}
|
|
5540
|
-
const sameOrigin = nextParsed.
|
|
6085
|
+
const sameOrigin = nextParsed.origin === parsed.origin;
|
|
5541
6086
|
const nextOpts = {
|
|
5542
6087
|
...opts,
|
|
5543
6088
|
redirectsLeft: opts.redirectsLeft - 1,
|
|
@@ -5656,11 +6201,11 @@ function parseDocSections(text) {
|
|
|
5656
6201
|
const newlineLen = newlineMatch ? newlineMatch[0].length : 0;
|
|
5657
6202
|
const fenceMatch = /^\s*(`{3,}|~{3,})/.exec(line);
|
|
5658
6203
|
if (fenceMatch !== null && fenceMatch[1] !== void 0) {
|
|
5659
|
-
const
|
|
5660
|
-
const ch =
|
|
6204
|
+
const run2 = fenceMatch[1];
|
|
6205
|
+
const ch = run2[0] ?? "";
|
|
5661
6206
|
if (fence === null) {
|
|
5662
|
-
fence = { ch, len:
|
|
5663
|
-
} else if (ch === fence.ch &&
|
|
6207
|
+
fence = { ch, len: run2.length };
|
|
6208
|
+
} else if (ch === fence.ch && run2.length >= fence.len && /^[ \t]*$/.test(line.slice(fenceMatch[0].length))) {
|
|
5664
6209
|
fence = null;
|
|
5665
6210
|
}
|
|
5666
6211
|
if (currentSection !== null) {
|
|
@@ -5719,8 +6264,8 @@ async function getSectionContent(fileId, heading, opts = {}) {
|
|
|
5719
6264
|
|
|
5720
6265
|
// src/pack.ts
|
|
5721
6266
|
init_define_import_meta_env();
|
|
5722
|
-
import * as
|
|
5723
|
-
import * as
|
|
6267
|
+
import * as fs12 from "node:fs";
|
|
6268
|
+
import * as path12 from "node:path";
|
|
5724
6269
|
|
|
5725
6270
|
// node_modules/minimatch/dist/esm/index.js
|
|
5726
6271
|
var esm_exports = {};
|
|
@@ -6803,11 +7348,11 @@ var qmarksTestNoExtDot = ([$0]) => {
|
|
|
6803
7348
|
return (f) => f.length === len && f !== "." && f !== "..";
|
|
6804
7349
|
};
|
|
6805
7350
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
6806
|
-
var
|
|
7351
|
+
var path11 = {
|
|
6807
7352
|
win32: { sep: "\\" },
|
|
6808
7353
|
posix: { sep: "/" }
|
|
6809
7354
|
};
|
|
6810
|
-
var sep2 = defaultPlatform === "win32" ?
|
|
7355
|
+
var sep2 = defaultPlatform === "win32" ? path11.win32.sep : path11.posix.sep;
|
|
6811
7356
|
minimatch.sep = sep2;
|
|
6812
7357
|
var GLOBSTAR = Symbol("globstar **");
|
|
6813
7358
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
@@ -7592,7 +8137,7 @@ var LANG_MAP = {
|
|
|
7592
8137
|
".exs": "elixir"
|
|
7593
8138
|
};
|
|
7594
8139
|
function getLang(filePath) {
|
|
7595
|
-
const ext2 =
|
|
8140
|
+
const ext2 = path12.extname(filePath).toLowerCase();
|
|
7596
8141
|
return LANG_MAP[ext2] ?? "";
|
|
7597
8142
|
}
|
|
7598
8143
|
function matches(rel, patterns) {
|
|
@@ -7602,30 +8147,30 @@ function matches(rel, patterns) {
|
|
|
7602
8147
|
return patterns.some((pat) => mm.minimatch(norm, pat) || mm.minimatch(base, pat));
|
|
7603
8148
|
}
|
|
7604
8149
|
function isPathWithinRoot(rootReal, resolvedPath) {
|
|
7605
|
-
const rel =
|
|
7606
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(".." +
|
|
8150
|
+
const rel = path12.relative(rootReal, resolvedPath);
|
|
8151
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(".." + path12.sep) && !path12.isAbsolute(rel);
|
|
7607
8152
|
}
|
|
7608
8153
|
function openWithinRoot(rootReal, p) {
|
|
7609
8154
|
let fd;
|
|
7610
8155
|
try {
|
|
7611
|
-
fd =
|
|
8156
|
+
fd = fs12.openSync(p, "r");
|
|
7612
8157
|
} catch {
|
|
7613
8158
|
return null;
|
|
7614
8159
|
}
|
|
7615
8160
|
let ownershipTransferred = false;
|
|
7616
8161
|
try {
|
|
7617
|
-
const stat =
|
|
8162
|
+
const stat = fs12.fstatSync(fd);
|
|
7618
8163
|
if (!stat.isFile()) return null;
|
|
7619
8164
|
let realPath;
|
|
7620
8165
|
try {
|
|
7621
|
-
realPath =
|
|
8166
|
+
realPath = fs12.realpathSync(p);
|
|
7622
8167
|
} catch {
|
|
7623
8168
|
return "outside-root";
|
|
7624
8169
|
}
|
|
7625
8170
|
if (!isPathWithinRoot(rootReal, realPath)) return "outside-root";
|
|
7626
8171
|
let realStat;
|
|
7627
8172
|
try {
|
|
7628
|
-
realStat =
|
|
8173
|
+
realStat = fs12.statSync(realPath);
|
|
7629
8174
|
} catch {
|
|
7630
8175
|
return "outside-root";
|
|
7631
8176
|
}
|
|
@@ -7635,7 +8180,7 @@ function openWithinRoot(rootReal, p) {
|
|
|
7635
8180
|
} finally {
|
|
7636
8181
|
if (!ownershipTransferred) {
|
|
7637
8182
|
try {
|
|
7638
|
-
|
|
8183
|
+
fs12.closeSync(fd);
|
|
7639
8184
|
} catch {
|
|
7640
8185
|
}
|
|
7641
8186
|
}
|
|
@@ -7643,11 +8188,11 @@ function openWithinRoot(rootReal, p) {
|
|
|
7643
8188
|
}
|
|
7644
8189
|
function* resolveOpenCandidates(projectRoot, patterns, rootReal, ignorePatterns, seen, skipped) {
|
|
7645
8190
|
for (const pattern of patterns) {
|
|
7646
|
-
const p =
|
|
8191
|
+
const p = path12.isAbsolute(pattern) ? pattern : path12.join(projectRoot, pattern);
|
|
7647
8192
|
if (seen.has(p)) continue;
|
|
7648
8193
|
let rel;
|
|
7649
8194
|
try {
|
|
7650
|
-
rel =
|
|
8195
|
+
rel = path12.relative(projectRoot, p).replace(/\\/g, "/");
|
|
7651
8196
|
} catch {
|
|
7652
8197
|
skipped.push(`${p} (outside project root)`);
|
|
7653
8198
|
continue;
|
|
@@ -7659,7 +8204,7 @@ function* resolveOpenCandidates(projectRoot, patterns, rootReal, ignorePatterns,
|
|
|
7659
8204
|
continue;
|
|
7660
8205
|
}
|
|
7661
8206
|
if (ignorePatterns && matches(rel, ignorePatterns)) {
|
|
7662
|
-
|
|
8207
|
+
fs12.closeSync(opened.fd);
|
|
7663
8208
|
continue;
|
|
7664
8209
|
}
|
|
7665
8210
|
yield { p, rel, fd: opened.fd, stat: opened.stat };
|
|
@@ -7721,7 +8266,7 @@ function stripBlockComments(content, pattern, lineStates) {
|
|
|
7721
8266
|
);
|
|
7722
8267
|
}
|
|
7723
8268
|
function stripComments(content, filePath) {
|
|
7724
|
-
const ext2 =
|
|
8269
|
+
const ext2 = path12.extname(filePath).toLowerCase();
|
|
7725
8270
|
const lineStates = computeLineStartQuoteStates(content);
|
|
7726
8271
|
if (ext2 === ".py") {
|
|
7727
8272
|
return stripLineComments(content, PY_LINE_COMMENT_RE, lineStates);
|
|
@@ -7759,7 +8304,7 @@ var SAFE_EXTS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp
|
|
|
7759
8304
|
function scanSecrets(files) {
|
|
7760
8305
|
const hits = [];
|
|
7761
8306
|
for (const pf of files) {
|
|
7762
|
-
if (SAFE_EXTS.has(
|
|
8307
|
+
if (SAFE_EXTS.has(path12.extname(pf.path).toLowerCase())) {
|
|
7763
8308
|
continue;
|
|
7764
8309
|
}
|
|
7765
8310
|
for (const [lineno, line] of pf.content.split("\n").entries()) {
|
|
@@ -7782,10 +8327,10 @@ function scanSecrets(files) {
|
|
|
7782
8327
|
function collectFiles(projectRoot, patterns, opts = {}) {
|
|
7783
8328
|
const result = { files: [], skipped: [], total_lines: 0, total_tokens: 0 };
|
|
7784
8329
|
const seen = /* @__PURE__ */ new Set();
|
|
7785
|
-
const rootResolved =
|
|
8330
|
+
const rootResolved = path12.resolve(projectRoot);
|
|
7786
8331
|
let rootReal;
|
|
7787
8332
|
try {
|
|
7788
|
-
rootReal =
|
|
8333
|
+
rootReal = fs12.realpathSync(rootResolved);
|
|
7789
8334
|
} catch {
|
|
7790
8335
|
rootReal = rootResolved;
|
|
7791
8336
|
}
|
|
@@ -7799,7 +8344,7 @@ function collectFiles(projectRoot, patterns, opts = {}) {
|
|
|
7799
8344
|
}
|
|
7800
8345
|
let content;
|
|
7801
8346
|
try {
|
|
7802
|
-
content =
|
|
8347
|
+
content = fs12.readFileSync(fd, "utf8");
|
|
7803
8348
|
} catch {
|
|
7804
8349
|
result.skipped.push(`${rel} (unreadable)`);
|
|
7805
8350
|
continue;
|
|
@@ -7821,13 +8366,13 @@ function collectFiles(projectRoot, patterns, opts = {}) {
|
|
|
7821
8366
|
result.total_lines += lines;
|
|
7822
8367
|
result.total_tokens += tokens;
|
|
7823
8368
|
} finally {
|
|
7824
|
-
|
|
8369
|
+
fs12.closeSync(fd);
|
|
7825
8370
|
}
|
|
7826
8371
|
}
|
|
7827
8372
|
return result;
|
|
7828
8373
|
}
|
|
7829
8374
|
function collectFromStdin(projectRoot, opts = {}) {
|
|
7830
|
-
const input =
|
|
8375
|
+
const input = fs12.readFileSync(0, "utf8");
|
|
7831
8376
|
const paths = input.split("\n").map((ln) => ln.trim()).filter((ln) => ln.length > 0);
|
|
7832
8377
|
return collectFiles(projectRoot, paths, opts);
|
|
7833
8378
|
}
|
|
@@ -7957,10 +8502,10 @@ function formatPack(result, style, opts = {}) {
|
|
|
7957
8502
|
function estimateBudget(projectRoot, patterns, opts = {}) {
|
|
7958
8503
|
const result = { entries: [], skipped: [], total_lines: 0, total_tokens: 0 };
|
|
7959
8504
|
const seen = /* @__PURE__ */ new Set();
|
|
7960
|
-
const rootResolved =
|
|
8505
|
+
const rootResolved = path12.resolve(projectRoot);
|
|
7961
8506
|
let rootReal;
|
|
7962
8507
|
try {
|
|
7963
|
-
rootReal =
|
|
8508
|
+
rootReal = fs12.realpathSync(rootResolved);
|
|
7964
8509
|
} catch {
|
|
7965
8510
|
rootReal = rootResolved;
|
|
7966
8511
|
}
|
|
@@ -7975,7 +8520,7 @@ function estimateBudget(projectRoot, patterns, opts = {}) {
|
|
|
7975
8520
|
let lines;
|
|
7976
8521
|
let tokens;
|
|
7977
8522
|
try {
|
|
7978
|
-
const data =
|
|
8523
|
+
const data = fs12.readFileSync(fd);
|
|
7979
8524
|
const sampleSize = Math.min(1e3, data.length);
|
|
7980
8525
|
const sampleLines = (data.toString("utf8", 0, sampleSize).match(/\n/g) || []).length;
|
|
7981
8526
|
lines = data.length > sampleSize ? Math.ceil(sampleLines * (data.length / sampleSize)) : sampleLines + 1;
|
|
@@ -7993,7 +8538,7 @@ function estimateBudget(projectRoot, patterns, opts = {}) {
|
|
|
7993
8538
|
result.total_lines += lines;
|
|
7994
8539
|
result.total_tokens += tokens;
|
|
7995
8540
|
} finally {
|
|
7996
|
-
|
|
8541
|
+
fs12.closeSync(fd);
|
|
7997
8542
|
}
|
|
7998
8543
|
}
|
|
7999
8544
|
result.entries.sort((a, b) => b.tokens - a.tokens);
|
|
@@ -8269,193 +8814,1407 @@ function extractCargo(lines) {
|
|
|
8269
8814
|
const body = detail && detail.length > 0 ? detail.join("\n").trim() : summaryByName.get(name);
|
|
8270
8815
|
result.blocks.push({ name, body });
|
|
8271
8816
|
}
|
|
8272
|
-
return result;
|
|
8817
|
+
return result;
|
|
8818
|
+
}
|
|
8819
|
+
function extractGeneric(lines) {
|
|
8820
|
+
const result = {
|
|
8821
|
+
runner: "unknown",
|
|
8822
|
+
blocks: [],
|
|
8823
|
+
summaryLines: [],
|
|
8824
|
+
statsLine: ""
|
|
8825
|
+
};
|
|
8826
|
+
for (const line of lines) {
|
|
8827
|
+
const s = line.trimEnd();
|
|
8828
|
+
if (/\b(FAILED|FAILURE|ERROR)\b/i.test(s)) {
|
|
8829
|
+
result.summaryLines.push(s);
|
|
8830
|
+
}
|
|
8831
|
+
}
|
|
8832
|
+
return result;
|
|
8833
|
+
}
|
|
8834
|
+
function extractFailures(text, options) {
|
|
8835
|
+
const cleaned = stripAnsi(text);
|
|
8836
|
+
const lines = cleaned.split("\n");
|
|
8837
|
+
const detected = options?.runner ?? detectRunner(cleaned);
|
|
8838
|
+
if (detected === "pytest") {
|
|
8839
|
+
return extractPytest(lines);
|
|
8840
|
+
}
|
|
8841
|
+
if (detected === "jest") {
|
|
8842
|
+
return extractJest(lines);
|
|
8843
|
+
}
|
|
8844
|
+
if (detected === "go") {
|
|
8845
|
+
return extractGo(lines);
|
|
8846
|
+
}
|
|
8847
|
+
if (detected === "cargo") {
|
|
8848
|
+
return extractCargo(lines);
|
|
8849
|
+
}
|
|
8850
|
+
return extractGeneric(lines);
|
|
8851
|
+
}
|
|
8852
|
+
function formatFailuresText(result) {
|
|
8853
|
+
if (result.blocks.length === 0 && result.summaryLines.length === 0) {
|
|
8854
|
+
return "No failures found.";
|
|
8855
|
+
}
|
|
8856
|
+
const parts = [];
|
|
8857
|
+
const sep5 = "\u2500".repeat(60);
|
|
8858
|
+
for (const block of result.blocks) {
|
|
8859
|
+
parts.push(sep5, `FAIL ${block.name}`, sep5, block.body, "");
|
|
8860
|
+
}
|
|
8861
|
+
if (result.summaryLines.length > 0) {
|
|
8862
|
+
if (parts.length > 0) {
|
|
8863
|
+
parts.push(sep5);
|
|
8864
|
+
}
|
|
8865
|
+
parts.push(...result.summaryLines);
|
|
8866
|
+
}
|
|
8867
|
+
if (result.statsLine) {
|
|
8868
|
+
parts.push(result.statsLine);
|
|
8869
|
+
}
|
|
8870
|
+
const n = getFailureCount(result);
|
|
8871
|
+
parts.push(`
|
|
8872
|
+
${n} failure(s) [${result.runner}]`);
|
|
8873
|
+
return parts.join("\n");
|
|
8874
|
+
}
|
|
8875
|
+
function formatFailuresJson(result) {
|
|
8876
|
+
return JSON.stringify(
|
|
8877
|
+
{
|
|
8878
|
+
runner: result.runner,
|
|
8879
|
+
count: getFailureCount(result),
|
|
8880
|
+
failures: result.blocks.map((b) => ({ name: b.name, body: b.body })),
|
|
8881
|
+
summary: result.summaryLines,
|
|
8882
|
+
stats: result.statsLine
|
|
8883
|
+
},
|
|
8884
|
+
null,
|
|
8885
|
+
2
|
|
8886
|
+
);
|
|
8887
|
+
}
|
|
8888
|
+
function failureSignatures(result) {
|
|
8889
|
+
const raw = result.blocks.length > 0 ? result.blocks.map((b) => b.name.trim()) : result.summaryLines.map((s) => s.trim()).filter((s) => s !== "");
|
|
8890
|
+
return Array.from(new Set(raw));
|
|
8891
|
+
}
|
|
8892
|
+
function computeFailureDelta(prevSignatures, currSignatures) {
|
|
8893
|
+
if (prevSignatures === null) {
|
|
8894
|
+
return { hasBaseline: false, newlyFailing: [...currSignatures], newlyFixed: [], stillFailing: [] };
|
|
8895
|
+
}
|
|
8896
|
+
const prevSet = new Set(prevSignatures);
|
|
8897
|
+
const currSet = new Set(currSignatures);
|
|
8898
|
+
return {
|
|
8899
|
+
hasBaseline: true,
|
|
8900
|
+
newlyFailing: currSignatures.filter((s) => !prevSet.has(s)),
|
|
8901
|
+
newlyFixed: prevSignatures.filter((s) => !currSet.has(s)),
|
|
8902
|
+
stillFailing: currSignatures.filter((s) => prevSet.has(s))
|
|
8903
|
+
};
|
|
8904
|
+
}
|
|
8905
|
+
function formatFailureDeltaText(delta, runner) {
|
|
8906
|
+
if (!delta.hasBaseline) {
|
|
8907
|
+
const lines2 = [
|
|
8908
|
+
`No baseline yet for this project/key -- showing all ${delta.newlyFailing.length} current failure(s) as new. [${runner}]`
|
|
8909
|
+
];
|
|
8910
|
+
if (delta.newlyFailing.length === 0) {
|
|
8911
|
+
lines2.push("(no failures)");
|
|
8912
|
+
} else {
|
|
8913
|
+
for (const name of delta.newlyFailing) lines2.push(`+ ${name}`);
|
|
8914
|
+
}
|
|
8915
|
+
return lines2.join("\n");
|
|
8916
|
+
}
|
|
8917
|
+
const lines = [];
|
|
8918
|
+
lines.push(`Newly failing (${delta.newlyFailing.length}):`);
|
|
8919
|
+
if (delta.newlyFailing.length === 0) {
|
|
8920
|
+
lines.push(" (none)");
|
|
8921
|
+
} else {
|
|
8922
|
+
for (const name of delta.newlyFailing) lines.push(` + ${name}`);
|
|
8923
|
+
}
|
|
8924
|
+
lines.push("");
|
|
8925
|
+
lines.push(`Newly fixed (${delta.newlyFixed.length}):`);
|
|
8926
|
+
if (delta.newlyFixed.length === 0) {
|
|
8927
|
+
lines.push(" (none)");
|
|
8928
|
+
} else {
|
|
8929
|
+
for (const name of delta.newlyFixed) lines.push(` - ${name}`);
|
|
8930
|
+
}
|
|
8931
|
+
lines.push("");
|
|
8932
|
+
lines.push(`Still failing (unchanged): ${delta.stillFailing.length}`);
|
|
8933
|
+
lines.push(
|
|
8934
|
+
`
|
|
8935
|
+
[${runner}] ${delta.newlyFailing.length} newly failing, ${delta.newlyFixed.length} newly fixed, ${delta.stillFailing.length} still failing`
|
|
8936
|
+
);
|
|
8937
|
+
return lines.join("\n");
|
|
8938
|
+
}
|
|
8939
|
+
function formatFailureDeltaJson(delta, runner) {
|
|
8940
|
+
return JSON.stringify(
|
|
8941
|
+
{
|
|
8942
|
+
runner,
|
|
8943
|
+
hasBaseline: delta.hasBaseline,
|
|
8944
|
+
newlyFailing: delta.newlyFailing,
|
|
8945
|
+
newlyFixed: delta.newlyFixed,
|
|
8946
|
+
stillFailingCount: delta.stillFailing.length
|
|
8947
|
+
},
|
|
8948
|
+
null,
|
|
8949
|
+
2
|
|
8950
|
+
);
|
|
8951
|
+
}
|
|
8952
|
+
|
|
8953
|
+
// src/failures_state.ts
|
|
8954
|
+
init_define_import_meta_env();
|
|
8955
|
+
import * as fs13 from "node:fs";
|
|
8956
|
+
import * as path13 from "node:path";
|
|
8957
|
+
var KEY_RE = /^[A-Za-z0-9_-]{1,80}$/;
|
|
8958
|
+
var DEFAULT_FAILURES_STATE_KEY = "default";
|
|
8959
|
+
function validateKey(key) {
|
|
8960
|
+
if (!KEY_RE.test(key)) {
|
|
8961
|
+
throw new Error(
|
|
8962
|
+
`Invalid --key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
|
|
8963
|
+
);
|
|
8964
|
+
}
|
|
8965
|
+
}
|
|
8966
|
+
function failuresStatePath(projectHash, key) {
|
|
8967
|
+
validateKey(key);
|
|
8968
|
+
return path13.join(dataDir(), "projects", `${projectHash}_failures_${key}.json`);
|
|
8969
|
+
}
|
|
8970
|
+
function loadFailureSnapshot(projectHash, key) {
|
|
8971
|
+
const p = failuresStatePath(projectHash, key);
|
|
8972
|
+
try {
|
|
8973
|
+
if (!fs13.existsSync(p)) return null;
|
|
8974
|
+
const parsed = JSON.parse(fs13.readFileSync(p, "utf-8"));
|
|
8975
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
8976
|
+
const obj = parsed;
|
|
8977
|
+
if (!Array.isArray(obj.signatures)) return null;
|
|
8978
|
+
return {
|
|
8979
|
+
signatures: obj.signatures.filter((s) => typeof s === "string"),
|
|
8980
|
+
runner: typeof obj.runner === "string" ? obj.runner : "unknown",
|
|
8981
|
+
storedAt: typeof obj.storedAt === "number" ? obj.storedAt : 0
|
|
8982
|
+
};
|
|
8983
|
+
} catch {
|
|
8984
|
+
return null;
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
function saveFailureSnapshot(projectHash, key, snapshot) {
|
|
8988
|
+
const p = failuresStatePath(projectHash, key);
|
|
8989
|
+
const dir = path13.dirname(p);
|
|
8990
|
+
ensureDirSync(dir);
|
|
8991
|
+
const content = JSON.stringify(snapshot);
|
|
8992
|
+
const doSave = () => {
|
|
8993
|
+
atomicWriteText(p, content);
|
|
8994
|
+
return true;
|
|
8995
|
+
};
|
|
8996
|
+
if (withFileLock(`${p}.lock`, doSave) === void 0) doSave();
|
|
8997
|
+
}
|
|
8998
|
+
|
|
8999
|
+
// src/text_commands.ts
|
|
9000
|
+
init_define_import_meta_env();
|
|
9001
|
+
import * as fs15 from "fs";
|
|
9002
|
+
import * as path15 from "path";
|
|
9003
|
+
|
|
9004
|
+
// src/project_memory.ts
|
|
9005
|
+
init_define_import_meta_env();
|
|
9006
|
+
import * as fs14 from "node:fs";
|
|
9007
|
+
import * as path14 from "node:path";
|
|
9008
|
+
var MAX_ENTRIES = 30;
|
|
9009
|
+
var KEY_RE2 = /^[A-Za-z0-9_-]{1,80}$/;
|
|
9010
|
+
function ordinal(a, b) {
|
|
9011
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
9012
|
+
}
|
|
9013
|
+
function memoryPath(projectHash) {
|
|
9014
|
+
return path14.join(dataDir(), "projects", `${projectHash}_memory.toml`);
|
|
9015
|
+
}
|
|
9016
|
+
function validateKey2(key) {
|
|
9017
|
+
if (!KEY_RE2.test(key)) {
|
|
9018
|
+
throw new Error(
|
|
9019
|
+
`Invalid memory key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
|
|
9020
|
+
);
|
|
9021
|
+
}
|
|
9022
|
+
}
|
|
9023
|
+
function parseTOML(content) {
|
|
9024
|
+
const result = {};
|
|
9025
|
+
for (const line of content.split("\n")) {
|
|
9026
|
+
const trimmed = line.trim();
|
|
9027
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
9028
|
+
continue;
|
|
9029
|
+
}
|
|
9030
|
+
const match2 = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*"(.*)"\s*$/);
|
|
9031
|
+
if (match2) {
|
|
9032
|
+
const [, key, value] = match2;
|
|
9033
|
+
if (key && value !== void 0) {
|
|
9034
|
+
const unescaped = value.replace(/\\([\\nrt"])/g, (_, c) => {
|
|
9035
|
+
switch (c) {
|
|
9036
|
+
case "\\":
|
|
9037
|
+
return "\\";
|
|
9038
|
+
case "n":
|
|
9039
|
+
return "\n";
|
|
9040
|
+
case "r":
|
|
9041
|
+
return "\r";
|
|
9042
|
+
case '"':
|
|
9043
|
+
return '"';
|
|
9044
|
+
default:
|
|
9045
|
+
return _;
|
|
9046
|
+
}
|
|
9047
|
+
});
|
|
9048
|
+
result[key] = unescaped;
|
|
9049
|
+
}
|
|
9050
|
+
}
|
|
9051
|
+
}
|
|
9052
|
+
return result;
|
|
9053
|
+
}
|
|
9054
|
+
function loadRaw(filePath) {
|
|
9055
|
+
try {
|
|
9056
|
+
if (!fs14.existsSync(filePath)) {
|
|
9057
|
+
return {};
|
|
9058
|
+
}
|
|
9059
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
9060
|
+
return parseTOML(content);
|
|
9061
|
+
} catch {
|
|
9062
|
+
return {};
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
function save(filePath, entries) {
|
|
9066
|
+
const lines = [];
|
|
9067
|
+
const sorted = Object.entries(entries).sort(([a], [b]) => ordinal(a, b));
|
|
9068
|
+
for (const [k, v] of sorted) {
|
|
9069
|
+
const escaped = v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
9070
|
+
lines.push(`${k} = "${escaped}"`);
|
|
9071
|
+
}
|
|
9072
|
+
const content = lines.length > 0 ? lines.join("\n") + "\n" : "";
|
|
9073
|
+
const dir = path14.dirname(filePath);
|
|
9074
|
+
ensureDirSync(dir);
|
|
9075
|
+
atomicWriteText(filePath, content);
|
|
9076
|
+
}
|
|
9077
|
+
function loadEntries(projectHash) {
|
|
9078
|
+
return loadRaw(memoryPath(projectHash));
|
|
9079
|
+
}
|
|
9080
|
+
function setEntry(projectHash, key, value) {
|
|
9081
|
+
validateKey2(key);
|
|
9082
|
+
const p = memoryPath(projectHash);
|
|
9083
|
+
const dir = path14.dirname(p);
|
|
9084
|
+
ensureDirSync(dir);
|
|
9085
|
+
const doSet = () => {
|
|
9086
|
+
const entries = loadRaw(p);
|
|
9087
|
+
const isNewKey = !(key in entries);
|
|
9088
|
+
if (isNewKey && Object.keys(entries).length >= MAX_ENTRIES) {
|
|
9089
|
+
const keysToKeep = MAX_ENTRIES - 1;
|
|
9090
|
+
const allKeys = Object.keys(entries).sort((a, b) => ordinal(a, b));
|
|
9091
|
+
for (const k of allKeys.slice(keysToKeep)) {
|
|
9092
|
+
delete entries[k];
|
|
9093
|
+
}
|
|
9094
|
+
}
|
|
9095
|
+
entries[key] = value;
|
|
9096
|
+
save(p, entries);
|
|
9097
|
+
return true;
|
|
9098
|
+
};
|
|
9099
|
+
if (withFileLock(`${p}.lock`, doSet) === void 0) doSet();
|
|
9100
|
+
}
|
|
9101
|
+
function unsetEntry(projectHash, key) {
|
|
9102
|
+
validateKey2(key);
|
|
9103
|
+
const p = memoryPath(projectHash);
|
|
9104
|
+
const doUnset = () => {
|
|
9105
|
+
const entries = loadRaw(p);
|
|
9106
|
+
if (key in entries) {
|
|
9107
|
+
delete entries[key];
|
|
9108
|
+
save(p, entries);
|
|
9109
|
+
}
|
|
9110
|
+
return true;
|
|
9111
|
+
};
|
|
9112
|
+
if (withFileLock(`${p}.lock`, doUnset) === void 0) doUnset();
|
|
9113
|
+
}
|
|
9114
|
+
function clearAll(projectHash) {
|
|
9115
|
+
const p = memoryPath(projectHash);
|
|
9116
|
+
const doClear = () => {
|
|
9117
|
+
if (fs14.existsSync(p)) {
|
|
9118
|
+
save(p, {});
|
|
9119
|
+
}
|
|
9120
|
+
return true;
|
|
9121
|
+
};
|
|
9122
|
+
if (withFileLock(`${p}.lock`, doClear) === void 0) doClear();
|
|
9123
|
+
}
|
|
9124
|
+
|
|
9125
|
+
// src/text_commands.ts
|
|
9126
|
+
function readInput(src) {
|
|
9127
|
+
if (src !== void 0) return fs15.readFileSync(src, "utf8");
|
|
9128
|
+
return fs15.readFileSync(0, "utf8");
|
|
9129
|
+
}
|
|
9130
|
+
function splitLines(text) {
|
|
9131
|
+
return text.split(/\r?\n/);
|
|
9132
|
+
}
|
|
9133
|
+
var DEFAULT_KINDS = ["TODO", "FIXME", "HACK", "XXX", "NOTE"];
|
|
9134
|
+
function countUnescapedQuotes(text, quoteChar) {
|
|
9135
|
+
let count = 0;
|
|
9136
|
+
let backslashes = 0;
|
|
9137
|
+
for (const ch of text) {
|
|
9138
|
+
if (ch === "\\") {
|
|
9139
|
+
backslashes++;
|
|
9140
|
+
continue;
|
|
9141
|
+
}
|
|
9142
|
+
if (ch === quoteChar && backslashes % 2 === 0) count++;
|
|
9143
|
+
backslashes = 0;
|
|
9144
|
+
}
|
|
9145
|
+
return count;
|
|
9146
|
+
}
|
|
9147
|
+
function isInsideStringLiteral2(line, markerIndex) {
|
|
9148
|
+
const before = line.slice(0, markerIndex);
|
|
9149
|
+
const dqCount = countUnescapedQuotes(before, '"');
|
|
9150
|
+
return dqCount % 2 !== 0;
|
|
9151
|
+
}
|
|
9152
|
+
function isMarkerOccurrence(matched, hasColon) {
|
|
9153
|
+
return hasColon || matched === matched.toUpperCase();
|
|
9154
|
+
}
|
|
9155
|
+
function scanFileForTodos(filePath, kindSet) {
|
|
9156
|
+
let text;
|
|
9157
|
+
try {
|
|
9158
|
+
text = fs15.readFileSync(filePath, "utf8");
|
|
9159
|
+
} catch {
|
|
9160
|
+
return [];
|
|
9161
|
+
}
|
|
9162
|
+
const kindPattern = [...kindSet].map(escapeRegExp).join("|");
|
|
9163
|
+
const re = new RegExp(`\\b(${kindPattern})\\b(\\s*:)?\\s*(.*)`, "i");
|
|
9164
|
+
const items = [];
|
|
9165
|
+
const lines = splitLines(text);
|
|
9166
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9167
|
+
const line = lines[i] ?? "";
|
|
9168
|
+
const m = re.exec(line);
|
|
9169
|
+
if (m === null) continue;
|
|
9170
|
+
if (!isMarkerOccurrence(m[1] ?? "", m[2] !== void 0)) continue;
|
|
9171
|
+
const idx = m.index ?? 0;
|
|
9172
|
+
if (isInsideStringLiteral2(line, idx)) continue;
|
|
9173
|
+
items.push({ file: filePath, line: i + 1, kind: m[1]?.toUpperCase() ?? "", text: (m[3] ?? "").trim() });
|
|
9174
|
+
}
|
|
9175
|
+
return items;
|
|
9176
|
+
}
|
|
9177
|
+
function collectTodoFiles(patterns) {
|
|
9178
|
+
if (patterns.length > 0) {
|
|
9179
|
+
const results = [];
|
|
9180
|
+
for (const p of patterns) {
|
|
9181
|
+
const abs = path15.resolve(p);
|
|
9182
|
+
try {
|
|
9183
|
+
const stat = fs15.statSync(abs);
|
|
9184
|
+
if (stat.isDirectory()) {
|
|
9185
|
+
results.push(...walkProject(abs).files);
|
|
9186
|
+
} else {
|
|
9187
|
+
results.push(abs);
|
|
9188
|
+
}
|
|
9189
|
+
} catch {
|
|
9190
|
+
}
|
|
9191
|
+
}
|
|
9192
|
+
return results;
|
|
9193
|
+
}
|
|
9194
|
+
return walkProject(process.cwd()).files;
|
|
9195
|
+
}
|
|
9196
|
+
function cmdTodo(patterns, opts) {
|
|
9197
|
+
const kindSet = new Set(
|
|
9198
|
+
opts.kinds !== void 0 && opts.kinds.length > 0 ? opts.kinds.split(",").map((k) => k.trim().toUpperCase()) : DEFAULT_KINDS
|
|
9199
|
+
);
|
|
9200
|
+
const files = collectTodoFiles(patterns);
|
|
9201
|
+
const items = [];
|
|
9202
|
+
for (const f of files) {
|
|
9203
|
+
items.push(...scanFileForTodos(f, kindSet));
|
|
9204
|
+
}
|
|
9205
|
+
if (opts.json === true) {
|
|
9206
|
+
process.stdout.write(JSON.stringify({ items }, null, 2) + "\n");
|
|
9207
|
+
return;
|
|
9208
|
+
}
|
|
9209
|
+
if (items.length === 0) {
|
|
9210
|
+
process.stdout.write("No TODO markers found.\n");
|
|
9211
|
+
return;
|
|
9212
|
+
}
|
|
9213
|
+
const groupBy = opts.group ?? "file";
|
|
9214
|
+
if (groupBy === "kind") {
|
|
9215
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
9216
|
+
for (const item of items) {
|
|
9217
|
+
const arr = byKind.get(item.kind) ?? [];
|
|
9218
|
+
arr.push(item);
|
|
9219
|
+
byKind.set(item.kind, arr);
|
|
9220
|
+
}
|
|
9221
|
+
for (const [kind, group] of byKind) {
|
|
9222
|
+
process.stdout.write(`
|
|
9223
|
+
[${kind}]
|
|
9224
|
+
`);
|
|
9225
|
+
for (const item of group) {
|
|
9226
|
+
process.stdout.write(` ${item.file}:${item.line} ${item.text}
|
|
9227
|
+
`);
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
} else {
|
|
9231
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
9232
|
+
for (const item of items) {
|
|
9233
|
+
const arr = byFile.get(item.file) ?? [];
|
|
9234
|
+
arr.push(item);
|
|
9235
|
+
byFile.set(item.file, arr);
|
|
9236
|
+
}
|
|
9237
|
+
for (const [file, group] of byFile) {
|
|
9238
|
+
for (const item of group) {
|
|
9239
|
+
process.stdout.write(`${file}:${item.line} ${item.kind} ${item.text}
|
|
9240
|
+
`);
|
|
9241
|
+
}
|
|
9242
|
+
}
|
|
9243
|
+
}
|
|
9244
|
+
}
|
|
9245
|
+
function parsePythonBlock(lines, start) {
|
|
9246
|
+
if (!/^Traceback \(most recent call last\):/.test(lines[start] ?? "")) return null;
|
|
9247
|
+
let i = start + 1;
|
|
9248
|
+
const frames = [];
|
|
9249
|
+
let block = null;
|
|
9250
|
+
while (i < lines.length) {
|
|
9251
|
+
const fl = lines[i] ?? "";
|
|
9252
|
+
const fm = /^\s{2}File "([^"]+)", line (\d+), in (\S+)/.exec(fl);
|
|
9253
|
+
if (fm !== null) {
|
|
9254
|
+
i++;
|
|
9255
|
+
const peek = lines[i]?.trim();
|
|
9256
|
+
const hasContext = peek !== void 0 && !peek.startsWith("File ") && !peek.startsWith("Traceback");
|
|
9257
|
+
if (hasContext) i++;
|
|
9258
|
+
frames.push({ file: fm[1] ?? "", lineNo: Number.parseInt(fm[2] ?? "0", 10), func: fm[3] ?? "", context: hasContext ? peek ?? "" : "" });
|
|
9259
|
+
continue;
|
|
9260
|
+
}
|
|
9261
|
+
if (/^Traceback \(most recent call last\):/.test(fl)) {
|
|
9262
|
+
break;
|
|
9263
|
+
}
|
|
9264
|
+
if (!/^\s/.test(fl) && fl.trim() !== "") {
|
|
9265
|
+
block = { frames, exception: fl.trim() };
|
|
9266
|
+
i++;
|
|
9267
|
+
break;
|
|
9268
|
+
}
|
|
9269
|
+
i++;
|
|
9270
|
+
}
|
|
9271
|
+
if (frames.length > 0 && block === null) {
|
|
9272
|
+
block = { frames, exception: "" };
|
|
9273
|
+
}
|
|
9274
|
+
return { block, nextIndex: i };
|
|
9275
|
+
}
|
|
9276
|
+
var NODE_FRAME_WITH_FUNC_RE = /^\s+at\s+(.+?)\s+\(([^)]+)\)\s*$/;
|
|
9277
|
+
var NODE_FRAME_ANON_RE = /^\s+at\s+([^\s()][^()]*)\s*$/;
|
|
9278
|
+
var NODE_LOC_RE = /^(.*):(\d+):(\d+)$/;
|
|
9279
|
+
function parseNodeFrameLine(line) {
|
|
9280
|
+
const withFunc = NODE_FRAME_WITH_FUNC_RE.exec(line);
|
|
9281
|
+
if (withFunc !== null) {
|
|
9282
|
+
const loc = NODE_LOC_RE.exec(withFunc[2] ?? "");
|
|
9283
|
+
if (loc === null) return null;
|
|
9284
|
+
return { file: loc[1] ?? "", lineNo: Number.parseInt(loc[2] ?? "0", 10), func: withFunc[1] ?? "" };
|
|
9285
|
+
}
|
|
9286
|
+
const anon = NODE_FRAME_ANON_RE.exec(line);
|
|
9287
|
+
if (anon !== null) {
|
|
9288
|
+
const loc = NODE_LOC_RE.exec((anon[1] ?? "").trim());
|
|
9289
|
+
if (loc === null) return null;
|
|
9290
|
+
return { file: loc[1] ?? "", lineNo: Number.parseInt(loc[2] ?? "0", 10), func: "" };
|
|
9291
|
+
}
|
|
9292
|
+
return null;
|
|
9293
|
+
}
|
|
9294
|
+
function parseNodeBlock(lines, start) {
|
|
9295
|
+
const header = (lines[start] ?? "").trim();
|
|
9296
|
+
if (header === "") return null;
|
|
9297
|
+
const firstFrame = parseNodeFrameLine(lines[start + 1] ?? "");
|
|
9298
|
+
if (firstFrame === null) return null;
|
|
9299
|
+
const frames = [firstFrame];
|
|
9300
|
+
let i = start + 2;
|
|
9301
|
+
while (i < lines.length) {
|
|
9302
|
+
const f = parseNodeFrameLine(lines[i] ?? "");
|
|
9303
|
+
if (f === null) break;
|
|
9304
|
+
frames.push(f);
|
|
9305
|
+
i++;
|
|
9306
|
+
}
|
|
9307
|
+
return { block: { frames, exception: header }, nextIndex: i };
|
|
9308
|
+
}
|
|
9309
|
+
var RUST_PANIC_HEADER_RE = /^thread '[^']*' panicked at (.+):(\d+):(\d+):\s*$/;
|
|
9310
|
+
var RUST_BACKTRACE_NOTE_RE = /^note: run with `RUST_BACKTRACE=1`/;
|
|
9311
|
+
var RUST_BACKTRACE_NUM_RE = /^\s*\d+:\s+(.+)$/;
|
|
9312
|
+
var RUST_BACKTRACE_AT_RE = /^\s+at\s+(.+):(\d+):(\d+)\s*$/;
|
|
9313
|
+
function parseRustBlock(lines, start) {
|
|
9314
|
+
const header = lines[start] ?? "";
|
|
9315
|
+
const hm = RUST_PANIC_HEADER_RE.exec(header);
|
|
9316
|
+
if (hm === null) return null;
|
|
9317
|
+
const panicFrame = { file: hm[1] ?? "", lineNo: Number.parseInt(hm[2] ?? "0", 10), func: "" };
|
|
9318
|
+
let i = start + 1;
|
|
9319
|
+
const msgLines = [];
|
|
9320
|
+
while (i < lines.length) {
|
|
9321
|
+
const l = lines[i] ?? "";
|
|
9322
|
+
if (l.trim() === "") {
|
|
9323
|
+
i++;
|
|
9324
|
+
break;
|
|
9325
|
+
}
|
|
9326
|
+
if (RUST_BACKTRACE_NOTE_RE.test(l)) {
|
|
9327
|
+
i++;
|
|
9328
|
+
break;
|
|
9329
|
+
}
|
|
9330
|
+
if (l.trim() === "stack backtrace:") break;
|
|
9331
|
+
msgLines.push(l.trim());
|
|
9332
|
+
i++;
|
|
9333
|
+
}
|
|
9334
|
+
const exception = msgLines.join(" ");
|
|
9335
|
+
if ((lines[i] ?? "").trim() === "stack backtrace:") {
|
|
9336
|
+
i++;
|
|
9337
|
+
const frames = [];
|
|
9338
|
+
while (i < lines.length) {
|
|
9339
|
+
const numMatch = RUST_BACKTRACE_NUM_RE.exec(lines[i] ?? "");
|
|
9340
|
+
if (numMatch === null) break;
|
|
9341
|
+
const atMatch = RUST_BACKTRACE_AT_RE.exec(lines[i + 1] ?? "");
|
|
9342
|
+
if (atMatch === null) {
|
|
9343
|
+
i += 1;
|
|
9344
|
+
continue;
|
|
9345
|
+
}
|
|
9346
|
+
frames.push({ file: atMatch[1] ?? "", lineNo: Number.parseInt(atMatch[2] ?? "0", 10), func: (numMatch[1] ?? "").trim() });
|
|
9347
|
+
i += 2;
|
|
9348
|
+
}
|
|
9349
|
+
if (frames.length > 0) {
|
|
9350
|
+
return { block: { frames, exception }, nextIndex: i };
|
|
9351
|
+
}
|
|
9352
|
+
}
|
|
9353
|
+
return { block: { frames: [panicFrame], exception }, nextIndex: i };
|
|
9354
|
+
}
|
|
9355
|
+
var JVM_HEADER_RE = /^(?:Exception in thread "[^"]*" )?(?:Caused by: )?((?:[A-Za-z_$][\w$]*\.)+[A-Za-z_$][\w$]*): (.*)$/;
|
|
9356
|
+
var JVM_FRAME_RE = /^\s+at\s+(\S+)\(([^)]*)\)\s*$/;
|
|
9357
|
+
var JVM_MORE_RE = /^\s*\.\.\.\s+\d+\s+more\s*$/;
|
|
9358
|
+
function parseJvmFrameLine(line) {
|
|
9359
|
+
const m = JVM_FRAME_RE.exec(line);
|
|
9360
|
+
if (m === null) return null;
|
|
9361
|
+
const func = m[1] ?? "";
|
|
9362
|
+
const inner = m[2] ?? "";
|
|
9363
|
+
if (inner === "Native Method" || inner === "Unknown Source") {
|
|
9364
|
+
return { file: inner, lineNo: 0, func };
|
|
9365
|
+
}
|
|
9366
|
+
const lm = /^(.+):(\d+)$/.exec(inner);
|
|
9367
|
+
if (lm === null) return null;
|
|
9368
|
+
return { file: lm[1] ?? "", lineNo: Number.parseInt(lm[2] ?? "0", 10), func };
|
|
9369
|
+
}
|
|
9370
|
+
function parseJvmBlock(lines, start) {
|
|
9371
|
+
const header = lines[start] ?? "";
|
|
9372
|
+
if (JVM_HEADER_RE.exec(header) === null) return null;
|
|
9373
|
+
const firstFrame = parseJvmFrameLine(lines[start + 1] ?? "");
|
|
9374
|
+
if (firstFrame === null) return null;
|
|
9375
|
+
const frames = [firstFrame];
|
|
9376
|
+
let i = start + 2;
|
|
9377
|
+
while (i < lines.length) {
|
|
9378
|
+
const l = lines[i] ?? "";
|
|
9379
|
+
if (JVM_MORE_RE.test(l)) {
|
|
9380
|
+
i++;
|
|
9381
|
+
break;
|
|
9382
|
+
}
|
|
9383
|
+
const f = parseJvmFrameLine(l);
|
|
9384
|
+
if (f === null) break;
|
|
9385
|
+
frames.push(f);
|
|
9386
|
+
i++;
|
|
9387
|
+
}
|
|
9388
|
+
return { block: { frames, exception: header.trim() }, nextIndex: i };
|
|
9389
|
+
}
|
|
9390
|
+
var DOTNET_HEADER_RE = /^(?:Unhandled exception\. )?((?:[A-Za-z_][\w]*\.)+[A-Za-z_][\w]*): (.*)$/;
|
|
9391
|
+
var DOTNET_FRAME_WITH_LOC_RE = /^\s+at\s+(.+?)\s+in\s+(.+):line\s+(\d+)\s*$/;
|
|
9392
|
+
var DOTNET_FRAME_NO_LOC_RE = /^\s+at\s+(.+)$/;
|
|
9393
|
+
function parseDotnetFrameLine(line) {
|
|
9394
|
+
const withLoc = DOTNET_FRAME_WITH_LOC_RE.exec(line);
|
|
9395
|
+
if (withLoc !== null) {
|
|
9396
|
+
return { file: withLoc[2] ?? "", lineNo: Number.parseInt(withLoc[3] ?? "0", 10), func: withLoc[1] ?? "" };
|
|
9397
|
+
}
|
|
9398
|
+
const noLoc = DOTNET_FRAME_NO_LOC_RE.exec(line);
|
|
9399
|
+
if (noLoc !== null) {
|
|
9400
|
+
return { file: "", lineNo: 0, func: (noLoc[1] ?? "").trim() };
|
|
9401
|
+
}
|
|
9402
|
+
return null;
|
|
9403
|
+
}
|
|
9404
|
+
function parseDotnetBlock(lines, start) {
|
|
9405
|
+
const header = lines[start] ?? "";
|
|
9406
|
+
if (DOTNET_HEADER_RE.exec(header) === null) return null;
|
|
9407
|
+
const firstFrame = DOTNET_FRAME_WITH_LOC_RE.exec(lines[start + 1] ?? "") !== null ? parseDotnetFrameLine(lines[start + 1] ?? "") : null;
|
|
9408
|
+
if (firstFrame === null) return null;
|
|
9409
|
+
const frames = [firstFrame];
|
|
9410
|
+
let i = start + 2;
|
|
9411
|
+
while (i < lines.length) {
|
|
9412
|
+
const f = parseDotnetFrameLine(lines[i] ?? "");
|
|
9413
|
+
if (f === null) break;
|
|
9414
|
+
frames.push(f);
|
|
9415
|
+
i++;
|
|
9416
|
+
}
|
|
9417
|
+
return { block: { frames, exception: header.trim() }, nextIndex: i };
|
|
9418
|
+
}
|
|
9419
|
+
function parseTracebacks(text) {
|
|
9420
|
+
const lines = splitLines(text);
|
|
9421
|
+
const blocks = [];
|
|
9422
|
+
let i = 0;
|
|
9423
|
+
while (i < lines.length) {
|
|
9424
|
+
const result = parsePythonBlock(lines, i) ?? parseRustBlock(lines, i) ?? parseNodeBlock(lines, i) ?? parseJvmBlock(lines, i) ?? parseDotnetBlock(lines, i);
|
|
9425
|
+
if (result === null) {
|
|
9426
|
+
i++;
|
|
9427
|
+
continue;
|
|
9428
|
+
}
|
|
9429
|
+
if (result.block !== null) blocks.push(result.block);
|
|
9430
|
+
i = result.nextIndex;
|
|
9431
|
+
}
|
|
9432
|
+
return blocks;
|
|
9433
|
+
}
|
|
9434
|
+
function isPathUnderRoot(normalPath, normalRoot) {
|
|
9435
|
+
if (!normalPath.startsWith(normalRoot)) return false;
|
|
9436
|
+
if (normalPath === normalRoot) return true;
|
|
9437
|
+
const nextChar = normalPath[normalRoot.length];
|
|
9438
|
+
return nextChar === "/" || nextChar === "\\";
|
|
9439
|
+
}
|
|
9440
|
+
function isProjectFrame(framePath, cwd) {
|
|
9441
|
+
if (framePath.startsWith("node:")) return false;
|
|
9442
|
+
if (framePath === "" || framePath === "Native Method" || framePath === "Unknown Source") return false;
|
|
9443
|
+
const normalCwd = normalizeDarwinSystemAlias(foldPath(canonicalize(cwd)));
|
|
9444
|
+
const normalAbs = normalizeDarwinSystemAlias(foldPath(canonicalize(framePath, cwd)));
|
|
9445
|
+
if (isPathUnderRoot(normalAbs, normalCwd)) {
|
|
9446
|
+
return true;
|
|
9447
|
+
}
|
|
9448
|
+
if (framePath.includes("site-packages") || framePath.includes("lib/python")) return false;
|
|
9449
|
+
if (framePath.includes("/rustc/")) return false;
|
|
9450
|
+
if (framePath.includes(".cargo/registry") || framePath.includes(".cargo\\registry")) return false;
|
|
9451
|
+
if (/^<.+>$/.test(framePath)) return false;
|
|
9452
|
+
if (!path15.isAbsolute(framePath) && !framePath.startsWith("..")) return true;
|
|
9453
|
+
return false;
|
|
9454
|
+
}
|
|
9455
|
+
function resolveFrameSymbol(frame, projectRoot) {
|
|
9456
|
+
const filePath = resolveIndexPath(frame.file, projectRoot);
|
|
9457
|
+
const syms = querySymbols({ filePath, limit: ALL_SYMBOLS_IN_FILE_LIMIT });
|
|
9458
|
+
const match2 = enclosingSymbol(syms, frame.lineNo);
|
|
9459
|
+
if (match2 === null) return null;
|
|
9460
|
+
return {
|
|
9461
|
+
key: `${match2.filePath}::${match2.name}`,
|
|
9462
|
+
name: match2.name,
|
|
9463
|
+
kind: match2.kind,
|
|
9464
|
+
filePath: match2.filePath,
|
|
9465
|
+
lineStart: match2.lineStart,
|
|
9466
|
+
lineEnd: match2.lineEnd,
|
|
9467
|
+
body: resolveBody(match2)
|
|
9468
|
+
};
|
|
9469
|
+
}
|
|
9470
|
+
function formatFrameBody(frame, projectRoot, seen) {
|
|
9471
|
+
const resolved = resolveFrameSymbol(frame, projectRoot);
|
|
9472
|
+
if (resolved === null) {
|
|
9473
|
+
return [` # body: No symbols enclosing line ${frame.lineNo} in '${frame.file}'`];
|
|
9474
|
+
}
|
|
9475
|
+
const header = ` # body: ${resolved.name} ${resolved.kind} ${resolved.filePath}:${resolved.lineStart}-${resolved.lineEnd}`;
|
|
9476
|
+
if (seen.has(resolved.key)) {
|
|
9477
|
+
return [`${header} (same as above)`];
|
|
9478
|
+
}
|
|
9479
|
+
seen.set(resolved.key, true);
|
|
9480
|
+
return [header, resolved.body];
|
|
9481
|
+
}
|
|
9482
|
+
function cmdTrace(src, opts) {
|
|
9483
|
+
const text = readInput(src);
|
|
9484
|
+
const blocks = parseTracebacks(text);
|
|
9485
|
+
if (blocks.length === 0) {
|
|
9486
|
+
process.stderr.write("token-goat: no traceback found\n");
|
|
9487
|
+
process.exitCode = 0;
|
|
9488
|
+
return;
|
|
9489
|
+
}
|
|
9490
|
+
const cwd = process.cwd();
|
|
9491
|
+
const keepN = opts.keep !== void 0 ? requireNonNegativeStrictInt("--keep", opts.keep) : 0;
|
|
9492
|
+
const filtered = blocks.map((b) => {
|
|
9493
|
+
let frames = b.frames.filter((f) => isProjectFrame(f.file, cwd));
|
|
9494
|
+
if (keepN > 0 && frames.length > keepN) frames = frames.slice(frames.length - keepN);
|
|
9495
|
+
return { ...b, frames };
|
|
9496
|
+
});
|
|
9497
|
+
if (opts.json === true) {
|
|
9498
|
+
if (opts.bodies !== true) {
|
|
9499
|
+
process.stdout.write(JSON.stringify({ tracebacks: filtered }, null, 2) + "\n");
|
|
9500
|
+
return;
|
|
9501
|
+
}
|
|
9502
|
+
const seenJson = /* @__PURE__ */ new Map();
|
|
9503
|
+
const withBodies = filtered.map((b) => ({
|
|
9504
|
+
...b,
|
|
9505
|
+
frames: b.frames.map((f) => {
|
|
9506
|
+
const resolved = resolveFrameSymbol(f, cwd);
|
|
9507
|
+
if (resolved === null) return { ...f };
|
|
9508
|
+
if (seenJson.has(resolved.key)) {
|
|
9509
|
+
return { ...f, bodyDuplicateOf: resolved.key };
|
|
9510
|
+
}
|
|
9511
|
+
seenJson.set(resolved.key, true);
|
|
9512
|
+
return {
|
|
9513
|
+
...f,
|
|
9514
|
+
bodySymbol: { name: resolved.name, kind: resolved.kind, filePath: resolved.filePath, lineStart: resolved.lineStart, lineEnd: resolved.lineEnd },
|
|
9515
|
+
body: resolved.body
|
|
9516
|
+
};
|
|
9517
|
+
})
|
|
9518
|
+
}));
|
|
9519
|
+
process.stdout.write(JSON.stringify({ tracebacks: withBodies }, null, 2) + "\n");
|
|
9520
|
+
return;
|
|
9521
|
+
}
|
|
9522
|
+
const seenBodies = /* @__PURE__ */ new Map();
|
|
9523
|
+
for (const [blockIndex, block] of filtered.entries()) {
|
|
9524
|
+
process.stdout.write("Traceback (most recent call last):\n");
|
|
9525
|
+
const projectFrameCount = blocks[blockIndex]?.frames.filter((f) => isProjectFrame(f.file, cwd)).length ?? 0;
|
|
9526
|
+
const droppedByKeep = projectFrameCount - block.frames.length;
|
|
9527
|
+
if (droppedByKeep > 0) {
|
|
9528
|
+
const noun = droppedByKeep === 1 ? "frame" : "frames";
|
|
9529
|
+
process.stdout.write(` ...(${droppedByKeep} more ${noun} elided; use a higher --keep to see more)
|
|
9530
|
+
`);
|
|
9531
|
+
}
|
|
9532
|
+
for (const f of block.frames) {
|
|
9533
|
+
process.stdout.write(` File "${f.file}", line ${f.lineNo}, in ${f.func}
|
|
9534
|
+
`);
|
|
9535
|
+
if (f.context) process.stdout.write(` ${f.context}
|
|
9536
|
+
`);
|
|
9537
|
+
if (opts.bodies === true) {
|
|
9538
|
+
for (const line of formatFrameBody(f, cwd, seenBodies)) process.stdout.write(`${line}
|
|
9539
|
+
`);
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
if (block.frames.length === 0) {
|
|
9543
|
+
const preFilterCount = blocks[blockIndex]?.frames.length ?? 0;
|
|
9544
|
+
const noun = preFilterCount === 1 ? "frame" : "frames";
|
|
9545
|
+
const verb = preFilterCount === 1 ? "was" : "were";
|
|
9546
|
+
process.stdout.write(` (all ${preFilterCount} ${noun} ${verb} filtered out as non-project -- this traceback runs entirely through dependency or runtime code)
|
|
9547
|
+
`);
|
|
9548
|
+
}
|
|
9549
|
+
if (block.exception) process.stdout.write(`${block.exception}
|
|
9550
|
+
`);
|
|
9551
|
+
process.stdout.write("\n");
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
9554
|
+
var VOLATILE_SUBS = [
|
|
9555
|
+
{ re: /\b\d{1,2}:\d{2}:\d{2}(?:\.\d+)?\b/g, placeholder: "[HH:MM:SS]" },
|
|
9556
|
+
{ re: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, placeholder: "[UUID]" },
|
|
9557
|
+
{ re: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g, placeholder: "[IP]" },
|
|
9558
|
+
{ re: /\b[0-9a-f]{8,}\b/g, placeholder: "[HEX]" },
|
|
9559
|
+
// Bare integers (counters, PIDs, ports, line numbers, byte counts, elapsed-ms values). Must run last: it operates on a string that has already had HH:MM:SS/UUID/IP/HEX replaced with their placeholders, so it never competes with those rules for the same digits. The lookbehind/lookahead exclude letters, digits AND underscore (not just \b, which treats underscore as a word character) so a digit run embedded in a longer token like v2, utf8, x86_64, sha256, or test_3_case is left untouched.
|
|
9560
|
+
{ re: /(?<![A-Za-z0-9_])\d+(?![A-Za-z0-9_])/g, placeholder: "[N]" }
|
|
9561
|
+
];
|
|
9562
|
+
function normalizeVolatile(line) {
|
|
9563
|
+
let out2 = line;
|
|
9564
|
+
for (const sub of VOLATILE_SUBS) {
|
|
9565
|
+
out2 = out2.replace(sub.re, sub.placeholder);
|
|
9566
|
+
}
|
|
9567
|
+
return out2;
|
|
9568
|
+
}
|
|
9569
|
+
var MAX_FOLD_REPEATS_KEYS = 2e4;
|
|
9570
|
+
function applyFiltersAndFold(lines, noNormalize, foldRepeats) {
|
|
9571
|
+
const dropped = [];
|
|
9572
|
+
for (const raw of lines) {
|
|
9573
|
+
let cur = raw;
|
|
9574
|
+
for (const filter2 of FILTERS) {
|
|
9575
|
+
if (cur === null) break;
|
|
9576
|
+
if (filter2.pattern !== null && !filter2.pattern.test(cur)) continue;
|
|
9577
|
+
cur = filter2.replacer(cur);
|
|
9578
|
+
break;
|
|
9579
|
+
}
|
|
9580
|
+
if (cur !== null) dropped.push(cur);
|
|
9581
|
+
}
|
|
9582
|
+
const folded = [];
|
|
9583
|
+
if (!foldRepeats) {
|
|
9584
|
+
let prevKey2 = null;
|
|
9585
|
+
let lastText = "";
|
|
9586
|
+
let count = 0;
|
|
9587
|
+
for (const line of dropped) {
|
|
9588
|
+
const key = noNormalize ? line : normalizeVolatile(line);
|
|
9589
|
+
if (key === prevKey2) {
|
|
9590
|
+
count++;
|
|
9591
|
+
} else {
|
|
9592
|
+
if (prevKey2 !== null) folded.push({ text: lastText, count });
|
|
9593
|
+
prevKey2 = key;
|
|
9594
|
+
lastText = line;
|
|
9595
|
+
count = 1;
|
|
9596
|
+
}
|
|
9597
|
+
}
|
|
9598
|
+
if (prevKey2 !== null) folded.push({ text: lastText, count });
|
|
9599
|
+
return folded;
|
|
9600
|
+
}
|
|
9601
|
+
const keyIndex = /* @__PURE__ */ new Map();
|
|
9602
|
+
let prevKey = null;
|
|
9603
|
+
for (const line of dropped) {
|
|
9604
|
+
const key = noNormalize ? line : normalizeVolatile(line);
|
|
9605
|
+
const seenIdx = keyIndex.get(key);
|
|
9606
|
+
if (seenIdx !== void 0) {
|
|
9607
|
+
const entry = folded[seenIdx];
|
|
9608
|
+
if (entry !== void 0) entry.count++;
|
|
9609
|
+
} else if (key === prevKey && folded.length > 0) {
|
|
9610
|
+
const entry = folded[folded.length - 1];
|
|
9611
|
+
if (entry !== void 0) entry.count++;
|
|
9612
|
+
} else {
|
|
9613
|
+
folded.push({ text: line, count: 1 });
|
|
9614
|
+
if (keyIndex.size < MAX_FOLD_REPEATS_KEYS) keyIndex.set(key, folded.length - 1);
|
|
9615
|
+
}
|
|
9616
|
+
prevKey = key;
|
|
9617
|
+
}
|
|
9618
|
+
return folded;
|
|
9619
|
+
}
|
|
9620
|
+
function cmdLogfold(src, opts) {
|
|
9621
|
+
const text = readInput(src);
|
|
9622
|
+
let lines = splitLines(text);
|
|
9623
|
+
if (opts.tail !== void 0) {
|
|
9624
|
+
const n = requireNonNegativeStrictInt("--tail", opts.tail);
|
|
9625
|
+
lines = lines.slice(Math.max(0, lines.length - n));
|
|
9626
|
+
}
|
|
9627
|
+
const folded = applyFiltersAndFold(lines, opts.noNormalize === true, opts.foldRepeats === true);
|
|
9628
|
+
if (opts.json === true) {
|
|
9629
|
+
process.stdout.write(JSON.stringify({ lines: folded }, null, 2) + "\n");
|
|
9630
|
+
return;
|
|
9631
|
+
}
|
|
9632
|
+
for (const item of folded) {
|
|
9633
|
+
if (item.count > 1) {
|
|
9634
|
+
process.stdout.write(`${item.text} (x${item.count})
|
|
9635
|
+
`);
|
|
9636
|
+
} else {
|
|
9637
|
+
process.stdout.write(`${item.text}
|
|
9638
|
+
`);
|
|
9639
|
+
}
|
|
9640
|
+
}
|
|
9641
|
+
}
|
|
9642
|
+
var LOCK_PRIORITY = [
|
|
9643
|
+
"package-lock.json",
|
|
9644
|
+
"yarn.lock",
|
|
9645
|
+
"pnpm-lock.yaml",
|
|
9646
|
+
"poetry.lock",
|
|
9647
|
+
"uv.lock",
|
|
9648
|
+
"Pipfile.lock",
|
|
9649
|
+
"Cargo.lock"
|
|
9650
|
+
];
|
|
9651
|
+
function findLockfile(startPath) {
|
|
9652
|
+
const stat = fs15.statSync(startPath, { throwIfNoEntry: false });
|
|
9653
|
+
if (stat !== void 0 && stat.isFile()) {
|
|
9654
|
+
return { file: startPath, others: [] };
|
|
9655
|
+
}
|
|
9656
|
+
const dir = stat !== void 0 && stat.isDirectory() ? startPath : path15.dirname(startPath);
|
|
9657
|
+
const found = [];
|
|
9658
|
+
for (const name of LOCK_PRIORITY) {
|
|
9659
|
+
const candidate = path15.join(dir, name);
|
|
9660
|
+
if (fs15.existsSync(candidate)) found.push(candidate);
|
|
9661
|
+
}
|
|
9662
|
+
try {
|
|
9663
|
+
const entries = fs15.readdirSync(dir);
|
|
9664
|
+
for (const e of entries) {
|
|
9665
|
+
if (/^requirements.*\.txt$/.test(e)) {
|
|
9666
|
+
const p = path15.join(dir, e);
|
|
9667
|
+
if (!found.includes(p)) found.push(p);
|
|
9668
|
+
}
|
|
9669
|
+
}
|
|
9670
|
+
} catch {
|
|
9671
|
+
}
|
|
9672
|
+
if (found.length === 0) return null;
|
|
9673
|
+
const primary = found[0];
|
|
9674
|
+
return { file: primary, others: found.slice(1) };
|
|
9675
|
+
}
|
|
9676
|
+
function collectV1Dependencies(deps, isDirect, out2) {
|
|
9677
|
+
for (const [name, val] of Object.entries(deps)) {
|
|
9678
|
+
out2.push({ name, version: val.version ?? "", kind: isDirect ? "direct" : "transitive" });
|
|
9679
|
+
if (val.dependencies !== void 0) collectV1Dependencies(val.dependencies, false, out2);
|
|
9680
|
+
}
|
|
9681
|
+
}
|
|
9682
|
+
function parsePackageLockJson(content) {
|
|
9683
|
+
const raw = JSON.parse(content);
|
|
9684
|
+
if (raw.packages === void 0 && raw.dependencies !== void 0) {
|
|
9685
|
+
const deps2 = [];
|
|
9686
|
+
collectV1Dependencies(raw.dependencies, true, deps2);
|
|
9687
|
+
return deps2;
|
|
9688
|
+
}
|
|
9689
|
+
const pkgs = raw.packages ?? {};
|
|
9690
|
+
const directDeps = pkgs[""] ?? {};
|
|
9691
|
+
const allDirect = /* @__PURE__ */ new Set([
|
|
9692
|
+
...Object.keys(directDeps.dependencies ?? {}),
|
|
9693
|
+
...Object.keys(directDeps.devDependencies ?? {}),
|
|
9694
|
+
...Object.keys(directDeps.optionalDependencies ?? {})
|
|
9695
|
+
]);
|
|
9696
|
+
const deps = [];
|
|
9697
|
+
for (const [key, val] of Object.entries(pkgs)) {
|
|
9698
|
+
if (key === "") continue;
|
|
9699
|
+
const name = key.split("node_modules/").pop() ?? key;
|
|
9700
|
+
const version = val.version ?? "";
|
|
9701
|
+
const isTopLevel = key === `node_modules/${name}`;
|
|
9702
|
+
deps.push({ name, version, kind: isTopLevel && allDirect.has(name) ? "direct" : "transitive" });
|
|
9703
|
+
}
|
|
9704
|
+
return deps;
|
|
9705
|
+
}
|
|
9706
|
+
function parseYarnLock(content) {
|
|
9707
|
+
const deps = [];
|
|
9708
|
+
const headerRe = /^"?(@?[^@"]+)@/;
|
|
9709
|
+
const versionRe = /^\s{2}version[:\s]+"?([^"\s]+)"?/;
|
|
9710
|
+
const lines = splitLines(content);
|
|
9711
|
+
let pendingName = null;
|
|
9712
|
+
for (const line of lines) {
|
|
9713
|
+
if (line.trim() === "" || line.startsWith("#")) {
|
|
9714
|
+
pendingName = null;
|
|
9715
|
+
continue;
|
|
9716
|
+
}
|
|
9717
|
+
if (!line.startsWith(" ") && !line.startsWith(" ")) {
|
|
9718
|
+
const m = headerRe.exec(line);
|
|
9719
|
+
if (m !== null) pendingName = m[1]?.trim() ?? null;
|
|
9720
|
+
continue;
|
|
9721
|
+
}
|
|
9722
|
+
if (pendingName !== null) {
|
|
9723
|
+
const vm = versionRe.exec(line);
|
|
9724
|
+
if (vm !== null) {
|
|
9725
|
+
deps.push({ name: pendingName, version: vm[1] ?? "", kind: "unknown" });
|
|
9726
|
+
pendingName = null;
|
|
9727
|
+
}
|
|
9728
|
+
}
|
|
9729
|
+
}
|
|
9730
|
+
return deps;
|
|
9731
|
+
}
|
|
9732
|
+
function parseTomlPackages(content) {
|
|
9733
|
+
const deps = [];
|
|
9734
|
+
const lines = splitLines(content);
|
|
9735
|
+
let inPackage = false;
|
|
9736
|
+
let name = "";
|
|
9737
|
+
let version = "";
|
|
9738
|
+
for (const line of lines) {
|
|
9739
|
+
if (/^\[\[package\]\]/.test(line)) {
|
|
9740
|
+
if (inPackage && name) deps.push({ name, version, kind: "unknown" });
|
|
9741
|
+
inPackage = true;
|
|
9742
|
+
name = "";
|
|
9743
|
+
version = "";
|
|
9744
|
+
continue;
|
|
9745
|
+
}
|
|
9746
|
+
if (inPackage && /^name\s*=/.test(line)) {
|
|
9747
|
+
const m = /=\s*"([^"]+)"/.exec(line);
|
|
9748
|
+
if (m !== null) name = m[1] ?? "";
|
|
9749
|
+
}
|
|
9750
|
+
if (inPackage && /^version\s*=/.test(line)) {
|
|
9751
|
+
const m = /=\s*"([^"]+)"/.exec(line);
|
|
9752
|
+
if (m !== null) version = m[1] ?? "";
|
|
9753
|
+
}
|
|
9754
|
+
}
|
|
9755
|
+
if (inPackage && name) deps.push({ name, version, kind: "unknown" });
|
|
9756
|
+
return deps;
|
|
9757
|
+
}
|
|
9758
|
+
function parsePipfileLock(content) {
|
|
9759
|
+
const raw = JSON.parse(content);
|
|
9760
|
+
const deps = [];
|
|
9761
|
+
for (const [name, meta] of Object.entries(raw.default ?? {})) {
|
|
9762
|
+
deps.push({ name, version: (meta.version ?? "").replace(/^==/, ""), kind: "unknown" });
|
|
9763
|
+
}
|
|
9764
|
+
for (const [name, meta] of Object.entries(raw.develop ?? {})) {
|
|
9765
|
+
deps.push({ name, version: (meta.version ?? "").replace(/^==/, ""), kind: "unknown" });
|
|
9766
|
+
}
|
|
9767
|
+
return deps;
|
|
9768
|
+
}
|
|
9769
|
+
function parseRequirementsTxt(content) {
|
|
9770
|
+
const deps = [];
|
|
9771
|
+
for (const raw of splitLines(content)) {
|
|
9772
|
+
if (/^\s*#/.test(raw)) continue;
|
|
9773
|
+
const eggMatch = /^\s*(?:-e\s+|--editable[\s=]+)?(?:git|hg|svn|bzr)\+.*#egg=([A-Za-z0-9_.-]+)/.exec(raw);
|
|
9774
|
+
if (eggMatch !== null) {
|
|
9775
|
+
deps.push({ name: eggMatch[1] ?? "", version: "", kind: "unknown" });
|
|
9776
|
+
continue;
|
|
9777
|
+
}
|
|
9778
|
+
const line = raw.split("#")[0]?.trim() ?? "";
|
|
9779
|
+
if (!line || line.startsWith("-")) continue;
|
|
9780
|
+
const m = /^([A-Za-z0-9_.-]+)(?:\[[^\]]*\])?\s*(?:[>=!~<]+\s*([^\s,;]+))?/.exec(line);
|
|
9781
|
+
if (m !== null) {
|
|
9782
|
+
deps.push({ name: m[1] ?? "", version: m[2] ?? "", kind: "unknown" });
|
|
9783
|
+
}
|
|
9784
|
+
}
|
|
9785
|
+
return deps;
|
|
9786
|
+
}
|
|
9787
|
+
function stripPnpmPeerSuffix(value) {
|
|
9788
|
+
let end = value.length;
|
|
9789
|
+
while (end > 0 && value[end - 1] === ")") {
|
|
9790
|
+
let depth = 0;
|
|
9791
|
+
let i = end - 1;
|
|
9792
|
+
for (; i >= 0; i--) {
|
|
9793
|
+
const ch = value[i];
|
|
9794
|
+
if (ch === ")") depth++;
|
|
9795
|
+
else if (ch === "(") {
|
|
9796
|
+
depth--;
|
|
9797
|
+
if (depth === 0) break;
|
|
9798
|
+
}
|
|
9799
|
+
}
|
|
9800
|
+
if (depth !== 0 || i < 0) break;
|
|
9801
|
+
end = i;
|
|
9802
|
+
}
|
|
9803
|
+
return value.slice(0, end);
|
|
9804
|
+
}
|
|
9805
|
+
function stripPnpmLegacyPeerHash(value) {
|
|
9806
|
+
const idx = value.indexOf("_");
|
|
9807
|
+
return idx === -1 ? value : value.slice(0, idx);
|
|
9808
|
+
}
|
|
9809
|
+
function splitPnpmPackageKey(rawKey) {
|
|
9810
|
+
const key = stripPnpmPeerSuffix(rawKey.startsWith("/") ? rawKey.slice(1) : rawKey);
|
|
9811
|
+
const scoped = key.startsWith("@");
|
|
9812
|
+
const nameSearchStart = scoped ? key.indexOf("/") : 0;
|
|
9813
|
+
if (scoped && nameSearchStart === -1) return null;
|
|
9814
|
+
const additionalSlashIdx = key.indexOf("/", nameSearchStart + 1);
|
|
9815
|
+
if (additionalSlashIdx !== -1) {
|
|
9816
|
+
const name2 = key.slice(0, additionalSlashIdx);
|
|
9817
|
+
const version2 = stripPnpmLegacyPeerHash(key.slice(additionalSlashIdx + 1));
|
|
9818
|
+
if (!name2 || !version2) return null;
|
|
9819
|
+
return { name: name2, version: version2 };
|
|
9820
|
+
}
|
|
9821
|
+
const versionSepIdx = key.indexOf("@", nameSearchStart + 1);
|
|
9822
|
+
if (versionSepIdx === -1) return null;
|
|
9823
|
+
const name = key.slice(0, versionSepIdx);
|
|
9824
|
+
const version = key.slice(versionSepIdx + 1);
|
|
9825
|
+
if (!name || !version) return null;
|
|
9826
|
+
return { name, version };
|
|
9827
|
+
}
|
|
9828
|
+
function collectPnpmDirectVersions(section, out2) {
|
|
9829
|
+
if (section === null || typeof section !== "object") return;
|
|
9830
|
+
for (const [name, val] of Object.entries(section)) {
|
|
9831
|
+
if (typeof val === "string" && val) {
|
|
9832
|
+
out2.set(name, stripPnpmLegacyPeerHash(stripPnpmPeerSuffix(val)));
|
|
9833
|
+
continue;
|
|
9834
|
+
}
|
|
9835
|
+
const version = val?.version;
|
|
9836
|
+
if (typeof version === "string" && version) out2.set(name, stripPnpmPeerSuffix(version));
|
|
9837
|
+
}
|
|
9838
|
+
}
|
|
9839
|
+
function parsePnpmLock(content) {
|
|
9840
|
+
let raw;
|
|
9841
|
+
try {
|
|
9842
|
+
raw = load(content);
|
|
9843
|
+
} catch {
|
|
9844
|
+
return [];
|
|
9845
|
+
}
|
|
9846
|
+
if (raw === null || typeof raw !== "object") return [];
|
|
9847
|
+
const doc = raw;
|
|
9848
|
+
const directVersions = /* @__PURE__ */ new Map();
|
|
9849
|
+
const rootSections = doc.importers !== void 0 ? doc.importers["."] : doc;
|
|
9850
|
+
collectPnpmDirectVersions(rootSections?.dependencies, directVersions);
|
|
9851
|
+
collectPnpmDirectVersions(rootSections?.devDependencies, directVersions);
|
|
9852
|
+
collectPnpmDirectVersions(rootSections?.optionalDependencies, directVersions);
|
|
9853
|
+
const deps = [];
|
|
9854
|
+
for (const key of Object.keys(doc.packages ?? {})) {
|
|
9855
|
+
const parsed = splitPnpmPackageKey(key);
|
|
9856
|
+
if (parsed === null) continue;
|
|
9857
|
+
const isDirect = directVersions.get(parsed.name) === parsed.version;
|
|
9858
|
+
deps.push({ name: parsed.name, version: parsed.version, kind: isDirect ? "direct" : "transitive" });
|
|
9859
|
+
}
|
|
9860
|
+
return deps;
|
|
9861
|
+
}
|
|
9862
|
+
function parseLockFile(filePath) {
|
|
9863
|
+
const base = path15.basename(filePath);
|
|
9864
|
+
const content = fs15.readFileSync(filePath, "utf8");
|
|
9865
|
+
if (base === "package-lock.json") return { format: "npm", deps: parsePackageLockJson(content) };
|
|
9866
|
+
if (base === "yarn.lock") return { format: "yarn", deps: parseYarnLock(content) };
|
|
9867
|
+
if (base === "pnpm-lock.yaml") return { format: "pnpm", deps: parsePnpmLock(content) };
|
|
9868
|
+
if (base === "poetry.lock") return { format: "poetry", deps: parseTomlPackages(content) };
|
|
9869
|
+
if (base === "uv.lock") return { format: "uv", deps: parseTomlPackages(content) };
|
|
9870
|
+
if (base === "Cargo.lock") return { format: "cargo", deps: parseTomlPackages(content) };
|
|
9871
|
+
if (base === "Pipfile.lock") return { format: "pipfile", deps: parsePipfileLock(content) };
|
|
9872
|
+
return { format: "requirements", deps: parseRequirementsTxt(content) };
|
|
9873
|
+
}
|
|
9874
|
+
function buildNpmEdges(content) {
|
|
9875
|
+
const raw = JSON.parse(content);
|
|
9876
|
+
if (raw.packages === void 0 && raw.dependencies !== void 0) {
|
|
9877
|
+
const edges2 = /* @__PURE__ */ new Map();
|
|
9878
|
+
const directNames2 = new Set(Object.keys(raw.dependencies));
|
|
9879
|
+
const walk = (deps) => {
|
|
9880
|
+
for (const [name, val] of Object.entries(deps)) {
|
|
9881
|
+
if (!edges2.has(name)) edges2.set(name, val.dependencies !== void 0 ? Object.keys(val.dependencies) : []);
|
|
9882
|
+
if (val.dependencies !== void 0) walk(val.dependencies);
|
|
9883
|
+
}
|
|
9884
|
+
};
|
|
9885
|
+
walk(raw.dependencies);
|
|
9886
|
+
return { edges: edges2, directNames: directNames2 };
|
|
9887
|
+
}
|
|
9888
|
+
const pkgs = raw.packages;
|
|
9889
|
+
if (pkgs === void 0) return null;
|
|
9890
|
+
const rootEntry = pkgs[""];
|
|
9891
|
+
const directNames = /* @__PURE__ */ new Set([
|
|
9892
|
+
...Object.keys(rootEntry?.dependencies ?? {}),
|
|
9893
|
+
...Object.keys(rootEntry?.devDependencies ?? {}),
|
|
9894
|
+
...Object.keys(rootEntry?.optionalDependencies ?? {})
|
|
9895
|
+
]);
|
|
9896
|
+
const edges = /* @__PURE__ */ new Map();
|
|
9897
|
+
for (const [key, val] of Object.entries(pkgs)) {
|
|
9898
|
+
if (key === "") continue;
|
|
9899
|
+
const name = key.split("node_modules/").pop() ?? key;
|
|
9900
|
+
if (edges.has(name)) continue;
|
|
9901
|
+
edges.set(name, [
|
|
9902
|
+
.../* @__PURE__ */ new Set([...Object.keys(val.dependencies ?? {}), ...Object.keys(val.devDependencies ?? {}), ...Object.keys(val.optionalDependencies ?? {})])
|
|
9903
|
+
]);
|
|
9904
|
+
}
|
|
9905
|
+
return { edges, directNames };
|
|
9906
|
+
}
|
|
9907
|
+
function findReverseDirectDeps(target, edges, directNames) {
|
|
9908
|
+
const result = [];
|
|
9909
|
+
for (const direct of directNames) {
|
|
9910
|
+
if (direct === target) continue;
|
|
9911
|
+
const seen = /* @__PURE__ */ new Set([direct]);
|
|
9912
|
+
const stack = [...edges.get(direct) ?? []];
|
|
9913
|
+
let reaches = false;
|
|
9914
|
+
while (stack.length > 0) {
|
|
9915
|
+
const cur = stack.pop();
|
|
9916
|
+
if (seen.has(cur)) continue;
|
|
9917
|
+
seen.add(cur);
|
|
9918
|
+
if (cur === target) {
|
|
9919
|
+
reaches = true;
|
|
9920
|
+
break;
|
|
9921
|
+
}
|
|
9922
|
+
for (const next of edges.get(cur) ?? []) stack.push(next);
|
|
9923
|
+
}
|
|
9924
|
+
if (reaches) result.push(direct);
|
|
9925
|
+
}
|
|
9926
|
+
return result.sort();
|
|
9927
|
+
}
|
|
9928
|
+
function cmdLockdepsPackage(lockfile, format, deps, query, json) {
|
|
9929
|
+
const matches2 = deps.filter((d) => d.name === query);
|
|
9930
|
+
if (matches2.length === 0) {
|
|
9931
|
+
const suggestions = suggestPackageNames(query, deps.map((d) => d.name));
|
|
9932
|
+
const hint = suggestions.length > 0 ? ` (did you mean: ${suggestions.join(", ")}?)` : "";
|
|
9933
|
+
throw new Error(`Package '${query}' not found in ${lockfile}${hint}`);
|
|
9934
|
+
}
|
|
9935
|
+
const primary = matches2.find((d) => d.kind === "direct") ?? matches2[0];
|
|
9936
|
+
const otherVersions = [...new Set(matches2.filter((d) => d.version !== primary.version).map((d) => d.version))];
|
|
9937
|
+
const graph = format === "npm" ? buildNpmEdges(fs15.readFileSync(lockfile, "utf8")) : null;
|
|
9938
|
+
const graphAvailable = graph !== null;
|
|
9939
|
+
const dependsOn = graph !== null ? [...graph.edges.get(query) ?? []].sort() : [];
|
|
9940
|
+
const dependedOnBy = graph !== null ? findReverseDirectDeps(query, graph.edges, graph.directNames) : [];
|
|
9941
|
+
if (json) {
|
|
9942
|
+
process.stdout.write(
|
|
9943
|
+
JSON.stringify(
|
|
9944
|
+
{ file: lockfile, format, package: primary.name, version: primary.version, kind: primary.kind, otherVersions, graphAvailable, dependsOn, dependedOnBy },
|
|
9945
|
+
null,
|
|
9946
|
+
2
|
|
9947
|
+
) + "\n"
|
|
9948
|
+
);
|
|
9949
|
+
return;
|
|
9950
|
+
}
|
|
9951
|
+
process.stdout.write(`Lockfile: ${lockfile} (${format})
|
|
9952
|
+
`);
|
|
9953
|
+
process.stdout.write(`Package: ${primary.name}
|
|
9954
|
+
`);
|
|
9955
|
+
process.stdout.write(`Version: ${primary.version}${primary.kind === "unknown" ? "" : ` (${primary.kind})`}
|
|
9956
|
+
`);
|
|
9957
|
+
if (otherVersions.length > 0) process.stdout.write(`Other versions in lockfile: ${otherVersions.join(", ")}
|
|
9958
|
+
`);
|
|
9959
|
+
if (!graphAvailable) {
|
|
9960
|
+
process.stdout.write(`
|
|
9961
|
+
Dependency graph not available for format '${format}' (only npm package-lock.json exposes package-to-package edges).
|
|
9962
|
+
`);
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
process.stdout.write(`
|
|
9966
|
+
Depends on (${dependsOn.length}):
|
|
9967
|
+
`);
|
|
9968
|
+
if (dependsOn.length === 0) process.stdout.write(" (none)\n");
|
|
9969
|
+
for (const n of dependsOn) process.stdout.write(` ${n}
|
|
9970
|
+
`);
|
|
9971
|
+
process.stdout.write(`
|
|
9972
|
+
Depended on by direct/top-level deps (${dependedOnBy.length}):
|
|
9973
|
+
`);
|
|
9974
|
+
if (dependedOnBy.length === 0) process.stdout.write(" (none)\n");
|
|
9975
|
+
for (const n of dependedOnBy) process.stdout.write(` ${n}
|
|
9976
|
+
`);
|
|
9977
|
+
}
|
|
9978
|
+
function cmdLockdeps(filePath, opts) {
|
|
9979
|
+
const target = filePath !== void 0 ? path15.resolve(filePath) : process.cwd();
|
|
9980
|
+
const found = findLockfile(target);
|
|
9981
|
+
if (found === null) {
|
|
9982
|
+
throw new Error("No lockfile found. Expected one of: " + LOCK_PRIORITY.join(", ") + ", requirements*.txt");
|
|
9983
|
+
}
|
|
9984
|
+
const { deps, format } = parseLockFile(found.file);
|
|
9985
|
+
const others = found.others;
|
|
9986
|
+
if (opts.package !== void 0) {
|
|
9987
|
+
cmdLockdepsPackage(found.file, format, deps, opts.package, opts.json === true);
|
|
9988
|
+
return;
|
|
9989
|
+
}
|
|
9990
|
+
if (opts.json === true) {
|
|
9991
|
+
process.stdout.write(JSON.stringify({ file: found.file, format, total: deps.length, others, deps }, null, 2) + "\n");
|
|
9992
|
+
return;
|
|
9993
|
+
}
|
|
9994
|
+
process.stdout.write(`Lockfile: ${found.file} (${format})
|
|
9995
|
+
`);
|
|
9996
|
+
if (others.length > 0) process.stdout.write(`Other lockfiles found (not parsed): ${others.join(", ")}
|
|
9997
|
+
`);
|
|
9998
|
+
process.stdout.write(`Total: ${deps.length} packages
|
|
9999
|
+
|
|
10000
|
+
`);
|
|
10001
|
+
for (const dep of deps) {
|
|
10002
|
+
const kindLabel = dep.kind === "unknown" ? "" : ` (${dep.kind})`;
|
|
10003
|
+
process.stdout.write(`${dep.name} ${dep.version}${kindLabel}
|
|
10004
|
+
`);
|
|
10005
|
+
}
|
|
8273
10006
|
}
|
|
8274
|
-
function
|
|
8275
|
-
const
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
const
|
|
8283
|
-
|
|
8284
|
-
|
|
10007
|
+
function resolveProjectHash() {
|
|
10008
|
+
const project = findProject(process.cwd());
|
|
10009
|
+
if (project === null) throw new Error("No project root found from cwd. Is this inside a project (git repo, package.json, etc.)?");
|
|
10010
|
+
return project.hash;
|
|
10011
|
+
}
|
|
10012
|
+
function cmdNote(action, key, value, opts) {
|
|
10013
|
+
const act = action.toLowerCase();
|
|
10014
|
+
if (act === "list") {
|
|
10015
|
+
const hash = resolveProjectHash();
|
|
10016
|
+
const entries = loadEntries(hash);
|
|
10017
|
+
if (opts.json === true) {
|
|
10018
|
+
process.stdout.write(JSON.stringify(entries, null, 2) + "\n");
|
|
10019
|
+
} else {
|
|
10020
|
+
const pairs = Object.entries(entries);
|
|
10021
|
+
if (pairs.length === 0) {
|
|
10022
|
+
process.stdout.write("(no notes set)\n");
|
|
10023
|
+
} else {
|
|
10024
|
+
for (const [k, v] of pairs) {
|
|
10025
|
+
process.stdout.write(`${k} = ${v}
|
|
10026
|
+
`);
|
|
10027
|
+
}
|
|
10028
|
+
}
|
|
8285
10029
|
}
|
|
10030
|
+
return;
|
|
8286
10031
|
}
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
const detected = options?.runner ?? detectRunner(cleaned);
|
|
8293
|
-
if (detected === "pytest") {
|
|
8294
|
-
return extractPytest(lines);
|
|
10032
|
+
if (act === "clear") {
|
|
10033
|
+
const hash = resolveProjectHash();
|
|
10034
|
+
clearAll(hash);
|
|
10035
|
+
process.stdout.write("Cleared all notes for this project.\n");
|
|
10036
|
+
return;
|
|
8295
10037
|
}
|
|
8296
|
-
if (
|
|
8297
|
-
|
|
10038
|
+
if (act === "get") {
|
|
10039
|
+
if (key === void 0) throw new Error("note get requires a key");
|
|
10040
|
+
const hash = resolveProjectHash();
|
|
10041
|
+
const entries = loadEntries(hash);
|
|
10042
|
+
const v = entries[key];
|
|
10043
|
+
if (v === void 0) throw new Error(`Key not found: ${key}`);
|
|
10044
|
+
process.stdout.write(v + "\n");
|
|
10045
|
+
return;
|
|
8298
10046
|
}
|
|
8299
|
-
if (
|
|
8300
|
-
|
|
10047
|
+
if (act === "unset") {
|
|
10048
|
+
if (key === void 0) throw new Error("note unset requires a key");
|
|
10049
|
+
const hash = resolveProjectHash();
|
|
10050
|
+
unsetEntry(hash, key);
|
|
10051
|
+
process.stdout.write(`Unset: ${key}
|
|
10052
|
+
`);
|
|
10053
|
+
return;
|
|
8301
10054
|
}
|
|
8302
|
-
if (
|
|
8303
|
-
|
|
10055
|
+
if (act === "set") {
|
|
10056
|
+
if (key === void 0) throw new Error("note set requires a key");
|
|
10057
|
+
if (value === void 0) throw new Error("note set requires a value");
|
|
10058
|
+
const hash = resolveProjectHash();
|
|
10059
|
+
setEntry(hash, key, value);
|
|
10060
|
+
process.stdout.write(`Set: ${key} = ${value}
|
|
10061
|
+
`);
|
|
10062
|
+
return;
|
|
8304
10063
|
}
|
|
8305
|
-
|
|
10064
|
+
throw new Error(`Unknown note action: ${action}. Use: set, get, unset, list, clear`);
|
|
8306
10065
|
}
|
|
8307
|
-
function
|
|
8308
|
-
|
|
8309
|
-
|
|
10066
|
+
function loadAllSessionReadCounts() {
|
|
10067
|
+
const sessionsDir = path15.join(tokenGoatHome(), "sessions");
|
|
10068
|
+
const totals = /* @__PURE__ */ new Map();
|
|
10069
|
+
let entries;
|
|
10070
|
+
try {
|
|
10071
|
+
entries = fs15.readdirSync(sessionsDir, { withFileTypes: true });
|
|
10072
|
+
} catch {
|
|
10073
|
+
return totals;
|
|
8310
10074
|
}
|
|
8311
|
-
const
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
10075
|
+
for (const entry of entries) {
|
|
10076
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
10077
|
+
const filePath = path15.join(sessionsDir, entry.name);
|
|
10078
|
+
let raw;
|
|
10079
|
+
try {
|
|
10080
|
+
raw = JSON.parse(fs15.readFileSync(filePath, "utf8"));
|
|
10081
|
+
} catch {
|
|
10082
|
+
continue;
|
|
10083
|
+
}
|
|
10084
|
+
if (raw === null || typeof raw !== "object") continue;
|
|
10085
|
+
const files = raw["files"];
|
|
10086
|
+
if (!Array.isArray(files)) continue;
|
|
10087
|
+
for (const f of files) {
|
|
10088
|
+
if (f === null || typeof f !== "object") continue;
|
|
10089
|
+
const fp = f["path"];
|
|
10090
|
+
const rc = f["readCount"];
|
|
10091
|
+
if (typeof fp !== "string" || typeof rc !== "number") continue;
|
|
10092
|
+
const key = foldPath(fp);
|
|
10093
|
+
const existing = totals.get(key);
|
|
10094
|
+
totals.set(key, { path: existing?.path ?? fp, readCount: (existing?.readCount ?? 0) + rc });
|
|
10095
|
+
}
|
|
10096
|
+
}
|
|
10097
|
+
return totals;
|
|
10098
|
+
}
|
|
10099
|
+
function cmdHot(opts) {
|
|
10100
|
+
const limit = opts.limit !== void 0 ? requireNonNegativeStrictInt("--limit", opts.limit) : 20;
|
|
10101
|
+
if (opts.limit !== void 0 && limit === 0) {
|
|
10102
|
+
throw new Error(`--limit must be a positive number, got: "${opts.limit}"`);
|
|
10103
|
+
}
|
|
10104
|
+
const totals = loadAllSessionReadCounts();
|
|
10105
|
+
let entries = [...totals.values()].map(({ path: p, readCount: rc }) => ({ path: p, readCount: rc }));
|
|
10106
|
+
const preProjectCount = entries.length;
|
|
10107
|
+
if (opts.project === true) {
|
|
10108
|
+
const project = findProject(process.cwd());
|
|
10109
|
+
if (project !== null) {
|
|
10110
|
+
const root = foldPath(project.root);
|
|
10111
|
+
entries = entries.filter((e) => isPathUnderRoot(foldPath(e.path), root));
|
|
10112
|
+
}
|
|
10113
|
+
}
|
|
10114
|
+
entries.sort((a, b) => b.readCount - a.readCount);
|
|
10115
|
+
entries = entries.slice(0, limit);
|
|
10116
|
+
if (opts.json === true) {
|
|
10117
|
+
process.stdout.write(JSON.stringify({ entries }, null, 2) + "\n");
|
|
10118
|
+
return;
|
|
8315
10119
|
}
|
|
8316
|
-
if (
|
|
8317
|
-
if (
|
|
8318
|
-
|
|
10120
|
+
if (entries.length === 0) {
|
|
10121
|
+
if (opts.project === true && preProjectCount > 0) {
|
|
10122
|
+
const noun = preProjectCount === 1 ? "file" : "files";
|
|
10123
|
+
process.stdout.write(`No session read data under this project root (${preProjectCount} ${noun} recorded outside it).
|
|
10124
|
+
`);
|
|
10125
|
+
return;
|
|
8319
10126
|
}
|
|
8320
|
-
|
|
10127
|
+
process.stdout.write("No session read data found.\n");
|
|
10128
|
+
return;
|
|
8321
10129
|
}
|
|
8322
|
-
|
|
8323
|
-
|
|
10130
|
+
const hotDisplayRoot = getDisplayRoot();
|
|
10131
|
+
for (const e of entries) {
|
|
10132
|
+
process.stdout.write(`${e.readCount} ${toDisplayPath(hotDisplayRoot, e.path)}
|
|
10133
|
+
`);
|
|
8324
10134
|
}
|
|
8325
|
-
const n = getFailureCount(result);
|
|
8326
|
-
parts.push(`
|
|
8327
|
-
${n} failure(s) [${result.runner}]`);
|
|
8328
|
-
return parts.join("\n");
|
|
8329
|
-
}
|
|
8330
|
-
function formatFailuresJson(result) {
|
|
8331
|
-
return JSON.stringify(
|
|
8332
|
-
{
|
|
8333
|
-
runner: result.runner,
|
|
8334
|
-
count: getFailureCount(result),
|
|
8335
|
-
failures: result.blocks.map((b) => ({ name: b.name, body: b.body })),
|
|
8336
|
-
summary: result.summaryLines,
|
|
8337
|
-
stats: result.statsLine
|
|
8338
|
-
},
|
|
8339
|
-
null,
|
|
8340
|
-
2
|
|
8341
|
-
);
|
|
8342
|
-
}
|
|
8343
|
-
function failureSignatures(result) {
|
|
8344
|
-
const raw = result.blocks.length > 0 ? result.blocks.map((b) => b.name.trim()) : result.summaryLines.map((s) => s.trim()).filter((s) => s !== "");
|
|
8345
|
-
return Array.from(new Set(raw));
|
|
8346
10135
|
}
|
|
8347
|
-
function
|
|
8348
|
-
|
|
8349
|
-
|
|
10136
|
+
function cmdRecent(nStr, opts) {
|
|
10137
|
+
const n = nStr !== void 0 ? requireNonNegativeStrictInt("recent", nStr) : 20;
|
|
10138
|
+
if (nStr !== void 0 && n === 0) {
|
|
10139
|
+
throw new Error(`recent: limit must be a positive number, got: "${nStr}"`);
|
|
10140
|
+
}
|
|
10141
|
+
const sessionFiles = getSessionFiles();
|
|
10142
|
+
const entries = [...sessionFiles.values()].map((e) => ({ path: e.path, readCount: e.readCount, lastReadAt: e.lastReadAt, wasEdited: e.wasEdited })).sort((a, b) => b.lastReadAt - a.lastReadAt).slice(0, n);
|
|
10143
|
+
if (opts.json === true) {
|
|
10144
|
+
process.stdout.write(JSON.stringify({ entries, scope: "current-session" }, null, 2) + "\n");
|
|
10145
|
+
return;
|
|
10146
|
+
}
|
|
10147
|
+
process.stdout.write("# Recent files (current session only \u2014 use `token-goat hot` for cross-session)\n");
|
|
10148
|
+
if (entries.length === 0) {
|
|
10149
|
+
process.stdout.write("No files read in this session yet.\n");
|
|
10150
|
+
return;
|
|
10151
|
+
}
|
|
10152
|
+
const recentDisplayRoot = getDisplayRoot();
|
|
10153
|
+
for (const e of entries) {
|
|
10154
|
+
const edited = e.wasEdited ? " [edited]" : "";
|
|
10155
|
+
const ts = new Date(e.lastReadAt).toISOString();
|
|
10156
|
+
process.stdout.write(`${ts} ${toDisplayPath(recentDisplayRoot, e.path)}${edited}
|
|
10157
|
+
`);
|
|
8350
10158
|
}
|
|
8351
|
-
const prevSet = new Set(prevSignatures);
|
|
8352
|
-
const currSet = new Set(currSignatures);
|
|
8353
|
-
return {
|
|
8354
|
-
hasBaseline: true,
|
|
8355
|
-
newlyFailing: currSignatures.filter((s) => !prevSet.has(s)),
|
|
8356
|
-
newlyFixed: prevSignatures.filter((s) => !currSet.has(s)),
|
|
8357
|
-
stillFailing: currSignatures.filter((s) => prevSet.has(s))
|
|
8358
|
-
};
|
|
8359
10159
|
}
|
|
8360
|
-
function
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
10160
|
+
function cmdIgnores(opts) {
|
|
10161
|
+
const cwd = process.cwd();
|
|
10162
|
+
const cfg = loadConfig();
|
|
10163
|
+
const walkMode = detectWalkMode(cwd);
|
|
10164
|
+
const walkIndexBuiltinExclusions = [".env", ".env.*", "*.d.ts"];
|
|
10165
|
+
const report = {
|
|
10166
|
+
walkMode,
|
|
10167
|
+
indexRespectsGitignore: walkMode === "git",
|
|
10168
|
+
walkIndexBuiltinExclusions,
|
|
10169
|
+
skipDirs: [...SKIP_DIRS].sort(),
|
|
10170
|
+
blockedRoots: cfg.worker.blocked_roots,
|
|
10171
|
+
excludeTests: cfg.repomap.exclude_tests,
|
|
10172
|
+
packIgnorePatterns: countPackIgnorePatterns(cwd)
|
|
10173
|
+
};
|
|
10174
|
+
if (opts.json === true) {
|
|
10175
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
10176
|
+
return;
|
|
8371
10177
|
}
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
if (
|
|
8375
|
-
|
|
10178
|
+
process.stdout.write(`Walk mode: ${walkMode}
|
|
10179
|
+
`);
|
|
10180
|
+
if (walkMode === "git") {
|
|
10181
|
+
process.stdout.write("token-goat index: .gitignore exclusions are active (via git ls-files).\n");
|
|
8376
10182
|
} else {
|
|
8377
|
-
|
|
10183
|
+
process.stdout.write(
|
|
10184
|
+
`token-goat index --walk: built-in exclusions ${walkIndexBuiltinExclusions.join(", ")}.
|
|
10185
|
+
`
|
|
10186
|
+
);
|
|
8378
10187
|
}
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
10188
|
+
process.stdout.write(
|
|
10189
|
+
`map/todo/conflicts (and hot --project) ignore neither .gitignore nor ${walkIndexBuiltinExclusions.join(", ")} in either mode -- they only skip: ${report.skipDirs.join(", ")} (and hidden directories).
|
|
10190
|
+
`
|
|
10191
|
+
);
|
|
10192
|
+
if (cfg.worker.blocked_roots.length > 0) {
|
|
10193
|
+
process.stdout.write(`Blocked roots (config, enforced by token-goat index / index --walk / worker only): ${cfg.worker.blocked_roots.join(", ")}
|
|
10194
|
+
`);
|
|
8383
10195
|
} else {
|
|
8384
|
-
|
|
10196
|
+
process.stdout.write("Blocked roots (config, enforced by token-goat index / index --walk / worker only): none\n");
|
|
8385
10197
|
}
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
);
|
|
8392
|
-
return lines.join("\n");
|
|
8393
|
-
}
|
|
8394
|
-
function formatFailureDeltaJson(delta, runner) {
|
|
8395
|
-
return JSON.stringify(
|
|
8396
|
-
{
|
|
8397
|
-
runner,
|
|
8398
|
-
hasBaseline: delta.hasBaseline,
|
|
8399
|
-
newlyFailing: delta.newlyFailing,
|
|
8400
|
-
newlyFixed: delta.newlyFixed,
|
|
8401
|
-
stillFailingCount: delta.stillFailing.length
|
|
8402
|
-
},
|
|
8403
|
-
null,
|
|
8404
|
-
2
|
|
10198
|
+
process.stdout.write(`Exclude tests from repomap: ${cfg.repomap.exclude_tests}
|
|
10199
|
+
`);
|
|
10200
|
+
process.stdout.write(
|
|
10201
|
+
report.packIgnorePatterns > 0 ? `.tokengoatignore: ${report.packIgnorePatterns} pattern${report.packIgnorePatterns === 1 ? "" : "s"}, applied by token-goat pack only -- it does not exclude anything from the symbol index. To keep a path out of the index, run "token-goat project exclude <path>".
|
|
10202
|
+
` : '.tokengoatignore: not present. It would apply to token-goat pack only -- to keep a path out of the symbol index, run "token-goat project exclude <path>".\n'
|
|
8405
10203
|
);
|
|
8406
10204
|
}
|
|
8407
|
-
|
|
8408
|
-
// src/failures_state.ts
|
|
8409
|
-
init_define_import_meta_env();
|
|
8410
|
-
import * as fs9 from "node:fs";
|
|
8411
|
-
import * as path11 from "node:path";
|
|
8412
|
-
var KEY_RE = /^[A-Za-z0-9_-]{1,80}$/;
|
|
8413
|
-
var DEFAULT_FAILURES_STATE_KEY = "default";
|
|
8414
|
-
function validateKey(key) {
|
|
8415
|
-
if (!KEY_RE.test(key)) {
|
|
8416
|
-
throw new Error(
|
|
8417
|
-
`Invalid --key ${JSON.stringify(key)}: use only letters, digits, hyphens, underscores (max 80 chars)`
|
|
8418
|
-
);
|
|
8419
|
-
}
|
|
8420
|
-
}
|
|
8421
|
-
function failuresStatePath(projectHash, key) {
|
|
8422
|
-
validateKey(key);
|
|
8423
|
-
return path11.join(dataDir(), "projects", `${projectHash}_failures_${key}.json`);
|
|
8424
|
-
}
|
|
8425
|
-
function loadFailureSnapshot(projectHash, key) {
|
|
8426
|
-
const p = failuresStatePath(projectHash, key);
|
|
10205
|
+
function countPackIgnorePatterns(root) {
|
|
8427
10206
|
try {
|
|
8428
|
-
|
|
8429
|
-
const parsed = JSON.parse(fs9.readFileSync(p, "utf-8"));
|
|
8430
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
8431
|
-
const obj = parsed;
|
|
8432
|
-
if (!Array.isArray(obj.signatures)) return null;
|
|
8433
|
-
return {
|
|
8434
|
-
signatures: obj.signatures.filter((s) => typeof s === "string"),
|
|
8435
|
-
runner: typeof obj.runner === "string" ? obj.runner : "unknown",
|
|
8436
|
-
storedAt: typeof obj.storedAt === "number" ? obj.storedAt : 0
|
|
8437
|
-
};
|
|
10207
|
+
return fs15.readFileSync(path15.join(root, ".tokengoatignore"), "utf8").split("\n").map((ln) => ln.trim()).filter((ln) => ln.length > 0 && !ln.startsWith("#")).length;
|
|
8438
10208
|
} catch {
|
|
8439
|
-
return
|
|
10209
|
+
return 0;
|
|
8440
10210
|
}
|
|
8441
10211
|
}
|
|
8442
|
-
function saveFailureSnapshot(projectHash, key, snapshot) {
|
|
8443
|
-
const p = failuresStatePath(projectHash, key);
|
|
8444
|
-
const dir = path11.dirname(p);
|
|
8445
|
-
ensureDirSync(dir);
|
|
8446
|
-
const content = JSON.stringify(snapshot);
|
|
8447
|
-
const doSave = () => {
|
|
8448
|
-
atomicWriteText(p, content);
|
|
8449
|
-
return true;
|
|
8450
|
-
};
|
|
8451
|
-
if (withFileLock(`${p}.lock`, doSave) === void 0) doSave();
|
|
8452
|
-
}
|
|
8453
10212
|
|
|
8454
10213
|
// src/dep_docs.ts
|
|
8455
10214
|
init_define_import_meta_env();
|
|
8456
10215
|
import { createRequire } from "node:module";
|
|
8457
|
-
import * as
|
|
8458
|
-
import * as
|
|
10216
|
+
import * as fs16 from "node:fs";
|
|
10217
|
+
import * as path16 from "node:path";
|
|
8459
10218
|
var _require = createRequire(import.meta.url);
|
|
8460
10219
|
var _ts = null;
|
|
8461
10220
|
var _tsLoadAttempted = false;
|
|
@@ -8474,21 +10233,21 @@ function loadTs() {
|
|
|
8474
10233
|
}
|
|
8475
10234
|
function dirExists(p) {
|
|
8476
10235
|
try {
|
|
8477
|
-
return
|
|
10236
|
+
return fs16.statSync(p).isDirectory();
|
|
8478
10237
|
} catch {
|
|
8479
10238
|
return false;
|
|
8480
10239
|
}
|
|
8481
10240
|
}
|
|
8482
10241
|
function fileExists(p) {
|
|
8483
10242
|
try {
|
|
8484
|
-
return
|
|
10243
|
+
return fs16.statSync(p).isFile();
|
|
8485
10244
|
} catch {
|
|
8486
10245
|
return false;
|
|
8487
10246
|
}
|
|
8488
10247
|
}
|
|
8489
10248
|
function readFileTextOrNull(p) {
|
|
8490
10249
|
try {
|
|
8491
|
-
return
|
|
10250
|
+
return fs16.readFileSync(p, "utf8");
|
|
8492
10251
|
} catch {
|
|
8493
10252
|
return null;
|
|
8494
10253
|
}
|
|
@@ -8496,7 +10255,7 @@ function readFileTextOrNull(p) {
|
|
|
8496
10255
|
function listInstalledPackageNames(nodeModulesDir) {
|
|
8497
10256
|
let entries;
|
|
8498
10257
|
try {
|
|
8499
|
-
entries =
|
|
10258
|
+
entries = fs16.readdirSync(nodeModulesDir, { withFileTypes: true });
|
|
8500
10259
|
} catch {
|
|
8501
10260
|
return [];
|
|
8502
10261
|
}
|
|
@@ -8506,7 +10265,7 @@ function listInstalledPackageNames(nodeModulesDir) {
|
|
|
8506
10265
|
if (entry.name.startsWith("@")) {
|
|
8507
10266
|
let scoped;
|
|
8508
10267
|
try {
|
|
8509
|
-
scoped =
|
|
10268
|
+
scoped = fs16.readdirSync(path16.join(nodeModulesDir, entry.name), { withFileTypes: true });
|
|
8510
10269
|
} catch {
|
|
8511
10270
|
continue;
|
|
8512
10271
|
}
|
|
@@ -8523,12 +10282,12 @@ var README_NAME_RE = /^readme(\.(md|markdown|txt))?$/i;
|
|
|
8523
10282
|
function findReadmeFile(pkgDir) {
|
|
8524
10283
|
const direct = findReadmeIn(pkgDir);
|
|
8525
10284
|
if (direct !== null) return direct;
|
|
8526
|
-
return findReadmeIn(
|
|
10285
|
+
return findReadmeIn(path16.join(pkgDir, "docs"));
|
|
8527
10286
|
}
|
|
8528
10287
|
function findReadmeIn(dir) {
|
|
8529
10288
|
let entries;
|
|
8530
10289
|
try {
|
|
8531
|
-
entries =
|
|
10290
|
+
entries = fs16.readdirSync(dir, { withFileTypes: true });
|
|
8532
10291
|
} catch {
|
|
8533
10292
|
return null;
|
|
8534
10293
|
}
|
|
@@ -8540,7 +10299,7 @@ function findReadmeIn(dir) {
|
|
|
8540
10299
|
return 1;
|
|
8541
10300
|
};
|
|
8542
10301
|
matches2.sort((a, b) => rank(a.name) - rank(b.name));
|
|
8543
|
-
return
|
|
10302
|
+
return path16.join(dir, matches2[0].name);
|
|
8544
10303
|
}
|
|
8545
10304
|
function typesPackageDirName(pkgName) {
|
|
8546
10305
|
if (pkgName.startsWith("@")) {
|
|
@@ -8567,30 +10326,30 @@ function resolveTypesLocation(pkgDir, pkgJson, nodeModulesDir, pkgName) {
|
|
|
8567
10326
|
if (declared !== void 0) {
|
|
8568
10327
|
const candidates = [declared, declared.endsWith(".d.ts") ? declared : `${declared}.d.ts`, declared.replace(/\.[cm]?[jt]s$/, ".d.ts")];
|
|
8569
10328
|
for (const c of candidates) {
|
|
8570
|
-
const p =
|
|
10329
|
+
const p = path16.join(pkgDir, c);
|
|
8571
10330
|
if (fileExists(p)) return { path: p, source: "bundled" };
|
|
8572
10331
|
}
|
|
8573
10332
|
}
|
|
8574
10333
|
const main = typeof pkgJson["main"] === "string" ? pkgJson["main"] : "index.js";
|
|
8575
|
-
const mainDts =
|
|
10334
|
+
const mainDts = path16.join(pkgDir, main.replace(/\.[cm]?js$/, ".d.ts"));
|
|
8576
10335
|
if (fileExists(mainDts)) return { path: mainDts, source: "bundled" };
|
|
8577
|
-
const indexDts =
|
|
10336
|
+
const indexDts = path16.join(pkgDir, "index.d.ts");
|
|
8578
10337
|
if (fileExists(indexDts)) return { path: indexDts, source: "bundled" };
|
|
8579
10338
|
const typesDirName = typesPackageDirName(pkgName);
|
|
8580
|
-
const typesPkgDir =
|
|
8581
|
-
const typesPkgJsonRaw = readFileTextOrNull(
|
|
10339
|
+
const typesPkgDir = path16.join(nodeModulesDir, "@types", typesDirName);
|
|
10340
|
+
const typesPkgJsonRaw = readFileTextOrNull(path16.join(typesPkgDir, "package.json"));
|
|
8582
10341
|
if (typesPkgJsonRaw !== null) {
|
|
8583
10342
|
try {
|
|
8584
10343
|
const typesPkgJson = JSON.parse(typesPkgJsonRaw);
|
|
8585
10344
|
const entry = (typeof typesPkgJson["types"] === "string" ? typesPkgJson["types"] : void 0) ?? (typeof typesPkgJson["main"] === "string" ? typesPkgJson["main"] : void 0) ?? "index.d.ts";
|
|
8586
10345
|
const entryCandidates = [entry, entry.endsWith(".d.ts") ? entry : `${entry}.d.ts`, entry.replace(/\.[cm]?[jt]s$/, ".d.ts")];
|
|
8587
10346
|
for (const c of entryCandidates) {
|
|
8588
|
-
const entryPath =
|
|
10347
|
+
const entryPath = path16.join(typesPkgDir, c);
|
|
8589
10348
|
if (fileExists(entryPath)) return { path: entryPath, source: "@types" };
|
|
8590
10349
|
}
|
|
8591
10350
|
} catch {
|
|
8592
10351
|
}
|
|
8593
|
-
const fallback =
|
|
10352
|
+
const fallback = path16.join(typesPkgDir, "index.d.ts");
|
|
8594
10353
|
if (fileExists(fallback)) return { path: fallback, source: "@types" };
|
|
8595
10354
|
}
|
|
8596
10355
|
return null;
|
|
@@ -8657,16 +10416,16 @@ function recordDepDocsStat(fullSourceBytes, emittedText, packageName) {
|
|
|
8657
10416
|
}
|
|
8658
10417
|
function runDepDocs(opts) {
|
|
8659
10418
|
const root = resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() });
|
|
8660
|
-
const nodeModulesDir =
|
|
8661
|
-
const pkgDir =
|
|
8662
|
-
const pkgJsonPath =
|
|
10419
|
+
const nodeModulesDir = path16.join(root, "node_modules");
|
|
10420
|
+
const pkgDir = path16.join(nodeModulesDir, opts.packageName);
|
|
10421
|
+
const pkgJsonPath = path16.join(pkgDir, "package.json");
|
|
8663
10422
|
if (!dirExists(pkgDir) || !fileExists(pkgJsonPath)) {
|
|
8664
10423
|
const known = listInstalledPackageNames(nodeModulesDir);
|
|
8665
10424
|
const suggestions = suggestPackageNames(opts.packageName, known);
|
|
8666
10425
|
const hint = suggestions.length > 0 ? ` (did you mean: ${suggestions.join(", ")}?)` : "";
|
|
8667
10426
|
return { text: `Package '${opts.packageName}' not found under ${nodeModulesDir}${hint}`, code: 1 };
|
|
8668
10427
|
}
|
|
8669
|
-
const pkgJsonRaw =
|
|
10428
|
+
const pkgJsonRaw = fs16.readFileSync(pkgJsonPath, "utf8");
|
|
8670
10429
|
let pkgJson;
|
|
8671
10430
|
try {
|
|
8672
10431
|
pkgJson = JSON.parse(pkgJsonRaw);
|
|
@@ -9170,14 +10929,14 @@ function cmdBaseline(opts) {
|
|
|
9170
10929
|
|
|
9171
10930
|
// src/index_reclaim.ts
|
|
9172
10931
|
init_define_import_meta_env();
|
|
9173
|
-
import * as
|
|
9174
|
-
import * as
|
|
10932
|
+
import * as fs17 from "node:fs";
|
|
10933
|
+
import * as path17 from "node:path";
|
|
9175
10934
|
var DERIVED_TABLES = ["chunk_vectors", "chunks", "refs", "symbols", "files"];
|
|
9176
10935
|
function indexSizeBytes(dbPath) {
|
|
9177
10936
|
let total = 0;
|
|
9178
10937
|
for (const p of [dbPath, `${dbPath}-wal`]) {
|
|
9179
10938
|
try {
|
|
9180
|
-
total +=
|
|
10939
|
+
total += fs17.statSync(p).size;
|
|
9181
10940
|
} catch {
|
|
9182
10941
|
}
|
|
9183
10942
|
}
|
|
@@ -9239,7 +10998,7 @@ function mb(bytes) {
|
|
|
9239
10998
|
}
|
|
9240
10999
|
function cmdReclaimIndex(opts) {
|
|
9241
11000
|
const dbPath = opts.dbPath ?? globalDbPath();
|
|
9242
|
-
if (opts.force !== true && isWorkerRunning(
|
|
11001
|
+
if (opts.force !== true && isWorkerRunning(path17.dirname(dbPath))) {
|
|
9243
11002
|
throw new Error(
|
|
9244
11003
|
"reclaim-index: the worker daemon is running and writing to this index. Stop it first with 'token-goat worker stop', then re-run. Pass --force to proceed anyway (results may be inaccurate if the worker is really live)."
|
|
9245
11004
|
);
|
|
@@ -9274,7 +11033,7 @@ function cmdReclaimIndex(opts) {
|
|
|
9274
11033
|
}
|
|
9275
11034
|
if (result.checkpointBusy) {
|
|
9276
11035
|
process.stdout.write(
|
|
9277
|
-
` note: a concurrent reader blocked WAL truncation, so some space may still be held in ${
|
|
11036
|
+
` note: a concurrent reader blocked WAL truncation, so some space may still be held in ${path17.basename(dbPath)}-wal
|
|
9278
11037
|
`
|
|
9279
11038
|
);
|
|
9280
11039
|
}
|
|
@@ -9282,9 +11041,9 @@ function cmdReclaimIndex(opts) {
|
|
|
9282
11041
|
|
|
9283
11042
|
// src/config_commands.ts
|
|
9284
11043
|
init_define_import_meta_env();
|
|
9285
|
-
import * as
|
|
11044
|
+
import * as fs18 from "node:fs";
|
|
9286
11045
|
import * as os9 from "node:os";
|
|
9287
|
-
import * as
|
|
11046
|
+
import * as path18 from "node:path";
|
|
9288
11047
|
function emit(text) {
|
|
9289
11048
|
const payload = colorStdout() ? text : stripAnsi(text);
|
|
9290
11049
|
process.stdout.write(ensureNewline(payload));
|
|
@@ -9293,7 +11052,7 @@ function emitErr2(text) {
|
|
|
9293
11052
|
process.stderr.write(ensureNewline(text));
|
|
9294
11053
|
}
|
|
9295
11054
|
function saveConfigSafe(cfg) {
|
|
9296
|
-
ensureDirSync(
|
|
11055
|
+
ensureDirSync(path18.dirname(configPath()));
|
|
9297
11056
|
saveConfig(cfg);
|
|
9298
11057
|
}
|
|
9299
11058
|
function levenshtein(a, b, cap = 3) {
|
|
@@ -9504,7 +11263,7 @@ function cmdConfig(opts) {
|
|
|
9504
11263
|
const parseErrAtLoad = getLastConfigParseError();
|
|
9505
11264
|
if (parseErrAtLoad !== null) {
|
|
9506
11265
|
try {
|
|
9507
|
-
|
|
11266
|
+
fs18.copyFileSync(configPath(), `${configPath()}.bak`);
|
|
9508
11267
|
emitErr2(`config set: warning: config.toml failed to parse (${parseErrAtLoad}); backed up the original to config.toml.bak and rewriting it from defaults`);
|
|
9509
11268
|
} catch {
|
|
9510
11269
|
}
|
|
@@ -9540,8 +11299,8 @@ function cmdConfig(opts) {
|
|
|
9540
11299
|
saveConfigSafe(cfg);
|
|
9541
11300
|
return coercedValue;
|
|
9542
11301
|
};
|
|
9543
|
-
ensureDirSync(
|
|
9544
|
-
const lockPath =
|
|
11302
|
+
ensureDirSync(path18.dirname(configPath()));
|
|
11303
|
+
const lockPath = path18.join(path18.dirname(configPath()), ".config.lock");
|
|
9545
11304
|
const lockResult = withFileLock(lockPath, applySet, { waitMs: LOCK_WAIT_MS_HARDENED });
|
|
9546
11305
|
const coerced = lockResult === void 0 ? applySet() : lockResult;
|
|
9547
11306
|
invalidateConfigCache();
|
|
@@ -9570,7 +11329,7 @@ function cmdConfig(opts) {
|
|
|
9570
11329
|
let raw = {};
|
|
9571
11330
|
let parseErr = null;
|
|
9572
11331
|
try {
|
|
9573
|
-
const text =
|
|
11332
|
+
const text = fs18.readFileSync(cfgFile, "utf8");
|
|
9574
11333
|
raw = parse(text);
|
|
9575
11334
|
} catch (e) {
|
|
9576
11335
|
const code = e.code;
|
|
@@ -9677,7 +11436,7 @@ function cmdProject(opts) {
|
|
|
9677
11436
|
emitErr2("project exclude requires a path argument");
|
|
9678
11437
|
throw new Error("missing path");
|
|
9679
11438
|
}
|
|
9680
|
-
const target =
|
|
11439
|
+
const target = path18.resolve(opts.pathArg);
|
|
9681
11440
|
const cfg = loadPersistedConfig();
|
|
9682
11441
|
const targetFolded = foldPath(normalizePath(target));
|
|
9683
11442
|
if (cfg.worker.blocked_roots.some((r) => foldPath(normalizePath(r)) === targetFolded)) {
|
|
@@ -9699,7 +11458,7 @@ function cmdProject(opts) {
|
|
|
9699
11458
|
const before = cfg.worker.blocked_roots;
|
|
9700
11459
|
const after = before.filter((r) => {
|
|
9701
11460
|
try {
|
|
9702
|
-
return
|
|
11461
|
+
return fs18.existsSync(r);
|
|
9703
11462
|
} catch {
|
|
9704
11463
|
return false;
|
|
9705
11464
|
}
|
|
@@ -9746,14 +11505,14 @@ function recordCompactDocStat(fullSourceBytes, emittedText, detail) {
|
|
|
9746
11505
|
recordStat("compact_doc", bytesSaved, Math.round(bytesSaved / 4), void 0, detail);
|
|
9747
11506
|
}
|
|
9748
11507
|
function cmdCompactDoc(opts) {
|
|
9749
|
-
const resolved =
|
|
11508
|
+
const resolved = path18.resolve(opts.filePath);
|
|
9750
11509
|
if (opts.heading !== void 0) {
|
|
9751
11510
|
const result = compactDoc(resolved, opts.heading);
|
|
9752
11511
|
if (result === null) {
|
|
9753
11512
|
emitErr2(`compact-doc: could not read or compact '${resolved}'`);
|
|
9754
11513
|
throw new Error(`could not compact: ${resolved}`);
|
|
9755
11514
|
}
|
|
9756
|
-
const legacyFullBytes =
|
|
11515
|
+
const legacyFullBytes = fs18.statSync(resolved).size;
|
|
9757
11516
|
if (opts.json === true) {
|
|
9758
11517
|
const jsonText = JSON.stringify({ path: resolved, compact: result }, null, 2);
|
|
9759
11518
|
emit(jsonText);
|
|
@@ -9780,7 +11539,7 @@ function cmdCompactDoc(opts) {
|
|
|
9780
11539
|
if (opts.force === true || opts.sentences !== void 0 || !fresh) {
|
|
9781
11540
|
let sourceText;
|
|
9782
11541
|
try {
|
|
9783
|
-
sourceText =
|
|
11542
|
+
sourceText = fs18.readFileSync(resolved, "utf-8");
|
|
9784
11543
|
} catch {
|
|
9785
11544
|
emitErr2(`compact-doc: could not read or compact '${resolved}'`);
|
|
9786
11545
|
throw new Error(`could not compact: ${resolved}`);
|
|
@@ -9796,7 +11555,7 @@ function cmdCompactDoc(opts) {
|
|
|
9796
11555
|
}
|
|
9797
11556
|
body = existing;
|
|
9798
11557
|
}
|
|
9799
|
-
const extractiveFullBytes =
|
|
11558
|
+
const extractiveFullBytes = fs18.statSync(resolved).size;
|
|
9800
11559
|
if (opts.json === true) {
|
|
9801
11560
|
const jsonText = JSON.stringify({ path: resolved, compactPath, rebuilt, compact: body }, null, 2);
|
|
9802
11561
|
emit(jsonText);
|
|
@@ -9853,7 +11612,7 @@ async function cmdFetchImage(opts) {
|
|
|
9853
11612
|
throw new Error(`fetch failed: ${opts.url}`, { cause: e });
|
|
9854
11613
|
}
|
|
9855
11614
|
const buf = fetched.body;
|
|
9856
|
-
const outPath = opts.out ??
|
|
11615
|
+
const outPath = opts.out ?? path18.join(os9.tmpdir(), `tg-fetch-${Date.now()}${extensionForContentType(fetched.contentType)}`);
|
|
9857
11616
|
const originalBytes = buf.length;
|
|
9858
11617
|
let shrunkBytes;
|
|
9859
11618
|
let outData;
|
|
@@ -9935,9 +11694,9 @@ function cmdHistory(opts) {
|
|
|
9935
11694
|
|
|
9936
11695
|
// src/cli_bootstrap_audit.ts
|
|
9937
11696
|
init_define_import_meta_env();
|
|
9938
|
-
import * as
|
|
11697
|
+
import * as fs19 from "node:fs";
|
|
9939
11698
|
import * as os10 from "node:os";
|
|
9940
|
-
import * as
|
|
11699
|
+
import * as path19 from "node:path";
|
|
9941
11700
|
import * as readline from "node:readline";
|
|
9942
11701
|
var FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["description", "tools", "allowed-tools", "allowed_tools"]);
|
|
9943
11702
|
function parseBudget(name, value) {
|
|
@@ -9946,7 +11705,7 @@ function parseBudget(name, value) {
|
|
|
9946
11705
|
return value;
|
|
9947
11706
|
}
|
|
9948
11707
|
async function readFrontmatter(filePath) {
|
|
9949
|
-
const stream =
|
|
11708
|
+
const stream = fs19.createReadStream(filePath, { encoding: "utf8" });
|
|
9950
11709
|
const lines = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
9951
11710
|
let first = true;
|
|
9952
11711
|
let inFrontmatter = false;
|
|
@@ -9992,44 +11751,44 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
9992
11751
|
let logicalRoot;
|
|
9993
11752
|
let rootIsLink;
|
|
9994
11753
|
try {
|
|
9995
|
-
rootIsLink = (await
|
|
9996
|
-
logicalRoot = await
|
|
11754
|
+
rootIsLink = (await fs19.promises.lstat(root)).isSymbolicLink();
|
|
11755
|
+
logicalRoot = await fs19.promises.realpath(root);
|
|
9997
11756
|
} catch (error) {
|
|
9998
11757
|
if (error.code === "ENOENT") return entries;
|
|
9999
|
-
diagnostics.push({ path:
|
|
11758
|
+
diagnostics.push({ path: path19.resolve(root), reason: "unreadable root" });
|
|
10000
11759
|
return entries;
|
|
10001
11760
|
}
|
|
10002
11761
|
if (rootIsLink && !followLinks) {
|
|
10003
|
-
diagnostics.push({ path:
|
|
11762
|
+
diagnostics.push({ path: path19.resolve(root), reason: "external root link skipped (use --follow-links)" });
|
|
10004
11763
|
return entries;
|
|
10005
11764
|
}
|
|
10006
11765
|
const canonicalKey = (candidate) => process.platform === "win32" ? candidate.toLocaleLowerCase() : candidate;
|
|
10007
11766
|
const isContained = (candidate, allowedRoot) => {
|
|
10008
|
-
const relative3 =
|
|
10009
|
-
return relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${
|
|
11767
|
+
const relative3 = path19.relative(canonicalKey(allowedRoot), canonicalKey(candidate));
|
|
11768
|
+
return relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${path19.sep}`) && !path19.isAbsolute(relative3);
|
|
10010
11769
|
};
|
|
10011
11770
|
async function visit(candidate, allowedRoot, topLevel = false) {
|
|
10012
11771
|
let real;
|
|
10013
11772
|
let candidateIsLink;
|
|
10014
11773
|
try {
|
|
10015
|
-
candidateIsLink = (await
|
|
10016
|
-
real = await
|
|
11774
|
+
candidateIsLink = (await fs19.promises.lstat(candidate)).isSymbolicLink();
|
|
11775
|
+
real = await fs19.promises.realpath(candidate);
|
|
10017
11776
|
} catch {
|
|
10018
|
-
diagnostics.push({ path:
|
|
11777
|
+
diagnostics.push({ path: path19.resolve(candidate), reason: "broken or unreadable link" });
|
|
10019
11778
|
return;
|
|
10020
11779
|
}
|
|
10021
11780
|
const withinAllowedRoot = allowedRoot === void 0 ? isContained(real, logicalRoot) : isContained(real, allowedRoot);
|
|
10022
11781
|
const canFollowExternal = followLinks && topLevel;
|
|
10023
11782
|
if (!withinAllowedRoot && !canFollowExternal) {
|
|
10024
|
-
diagnostics.push({ path:
|
|
11783
|
+
diagnostics.push({ path: path19.resolve(candidate), reason: candidateIsLink ? "external link skipped (use --follow-links)" : "canonical target outside scan root" });
|
|
10025
11784
|
return;
|
|
10026
11785
|
}
|
|
10027
11786
|
const trustedRoot = !withinAllowedRoot && canFollowExternal ? real : allowedRoot ?? real;
|
|
10028
11787
|
let stat;
|
|
10029
11788
|
try {
|
|
10030
|
-
stat = await
|
|
11789
|
+
stat = await fs19.promises.stat(real);
|
|
10031
11790
|
} catch {
|
|
10032
|
-
diagnostics.push({ path:
|
|
11791
|
+
diagnostics.push({ path: path19.resolve(candidate), reason: "unreadable" });
|
|
10033
11792
|
return;
|
|
10034
11793
|
}
|
|
10035
11794
|
const canonical = process.platform === "win32" ? real.toLocaleLowerCase() : real;
|
|
@@ -10038,16 +11797,16 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
10038
11797
|
visitedDirs.add(canonical);
|
|
10039
11798
|
let children;
|
|
10040
11799
|
try {
|
|
10041
|
-
children = await
|
|
11800
|
+
children = await fs19.promises.readdir(real, { withFileTypes: true });
|
|
10042
11801
|
} catch {
|
|
10043
|
-
diagnostics.push({ path:
|
|
11802
|
+
diagnostics.push({ path: path19.resolve(candidate), reason: "unreadable directory" });
|
|
10044
11803
|
return;
|
|
10045
11804
|
}
|
|
10046
11805
|
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
10047
|
-
for (const child of children) await visit(
|
|
11806
|
+
for (const child of children) await visit(path19.join(real, child.name), trustedRoot);
|
|
10048
11807
|
return;
|
|
10049
11808
|
}
|
|
10050
|
-
if (!stat.isFile() ||
|
|
11809
|
+
if (!stat.isFile() || path19.extname(real).toLowerCase() !== ".md") return;
|
|
10051
11810
|
if (seenFiles.has(canonical)) return;
|
|
10052
11811
|
seenFiles.add(canonical);
|
|
10053
11812
|
try {
|
|
@@ -10057,35 +11816,35 @@ async function scanMetadataRoot(root, kind, diagnostics, visitedDirs = /* @__PUR
|
|
|
10057
11816
|
const toolsBytes = Buffer.byteLength(metadata.tools, "utf8");
|
|
10058
11817
|
entries.push({
|
|
10059
11818
|
kind,
|
|
10060
|
-
path:
|
|
11819
|
+
path: path19.resolve(real),
|
|
10061
11820
|
description_bytes: descriptionBytes,
|
|
10062
11821
|
tools_bytes: toolsBytes,
|
|
10063
11822
|
metadata_bytes: descriptionBytes + toolsBytes,
|
|
10064
11823
|
estimated_tokens: Math.floor((descriptionBytes + toolsBytes) / 4)
|
|
10065
11824
|
});
|
|
10066
11825
|
} catch {
|
|
10067
|
-
diagnostics.push({ path:
|
|
11826
|
+
diagnostics.push({ path: path19.resolve(candidate), reason: "unreadable file" });
|
|
10068
11827
|
}
|
|
10069
11828
|
}
|
|
10070
11829
|
try {
|
|
10071
|
-
const children = await
|
|
11830
|
+
const children = await fs19.promises.readdir(logicalRoot, { withFileTypes: true });
|
|
10072
11831
|
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
10073
|
-
for (const child of children) await visit(
|
|
11832
|
+
for (const child of children) await visit(path19.join(logicalRoot, child.name), void 0, true);
|
|
10074
11833
|
} catch {
|
|
10075
|
-
diagnostics.push({ path:
|
|
11834
|
+
diagnostics.push({ path: path19.resolve(root), reason: "unreadable root" });
|
|
10076
11835
|
}
|
|
10077
11836
|
return entries;
|
|
10078
11837
|
}
|
|
10079
11838
|
async function buildBootstrapAudit(opts = {}) {
|
|
10080
11839
|
const project = resolveProjectRoot(opts.project === void 0 ? {} : { project: opts.project });
|
|
10081
|
-
const home =
|
|
11840
|
+
const home = path19.resolve(opts.home ?? os10.homedir());
|
|
10082
11841
|
const context = buildStats(project, home, opts.project === void 0 ? [] : [opts.project]);
|
|
10083
11842
|
const diagnostics = [];
|
|
10084
11843
|
const top = opts.top === void 0 ? 10 : parseBudget("--top", opts.top) ?? 10;
|
|
10085
11844
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
10086
11845
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
10087
|
-
const agents = await scanMetadataRoot(
|
|
10088
|
-
const skills = await scanMetadataRoot(
|
|
11846
|
+
const agents = await scanMetadataRoot(path19.join(home, ".claude", "agents"), "agent", diagnostics, visitedDirs, seenFiles, opts.followLinks === true);
|
|
11847
|
+
const skills = await scanMetadataRoot(path19.join(home, ".claude", "skills"), "skill", diagnostics, visitedDirs, seenFiles, opts.followLinks === true);
|
|
10089
11848
|
const largest = [...agents, ...skills].sort((a, b) => b.metadata_bytes - a.metadata_bytes || a.path.localeCompare(b.path)).slice(0, top);
|
|
10090
11849
|
const metadataBytes = [...agents, ...skills].reduce((sum, entry) => sum + entry.metadata_bytes, 0);
|
|
10091
11850
|
const totalTokens = context.total_tokens + Math.floor(metadataBytes / 4);
|
|
@@ -10146,8 +11905,8 @@ async function runBootstrapAudit(opts = {}) {
|
|
|
10146
11905
|
|
|
10147
11906
|
// src/cli_memory.ts
|
|
10148
11907
|
init_define_import_meta_env();
|
|
10149
|
-
import * as
|
|
10150
|
-
import * as
|
|
11908
|
+
import * as fs20 from "node:fs";
|
|
11909
|
+
import * as path20 from "node:path";
|
|
10151
11910
|
function removeExactDupLines(text, report) {
|
|
10152
11911
|
if (report.exactDupLines.length === 0) return text;
|
|
10153
11912
|
const toRemove = new Set(report.exactDupLines.map(([, dupIdx]) => dupIdx));
|
|
@@ -10205,7 +11964,7 @@ function printReport(reports, clusters) {
|
|
|
10205
11964
|
} else {
|
|
10206
11965
|
for (const cluster of clusters) {
|
|
10207
11966
|
w(
|
|
10208
|
-
` [${cluster.method}, similarity ${cluster.similarity}, ~${cluster.tokens} tok] ${cluster.members.map((m) =>
|
|
11967
|
+
` [${cluster.method}, similarity ${cluster.similarity}, ~${cluster.tokens} tok] ${cluster.members.map((m) => path20.basename(m)).join(", ")}
|
|
10209
11968
|
`
|
|
10210
11969
|
);
|
|
10211
11970
|
}
|
|
@@ -10220,7 +11979,7 @@ async function runMemoryCommand(opts = {}) {
|
|
|
10220
11979
|
const claudeMds = findClaudeMdFiles(projectRoot);
|
|
10221
11980
|
const reports = auditClaudeMd(claudeMds);
|
|
10222
11981
|
const memoryMdPath = findMemoryMd(projectRoot);
|
|
10223
|
-
const clusters = memoryMdPath !== null ? await findContentDuplicates(
|
|
11982
|
+
const clusters = memoryMdPath !== null ? await findContentDuplicates(path20.dirname(memoryMdPath)) : [];
|
|
10224
11983
|
printReport(reports, clusters);
|
|
10225
11984
|
if (opts.fix !== true) return;
|
|
10226
11985
|
const changes = [];
|
|
@@ -10228,7 +11987,7 @@ async function runMemoryCommand(opts = {}) {
|
|
|
10228
11987
|
if (report.exactDupLines.length === 0) continue;
|
|
10229
11988
|
let before;
|
|
10230
11989
|
try {
|
|
10231
|
-
before =
|
|
11990
|
+
before = fs20.readFileSync(report.path, "utf-8");
|
|
10232
11991
|
} catch {
|
|
10233
11992
|
continue;
|
|
10234
11993
|
}
|
|
@@ -10266,33 +12025,33 @@ async function runMemoryCommand(opts = {}) {
|
|
|
10266
12025
|
|
|
10267
12026
|
// src/cli_waste.ts
|
|
10268
12027
|
init_define_import_meta_env();
|
|
10269
|
-
import * as
|
|
10270
|
-
import * as
|
|
12028
|
+
import * as fs22 from "node:fs";
|
|
12029
|
+
import * as path22 from "node:path";
|
|
10271
12030
|
|
|
10272
12031
|
// src/waste.ts
|
|
10273
12032
|
init_define_import_meta_env();
|
|
10274
|
-
import * as
|
|
12033
|
+
import * as fs21 from "node:fs";
|
|
10275
12034
|
import * as os11 from "node:os";
|
|
10276
|
-
import * as
|
|
12035
|
+
import * as path21 from "node:path";
|
|
10277
12036
|
function projectTranscriptsDir(projectRoot) {
|
|
10278
|
-
const rootStr =
|
|
12037
|
+
const rootStr = path21.resolve(projectRoot);
|
|
10279
12038
|
const slug = rootStr.replace(/[^A-Za-z0-9]/g, "-");
|
|
10280
|
-
return
|
|
12039
|
+
return path21.join(os11.homedir(), ".claude", "projects", slug);
|
|
10281
12040
|
}
|
|
10282
12041
|
function findLatestTranscript(projectRoot) {
|
|
10283
12042
|
const dir = projectTranscriptsDir(projectRoot);
|
|
10284
12043
|
let entries;
|
|
10285
12044
|
try {
|
|
10286
|
-
entries =
|
|
12045
|
+
entries = fs21.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
10287
12046
|
} catch {
|
|
10288
12047
|
return null;
|
|
10289
12048
|
}
|
|
10290
12049
|
let best = null;
|
|
10291
12050
|
for (const name of entries) {
|
|
10292
|
-
const full =
|
|
12051
|
+
const full = path21.join(dir, name);
|
|
10293
12052
|
let stat;
|
|
10294
12053
|
try {
|
|
10295
|
-
stat =
|
|
12054
|
+
stat = fs21.statSync(full);
|
|
10296
12055
|
} catch {
|
|
10297
12056
|
continue;
|
|
10298
12057
|
}
|
|
@@ -10349,7 +12108,7 @@ function extractResultText(content) {
|
|
|
10349
12108
|
return "";
|
|
10350
12109
|
}
|
|
10351
12110
|
function parseTranscript2(transcriptPath) {
|
|
10352
|
-
const raw =
|
|
12111
|
+
const raw = fs21.readFileSync(transcriptPath, "utf-8");
|
|
10353
12112
|
const calls = [];
|
|
10354
12113
|
const resultTextById = /* @__PURE__ */ new Map();
|
|
10355
12114
|
const assistantTurns = [];
|
|
@@ -10570,7 +12329,7 @@ function printReport2(report) {
|
|
|
10570
12329
|
}
|
|
10571
12330
|
async function runWasteCommand(opts = {}) {
|
|
10572
12331
|
const projectRoot = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
10573
|
-
const transcriptPath = opts.transcript !== void 0 ?
|
|
12332
|
+
const transcriptPath = opts.transcript !== void 0 ? path22.resolve(opts.transcript) : findLatestTranscript(projectRoot);
|
|
10574
12333
|
if (transcriptPath === null) {
|
|
10575
12334
|
if (opts.json === true) {
|
|
10576
12335
|
process.stdout.write(`${JSON.stringify({ error: "no session transcript found", project: projectRoot })}
|
|
@@ -10584,7 +12343,7 @@ async function runWasteCommand(opts = {}) {
|
|
|
10584
12343
|
process.exitCode = 1;
|
|
10585
12344
|
return;
|
|
10586
12345
|
}
|
|
10587
|
-
if (!
|
|
12346
|
+
if (!fs22.existsSync(transcriptPath)) {
|
|
10588
12347
|
process.stderr.write(`token-goat: transcript not found: ${transcriptPath}
|
|
10589
12348
|
`);
|
|
10590
12349
|
process.exitCode = 1;
|
|
@@ -10601,17 +12360,17 @@ async function runWasteCommand(opts = {}) {
|
|
|
10601
12360
|
|
|
10602
12361
|
// src/session_read.ts
|
|
10603
12362
|
init_define_import_meta_env();
|
|
10604
|
-
import * as
|
|
10605
|
-
import * as
|
|
12363
|
+
import * as fs23 from "node:fs";
|
|
12364
|
+
import * as path23 from "node:path";
|
|
10606
12365
|
import * as readline2 from "node:readline";
|
|
10607
12366
|
function resolveSessionTranscript(arg, opts = {}) {
|
|
10608
12367
|
if (arg !== void 0 && arg !== "") {
|
|
10609
|
-
if (
|
|
12368
|
+
if (fs23.existsSync(arg) && fs23.statSync(arg).isFile()) return arg;
|
|
10610
12369
|
const projectRoot2 = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
10611
12370
|
const dir = projectTranscriptsDir(projectRoot2);
|
|
10612
12371
|
const byId = arg.endsWith(".jsonl") ? arg : `${arg}.jsonl`;
|
|
10613
|
-
const candidate =
|
|
10614
|
-
if (
|
|
12372
|
+
const candidate = path23.join(dir, byId);
|
|
12373
|
+
if (fs23.existsSync(candidate) && fs23.statSync(candidate).isFile()) return candidate;
|
|
10615
12374
|
return null;
|
|
10616
12375
|
}
|
|
10617
12376
|
const projectRoot = resolveProjectRoot(opts.project !== void 0 ? { project: opts.project } : {});
|
|
@@ -10669,7 +12428,7 @@ function toolCallsForBlocks(blocks) {
|
|
|
10669
12428
|
return blocks.filter((b) => b.type === "tool_use" && b.name !== void 0).map((b) => b.name);
|
|
10670
12429
|
}
|
|
10671
12430
|
async function* streamTurns(transcriptPath) {
|
|
10672
|
-
const input =
|
|
12431
|
+
const input = fs23.createReadStream(transcriptPath, { encoding: "utf8" });
|
|
10673
12432
|
const rl = readline2.createInterface({ input, crlfDelay: Infinity });
|
|
10674
12433
|
try {
|
|
10675
12434
|
let lineNumber = 0;
|
|
@@ -10768,15 +12527,15 @@ function formatSessionSlice(turns) {
|
|
|
10768
12527
|
|
|
10769
12528
|
// src/cli_mcp_audit.ts
|
|
10770
12529
|
init_define_import_meta_env();
|
|
10771
|
-
import * as
|
|
10772
|
-
import * as
|
|
12530
|
+
import * as fs24 from "node:fs";
|
|
12531
|
+
import * as path24 from "node:path";
|
|
10773
12532
|
function readMcpConfig(projectRoot) {
|
|
10774
|
-
const configPath2 =
|
|
12533
|
+
const configPath2 = path24.join(projectRoot, ".mcp.json");
|
|
10775
12534
|
try {
|
|
10776
|
-
if (!
|
|
12535
|
+
if (!fs24.existsSync(configPath2)) {
|
|
10777
12536
|
return null;
|
|
10778
12537
|
}
|
|
10779
|
-
const content =
|
|
12538
|
+
const content = fs24.readFileSync(configPath2, "utf-8");
|
|
10780
12539
|
const parsed = JSON.parse(content);
|
|
10781
12540
|
return parsed.mcpServers || parsed;
|
|
10782
12541
|
} catch {
|
|
@@ -10791,8 +12550,9 @@ function analyzeMcpCache() {
|
|
|
10791
12550
|
const entry = value;
|
|
10792
12551
|
const command = typeof entry["command"] === "string" ? entry["command"] : "";
|
|
10793
12552
|
const sizeBytes = typeof entry["sizeBytes"] === "number" ? entry["sizeBytes"] : 0;
|
|
10794
|
-
const toolMatch = command.match(/^mcp:mcp__(
|
|
10795
|
-
|
|
12553
|
+
const toolMatch = command.match(/^mcp:mcp__(.+?)__/i);
|
|
12554
|
+
if (!toolMatch) continue;
|
|
12555
|
+
const toolName = toolMatch[1];
|
|
10796
12556
|
if (!serverMetrics.has(toolName)) {
|
|
10797
12557
|
serverMetrics.set(toolName, { callCount: 0, perCallEstimate: 0, totalBytes: 0 });
|
|
10798
12558
|
}
|
|
@@ -11073,10 +12833,10 @@ function readBoundedText(text, file) {
|
|
|
11073
12833
|
if (text === void 0 && file === void 0) throw new CliError("provide text or --file");
|
|
11074
12834
|
let value;
|
|
11075
12835
|
if (file !== void 0) {
|
|
11076
|
-
if (
|
|
12836
|
+
if (fs25.statSync(file).size > CONTENT_MAX_INPUT_CHARS) {
|
|
11077
12837
|
throw new CliError(`file exceeds the ${CONTENT_MAX_INPUT_CHARS}-byte safety limit`);
|
|
11078
12838
|
}
|
|
11079
|
-
value =
|
|
12839
|
+
value = fs25.readFileSync(file, "utf8");
|
|
11080
12840
|
} else {
|
|
11081
12841
|
if (text === void 0) throw new CliError("provide text or --file");
|
|
11082
12842
|
value = text;
|
|
@@ -11293,7 +13053,7 @@ async function cmdMcpServe() {
|
|
|
11293
13053
|
let StdioServerTransport;
|
|
11294
13054
|
try {
|
|
11295
13055
|
;
|
|
11296
|
-
({ createMcpServer } = await import("./token-goat-hook-chunk-
|
|
13056
|
+
({ createMcpServer } = await import("./token-goat-hook-chunk-K6HLYRRI.mjs"));
|
|
11297
13057
|
({ StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"));
|
|
11298
13058
|
} catch (err2) {
|
|
11299
13059
|
process.stderr.write(
|
|
@@ -11306,14 +13066,15 @@ async function cmdMcpServe() {
|
|
|
11306
13066
|
const server = await createMcpServer();
|
|
11307
13067
|
const transport = new StdioServerTransport();
|
|
11308
13068
|
await server.connect(transport);
|
|
11309
|
-
await new Promise((
|
|
11310
|
-
server.server.onclose =
|
|
13069
|
+
await new Promise((resolve12) => {
|
|
13070
|
+
server.server.onclose = resolve12;
|
|
11311
13071
|
});
|
|
11312
13072
|
}
|
|
11313
13073
|
async function cmdHook(event, opts) {
|
|
11314
13074
|
if (typeof opts.harness === "string" && opts.harness.length > 0) {
|
|
11315
13075
|
process.env[ENV_KEYS.HARNESS_OVERRIDE] = opts.harness;
|
|
11316
13076
|
}
|
|
13077
|
+
const { relay } = await import("./token-goat-hook-chunk-ULGSXGZK.mjs");
|
|
11317
13078
|
await relay(event);
|
|
11318
13079
|
}
|
|
11319
13080
|
async function cmdInstall(opts) {
|
|
@@ -11409,16 +13170,16 @@ async function cmdInstall(opts) {
|
|
|
11409
13170
|
);
|
|
11410
13171
|
}
|
|
11411
13172
|
try {
|
|
11412
|
-
const skillDir =
|
|
11413
|
-
if (
|
|
11414
|
-
const entries =
|
|
13173
|
+
const skillDir = path25.join(homedir11(), ".claude", "skills");
|
|
13174
|
+
if (fs25.existsSync(skillDir)) {
|
|
13175
|
+
const entries = fs25.readdirSync(skillDir, { withFileTypes: true });
|
|
11415
13176
|
const skillNames = [];
|
|
11416
13177
|
const sessionId = getSessionId();
|
|
11417
13178
|
for (const entry of entries) {
|
|
11418
13179
|
if (!entry.isDirectory()) continue;
|
|
11419
|
-
const skillFile =
|
|
11420
|
-
if (
|
|
11421
|
-
const body =
|
|
13180
|
+
const skillFile = path25.join(skillDir, entry.name, "SKILL.md");
|
|
13181
|
+
if (fs25.existsSync(skillFile)) {
|
|
13182
|
+
const body = fs25.readFileSync(skillFile, "utf-8");
|
|
11422
13183
|
const compact = extractCompactFromMarker(body);
|
|
11423
13184
|
if (compact === null) continue;
|
|
11424
13185
|
const sourceSha = contentHash(body);
|
|
@@ -11428,10 +13189,10 @@ async function cmdInstall(opts) {
|
|
|
11428
13189
|
}
|
|
11429
13190
|
if (skillNames.length > 0) {
|
|
11430
13191
|
const dir = skillOutputsDir();
|
|
11431
|
-
await
|
|
11432
|
-
const pregenPath =
|
|
13192
|
+
await fs25.promises.mkdir(dir, { recursive: true });
|
|
13193
|
+
const pregenPath = path25.join(dir, "pregen.json");
|
|
11433
13194
|
const pregenData = { ts: Date.now(), names: skillNames };
|
|
11434
|
-
await
|
|
13195
|
+
await fs25.promises.writeFile(pregenPath, JSON.stringify(pregenData, null, 2));
|
|
11435
13196
|
out(`Pre-generated ${skillNames.length} skill compacts.`);
|
|
11436
13197
|
}
|
|
11437
13198
|
}
|
|
@@ -11472,6 +13233,9 @@ function cmdUninstall(opts) {
|
|
|
11472
13233
|
const removed2 = removal.run();
|
|
11473
13234
|
out(removed2 ? `Removed token-goat ${removal.label}.` : `No token-goat ${removal.label} to remove.`);
|
|
11474
13235
|
}
|
|
13236
|
+
for (const leftover of leftoverIntegrations(opts)) {
|
|
13237
|
+
out(`NOTE: the token-goat ${leftover.label} is still installed. Run "token-goat uninstall ${leftover.flag}" to remove it.`);
|
|
13238
|
+
}
|
|
11475
13239
|
if (opts.vscode === true && otherScopeHasManagedServer({ project: opts.project === true })) {
|
|
11476
13240
|
const otherScope = opts.project === true ? "user" : "project";
|
|
11477
13241
|
out(`NOTE: token-goat is still registered in VS Code ${otherScope} scope. Run "token-goat uninstall --vscode${otherScope === "project" ? " --project" : ""}" to remove it too.`);
|
|
@@ -11479,6 +13243,43 @@ function cmdUninstall(opts) {
|
|
|
11479
13243
|
if (opts.hermes === true) {
|
|
11480
13244
|
out("No separate Hermes integration to remove (it shares the Claude Code hook entries).");
|
|
11481
13245
|
}
|
|
13246
|
+
if (opts.purge === true) runPurge();
|
|
13247
|
+
}
|
|
13248
|
+
function leftoverIntegrations(opts) {
|
|
13249
|
+
const candidates = [
|
|
13250
|
+
{ skipped: opts.codex !== true, present: isCodexInstalled, flag: "--codex", label: "Codex CLI integration" },
|
|
13251
|
+
{ skipped: opts.gemini !== true, present: isGeminiInstalled, flag: "--gemini", label: "Gemini CLI integration" },
|
|
13252
|
+
{ skipped: opts.qwen !== true, present: isQwenInstalled, flag: "--qwen", label: "Qwen Code integration" },
|
|
13253
|
+
{ skipped: opts.pi !== true, present: () => isPiInstalled() || isPiInstalled({ local: true }), flag: "--pi", label: "pi extension" },
|
|
13254
|
+
{ skipped: opts.openclaw !== true, present: isOpenclawInstalled, flag: "--openclaw", label: "OpenClaw integration" },
|
|
13255
|
+
{
|
|
13256
|
+
skipped: opts.copilot !== true,
|
|
13257
|
+
present: () => isCopilotCliInstalled() || isCopilotCliInstalled({ local: true }),
|
|
13258
|
+
flag: "--copilot",
|
|
13259
|
+
label: "Copilot CLI integration"
|
|
13260
|
+
},
|
|
13261
|
+
{ skipped: opts.opencode !== true, present: isOpencodeInstalled, flag: "--opencode", label: "opencode plugin" },
|
|
13262
|
+
{ skipped: opts.grok !== true, present: isGrokInstalled, flag: "--grok", label: "Grok CLI integration" }
|
|
13263
|
+
];
|
|
13264
|
+
const found = [];
|
|
13265
|
+
for (const candidate of candidates) {
|
|
13266
|
+
if (!candidate.skipped) continue;
|
|
13267
|
+
try {
|
|
13268
|
+
if (candidate.present()) found.push({ flag: candidate.flag, label: candidate.label });
|
|
13269
|
+
} catch {
|
|
13270
|
+
}
|
|
13271
|
+
}
|
|
13272
|
+
return found;
|
|
13273
|
+
}
|
|
13274
|
+
function runPurge() {
|
|
13275
|
+
if (isWorkerRunning()) {
|
|
13276
|
+
err('token-goat: the background worker is running, so --purge would delete files it is about to rewrite. Run "token-goat worker stop" first.');
|
|
13277
|
+
return;
|
|
13278
|
+
}
|
|
13279
|
+
const result = purgeDataDirectories();
|
|
13280
|
+
for (const root of result.absent) out(`Nothing to purge at ${root}.`);
|
|
13281
|
+
for (const removed of result.removed) out(`Purged ${removed.path} (${formatBytes(removed.bytes)} reclaimed).`);
|
|
13282
|
+
for (const failure of result.failed) err(`token-goat: could not purge ${failure.path}: ${failure.reason}`);
|
|
11482
13283
|
}
|
|
11483
13284
|
function cmdWorkerStart() {
|
|
11484
13285
|
if (isWorkerRunning()) {
|
|
@@ -11583,7 +13384,7 @@ ${formatSessionOutline(turns)}`;
|
|
|
11583
13384
|
}
|
|
11584
13385
|
function sessionTranscriptSize(transcriptPath) {
|
|
11585
13386
|
try {
|
|
11586
|
-
return
|
|
13387
|
+
return fs25.statSync(transcriptPath).size;
|
|
11587
13388
|
} catch {
|
|
11588
13389
|
return 0;
|
|
11589
13390
|
}
|
|
@@ -11640,7 +13441,27 @@ function cmdHintStats(opts = {}) {
|
|
|
11640
13441
|
...opts.markIneffective !== void 0 && isHintCategory(opts.markIneffective) ? { markIneffective: opts.markIneffective } : {}
|
|
11641
13442
|
});
|
|
11642
13443
|
}
|
|
11643
|
-
function _applyFiltersAndPrint(content, opts) {
|
|
13444
|
+
function _applyFiltersAndPrint(content, opts, fenceUntrusted = false, fenceTag = UNTRUSTED_WEB_TAG) {
|
|
13445
|
+
const emit2 = (text) => {
|
|
13446
|
+
if (!fenceUntrusted || text === "") {
|
|
13447
|
+
out(text);
|
|
13448
|
+
return text;
|
|
13449
|
+
}
|
|
13450
|
+
let matches2 = [];
|
|
13451
|
+
try {
|
|
13452
|
+
if (loadConfig().injection.enabled) matches2 = scanForInjectionPatterns(text);
|
|
13453
|
+
} catch {
|
|
13454
|
+
matches2 = [];
|
|
13455
|
+
}
|
|
13456
|
+
if (matches2.length === 0) {
|
|
13457
|
+
out(text);
|
|
13458
|
+
return text;
|
|
13459
|
+
}
|
|
13460
|
+
recordStat("injection_detected", 0, 0, void 0, matches2.join(","));
|
|
13461
|
+
const fenced = fenceUntrustedContent(text, matches2, fenceTag);
|
|
13462
|
+
out(fenced);
|
|
13463
|
+
return fenced;
|
|
13464
|
+
};
|
|
11644
13465
|
if (opts.section !== void 0) {
|
|
11645
13466
|
const sectionResult = extractSection(content, opts.section);
|
|
11646
13467
|
if (sectionResult === null) {
|
|
@@ -11669,9 +13490,7 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
11669
13490
|
}
|
|
11670
13491
|
const lines = content.split(/\r?\n/);
|
|
11671
13492
|
if (opts.full === true) {
|
|
11672
|
-
|
|
11673
|
-
out(printedFull);
|
|
11674
|
-
return printedFull;
|
|
13493
|
+
return emit2(lines.join("\n"));
|
|
11675
13494
|
}
|
|
11676
13495
|
const headN = opts.head !== void 0 ? requireNonNegativeInt("--head", opts.head) : 30;
|
|
11677
13496
|
const tailN = opts.tail !== void 0 ? requireNonNegativeInt("--tail", opts.tail) : 80;
|
|
@@ -11686,13 +13505,11 @@ function _applyFiltersAndPrint(content, opts) {
|
|
|
11686
13505
|
} else if (opts.tail !== void 0) {
|
|
11687
13506
|
result = lines.slice(Math.max(0, lines.length - tailN));
|
|
11688
13507
|
}
|
|
11689
|
-
|
|
11690
|
-
out(printed);
|
|
11691
|
-
return printed;
|
|
13508
|
+
return emit2(result.join("\n"));
|
|
11692
13509
|
}
|
|
11693
13510
|
function fileSizeOrZero(filePath) {
|
|
11694
13511
|
try {
|
|
11695
|
-
return
|
|
13512
|
+
return fs25.statSync(filePath).size;
|
|
11696
13513
|
} catch {
|
|
11697
13514
|
return 0;
|
|
11698
13515
|
}
|
|
@@ -11707,16 +13524,16 @@ function cmdBashOutput(id, opts) {
|
|
|
11707
13524
|
}
|
|
11708
13525
|
let content;
|
|
11709
13526
|
try {
|
|
11710
|
-
const st =
|
|
13527
|
+
const st = fs25.statSync(opts.file);
|
|
11711
13528
|
if (st.isFIFO() || st.isSocket()) {
|
|
11712
13529
|
throw new CliError(`--file '${opts.file}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
11713
13530
|
}
|
|
11714
|
-
content =
|
|
13531
|
+
content = fs25.readFileSync(opts.file, "utf-8");
|
|
11715
13532
|
} catch (e) {
|
|
11716
13533
|
if (e instanceof CliError) throw e;
|
|
11717
13534
|
throw new CliError(`cannot read file: ${opts.file}`);
|
|
11718
13535
|
}
|
|
11719
|
-
_applyFiltersAndPrint(opts.transcript === true ? extractTranscriptText(content) : content, opts);
|
|
13536
|
+
_applyFiltersAndPrint(opts.transcript === true ? extractTranscriptText(content) : content, opts, true, UNTRUSTED_TOOL_TAG);
|
|
11720
13537
|
return;
|
|
11721
13538
|
}
|
|
11722
13539
|
if (id === void 0) {
|
|
@@ -11726,7 +13543,7 @@ function cmdBashOutput(id, opts) {
|
|
|
11726
13543
|
if (entry === null) {
|
|
11727
13544
|
throw new CliError(`no cached bash output for id: ${id}. If this id is from a background task, recall its output file directly with: token-goat bash-output --file <path-to-output-file>`);
|
|
11728
13545
|
}
|
|
11729
|
-
_applyFiltersAndPrint(entry.output, opts);
|
|
13546
|
+
_applyFiltersAndPrint(entry.output, opts, true, UNTRUSTED_TOOL_TAG);
|
|
11730
13547
|
}
|
|
11731
13548
|
function cmdWebOutput(id, opts) {
|
|
11732
13549
|
if (id === void 0) {
|
|
@@ -11736,7 +13553,7 @@ function cmdWebOutput(id, opts) {
|
|
|
11736
13553
|
if (content === null) {
|
|
11737
13554
|
throw new CliError(`no cached web output for id: ${id}. The cache may have expired; re-run the WebFetch to repopulate it.`);
|
|
11738
13555
|
}
|
|
11739
|
-
_applyFiltersAndPrint(content, opts);
|
|
13556
|
+
_applyFiltersAndPrint(content, opts, true);
|
|
11740
13557
|
}
|
|
11741
13558
|
function cmdMcpOutput(id, opts) {
|
|
11742
13559
|
if (id === void 0) {
|
|
@@ -11749,7 +13566,7 @@ function cmdMcpOutput(id, opts) {
|
|
|
11749
13566
|
if (entry === null) {
|
|
11750
13567
|
throw new CliError(`no cached mcp output for id: ${id}. The cache may have expired; re-run the MCP tool call to repopulate it.`);
|
|
11751
13568
|
}
|
|
11752
|
-
_applyFiltersAndPrint(entry.output, opts);
|
|
13569
|
+
_applyFiltersAndPrint(entry.output, opts, true, UNTRUSTED_TOOL_TAG);
|
|
11753
13570
|
}
|
|
11754
13571
|
async function cmdPdfExtract(file, opts) {
|
|
11755
13572
|
const text = await runPdfExtractText(file, opts.pages, opts.layout === true);
|
|
@@ -12092,16 +13909,17 @@ function emitExtraFileArgsNote(command, first, extras, opts = {}) {
|
|
|
12092
13909
|
if (extras === void 0 || extras.length === 0) return;
|
|
12093
13910
|
out(extraFileArgsNote(command, first, extras, opts));
|
|
12094
13911
|
}
|
|
12095
|
-
function cmdCompress(opts) {
|
|
13912
|
+
async function cmdCompress(opts) {
|
|
12096
13913
|
try {
|
|
13914
|
+
const bashRunner = await import("./token-goat-hook-chunk-3OJELLK5.mjs");
|
|
12097
13915
|
if (opts.compress === false) {
|
|
12098
|
-
process.exitCode = runRaw(opts.cmd, parseTimeout(opts.timeout));
|
|
13916
|
+
process.exitCode = bashRunner.runRaw(opts.cmd, parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS));
|
|
12099
13917
|
return;
|
|
12100
13918
|
}
|
|
12101
13919
|
const maxTokens = opts.maxTokens !== void 0 ? requireNonNegativeInt("--max-tokens", opts.maxTokens) : 0;
|
|
12102
|
-
process.exitCode = run(opts.cmd, {
|
|
13920
|
+
process.exitCode = bashRunner.run(opts.cmd, {
|
|
12103
13921
|
filterName: opts.filter,
|
|
12104
|
-
timeout: parseTimeout(opts.timeout),
|
|
13922
|
+
timeout: parseTimeout(opts.timeout, bashRunner.DEFAULT_TIMEOUT_SECONDS),
|
|
12105
13923
|
maxTokens,
|
|
12106
13924
|
...opts.profile !== void 0 ? { compressionProfile: opts.profile } : {}
|
|
12107
13925
|
});
|
|
@@ -12110,16 +13928,16 @@ function cmdCompress(opts) {
|
|
|
12110
13928
|
process.exitCode = 1;
|
|
12111
13929
|
}
|
|
12112
13930
|
}
|
|
12113
|
-
function parseTimeout(raw) {
|
|
13931
|
+
function parseTimeout(raw, fallbackSeconds) {
|
|
12114
13932
|
const sec = raw ? parseInt(raw, 10) : 0;
|
|
12115
|
-
return Number.isFinite(sec) && sec > 0 ? sec :
|
|
13933
|
+
return Number.isFinite(sec) && sec > 0 ? sec : fallbackSeconds;
|
|
12116
13934
|
}
|
|
12117
13935
|
async function cmdSkillBody(name, opts) {
|
|
12118
13936
|
const filePath = await getSkillFilePath(name);
|
|
12119
13937
|
if (filePath === null) {
|
|
12120
13938
|
throw new CliError(`skill '${name}' not found`);
|
|
12121
13939
|
}
|
|
12122
|
-
const body =
|
|
13940
|
+
const body = fs25.readFileSync(filePath, "utf-8");
|
|
12123
13941
|
if (opts.compact === true) {
|
|
12124
13942
|
out(extractCompactFromMarker(body) ?? body);
|
|
12125
13943
|
} else {
|
|
@@ -12136,7 +13954,7 @@ async function cmdSkillCompact(name, opts) {
|
|
|
12136
13954
|
for (const skill of skills) {
|
|
12137
13955
|
const filePath = await getSkillFilePath(skill.name);
|
|
12138
13956
|
if (!filePath) continue;
|
|
12139
|
-
const body2 =
|
|
13957
|
+
const body2 = fs25.readFileSync(filePath, "utf-8");
|
|
12140
13958
|
const compact2 = extractCompactFromMarker(body2);
|
|
12141
13959
|
if (compact2 === null) continue;
|
|
12142
13960
|
const sourceSha2 = contentHash(body2);
|
|
@@ -12157,19 +13975,19 @@ async function cmdSkillCompact(name, opts) {
|
|
|
12157
13975
|
if (!opts.path.trim()) {
|
|
12158
13976
|
throw new CliError("--path cannot be empty");
|
|
12159
13977
|
}
|
|
12160
|
-
if (!
|
|
13978
|
+
if (!fs25.existsSync(opts.path)) {
|
|
12161
13979
|
throw new CliError(`skill file not found: ${opts.path}`);
|
|
12162
13980
|
}
|
|
12163
13981
|
try {
|
|
12164
|
-
body =
|
|
13982
|
+
body = fs25.readFileSync(opts.path, "utf-8");
|
|
12165
13983
|
} catch (e) {
|
|
12166
13984
|
if (e.code === "ENOENT") {
|
|
12167
13985
|
throw new CliError(`skill file not found: ${opts.path}`);
|
|
12168
13986
|
}
|
|
12169
13987
|
throw new CliError(`failed to read skill file '${opts.path}': ${extractErrorMessage(e)}`);
|
|
12170
13988
|
}
|
|
12171
|
-
cacheName = name ??
|
|
12172
|
-
sourcePath =
|
|
13989
|
+
cacheName = name ?? path25.basename(path25.dirname(path25.resolve(opts.path)));
|
|
13990
|
+
sourcePath = path25.resolve(opts.path);
|
|
12173
13991
|
} else {
|
|
12174
13992
|
if (name === void 0 || !name.trim()) {
|
|
12175
13993
|
throw new CliError("skill-compact requires a <name> or --path <file>");
|
|
@@ -12178,7 +13996,7 @@ async function cmdSkillCompact(name, opts) {
|
|
|
12178
13996
|
if (filePath === null) {
|
|
12179
13997
|
throw new CliError(`skill '${name}' not found`);
|
|
12180
13998
|
}
|
|
12181
|
-
body =
|
|
13999
|
+
body = fs25.readFileSync(filePath, "utf-8");
|
|
12182
14000
|
cacheName = name;
|
|
12183
14001
|
sourcePath = filePath;
|
|
12184
14002
|
}
|
|
@@ -12310,8 +14128,8 @@ async function cmdSkillDiff(name) {
|
|
|
12310
14128
|
}
|
|
12311
14129
|
const newer = versions[0];
|
|
12312
14130
|
const older = versions[1];
|
|
12313
|
-
const newerBody = await
|
|
12314
|
-
const olderBody = await
|
|
14131
|
+
const newerBody = await fs25.promises.readFile(path25.resolve(dir, `${newer.outputId}.txt`), "utf-8").catch(() => null);
|
|
14132
|
+
const olderBody = await fs25.promises.readFile(path25.resolve(dir, `${older.outputId}.txt`), "utf-8").catch(() => null);
|
|
12315
14133
|
if (newerBody === null || olderBody === null) {
|
|
12316
14134
|
out(`a cached version of '${name}' was evicted while diffing -- try again`);
|
|
12317
14135
|
return;
|
|
@@ -12340,7 +14158,7 @@ async function cmdSkillSection(nameHeading, headingArg) {
|
|
|
12340
14158
|
if (!filePath) {
|
|
12341
14159
|
throw new CliError(`skill '${skillName}' not found`);
|
|
12342
14160
|
}
|
|
12343
|
-
const body =
|
|
14161
|
+
const body = fs25.readFileSync(filePath, "utf-8");
|
|
12344
14162
|
const extracted = extractNamedSection(body, heading);
|
|
12345
14163
|
if (!extracted) {
|
|
12346
14164
|
process.exitCode = 1;
|
|
@@ -12350,7 +14168,7 @@ async function cmdSkillSection(nameHeading, headingArg) {
|
|
|
12350
14168
|
}
|
|
12351
14169
|
function atomicWriteBuffer(dest, data) {
|
|
12352
14170
|
try {
|
|
12353
|
-
if (
|
|
14171
|
+
if (fs25.statSync(dest).isDirectory()) {
|
|
12354
14172
|
const e = Object.assign(new Error(`EISDIR: illegal operation on a directory, open '${dest}'`), { code: "EISDIR", path: dest });
|
|
12355
14173
|
throw e;
|
|
12356
14174
|
}
|
|
@@ -12358,23 +14176,23 @@ function atomicWriteBuffer(dest, data) {
|
|
|
12358
14176
|
if (e.code !== "ENOENT") throw e;
|
|
12359
14177
|
}
|
|
12360
14178
|
const rnd = Math.random().toString(36).slice(2, 8);
|
|
12361
|
-
const tmp =
|
|
14179
|
+
const tmp = path25.join(path25.dirname(path25.resolve(dest)), `.tmp.${process.pid}.${rnd}`);
|
|
12362
14180
|
try {
|
|
12363
|
-
|
|
14181
|
+
fs25.writeFileSync(tmp, data, { mode: 384 });
|
|
12364
14182
|
try {
|
|
12365
|
-
const destMode =
|
|
12366
|
-
|
|
14183
|
+
const destMode = fs25.statSync(dest).mode;
|
|
14184
|
+
fs25.chmodSync(tmp, destMode);
|
|
12367
14185
|
} catch (e) {
|
|
12368
14186
|
if (e.code !== "ENOENT") throw e;
|
|
12369
14187
|
}
|
|
12370
14188
|
withRetryOnLock(() => {
|
|
12371
14189
|
try {
|
|
12372
|
-
|
|
14190
|
+
fs25.renameSync(tmp, dest);
|
|
12373
14191
|
} catch (e) {
|
|
12374
14192
|
if (e.code === "EXDEV") {
|
|
12375
|
-
|
|
14193
|
+
fs25.copyFileSync(tmp, dest);
|
|
12376
14194
|
try {
|
|
12377
|
-
|
|
14195
|
+
fs25.unlinkSync(tmp);
|
|
12378
14196
|
} catch (ue) {
|
|
12379
14197
|
process.stderr.write(`token-goat write-file: warning: could not remove temp file ${tmp}: ${ue.message}
|
|
12380
14198
|
`);
|
|
@@ -12386,7 +14204,7 @@ function atomicWriteBuffer(dest, data) {
|
|
|
12386
14204
|
});
|
|
12387
14205
|
} catch (e) {
|
|
12388
14206
|
try {
|
|
12389
|
-
|
|
14207
|
+
fs25.unlinkSync(tmp);
|
|
12390
14208
|
} catch {
|
|
12391
14209
|
}
|
|
12392
14210
|
throw e;
|
|
@@ -12396,9 +14214,9 @@ function mapFsError(e, src, dest, srcLabel = "source") {
|
|
|
12396
14214
|
const fe = e;
|
|
12397
14215
|
if (fe.code === "ENOENT") {
|
|
12398
14216
|
const errPath = fe.path ?? "";
|
|
12399
|
-
const isSource = src !== void 0 &&
|
|
14217
|
+
const isSource = src !== void 0 && path25.resolve(errPath) === path25.resolve(src);
|
|
12400
14218
|
if (isSource) throw new CliError(`${srcLabel} file not found: ${src}`);
|
|
12401
|
-
const destDir = dest ?
|
|
14219
|
+
const destDir = dest ? path25.dirname(path25.resolve(dest)) : path25.dirname(path25.resolve(errPath || "."));
|
|
12402
14220
|
throw new CliError(`destination directory does not exist: ${destDir}`);
|
|
12403
14221
|
}
|
|
12404
14222
|
if (fe.code === "ENOTDIR") {
|
|
@@ -12409,7 +14227,7 @@ function mapFsError(e, src, dest, srcLabel = "source") {
|
|
|
12409
14227
|
}
|
|
12410
14228
|
if (fe.code === "EISDIR") {
|
|
12411
14229
|
const errPath = fe.path ?? "";
|
|
12412
|
-
const isSource = src !== void 0 && (errPath === "" ||
|
|
14230
|
+
const isSource = src !== void 0 && (errPath === "" || path25.resolve(errPath) === path25.resolve(src));
|
|
12413
14231
|
if (isSource) throw new CliError(`source is a directory, not a file: ${src}`);
|
|
12414
14232
|
throw new CliError(`destination is a directory, not a file: ${dest ?? (errPath || "(unknown)")}`);
|
|
12415
14233
|
}
|
|
@@ -12478,7 +14296,7 @@ function validateWritablePath(dest, label) {
|
|
|
12478
14296
|
throw new CliError(`${label} path contains a null byte`);
|
|
12479
14297
|
}
|
|
12480
14298
|
if (isWindows()) {
|
|
12481
|
-
const base =
|
|
14299
|
+
const base = path25.basename(dest);
|
|
12482
14300
|
const stem = base.replace(/\.[^.]*$/, "").toUpperCase();
|
|
12483
14301
|
if (WIN_RESERVED.has(stem)) {
|
|
12484
14302
|
throw new CliError(`${label} '${base}' is a reserved Windows device name`);
|
|
@@ -12508,7 +14326,7 @@ function readFileBoundedRaw(filePath, label, allowStdIn = false) {
|
|
|
12508
14326
|
throw new CliError(`${label} ${filePath} requires piped input; use ${altLabel} for interactive use`);
|
|
12509
14327
|
}
|
|
12510
14328
|
try {
|
|
12511
|
-
const st =
|
|
14329
|
+
const st = fs25.statSync(filePath);
|
|
12512
14330
|
if (st.isFIFO() || st.isSocket()) {
|
|
12513
14331
|
throw new CliError(`${label} '${filePath}' is a special file (FIFO or socket) \u2014 only regular files are supported`);
|
|
12514
14332
|
}
|
|
@@ -12516,7 +14334,7 @@ function readFileBoundedRaw(filePath, label, allowStdIn = false) {
|
|
|
12516
14334
|
if (st.size > maxBytes) {
|
|
12517
14335
|
throw new CliError(`${label} '${filePath}' exceeds size limit (${Math.round(st.size / 1024 / 1024)} MB); set TOKEN_GOAT_MAX_STDIN_MB to override`);
|
|
12518
14336
|
}
|
|
12519
|
-
return
|
|
14337
|
+
return fs25.readFileSync(filePath);
|
|
12520
14338
|
} catch (e) {
|
|
12521
14339
|
if (e instanceof CliError) throw e;
|
|
12522
14340
|
mapFsError(e, filePath, void 0, label);
|
|
@@ -12560,7 +14378,7 @@ function cmdNoteAdd(file, opts) {
|
|
|
12560
14378
|
throw new CliError("note content must be valid UTF-8 text");
|
|
12561
14379
|
}
|
|
12562
14380
|
const resolvedPath = resolveIndexPath(file);
|
|
12563
|
-
if (!
|
|
14381
|
+
if (!fs25.existsSync(resolvedPath)) {
|
|
12564
14382
|
throw new CliError(`File not found: '${resolvedPath}'`);
|
|
12565
14383
|
}
|
|
12566
14384
|
healStaleIndex(resolvedPath);
|
|
@@ -12619,7 +14437,7 @@ function cmdWriteFile(dest, opts) {
|
|
|
12619
14437
|
throw new CliError(`TOKEN_GOAT_MAX_STDIN_MB must be a positive integer; got '${process.env["TOKEN_GOAT_MAX_STDIN_MB"] ?? ""}'`);
|
|
12620
14438
|
}
|
|
12621
14439
|
const maxBytes = maxMB * 1024 * 1024;
|
|
12622
|
-
return new Promise((
|
|
14440
|
+
return new Promise((resolve12, reject) => {
|
|
12623
14441
|
const chunks = [];
|
|
12624
14442
|
let totalBytes = 0;
|
|
12625
14443
|
let settled = false;
|
|
@@ -12643,7 +14461,7 @@ function cmdWriteFile(dest, opts) {
|
|
|
12643
14461
|
try {
|
|
12644
14462
|
atomicWriteBuffer(dest, Buffer.concat(chunks));
|
|
12645
14463
|
enqueueDirtyPathSafe(dest);
|
|
12646
|
-
|
|
14464
|
+
resolve12();
|
|
12647
14465
|
} catch (e) {
|
|
12648
14466
|
try {
|
|
12649
14467
|
mapFsError(e, void 0, dest);
|
|
@@ -12775,7 +14593,7 @@ function writeReplacedBuffer(file, replacedBuf, preWriteStat) {
|
|
|
12775
14593
|
}
|
|
12776
14594
|
let preRenameStat;
|
|
12777
14595
|
try {
|
|
12778
|
-
preRenameStat =
|
|
14596
|
+
preRenameStat = fs25.statSync(file);
|
|
12779
14597
|
} catch {
|
|
12780
14598
|
}
|
|
12781
14599
|
if (preRenameStat !== void 0 && (preRenameStat.mtimeMs !== preWriteStat.mtimeMs || preRenameStat.size !== preWriteStat.size)) {
|
|
@@ -12816,7 +14634,7 @@ function cmdReplace(file, opts) {
|
|
|
12816
14634
|
const targetBuf = readFileBoundedRaw(file, "target file", true);
|
|
12817
14635
|
let preWriteStat;
|
|
12818
14636
|
try {
|
|
12819
|
-
preWriteStat =
|
|
14637
|
+
preWriteStat = fs25.statSync(file);
|
|
12820
14638
|
} catch {
|
|
12821
14639
|
}
|
|
12822
14640
|
const usingFrom = opts.oldFrom !== void 0 || opts.newFrom !== void 0;
|
|
@@ -12910,7 +14728,7 @@ function cmdInsertSection(file, opts) {
|
|
|
12910
14728
|
}
|
|
12911
14729
|
let preWriteStat;
|
|
12912
14730
|
try {
|
|
12913
|
-
preWriteStat =
|
|
14731
|
+
preWriteStat = fs25.statSync(file);
|
|
12914
14732
|
} catch {
|
|
12915
14733
|
}
|
|
12916
14734
|
const result = readSection(file, opts.after);
|
|
@@ -12924,7 +14742,7 @@ function cmdInsertSection(file, opts) {
|
|
|
12924
14742
|
}
|
|
12925
14743
|
let rawText;
|
|
12926
14744
|
try {
|
|
12927
|
-
rawText =
|
|
14745
|
+
rawText = fs25.readFileSync(file, "utf-8");
|
|
12928
14746
|
} catch (e) {
|
|
12929
14747
|
mapFsError(e, void 0, file);
|
|
12930
14748
|
}
|
|
@@ -12939,7 +14757,7 @@ function cmdInsertSection(file, opts) {
|
|
|
12939
14757
|
if (preWriteStat !== void 0) {
|
|
12940
14758
|
let preRenameStat;
|
|
12941
14759
|
try {
|
|
12942
|
-
preRenameStat =
|
|
14760
|
+
preRenameStat = fs25.statSync(file);
|
|
12943
14761
|
} catch {
|
|
12944
14762
|
}
|
|
12945
14763
|
if (preRenameStat !== void 0 && (preRenameStat.mtimeMs !== preWriteStat.mtimeMs || preRenameStat.size !== preWriteStat.size)) {
|
|
@@ -12956,6 +14774,9 @@ function cmdInsertSection(file, opts) {
|
|
|
12956
14774
|
out(`inserted after '${result.heading}'${redirectNote} in ${file}`);
|
|
12957
14775
|
}
|
|
12958
14776
|
async function cmdGdriveSections(fileId, opts) {
|
|
14777
|
+
if (!loadConfig().gdrive.enabled) {
|
|
14778
|
+
throw new CliError("gdrive-sections is disabled by gdrive.enabled = false in this install");
|
|
14779
|
+
}
|
|
12959
14780
|
const fetchOpts = { fresh: opts.fresh === true };
|
|
12960
14781
|
const text = await fetchDoc(fileId, fetchOpts);
|
|
12961
14782
|
const fullSourceBytes = Buffer.byteLength(text, "utf8");
|
|
@@ -12977,25 +14798,25 @@ ${content}`;
|
|
|
12977
14798
|
}
|
|
12978
14799
|
function expandGlobs(root, patterns, globFnOverride) {
|
|
12979
14800
|
const out2 = [];
|
|
12980
|
-
const globFn = globFnOverride ??
|
|
14801
|
+
const globFn = globFnOverride ?? fs25["globSync"];
|
|
12981
14802
|
for (const p of patterns) {
|
|
12982
14803
|
if (globFn !== void 0 && (p.includes("*") || p.includes("?") || p.includes("{"))) {
|
|
12983
14804
|
try {
|
|
12984
14805
|
const hits = globFn(p, { cwd: root });
|
|
12985
|
-
for (const h of hits) out2.push(
|
|
14806
|
+
for (const h of hits) out2.push(path25.isAbsolute(h) ? h : path25.join(root, h));
|
|
12986
14807
|
continue;
|
|
12987
14808
|
} catch {
|
|
12988
14809
|
}
|
|
12989
14810
|
}
|
|
12990
|
-
out2.push(
|
|
14811
|
+
out2.push(path25.isAbsolute(p) ? p : path25.join(root, p));
|
|
12991
14812
|
}
|
|
12992
14813
|
return out2;
|
|
12993
14814
|
}
|
|
12994
14815
|
function readIgnoreFile(root) {
|
|
12995
|
-
const ignorePath =
|
|
14816
|
+
const ignorePath = path25.join(root, ".tokengoatignore");
|
|
12996
14817
|
let raw;
|
|
12997
14818
|
try {
|
|
12998
|
-
raw =
|
|
14819
|
+
raw = fs25.readFileSync(ignorePath, "utf8");
|
|
12999
14820
|
} catch {
|
|
13000
14821
|
return void 0;
|
|
13001
14822
|
}
|
|
@@ -13036,14 +14857,14 @@ function cmdPack(patterns, opts) {
|
|
|
13036
14857
|
}
|
|
13037
14858
|
let instruction;
|
|
13038
14859
|
if (opts.instructionFile !== void 0) {
|
|
13039
|
-
instruction =
|
|
14860
|
+
instruction = fs25.readFileSync(opts.instructionFile, "utf8");
|
|
13040
14861
|
}
|
|
13041
14862
|
const formatted = formatPack(result, style, {
|
|
13042
14863
|
...opts.lineNumbers === true ? { line_numbers: true } : {},
|
|
13043
14864
|
...instruction !== void 0 ? { instruction } : {}
|
|
13044
14865
|
});
|
|
13045
14866
|
if (opts.output !== void 0) {
|
|
13046
|
-
|
|
14867
|
+
fs25.writeFileSync(opts.output, formatted, "utf8");
|
|
13047
14868
|
} else {
|
|
13048
14869
|
out(formatted);
|
|
13049
14870
|
}
|
|
@@ -13061,7 +14882,7 @@ function cmdTokens(patterns, opts) {
|
|
|
13061
14882
|
if (opts.tree === true) {
|
|
13062
14883
|
const dirs = /* @__PURE__ */ new Map();
|
|
13063
14884
|
for (const e of entries) {
|
|
13064
|
-
const dir =
|
|
14885
|
+
const dir = path25.dirname(e.rel_path);
|
|
13065
14886
|
if (!dirs.has(dir)) dirs.set(dir, []);
|
|
13066
14887
|
dirs.get(dir).push(e);
|
|
13067
14888
|
}
|
|
@@ -13071,7 +14892,7 @@ function cmdTokens(patterns, opts) {
|
|
|
13071
14892
|
const pct = result.total_tokens > 0 ? Math.round(dirTokens / result.total_tokens * 100) : 0;
|
|
13072
14893
|
lines2.push(`${dir}/ (${dirTokens} tokens, ${pct}%)`);
|
|
13073
14894
|
for (const e of dirEntries) {
|
|
13074
|
-
lines2.push(` ${
|
|
14895
|
+
lines2.push(` ${path25.basename(e.rel_path).padEnd(30)} ${String(e.tokens).padStart(8)} tokens`);
|
|
13075
14896
|
}
|
|
13076
14897
|
}
|
|
13077
14898
|
out(lines2.join("\n"));
|
|
@@ -13102,7 +14923,7 @@ function cmdBudget(patterns, opts) {
|
|
|
13102
14923
|
}
|
|
13103
14924
|
}
|
|
13104
14925
|
function cmdFailures(src, opts) {
|
|
13105
|
-
const text = src !== void 0 ?
|
|
14926
|
+
const text = src !== void 0 ? fs25.readFileSync(src, "utf8") : fs25.readFileSync(0, "utf8");
|
|
13106
14927
|
const result = extractFailures(text, opts.runner !== void 0 ? { runner: opts.runner } : {});
|
|
13107
14928
|
if (opts.delta !== true) {
|
|
13108
14929
|
out(opts.json === true ? formatFailuresJson(result) : formatFailuresText(result));
|
|
@@ -13143,6 +14964,12 @@ function buildProgram() {
|
|
|
13143
14964
|
if (projectParseErr !== null) {
|
|
13144
14965
|
err(`token-goat: .token-goat.toml failed to parse (${projectParseErr}); ignoring project override`);
|
|
13145
14966
|
}
|
|
14967
|
+
const lockedKeys = lastProjectConfigLockedKeys();
|
|
14968
|
+
if (lockedKeys.length > 0) {
|
|
14969
|
+
err(
|
|
14970
|
+
`token-goat: .token-goat.toml may not set ${lockedKeys.join(", ")}; these are security settings and come from the global config or the environment only`
|
|
14971
|
+
);
|
|
14972
|
+
}
|
|
13146
14973
|
try {
|
|
13147
14974
|
await fn(...args);
|
|
13148
14975
|
if (process.exitCode === void 0) {
|
|
@@ -13289,7 +15116,7 @@ function buildProgram() {
|
|
|
13289
15116
|
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));
|
|
13290
15117
|
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));
|
|
13291
15118
|
program2.command("install").description("install hooks into Claude Code settings").option("-p, --project", "install into project scope instead of user scope").option("--codex", "also patch Codex CLI (~/.codex/config.toml, ~/.codex/AGENTS.md)").option("--gemini", "also patch Gemini CLI (~/.gemini/settings.json)").option("--qwen", "also patch Qwen Code (~/.qwen/settings.json)").option("--pi", "also drop a pi (pi-coding-agent) extension (~/.pi/agent/extensions/token-goat.ts)").option("--opencode", "also 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", "also register an OpenClaw plugin (~/.openclaw/openclaw.json, ~/.openclaw/plugins/token-goat.ts)").option("--copilot", "also register a Copilot CLI hook config and routing block (~/.copilot/hooks/token-goat.json, ~/.copilot/hooks/token-goat-shim.js, ~/.copilot/copilot-instructions.md; with --local, <project>/.github/hooks/token-goat.json, <project>/.github/hooks/token-goat-shim.js, <project>/.github/copilot-instructions.md)").option("--grok", "also register a Grok CLI (xAI Grok Build) hook config (~/.grok/hooks/token-goat.json, ~/.grok/hooks/token-goat-shim.js)").option("--vscode", "also configure a VS Code MCP server (user-profile mcp.json by default; -p/--project for the workspace .vscode/mcp.json) and Copilot routing guidance").option("--local", "with --pi, install the project-local extension (<project>/.pi/extensions/token-goat.ts) instead of the global one").action(guard(cmdInstall));
|
|
13292
|
-
program2.command("uninstall").description("remove token-goat hooks from Claude Code settings").option("-p, --project", "uninstall from project scope instead of user scope").option("--codex", "also strip the Codex CLI integration (~/.codex/config.toml, ~/.codex/AGENTS.md)").option("--gemini", "also strip the Gemini CLI integration (~/.gemini/settings.json)").option("--qwen", "also strip the Qwen Code integration (~/.qwen/settings.json)").option("--pi", "also remove the pi (pi-coding-agent) extension").option("--opencode", "also remove the opencode plugin").option("--hermes", "no-op verification flag for symmetry with install (removes no files)").option("--openclaw", "also remove the OpenClaw plugin and config entry").option("--copilot", "also 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", "also remove the Grok CLI hook config and shim script").option("--vscode", "also remove the VS Code MCP server (user scope by default; -p/--project for the workspace one) and routing guidance").option("--local", "with --pi, remove the project-local extension instead of the global one").action(guard(cmdUninstall));
|
|
15119
|
+
program2.command("uninstall").description("remove token-goat hooks from Claude Code settings").option("-p, --project", "uninstall from project scope instead of user scope").option("--codex", "also strip the Codex CLI integration (~/.codex/config.toml, ~/.codex/AGENTS.md)").option("--gemini", "also strip the Gemini CLI integration (~/.gemini/settings.json)").option("--qwen", "also strip the Qwen Code integration (~/.qwen/settings.json)").option("--pi", "also remove the pi (pi-coding-agent) extension").option("--opencode", "also remove the opencode plugin").option("--hermes", "no-op verification flag for symmetry with install (removes no files)").option("--openclaw", "also remove the OpenClaw plugin and config entry").option("--copilot", "also 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", "also remove the Grok CLI hook config and shim script").option("--vscode", "also remove the VS Code MCP server (user scope by default; -p/--project for the workspace one) and routing guidance").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));
|
|
13293
15120
|
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("-p, --project", "also check the workspace .vscode/mcp.json (relative to --cwd or the real cwd)").action(guard(cmdMcpStatus));
|
|
13294
15121
|
const worker = program2.command("worker").description("background indexer lifecycle");
|
|
13295
15122
|
worker.command("start").description("start the background indexer").action(guard(cmdWorkerStart));
|
|
@@ -13674,14 +15501,14 @@ function applyExitOverride(command) {
|
|
|
13674
15501
|
command.exitOverride();
|
|
13675
15502
|
for (const sub of command.commands) applyExitOverride(sub);
|
|
13676
15503
|
}
|
|
13677
|
-
async function
|
|
15504
|
+
async function run(argv = process.argv) {
|
|
13678
15505
|
if (argv[2] === "--worker-daemon") {
|
|
13679
15506
|
runDetachedWorkerDaemon();
|
|
13680
15507
|
return;
|
|
13681
15508
|
}
|
|
13682
15509
|
if (argv[2] === "--batch-serve" && typeof argv[3] === "string") {
|
|
13683
|
-
const { serveBatch } = await import("./token-goat-hook-chunk-
|
|
13684
|
-
serveBatch(argv[3], (a) =>
|
|
15510
|
+
const { serveBatch } = await import("./token-goat-hook-chunk-5AQYD2SZ.mjs");
|
|
15511
|
+
serveBatch(argv[3], (a) => run(a));
|
|
13685
15512
|
return;
|
|
13686
15513
|
}
|
|
13687
15514
|
const program2 = buildProgram();
|
|
@@ -13713,5 +15540,6 @@ export {
|
|
|
13713
15540
|
buildProgram,
|
|
13714
15541
|
cmdIndex,
|
|
13715
15542
|
expandGlobs,
|
|
13716
|
-
|
|
15543
|
+
leftoverIntegrations,
|
|
15544
|
+
run
|
|
13717
15545
|
};
|